Merge "KeyStore: X25519 key import"
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())) {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implem
|
|||||||
getUserKeyDescriptor(),
|
getUserKeyDescriptor(),
|
||||||
getKeyIdDescriptor().nspace,
|
getKeyIdDescriptor().nspace,
|
||||||
getAuthorizations(),
|
getAuthorizations(),
|
||||||
"x25519",
|
"XDH",
|
||||||
getSecurityLevel());
|
getSecurityLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user