Merge "Avoid IllegalStateException when generating/importing keys." into mnc-dev

This commit is contained in:
Alex Klyubin
2015-07-06 21:50:42 +00:00
committed by Android (Google) Code Review
4 changed files with 106 additions and 90 deletions

View File

@@ -239,6 +239,13 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
"At least one digest algorithm must be specified"); "At least one digest algorithm must be specified");
} }
} }
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds());
} catch (IllegalStateException | IllegalArgumentException e) { } catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e); throw new InvalidAlgorithmParameterException(e);
} }

View File

@@ -310,7 +310,14 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} else { } else {
mKeymasterDigests = EmptyArray.INT; mKeymasterDigests = EmptyArray.INT;
} }
} catch (IllegalArgumentException e) {
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds());
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e); throw new InvalidAlgorithmParameterException(e);
} }

View File

@@ -484,8 +484,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
spec.getKeyValidityForOriginationEnd()); spec.getKeyValidityForOriginationEnd());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
spec.getKeyValidityForConsumptionEnd()); spec.getKeyValidityForConsumptionEnd());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException("Invalid parameter", e); throw new KeyStoreException(e);
} }
} }
@@ -598,102 +598,100 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
+ " RAW format export"); + " RAW format export");
} }
String keyAlgorithmString = key.getAlgorithm();
int keymasterAlgorithm;
int keymasterDigest;
try {
keymasterAlgorithm =
KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(keyAlgorithmString);
keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString);
} catch (IllegalArgumentException e) {
throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
}
KeymasterArguments args = new KeymasterArguments(); KeymasterArguments args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm); try {
int keymasterAlgorithm =
KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
int[] keymasterDigests; int[] keymasterDigests;
if (params.isDigestsSpecified()) { int keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
// Digest(s) specified in parameters if (params.isDigestsSpecified()) {
keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests()); // Digest(s) specified in parameters
if (keymasterDigest != -1) { keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
// Digest also specified in the JCA key algorithm name. if (keymasterDigest != -1) {
if (!com.android.internal.util.ArrayUtils.contains( // Digest also specified in the JCA key algorithm name.
keymasterDigests, keymasterDigest)) { if (!com.android.internal.util.ArrayUtils.contains(
throw new KeyStoreException("Key digest mismatch" keymasterDigests, keymasterDigest)) {
+ ". Key: " + keyAlgorithmString throw new KeyStoreException("Digest specified in key algorithm "
+ ", parameter spec: " + Arrays.asList(params.getDigests())); + key.getAlgorithm() + " not specified in protection parameters: "
} + Arrays.asList(params.getDigests()));
// When the key is read back from keystore we reconstruct the JCA key algorithm }
// name from the KM_TAG_ALGORITHM and the first KM_TAG_DIGEST. Thus we need to // When the key is read back from keystore we reconstruct the JCA key algorithm
// ensure that the digest reflected in the JCA key algorithm name is the first // name from the KM_TAG_ALGORITHM and the first KM_TAG_DIGEST. Thus we need to
// KM_TAG_DIGEST tag. // ensure that the digest reflected in the JCA key algorithm name is the first
if (keymasterDigests[0] != keymasterDigest) { // KM_TAG_DIGEST tag.
// The first digest is not the one implied by the JCA key algorithm name. if (keymasterDigests[0] != keymasterDigest) {
// Swap the implied digest with the first one. // The first digest is not the one implied by the JCA key algorithm name.
for (int i = 0; i < keymasterDigests.length; i++) { // Swap the implied digest with the first one.
if (keymasterDigests[i] == keymasterDigest) { for (int i = 0; i < keymasterDigests.length; i++) {
keymasterDigests[i] = keymasterDigests[0]; if (keymasterDigests[i] == keymasterDigest) {
keymasterDigests[0] = keymasterDigest; keymasterDigests[i] = keymasterDigests[0];
break; keymasterDigests[0] = keymasterDigest;
break;
}
} }
} }
} }
}
} else {
// No digest specified in parameters
if (keymasterDigest != -1) {
// Digest specified in the JCA key algorithm name.
keymasterDigests = new int[] {keymasterDigest};
} else { } else {
keymasterDigests = EmptyArray.INT; // No digest specified in parameters
} if (keymasterDigest != -1) {
} // Digest specified in the JCA key algorithm name.
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests); keymasterDigests = new int[] {keymasterDigest};
if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { } else {
if (keymasterDigests.length == 0) { keymasterDigests = EmptyArray.INT;
throw new KeyStoreException("At least one digest algorithm must be specified" }
+ " for key algorithm " + keyAlgorithmString); }
} args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
} if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
if (keymasterDigests.length == 0) {
@KeyProperties.PurposeEnum int purposes = params.getPurposes(); throw new KeyStoreException("At least one digest algorithm must be specified"
int[] keymasterBlockModes = + " for key algorithm " + key.getAlgorithm());
KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
&& (params.isRandomizedEncryptionRequired())) {
for (int keymasterBlockMode : keymasterBlockModes) {
if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
keymasterBlockMode)) {
throw new KeyStoreException(
"Randomized encryption (IND-CPA) required but may be violated by block"
+ " mode: "
+ KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
+ ". See KeyProtection documentation.");
} }
} }
}
args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, KeyProperties.Purpose.allToKeymaster(purposes));
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
if (params.getSignaturePaddings().length > 0) {
throw new KeyStoreException("Signature paddings not supported for symmetric keys");
}
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
KeymasterUtils.addUserAuthArgs(args,
params.isUserAuthenticationRequired(),
params.getUserAuthenticationValidityDurationSeconds());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
params.getKeyValidityForOriginationEnd());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
params.getKeyValidityForConsumptionEnd());
if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) @KeyProperties.PurposeEnum int purposes = params.getPurposes();
&& (!params.isRandomizedEncryptionRequired())) { int[] keymasterBlockModes =
// Permit caller-provided IV when encrypting with this key KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
&& (params.isRandomizedEncryptionRequired())) {
for (int keymasterBlockMode : keymasterBlockModes) {
if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
keymasterBlockMode)) {
throw new KeyStoreException(
"Randomized encryption (IND-CPA) required but may be violated by"
+ " block mode: "
+ KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
+ ". See KeyProtection documentation.");
}
}
}
args.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
KeyProperties.Purpose.allToKeymaster(purposes));
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
if (params.getSignaturePaddings().length > 0) {
throw new KeyStoreException("Signature paddings not supported for symmetric keys");
}
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
KeymasterUtils.addUserAuthArgs(args,
params.isUserAuthenticationRequired(),
params.getUserAuthenticationValidityDurationSeconds());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
params.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
params.getKeyValidityForOriginationEnd());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
params.getKeyValidityForConsumptionEnd());
if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
&& (!params.isRandomizedEncryptionRequired())) {
// Permit caller-provided IV when encrypting with this key
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
}
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
} }
Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias); Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias);

View File

@@ -87,6 +87,10 @@ public abstract class KeymasterUtils {
* @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user * @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user
* authentication is valid as authorization for using the key or {@code -1} if every * authentication is valid as authorization for using the key or {@code -1} if every
* use of the key needs authorization. * use of the key needs authorization.
*
* @throws IllegalStateException if user authentication is required but the system is in a wrong
* state (e.g., secure lock screen not set up) for generating or importing keys that
* require user authentication.
*/ */
public static void addUserAuthArgs(KeymasterArguments args, public static void addUserAuthArgs(KeymasterArguments args,
boolean userAuthenticationRequired, boolean userAuthenticationRequired,