summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rwxr-xr-xapi/system-current.txt7
-rw-r--r--core/api/current.txt3
-rw-r--r--core/api/system-current.txt7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreProvider.java26
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java6
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java88
-rw-r--r--keystore/java/android/security/keystore/KeyInfo.java21
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java40
9 files changed, 186 insertions, 15 deletions
diff --git a/api/current.txt b/api/current.txt
index 1a405d52c025..010c896235e3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42821,10 +42821,11 @@ package android.security.keystore {
method public String getKeystoreAlias();
method public int getOrigin();
method public int getPurposes();
+ method public int getSecurityLevel();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
method public int getUserAuthenticationValidityDurationSeconds();
- method public boolean isInsideSecureHardware();
+ method @Deprecated public boolean isInsideSecureHardware();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isTrustedUserPresenceRequired();
method public boolean isUserAuthenticationRequired();
diff --git a/api/system-current.txt b/api/system-current.txt
index 042e2dc53b9c..abe95aebf8b2 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9377,8 +9377,13 @@ package android.security.keystore {
ctor public DeviceIdAttestationException(@Nullable String, @Nullable Throwable);
}
+ public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+ method public int getNamespace();
+ }
+
public static final class KeyGenParameterSpec.Builder {
- method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setNamespace(int);
+ method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
}
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 35abacb4b451..75b34cd096e7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -40989,10 +40989,11 @@ package android.security.keystore {
method public String getKeystoreAlias();
method public int getOrigin();
method public int getPurposes();
+ method public int getSecurityLevel();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
method public int getUserAuthenticationValidityDurationSeconds();
- method public boolean isInsideSecureHardware();
+ method @Deprecated public boolean isInsideSecureHardware();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isTrustedUserPresenceRequired();
method public boolean isUserAuthenticationRequired();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f36f4f33d7fe..a795a53ac3b5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8259,8 +8259,13 @@ package android.security.keystore {
ctor public DeviceIdAttestationException(@Nullable String, @Nullable Throwable);
}
+ public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+ method public int getNamespace();
+ }
+
public static final class KeyGenParameterSpec.Builder {
- method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setNamespace(int);
+ method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 71e6559c53c6..d1b4464c1aed 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -23,6 +23,7 @@ import android.security.KeyStore;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
+import android.sysprop.Keystore2Properties;
import java.io.IOException;
import java.security.KeyFactory;
@@ -111,6 +112,26 @@ public class AndroidKeyStoreProvider extends Provider {
putSecretKeyFactoryImpl("HmacSHA512");
}
+ private static boolean sKeystore2Enabled;
+
+ /**
+ * This function indicates whether or not Keystore 2.0 is enabled. Some parts of the
+ * Keystore SPI must behave subtly differently when Keystore 2.0 is enabled. However,
+ * the platform property that indicates that Keystore 2.0 is enabled is not readable
+ * by applications. So we set this value when {@code install()} is called because it
+ * is called by zygote, which can access Keystore2Properties.
+ *
+ * This function can be removed once the transition to Keystore 2.0 is complete.
+ * b/171305684
+ *
+ * @return true if Keystore 2.0 is enabled.
+ * @hide
+ */
+ public static boolean isKeystore2Enabled() {
+ return sKeystore2Enabled;
+ }
+
+
/**
* Installs a new instance of this provider (and the
* {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -138,6 +159,11 @@ public class AndroidKeyStoreProvider extends Provider {
// priority.
Security.addProvider(workaroundProvider);
}
+
+ // {@code install()} is run by zygote when this property is still accessible. We store its
+ // value so that the Keystore SPI can act accordingly without having to access an internal
+ // property.
+ sKeystore2Enabled = Keystore2Properties.keystore2_enabled().orElse(false);
}
private void putSecretKeyFactoryImpl(String algorithm) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 970726051e11..3694d635422f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -211,7 +211,11 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
userAuthenticationValidWhileOnBody,
trustedUserPresenceRequired,
invalidatedByBiometricEnrollment,
- userConfirmationRequired);
+ userConfirmationRequired,
+ // Keystore 1.0 does not tell us the exact security level of the key
+ // so we report an unknown but secure security level.
+ insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
+ : KeyProperties.SECURITY_LEVEL_SOFTWARE);
}
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 688c4a7b5969..e9aac7ddb56d 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -27,7 +27,6 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.os.Build;
import android.security.GateKeeper;
-import android.security.KeyStore;
import android.text.TextUtils;
import java.math.BigInteger;
@@ -246,7 +245,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
private final String mKeystoreAlias;
- private final int mUid;
+ private final int mNamespace;
private final int mKeySize;
private final AlgorithmParameterSpec mSpec;
private final X500Principal mCertificateSubject;
@@ -286,7 +285,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*/
public KeyGenParameterSpec(
String keyStoreAlias,
- int uid,
+ int namespace,
int keySize,
AlgorithmParameterSpec spec,
X500Principal certificateSubject,
@@ -337,7 +336,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
}
mKeystoreAlias = keyStoreAlias;
- mUid = uid;
+ mNamespace = namespace;
mKeySize = keySize;
mSpec = spec;
mCertificateSubject = certificateSubject;
@@ -382,11 +381,43 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
* Returns the UID which will own the key. {@code -1} is an alias for the UID of the current
* process.
*
+ * @deprecated See deprecation message on {@link KeyGenParameterSpec.Builder#setUid(int)}.
+ * Known namespaces will be translated to their legacy UIDs. Unknown
+ * Namespaces will yield {@link IllegalStateException}.
+ *
* @hide
*/
@UnsupportedAppUsage
+ @Deprecated
public int getUid() {
- return mUid;
+ if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
+ // a UID, because we are still being used with the old Keystore SPI.
+ // TODO This if statement and body can be removed when the Keystore 2 migration is
+ // complete. b/171563717
+ return mNamespace;
+ }
+ try {
+ return KeyProperties.namespaceToLegacyUid(mNamespace);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException("getUid called on KeyGenParameterSpec with non legacy"
+ + " keystore namespace.", e);
+ }
+ }
+
+ /**
+ * Returns the target namespace for the key.
+ * See {@link KeyGenParameterSpec.Builder#setNamespace(int)}.
+ *
+ * @return The numeric namespace as configured in the keystore2_key_contexts files of Android's
+ * SEPolicy.
+ * TODO b/171806779 link to public Keystore 2.0 documentation.
+ * See bug for more details for now.
+ * @hide
+ */
+ @SystemApi
+ public int getNamespace() {
+ return mNamespace;
}
/**
@@ -767,7 +798,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private final String mKeystoreAlias;
private @KeyProperties.PurposeEnum int mPurposes;
- private int mUid = KeyStore.UID_SELF;
+ private int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
private int mKeySize = -1;
private AlgorithmParameterSpec mSpec;
private X500Principal mCertificateSubject;
@@ -830,7 +861,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*/
public Builder(@NonNull KeyGenParameterSpec sourceSpec) {
this(sourceSpec.getKeystoreAlias(), sourceSpec.getPurposes());
- mUid = sourceSpec.getUid();
+ mNamespace = sourceSpec.getNamespace();
mKeySize = sourceSpec.getKeySize();
mSpec = sourceSpec.getAlgorithmParameterSpec();
mCertificateSubject = sourceSpec.getCertificateSubject();
@@ -873,12 +904,51 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*
* @param uid UID or {@code -1} for the UID of the current process.
*
+ * @deprecated Setting the UID of the target namespace is based on a hardcoded
+ * hack in the Keystore service. This is no longer supported with Keystore 2.0/Android S.
+ * Instead, dedicated non UID based namespaces can be configured in SEPolicy using
+ * the keystore2_key_contexts files. The functionality of this method will be supported
+ * by mapping knows special UIDs, such as WIFI, to the newly configured SELinux based
+ * namespaces. Unknown UIDs will yield {@link IllegalArgumentException}.
+ *
* @hide
*/
@SystemApi
@NonNull
+ @Deprecated
public Builder setUid(int uid) {
- mUid = uid;
+ if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
+ // a UID, because we are still being used with the old Keystore SPI.
+ // TODO This if statement and body can be removed when the Keystore 2 migration is
+ // complete. b/171563717
+ mNamespace = uid;
+ return this;
+ }
+ mNamespace = KeyProperties.legacyUidToNamespace(uid);
+ return this;
+ }
+
+ /**
+ * Set the designated SELinux namespace that the key shall live in. The caller must
+ * have sufficient permissions to install a key in the given namespace. Namespaces
+ * can be created using SEPolicy. The keystore2_key_contexts files map numeric
+ * namespaces to SELinux labels, and SEPolicy can be used to grant access to these
+ * namespaces to the desired target context. This is the preferred way to share
+ * keys between system and vendor components, e.g., WIFI settings and WPA supplicant.
+ *
+ * @param namespace Numeric SELinux namespace as configured in keystore2_key_contexts
+ * of Android's SEPolicy.
+ * TODO b/171806779 link to public Keystore 2.0 documentation.
+ * See bug for more details for now.
+ * @return this Builder object.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public Builder setNamespace(int namespace) {
+ mNamespace = namespace;
return this;
}
@@ -1489,7 +1559,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
public KeyGenParameterSpec build() {
return new KeyGenParameterSpec(
mKeystoreAlias,
- mUid,
+ mNamespace,
mKeySize,
mSpec,
mCertificateSubject,
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index d891a25dba68..7158d0cf248e 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -84,6 +84,7 @@ public class KeyInfo implements KeySpec {
private final boolean mTrustedUserPresenceRequired;
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mUserConfirmationRequired;
+ private final @KeyProperties.SecurityLevelEnum int mSecurityLevel;
/**
* @hide
@@ -107,7 +108,8 @@ public class KeyInfo implements KeySpec {
boolean userAuthenticationValidWhileOnBody,
boolean trustedUserPresenceRequired,
boolean invalidatedByBiometricEnrollment,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ @KeyProperties.SecurityLevelEnum int securityLevel) {
mKeystoreAlias = keystoreKeyAlias;
mInsideSecureHardware = insideSecureHardware;
mOrigin = origin;
@@ -131,6 +133,7 @@ public class KeyInfo implements KeySpec {
mTrustedUserPresenceRequired = trustedUserPresenceRequired;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mUserConfirmationRequired = userConfirmationRequired;
+ mSecurityLevel = securityLevel;
}
/**
@@ -144,7 +147,10 @@ public class KeyInfo implements KeySpec {
* Returns {@code true} if the key resides inside secure hardware (e.g., Trusted Execution
* Environment (TEE) or Secure Element (SE)). Key material of such keys is available in
* plaintext only inside the secure hardware and is not exposed outside of it.
+ *
+ * @deprecated This method is superseded by @see getSecurityLevel.
*/
+ @Deprecated
public boolean isInsideSecureHardware() {
return mInsideSecureHardware;
}
@@ -355,4 +361,17 @@ public class KeyInfo implements KeySpec {
public boolean isTrustedUserPresenceRequired() {
return mTrustedUserPresenceRequired;
}
+
+ /**
+ * Returns the security level that the key is protected by.
+ * {@code KeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT} and
+ * {@code KeyProperties.SecurityLevelEnum.STRONGBOX} indicate that the key material resides
+ * in secure hardware. Key material of such keys is available in
+ * plaintext only inside the secure hardware and is not exposed outside of it.
+ *
+ * <p>See {@link KeyProperties}.{@code SecurityLevelEnum} constants.
+ */
+ public @KeyProperties.SecurityLevelEnum int getSecurityLevel() {
+ return mSecurityLevel;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 9050c695eba7..5928540b19bf 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.security.KeyStore;
import android.security.keymaster.KeymasterDefs;
import libcore.util.EmptyArray;
@@ -857,4 +858,43 @@ public abstract class KeyProperties {
}
}
+ /**
+ * This value indicates the implicit keystore namespace of the calling application.
+ * It is used by default. Only select system components can choose a different namespace
+ * which it must be configured in SEPolicy.
+ * @hide
+ */
+ public static final int NAMESPACE_APPLICATION = -1;
+
+ /**
+ * For legacy support, translate namespaces into known UIDs.
+ * @hide
+ */
+ public static int namespaceToLegacyUid(int namespace) {
+ switch (namespace) {
+ case NAMESPACE_APPLICATION:
+ return KeyStore.UID_SELF;
+ // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
+ // b/171305388 and b/171305607
+ default:
+ throw new IllegalArgumentException("No UID corresponding to namespace "
+ + namespace);
+ }
+ }
+
+ /**
+ * For legacy support, translate namespaces into known UIDs.
+ * @hide
+ */
+ public static int legacyUidToNamespace(int uid) {
+ switch (uid) {
+ case KeyStore.UID_SELF:
+ return NAMESPACE_APPLICATION;
+ // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
+ // b/171305388 and b/171305607
+ default:
+ throw new IllegalArgumentException("No namespace corresponding to uid "
+ + uid);
+ }
+ }
}