Home | History | Annotate | Download | only in security
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    286     public Date getEndDate() {
    287         return mEndDate;
    288     }
    289 
    290     /**
    291      * @hide
    292      */
    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      */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    481         public KeyPairGeneratorSpec build() {
    482             return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mKeyType, mKeySize, mSpec,
    483                     mSubjectDN, mSerialNumber, mStartDate, mEndDate, mFlags);
    484         }
    485     }
    486 }
    487