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