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