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