blob: c52fd48459cb4ed1dec0f09687e8b95f4730d77b [file] [log] [blame]
Kenny Rootdb026712012-08-20 10:48:46 -07001/*
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
Alex Klyubindcdaf872015-05-13 15:57:09 -070017package android.security.keystore;
Kenny Rootdb026712012-08-20 10:48:46 -070018
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070019import android.annotation.Nullable;
Alex Klyubindcdaf872015-05-13 15:57:09 -070020import android.security.Credentials;
21import android.security.KeyPairGeneratorSpec;
22import android.security.KeyStore;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070023import android.security.keymaster.KeyCharacteristics;
24import android.security.keymaster.KeymasterArguments;
Shawn Willden8d8c7472016-02-02 08:27:39 -070025import android.security.keymaster.KeymasterCertificateChain;
Alex Klyubin4350bab2015-06-08 10:14:58 -070026import android.security.keymaster.KeymasterDefs;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070027
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070028import 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;
Kenny Rootdb026712012-08-20 10:48:46 -070046import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
Kenny Rootdb026712012-08-20 10:48:46 -070047
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070048import libcore.util.EmptyArray;
49
Shawn Willden8d8c7472016-02-02 08:27:39 -070050import java.io.ByteArrayOutputStream;
51import java.io.IOException;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070052import java.math.BigInteger;
Kenny Rootdb026712012-08-20 10:48:46 -070053import java.security.InvalidAlgorithmParameterException;
Kenny Rootdb026712012-08-20 10:48:46 -070054import java.security.KeyPair;
55import java.security.KeyPairGenerator;
56import java.security.KeyPairGeneratorSpi;
Kenny Rootdb026712012-08-20 10:48:46 -070057import java.security.PrivateKey;
Alex Klyubin4350bab2015-06-08 10:14:58 -070058import java.security.ProviderException;
Kenny Rootdb026712012-08-20 10:48:46 -070059import java.security.PublicKey;
60import java.security.SecureRandom;
Alex Klyubin4a0ff7c2015-06-09 13:25:20 -070061import java.security.UnrecoverableKeyException;
Kenny Rootdb026712012-08-20 10:48:46 -070062import java.security.cert.CertificateEncodingException;
Shawn Willden8d8c7472016-02-02 08:27:39 -070063import java.security.cert.CertificateParsingException;
Kenny Rootdb026712012-08-20 10:48:46 -070064import java.security.cert.X509Certificate;
65import java.security.spec.AlgorithmParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070066import java.security.spec.ECGenParameterSpec;
Kenny Rootf64386f2013-08-16 14:03:29 -070067import java.security.spec.RSAKeyGenParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070068import java.util.ArrayList;
Shawn Willden8d8c7472016-02-02 08:27:39 -070069import java.util.Collection;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070070import java.util.Collections;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070071import java.util.HashMap;
72import java.util.HashSet;
Shawn Willden8d8c7472016-02-02 08:27:39 -070073import java.util.Iterator;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070074import java.util.List;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070075import java.util.Locale;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070076import java.util.Map;
77import java.util.Set;
Kenny Rootdb026712012-08-20 10:48:46 -070078
79/**
80 * Provides a way to create instances of a KeyPair which will be placed in the
81 * Android keystore service usable only by the application that called it. This
82 * can be used in conjunction with
83 * {@link java.security.KeyStore#getInstance(String)} using the
84 * {@code "AndroidKeyStore"} type.
85 * <p>
86 * This class can not be directly instantiated and must instead be used via the
87 * {@link KeyPairGenerator#getInstance(String)
Alex Klyubine21f0232015-05-19 09:41:17 -070088 * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
Kenny Rootdb026712012-08-20 10:48:46 -070089 *
Alex Klyubine21f0232015-05-19 09:41:17 -070090 * @hide
Kenny Rootdb026712012-08-20 10:48:46 -070091 */
Alex Klyubine21f0232015-05-19 09:41:17 -070092public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -080093
Alex Klyubine21f0232015-05-19 09:41:17 -070094 public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -080095 public RSA() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070096 super(KeymasterDefs.KM_ALGORITHM_RSA);
Alex Klyubin21a76df2015-01-14 13:35:32 -080097 }
98 }
99
Alex Klyubine21f0232015-05-19 09:41:17 -0700100 public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800101 public EC() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700102 super(KeymasterDefs.KM_ALGORITHM_EC);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800103 }
104 }
105
106 /*
107 * These must be kept in sync with system/security/keystore/defaults.h
108 */
109
110 /* EC */
111 private static final int EC_DEFAULT_KEY_SIZE = 256;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800112
113 /* RSA */
114 private static final int RSA_DEFAULT_KEY_SIZE = 2048;
115 private static final int RSA_MIN_KEY_SIZE = 512;
116 private static final int RSA_MAX_KEY_SIZE = 8192;
117
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700118 private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
119 new HashMap<String, Integer>();
120 private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700121 private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700122 static {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700123 // Aliases for NIST P-224
124 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
125 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
126
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700127
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700128 // 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);
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700143
144 SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
145 new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
146 Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700147 }
Alex Klyubin4a0ff7c2015-06-09 13:25:20 -0700148
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700149 private final int mOriginalKeymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800150
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700151 private KeyStore mKeyStore;
Kenny Rootdb026712012-08-20 10:48:46 -0700152
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700153 private KeyGenParameterSpec mSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700154
155 private String mEntryAlias;
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700156 private int mEntryUid;
Alex Klyubin96481c32015-05-15 10:47:18 -0700157 private boolean mEncryptionAtRestRequired;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700158 private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
159 private int mKeymasterAlgorithm = -1;
160 private int mKeySizeBits;
161 private SecureRandom mRng;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800162
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700163 private int[] mKeymasterPurposes;
164 private int[] mKeymasterBlockModes;
165 private int[] mKeymasterEncryptionPaddings;
166 private int[] mKeymasterSignaturePaddings;
167 private int[] mKeymasterDigests;
168
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700169 private BigInteger mRSAPublicExponent;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700170
171 protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
172 mOriginalKeymasterAlgorithm = keymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800173 }
174
Shawn Willden8d8c7472016-02-02 08:27:39 -0700175 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700176 @Override
177 public void initialize(int keysize, SecureRandom random) {
178 throw new IllegalArgumentException(
179 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
180 + " required to initialize this KeyPairGenerator");
Alex Klyubin21a76df2015-01-14 13:35:32 -0800181 }
Kenny Rootdb026712012-08-20 10:48:46 -0700182
Shawn Willden8d8c7472016-02-02 08:27:39 -0700183 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700184 @Override
185 public void initialize(AlgorithmParameterSpec params, SecureRandom random)
186 throws InvalidAlgorithmParameterException {
187 resetAll();
188
189 boolean success = false;
190 try {
191 if (params == null) {
192 throw new InvalidAlgorithmParameterException(
193 "Must supply params of type " + KeyGenParameterSpec.class.getName()
194 + " or " + KeyPairGeneratorSpec.class.getName());
195 }
196
197 KeyGenParameterSpec spec;
198 boolean encryptionAtRestRequired = false;
199 int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
200 if (params instanceof KeyGenParameterSpec) {
201 spec = (KeyGenParameterSpec) params;
202 } else if (params instanceof KeyPairGeneratorSpec) {
203 // Legacy/deprecated spec
204 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
205 try {
206 KeyGenParameterSpec.Builder specBuilder;
207 String specKeyAlgorithm = legacySpec.getKeyType();
208 if (specKeyAlgorithm != null) {
209 // Spec overrides the generator's default key algorithm
210 try {
211 keymasterAlgorithm =
212 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
213 specKeyAlgorithm);
214 } catch (IllegalArgumentException e) {
215 throw new InvalidAlgorithmParameterException(
216 "Invalid key type in parameters", e);
217 }
218 }
219 switch (keymasterAlgorithm) {
220 case KeymasterDefs.KM_ALGORITHM_EC:
221 specBuilder = new KeyGenParameterSpec.Builder(
222 legacySpec.getKeystoreAlias(),
223 KeyProperties.PURPOSE_SIGN
224 | KeyProperties.PURPOSE_VERIFY);
Alex Klyubindcf3d352015-06-11 14:44:46 -0700225 // Authorized to be used with any digest (including no digest).
Alex Klyubine4928a22015-07-21 13:38:48 -0700226 // MD5 was never offered for Android Keystore for ECDSA.
227 specBuilder.setDigests(
228 KeyProperties.DIGEST_NONE,
229 KeyProperties.DIGEST_SHA1,
230 KeyProperties.DIGEST_SHA224,
231 KeyProperties.DIGEST_SHA256,
232 KeyProperties.DIGEST_SHA384,
233 KeyProperties.DIGEST_SHA512);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700234 break;
235 case KeymasterDefs.KM_ALGORITHM_RSA:
236 specBuilder = new KeyGenParameterSpec.Builder(
237 legacySpec.getKeystoreAlias(),
238 KeyProperties.PURPOSE_ENCRYPT
239 | KeyProperties.PURPOSE_DECRYPT
240 | KeyProperties.PURPOSE_SIGN
241 | KeyProperties.PURPOSE_VERIFY);
Alex Klyubindcf3d352015-06-11 14:44:46 -0700242 // Authorized to be used with any digest (including no digest).
Alex Klyubine4928a22015-07-21 13:38:48 -0700243 specBuilder.setDigests(
244 KeyProperties.DIGEST_NONE,
245 KeyProperties.DIGEST_MD5,
246 KeyProperties.DIGEST_SHA1,
247 KeyProperties.DIGEST_SHA224,
248 KeyProperties.DIGEST_SHA256,
249 KeyProperties.DIGEST_SHA384,
250 KeyProperties.DIGEST_SHA512);
Alex Klyubin2e3aaa72015-06-17 13:58:00 -0700251 // Authorized to be used with any encryption and signature padding
Alex Klyubine4928a22015-07-21 13:38:48 -0700252 // schemes (including no padding).
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700253 specBuilder.setEncryptionPaddings(
Alex Klyubine4928a22015-07-21 13:38:48 -0700254 KeyProperties.ENCRYPTION_PADDING_NONE,
255 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
256 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
257 specBuilder.setSignaturePaddings(
258 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
259 KeyProperties.SIGNATURE_PADDING_RSA_PSS);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700260 // Disable randomized encryption requirement to support encryption
261 // padding NONE above.
262 specBuilder.setRandomizedEncryptionRequired(false);
263 break;
264 default:
265 throw new ProviderException(
266 "Unsupported algorithm: " + mKeymasterAlgorithm);
267 }
268
269 if (legacySpec.getKeySize() != -1) {
270 specBuilder.setKeySize(legacySpec.getKeySize());
271 }
272 if (legacySpec.getAlgorithmParameterSpec() != null) {
273 specBuilder.setAlgorithmParameterSpec(
274 legacySpec.getAlgorithmParameterSpec());
275 }
276 specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
277 specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
278 specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
279 specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
280 encryptionAtRestRequired = legacySpec.isEncryptionRequired();
281 specBuilder.setUserAuthenticationRequired(false);
282
283 spec = specBuilder.build();
284 } catch (NullPointerException | IllegalArgumentException e) {
285 throw new InvalidAlgorithmParameterException(e);
286 }
287 } else {
288 throw new InvalidAlgorithmParameterException(
289 "Unsupported params class: " + params.getClass().getName()
290 + ". Supported: " + KeyGenParameterSpec.class.getName()
291 + ", " + KeyPairGeneratorSpec.class.getName());
292 }
293
294 mEntryAlias = spec.getKeystoreAlias();
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700295 mEntryUid = spec.getUid();
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700296 mSpec = spec;
297 mKeymasterAlgorithm = keymasterAlgorithm;
298 mEncryptionAtRestRequired = encryptionAtRestRequired;
299 mKeySizeBits = spec.getKeySize();
300 initAlgorithmSpecificParameters();
301 if (mKeySizeBits == -1) {
302 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
303 }
Max Biresd255a212018-12-18 17:26:56 -0800304 checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700305
306 if (spec.getKeystoreAlias() == null) {
307 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
308 }
309
310 String jcaKeyAlgorithm;
311 try {
312 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
313 keymasterAlgorithm);
314 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
315 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
316 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
317 spec.getEncryptionPaddings());
Alex Klyubinfdbc02a2015-06-29 14:39:29 -0700318 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
319 && (spec.isRandomizedEncryptionRequired())) {
320 for (int keymasterPadding : mKeymasterEncryptionPaddings) {
321 if (!KeymasterUtils
322 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
323 keymasterPadding)) {
324 throw new InvalidAlgorithmParameterException(
325 "Randomized encryption (IND-CPA) required but may be violated"
326 + " by padding scheme: "
327 + KeyProperties.EncryptionPadding.fromKeymaster(
328 keymasterPadding)
329 + ". See " + KeyGenParameterSpec.class.getName()
330 + " documentation.");
331 }
332 }
333 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700334 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
335 spec.getSignaturePaddings());
336 if (spec.isDigestsSpecified()) {
337 mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
338 } else {
339 mKeymasterDigests = EmptyArray.INT;
340 }
Alex Klyubinb6e62862015-07-06 10:31:07 -0700341
342 // Check that user authentication related parameters are acceptable. This method
343 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
344 // not set up).
Brian Young5437b812018-02-23 18:04:20 +0000345 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
Alex Klyubinb6e62862015-07-06 10:31:07 -0700346 } catch (IllegalArgumentException | IllegalStateException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700347 throw new InvalidAlgorithmParameterException(e);
348 }
349
350 mJcaKeyAlgorithm = jcaKeyAlgorithm;
351 mRng = random;
352 mKeyStore = KeyStore.getInstance();
353 success = true;
354 } finally {
355 if (!success) {
356 resetAll();
357 }
358 }
359 }
360
361 private void resetAll() {
362 mEntryAlias = null;
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700363 mEntryUid = KeyStore.UID_SELF;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700364 mJcaKeyAlgorithm = null;
365 mKeymasterAlgorithm = -1;
366 mKeymasterPurposes = null;
367 mKeymasterBlockModes = null;
368 mKeymasterEncryptionPaddings = null;
369 mKeymasterSignaturePaddings = null;
370 mKeymasterDigests = null;
371 mKeySizeBits = 0;
372 mSpec = null;
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700373 mRSAPublicExponent = null;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700374 mEncryptionAtRestRequired = false;
375 mRng = null;
376 mKeyStore = null;
377 }
378
379 private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
380 AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
381 switch (mKeymasterAlgorithm) {
382 case KeymasterDefs.KM_ALGORITHM_RSA:
383 {
384 BigInteger publicExponent = null;
385 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
386 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
387 if (mKeySizeBits == -1) {
388 mKeySizeBits = rsaSpec.getKeysize();
389 } else if (mKeySizeBits != rsaSpec.getKeysize()) {
390 throw new InvalidAlgorithmParameterException("RSA key size must match "
391 + " between " + mSpec + " and " + algSpecificSpec
392 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
393 }
394 publicExponent = rsaSpec.getPublicExponent();
395 } else if (algSpecificSpec != null) {
396 throw new InvalidAlgorithmParameterException(
397 "RSA may only use RSAKeyGenParameterSpec");
398 }
399 if (publicExponent == null) {
400 publicExponent = RSAKeyGenParameterSpec.F4;
401 }
402 if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
403 throw new InvalidAlgorithmParameterException(
404 "RSA public exponent must be positive: " + publicExponent);
405 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700406 if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700407 throw new InvalidAlgorithmParameterException(
408 "Unsupported RSA public exponent: " + publicExponent
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700409 + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700410 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700411 mRSAPublicExponent = publicExponent;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700412 break;
413 }
414 case KeymasterDefs.KM_ALGORITHM_EC:
415 if (algSpecificSpec instanceof ECGenParameterSpec) {
416 ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
417 String curveName = ecSpec.getName();
418 Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
419 curveName.toLowerCase(Locale.US));
420 if (ecSpecKeySizeBits == null) {
421 throw new InvalidAlgorithmParameterException(
422 "Unsupported EC curve name: " + curveName
423 + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
424 }
425 if (mKeySizeBits == -1) {
426 mKeySizeBits = ecSpecKeySizeBits;
427 } else if (mKeySizeBits != ecSpecKeySizeBits) {
428 throw new InvalidAlgorithmParameterException("EC key size must match "
429 + " between " + mSpec + " and " + algSpecificSpec
430 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
431 }
432 } else if (algSpecificSpec != null) {
433 throw new InvalidAlgorithmParameterException(
434 "EC may only use ECGenParameterSpec");
435 }
436 break;
437 default:
438 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
439 }
440 }
441
Kenny Rootdb026712012-08-20 10:48:46 -0700442 @Override
443 public KeyPair generateKeyPair() {
444 if (mKeyStore == null || mSpec == null) {
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700445 throw new IllegalStateException("Not initialized");
Kenny Rootdb026712012-08-20 10:48:46 -0700446 }
447
Frank Salimea5e0382018-01-23 22:42:29 -0800448 int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700449 if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
Kenny Root2eeda722013-04-10 11:30:58 -0700450 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
451 throw new IllegalStateException(
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700452 "Encryption at rest using secure lock screen credential requested for key pair"
453 + ", but the user has not yet entered the credential");
Kenny Root2eeda722013-04-10 11:30:58 -0700454 }
455
Frank Salimea5e0382018-01-23 22:42:29 -0800456 if (mSpec.isStrongBoxBacked()) {
457 flags |= KeyStore.FLAG_STRONGBOX;
458 }
Rubin Xub3a13e12019-12-24 13:35:02 +0000459 if (mSpec.isCriticalToDeviceEncryption()) {
460 flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
461 }
Frank Salimea5e0382018-01-23 22:42:29 -0800462
Shawn Willden8d8c7472016-02-02 08:27:39 -0700463 byte[] additionalEntropy =
464 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
465 mRng, (mKeySizeBits + 7) / 8);
466
467 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
468 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
469 boolean success = false;
470 try {
471 generateKeystoreKeyPair(
472 privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
473 KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
474
475 storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
476
477 success = true;
478 return keyPair;
Frank Salimb6315032018-03-15 17:33:16 -0700479 } catch (ProviderException e) {
480 if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
481 throw new SecureKeyImportUnavailableException(e);
482 } else {
483 throw e;
484 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700485 } finally {
486 if (!success) {
487 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
488 }
489 }
490 }
491
492 private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
493 throws ProviderException {
494 byte[] challenge = mSpec.getAttestationChallenge();
495 if (challenge != null) {
496 KeymasterArguments args = new KeymasterArguments();
497 args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
498 return getAttestationChain(privateKeyAlias, keyPair, args);
499 }
500
501 // Very short certificate chain in the non-attestation case.
502 return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
503 }
504
505 private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
506 byte[] additionalEntropy, final int flags) throws ProviderException {
507 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
508 int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
509 mEntryUid, flags, resultingKeyCharacteristics);
510 if (errorCode != KeyStore.NO_ERROR) {
Frank Salimea5e0382018-01-23 22:42:29 -0800511 if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
512 throw new StrongBoxUnavailableException("Failed to generate key pair");
513 } else {
514 throw new ProviderException(
515 "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
516 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700517 }
518 }
519
520 private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
521 try {
522 KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
523 mKeyStore, privateKeyAlias, mEntryUid);
524 if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
525 throw new ProviderException(
526 "Generated key pair algorithm does not match requested algorithm: "
527 + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
528 }
529 return result;
Max Bires13f98ce2018-11-02 10:50:40 -0700530 } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
Shawn Willden8d8c7472016-02-02 08:27:39 -0700531 throw new ProviderException("Failed to load generated key pair from keystore", e);
532 }
533 }
534
535 private KeymasterArguments constructKeyGenerationArguments() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700536 KeymasterArguments args = new KeymasterArguments();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700537 args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
538 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
539 args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
540 args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
541 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
542 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
543 args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
Kenny Rootdb026712012-08-20 10:48:46 -0700544
Brian Young5437b812018-02-23 18:04:20 +0000545 KeymasterUtils.addUserAuthArgs(args, mSpec);
Alex Klyubind6c77992015-06-23 12:06:27 -0700546 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
547 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
548 mSpec.getKeyValidityForOriginationEnd());
549 args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
550 mSpec.getKeyValidityForConsumptionEnd());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700551 addAlgorithmSpecificParameters(args);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700552
Shawn Willden8d8c7472016-02-02 08:27:39 -0700553 if (mSpec.isUniqueIdIncluded())
554 args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700555
Shawn Willden8d8c7472016-02-02 08:27:39 -0700556 return args;
557 }
Kenny Rootdb026712012-08-20 10:48:46 -0700558
Shawn Willden8d8c7472016-02-02 08:27:39 -0700559 private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
560 throws ProviderException {
561 Iterator<byte[]> iter = iterable.iterator();
562 storeCertificate(
563 Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
Kenny Rootdb026712012-08-20 10:48:46 -0700564
Shawn Willden8d8c7472016-02-02 08:27:39 -0700565 if (!iter.hasNext()) {
566 return;
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700567 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700568
569 ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
570 while (iter.hasNext()) {
571 byte[] data = iter.next();
572 certificateConcatenationStream.write(data, 0, data.length);
573 }
574
575 storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
576 flags, "Failed to store attestation CA certificate");
577 }
578
579 private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
580 String failureMessage) throws ProviderException {
581 int insertErrorCode = mKeyStore.insert(
582 prefix + mEntryAlias,
583 certificateBytes,
584 mEntryUid,
585 flags);
586 if (insertErrorCode != KeyStore.NO_ERROR) {
587 throw new ProviderException(failureMessage,
588 KeyStore.getKeyStoreException(insertErrorCode));
589 }
590 }
591
592 private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
593 try {
594 return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
595 .getEncoded();
596 } catch (IOException | CertificateParsingException e) {
597 throw new ProviderException("Failed to generate self-signed certificate", e);
598 } catch (CertificateEncodingException e) {
599 throw new ProviderException(
600 "Failed to obtain encoded form of self-signed certificate", e);
601 }
602 }
603
604 private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
605 KeyPair keyPair, KeymasterArguments args)
606 throws ProviderException {
607 KeymasterCertificateChain outChain = new KeymasterCertificateChain();
608 int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
609 if (errorCode != KeyStore.NO_ERROR) {
610 throw new ProviderException("Failed to generate attestation certificate chain",
611 KeyStore.getKeyStoreException(errorCode));
612 }
613 Collection<byte[]> chain = outChain.getCertificates();
614 if (chain.size() < 2) {
615 throw new ProviderException("Attestation certificate chain contained "
616 + chain.size() + " entries. At least two are required.");
617 }
618 return chain;
Kenny Rootdb026712012-08-20 10:48:46 -0700619 }
620
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700621 private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
622 switch (mKeymasterAlgorithm) {
623 case KeymasterDefs.KM_ALGORITHM_RSA:
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700624 keymasterArgs.addUnsignedLong(
625 KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700626 break;
627 case KeymasterDefs.KM_ALGORITHM_EC:
628 break;
629 default:
630 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
631 }
632 }
633
Shawn Willden8d8c7472016-02-02 08:27:39 -0700634 private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
635 PublicKey publicKey) throws CertificateParsingException, IOException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700636 String signatureAlgorithm =
637 getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
638 if (signatureAlgorithm == null) {
639 // Key cannot be used to sign a certificate
640 return generateSelfSignedCertificateWithFakeSignature(publicKey);
641 } else {
642 // Key can be used to sign a certificate
Alex Klyubin856aebe2015-06-23 10:54:44 -0700643 try {
644 return generateSelfSignedCertificateWithValidSignature(
645 privateKey, publicKey, signatureAlgorithm);
646 } catch (Exception e) {
647 // Failed to generate the self-signed certificate with valid signature. Fall back
648 // to generating a self-signed certificate with a fake signature. This is done for
649 // all exception types because we prefer key pair generation to succeed and end up
650 // producing a self-signed certificate with an invalid signature to key pair
651 // generation failing.
652 return generateSelfSignedCertificateWithFakeSignature(publicKey);
653 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700654 }
655 }
656
Alex Klyubin21a76df2015-01-14 13:35:32 -0800657 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700658 private X509Certificate generateSelfSignedCertificateWithValidSignature(
Alex Klyubin856aebe2015-06-23 10:54:44 -0700659 PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800660 final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
661 certGen.setPublicKey(publicKey);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700662 certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
663 certGen.setSubjectDN(mSpec.getCertificateSubject());
664 certGen.setIssuerDN(mSpec.getCertificateSubject());
665 certGen.setNotBefore(mSpec.getCertificateNotBefore());
666 certGen.setNotAfter(mSpec.getCertificateNotAfter());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700667 certGen.setSignatureAlgorithm(signatureAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800668 return certGen.generate(privateKey);
669 }
670
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700671 @SuppressWarnings("deprecation")
672 private X509Certificate generateSelfSignedCertificateWithFakeSignature(
Shawn Willden8d8c7472016-02-02 08:27:39 -0700673 PublicKey publicKey) throws IOException, CertificateParsingException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700674 V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
675 ASN1ObjectIdentifier sigAlgOid;
676 AlgorithmIdentifier sigAlgId;
677 byte[] signature;
678 switch (mKeymasterAlgorithm) {
679 case KeymasterDefs.KM_ALGORITHM_EC:
680 sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
681 sigAlgId = new AlgorithmIdentifier(sigAlgOid);
682 ASN1EncodableVector v = new ASN1EncodableVector();
683 v.add(new DERInteger(0));
684 v.add(new DERInteger(0));
685 signature = new DERSequence().getEncoded();
686 break;
687 case KeymasterDefs.KM_ALGORITHM_RSA:
688 sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
689 sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
690 signature = new byte[1];
691 break;
692 default:
693 throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800694 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700695
696 try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
697 tbsGenerator.setSubjectPublicKeyInfo(
698 SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
699 }
700 tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
701 X509Principal subject =
702 new X509Principal(mSpec.getCertificateSubject().getEncoded());
703 tbsGenerator.setSubject(subject);
704 tbsGenerator.setIssuer(subject);
705 tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
706 tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
707 tbsGenerator.setSignature(sigAlgId);
708 TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
709
710 ASN1EncodableVector result = new ASN1EncodableVector();
711 result.add(tbsCertificate);
712 result.add(sigAlgId);
713 result.add(new DERBitString(signature));
714 return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
Alex Klyubin21a76df2015-01-14 13:35:32 -0800715 }
716
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700717 private static int getDefaultKeySize(int keymasterAlgorithm) {
718 switch (keymasterAlgorithm) {
719 case KeymasterDefs.KM_ALGORITHM_EC:
720 return EC_DEFAULT_KEY_SIZE;
721 case KeymasterDefs.KM_ALGORITHM_RSA:
722 return RSA_DEFAULT_KEY_SIZE;
723 default:
724 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800725 }
Alex Klyubin21a76df2015-01-14 13:35:32 -0800726 }
727
Max Biresd255a212018-12-18 17:26:56 -0800728 private static void checkValidKeySize(
729 int keymasterAlgorithm,
730 int keySize,
731 boolean isStrongBoxBacked)
Alex Klyubin21a76df2015-01-14 13:35:32 -0800732 throws InvalidAlgorithmParameterException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700733 switch (keymasterAlgorithm) {
734 case KeymasterDefs.KM_ALGORITHM_EC:
Max Biresd255a212018-12-18 17:26:56 -0800735 if (isStrongBoxBacked && keySize != 256) {
736 throw new InvalidAlgorithmParameterException(
737 "Unsupported StrongBox EC key size: "
738 + keySize + " bits. Supported: 256");
739 }
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700740 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
741 throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
742 + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
Kenny Rootf64386f2013-08-16 14:03:29 -0700743 }
744 break;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700745 case KeymasterDefs.KM_ALGORITHM_RSA:
746 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
747 throw new InvalidAlgorithmParameterException("RSA key size must be >= "
748 + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
749 }
750 break;
751 default:
752 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Kenny Rootf64386f2013-08-16 14:03:29 -0700753 }
Kenny Rootf64386f2013-08-16 14:03:29 -0700754 }
755
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700756 /**
757 * Returns the {@code Signature} algorithm to be used for signing a certificate using the
758 * specified key or {@code null} if the key cannot be used for signing a certificate.
759 */
760 @Nullable
761 private static String getCertificateSignatureAlgorithm(
762 int keymasterAlgorithm,
763 int keySizeBits,
764 KeyGenParameterSpec spec) {
765 // Constraints:
Alex Klyubinf78dd672015-06-15 15:16:09 -0700766 // 1. Key must be authorized for signing without user authentication.
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700767 // 2. Signature digest must be one of key's authorized digests.
Alex Klyubin6e90ade2015-06-22 13:21:59 -0700768 // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
769 // of RSA PKCS#1 signature padding scheme (about 30 bytes).
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700770 // 4. For EC keys, the there is no point in using a digest whose output size is longer than
771 // key/field size because the digest will be truncated to that size.
Kenny Rootdb026712012-08-20 10:48:46 -0700772
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700773 if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
774 // Key not authorized for signing
775 return null;
Kenny Rootdb026712012-08-20 10:48:46 -0700776 }
Alex Klyubinf78dd672015-06-15 15:16:09 -0700777 if (spec.isUserAuthenticationRequired()) {
778 // Key not authorized for use without user authentication
779 return null;
780 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700781 if (!spec.isDigestsSpecified()) {
782 // Key not authorized for any digests -- can't sign
783 return null;
784 }
785 switch (keymasterAlgorithm) {
786 case KeymasterDefs.KM_ALGORITHM_EC:
787 {
788 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
789 spec.getDigests(),
790 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
Kenny Rootdb026712012-08-20 10:48:46 -0700791
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700792 int bestKeymasterDigest = -1;
793 int bestDigestOutputSizeBits = -1;
794 for (int keymasterDigest : availableKeymasterDigests) {
795 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
796 if (outputSizeBits == keySizeBits) {
797 // Perfect match -- use this digest
798 bestKeymasterDigest = keymasterDigest;
799 bestDigestOutputSizeBits = outputSizeBits;
800 break;
801 }
802 // Not a perfect match -- check against the best digest so far
803 if (bestKeymasterDigest == -1) {
804 // First digest tested -- definitely the best so far
805 bestKeymasterDigest = keymasterDigest;
806 bestDigestOutputSizeBits = outputSizeBits;
807 } else {
808 // Prefer output size to be as close to key size as possible, with output
809 // sizes larger than key size preferred to those smaller than key size.
810 if (bestDigestOutputSizeBits < keySizeBits) {
811 // Output size of the best digest so far is smaller than key size.
812 // Anything larger is a win.
813 if (outputSizeBits > bestDigestOutputSizeBits) {
814 bestKeymasterDigest = keymasterDigest;
815 bestDigestOutputSizeBits = outputSizeBits;
816 }
817 } else {
818 // Output size of the best digest so far is larger than key size.
819 // Anything smaller is a win, as long as it's not smaller than key size.
820 if ((outputSizeBits < bestDigestOutputSizeBits)
821 && (outputSizeBits >= keySizeBits)) {
822 bestKeymasterDigest = keymasterDigest;
823 bestDigestOutputSizeBits = outputSizeBits;
824 }
825 }
826 }
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700827 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700828 if (bestKeymasterDigest == -1) {
829 return null;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700830 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700831 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
832 bestKeymasterDigest) + "WithECDSA";
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700833 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700834 case KeymasterDefs.KM_ALGORITHM_RSA:
835 {
Alex Klyubin7c475cc2015-06-12 12:16:45 -0700836 // Check whether this key is authorized for PKCS#1 signature padding.
837 // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
838 // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
839 // to be authorized for PKCS#1 padding or padding NONE which means any padding.
Alex Klyubine4928a22015-07-21 13:38:48 -0700840 boolean pkcs1SignaturePaddingSupported =
841 com.android.internal.util.ArrayUtils.contains(
842 KeyProperties.SignaturePadding.allToKeymaster(
843 spec.getSignaturePaddings()),
844 KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
Alex Klyubin7c475cc2015-06-12 12:16:45 -0700845 if (!pkcs1SignaturePaddingSupported) {
846 // Key not authorized for PKCS#1 signature padding -- can't sign
847 return null;
848 }
849
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700850 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
851 spec.getDigests(),
852 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
853
Alex Klyubin6e90ade2015-06-22 13:21:59 -0700854 // The amount of space available for the digest is less than modulus size by about
855 // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
856 // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
857 // overhead (depending the on chosen digest) for encoding digest OID and digest
858 // value in DER.
859 int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700860 int bestKeymasterDigest = -1;
861 int bestDigestOutputSizeBits = -1;
862 for (int keymasterDigest : availableKeymasterDigests) {
863 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
864 if (outputSizeBits > maxDigestOutputSizeBits) {
865 // Digest too long (signature generation will fail) -- skip
866 continue;
867 }
868 if (bestKeymasterDigest == -1) {
869 // First digest tested -- definitely the best so far
870 bestKeymasterDigest = keymasterDigest;
871 bestDigestOutputSizeBits = outputSizeBits;
872 } else {
873 // The longer the better
874 if (outputSizeBits > bestDigestOutputSizeBits) {
875 bestKeymasterDigest = keymasterDigest;
876 bestDigestOutputSizeBits = outputSizeBits;
877 }
878 }
879 }
880 if (bestKeymasterDigest == -1) {
881 return null;
882 }
883 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
884 bestKeymasterDigest) + "WithRSA";
885 }
886 default:
887 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
888 }
889 }
890
891 private static Set<Integer> getAvailableKeymasterSignatureDigests(
892 @KeyProperties.DigestEnum String[] authorizedKeyDigests,
893 @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
894 Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
895 for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
896 authorizedKeymasterKeyDigests.add(keymasterDigest);
897 }
898 Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
899 for (int keymasterDigest
900 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
901 supportedKeymasterSignatureDigests.add(keymasterDigest);
902 }
Alex Klyubine4928a22015-07-21 13:38:48 -0700903 Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
904 result.retainAll(authorizedKeymasterKeyDigests);
905 return result;
Kenny Rootdb026712012-08-20 10:48:46 -0700906 }
907}