summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Frank Salim <franksalim@google.com> 2018-04-02 23:13:25 +0000
committer android-build-merger <android-build-merger@google.com> 2018-04-02 23:13:25 +0000
commit1a2743029adabca71c8c8c36ca3a9f68a776d080 (patch)
tree5d9c394110a860a32e5fc24fa3d5aaa6b8029478
parent8700c434837f5ca834b35cb0d690d744e8bf1eea (diff)
parent50228a647183c9315312f8f36ba849f8b1e6d3d0 (diff)
Merge "Revise secure key import API after review" into pi-dev
am: 50228a6471 Change-Id: I4fe07806b781d337f2df40f34fb75662187f4360
-rw-r--r--api/current.txt11
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java10
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java6
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreProvider.java11
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java5
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java6
-rw-r--r--keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java46
-rw-r--r--keystore/java/android/security/keystore/StrongBoxUnavailableException.java15
-rw-r--r--keystore/java/android/security/keystore/WrappedKeyEntry.java59
9 files changed, 157 insertions, 12 deletions
diff --git a/api/current.txt b/api/current.txt
index bea1b2a1dc34..47ce87d0d03b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38729,7 +38729,18 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setUserConfirmationRequired(boolean);
}
+ public class SecureKeyImportUnavailableException extends java.security.ProviderException {
+ ctor public SecureKeyImportUnavailableException();
+ ctor public SecureKeyImportUnavailableException(java.lang.String);
+ ctor public SecureKeyImportUnavailableException(java.lang.String, java.lang.Throwable);
+ ctor public SecureKeyImportUnavailableException(java.lang.Throwable);
+ }
+
public class StrongBoxUnavailableException extends java.security.ProviderException {
+ ctor public StrongBoxUnavailableException();
+ ctor public StrongBoxUnavailableException(java.lang.String);
+ ctor public StrongBoxUnavailableException(java.lang.String, java.lang.Throwable);
+ ctor public StrongBoxUnavailableException(java.lang.Throwable);
}
public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
index e4cf84afcb8f..cc805605bdf8 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
@@ -93,15 +93,17 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider {
putSymmetricCipherImpl("AES/CTR/NoPadding",
PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
- putSymmetricCipherImpl("DESede/CBC/NoPadding",
+ if ("true".equals(System.getProperty("supports3DES"))) {
+ putSymmetricCipherImpl("DESede/CBC/NoPadding",
PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
- putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
+ putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding");
- putSymmetricCipherImpl("DESede/ECB/NoPadding",
+ putSymmetricCipherImpl("DESede/ECB/NoPadding",
PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding");
- putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
+ putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding");
+ }
putSymmetricCipherImpl("AES/GCM/NoPadding",
PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding");
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index d68a33de2c61..5fc742afeaeb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -475,6 +475,12 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
success = true;
return keyPair;
+ } catch (ProviderException e) {
+ if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
+ throw new SecureKeyImportUnavailableException(e);
+ } else {
+ throw e;
+ }
} finally {
if (!success) {
Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 2c45d43da3f1..9b7695daf5ff 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -67,6 +67,8 @@ public class AndroidKeyStoreProvider extends Provider {
public AndroidKeyStoreProvider() {
super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
+ boolean supports3DES = "true".equals(System.getProperty("supports3DES"));
+
// java.security.KeyStore
put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
@@ -80,16 +82,21 @@ public class AndroidKeyStoreProvider extends Provider {
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
- put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1");
put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224");
put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256");
put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA384");
put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA512");
+ if (supports3DES) {
+ put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
+ }
+
// java.security.SecretKeyFactory
putSecretKeyFactoryImpl("AES");
- putSecretKeyFactoryImpl("DESede");
+ if (supports3DES) {
+ putSecretKeyFactoryImpl("DESede");
+ }
putSecretKeyFactoryImpl("HmacSHA1");
putSecretKeyFactoryImpl("HmacSHA224");
putSecretKeyFactoryImpl("HmacSHA256");
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index fc86ca0443b0..3e9853c455e5 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -26,6 +26,7 @@ import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;
@@ -755,7 +756,9 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
0, // FIXME fingerprint id?
mUid,
new KeyCharacteristics());
- if (errorCode != KeyStore.NO_ERROR) {
+ if (errorCode == KeymasterDefs.KM_ERROR_UNIMPLEMENTED) {
+ throw new SecureKeyImportUnavailableException("Could not import wrapped key");
+ } else if (errorCode != KeyStore.NO_ERROR) {
throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
+ errorCode);
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index f54b6decc5c4..f12a659039ee 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -689,7 +689,11 @@ public abstract class KeyProperties {
*/
public static final int ORIGIN_UNKNOWN = 1 << 2;
- /** Key was imported into the AndroidKeyStore in an encrypted wrapper */
+ /**
+ * Key was imported into the AndroidKeyStore in an encrypted wrapper. Unlike imported keys,
+ * securely imported keys can be imported without appearing as plaintext in the device's host
+ * memory.
+ */
public static final int ORIGIN_SECURELY_IMPORTED = 1 << 3;
diff --git a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
new file mode 100644
index 000000000000..d1cc572bdaf7
--- /dev/null
+++ b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.KeyStore;
+import android.security.KeyStoreException;
+
+import java.security.ProviderException;
+
+/**
+ * Indicates that the Keystore does not support securely importing wrapped keys.
+ */
+public class SecureKeyImportUnavailableException extends ProviderException {
+
+ public SecureKeyImportUnavailableException() {
+ super();
+ }
+
+ public SecureKeyImportUnavailableException(String message) {
+ super(message, new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE,
+ "Secure Key Import not available"));
+ }
+
+ public SecureKeyImportUnavailableException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SecureKeyImportUnavailableException(Throwable cause) {
+ super(cause);
+ }
+}
+
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index 66a77ed1a0de..6c7e9a9521e0 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -27,13 +27,22 @@ import java.security.ProviderException;
*/
public class StrongBoxUnavailableException extends ProviderException {
- /**
- * @hide
- */
+ public StrongBoxUnavailableException() {
+ super();
+ }
+
public StrongBoxUnavailableException(String message) {
super(message,
new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
);
}
+
+ public StrongBoxUnavailableException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public StrongBoxUnavailableException(Throwable cause) {
+ super(cause);
+ }
}
diff --git a/keystore/java/android/security/keystore/WrappedKeyEntry.java b/keystore/java/android/security/keystore/WrappedKeyEntry.java
index a8f4afe7a201..7155686b1385 100644
--- a/keystore/java/android/security/keystore/WrappedKeyEntry.java
+++ b/keystore/java/android/security/keystore/WrappedKeyEntry.java
@@ -21,7 +21,55 @@ import java.security.KeyStore.Entry;
import java.security.spec.AlgorithmParameterSpec;
/**
- * An {@link Entry} that holds a wrapped key.
+ * An {@link Entry} that holds a wrapped key. Wrapped keys contain encrypted key data and
+ * description information that can be used to securely import key material into a hardware-backed
+ * Keystore.
+ *
+ * <p>
+ * The wrapped key is in DER-encoded ASN.1 format, specified by the following schema:
+ * </p>
+ *
+ * <pre>
+ * KeyDescription ::= SEQUENCE(
+ * keyFormat INTEGER, # Values from KeyFormat enum.
+ * keyParams AuthorizationList,
+ * )
+ *
+ * SecureKeyWrapper ::= SEQUENCE(
+ * version INTEGER, # Contains value 0
+ * encryptedTransportKey OCTET_STRING,
+ * initializationVector OCTET_STRING,
+ * keyDescription KeyDescription,
+ * encryptedKey OCTET_STRING,
+ * tag OCTET_STRING
+ * )
+ * </pre>
+ * <ul>
+ * <li>keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+ * key material.
+ * </li>
+ * <li>keyParams is the characteristics of the key to be imported (as with generateKey or
+ * importKey). If the secure import is successful, these characteristics must be
+ * associated with the key exactly as if the key material had been insecurely imported
+ * with importKey. See <a href="https://developer.android.com/training/articles/security-key-attestation.html#certificate_schema">Key Attestation</a> for the AuthorizationList format.
+ * </li>
+ * <li>encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+ * in RSA-OAEP mode (SHA-256 digest, SHA-1 MGF1 digest) with the wrapping key specified by
+ * wrappingKeyBlob.
+ * </li>
+ * <li>keyDescription is a KeyDescription, above.
+ * </li>
+ * <li>encryptedKey is the key material of the key to be imported, in format keyFormat, and
+ * encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
+ * representation of keyDescription provided as additional authenticated data.
+ * </li>
+ * <li>tag is the tag produced by the AES-GCM encryption of encryptedKey.
+ * </li>
+ *</ul>
+ *
+ * <p>
+ * Imported wrapped keys will have KeymasterDefs.KM_ORIGIN_SECURELY_IMPORTED
+ * </p>
*/
public class WrappedKeyEntry implements Entry {
@@ -30,6 +78,14 @@ public class WrappedKeyEntry implements Entry {
private final String mTransformation;
private final AlgorithmParameterSpec mAlgorithmParameterSpec;
+ /**
+ * Constructs a {@link WrappedKeyEntry} with a binary wrapped key.
+ *
+ * @param wrappedKeyBytes ASN.1 DER encoded wrapped key
+ * @param wrappingKeyAlias identifies the private key that can unwrap the wrapped key
+ * @param transformation used to unwrap the key. ex: "RSA/ECB/OAEPPadding"
+ * @param algorithmParameterSpec spec for the private key used to unwrap the wrapped key
+ */
public WrappedKeyEntry(byte[] wrappedKeyBytes, String wrappingKeyAlias, String transformation,
AlgorithmParameterSpec algorithmParameterSpec) {
mWrappedKeyBytes = wrappedKeyBytes;
@@ -54,3 +110,4 @@ public class WrappedKeyEntry implements Entry {
return mAlgorithmParameterSpec;
}
}
+