summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-06-04 13:04:43 -0700
committerAlex Klyubin <klyubin@google.com>2015-06-04 13:19:50 -0700
commit97a27a73e6c5f5800303596ceebf314d90429d35 (patch)
treedd19b573980a3f1862a6b5c15cefbbf40551c298 /keystore
parentcb9400aa23b81f12d8af198187fc799d6bcf164a (diff)
downloadframeworks_base-97a27a73e6c5f5800303596ceebf314d90429d35.zip
frameworks_base-97a27a73e6c5f5800303596ceebf314d90429d35.tar.gz
frameworks_base-97a27a73e6c5f5800303596ceebf314d90429d35.tar.bz2
Export KeyFactory backed by Android Keystore.
The KeyFactory can be used to obtain information (KeyInfo) about Android Keystore private keys. Bug: 18088752 Change-Id: Ied1a69928f391537de6765cef7dc7d7241cf62bb
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java91
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreProvider.java8
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java51
3 files changed, 133 insertions, 17 deletions
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
new file mode 100644
index 0000000..20db41b
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.security.Credentials;
+import android.security.KeyStore;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+/**
+ * {@link KeyFactorySpi} backed by Android KeyStore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
+
+ private final KeyStore mKeyStore = KeyStore.getInstance();
+
+ @Override
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpecClass)
+ throws InvalidKeySpecException {
+ if (keySpecClass == null) {
+ throw new InvalidKeySpecException("keySpecClass == null");
+ }
+ if (!(key instanceof AndroidKeyStorePrivateKey)) {
+ throw new InvalidKeySpecException("Only Android KeyStore private keys supported: " +
+ ((key != null) ? key.getClass().getName() : "null"));
+ }
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpecClass)) {
+ throw new InvalidKeySpecException(
+ "Key material export of Android KeyStore keys is not supported");
+ }
+ if (!KeyInfo.class.equals(keySpecClass)) {
+ throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
+ }
+ String keyAliasInKeystore = ((AndroidKeyStoreKey) key).getAlias();
+ String entryAlias;
+ if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
+ entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
+ } else {
+ throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
+ }
+
+ @SuppressWarnings("unchecked")
+ T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
+ mKeyStore, entryAlias, keyAliasInKeystore);
+ return result;
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException {
+ throw new UnsupportedOperationException(
+ "To generate a key pair in Android KeyStore, use KeyPairGenerator initialized with"
+ + " " + KeyGenParameterSpec.class.getName());
+ }
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException {
+ throw new UnsupportedOperationException(
+ "To generate a key pair in Android KeyStore, use KeyPairGenerator initialized with"
+ + " " + KeyGenParameterSpec.class.getName());
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key arg0) throws InvalidKeyException {
+ throw new UnsupportedOperationException(
+ "To import a key into Android KeyStore, use KeyStore.setEntry with "
+ + KeyProtection.class.getName());
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 649a515..1cd49d7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -52,6 +52,10 @@ public class AndroidKeyStoreProvider extends Provider {
put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
+ // java.security.KeyFactory
+ putKeyFactoryImpl("EC");
+ putKeyFactoryImpl("RSA");
+
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1");
@@ -100,6 +104,10 @@ public class AndroidKeyStoreProvider extends Provider {
put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreSecretKeyFactorySpi");
}
+ private void putKeyFactoryImpl(String algorithm) {
+ put("KeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreKeyFactorySpi");
+ }
+
/**
* Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
* primitive.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 455f170..8b00821 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -21,9 +21,8 @@ import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
-import libcore.util.EmptyArray;
-
import java.security.InvalidKeyException;
+import java.security.ProviderException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
@@ -35,7 +34,7 @@ import javax.crypto.SecretKeyFactorySpi;
import javax.crypto.spec.SecretKeySpec;
/**
- * {@link SecretKeyFactorySpi} backed by Android KeyStore.
+ * {@link SecretKeyFactorySpi} backed by Android Keystore.
*
* @hide
*/
@@ -60,7 +59,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
if (!KeyInfo.class.equals(keySpecClass)) {
throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
}
- String keyAliasInKeystore = ((AndroidKeyStoreSecretKey) key).getAlias();
+ String keyAliasInKeystore = ((AndroidKeyStoreKey) key).getAlias();
String entryAlias;
if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
@@ -68,11 +67,15 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
}
+ return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore);
+ }
+
+ static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore) {
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
int errorCode =
- mKeyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
+ keyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
- throw new InvalidKeySpecException("Failed to obtain information about key."
+ throw new ProviderException("Failed to obtain information about key."
+ " Keystore error: " + errorCode);
}
@@ -81,6 +84,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
int keySize;
@KeyProperties.PurposeEnum int purposes;
String[] encryptionPaddings;
+ String[] signaturePaddings;
@KeyProperties.DigestEnum String[] digests;
@KeyProperties.BlockModeEnum String[] blockModes;
int keymasterSwEnforcedUserAuthenticators;
@@ -95,29 +99,40 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
origin = KeyProperties.Origin.fromKeymaster(
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
} else {
- throw new InvalidKeySpecException("Key origin not available");
+ throw new ProviderException("Key origin not available");
}
Integer keySizeInteger = keyCharacteristics.getInteger(KeymasterDefs.KM_TAG_KEY_SIZE);
if (keySizeInteger == null) {
- throw new InvalidKeySpecException("Key size not available");
+ throw new ProviderException("Key size not available");
}
keySize = keySizeInteger;
purposes = KeyProperties.Purpose.allFromKeymaster(
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
List<String> encryptionPaddingsList = new ArrayList<String>();
+ List<String> signaturePaddingsList = new ArrayList<String>();
+ // Keymaster stores both types of paddings in the same array -- we split it into two.
for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
- @KeyProperties.EncryptionPaddingEnum String jcaPadding;
try {
- jcaPadding = KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
+ @KeyProperties.EncryptionPaddingEnum String jcaPadding =
+ KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
+ encryptionPaddingsList.add(jcaPadding);
} catch (IllegalArgumentException e) {
- throw new InvalidKeySpecException(
- "Unsupported encryption padding: " + keymasterPadding);
+ try {
+ @KeyProperties.SignaturePaddingEnum String padding =
+ KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding);
+ signaturePaddingsList.add(padding);
+ } catch (IllegalArgumentException e2) {
+ throw new ProviderException(
+ "Unsupported encryption padding: " + keymasterPadding);
+ }
}
- encryptionPaddingsList.add(jcaPadding);
+
}
encryptionPaddings =
encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
+ signaturePaddings =
+ signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]);
digests = KeyProperties.Digest.allFromKeymaster(
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
@@ -128,7 +143,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
keymasterHwEnforcedUserAuthenticators =
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
} catch (IllegalArgumentException e) {
- throw new InvalidKeySpecException("Unsupported key characteristic", e);
+ throw new ProviderException("Unsupported key characteristic", e);
}
Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
@@ -164,7 +179,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
keyValidityForConsumptionEnd,
purposes,
encryptionPaddings,
- EmptyArray.STRING, // no signature paddings -- this is symmetric crypto
+ signaturePaddings,
digests,
blockModes,
userAuthenticationRequired,
@@ -175,12 +190,14 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
@Override
protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
throw new UnsupportedOperationException(
- "Key import into Android KeyStore is not supported");
+ "To generate secret key in Android KeyStore, use KeyGenerator initialized with "
+ + KeyGenParameterSpec.class.getName());
}
@Override
protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
throw new UnsupportedOperationException(
- "Key import into Android KeyStore is not supported");
+ "To import a secret key into Android KeyStore, use KeyStore.setEntry with "
+ + KeyProtection.class.getName());
}
}