blob: 69155a89851f4e6676a66388408fb99bbf4006b3 [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 Klyubin4350bab2015-06-08 10:14:58 -070023import android.security.keymaster.ExportResult;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070024import android.security.keymaster.KeyCharacteristics;
25import android.security.keymaster.KeymasterArguments;
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 Root12e75222013-04-23 22:34:24 -070047import com.android.org.conscrypt.OpenSSLEngine;
Kenny Rootdb026712012-08-20 10:48:46 -070048
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070049import libcore.util.EmptyArray;
50
51import java.math.BigInteger;
Kenny Rootdb026712012-08-20 10:48:46 -070052import java.security.InvalidAlgorithmParameterException;
53import java.security.InvalidKeyException;
54import java.security.KeyFactory;
55import java.security.KeyPair;
56import java.security.KeyPairGenerator;
57import java.security.KeyPairGeneratorSpi;
58import java.security.NoSuchAlgorithmException;
59import java.security.PrivateKey;
Alex Klyubin4350bab2015-06-08 10:14:58 -070060import java.security.ProviderException;
Kenny Rootdb026712012-08-20 10:48:46 -070061import java.security.PublicKey;
62import java.security.SecureRandom;
63import java.security.cert.CertificateEncodingException;
64import java.security.cert.X509Certificate;
65import java.security.spec.AlgorithmParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070066import java.security.spec.ECGenParameterSpec;
Kenny Rootdb026712012-08-20 10:48:46 -070067import java.security.spec.InvalidKeySpecException;
Kenny Rootf64386f2013-08-16 14:03:29 -070068import java.security.spec.RSAKeyGenParameterSpec;
Kenny Rootdb026712012-08-20 10:48:46 -070069import java.security.spec.X509EncodedKeySpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070070import java.util.ArrayList;
71import java.util.Collections;
72import java.util.Date;
73import java.util.HashMap;
74import java.util.HashSet;
75import 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;
113 private static final int EC_MIN_KEY_SIZE = 192;
114 private static final int EC_MAX_KEY_SIZE = 521;
115
116 /* RSA */
117 private static final int RSA_DEFAULT_KEY_SIZE = 2048;
118 private static final int RSA_MIN_KEY_SIZE = 512;
119 private static final int RSA_MAX_KEY_SIZE = 8192;
120
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700121 private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
122 new HashMap<String, Integer>();
123 private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
124 static {
125 // Aliases for NIST P-192
126 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-192", 192);
127 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp192r1", 192);
128 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime192v1", 192);
129
130 // Aliases for NIST P-224
131 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
132 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
133
134 // Aliases for NIST P-256
135 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
136 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
137 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
138
139 // Aliases for NIST P-384
140 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
141 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
142
143 // Aliases for NIST P-521
144 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
145 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
146
147 SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
148 Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
149 }
150 private final int mOriginalKeymasterAlgorithm;
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 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
169 private long mRSAPublicExponent;
170
171 protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
172 mOriginalKeymasterAlgorithm = keymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800173 }
174
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700175 @Override
176 public void initialize(int keysize, SecureRandom random) {
177 throw new IllegalArgumentException(
178 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
179 + " required to initialize this KeyPairGenerator");
Alex Klyubin21a76df2015-01-14 13:35:32 -0800180 }
Kenny Rootdb026712012-08-20 10:48:46 -0700181
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700182 @Override
183 public void initialize(AlgorithmParameterSpec params, SecureRandom random)
184 throws InvalidAlgorithmParameterException {
185 resetAll();
186
187 boolean success = false;
188 try {
189 if (params == null) {
190 throw new InvalidAlgorithmParameterException(
191 "Must supply params of type " + KeyGenParameterSpec.class.getName()
192 + " or " + KeyPairGeneratorSpec.class.getName());
193 }
194
195 KeyGenParameterSpec spec;
196 boolean encryptionAtRestRequired = false;
197 int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
198 if (params instanceof KeyGenParameterSpec) {
199 spec = (KeyGenParameterSpec) params;
200 } else if (params instanceof KeyPairGeneratorSpec) {
201 // Legacy/deprecated spec
202 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
203 try {
204 KeyGenParameterSpec.Builder specBuilder;
205 String specKeyAlgorithm = legacySpec.getKeyType();
206 if (specKeyAlgorithm != null) {
207 // Spec overrides the generator's default key algorithm
208 try {
209 keymasterAlgorithm =
210 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
211 specKeyAlgorithm);
212 } catch (IllegalArgumentException e) {
213 throw new InvalidAlgorithmParameterException(
214 "Invalid key type in parameters", e);
215 }
216 }
217 switch (keymasterAlgorithm) {
218 case KeymasterDefs.KM_ALGORITHM_EC:
219 specBuilder = new KeyGenParameterSpec.Builder(
220 legacySpec.getKeystoreAlias(),
221 KeyProperties.PURPOSE_SIGN
222 | KeyProperties.PURPOSE_VERIFY);
223 specBuilder.setDigests(
224 KeyProperties.DIGEST_NONE,
225 KeyProperties.DIGEST_MD5,
226 KeyProperties.DIGEST_SHA1,
227 KeyProperties.DIGEST_SHA224,
228 KeyProperties.DIGEST_SHA256,
229 KeyProperties.DIGEST_SHA384,
230 KeyProperties.DIGEST_SHA512);
231 break;
232 case KeymasterDefs.KM_ALGORITHM_RSA:
233 specBuilder = new KeyGenParameterSpec.Builder(
234 legacySpec.getKeystoreAlias(),
235 KeyProperties.PURPOSE_ENCRYPT
236 | KeyProperties.PURPOSE_DECRYPT
237 | KeyProperties.PURPOSE_SIGN
238 | KeyProperties.PURPOSE_VERIFY);
239 specBuilder.setDigests(
240 KeyProperties.DIGEST_NONE,
241 KeyProperties.DIGEST_MD5,
242 KeyProperties.DIGEST_SHA1,
243 KeyProperties.DIGEST_SHA224,
244 KeyProperties.DIGEST_SHA256,
245 KeyProperties.DIGEST_SHA384,
246 KeyProperties.DIGEST_SHA512);
247 specBuilder.setSignaturePaddings(
248 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
249 specBuilder.setEncryptionPaddings(
250 KeyProperties.ENCRYPTION_PADDING_NONE,
251 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
252 // Disable randomized encryption requirement to support encryption
253 // padding NONE above.
254 specBuilder.setRandomizedEncryptionRequired(false);
255 break;
256 default:
257 throw new ProviderException(
258 "Unsupported algorithm: " + mKeymasterAlgorithm);
259 }
260
261 if (legacySpec.getKeySize() != -1) {
262 specBuilder.setKeySize(legacySpec.getKeySize());
263 }
264 if (legacySpec.getAlgorithmParameterSpec() != null) {
265 specBuilder.setAlgorithmParameterSpec(
266 legacySpec.getAlgorithmParameterSpec());
267 }
268 specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
269 specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
270 specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
271 specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
272 encryptionAtRestRequired = legacySpec.isEncryptionRequired();
273 specBuilder.setUserAuthenticationRequired(false);
274
275 spec = specBuilder.build();
276 } catch (NullPointerException | IllegalArgumentException e) {
277 throw new InvalidAlgorithmParameterException(e);
278 }
279 } else {
280 throw new InvalidAlgorithmParameterException(
281 "Unsupported params class: " + params.getClass().getName()
282 + ". Supported: " + KeyGenParameterSpec.class.getName()
283 + ", " + KeyPairGeneratorSpec.class.getName());
284 }
285
286 mEntryAlias = spec.getKeystoreAlias();
287 mSpec = spec;
288 mKeymasterAlgorithm = keymasterAlgorithm;
289 mEncryptionAtRestRequired = encryptionAtRestRequired;
290 mKeySizeBits = spec.getKeySize();
291 initAlgorithmSpecificParameters();
292 if (mKeySizeBits == -1) {
293 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
294 }
295 checkValidKeySize(keymasterAlgorithm, mKeySizeBits);
296
297 if (spec.getKeystoreAlias() == null) {
298 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
299 }
300
301 String jcaKeyAlgorithm;
302 try {
303 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
304 keymasterAlgorithm);
305 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
306 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
307 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
308 spec.getEncryptionPaddings());
309 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
310 spec.getSignaturePaddings());
311 if (spec.isDigestsSpecified()) {
312 mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
313 } else {
314 mKeymasterDigests = EmptyArray.INT;
315 }
316 } catch (IllegalArgumentException e) {
317 throw new InvalidAlgorithmParameterException(e);
318 }
319
320 mJcaKeyAlgorithm = jcaKeyAlgorithm;
321 mRng = random;
322 mKeyStore = KeyStore.getInstance();
323 success = true;
324 } finally {
325 if (!success) {
326 resetAll();
327 }
328 }
329 }
330
331 private void resetAll() {
332 mEntryAlias = null;
333 mJcaKeyAlgorithm = null;
334 mKeymasterAlgorithm = -1;
335 mKeymasterPurposes = null;
336 mKeymasterBlockModes = null;
337 mKeymasterEncryptionPaddings = null;
338 mKeymasterSignaturePaddings = null;
339 mKeymasterDigests = null;
340 mKeySizeBits = 0;
341 mSpec = null;
342 mRSAPublicExponent = -1;
343 mEncryptionAtRestRequired = false;
344 mRng = null;
345 mKeyStore = null;
346 }
347
348 private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
349 AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
350 switch (mKeymasterAlgorithm) {
351 case KeymasterDefs.KM_ALGORITHM_RSA:
352 {
353 BigInteger publicExponent = null;
354 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
355 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
356 if (mKeySizeBits == -1) {
357 mKeySizeBits = rsaSpec.getKeysize();
358 } else if (mKeySizeBits != rsaSpec.getKeysize()) {
359 throw new InvalidAlgorithmParameterException("RSA key size must match "
360 + " between " + mSpec + " and " + algSpecificSpec
361 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
362 }
363 publicExponent = rsaSpec.getPublicExponent();
364 } else if (algSpecificSpec != null) {
365 throw new InvalidAlgorithmParameterException(
366 "RSA may only use RSAKeyGenParameterSpec");
367 }
368 if (publicExponent == null) {
369 publicExponent = RSAKeyGenParameterSpec.F4;
370 }
371 if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
372 throw new InvalidAlgorithmParameterException(
373 "RSA public exponent must be positive: " + publicExponent);
374 }
375 if (publicExponent.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
376 throw new InvalidAlgorithmParameterException(
377 "Unsupported RSA public exponent: " + publicExponent
378 + ". Only exponents <= " + Long.MAX_VALUE + " supported");
379 }
380 mRSAPublicExponent = publicExponent.longValue();
381 break;
382 }
383 case KeymasterDefs.KM_ALGORITHM_EC:
384 if (algSpecificSpec instanceof ECGenParameterSpec) {
385 ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
386 String curveName = ecSpec.getName();
387 Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
388 curveName.toLowerCase(Locale.US));
389 if (ecSpecKeySizeBits == null) {
390 throw new InvalidAlgorithmParameterException(
391 "Unsupported EC curve name: " + curveName
392 + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
393 }
394 if (mKeySizeBits == -1) {
395 mKeySizeBits = ecSpecKeySizeBits;
396 } else if (mKeySizeBits != ecSpecKeySizeBits) {
397 throw new InvalidAlgorithmParameterException("EC key size must match "
398 + " between " + mSpec + " and " + algSpecificSpec
399 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
400 }
401 } else if (algSpecificSpec != null) {
402 throw new InvalidAlgorithmParameterException(
403 "EC may only use ECGenParameterSpec");
404 }
405 break;
406 default:
407 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
408 }
409 }
410
Kenny Rootdb026712012-08-20 10:48:46 -0700411 @Override
412 public KeyPair generateKeyPair() {
413 if (mKeyStore == null || mSpec == null) {
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700414 throw new IllegalStateException("Not initialized");
Kenny Rootdb026712012-08-20 10:48:46 -0700415 }
416
Alex Klyubin96481c32015-05-15 10:47:18 -0700417 final int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700418 if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
Kenny Root2eeda722013-04-10 11:30:58 -0700419 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
420 throw new IllegalStateException(
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700421 "Encryption at rest using secure lock screen credential requested for key pair"
422 + ", but the user has not yet entered the credential");
Kenny Root2eeda722013-04-10 11:30:58 -0700423 }
424
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700425 KeymasterArguments args = new KeymasterArguments();
426 args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
427 args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
428 args.addInts(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
429 args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
430 args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
431 args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
432 args.addInts(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
Kenny Rootdb026712012-08-20 10:48:46 -0700433
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700434 // TODO: Remove the digest and padding NONE workaround below once Android Keystore returns
435 // keys which are backed by AndroidKeyStoreBCWorkaround provider instead of Conscrypt. The
436 // workaround is needed because Conscrypt (via keystore-engine) uses old KeyStore API which
437 // translates into digest NONE and padding NONE in the new API. keystore-engine cannot be
438 // updated to pass in the correct padding and digest values because it uses
439 // OpenSSL/BoringSSL engine which performs digesting and padding prior before invoking
440 // KeyStore API.
441 if (!com.android.internal.util.ArrayUtils.contains(
442 mKeymasterDigests, KeymasterDefs.KM_DIGEST_NONE)) {
443 args.addInt(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
444 }
445 if ((!com.android.internal.util.ArrayUtils.contains(
446 mKeymasterSignaturePaddings, KeymasterDefs.KM_PAD_NONE))
447 && (!com.android.internal.util.ArrayUtils.contains(
448 mKeymasterEncryptionPaddings, KeymasterDefs.KM_PAD_NONE))) {
449 args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
450 }
Kenny Rootf64386f2013-08-16 14:03:29 -0700451
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700452 KeymasterUtils.addUserAuthArgs(args,
453 mSpec.isUserAuthenticationRequired(),
454 mSpec.getUserAuthenticationValidityDurationSeconds());
455 args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
456 (mSpec.getKeyValidityStart() != null)
457 ? mSpec.getKeyValidityStart() : new Date(0));
458 args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
459 (mSpec.getKeyValidityForOriginationEnd() != null)
460 ? mSpec.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
461 args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
462 (mSpec.getKeyValidityForConsumptionEnd() != null)
463 ? mSpec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
464 addAlgorithmSpecificParameters(args);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700465
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700466 byte[] additionalEntropy =
467 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
468 mRng, (mKeySizeBits + 7) / 8);
469
470 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700471 boolean success = false;
Kenny Rootdb026712012-08-20 10:48:46 -0700472 try {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700473 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias);
474 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
475 int errorCode = mKeyStore.generateKey(
476 privateKeyAlias,
477 args,
478 additionalEntropy,
479 flags,
480 resultingKeyCharacteristics);
481 if (errorCode != KeyStore.NO_ERROR) {
482 throw new ProviderException(
483 "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700484 }
Kenny Rootdb026712012-08-20 10:48:46 -0700485
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700486 final PrivateKey privKey;
487 final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
488 try {
489 privKey = engine.getPrivateKeyById(privateKeyAlias);
490 } catch (InvalidKeyException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700491 throw new ProviderException("Failed to obtain generated private key", e);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700492 }
Kenny Rootdb026712012-08-20 10:48:46 -0700493
Alex Klyubin4350bab2015-06-08 10:14:58 -0700494 ExportResult exportResult =
495 mKeyStore.exportKey(
496 privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
497 if (exportResult == null) {
498 throw new KeyStoreConnectException();
499 } else if (exportResult.resultCode != KeyStore.NO_ERROR) {
500 throw new ProviderException(
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700501 "Failed to obtain X.509 form of generated public key",
Alex Klyubin4350bab2015-06-08 10:14:58 -0700502 KeyStore.getKeyStoreException(exportResult.resultCode));
503 }
504 final byte[] pubKeyBytes = exportResult.exportData;
505
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700506 final PublicKey pubKey;
507 try {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700508 final KeyFactory keyFact = KeyFactory.getInstance(mJcaKeyAlgorithm);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700509 pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
510 } catch (NoSuchAlgorithmException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700511 throw new ProviderException(
512 "Failed to obtain " + mJcaKeyAlgorithm + " KeyFactory", e);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700513 } catch (InvalidKeySpecException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700514 throw new ProviderException("Invalid X.509 encoding of generated public key", e);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700515 }
516
517 final X509Certificate cert;
518 try {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700519 cert = generateSelfSignedCertificate(privKey, pubKey);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700520 } catch (Exception e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700521 throw new ProviderException("Failed to generate self-signed certificate", e);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700522 }
523
524 byte[] certBytes;
525 try {
526 certBytes = cert.getEncoded();
527 } catch (CertificateEncodingException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700528 throw new ProviderException(
529 "Failed to obtain encoded form of self-signed certificate", e);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700530 }
531
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700532 int insertErrorCode = mKeyStore.insert(
533 Credentials.USER_CERTIFICATE + mEntryAlias,
534 certBytes,
535 KeyStore.UID_SELF,
536 flags);
537 if (insertErrorCode != KeyStore.NO_ERROR) {
538 throw new ProviderException("Failed to store self-signed certificate",
539 KeyStore.getKeyStoreException(insertErrorCode));
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700540 }
541
542 KeyPair result = new KeyPair(pubKey, privKey);
543 success = true;
544 return result;
545 } finally {
546 if (!success) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700547 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias);
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700548 }
549 }
Kenny Rootdb026712012-08-20 10:48:46 -0700550 }
551
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700552 private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
553 switch (mKeymasterAlgorithm) {
554 case KeymasterDefs.KM_ALGORITHM_RSA:
555 keymasterArgs.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
556 break;
557 case KeymasterDefs.KM_ALGORITHM_EC:
558 break;
559 default:
560 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
561 }
562 }
563
564 private X509Certificate generateSelfSignedCertificate(
565 PrivateKey privateKey, PublicKey publicKey) throws Exception {
566 String signatureAlgorithm =
567 getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
568 if (signatureAlgorithm == null) {
569 // Key cannot be used to sign a certificate
570 return generateSelfSignedCertificateWithFakeSignature(publicKey);
571 } else {
572 // Key can be used to sign a certificate
573 return generateSelfSignedCertificateWithValidSignature(
574 privateKey, publicKey, signatureAlgorithm);
575 }
576 }
577
Alex Klyubin21a76df2015-01-14 13:35:32 -0800578 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700579 private X509Certificate generateSelfSignedCertificateWithValidSignature(
580 PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm)
581 throws Exception {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800582 final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
583 certGen.setPublicKey(publicKey);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700584 certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
585 certGen.setSubjectDN(mSpec.getCertificateSubject());
586 certGen.setIssuerDN(mSpec.getCertificateSubject());
587 certGen.setNotBefore(mSpec.getCertificateNotBefore());
588 certGen.setNotAfter(mSpec.getCertificateNotAfter());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700589 certGen.setSignatureAlgorithm(signatureAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800590 return certGen.generate(privateKey);
591 }
592
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700593 @SuppressWarnings("deprecation")
594 private X509Certificate generateSelfSignedCertificateWithFakeSignature(
595 PublicKey publicKey) throws Exception {
596 V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
597 ASN1ObjectIdentifier sigAlgOid;
598 AlgorithmIdentifier sigAlgId;
599 byte[] signature;
600 switch (mKeymasterAlgorithm) {
601 case KeymasterDefs.KM_ALGORITHM_EC:
602 sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
603 sigAlgId = new AlgorithmIdentifier(sigAlgOid);
604 ASN1EncodableVector v = new ASN1EncodableVector();
605 v.add(new DERInteger(0));
606 v.add(new DERInteger(0));
607 signature = new DERSequence().getEncoded();
608 break;
609 case KeymasterDefs.KM_ALGORITHM_RSA:
610 sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
611 sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
612 signature = new byte[1];
613 break;
614 default:
615 throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800616 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700617
618 try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
619 tbsGenerator.setSubjectPublicKeyInfo(
620 SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
621 }
622 tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
623 X509Principal subject =
624 new X509Principal(mSpec.getCertificateSubject().getEncoded());
625 tbsGenerator.setSubject(subject);
626 tbsGenerator.setIssuer(subject);
627 tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
628 tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
629 tbsGenerator.setSignature(sigAlgId);
630 TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
631
632 ASN1EncodableVector result = new ASN1EncodableVector();
633 result.add(tbsCertificate);
634 result.add(sigAlgId);
635 result.add(new DERBitString(signature));
636 return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
Alex Klyubin21a76df2015-01-14 13:35:32 -0800637 }
638
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700639 private static int getDefaultKeySize(int keymasterAlgorithm) {
640 switch (keymasterAlgorithm) {
641 case KeymasterDefs.KM_ALGORITHM_EC:
642 return EC_DEFAULT_KEY_SIZE;
643 case KeymasterDefs.KM_ALGORITHM_RSA:
644 return RSA_DEFAULT_KEY_SIZE;
645 default:
646 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800647 }
Alex Klyubin21a76df2015-01-14 13:35:32 -0800648 }
649
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700650 private static void checkValidKeySize(int keymasterAlgorithm, int keySize)
Alex Klyubin21a76df2015-01-14 13:35:32 -0800651 throws InvalidAlgorithmParameterException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700652 switch (keymasterAlgorithm) {
653 case KeymasterDefs.KM_ALGORITHM_EC:
654 if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
655 throw new InvalidAlgorithmParameterException("EC key size must be >= "
656 + EC_MIN_KEY_SIZE + " and <= " + EC_MAX_KEY_SIZE);
Kenny Rootf64386f2013-08-16 14:03:29 -0700657 }
658 break;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700659 case KeymasterDefs.KM_ALGORITHM_RSA:
660 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
661 throw new InvalidAlgorithmParameterException("RSA key size must be >= "
662 + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
663 }
664 break;
665 default:
666 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Kenny Rootf64386f2013-08-16 14:03:29 -0700667 }
Kenny Rootf64386f2013-08-16 14:03:29 -0700668 }
669
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700670 /**
671 * Returns the {@code Signature} algorithm to be used for signing a certificate using the
672 * specified key or {@code null} if the key cannot be used for signing a certificate.
673 */
674 @Nullable
675 private static String getCertificateSignatureAlgorithm(
676 int keymasterAlgorithm,
677 int keySizeBits,
678 KeyGenParameterSpec spec) {
679 // Constraints:
680 // 1. Key must be authorized for signing.
681 // 2. Signature digest must be one of key's authorized digests.
682 // 3. For RSA keys, the digest output size must not exceed modulus size minus space needed
683 // for RSA PKCS#1 signature padding (about 29 bytes: minimum 10 bytes of padding + 15--19
684 // bytes overhead for encoding digest OID and digest value in DER).
685 // 4. For EC keys, the there is no point in using a digest whose output size is longer than
686 // key/field size because the digest will be truncated to that size.
Kenny Rootdb026712012-08-20 10:48:46 -0700687
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700688 if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
689 // Key not authorized for signing
690 return null;
Kenny Rootdb026712012-08-20 10:48:46 -0700691 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700692 if (!spec.isDigestsSpecified()) {
693 // Key not authorized for any digests -- can't sign
694 return null;
695 }
696 switch (keymasterAlgorithm) {
697 case KeymasterDefs.KM_ALGORITHM_EC:
698 {
699 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
700 spec.getDigests(),
701 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
Kenny Rootdb026712012-08-20 10:48:46 -0700702
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700703 int bestKeymasterDigest = -1;
704 int bestDigestOutputSizeBits = -1;
705 for (int keymasterDigest : availableKeymasterDigests) {
706 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
707 if (outputSizeBits == keySizeBits) {
708 // Perfect match -- use this digest
709 bestKeymasterDigest = keymasterDigest;
710 bestDigestOutputSizeBits = outputSizeBits;
711 break;
712 }
713 // Not a perfect match -- check against the best digest so far
714 if (bestKeymasterDigest == -1) {
715 // First digest tested -- definitely the best so far
716 bestKeymasterDigest = keymasterDigest;
717 bestDigestOutputSizeBits = outputSizeBits;
718 } else {
719 // Prefer output size to be as close to key size as possible, with output
720 // sizes larger than key size preferred to those smaller than key size.
721 if (bestDigestOutputSizeBits < keySizeBits) {
722 // Output size of the best digest so far is smaller than key size.
723 // Anything larger is a win.
724 if (outputSizeBits > bestDigestOutputSizeBits) {
725 bestKeymasterDigest = keymasterDigest;
726 bestDigestOutputSizeBits = outputSizeBits;
727 }
728 } else {
729 // Output size of the best digest so far is larger than key size.
730 // Anything smaller is a win, as long as it's not smaller than key size.
731 if ((outputSizeBits < bestDigestOutputSizeBits)
732 && (outputSizeBits >= keySizeBits)) {
733 bestKeymasterDigest = keymasterDigest;
734 bestDigestOutputSizeBits = outputSizeBits;
735 }
736 }
737 }
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700738 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700739 if (bestKeymasterDigest == -1) {
740 return null;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700741 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700742 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
743 bestKeymasterDigest) + "WithECDSA";
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700744 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700745 case KeymasterDefs.KM_ALGORITHM_RSA:
746 {
747 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
748 spec.getDigests(),
749 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
750
751 // The amount of space available for the digest is less than modulus size because
752 // padding must be at least 10 bytes long, and then there's also the 15--19
753 // bytes overhead for encoding digest OID and digest value in DER.
754 int maxDigestOutputSizeBits = keySizeBits - 29 * 8;
755 int bestKeymasterDigest = -1;
756 int bestDigestOutputSizeBits = -1;
757 for (int keymasterDigest : availableKeymasterDigests) {
758 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
759 if (outputSizeBits > maxDigestOutputSizeBits) {
760 // Digest too long (signature generation will fail) -- skip
761 continue;
762 }
763 if (bestKeymasterDigest == -1) {
764 // First digest tested -- definitely the best so far
765 bestKeymasterDigest = keymasterDigest;
766 bestDigestOutputSizeBits = outputSizeBits;
767 } else {
768 // The longer the better
769 if (outputSizeBits > bestDigestOutputSizeBits) {
770 bestKeymasterDigest = keymasterDigest;
771 bestDigestOutputSizeBits = outputSizeBits;
772 }
773 }
774 }
775 if (bestKeymasterDigest == -1) {
776 return null;
777 }
778 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
779 bestKeymasterDigest) + "WithRSA";
780 }
781 default:
782 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
783 }
784 }
785
786 private static Set<Integer> getAvailableKeymasterSignatureDigests(
787 @KeyProperties.DigestEnum String[] authorizedKeyDigests,
788 @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
789 Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
790 for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
791 authorizedKeymasterKeyDigests.add(keymasterDigest);
792 }
793 Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
794 for (int keymasterDigest
795 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
796 supportedKeymasterSignatureDigests.add(keymasterDigest);
797 }
798 if (authorizedKeymasterKeyDigests.contains(KeymasterDefs.KM_DIGEST_NONE)) {
799 // Key is authorized to be used with any digest
800 return supportedKeymasterSignatureDigests;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700801 } else {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700802 // Key is authorized to be used only with specific digests.
803 Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
804 result.retainAll(authorizedKeymasterKeyDigests);
805 return result;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700806 }
Kenny Rootdb026712012-08-20 10:48:46 -0700807 }
808}