use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by AOSPA.
the class AndroidKeyStoreECDSASignatureSpi method initKey.
@Override
protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm() + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported");
}
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
int errorCode = getKeyStore().getKeyCharacteristics(key.getAlias(), null, null, key.getUid(), keyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
throw getKeyStore().getInvalidKeyException(key.getAlias(), key.getUid(), errorCode);
}
long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
if (keySizeBits == -1) {
throw new InvalidKeyException("Size of key not known");
} else if (keySizeBits > Integer.MAX_VALUE) {
throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
}
mGroupSizeBits = (int) keySizeBits;
super.initKey(key);
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.
the class AndroidKeyStoreSpi method setPrivateKeyEntry.
private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain, java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
int flags = 0;
KeyProtection spec;
if (param == null) {
spec = getLegacyKeyProtectionParameter(key);
} else if (param instanceof KeyStoreParameter) {
spec = getLegacyKeyProtectionParameter(key);
KeyStoreParameter legacySpec = (KeyStoreParameter) param;
if (legacySpec.isEncryptionRequired()) {
flags = KeyStore.FLAG_ENCRYPTED;
}
} else if (param instanceof KeyProtection) {
spec = (KeyProtection) param;
} else {
throw new KeyStoreException("Unsupported protection parameter class:" + param.getClass().getName() + ". Supported: " + KeyProtection.class.getName() + ", " + KeyStoreParameter.class.getName());
}
// Make sure the chain exists since this is a PrivateKey
if ((chain == null) || (chain.length == 0)) {
throw new KeyStoreException("Must supply at least one Certificate with PrivateKey");
}
// Do chain type checking.
X509Certificate[] x509chain = new X509Certificate[chain.length];
for (int i = 0; i < chain.length; i++) {
if (!"X.509".equals(chain[i].getType())) {
throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #" + i);
}
if (!(chain[i] instanceof X509Certificate)) {
throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #" + i);
}
x509chain[i] = (X509Certificate) chain[i];
}
final byte[] userCertBytes;
try {
userCertBytes = x509chain[0].getEncoded();
} catch (CertificateEncodingException e) {
throw new KeyStoreException("Failed to encode certificate #0", e);
}
/*
* If we have a chain, store it in the CA certificate slot for this
* alias as concatenated DER-encoded certificates. These can be
* deserialized by {@link CertificateFactory#generateCertificates}.
*/
final byte[] chainBytes;
if (chain.length > 1) {
/*
* The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...}
* so we only need the certificates starting at index 1.
*/
final byte[][] certsBytes = new byte[x509chain.length - 1][];
int totalCertLength = 0;
for (int i = 0; i < certsBytes.length; i++) {
try {
certsBytes[i] = x509chain[i + 1].getEncoded();
totalCertLength += certsBytes[i].length;
} catch (CertificateEncodingException e) {
throw new KeyStoreException("Failed to encode certificate #" + i, e);
}
}
/*
* Serialize this into one byte array so we can later call
* CertificateFactory#generateCertificates to recover them.
*/
chainBytes = new byte[totalCertLength];
int outputOffset = 0;
for (int i = 0; i < certsBytes.length; i++) {
final int certLength = certsBytes[i].length;
System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength);
outputOffset += certLength;
certsBytes[i] = null;
}
} else {
chainBytes = null;
}
final String pkeyAlias;
if (key instanceof AndroidKeyStorePrivateKey) {
pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
} else {
pkeyAlias = null;
}
byte[] pkcs8EncodedPrivateKeyBytes;
KeymasterArguments importArgs;
final boolean shouldReplacePrivateKey;
if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
if (!alias.equals(keySubalias)) {
throw new KeyStoreException("Can only replace keys with same alias: " + alias + " != " + keySubalias);
}
shouldReplacePrivateKey = false;
importArgs = null;
pkcs8EncodedPrivateKeyBytes = null;
} else {
shouldReplacePrivateKey = true;
// Make sure the PrivateKey format is the one we support.
final String keyFormat = key.getFormat();
if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
throw new KeyStoreException("Unsupported private key export format: " + keyFormat + ". Only private keys which export their key material in PKCS#8 format are" + " supported.");
}
// Make sure we can actually encode the key.
pkcs8EncodedPrivateKeyBytes = key.getEncoded();
if (pkcs8EncodedPrivateKeyBytes == null) {
throw new KeyStoreException("Private key did not export any key material");
}
importArgs = new KeymasterArguments();
try {
importArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(key.getAlgorithm()));
@KeyProperties.PurposeEnum int purposes = spec.getPurposes();
importArgs.addEnums(KeymasterDefs.KM_TAG_PURPOSE, KeyProperties.Purpose.allToKeymaster(purposes));
if (spec.isDigestsSpecified()) {
importArgs.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeyProperties.Digest.allToKeymaster(spec.getDigests()));
}
importArgs.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()));
int[] keymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(spec.getEncryptionPaddings());
if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (spec.isRandomizedEncryptionRequired())) {
for (int keymasterPadding : keymasterEncryptionPaddings) {
if (!KeymasterUtils.isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(keymasterPadding)) {
throw new KeyStoreException("Randomized encryption (IND-CPA) required but is violated by" + " encryption padding mode: " + KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding) + ". See KeyProtection documentation.");
}
}
}
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
KeymasterUtils.addUserAuthArgs(importArgs, spec.isUserAuthenticationRequired(), spec.getUserAuthenticationValidityDurationSeconds(), spec.isUserAuthenticationValidWhileOnBody(), spec.isInvalidatedByBiometricEnrollment());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, spec.getKeyValidityForOriginationEnd());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, spec.getKeyValidityForConsumptionEnd());
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
}
}
boolean success = false;
try {
// Store the private key, if necessary
if (shouldReplacePrivateKey) {
// Delete the stored private key and any related entries before importing the
// provided key
Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
int errorCode = mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, importArgs, KeymasterDefs.KM_KEY_FORMAT_PKCS8, pkcs8EncodedPrivateKeyBytes, mUid, flags, resultingKeyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
throw new KeyStoreException("Failed to store private key", KeyStore.getKeyStoreException(errorCode));
}
} else {
// Keep the stored private key around -- delete all other entry types
Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
}
// Store the leaf certificate
int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes, mUid, flags);
if (errorCode != KeyStore.NO_ERROR) {
throw new KeyStoreException("Failed to store certificate #0", KeyStore.getKeyStoreException(errorCode));
}
// Store the certificate chain
errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes, mUid, flags);
if (errorCode != KeyStore.NO_ERROR) {
throw new KeyStoreException("Failed to store certificate chain", KeyStore.getKeyStoreException(errorCode));
}
success = true;
} finally {
if (!success) {
if (shouldReplacePrivateKey) {
Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
} else {
Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
}
}
}
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.
the class KeyStoreTest method generateRsaKey.
private KeyCharacteristics generateRsaKey(String name) throws Exception {
KeymasterArguments args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
return outCharacteristics;
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.
the class KeyStoreTest method testOperationPruning.
// This is a very implementation specific test and should be thrown out eventually, however it
// is nice for now to test that keystore is properly pruning operations.
public void testOperationPruning() throws Exception {
String name = "test";
KeymasterArguments args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
IBinder first = result.token;
// Implementation detail: softkeymaster supports 16 concurrent operations
for (int i = 0; i < 16; i++) {
result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
}
// At this point the first operation should be pruned.
assertEquals("Operation should be pruned", KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, mKeyStore.update(first, null, new byte[] { 0x01 }).resultCode);
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.
the class KeyStoreTest method testAppId.
public void testAppId() throws Exception {
String name = "test";
byte[] id = new byte[] { 0x01, 0x02, 0x03 };
KeymasterArguments args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
args.addBytes(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
assertEquals("getKeyCharacteristics should fail without application ID", KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB, mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
assertEquals("getKeyCharacteristics should succeed with application ID", KeyStore.NO_ERROR, mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null, outCharacteristics));
}
Aggregations