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