blob: dba3949ba98f91c3fc5a90b2dafbfa981fac5b20 [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;
Rubin Xu59ced282017-01-30 23:39:12 +000021import android.security.GateKeeper;
Alex Klyubindcdaf872015-05-13 15:57:09 -070022import android.security.KeyPairGeneratorSpec;
23import android.security.KeyStore;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070024import android.security.keymaster.KeyCharacteristics;
25import android.security.keymaster.KeymasterArguments;
Shawn Willden8d8c7472016-02-02 08:27:39 -070026import android.security.keymaster.KeymasterCertificateChain;
Alex Klyubin4350bab2015-06-08 10:14:58 -070027import android.security.keymaster.KeymasterDefs;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070028
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070029import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
30import com.android.org.bouncycastle.asn1.ASN1InputStream;
31import com.android.org.bouncycastle.asn1.ASN1Integer;
32import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
33import com.android.org.bouncycastle.asn1.DERBitString;
34import com.android.org.bouncycastle.asn1.DERInteger;
35import com.android.org.bouncycastle.asn1.DERNull;
36import com.android.org.bouncycastle.asn1.DERSequence;
37import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
38import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
39import com.android.org.bouncycastle.asn1.x509.Certificate;
40import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
41import com.android.org.bouncycastle.asn1.x509.TBSCertificate;
42import com.android.org.bouncycastle.asn1.x509.Time;
43import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
44import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
45import com.android.org.bouncycastle.jce.X509Principal;
46import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
Kenny Rootdb026712012-08-20 10:48:46 -070047import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
Kenny Rootdb026712012-08-20 10:48:46 -070048
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070049import libcore.util.EmptyArray;
50
Shawn Willden8d8c7472016-02-02 08:27:39 -070051import java.io.ByteArrayOutputStream;
52import java.io.IOException;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070053import java.math.BigInteger;
Kenny Rootdb026712012-08-20 10:48:46 -070054import java.security.InvalidAlgorithmParameterException;
Kenny Rootdb026712012-08-20 10:48:46 -070055import java.security.KeyPair;
56import java.security.KeyPairGenerator;
57import java.security.KeyPairGeneratorSpi;
Kenny Rootdb026712012-08-20 10:48:46 -070058import java.security.PrivateKey;
Alex Klyubin4350bab2015-06-08 10:14:58 -070059import java.security.ProviderException;
Kenny Rootdb026712012-08-20 10:48:46 -070060import java.security.PublicKey;
61import java.security.SecureRandom;
Alex Klyubin4a0ff7c2015-06-09 13:25:20 -070062import java.security.UnrecoverableKeyException;
Kenny Rootdb026712012-08-20 10:48:46 -070063import java.security.cert.CertificateEncodingException;
Shawn Willden8d8c7472016-02-02 08:27:39 -070064import java.security.cert.CertificateParsingException;
Kenny Rootdb026712012-08-20 10:48:46 -070065import java.security.cert.X509Certificate;
66import java.security.spec.AlgorithmParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070067import java.security.spec.ECGenParameterSpec;
Kenny Rootf64386f2013-08-16 14:03:29 -070068import java.security.spec.RSAKeyGenParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070069import java.util.ArrayList;
Shawn Willden8d8c7472016-02-02 08:27:39 -070070import java.util.Collection;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070071import java.util.Collections;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070072import java.util.HashMap;
73import java.util.HashSet;
Shawn Willden8d8c7472016-02-02 08:27:39 -070074import java.util.Iterator;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070075import java.util.List;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070076import java.util.Locale;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070077import java.util.Map;
78import java.util.Set;
Kenny Rootdb026712012-08-20 10:48:46 -070079
80/**
81 * Provides a way to create instances of a KeyPair which will be placed in the
82 * Android keystore service usable only by the application that called it. This
83 * can be used in conjunction with
84 * {@link java.security.KeyStore#getInstance(String)} using the
85 * {@code "AndroidKeyStore"} type.
86 * <p>
87 * This class can not be directly instantiated and must instead be used via the
88 * {@link KeyPairGenerator#getInstance(String)
Alex Klyubine21f0232015-05-19 09:41:17 -070089 * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
Kenny Rootdb026712012-08-20 10:48:46 -070090 *
Alex Klyubine21f0232015-05-19 09:41:17 -070091 * @hide
Kenny Rootdb026712012-08-20 10:48:46 -070092 */
Alex Klyubine21f0232015-05-19 09:41:17 -070093public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -080094
Alex Klyubine21f0232015-05-19 09:41:17 -070095 public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -080096 public RSA() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070097 super(KeymasterDefs.KM_ALGORITHM_RSA);
Alex Klyubin21a76df2015-01-14 13:35:32 -080098 }
99 }
100
Alex Klyubine21f0232015-05-19 09:41:17 -0700101 public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800102 public EC() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700103 super(KeymasterDefs.KM_ALGORITHM_EC);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800104 }
105 }
106
107 /*
108 * These must be kept in sync with system/security/keystore/defaults.h
109 */
110
111 /* EC */
112 private static final int EC_DEFAULT_KEY_SIZE = 256;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800113
114 /* RSA */
115 private static final int RSA_DEFAULT_KEY_SIZE = 2048;
116 private static final int RSA_MIN_KEY_SIZE = 512;
117 private static final int RSA_MAX_KEY_SIZE = 8192;
118
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700119 private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
120 new HashMap<String, Integer>();
121 private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700122 private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700123 static {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700124 // Aliases for NIST P-224
125 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
126 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
127
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700128
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700129 // Aliases for NIST P-256
130 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
131 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
132 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
133
134 // Aliases for NIST P-384
135 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
136 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
137
138 // Aliases for NIST P-521
139 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
140 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
141
142 SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
143 Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700144
145 SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
146 new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
147 Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700148 }
Alex Klyubin4a0ff7c2015-06-09 13:25:20 -0700149
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700150 private final int mOriginalKeymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800151
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700152 private KeyStore mKeyStore;
Kenny Rootdb026712012-08-20 10:48:46 -0700153
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700154 private KeyGenParameterSpec mSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700155
156 private String mEntryAlias;
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700157 private int mEntryUid;
Alex Klyubin96481c32015-05-15 10:47:18 -0700158 private boolean mEncryptionAtRestRequired;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700159 private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
160 private int mKeymasterAlgorithm = -1;
161 private int mKeySizeBits;
162 private SecureRandom mRng;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800163
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700164 private int[] mKeymasterPurposes;
165 private int[] mKeymasterBlockModes;
166 private int[] mKeymasterEncryptionPaddings;
167 private int[] mKeymasterSignaturePaddings;
168 private int[] mKeymasterDigests;
169
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700170 private BigInteger mRSAPublicExponent;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700171
172 protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
173 mOriginalKeymasterAlgorithm = keymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800174 }
175
Shawn Willden8d8c7472016-02-02 08:27:39 -0700176 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700177 @Override
178 public void initialize(int keysize, SecureRandom random) {
179 throw new IllegalArgumentException(
180 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
181 + " required to initialize this KeyPairGenerator");
Alex Klyubin21a76df2015-01-14 13:35:32 -0800182 }
Kenny Rootdb026712012-08-20 10:48:46 -0700183
Shawn Willden8d8c7472016-02-02 08:27:39 -0700184 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700185 @Override
186 public void initialize(AlgorithmParameterSpec params, SecureRandom random)
187 throws InvalidAlgorithmParameterException {
188 resetAll();
189
190 boolean success = false;
191 try {
192 if (params == null) {
193 throw new InvalidAlgorithmParameterException(
194 "Must supply params of type " + KeyGenParameterSpec.class.getName()
195 + " or " + KeyPairGeneratorSpec.class.getName());
196 }
197
198 KeyGenParameterSpec spec;
199 boolean encryptionAtRestRequired = false;
200 int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
201 if (params instanceof KeyGenParameterSpec) {
202 spec = (KeyGenParameterSpec) params;
203 } else if (params instanceof KeyPairGeneratorSpec) {
204 // Legacy/deprecated spec
205 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
206 try {
207 KeyGenParameterSpec.Builder specBuilder;
208 String specKeyAlgorithm = legacySpec.getKeyType();
209 if (specKeyAlgorithm != null) {
210 // Spec overrides the generator's default key algorithm
211 try {
212 keymasterAlgorithm =
213 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
214 specKeyAlgorithm);
215 } catch (IllegalArgumentException e) {
216 throw new InvalidAlgorithmParameterException(
217 "Invalid key type in parameters", e);
218 }
219 }
220 switch (keymasterAlgorithm) {
221 case KeymasterDefs.KM_ALGORITHM_EC:
222 specBuilder = new KeyGenParameterSpec.Builder(
223 legacySpec.getKeystoreAlias(),
224 KeyProperties.PURPOSE_SIGN
225 | KeyProperties.PURPOSE_VERIFY);
Alex Klyubindcf3d352015-06-11 14:44:46 -0700226 // Authorized to be used with any digest (including no digest).
Alex Klyubine4928a22015-07-21 13:38:48 -0700227 // MD5 was never offered for Android Keystore for ECDSA.
228 specBuilder.setDigests(
229 KeyProperties.DIGEST_NONE,
230 KeyProperties.DIGEST_SHA1,
231 KeyProperties.DIGEST_SHA224,
232 KeyProperties.DIGEST_SHA256,
233 KeyProperties.DIGEST_SHA384,
234 KeyProperties.DIGEST_SHA512);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700235 break;
236 case KeymasterDefs.KM_ALGORITHM_RSA:
237 specBuilder = new KeyGenParameterSpec.Builder(
238 legacySpec.getKeystoreAlias(),
239 KeyProperties.PURPOSE_ENCRYPT
240 | KeyProperties.PURPOSE_DECRYPT
241 | KeyProperties.PURPOSE_SIGN
242 | KeyProperties.PURPOSE_VERIFY);
Alex Klyubindcf3d352015-06-11 14:44:46 -0700243 // Authorized to be used with any digest (including no digest).
Alex Klyubine4928a22015-07-21 13:38:48 -0700244 specBuilder.setDigests(
245 KeyProperties.DIGEST_NONE,
246 KeyProperties.DIGEST_MD5,
247 KeyProperties.DIGEST_SHA1,
248 KeyProperties.DIGEST_SHA224,
249 KeyProperties.DIGEST_SHA256,
250 KeyProperties.DIGEST_SHA384,
251 KeyProperties.DIGEST_SHA512);
Alex Klyubin2e3aaa72015-06-17 13:58:00 -0700252 // Authorized to be used with any encryption and signature padding
Alex Klyubine4928a22015-07-21 13:38:48 -0700253 // schemes (including no padding).
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700254 specBuilder.setEncryptionPaddings(
Alex Klyubine4928a22015-07-21 13:38:48 -0700255 KeyProperties.ENCRYPTION_PADDING_NONE,
256 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
257 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
258 specBuilder.setSignaturePaddings(
259 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
260 KeyProperties.SIGNATURE_PADDING_RSA_PSS);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700261 // Disable randomized encryption requirement to support encryption
262 // padding NONE above.
263 specBuilder.setRandomizedEncryptionRequired(false);
264 break;
265 default:
266 throw new ProviderException(
267 "Unsupported algorithm: " + mKeymasterAlgorithm);
268 }
269
270 if (legacySpec.getKeySize() != -1) {
271 specBuilder.setKeySize(legacySpec.getKeySize());
272 }
273 if (legacySpec.getAlgorithmParameterSpec() != null) {
274 specBuilder.setAlgorithmParameterSpec(
275 legacySpec.getAlgorithmParameterSpec());
276 }
277 specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
278 specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
279 specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
280 specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
281 encryptionAtRestRequired = legacySpec.isEncryptionRequired();
282 specBuilder.setUserAuthenticationRequired(false);
283
284 spec = specBuilder.build();
285 } catch (NullPointerException | IllegalArgumentException e) {
286 throw new InvalidAlgorithmParameterException(e);
287 }
288 } else {
289 throw new InvalidAlgorithmParameterException(
290 "Unsupported params class: " + params.getClass().getName()
291 + ". Supported: " + KeyGenParameterSpec.class.getName()
292 + ", " + KeyPairGeneratorSpec.class.getName());
293 }
294
295 mEntryAlias = spec.getKeystoreAlias();
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700296 mEntryUid = spec.getUid();
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700297 mSpec = spec;
298 mKeymasterAlgorithm = keymasterAlgorithm;
299 mEncryptionAtRestRequired = encryptionAtRestRequired;
300 mKeySizeBits = spec.getKeySize();
301 initAlgorithmSpecificParameters();
302 if (mKeySizeBits == -1) {
303 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
304 }
305 checkValidKeySize(keymasterAlgorithm, mKeySizeBits);
306
307 if (spec.getKeystoreAlias() == null) {
308 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
309 }
310
311 String jcaKeyAlgorithm;
312 try {
313 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
314 keymasterAlgorithm);
315 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
316 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
317 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
318 spec.getEncryptionPaddings());
Alex Klyubinfdbc02a2015-06-29 14:39:29 -0700319 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
320 && (spec.isRandomizedEncryptionRequired())) {
321 for (int keymasterPadding : mKeymasterEncryptionPaddings) {
322 if (!KeymasterUtils
323 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
324 keymasterPadding)) {
325 throw new InvalidAlgorithmParameterException(
326 "Randomized encryption (IND-CPA) required but may be violated"
327 + " by padding scheme: "
328 + KeyProperties.EncryptionPadding.fromKeymaster(
329 keymasterPadding)
330 + ". See " + KeyGenParameterSpec.class.getName()
331 + " documentation.");
332 }
333 }
334 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700335 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
336 spec.getSignaturePaddings());
337 if (spec.isDigestsSpecified()) {
338 mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
339 } else {
340 mKeymasterDigests = EmptyArray.INT;
341 }
Alex Klyubinb6e62862015-07-06 10:31:07 -0700342
343 // Check that user authentication related parameters are acceptable. This method
344 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
345 // not set up).
346 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
347 mSpec.isUserAuthenticationRequired(),
Shawn Willdenadef4962016-01-29 07:07:16 -0700348 mSpec.getUserAuthenticationValidityDurationSeconds(),
Shawn Willdenc38eae52016-02-22 23:28:34 +0000349 mSpec.isUserAuthenticationValidWhileOnBody(),
Rubin Xu59ced282017-01-30 23:39:12 +0000350 mSpec.isInvalidatedByBiometricEnrollment(),
351 GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
Alex Klyubinb6e62862015-07-06 10:31:07 -0700352 } catch (IllegalArgumentException | IllegalStateException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700353 throw new InvalidAlgorithmParameterException(e);
354 }
355
356 mJcaKeyAlgorithm = jcaKeyAlgorithm;
357 mRng = random;
358 mKeyStore = KeyStore.getInstance();
359 success = true;
360 } finally {
361 if (!success) {
362 resetAll();
363 }
364 }
365 }
366
367 private void resetAll() {
368 mEntryAlias = null;
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700369 mEntryUid = KeyStore.UID_SELF;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700370 mJcaKeyAlgorithm = null;
371 mKeymasterAlgorithm = -1;
372 mKeymasterPurposes = null;
373 mKeymasterBlockModes = null;
374 mKeymasterEncryptionPaddings = null;
375 mKeymasterSignaturePaddings = null;
376 mKeymasterDigests = null;
377 mKeySizeBits = 0;
378 mSpec = null;
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700379 mRSAPublicExponent = null;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700380 mEncryptionAtRestRequired = false;
381 mRng = null;
382 mKeyStore = null;
383 }
384
385 private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
386 AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
387 switch (mKeymasterAlgorithm) {
388 case KeymasterDefs.KM_ALGORITHM_RSA:
389 {
390 BigInteger publicExponent = null;
391 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
392 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
393 if (mKeySizeBits == -1) {
394 mKeySizeBits = rsaSpec.getKeysize();
395 } else if (mKeySizeBits != rsaSpec.getKeysize()) {
396 throw new InvalidAlgorithmParameterException("RSA key size must match "
397 + " between " + mSpec + " and " + algSpecificSpec
398 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
399 }
400 publicExponent = rsaSpec.getPublicExponent();
401 } else if (algSpecificSpec != null) {
402 throw new InvalidAlgorithmParameterException(
403 "RSA may only use RSAKeyGenParameterSpec");
404 }
405 if (publicExponent == null) {
406 publicExponent = RSAKeyGenParameterSpec.F4;
407 }
408 if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
409 throw new InvalidAlgorithmParameterException(
410 "RSA public exponent must be positive: " + publicExponent);
411 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700412 if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700413 throw new InvalidAlgorithmParameterException(
414 "Unsupported RSA public exponent: " + publicExponent
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700415 + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700416 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700417 mRSAPublicExponent = publicExponent;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700418 break;
419 }
420 case KeymasterDefs.KM_ALGORITHM_EC:
421 if (algSpecificSpec instanceof ECGenParameterSpec) {
422 ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
423 String curveName = ecSpec.getName();
424 Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
425 curveName.toLowerCase(Locale.US));
426 if (ecSpecKeySizeBits == null) {
427 throw new InvalidAlgorithmParameterException(
428 "Unsupported EC curve name: " + curveName
429 + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
430 }
431 if (mKeySizeBits == -1) {
432 mKeySizeBits = ecSpecKeySizeBits;
433 } else if (mKeySizeBits != ecSpecKeySizeBits) {
434 throw new InvalidAlgorithmParameterException("EC key size must match "
435 + " between " + mSpec + " and " + algSpecificSpec
436 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
437 }
438 } else if (algSpecificSpec != null) {
439 throw new InvalidAlgorithmParameterException(
440 "EC may only use ECGenParameterSpec");
441 }
442 break;
443 default:
444 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
445 }
446 }
447
Kenny Rootdb026712012-08-20 10:48:46 -0700448 @Override
449 public KeyPair generateKeyPair() {
450 if (mKeyStore == null || mSpec == null) {
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700451 throw new IllegalStateException("Not initialized");
Kenny Rootdb026712012-08-20 10:48:46 -0700452 }
453
Alex Klyubin96481c32015-05-15 10:47:18 -0700454 final int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700455 if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
Kenny Root2eeda722013-04-10 11:30:58 -0700456 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
457 throw new IllegalStateException(
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700458 "Encryption at rest using secure lock screen credential requested for key pair"
459 + ", but the user has not yet entered the credential");
Kenny Root2eeda722013-04-10 11:30:58 -0700460 }
461
Shawn Willden8d8c7472016-02-02 08:27:39 -0700462 byte[] additionalEntropy =
463 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
464 mRng, (mKeySizeBits + 7) / 8);
465
466 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
467 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
468 boolean success = false;
469 try {
470 generateKeystoreKeyPair(
471 privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
472 KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
473
474 storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
475
476 success = true;
477 return keyPair;
478 } finally {
479 if (!success) {
480 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
481 }
482 }
483 }
484
485 private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
486 throws ProviderException {
487 byte[] challenge = mSpec.getAttestationChallenge();
488 if (challenge != null) {
489 KeymasterArguments args = new KeymasterArguments();
490 args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
491 return getAttestationChain(privateKeyAlias, keyPair, args);
492 }
493
494 // Very short certificate chain in the non-attestation case.
495 return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
496 }
497
498 private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
499 byte[] additionalEntropy, final int flags) throws ProviderException {
500 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
501 int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
502 mEntryUid, flags, resultingKeyCharacteristics);
503 if (errorCode != KeyStore.NO_ERROR) {
504 throw new ProviderException(
505 "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
506 }
507 }
508
509 private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
510 try {
511 KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
512 mKeyStore, privateKeyAlias, mEntryUid);
513 if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
514 throw new ProviderException(
515 "Generated key pair algorithm does not match requested algorithm: "
516 + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
517 }
518 return result;
519 } catch (UnrecoverableKeyException e) {
520 throw new ProviderException("Failed to load generated key pair from keystore", e);
521 }
522 }
523
524 private KeymasterArguments constructKeyGenerationArguments() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700525 KeymasterArguments args = new KeymasterArguments();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700526 args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
527 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
528 args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
529 args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
530 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
531 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
532 args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
Kenny Rootdb026712012-08-20 10:48:46 -0700533
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700534 KeymasterUtils.addUserAuthArgs(args,
535 mSpec.isUserAuthenticationRequired(),
Shawn Willdenadef4962016-01-29 07:07:16 -0700536 mSpec.getUserAuthenticationValidityDurationSeconds(),
Shawn Willdenc38eae52016-02-22 23:28:34 +0000537 mSpec.isUserAuthenticationValidWhileOnBody(),
Rubin Xu59ced282017-01-30 23:39:12 +0000538 mSpec.isInvalidatedByBiometricEnrollment(),
539 GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
Alex Klyubind6c77992015-06-23 12:06:27 -0700540 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
541 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
542 mSpec.getKeyValidityForOriginationEnd());
543 args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
544 mSpec.getKeyValidityForConsumptionEnd());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700545 addAlgorithmSpecificParameters(args);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700546
Shawn Willden8d8c7472016-02-02 08:27:39 -0700547 if (mSpec.isUniqueIdIncluded())
548 args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700549
Shawn Willden8d8c7472016-02-02 08:27:39 -0700550 return args;
551 }
Kenny Rootdb026712012-08-20 10:48:46 -0700552
Shawn Willden8d8c7472016-02-02 08:27:39 -0700553 private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
554 throws ProviderException {
555 Iterator<byte[]> iter = iterable.iterator();
556 storeCertificate(
557 Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
Kenny Rootdb026712012-08-20 10:48:46 -0700558
Shawn Willden8d8c7472016-02-02 08:27:39 -0700559 if (!iter.hasNext()) {
560 return;
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700561 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700562
563 ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
564 while (iter.hasNext()) {
565 byte[] data = iter.next();
566 certificateConcatenationStream.write(data, 0, data.length);
567 }
568
569 storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
570 flags, "Failed to store attestation CA certificate");
571 }
572
573 private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
574 String failureMessage) throws ProviderException {
575 int insertErrorCode = mKeyStore.insert(
576 prefix + mEntryAlias,
577 certificateBytes,
578 mEntryUid,
579 flags);
580 if (insertErrorCode != KeyStore.NO_ERROR) {
581 throw new ProviderException(failureMessage,
582 KeyStore.getKeyStoreException(insertErrorCode));
583 }
584 }
585
586 private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
587 try {
588 return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
589 .getEncoded();
590 } catch (IOException | CertificateParsingException e) {
591 throw new ProviderException("Failed to generate self-signed certificate", e);
592 } catch (CertificateEncodingException e) {
593 throw new ProviderException(
594 "Failed to obtain encoded form of self-signed certificate", e);
595 }
596 }
597
598 private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
599 KeyPair keyPair, KeymasterArguments args)
600 throws ProviderException {
601 KeymasterCertificateChain outChain = new KeymasterCertificateChain();
602 int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
603 if (errorCode != KeyStore.NO_ERROR) {
604 throw new ProviderException("Failed to generate attestation certificate chain",
605 KeyStore.getKeyStoreException(errorCode));
606 }
607 Collection<byte[]> chain = outChain.getCertificates();
608 if (chain.size() < 2) {
609 throw new ProviderException("Attestation certificate chain contained "
610 + chain.size() + " entries. At least two are required.");
611 }
612 return chain;
Kenny Rootdb026712012-08-20 10:48:46 -0700613 }
614
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700615 private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
616 switch (mKeymasterAlgorithm) {
617 case KeymasterDefs.KM_ALGORITHM_RSA:
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700618 keymasterArgs.addUnsignedLong(
619 KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700620 break;
621 case KeymasterDefs.KM_ALGORITHM_EC:
622 break;
623 default:
624 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
625 }
626 }
627
Shawn Willden8d8c7472016-02-02 08:27:39 -0700628 private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
629 PublicKey publicKey) throws CertificateParsingException, IOException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700630 String signatureAlgorithm =
631 getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
632 if (signatureAlgorithm == null) {
633 // Key cannot be used to sign a certificate
634 return generateSelfSignedCertificateWithFakeSignature(publicKey);
635 } else {
636 // Key can be used to sign a certificate
Alex Klyubin856aebe2015-06-23 10:54:44 -0700637 try {
638 return generateSelfSignedCertificateWithValidSignature(
639 privateKey, publicKey, signatureAlgorithm);
640 } catch (Exception e) {
641 // Failed to generate the self-signed certificate with valid signature. Fall back
642 // to generating a self-signed certificate with a fake signature. This is done for
643 // all exception types because we prefer key pair generation to succeed and end up
644 // producing a self-signed certificate with an invalid signature to key pair
645 // generation failing.
646 return generateSelfSignedCertificateWithFakeSignature(publicKey);
647 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700648 }
649 }
650
Alex Klyubin21a76df2015-01-14 13:35:32 -0800651 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700652 private X509Certificate generateSelfSignedCertificateWithValidSignature(
Alex Klyubin856aebe2015-06-23 10:54:44 -0700653 PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800654 final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
655 certGen.setPublicKey(publicKey);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700656 certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
657 certGen.setSubjectDN(mSpec.getCertificateSubject());
658 certGen.setIssuerDN(mSpec.getCertificateSubject());
659 certGen.setNotBefore(mSpec.getCertificateNotBefore());
660 certGen.setNotAfter(mSpec.getCertificateNotAfter());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700661 certGen.setSignatureAlgorithm(signatureAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800662 return certGen.generate(privateKey);
663 }
664
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700665 @SuppressWarnings("deprecation")
666 private X509Certificate generateSelfSignedCertificateWithFakeSignature(
Shawn Willden8d8c7472016-02-02 08:27:39 -0700667 PublicKey publicKey) throws IOException, CertificateParsingException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700668 V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
669 ASN1ObjectIdentifier sigAlgOid;
670 AlgorithmIdentifier sigAlgId;
671 byte[] signature;
672 switch (mKeymasterAlgorithm) {
673 case KeymasterDefs.KM_ALGORITHM_EC:
674 sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
675 sigAlgId = new AlgorithmIdentifier(sigAlgOid);
676 ASN1EncodableVector v = new ASN1EncodableVector();
677 v.add(new DERInteger(0));
678 v.add(new DERInteger(0));
679 signature = new DERSequence().getEncoded();
680 break;
681 case KeymasterDefs.KM_ALGORITHM_RSA:
682 sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
683 sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
684 signature = new byte[1];
685 break;
686 default:
687 throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800688 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700689
690 try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
691 tbsGenerator.setSubjectPublicKeyInfo(
692 SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
693 }
694 tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
695 X509Principal subject =
696 new X509Principal(mSpec.getCertificateSubject().getEncoded());
697 tbsGenerator.setSubject(subject);
698 tbsGenerator.setIssuer(subject);
699 tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
700 tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
701 tbsGenerator.setSignature(sigAlgId);
702 TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
703
704 ASN1EncodableVector result = new ASN1EncodableVector();
705 result.add(tbsCertificate);
706 result.add(sigAlgId);
707 result.add(new DERBitString(signature));
708 return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
Alex Klyubin21a76df2015-01-14 13:35:32 -0800709 }
710
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700711 private static int getDefaultKeySize(int keymasterAlgorithm) {
712 switch (keymasterAlgorithm) {
713 case KeymasterDefs.KM_ALGORITHM_EC:
714 return EC_DEFAULT_KEY_SIZE;
715 case KeymasterDefs.KM_ALGORITHM_RSA:
716 return RSA_DEFAULT_KEY_SIZE;
717 default:
718 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800719 }
Alex Klyubin21a76df2015-01-14 13:35:32 -0800720 }
721
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700722 private static void checkValidKeySize(int keymasterAlgorithm, int keySize)
Alex Klyubin21a76df2015-01-14 13:35:32 -0800723 throws InvalidAlgorithmParameterException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700724 switch (keymasterAlgorithm) {
725 case KeymasterDefs.KM_ALGORITHM_EC:
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700726 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
727 throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
728 + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
Kenny Rootf64386f2013-08-16 14:03:29 -0700729 }
730 break;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700731 case KeymasterDefs.KM_ALGORITHM_RSA:
732 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
733 throw new InvalidAlgorithmParameterException("RSA key size must be >= "
734 + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
735 }
736 break;
737 default:
738 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Kenny Rootf64386f2013-08-16 14:03:29 -0700739 }
Kenny Rootf64386f2013-08-16 14:03:29 -0700740 }
741
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700742 /**
743 * Returns the {@code Signature} algorithm to be used for signing a certificate using the
744 * specified key or {@code null} if the key cannot be used for signing a certificate.
745 */
746 @Nullable
747 private static String getCertificateSignatureAlgorithm(
748 int keymasterAlgorithm,
749 int keySizeBits,
750 KeyGenParameterSpec spec) {
751 // Constraints:
Alex Klyubinf78dd672015-06-15 15:16:09 -0700752 // 1. Key must be authorized for signing without user authentication.
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700753 // 2. Signature digest must be one of key's authorized digests.
Alex Klyubin6e90ade2015-06-22 13:21:59 -0700754 // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
755 // of RSA PKCS#1 signature padding scheme (about 30 bytes).
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700756 // 4. For EC keys, the there is no point in using a digest whose output size is longer than
757 // key/field size because the digest will be truncated to that size.
Kenny Rootdb026712012-08-20 10:48:46 -0700758
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700759 if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
760 // Key not authorized for signing
761 return null;
Kenny Rootdb026712012-08-20 10:48:46 -0700762 }
Alex Klyubinf78dd672015-06-15 15:16:09 -0700763 if (spec.isUserAuthenticationRequired()) {
764 // Key not authorized for use without user authentication
765 return null;
766 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700767 if (!spec.isDigestsSpecified()) {
768 // Key not authorized for any digests -- can't sign
769 return null;
770 }
771 switch (keymasterAlgorithm) {
772 case KeymasterDefs.KM_ALGORITHM_EC:
773 {
774 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
775 spec.getDigests(),
776 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
Kenny Rootdb026712012-08-20 10:48:46 -0700777
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700778 int bestKeymasterDigest = -1;
779 int bestDigestOutputSizeBits = -1;
780 for (int keymasterDigest : availableKeymasterDigests) {
781 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
782 if (outputSizeBits == keySizeBits) {
783 // Perfect match -- use this digest
784 bestKeymasterDigest = keymasterDigest;
785 bestDigestOutputSizeBits = outputSizeBits;
786 break;
787 }
788 // Not a perfect match -- check against the best digest so far
789 if (bestKeymasterDigest == -1) {
790 // First digest tested -- definitely the best so far
791 bestKeymasterDigest = keymasterDigest;
792 bestDigestOutputSizeBits = outputSizeBits;
793 } else {
794 // Prefer output size to be as close to key size as possible, with output
795 // sizes larger than key size preferred to those smaller than key size.
796 if (bestDigestOutputSizeBits < keySizeBits) {
797 // Output size of the best digest so far is smaller than key size.
798 // Anything larger is a win.
799 if (outputSizeBits > bestDigestOutputSizeBits) {
800 bestKeymasterDigest = keymasterDigest;
801 bestDigestOutputSizeBits = outputSizeBits;
802 }
803 } else {
804 // Output size of the best digest so far is larger than key size.
805 // Anything smaller is a win, as long as it's not smaller than key size.
806 if ((outputSizeBits < bestDigestOutputSizeBits)
807 && (outputSizeBits >= keySizeBits)) {
808 bestKeymasterDigest = keymasterDigest;
809 bestDigestOutputSizeBits = outputSizeBits;
810 }
811 }
812 }
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700813 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700814 if (bestKeymasterDigest == -1) {
815 return null;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700816 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700817 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
818 bestKeymasterDigest) + "WithECDSA";
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700819 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700820 case KeymasterDefs.KM_ALGORITHM_RSA:
821 {
Alex Klyubin7c475cc2015-06-12 12:16:45 -0700822 // Check whether this key is authorized for PKCS#1 signature padding.
823 // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
824 // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
825 // to be authorized for PKCS#1 padding or padding NONE which means any padding.
Alex Klyubine4928a22015-07-21 13:38:48 -0700826 boolean pkcs1SignaturePaddingSupported =
827 com.android.internal.util.ArrayUtils.contains(
828 KeyProperties.SignaturePadding.allToKeymaster(
829 spec.getSignaturePaddings()),
830 KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
Alex Klyubin7c475cc2015-06-12 12:16:45 -0700831 if (!pkcs1SignaturePaddingSupported) {
832 // Key not authorized for PKCS#1 signature padding -- can't sign
833 return null;
834 }
835
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700836 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
837 spec.getDigests(),
838 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
839
Alex Klyubin6e90ade2015-06-22 13:21:59 -0700840 // The amount of space available for the digest is less than modulus size by about
841 // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
842 // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
843 // overhead (depending the on chosen digest) for encoding digest OID and digest
844 // value in DER.
845 int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700846 int bestKeymasterDigest = -1;
847 int bestDigestOutputSizeBits = -1;
848 for (int keymasterDigest : availableKeymasterDigests) {
849 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
850 if (outputSizeBits > maxDigestOutputSizeBits) {
851 // Digest too long (signature generation will fail) -- skip
852 continue;
853 }
854 if (bestKeymasterDigest == -1) {
855 // First digest tested -- definitely the best so far
856 bestKeymasterDigest = keymasterDigest;
857 bestDigestOutputSizeBits = outputSizeBits;
858 } else {
859 // The longer the better
860 if (outputSizeBits > bestDigestOutputSizeBits) {
861 bestKeymasterDigest = keymasterDigest;
862 bestDigestOutputSizeBits = outputSizeBits;
863 }
864 }
865 }
866 if (bestKeymasterDigest == -1) {
867 return null;
868 }
869 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
870 bestKeymasterDigest) + "WithRSA";
871 }
872 default:
873 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
874 }
875 }
876
877 private static Set<Integer> getAvailableKeymasterSignatureDigests(
878 @KeyProperties.DigestEnum String[] authorizedKeyDigests,
879 @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
880 Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
881 for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
882 authorizedKeymasterKeyDigests.add(keymasterDigest);
883 }
884 Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
885 for (int keymasterDigest
886 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
887 supportedKeymasterSignatureDigests.add(keymasterDigest);
888 }
Alex Klyubine4928a22015-07-21 13:38:48 -0700889 Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
890 result.retainAll(authorizedKeymasterKeyDigests);
891 return result;
Kenny Rootdb026712012-08-20 10:48:46 -0700892 }
893}