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}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 */ 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 * guide/topics/security/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 */ 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