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