1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security;
18 
19 import com.android.org.conscrypt.NativeCrypto;
20 
21 import android.content.Context;
22 import android.text.TextUtils;
23 
24 import java.math.BigInteger;
25 import java.security.NoSuchAlgorithmException;
26 import java.security.PrivateKey;
27 import java.security.cert.Certificate;
28 import java.security.spec.AlgorithmParameterSpec;
29 import java.security.spec.DSAParameterSpec;
30 import java.security.spec.RSAKeyGenParameterSpec;
31 import java.util.Date;
32 
33 import javax.security.auth.x500.X500Principal;
34 
35 /**
36  * This provides the required parameters needed for initializing the
37  * {@code KeyPairGenerator} that works with
38  * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
39  * facility</a>. The Android KeyStore facility is accessed through a
40  * {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore}
41  * provider. The {@code context} passed in may be used to pop up some UI to ask
42  * the user to unlock or initialize the Android KeyStore facility.
43  * <p>
44  * After generation, the {@code keyStoreAlias} is used with the
45  * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
46  * interface to retrieve the {@link PrivateKey} and its associated
47  * {@link Certificate} chain.
48  * <p>
49  * The KeyPair generator will create a self-signed certificate with the subject
50  * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer
51  * Distinguished Name along with the other parameters specified with the
52  * {@link Builder}.
53  * <p>
54  * The self-signed X.509 certificate may be replaced at a later time by a
55  * certificate signed by a real Certificate Authority.
56  */
57 public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
58     /*
59      * These must be kept in sync with system/security/keystore/defaults.h
60      */
61 
62     /* DSA */
63     private static final int DSA_DEFAULT_KEY_SIZE = 1024;
64     private static final int DSA_MIN_KEY_SIZE = 512;
65     private static final int DSA_MAX_KEY_SIZE = 8192;
66 
67     /* EC */
68     private static final int EC_DEFAULT_KEY_SIZE = 256;
69     private static final int EC_MIN_KEY_SIZE = 192;
70     private static final int EC_MAX_KEY_SIZE = 521;
71 
72     /* RSA */
73     private static final int RSA_DEFAULT_KEY_SIZE = 2048;
74     private static final int RSA_MIN_KEY_SIZE = 512;
75     private static final int RSA_MAX_KEY_SIZE = 8192;
76 
77     private final Context mContext;
78 
79     private final String mKeystoreAlias;
80 
81     private final String mKeyType;
82 
83     private final int mKeySize;
84 
85     private final AlgorithmParameterSpec mSpec;
86 
87     private final X500Principal mSubjectDN;
88 
89     private final BigInteger mSerialNumber;
90 
91     private final Date mStartDate;
92 
93     private final Date mEndDate;
94 
95     private final int mFlags;
96 
97     /**
98      * Parameter specification for the "{@code AndroidKeyPairGenerator}"
99      * instance of the {@link java.security.KeyPairGenerator} API. The
100      * {@code context} passed in may be used to pop up some UI to ask the user
101      * to unlock or initialize the Android keystore facility.
102      * <p>
103      * After generation, the {@code keyStoreAlias} is used with the
104      * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
105      * interface to retrieve the {@link PrivateKey} and its associated
106      * {@link Certificate} chain.
107      * <p>
108      * The KeyPair generator will create a self-signed certificate with the
109      * properties of {@code subjectDN} as its X.509v3 Subject Distinguished Name
110      * and as its X.509v3 Issuer Distinguished Name, using the specified
111      * {@code serialNumber}, and the validity date starting at {@code startDate}
112      * and ending at {@code endDate}.
113      *
114      * @param context Android context for the activity
115      * @param keyStoreAlias name to use for the generated key in the Android
116      *            keystore
117      * @param keyType key algorithm to use (RSA, DSA, EC)
118      * @param keySize size of key to generate
119      * @param spec the underlying key type parameters
120      * @param subjectDN X.509 v3 Subject Distinguished Name
121      * @param serialNumber X509 v3 certificate serial number
122      * @param startDate the start of the self-signed certificate validity period
123      * @param endDate the end date of the self-signed certificate validity
124      *            period
125      * @throws IllegalArgumentException when any argument is {@code null} or
126      *             {@code endDate} is before {@code startDate}.
127      * @hide should be built with KeyPairGeneratorSpecBuilder
128      */
KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize, AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate, int flags)129     public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
130             AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
131             Date startDate, Date endDate, int flags) {
132         if (context == null) {
133             throw new IllegalArgumentException("context == null");
134         } else if (TextUtils.isEmpty(keyStoreAlias)) {
135             throw new IllegalArgumentException("keyStoreAlias must not be empty");
136         } else if (subjectDN == null) {
137             throw new IllegalArgumentException("subjectDN == null");
138         } else if (serialNumber == null) {
139             throw new IllegalArgumentException("serialNumber == null");
140         } else if (startDate == null) {
141             throw new IllegalArgumentException("startDate == null");
142         } else if (endDate == null) {
143             throw new IllegalArgumentException("endDate == null");
144         } else if (endDate.before(startDate)) {
145             throw new IllegalArgumentException("endDate < startDate");
146         }
147 
148         final int keyTypeInt = KeyStore.getKeyTypeForAlgorithm(keyType);
149         if (keySize == -1) {
150             keySize = getDefaultKeySizeForType(keyTypeInt);
151         }
152         checkCorrectParametersSpec(keyTypeInt, keySize, spec);
153         checkValidKeySize(keyTypeInt, keySize);
154 
155         mContext = context;
156         mKeystoreAlias = keyStoreAlias;
157         mKeyType = keyType;
158         mKeySize = keySize;
159         mSpec = spec;
160         mSubjectDN = subjectDN;
161         mSerialNumber = serialNumber;
162         mStartDate = startDate;
163         mEndDate = endDate;
164         mFlags = flags;
165     }
166 
getDefaultKeySizeForType(int keyType)167     private static int getDefaultKeySizeForType(int keyType) {
168         if (keyType == NativeCrypto.EVP_PKEY_DSA) {
169             return DSA_DEFAULT_KEY_SIZE;
170         } else if (keyType == NativeCrypto.EVP_PKEY_EC) {
171             return EC_DEFAULT_KEY_SIZE;
172         } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
173             return RSA_DEFAULT_KEY_SIZE;
174         }
175         throw new IllegalArgumentException("Invalid key type " + keyType);
176     }
177 
checkValidKeySize(int keyType, int keySize)178     private static void checkValidKeySize(int keyType, int keySize) {
179         if (keyType == NativeCrypto.EVP_PKEY_DSA) {
180             if (keySize < DSA_MIN_KEY_SIZE || keySize > DSA_MAX_KEY_SIZE) {
181                 throw new IllegalArgumentException("DSA keys must be >= " + DSA_MIN_KEY_SIZE
182                         + " and <= " + DSA_MAX_KEY_SIZE);
183             }
184         } else if (keyType == NativeCrypto.EVP_PKEY_EC) {
185             if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
186                 throw new IllegalArgumentException("EC keys must be >= " + EC_MIN_KEY_SIZE
187                         + " and <= " + EC_MAX_KEY_SIZE);
188             }
189         } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
190             if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
191                 throw new IllegalArgumentException("RSA keys must be >= " + RSA_MIN_KEY_SIZE
192                         + " and <= " + RSA_MAX_KEY_SIZE);
193             }
194         } else {
195             throw new IllegalArgumentException("Invalid key type " + keyType);
196         }
197     }
198 
checkCorrectParametersSpec(int keyType, int keySize, AlgorithmParameterSpec spec)199     private static void checkCorrectParametersSpec(int keyType, int keySize,
200             AlgorithmParameterSpec spec) {
201         if (keyType == NativeCrypto.EVP_PKEY_DSA && spec != null) {
202             if (!(spec instanceof DSAParameterSpec)) {
203                 throw new IllegalArgumentException("DSA keys must have DSAParameterSpec specified");
204             }
205         } else if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) {
206             if (spec instanceof RSAKeyGenParameterSpec) {
207                 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
208                 if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
209                     throw new IllegalArgumentException("RSA key size must match: " + keySize
210                             + " vs " + rsaSpec.getKeysize());
211                 }
212             } else {
213                 throw new IllegalArgumentException("RSA may only use RSAKeyGenParameterSpec");
214             }
215         }
216     }
217 
218     /**
219      * Gets the Android context used for operations with this instance.
220      */
getContext()221     public Context getContext() {
222         return mContext;
223     }
224 
225     /**
226      * Returns the alias that will be used in the {@code java.security.KeyStore}
227      * in conjunction with the {@code AndroidKeyStore}.
228      */
getKeystoreAlias()229     public String getKeystoreAlias() {
230         return mKeystoreAlias;
231     }
232 
233     /**
234      * Returns the key type (e.g., "RSA", "DSA", "EC") specified by this
235      * parameter.
236      */
getKeyType()237     public String getKeyType() {
238         return mKeyType;
239     }
240 
241     /**
242      * Returns the key size specified by this parameter. For instance, for RSA
243      * this will return the modulus size and for EC it will return the field
244      * size.
245      */
getKeySize()246     public int getKeySize() {
247         return mKeySize;
248     }
249 
250     /**
251      * Returns the {@link AlgorithmParameterSpec} that will be used for creation
252      * of the key pair.
253      */
getAlgorithmParameterSpec()254     public AlgorithmParameterSpec getAlgorithmParameterSpec() {
255         return mSpec;
256     }
257 
258     /**
259      * Gets the subject distinguished name to be used on the X.509 certificate
260      * that will be put in the {@link java.security.KeyStore}.
261      */
getSubjectDN()262     public X500Principal getSubjectDN() {
263         return mSubjectDN;
264     }
265 
266     /**
267      * Gets the serial number to be used on the X.509 certificate that will be
268      * put in the {@link java.security.KeyStore}.
269      */
getSerialNumber()270     public BigInteger getSerialNumber() {
271         return mSerialNumber;
272     }
273 
274     /**
275      * Gets the start date to be used on the X.509 certificate that will be put
276      * in the {@link java.security.KeyStore}.
277      */
getStartDate()278     public Date getStartDate() {
279         return mStartDate;
280     }
281 
282     /**
283      * Gets the end date to be used on the X.509 certificate that will be put in
284      * the {@link java.security.KeyStore}.
285      */
getEndDate()286     public Date getEndDate() {
287         return mEndDate;
288     }
289 
290     /**
291      * @hide
292      */
getFlags()293     int getFlags() {
294         return mFlags;
295     }
296 
297     /**
298      * Returns {@code true} if this parameter will require generated keys to be
299      * encrypted in the {@link java.security.KeyStore}.
300      */
isEncryptionRequired()301     public boolean isEncryptionRequired() {
302         return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
303     }
304 
305     /**
306      * Builder class for {@link KeyPairGeneratorSpec} objects.
307      * <p>
308      * This will build a parameter spec for use with the <a href="{@docRoot}
309      * training/articles/keystore.html">Android KeyStore facility</a>.
310      * <p>
311      * The required fields must be filled in with the builder.
312      * <p>
313      * Example:
314      *
315      * <pre class="prettyprint">
316      * Calendar start = new Calendar();
317      * Calendar end = new Calendar();
318      * end.add(1, Calendar.YEAR);
319      *
320      * KeyPairGeneratorSpec spec =
321      *         new KeyPairGeneratorSpec.Builder(mContext).setAlias(&quot;myKey&quot;)
322      *                 .setSubject(new X500Principal(&quot;CN=myKey&quot;)).setSerial(BigInteger.valueOf(1337))
323      *                 .setStartDate(start.getTime()).setEndDate(end.getTime()).build();
324      * </pre>
325      */
326     public final static class Builder {
327         private final Context mContext;
328 
329         private String mKeystoreAlias;
330 
331         private String mKeyType = "RSA";
332 
333         private int mKeySize = -1;
334 
335         private AlgorithmParameterSpec mSpec;
336 
337         private X500Principal mSubjectDN;
338 
339         private BigInteger mSerialNumber;
340 
341         private Date mStartDate;
342 
343         private Date mEndDate;
344 
345         private int mFlags;
346 
347         /**
348          * Creates a new instance of the {@code Builder} with the given
349          * {@code context}. The {@code context} passed in may be used to pop up
350          * some UI to ask the user to unlock or initialize the Android KeyStore
351          * facility.
352          */
Builder(Context context)353         public Builder(Context context) {
354             if (context == null) {
355                 throw new NullPointerException("context == null");
356             }
357             mContext = context;
358         }
359 
360         /**
361          * Sets the alias to be used to retrieve the key later from a
362          * {@link java.security.KeyStore} instance using the
363          * {@code AndroidKeyStore} provider.
364          */
setAlias(String alias)365         public Builder setAlias(String alias) {
366             if (alias == null) {
367                 throw new NullPointerException("alias == null");
368             }
369             mKeystoreAlias = alias;
370             return this;
371         }
372 
373         /**
374          * Sets the key type (e.g., RSA, DSA, EC) of the keypair to be created.
375          */
setKeyType(String keyType)376         public Builder setKeyType(String keyType) throws NoSuchAlgorithmException {
377             if (keyType == null) {
378                 throw new NullPointerException("keyType == null");
379             } else {
380                 try {
381                     KeyStore.getKeyTypeForAlgorithm(keyType);
382                 } catch (IllegalArgumentException e) {
383                     throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
384                 }
385             }
386             mKeyType = keyType;
387             return this;
388         }
389 
390         /**
391          * Sets the key size for the keypair to be created. For instance, for a
392          * key type of RSA this will set the modulus size and for a key type of
393          * EC it will select a curve with a matching field size.
394          */
setKeySize(int keySize)395         public Builder setKeySize(int keySize) {
396             if (keySize < 0) {
397                 throw new IllegalArgumentException("keySize < 0");
398             }
399             mKeySize = keySize;
400             return this;
401         }
402 
403         /**
404          * Sets the underlying key type's parameters. This is required for DSA
405          * where you must set this to an instance of
406          * {@link java.security.spec.DSAParameterSpec}.
407          */
setAlgorithmParameterSpec(AlgorithmParameterSpec spec)408         public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) {
409             if (spec == null) {
410                 throw new NullPointerException("spec == null");
411             }
412             mSpec = spec;
413             return this;
414         }
415 
416         /**
417          * Sets the subject used for the self-signed certificate of the
418          * generated key pair.
419          */
setSubject(X500Principal subject)420         public Builder setSubject(X500Principal subject) {
421             if (subject == null) {
422                 throw new NullPointerException("subject == null");
423             }
424             mSubjectDN = subject;
425             return this;
426         }
427 
428         /**
429          * Sets the serial number used for the self-signed certificate of the
430          * generated key pair.
431          */
setSerialNumber(BigInteger serialNumber)432         public Builder setSerialNumber(BigInteger serialNumber) {
433             if (serialNumber == null) {
434                 throw new NullPointerException("serialNumber == null");
435             }
436             mSerialNumber = serialNumber;
437             return this;
438         }
439 
440         /**
441          * Sets the start of the validity period for the self-signed certificate
442          * of the generated key pair.
443          */
setStartDate(Date startDate)444         public Builder setStartDate(Date startDate) {
445             if (startDate == null) {
446                 throw new NullPointerException("startDate == null");
447             }
448             mStartDate = startDate;
449             return this;
450         }
451 
452         /**
453          * Sets the end of the validity period for the self-signed certificate
454          * of the generated key pair.
455          */
setEndDate(Date endDate)456         public Builder setEndDate(Date endDate) {
457             if (endDate == null) {
458                 throw new NullPointerException("endDate == null");
459             }
460             mEndDate = endDate;
461             return this;
462         }
463 
464         /**
465          * Indicates that this key must be encrypted at rest on storage. Note
466          * that enabling this will require that the user enable a strong lock
467          * screen (e.g., PIN, password) before creating or using the generated
468          * key is successful.
469          */
setEncryptionRequired()470         public Builder setEncryptionRequired() {
471             mFlags |= KeyStore.FLAG_ENCRYPTED;
472             return this;
473         }
474 
475         /**
476          * Builds the instance of the {@code KeyPairGeneratorSpec}.
477          *
478          * @throws IllegalArgumentException if a required field is missing
479          * @return built instance of {@code KeyPairGeneratorSpec}
480          */
build()481         public KeyPairGeneratorSpec build() {
482             return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mKeyType, mKeySize, mSpec,
483                     mSubjectDN, mSerialNumber, mStartDate, mEndDate, mFlags);
484         }
485     }
486 }
487