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("myKey") 322 * .setSubject(new X500Principal("CN=myKey")).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