KeyPairGeneratorSpec.java revision a39859889b7de0ad3190386cc732fa4bdcbe5504
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
17package android.security;
18
19import com.android.org.conscrypt.NativeCrypto;
20
21import android.content.Context;
22import android.text.TextUtils;
23
24import java.math.BigInteger;
25import java.security.NoSuchAlgorithmException;
26import java.security.PrivateKey;
27import java.security.cert.Certificate;
28import java.security.spec.AlgorithmParameterSpec;
29import java.security.spec.DSAParameterSpec;
30import java.security.spec.RSAKeyGenParameterSpec;
31import java.util.Date;
32
33import 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}guide/topics/security/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 */
57public 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     */
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
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
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
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     */
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     */
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     * @hide
237     */
238    public String getKeyType() {
239        return mKeyType;
240    }
241
242    /**
243     * Returns the key size specified by this parameter. For instance, for RSA
244     * this will return the modulus size and for EC it will return the field
245     * size.
246     * @hide
247     */
248    public int getKeySize() {
249        return mKeySize;
250    }
251
252    /**
253     * Returns the {@link AlgorithmParameterSpec} that will be used for creation
254     * of the key pair.
255     * @hide
256     */
257    public AlgorithmParameterSpec getAlgorithmParameterSpec() {
258        return mSpec;
259    }
260
261    /**
262     * Gets the subject distinguished name to be used on the X.509 certificate
263     * that will be put in the {@link java.security.KeyStore}.
264     */
265    public X500Principal getSubjectDN() {
266        return mSubjectDN;
267    }
268
269    /**
270     * Gets the serial number to be used on the X.509 certificate that will be
271     * put in the {@link java.security.KeyStore}.
272     */
273    public BigInteger getSerialNumber() {
274        return mSerialNumber;
275    }
276
277    /**
278     * Gets the start date to be used on the X.509 certificate that will be put
279     * in the {@link java.security.KeyStore}.
280     */
281    public Date getStartDate() {
282        return mStartDate;
283    }
284
285    /**
286     * Gets the end date to be used on the X.509 certificate that will be put in
287     * the {@link java.security.KeyStore}.
288     */
289    public Date getEndDate() {
290        return mEndDate;
291    }
292
293    /**
294     * @hide
295     */
296    int getFlags() {
297        return mFlags;
298    }
299
300    /**
301     * Returns {@code true} if this parameter will require generated keys to be
302     * encrypted in the {@link java.security.KeyStore}.
303     */
304    public boolean isEncryptionRequired() {
305        return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
306    }
307
308    /**
309     * Builder class for {@link KeyPairGeneratorSpec} objects.
310     * <p>
311     * This will build a parameter spec for use with the <a href="{@docRoot}
312     * guide/topics/security/keystore.html">Android KeyStore facility</a>.
313     * <p>
314     * The required fields must be filled in with the builder.
315     * <p>
316     * Example:
317     *
318     * <pre class="prettyprint">
319     * Calendar start = new Calendar();
320     * Calendar end = new Calendar();
321     * end.add(1, Calendar.YEAR);
322     *
323     * KeyPairGeneratorSpec spec =
324     *         new KeyPairGeneratorSpec.Builder(mContext).setAlias(&quot;myKey&quot;)
325     *                 .setSubject(new X500Principal(&quot;CN=myKey&quot;)).setSerial(BigInteger.valueOf(1337))
326     *                 .setStartDate(start.getTime()).setEndDate(end.getTime()).build();
327     * </pre>
328     */
329    public final static class Builder {
330        private final Context mContext;
331
332        private String mKeystoreAlias;
333
334        private String mKeyType = "RSA";
335
336        private int mKeySize = -1;
337
338        private AlgorithmParameterSpec mSpec;
339
340        private X500Principal mSubjectDN;
341
342        private BigInteger mSerialNumber;
343
344        private Date mStartDate;
345
346        private Date mEndDate;
347
348        private int mFlags;
349
350        /**
351         * Creates a new instance of the {@code Builder} with the given
352         * {@code context}. The {@code context} passed in may be used to pop up
353         * some UI to ask the user to unlock or initialize the Android KeyStore
354         * facility.
355         */
356        public Builder(Context context) {
357            if (context == null) {
358                throw new NullPointerException("context == null");
359            }
360            mContext = context;
361        }
362
363        /**
364         * Sets the alias to be used to retrieve the key later from a
365         * {@link java.security.KeyStore} instance using the
366         * {@code AndroidKeyStore} provider.
367         */
368        public Builder setAlias(String alias) {
369            if (alias == null) {
370                throw new NullPointerException("alias == null");
371            }
372            mKeystoreAlias = alias;
373            return this;
374        }
375
376        /**
377         * Sets the key type (e.g., RSA, DSA, EC) of the keypair to be created.
378         * @hide
379         */
380        public Builder setKeyType(String keyType) throws NoSuchAlgorithmException {
381            if (keyType == null) {
382                throw new NullPointerException("keyType == null");
383            } else {
384                try {
385                    KeyStore.getKeyTypeForAlgorithm(keyType);
386                } catch (IllegalArgumentException e) {
387                    throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
388                }
389            }
390            mKeyType = keyType;
391            return this;
392        }
393
394        /**
395         * Sets the key size for the keypair to be created. For instance, for a
396         * key type of RSA this will set the modulus size and for a key type of
397         * EC it will select a curve with a matching field size.
398         * @hide
399         */
400        public Builder setKeySize(int keySize) {
401            if (keySize < 0) {
402                throw new IllegalArgumentException("keySize < 0");
403            }
404            mKeySize = keySize;
405            return this;
406        }
407
408        /**
409         * Sets the underlying key type's parameters. This is required for DSA
410         * where you must set this to an instance of
411         * {@link java.security.spec.DSAParameterSpec}.
412         * @hide
413         */
414        public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) {
415            if (spec == null) {
416                throw new NullPointerException("spec == null");
417            }
418            mSpec = spec;
419            return this;
420        }
421
422        /**
423         * Sets the subject used for the self-signed certificate of the
424         * generated key pair.
425         */
426        public Builder setSubject(X500Principal subject) {
427            if (subject == null) {
428                throw new NullPointerException("subject == null");
429            }
430            mSubjectDN = subject;
431            return this;
432        }
433
434        /**
435         * Sets the serial number used for the self-signed certificate of the
436         * generated key pair.
437         */
438        public Builder setSerialNumber(BigInteger serialNumber) {
439            if (serialNumber == null) {
440                throw new NullPointerException("serialNumber == null");
441            }
442            mSerialNumber = serialNumber;
443            return this;
444        }
445
446        /**
447         * Sets the start of the validity period for the self-signed certificate
448         * of the generated key pair.
449         */
450        public Builder setStartDate(Date startDate) {
451            if (startDate == null) {
452                throw new NullPointerException("startDate == null");
453            }
454            mStartDate = startDate;
455            return this;
456        }
457
458        /**
459         * Sets the end of the validity period for the self-signed certificate
460         * of the generated key pair.
461         */
462        public Builder setEndDate(Date endDate) {
463            if (endDate == null) {
464                throw new NullPointerException("endDate == null");
465            }
466            mEndDate = endDate;
467            return this;
468        }
469
470        /**
471         * Indicates that this key must be encrypted at rest on storage. Note
472         * that enabling this will require that the user enable a strong lock
473         * screen (e.g., PIN, password) before creating or using the generated
474         * key is successful.
475         */
476        public Builder setEncryptionRequired() {
477            mFlags |= KeyStore.FLAG_ENCRYPTED;
478            return this;
479        }
480
481        /**
482         * Builds the instance of the {@code KeyPairGeneratorSpec}.
483         *
484         * @throws IllegalArgumentException if a required field is missing
485         * @return built instance of {@code KeyPairGeneratorSpec}
486         */
487        public KeyPairGeneratorSpec build() {
488            return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mKeyType, mKeySize, mSpec,
489                    mSubjectDN, mSerialNumber, mStartDate, mEndDate, mFlags);
490        }
491    }
492}
493