Merge "KeyStore: X25519 key import"

This commit is contained in:
Eran Messeri
2022-11-25 14:57:55 +00:00
committed by Gerrit Code Review
6 changed files with 125 additions and 47 deletions

View File

@@ -196,6 +196,7 @@ public abstract class KeyProperties {
@StringDef(prefix = { "KEY_" }, value = { @StringDef(prefix = { "KEY_" }, value = {
KEY_ALGORITHM_RSA, KEY_ALGORITHM_RSA,
KEY_ALGORITHM_EC, KEY_ALGORITHM_EC,
KEY_ALGORITHM_XDH,
KEY_ALGORITHM_AES, KEY_ALGORITHM_AES,
KEY_ALGORITHM_HMAC_SHA1, KEY_ALGORITHM_HMAC_SHA1,
KEY_ALGORITHM_HMAC_SHA224, KEY_ALGORITHM_HMAC_SHA224,
@@ -211,6 +212,11 @@ public abstract class KeyProperties {
/** Elliptic Curve (EC) Cryptography key. */ /** Elliptic Curve (EC) Cryptography key. */
public static final String KEY_ALGORITHM_EC = "EC"; public static final String KEY_ALGORITHM_EC = "EC";
/** Curve 25519 based Agreement key.
* @hide
*/
public static final String KEY_ALGORITHM_XDH = "XDH";
/** Advanced Encryption Standard (AES) key. */ /** Advanced Encryption Standard (AES) key. */
public static final String KEY_ALGORITHM_AES = "AES"; public static final String KEY_ALGORITHM_AES = "AES";
@@ -246,7 +252,8 @@ public abstract class KeyProperties {
public static int toKeymasterAsymmetricKeyAlgorithm( public static int toKeymasterAsymmetricKeyAlgorithm(
@NonNull @KeyAlgorithmEnum String algorithm) { @NonNull @KeyAlgorithmEnum String algorithm) {
if (KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) { if (KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)
|| KEY_ALGORITHM_XDH.equalsIgnoreCase(algorithm)) {
return KeymasterDefs.KM_ALGORITHM_EC; return KeymasterDefs.KM_ALGORITHM_EC;
} else if (KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { } else if (KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
return KeymasterDefs.KM_ALGORITHM_RSA; return KeymasterDefs.KM_ALGORITHM_RSA;

View File

@@ -24,13 +24,9 @@ import android.system.keystore2.Authorization;
import android.system.keystore2.KeyDescriptor; import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyMetadata; import android.system.keystore2.KeyMetadata;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPublicKey; import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec; import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint; import java.security.spec.ECPoint;
import java.security.spec.InvalidParameterSpecException;
/** /**
* {@link ECPublicKey} backed by keystore. * {@link ECPublicKey} backed by keystore.
@@ -62,34 +58,13 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme
} }
} }
private static String getEcCurveFromKeymaster(int ecCurve) {
switch (ecCurve) {
case android.hardware.security.keymint.EcCurve.P_224:
return "secp224r1";
case android.hardware.security.keymint.EcCurve.P_256:
return "secp256r1";
case android.hardware.security.keymint.EcCurve.P_384:
return "secp384r1";
case android.hardware.security.keymint.EcCurve.P_521:
return "secp521r1";
}
return "";
}
private ECParameterSpec getCurveSpec(String name)
throws NoSuchAlgorithmException, InvalidParameterSpecException {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(name));
return parameters.getParameterSpec(ECParameterSpec.class);
}
@Override @Override
public AndroidKeyStorePrivateKey getPrivateKey() { public AndroidKeyStorePrivateKey getPrivateKey() {
ECParameterSpec params = mParams; ECParameterSpec params = mParams;
for (Authorization a : getAuthorizations()) { for (Authorization a : getAuthorizations()) {
try { try {
if (a.keyParameter.tag == KeymasterDefs.KM_TAG_EC_CURVE) { if (a.keyParameter.tag == KeymasterDefs.KM_TAG_EC_CURVE) {
params = getCurveSpec(getEcCurveFromKeymaster( params = KeymasterUtils.getCurveSpec(KeymasterUtils.getEcCurveFromKeymaster(
a.keyParameter.value.getEcCurve())); a.keyParameter.value.getEcCurve()));
break; break;
} }

View File

@@ -32,7 +32,6 @@ import java.security.ProviderException;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.interfaces.ECKey; import java.security.interfaces.ECKey;
import java.security.interfaces.XECKey;
import java.security.spec.AlgorithmParameterSpec; import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -134,10 +133,15 @@ public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi
throw new InvalidKeyException("key == null"); throw new InvalidKeyException("key == null");
} else if (!(key instanceof PublicKey)) { } else if (!(key instanceof PublicKey)) {
throw new InvalidKeyException("Only public keys supported. Key: " + key); throw new InvalidKeyException("Only public keys supported. Key: " + key);
} else if (!(mKey instanceof ECKey && key instanceof ECKey) } else if (mKey instanceof ECKey && !(key instanceof ECKey)
&& !(mKey instanceof XECKey && key instanceof XECKey)) { /*&& !(mKey instanceof XECKey && key instanceof XECKey)*/) {
/** TODO This condition is temporary modified, because OpenSSL implementation does not
* implement OpenSSLX25519PublicKey from XECKey interface (b/214203951).
* This change has to revert once conscrypt implements OpenSSLX25519PublicKey from
* XECKey interface.
*/
throw new InvalidKeyException( throw new InvalidKeyException(
"Public and Private key should be of the same type:"); "Public and Private key should be of the same type.");
} else if (mKey instanceof ECKey } else if (mKey instanceof ECKey
&& !((ECKey) key).getParams().getCurve() && !((ECKey) key).getParams().getCurve()
.equals(((ECKey) mKey).getParams().getCurve())) { .equals(((ECKey) mKey).getParams().getCurve())) {

View File

@@ -20,6 +20,7 @@ import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MG
import android.annotation.NonNull; import android.annotation.NonNull;
import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager;
import android.hardware.security.keymint.EcCurve;
import android.hardware.security.keymint.HardwareAuthenticatorType; import android.hardware.security.keymint.HardwareAuthenticatorType;
import android.hardware.security.keymint.KeyParameter; import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.SecurityLevel; import android.hardware.security.keymint.SecurityLevel;
@@ -67,6 +68,14 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.interfaces.ECKey; import java.security.interfaces.ECKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.EdECKey;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.XECKey;
import java.security.interfaces.XECPrivateKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.NamedParameterSpec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@@ -567,22 +576,14 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
spec.getMaxUsageCount() spec.getMaxUsageCount()
)); ));
} }
if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) { if (KeymasterDefs.KM_ALGORITHM_EC
if (key instanceof ECKey) { == KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
ECKey ecKey = (ECKey) key; key.getAlgorithm())) {
importArgs.add(KeyStore2ParameterUtils.makeEnum( importArgs.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_EC_CURVE, KeymasterDefs.KM_TAG_EC_CURVE,
KeyProperties.EcCurve.toKeymasterCurve(ecKey.getParams()) getKeymasterEcCurve(key)
)); ));
} }
}
/* TODO: check for Ed25519(EdDSA) or X25519(XDH) key algorithm and
* add import args for KM_TAG_EC_CURVE as EcCurve.CURVE_25519.
* Currently conscrypt does not support EdDSA key import and XDH keys are not an
* instance of XECKey, hence these conditions are not added, once it is fully
* implemented by conscrypt, we can add CURVE_25519 argument for EdDSA and XDH
* algorithms.
*/
} catch (IllegalArgumentException | IllegalStateException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e); throw new KeyStoreException(e);
} }
@@ -608,6 +609,31 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
} }
} }
private int getKeymasterEcCurve(PrivateKey key) {
if (key instanceof ECKey) {
ECParameterSpec param = ((ECPrivateKey) key).getParams();
int kmECCurve = KeymasterUtils.getKeymasterEcCurve(KeymasterUtils.getCurveName(param));
if (kmECCurve >= 0) {
return kmECCurve;
}
} else if (key instanceof XECKey) {
AlgorithmParameterSpec param = ((XECPrivateKey) key).getParams();
if (param.equals(NamedParameterSpec.X25519)) {
return EcCurve.CURVE_25519;
}
} else if (key.getAlgorithm().equals("XDH")) {
// TODO com.android.org.conscrypt.OpenSSLX25519PrivateKey does not implement XECKey,
// this case is not required once it implements XECKey interface(b/214203951).
return EcCurve.CURVE_25519;
} else if (key instanceof EdECKey) {
AlgorithmParameterSpec param = ((EdECPrivateKey) key).getParams();
if (param.equals(NamedParameterSpec.ED25519)) {
return EcCurve.CURVE_25519;
}
}
throw new IllegalArgumentException("Unexpected Key " + key.getClass().getName());
}
private static void assertCanReplace(String alias, @Domain int targetDomain, private static void assertCanReplace(String alias, @Domain int targetDomain,
int targetNamespace, KeyDescriptor descriptor) int targetNamespace, KeyDescriptor descriptor)
throws KeyStoreException { throws KeyStoreException {

View File

@@ -88,7 +88,7 @@ public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implem
getUserKeyDescriptor(), getUserKeyDescriptor(),
getKeyIdDescriptor().nspace, getKeyIdDescriptor().nspace,
getAuthorizations(), getAuthorizations(),
"x25519", "XDH",
getSecurityLevel()); getSecurityLevel());
} }

View File

@@ -20,7 +20,12 @@ import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs; import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.ProviderException; import java.security.ProviderException;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.InvalidParameterSpecException;
/** /**
* @hide * @hide
@@ -121,4 +126,65 @@ public abstract class KeymasterUtils {
break; break;
} }
} }
static String getEcCurveFromKeymaster(int ecCurve) {
switch (ecCurve) {
case android.hardware.security.keymint.EcCurve.P_224:
return "secp224r1";
case android.hardware.security.keymint.EcCurve.P_256:
return "secp256r1";
case android.hardware.security.keymint.EcCurve.P_384:
return "secp384r1";
case android.hardware.security.keymint.EcCurve.P_521:
return "secp521r1";
}
return "";
}
static int getKeymasterEcCurve(String ecCurveName) {
if (ecCurveName.equals("secp224r1")) {
return android.hardware.security.keymint.EcCurve.P_224;
} else if (ecCurveName.equals("secp256r1")) {
return android.hardware.security.keymint.EcCurve.P_256;
} else if (ecCurveName.equals("secp384r1")) {
return android.hardware.security.keymint.EcCurve.P_384;
} else if (ecCurveName.equals("secp521r1")) {
return android.hardware.security.keymint.EcCurve.P_521;
}
return -1;
}
static ECParameterSpec getCurveSpec(String name)
throws NoSuchAlgorithmException, InvalidParameterSpecException {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(name));
return parameters.getParameterSpec(ECParameterSpec.class);
}
static String getCurveName(ECParameterSpec spec) {
if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp224r1")) {
return "secp224r1";
} else if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp256r1")) {
return "secp256r1";
} else if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp384r1")) {
return "secp384r1";
} else if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp521r1")) {
return "secp521r1";
}
return null;
}
private static boolean isECParameterSpecOfCurve(ECParameterSpec spec, String curveName) {
try {
ECParameterSpec curveSpec = KeymasterUtils.getCurveSpec(curveName);
if (curveSpec.getCurve().equals(spec.getCurve())
&& curveSpec.getOrder().equals(spec.getOrder())
&& curveSpec.getGenerator().equals(spec.getGenerator())) {
return true;
}
} catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
return false;
}
return false;
}
} }