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