Merge "Keystore 2.0 SPI: Update KeyInfo and KeyGenParameterSpec"

This commit is contained in:
Janis Danisevskis
2020-11-11 23:10:13 +00:00
committed by Gerrit Code Review
9 changed files with 186 additions and 15 deletions

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}