AndroidKeyStoreKeyPairGeneratorSpi.java revision 4a0ff7ca984d29bd34b02e54441957cad65e8b53
1fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill/*
2fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Copyright (C) 2012 The Android Open Source Project
3fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
4fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Licensed under the Apache License, Version 2.0 (the "License");
5fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * you may not use this file except in compliance with the License.
6fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * You may obtain a copy of the License at
7fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
8fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *      http://www.apache.org/licenses/LICENSE-2.0
9fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill *
10fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * Unless required by applicable law or agreed to in writing, software
11fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * distributed under the License is distributed on an "AS IS" BASIS,
12fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * See the License for the specific language governing permissions and
14fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * limitations under the License.
15fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill */
16fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
17fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillpackage android.security.keystore;
18fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
19cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport android.annotation.Nullable;
20fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.security.Credentials;
21fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.security.KeyPairGeneratorSpec;
22cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport android.security.KeyStore;
23fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.security.keymaster.KeyCharacteristics;
24fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.security.keymaster.KeymasterArguments;
25fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport android.security.keymaster.KeymasterDefs;
26fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
27fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.asn1.ASN1EncodableVector;
28fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.asn1.ASN1InputStream;
29248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neillimport com.android.org.bouncycastle.asn1.ASN1Integer;
30cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
31cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport com.android.org.bouncycastle.asn1.DERBitString;
32cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport com.android.org.bouncycastle.asn1.DERInteger;
33cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport com.android.org.bouncycastle.asn1.DERNull;
34fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.asn1.DERSequence;
35cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neillimport com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
36fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
37fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.asn1.x509.Certificate;
384a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
39fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.asn1.x509.TBSCertificate;
404a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport com.android.org.bouncycastle.asn1.x509.Time;
414a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
42546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
434a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport com.android.org.bouncycastle.jce.X509Principal;
44fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport com.android.org.bouncycastle.jce.provider.X509CertificateObject;
454a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
46546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
474a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport libcore.util.EmptyArray;
484a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
49fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.math.BigInteger;
50fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.InvalidAlgorithmParameterException;
51fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.KeyPair;
524a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport java.security.KeyPairGenerator;
53546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.security.KeyPairGeneratorSpi;
54546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.security.PrivateKey;
55fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.ProviderException;
564a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neillimport java.security.PublicKey;
57fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.SecureRandom;
58fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.UnrecoverableKeyException;
59fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.cert.CertificateEncodingException;
60546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.security.cert.X509Certificate;
61546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.security.spec.AlgorithmParameterSpec;
62546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.security.spec.ECGenParameterSpec;
63fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.security.spec.RSAKeyGenParameterSpec;
64546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.util.ArrayList;
65546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.util.Collections;
66fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.util.Date;
67fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.util.HashMap;
68546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillimport java.util.HashSet;
69fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.util.List;
70fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.util.Locale;
71fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.util.Map;
72fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neillimport java.util.Set;
73cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
74248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill/**
75248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * Provides a way to create instances of a KeyPair which will be placed in the
76248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * Android keystore service usable only by the application that called it. This
77cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * can be used in conjunction with
78fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * {@link java.security.KeyStore#getInstance(String)} using the
79248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill * {@code "AndroidKeyStore"} type.
80fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * <p>
81fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * This class can not be directly instantiated and must instead be used via the
82cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill * {@link KeyPairGenerator#getInstance(String)
83fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
844a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill *
854a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill * @hide
86fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill */
87546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neillpublic abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
88546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
89546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
90546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill        public RSA() {
91546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill            super(KeymasterDefs.KM_ALGORITHM_RSA);
92546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill        }
93546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    }
94546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
95546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
96546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill        public EC() {
97546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill            super(KeymasterDefs.KM_ALGORITHM_EC);
98546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill        }
99546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    }
100546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
101546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    /*
102fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill     * These must be kept in sync with system/security/keystore/defaults.h
103184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill     */
104184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill
105184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill    /* EC */
106184e75146cb17f8695dffba69e0ca8d80b350af3Tom O'Neill    private static final int EC_DEFAULT_KEY_SIZE = 256;
1074a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private static final int EC_MIN_KEY_SIZE = 192;
108546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    private static final int EC_MAX_KEY_SIZE = 521;
109546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill
110546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill    /* RSA */
111fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    private static final int RSA_DEFAULT_KEY_SIZE = 2048;
112fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    private static final int RSA_MIN_KEY_SIZE = 512;
113fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    private static final int RSA_MAX_KEY_SIZE = 8192;
114fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
115fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
116fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            new HashMap<String, Integer>();
117fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
118fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    static {
119fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        // Aliases for NIST P-192
120fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-192", 192);
121fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp192r1", 192);
122fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime192v1", 192);
123fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1244a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        // Aliases for NIST P-224
125fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
1264a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
1274a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
1284a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        // Aliases for NIST P-256
129cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
1304a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
1314a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
1324a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
133fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        // Aliases for NIST P-384
134fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
135fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
136cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
137cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        // Aliases for NIST P-521
138cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
139cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
140cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
141cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
142cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
143cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    }
144cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
145cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private final int mOriginalKeymasterAlgorithm;
146cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
147cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private KeyStore mKeyStore;
148cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
149cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private KeyGenParameterSpec mSpec;
150cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
151cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private String mEntryAlias;
152cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private boolean mEncryptionAtRestRequired;
153cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
154cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private int mKeymasterAlgorithm = -1;
1554a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private int mKeySizeBits;
156cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private SecureRandom mRng;
1574a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill
158cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private int[] mKeymasterPurposes;
159cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private int[] mKeymasterBlockModes;
160248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    private int[] mKeymasterEncryptionPaddings;
161cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    private int[] mKeymasterSignaturePaddings;
1624a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    private int[] mKeymasterDigests;
163fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
164248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    private long mRSAPublicExponent;
165cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
166cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
167cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        mOriginalKeymasterAlgorithm = keymasterAlgorithm;
168248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    }
169cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
170cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill    @Override
171248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    public void initialize(int keysize, SecureRandom random) {
172fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        throw new IllegalArgumentException(
173fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
174cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                + " required to initialize this KeyPairGenerator");
175fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill    }
176fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
1774a7c49c81f021ebb01c1ac06737b4e705f212783Tom O'Neill    @Override
178248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill    public void initialize(AlgorithmParameterSpec params, SecureRandom random)
179cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill            throws InvalidAlgorithmParameterException {
180fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        resetAll();
181cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill
182cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill        boolean success = false;
183fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill        try {
184fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            if (params == null) {
185fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                throw new InvalidAlgorithmParameterException(
186cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                        "Must supply params of type " + KeyGenParameterSpec.class.getName()
187fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                        + " or " + KeyPairGeneratorSpec.class.getName());
188fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            }
189fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill
190fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill            KeyGenParameterSpec spec;
191248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill            boolean encryptionAtRestRequired = false;
192248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill            int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
193546113d4c290f36bf21b1e9c7b93d1592df17fceTom O'Neill            if (params instanceof KeyGenParameterSpec) {
194248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill                spec = (KeyGenParameterSpec) params;
195248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill            } else if (params instanceof KeyPairGeneratorSpec) {
196248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill                // Legacy/deprecated spec
197fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
198248ada68cce2d1ab8f59ef18b869d866f4af6045Tom O'Neill                try {
19917c5e79496bc1e2d53bc3c4e33bad4b39b80c36dTom O'Neill                    KeyGenParameterSpec.Builder specBuilder;
200fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                    String specKeyAlgorithm = legacySpec.getKeyType();
201fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                    if (specKeyAlgorithm != null) {
202cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                        // Spec overrides the generator's default key algorithm
203cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                        try {
204cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                            keymasterAlgorithm =
205cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                    KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
206cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                            specKeyAlgorithm);
207cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                        } catch (IllegalArgumentException e) {
208cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                            throw new InvalidAlgorithmParameterException(
209cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                    "Invalid key type in parameters", e);
210cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                        }
211cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                    }
212cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                    switch (keymasterAlgorithm) {
213cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                        case KeymasterDefs.KM_ALGORITHM_EC:
214cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                            specBuilder = new KeyGenParameterSpec.Builder(
215cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                    legacySpec.getKeystoreAlias(),
216cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                    KeyProperties.PURPOSE_SIGN
217cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                    | KeyProperties.PURPOSE_VERIFY);
218fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                            specBuilder.setDigests(
219cef05c28eb452810e4b79895970457ff2bdef5b4Tom O'Neill                                    KeyProperties.DIGEST_NONE,
220fa2992c412c08f76331a3f58ca57cf8cf04e7b84Tom O'Neill                                    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                Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
707                        spec.getDigests(),
708                        AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
709
710                // The amount of space available for the digest is less than modulus size because
711                // padding must be at least 10 bytes long, and then there's also the 15--19
712                // bytes overhead for encoding digest OID and digest value in DER.
713                int maxDigestOutputSizeBits = keySizeBits - 29 * 8;
714                int bestKeymasterDigest = -1;
715                int bestDigestOutputSizeBits = -1;
716                for (int keymasterDigest : availableKeymasterDigests) {
717                    int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
718                    if (outputSizeBits > maxDigestOutputSizeBits) {
719                        // Digest too long (signature generation will fail) -- skip
720                        continue;
721                    }
722                    if (bestKeymasterDigest == -1) {
723                        // First digest tested -- definitely the best so far
724                        bestKeymasterDigest = keymasterDigest;
725                        bestDigestOutputSizeBits = outputSizeBits;
726                    } else {
727                        // The longer the better
728                        if (outputSizeBits > bestDigestOutputSizeBits) {
729                            bestKeymasterDigest = keymasterDigest;
730                            bestDigestOutputSizeBits = outputSizeBits;
731                        }
732                    }
733                }
734                if (bestKeymasterDigest == -1) {
735                    return null;
736                }
737                return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
738                        bestKeymasterDigest) + "WithRSA";
739            }
740            default:
741                throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
742        }
743    }
744
745    private static Set<Integer> getAvailableKeymasterSignatureDigests(
746            @KeyProperties.DigestEnum String[] authorizedKeyDigests,
747            @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
748        Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
749        for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
750            authorizedKeymasterKeyDigests.add(keymasterDigest);
751        }
752        Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
753        for (int keymasterDigest
754                : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
755            supportedKeymasterSignatureDigests.add(keymasterDigest);
756        }
757        if (authorizedKeymasterKeyDigests.contains(KeymasterDefs.KM_DIGEST_NONE)) {
758            // Key is authorized to be used with any digest
759            return supportedKeymasterSignatureDigests;
760        } else {
761            // Key is authorized to be used only with specific digests.
762            Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
763            result.retainAll(authorizedKeymasterKeyDigests);
764            return result;
765        }
766    }
767}
768