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