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