1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.security.keystore; 18 19 import android.annotation.Nullable; 20 import android.security.Credentials; 21 import android.security.GateKeeper; 22 import android.security.KeyPairGeneratorSpec; 23 import android.security.KeyStore; 24 import android.security.KeyStoreException; 25 import android.security.keymaster.KeyCharacteristics; 26 import android.security.keymaster.KeymasterArguments; 27 import android.security.keymaster.KeymasterCertificateChain; 28 import android.security.keymaster.KeymasterDefs; 29 30 import com.android.org.bouncycastle.asn1.ASN1EncodableVector; 31 import com.android.org.bouncycastle.asn1.ASN1InputStream; 32 import com.android.org.bouncycastle.asn1.ASN1Integer; 33 import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; 34 import com.android.org.bouncycastle.asn1.DERBitString; 35 import com.android.org.bouncycastle.asn1.DERInteger; 36 import com.android.org.bouncycastle.asn1.DERNull; 37 import com.android.org.bouncycastle.asn1.DERSequence; 38 import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 39 import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; 40 import com.android.org.bouncycastle.asn1.x509.Certificate; 41 import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 42 import com.android.org.bouncycastle.asn1.x509.TBSCertificate; 43 import com.android.org.bouncycastle.asn1.x509.Time; 44 import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; 45 import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 46 import com.android.org.bouncycastle.jce.X509Principal; 47 import com.android.org.bouncycastle.jce.provider.X509CertificateObject; 48 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; 49 50 import libcore.util.EmptyArray; 51 52 import java.io.ByteArrayOutputStream; 53 import java.io.IOException; 54 import java.math.BigInteger; 55 import java.security.InvalidAlgorithmParameterException; 56 import java.security.KeyPair; 57 import java.security.KeyPairGenerator; 58 import java.security.KeyPairGeneratorSpi; 59 import java.security.PrivateKey; 60 import java.security.ProviderException; 61 import java.security.PublicKey; 62 import java.security.SecureRandom; 63 import java.security.UnrecoverableKeyException; 64 import java.security.cert.CertificateEncodingException; 65 import java.security.cert.CertificateParsingException; 66 import java.security.cert.X509Certificate; 67 import java.security.spec.AlgorithmParameterSpec; 68 import java.security.spec.ECGenParameterSpec; 69 import java.security.spec.RSAKeyGenParameterSpec; 70 import java.util.ArrayList; 71 import java.util.Collection; 72 import java.util.Collections; 73 import java.util.HashMap; 74 import java.util.HashSet; 75 import java.util.Iterator; 76 import java.util.List; 77 import java.util.Locale; 78 import java.util.Map; 79 import java.util.Set; 80 81 /** 82 * Provides a way to create instances of a KeyPair which will be placed in the 83 * Android keystore service usable only by the application that called it. This 84 * can be used in conjunction with 85 * {@link java.security.KeyStore#getInstance(String)} using the 86 * {@code "AndroidKeyStore"} type. 87 * <p> 88 * This class can not be directly instantiated and must instead be used via the 89 * {@link KeyPairGenerator#getInstance(String) 90 * KeyPairGenerator.getInstance("AndroidKeyStore")} API. 91 * 92 * @hide 93 */ 94 public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi { 95 96 public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi { RSA()97 public RSA() { 98 super(KeymasterDefs.KM_ALGORITHM_RSA); 99 } 100 } 101 102 public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi { EC()103 public EC() { 104 super(KeymasterDefs.KM_ALGORITHM_EC); 105 } 106 } 107 108 /* 109 * These must be kept in sync with system/security/keystore/defaults.h 110 */ 111 112 /* EC */ 113 private static final int EC_DEFAULT_KEY_SIZE = 256; 114 115 /* RSA */ 116 private static final int RSA_DEFAULT_KEY_SIZE = 2048; 117 private static final int RSA_MIN_KEY_SIZE = 512; 118 private static final int RSA_MAX_KEY_SIZE = 8192; 119 120 private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE = 121 new HashMap<String, Integer>(); 122 private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>(); 123 private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>(); 124 static { 125 // Aliases for NIST P-224 126 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224); 127 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224); 128 129 130 // Aliases for NIST P-256 131 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256); 132 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256); 133 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256); 134 135 // Aliases for NIST P-384 136 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384); 137 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384); 138 139 // Aliases for NIST P-521 140 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521); 141 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521); 142 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet()143 SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet()); 144 Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES); 145 SUPPORTED_EC_NIST_CURVE_SIZES.addAll( new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()))146 SUPPORTED_EC_NIST_CURVE_SIZES.addAll( 147 new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values())); 148 Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES); 149 } 150 151 private final int mOriginalKeymasterAlgorithm; 152 153 private KeyStore mKeyStore; 154 155 private KeyGenParameterSpec mSpec; 156 157 private String mEntryAlias; 158 private int mEntryUid; 159 private boolean mEncryptionAtRestRequired; 160 private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm; 161 private int mKeymasterAlgorithm = -1; 162 private int mKeySizeBits; 163 private SecureRandom mRng; 164 165 private int[] mKeymasterPurposes; 166 private int[] mKeymasterBlockModes; 167 private int[] mKeymasterEncryptionPaddings; 168 private int[] mKeymasterSignaturePaddings; 169 private int[] mKeymasterDigests; 170 171 private BigInteger mRSAPublicExponent; 172 AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm)173 protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) { 174 mOriginalKeymasterAlgorithm = keymasterAlgorithm; 175 } 176 177 @SuppressWarnings("deprecation") 178 @Override initialize(int keysize, SecureRandom random)179 public void initialize(int keysize, SecureRandom random) { 180 throw new IllegalArgumentException( 181 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName() 182 + " required to initialize this KeyPairGenerator"); 183 } 184 185 @SuppressWarnings("deprecation") 186 @Override initialize(AlgorithmParameterSpec params, SecureRandom random)187 public void initialize(AlgorithmParameterSpec params, SecureRandom random) 188 throws InvalidAlgorithmParameterException { 189 resetAll(); 190 191 boolean success = false; 192 try { 193 if (params == null) { 194 throw new InvalidAlgorithmParameterException( 195 "Must supply params of type " + KeyGenParameterSpec.class.getName() 196 + " or " + KeyPairGeneratorSpec.class.getName()); 197 } 198 199 KeyGenParameterSpec spec; 200 boolean encryptionAtRestRequired = false; 201 int keymasterAlgorithm = mOriginalKeymasterAlgorithm; 202 if (params instanceof KeyGenParameterSpec) { 203 spec = (KeyGenParameterSpec) params; 204 } else if (params instanceof KeyPairGeneratorSpec) { 205 // Legacy/deprecated spec 206 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params; 207 try { 208 KeyGenParameterSpec.Builder specBuilder; 209 String specKeyAlgorithm = legacySpec.getKeyType(); 210 if (specKeyAlgorithm != null) { 211 // Spec overrides the generator's default key algorithm 212 try { 213 keymasterAlgorithm = 214 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm( 215 specKeyAlgorithm); 216 } catch (IllegalArgumentException e) { 217 throw new InvalidAlgorithmParameterException( 218 "Invalid key type in parameters", e); 219 } 220 } 221 switch (keymasterAlgorithm) { 222 case KeymasterDefs.KM_ALGORITHM_EC: 223 specBuilder = new KeyGenParameterSpec.Builder( 224 legacySpec.getKeystoreAlias(), 225 KeyProperties.PURPOSE_SIGN 226 | KeyProperties.PURPOSE_VERIFY); 227 // Authorized to be used with any digest (including no digest). 228 // MD5 was never offered for Android Keystore for ECDSA. 229 specBuilder.setDigests( 230 KeyProperties.DIGEST_NONE, 231 KeyProperties.DIGEST_SHA1, 232 KeyProperties.DIGEST_SHA224, 233 KeyProperties.DIGEST_SHA256, 234 KeyProperties.DIGEST_SHA384, 235 KeyProperties.DIGEST_SHA512); 236 break; 237 case KeymasterDefs.KM_ALGORITHM_RSA: 238 specBuilder = new KeyGenParameterSpec.Builder( 239 legacySpec.getKeystoreAlias(), 240 KeyProperties.PURPOSE_ENCRYPT 241 | KeyProperties.PURPOSE_DECRYPT 242 | KeyProperties.PURPOSE_SIGN 243 | KeyProperties.PURPOSE_VERIFY); 244 // Authorized to be used with any digest (including no digest). 245 specBuilder.setDigests( 246 KeyProperties.DIGEST_NONE, 247 KeyProperties.DIGEST_MD5, 248 KeyProperties.DIGEST_SHA1, 249 KeyProperties.DIGEST_SHA224, 250 KeyProperties.DIGEST_SHA256, 251 KeyProperties.DIGEST_SHA384, 252 KeyProperties.DIGEST_SHA512); 253 // Authorized to be used with any encryption and signature padding 254 // schemes (including no padding). 255 specBuilder.setEncryptionPaddings( 256 KeyProperties.ENCRYPTION_PADDING_NONE, 257 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, 258 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); 259 specBuilder.setSignaturePaddings( 260 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, 261 KeyProperties.SIGNATURE_PADDING_RSA_PSS); 262 // Disable randomized encryption requirement to support encryption 263 // padding NONE above. 264 specBuilder.setRandomizedEncryptionRequired(false); 265 break; 266 default: 267 throw new ProviderException( 268 "Unsupported algorithm: " + mKeymasterAlgorithm); 269 } 270 271 if (legacySpec.getKeySize() != -1) { 272 specBuilder.setKeySize(legacySpec.getKeySize()); 273 } 274 if (legacySpec.getAlgorithmParameterSpec() != null) { 275 specBuilder.setAlgorithmParameterSpec( 276 legacySpec.getAlgorithmParameterSpec()); 277 } 278 specBuilder.setCertificateSubject(legacySpec.getSubjectDN()); 279 specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber()); 280 specBuilder.setCertificateNotBefore(legacySpec.getStartDate()); 281 specBuilder.setCertificateNotAfter(legacySpec.getEndDate()); 282 encryptionAtRestRequired = legacySpec.isEncryptionRequired(); 283 specBuilder.setUserAuthenticationRequired(false); 284 285 spec = specBuilder.build(); 286 } catch (NullPointerException | IllegalArgumentException e) { 287 throw new InvalidAlgorithmParameterException(e); 288 } 289 } else { 290 throw new InvalidAlgorithmParameterException( 291 "Unsupported params class: " + params.getClass().getName() 292 + ". Supported: " + KeyGenParameterSpec.class.getName() 293 + ", " + KeyPairGeneratorSpec.class.getName()); 294 } 295 296 mEntryAlias = spec.getKeystoreAlias(); 297 mEntryUid = spec.getUid(); 298 mSpec = spec; 299 mKeymasterAlgorithm = keymasterAlgorithm; 300 mEncryptionAtRestRequired = encryptionAtRestRequired; 301 mKeySizeBits = spec.getKeySize(); 302 initAlgorithmSpecificParameters(); 303 if (mKeySizeBits == -1) { 304 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm); 305 } 306 checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked()); 307 308 if (spec.getKeystoreAlias() == null) { 309 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided"); 310 } 311 312 String jcaKeyAlgorithm; 313 try { 314 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm( 315 keymasterAlgorithm); 316 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes()); 317 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()); 318 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster( 319 spec.getEncryptionPaddings()); 320 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0) 321 && (spec.isRandomizedEncryptionRequired())) { 322 for (int keymasterPadding : mKeymasterEncryptionPaddings) { 323 if (!KeymasterUtils 324 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto( 325 keymasterPadding)) { 326 throw new InvalidAlgorithmParameterException( 327 "Randomized encryption (IND-CPA) required but may be violated" 328 + " by padding scheme: " 329 + KeyProperties.EncryptionPadding.fromKeymaster( 330 keymasterPadding) 331 + ". See " + KeyGenParameterSpec.class.getName() 332 + " documentation."); 333 } 334 } 335 } 336 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster( 337 spec.getSignaturePaddings()); 338 if (spec.isDigestsSpecified()) { 339 mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests()); 340 } else { 341 mKeymasterDigests = EmptyArray.INT; 342 } 343 344 // Check that user authentication related parameters are acceptable. This method 345 // will throw an IllegalStateException if there are issues (e.g., secure lock screen 346 // not set up). 347 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec); 348 } catch (IllegalArgumentException | IllegalStateException e) { 349 throw new InvalidAlgorithmParameterException(e); 350 } 351 352 mJcaKeyAlgorithm = jcaKeyAlgorithm; 353 mRng = random; 354 mKeyStore = KeyStore.getInstance(); 355 success = true; 356 } finally { 357 if (!success) { 358 resetAll(); 359 } 360 } 361 } 362 resetAll()363 private void resetAll() { 364 mEntryAlias = null; 365 mEntryUid = KeyStore.UID_SELF; 366 mJcaKeyAlgorithm = null; 367 mKeymasterAlgorithm = -1; 368 mKeymasterPurposes = null; 369 mKeymasterBlockModes = null; 370 mKeymasterEncryptionPaddings = null; 371 mKeymasterSignaturePaddings = null; 372 mKeymasterDigests = null; 373 mKeySizeBits = 0; 374 mSpec = null; 375 mRSAPublicExponent = null; 376 mEncryptionAtRestRequired = false; 377 mRng = null; 378 mKeyStore = null; 379 } 380 initAlgorithmSpecificParameters()381 private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException { 382 AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec(); 383 switch (mKeymasterAlgorithm) { 384 case KeymasterDefs.KM_ALGORITHM_RSA: 385 { 386 BigInteger publicExponent = null; 387 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) { 388 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec; 389 if (mKeySizeBits == -1) { 390 mKeySizeBits = rsaSpec.getKeysize(); 391 } else if (mKeySizeBits != rsaSpec.getKeysize()) { 392 throw new InvalidAlgorithmParameterException("RSA key size must match " 393 + " between " + mSpec + " and " + algSpecificSpec 394 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize()); 395 } 396 publicExponent = rsaSpec.getPublicExponent(); 397 } else if (algSpecificSpec != null) { 398 throw new InvalidAlgorithmParameterException( 399 "RSA may only use RSAKeyGenParameterSpec"); 400 } 401 if (publicExponent == null) { 402 publicExponent = RSAKeyGenParameterSpec.F4; 403 } 404 if (publicExponent.compareTo(BigInteger.ZERO) < 1) { 405 throw new InvalidAlgorithmParameterException( 406 "RSA public exponent must be positive: " + publicExponent); 407 } 408 if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) { 409 throw new InvalidAlgorithmParameterException( 410 "Unsupported RSA public exponent: " + publicExponent 411 + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE); 412 } 413 mRSAPublicExponent = publicExponent; 414 break; 415 } 416 case KeymasterDefs.KM_ALGORITHM_EC: 417 if (algSpecificSpec instanceof ECGenParameterSpec) { 418 ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec; 419 String curveName = ecSpec.getName(); 420 Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get( 421 curveName.toLowerCase(Locale.US)); 422 if (ecSpecKeySizeBits == null) { 423 throw new InvalidAlgorithmParameterException( 424 "Unsupported EC curve name: " + curveName 425 + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES); 426 } 427 if (mKeySizeBits == -1) { 428 mKeySizeBits = ecSpecKeySizeBits; 429 } else if (mKeySizeBits != ecSpecKeySizeBits) { 430 throw new InvalidAlgorithmParameterException("EC key size must match " 431 + " between " + mSpec + " and " + algSpecificSpec 432 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits); 433 } 434 } else if (algSpecificSpec != null) { 435 throw new InvalidAlgorithmParameterException( 436 "EC may only use ECGenParameterSpec"); 437 } 438 break; 439 default: 440 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm); 441 } 442 } 443 444 @Override generateKeyPair()445 public KeyPair generateKeyPair() { 446 if (mKeyStore == null || mSpec == null) { 447 throw new IllegalStateException("Not initialized"); 448 } 449 450 int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0; 451 if (((flags & KeyStore.FLAG_ENCRYPTED) != 0) 452 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) { 453 throw new IllegalStateException( 454 "Encryption at rest using secure lock screen credential requested for key pair" 455 + ", but the user has not yet entered the credential"); 456 } 457 458 if (mSpec.isStrongBoxBacked()) { 459 flags |= KeyStore.FLAG_STRONGBOX; 460 } 461 462 byte[] additionalEntropy = 463 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng( 464 mRng, (mKeySizeBits + 7) / 8); 465 466 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid); 467 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias; 468 boolean success = false; 469 try { 470 generateKeystoreKeyPair( 471 privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags); 472 KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias); 473 474 storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair)); 475 476 success = true; 477 return keyPair; 478 } catch (ProviderException e) { 479 if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) { 480 throw new SecureKeyImportUnavailableException(e); 481 } else { 482 throw e; 483 } 484 } finally { 485 if (!success) { 486 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid); 487 } 488 } 489 } 490 createCertificateChain(final String privateKeyAlias, KeyPair keyPair)491 private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair) 492 throws ProviderException { 493 byte[] challenge = mSpec.getAttestationChallenge(); 494 if (challenge != null) { 495 KeymasterArguments args = new KeymasterArguments(); 496 args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge); 497 return getAttestationChain(privateKeyAlias, keyPair, args); 498 } 499 500 // Very short certificate chain in the non-attestation case. 501 return Collections.singleton(generateSelfSignedCertificateBytes(keyPair)); 502 } 503 generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args, byte[] additionalEntropy, final int flags)504 private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args, 505 byte[] additionalEntropy, final int flags) throws ProviderException { 506 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics(); 507 int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy, 508 mEntryUid, flags, resultingKeyCharacteristics); 509 if (errorCode != KeyStore.NO_ERROR) { 510 if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) { 511 throw new StrongBoxUnavailableException("Failed to generate key pair"); 512 } else { 513 throw new ProviderException( 514 "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode)); 515 } 516 } 517 } 518 loadKeystoreKeyPair(final String privateKeyAlias)519 private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException { 520 try { 521 KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore( 522 mKeyStore, privateKeyAlias, mEntryUid); 523 if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) { 524 throw new ProviderException( 525 "Generated key pair algorithm does not match requested algorithm: " 526 + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm); 527 } 528 return result; 529 } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) { 530 throw new ProviderException("Failed to load generated key pair from keystore", e); 531 } 532 } 533 constructKeyGenerationArguments()534 private KeymasterArguments constructKeyGenerationArguments() { 535 KeymasterArguments args = new KeymasterArguments(); 536 args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits); 537 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm); 538 args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes); 539 args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes); 540 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings); 541 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings); 542 args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests); 543 544 KeymasterUtils.addUserAuthArgs(args, mSpec); 545 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart()); 546 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, 547 mSpec.getKeyValidityForOriginationEnd()); 548 args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, 549 mSpec.getKeyValidityForConsumptionEnd()); 550 addAlgorithmSpecificParameters(args); 551 552 if (mSpec.isUniqueIdIncluded()) 553 args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID); 554 555 return args; 556 } 557 storeCertificateChain(final int flags, Iterable<byte[]> iterable)558 private void storeCertificateChain(final int flags, Iterable<byte[]> iterable) 559 throws ProviderException { 560 Iterator<byte[]> iter = iterable.iterator(); 561 storeCertificate( 562 Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate"); 563 564 if (!iter.hasNext()) { 565 return; 566 } 567 568 ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream(); 569 while (iter.hasNext()) { 570 byte[] data = iter.next(); 571 certificateConcatenationStream.write(data, 0, data.length); 572 } 573 574 storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(), 575 flags, "Failed to store attestation CA certificate"); 576 } 577 storeCertificate(String prefix, byte[] certificateBytes, final int flags, String failureMessage)578 private void storeCertificate(String prefix, byte[] certificateBytes, final int flags, 579 String failureMessage) throws ProviderException { 580 int insertErrorCode = mKeyStore.insert( 581 prefix + mEntryAlias, 582 certificateBytes, 583 mEntryUid, 584 flags); 585 if (insertErrorCode != KeyStore.NO_ERROR) { 586 throw new ProviderException(failureMessage, 587 KeyStore.getKeyStoreException(insertErrorCode)); 588 } 589 } 590 generateSelfSignedCertificateBytes(KeyPair keyPair)591 private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException { 592 try { 593 return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic()) 594 .getEncoded(); 595 } catch (IOException | CertificateParsingException e) { 596 throw new ProviderException("Failed to generate self-signed certificate", e); 597 } catch (CertificateEncodingException e) { 598 throw new ProviderException( 599 "Failed to obtain encoded form of self-signed certificate", e); 600 } 601 } 602 getAttestationChain(String privateKeyAlias, KeyPair keyPair, KeymasterArguments args)603 private Iterable<byte[]> getAttestationChain(String privateKeyAlias, 604 KeyPair keyPair, KeymasterArguments args) 605 throws ProviderException { 606 KeymasterCertificateChain outChain = new KeymasterCertificateChain(); 607 int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain); 608 if (errorCode != KeyStore.NO_ERROR) { 609 throw new ProviderException("Failed to generate attestation certificate chain", 610 KeyStore.getKeyStoreException(errorCode)); 611 } 612 Collection<byte[]> chain = outChain.getCertificates(); 613 if (chain.size() < 2) { 614 throw new ProviderException("Attestation certificate chain contained " 615 + chain.size() + " entries. At least two are required."); 616 } 617 return chain; 618 } 619 addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs)620 private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) { 621 switch (mKeymasterAlgorithm) { 622 case KeymasterDefs.KM_ALGORITHM_RSA: 623 keymasterArgs.addUnsignedLong( 624 KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent); 625 break; 626 case KeymasterDefs.KM_ALGORITHM_EC: 627 break; 628 default: 629 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm); 630 } 631 } 632 generateSelfSignedCertificate(PrivateKey privateKey, PublicKey publicKey)633 private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey, 634 PublicKey publicKey) throws CertificateParsingException, IOException { 635 String signatureAlgorithm = 636 getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec); 637 if (signatureAlgorithm == null) { 638 // Key cannot be used to sign a certificate 639 return generateSelfSignedCertificateWithFakeSignature(publicKey); 640 } else { 641 // Key can be used to sign a certificate 642 try { 643 return generateSelfSignedCertificateWithValidSignature( 644 privateKey, publicKey, signatureAlgorithm); 645 } catch (Exception e) { 646 // Failed to generate the self-signed certificate with valid signature. Fall back 647 // to generating a self-signed certificate with a fake signature. This is done for 648 // all exception types because we prefer key pair generation to succeed and end up 649 // producing a self-signed certificate with an invalid signature to key pair 650 // generation failing. 651 return generateSelfSignedCertificateWithFakeSignature(publicKey); 652 } 653 } 654 } 655 656 @SuppressWarnings("deprecation") generateSelfSignedCertificateWithValidSignature( PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm)657 private X509Certificate generateSelfSignedCertificateWithValidSignature( 658 PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception { 659 final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); 660 certGen.setPublicKey(publicKey); 661 certGen.setSerialNumber(mSpec.getCertificateSerialNumber()); 662 certGen.setSubjectDN(mSpec.getCertificateSubject()); 663 certGen.setIssuerDN(mSpec.getCertificateSubject()); 664 certGen.setNotBefore(mSpec.getCertificateNotBefore()); 665 certGen.setNotAfter(mSpec.getCertificateNotAfter()); 666 certGen.setSignatureAlgorithm(signatureAlgorithm); 667 return certGen.generate(privateKey); 668 } 669 670 @SuppressWarnings("deprecation") generateSelfSignedCertificateWithFakeSignature( PublicKey publicKey)671 private X509Certificate generateSelfSignedCertificateWithFakeSignature( 672 PublicKey publicKey) throws IOException, CertificateParsingException { 673 V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator(); 674 ASN1ObjectIdentifier sigAlgOid; 675 AlgorithmIdentifier sigAlgId; 676 byte[] signature; 677 switch (mKeymasterAlgorithm) { 678 case KeymasterDefs.KM_ALGORITHM_EC: 679 sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256; 680 sigAlgId = new AlgorithmIdentifier(sigAlgOid); 681 ASN1EncodableVector v = new ASN1EncodableVector(); 682 v.add(new DERInteger(0)); 683 v.add(new DERInteger(0)); 684 signature = new DERSequence().getEncoded(); 685 break; 686 case KeymasterDefs.KM_ALGORITHM_RSA: 687 sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption; 688 sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE); 689 signature = new byte[1]; 690 break; 691 default: 692 throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm); 693 } 694 695 try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) { 696 tbsGenerator.setSubjectPublicKeyInfo( 697 SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject())); 698 } 699 tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber())); 700 X509Principal subject = 701 new X509Principal(mSpec.getCertificateSubject().getEncoded()); 702 tbsGenerator.setSubject(subject); 703 tbsGenerator.setIssuer(subject); 704 tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore())); 705 tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter())); 706 tbsGenerator.setSignature(sigAlgId); 707 TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate(); 708 709 ASN1EncodableVector result = new ASN1EncodableVector(); 710 result.add(tbsCertificate); 711 result.add(sigAlgId); 712 result.add(new DERBitString(signature)); 713 return new X509CertificateObject(Certificate.getInstance(new DERSequence(result))); 714 } 715 getDefaultKeySize(int keymasterAlgorithm)716 private static int getDefaultKeySize(int keymasterAlgorithm) { 717 switch (keymasterAlgorithm) { 718 case KeymasterDefs.KM_ALGORITHM_EC: 719 return EC_DEFAULT_KEY_SIZE; 720 case KeymasterDefs.KM_ALGORITHM_RSA: 721 return RSA_DEFAULT_KEY_SIZE; 722 default: 723 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm); 724 } 725 } 726 checkValidKeySize( int keymasterAlgorithm, int keySize, boolean isStrongBoxBacked)727 private static void checkValidKeySize( 728 int keymasterAlgorithm, 729 int keySize, 730 boolean isStrongBoxBacked) 731 throws InvalidAlgorithmParameterException { 732 switch (keymasterAlgorithm) { 733 case KeymasterDefs.KM_ALGORITHM_EC: 734 if (isStrongBoxBacked && keySize != 256) { 735 throw new InvalidAlgorithmParameterException( 736 "Unsupported StrongBox EC key size: " 737 + keySize + " bits. Supported: 256"); 738 } 739 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) { 740 throw new InvalidAlgorithmParameterException("Unsupported EC key size: " 741 + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES); 742 } 743 break; 744 case KeymasterDefs.KM_ALGORITHM_RSA: 745 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) { 746 throw new InvalidAlgorithmParameterException("RSA key size must be >= " 747 + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE); 748 } 749 break; 750 default: 751 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm); 752 } 753 } 754 755 /** 756 * Returns the {@code Signature} algorithm to be used for signing a certificate using the 757 * specified key or {@code null} if the key cannot be used for signing a certificate. 758 */ 759 @Nullable getCertificateSignatureAlgorithm( int keymasterAlgorithm, int keySizeBits, KeyGenParameterSpec spec)760 private static String getCertificateSignatureAlgorithm( 761 int keymasterAlgorithm, 762 int keySizeBits, 763 KeyGenParameterSpec spec) { 764 // Constraints: 765 // 1. Key must be authorized for signing without user authentication. 766 // 2. Signature digest must be one of key's authorized digests. 767 // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead 768 // of RSA PKCS#1 signature padding scheme (about 30 bytes). 769 // 4. For EC keys, the there is no point in using a digest whose output size is longer than 770 // key/field size because the digest will be truncated to that size. 771 772 if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) { 773 // Key not authorized for signing 774 return null; 775 } 776 if (spec.isUserAuthenticationRequired()) { 777 // Key not authorized for use without user authentication 778 return null; 779 } 780 if (!spec.isDigestsSpecified()) { 781 // Key not authorized for any digests -- can't sign 782 return null; 783 } 784 switch (keymasterAlgorithm) { 785 case KeymasterDefs.KM_ALGORITHM_EC: 786 { 787 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests( 788 spec.getDigests(), 789 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests()); 790 791 int bestKeymasterDigest = -1; 792 int bestDigestOutputSizeBits = -1; 793 for (int keymasterDigest : availableKeymasterDigests) { 794 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest); 795 if (outputSizeBits == keySizeBits) { 796 // Perfect match -- use this digest 797 bestKeymasterDigest = keymasterDigest; 798 bestDigestOutputSizeBits = outputSizeBits; 799 break; 800 } 801 // Not a perfect match -- check against the best digest so far 802 if (bestKeymasterDigest == -1) { 803 // First digest tested -- definitely the best so far 804 bestKeymasterDigest = keymasterDigest; 805 bestDigestOutputSizeBits = outputSizeBits; 806 } else { 807 // Prefer output size to be as close to key size as possible, with output 808 // sizes larger than key size preferred to those smaller than key size. 809 if (bestDigestOutputSizeBits < keySizeBits) { 810 // Output size of the best digest so far is smaller than key size. 811 // Anything larger is a win. 812 if (outputSizeBits > bestDigestOutputSizeBits) { 813 bestKeymasterDigest = keymasterDigest; 814 bestDigestOutputSizeBits = outputSizeBits; 815 } 816 } else { 817 // Output size of the best digest so far is larger than key size. 818 // Anything smaller is a win, as long as it's not smaller than key size. 819 if ((outputSizeBits < bestDigestOutputSizeBits) 820 && (outputSizeBits >= keySizeBits)) { 821 bestKeymasterDigest = keymasterDigest; 822 bestDigestOutputSizeBits = outputSizeBits; 823 } 824 } 825 } 826 } 827 if (bestKeymasterDigest == -1) { 828 return null; 829 } 830 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest( 831 bestKeymasterDigest) + "WithECDSA"; 832 } 833 case KeymasterDefs.KM_ALGORITHM_RSA: 834 { 835 // Check whether this key is authorized for PKCS#1 signature padding. 836 // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle 837 // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs 838 // to be authorized for PKCS#1 padding or padding NONE which means any padding. 839 boolean pkcs1SignaturePaddingSupported = 840 com.android.internal.util.ArrayUtils.contains( 841 KeyProperties.SignaturePadding.allToKeymaster( 842 spec.getSignaturePaddings()), 843 KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN); 844 if (!pkcs1SignaturePaddingSupported) { 845 // Key not authorized for PKCS#1 signature padding -- can't sign 846 return null; 847 } 848 849 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests( 850 spec.getDigests(), 851 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests()); 852 853 // The amount of space available for the digest is less than modulus size by about 854 // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00, 855 // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes 856 // overhead (depending the on chosen digest) for encoding digest OID and digest 857 // value in DER. 858 int maxDigestOutputSizeBits = keySizeBits - 30 * 8; 859 int bestKeymasterDigest = -1; 860 int bestDigestOutputSizeBits = -1; 861 for (int keymasterDigest : availableKeymasterDigests) { 862 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest); 863 if (outputSizeBits > maxDigestOutputSizeBits) { 864 // Digest too long (signature generation will fail) -- skip 865 continue; 866 } 867 if (bestKeymasterDigest == -1) { 868 // First digest tested -- definitely the best so far 869 bestKeymasterDigest = keymasterDigest; 870 bestDigestOutputSizeBits = outputSizeBits; 871 } else { 872 // The longer the better 873 if (outputSizeBits > bestDigestOutputSizeBits) { 874 bestKeymasterDigest = keymasterDigest; 875 bestDigestOutputSizeBits = outputSizeBits; 876 } 877 } 878 } 879 if (bestKeymasterDigest == -1) { 880 return null; 881 } 882 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest( 883 bestKeymasterDigest) + "WithRSA"; 884 } 885 default: 886 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm); 887 } 888 } 889 getAvailableKeymasterSignatureDigests( @eyProperties.DigestEnum String[] authorizedKeyDigests, @KeyProperties.DigestEnum String[] supportedSignatureDigests)890 private static Set<Integer> getAvailableKeymasterSignatureDigests( 891 @KeyProperties.DigestEnum String[] authorizedKeyDigests, 892 @KeyProperties.DigestEnum String[] supportedSignatureDigests) { 893 Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>(); 894 for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) { 895 authorizedKeymasterKeyDigests.add(keymasterDigest); 896 } 897 Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>(); 898 for (int keymasterDigest 899 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) { 900 supportedKeymasterSignatureDigests.add(keymasterDigest); 901 } 902 Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests); 903 result.retainAll(authorizedKeymasterKeyDigests); 904 return result; 905 } 906 } 907