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 = {
KEY_ALGORITHM_RSA,
KEY_ALGORITHM_EC,
KEY_ALGORITHM_XDH,
KEY_ALGORITHM_AES,
KEY_ALGORITHM_HMAC_SHA1,
KEY_ALGORITHM_HMAC_SHA224,
@@ -211,6 +212,11 @@ public abstract class KeyProperties {
/** Elliptic Curve (EC) Cryptography key. */
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. */
public static final String KEY_ALGORITHM_AES = "AES";
@@ -246,7 +252,8 @@ public abstract class KeyProperties {
public static int toKeymasterAsymmetricKeyAlgorithm(
@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;
} else if (KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
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.KeyMetadata;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.InvalidParameterSpecException;
/**
* {@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
public AndroidKeyStorePrivateKey getPrivateKey() {
ECParameterSpec params = mParams;
for (Authorization a : getAuthorizations()) {
try {
if (a.keyParameter.tag == KeymasterDefs.KM_TAG_EC_CURVE) {
params = getCurveSpec(getEcCurveFromKeymaster(
params = KeymasterUtils.getCurveSpec(KeymasterUtils.getEcCurveFromKeymaster(
a.keyParameter.value.getEcCurve()));
break;
}

View File

@@ -32,7 +32,6 @@ import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.ECKey;
import java.security.interfaces.XECKey;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.List;
@@ -134,10 +133,15 @@ public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi
throw new InvalidKeyException("key == null");
} else if (!(key instanceof PublicKey)) {
throw new InvalidKeyException("Only public keys supported. Key: " + key);
} else if (!(mKey instanceof ECKey && key instanceof ECKey)
&& !(mKey instanceof XECKey && key instanceof XECKey)) {
} else if (mKey instanceof ECKey && !(key instanceof ECKey)
/*&& !(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(
"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
&& !((ECKey) key).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.hardware.biometrics.BiometricManager;
import android.hardware.security.keymint.EcCurve;
import android.hardware.security.keymint.HardwareAuthenticatorType;
import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.SecurityLevel;
@@ -67,6 +68,14 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
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.Arrays;
import java.util.Collection;
@@ -567,22 +576,14 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
spec.getMaxUsageCount()
));
}
if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
if (key instanceof ECKey) {
ECKey ecKey = (ECKey) key;
importArgs.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_EC_CURVE,
KeyProperties.EcCurve.toKeymasterCurve(ecKey.getParams())
));
}
if (KeymasterDefs.KM_ALGORITHM_EC
== KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
key.getAlgorithm())) {
importArgs.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_EC_CURVE,
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) {
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,
int targetNamespace, KeyDescriptor descriptor)
throws KeyStoreException {

View File

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

View File

@@ -20,7 +20,12 @@ import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.ProviderException;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.InvalidParameterSpecException;
/**
* @hide
@@ -121,4 +126,65 @@ public abstract class KeymasterUtils {
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;
}
}