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