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