Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb479e08 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Keystore: Support Curve 25519 in the SPI layer" am: 76cee808 am: 7b176536

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1984970

Change-Id: I7434def089facb812a5d4fc59889ac402354df27
parents b0aeecc0 7b176536
Loading
Loading
Loading
Loading
+83 −28
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.NamedParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
@@ -119,36 +120,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
    private static final int RSA_MIN_KEY_SIZE = 512;
    private static final int RSA_MAX_KEY_SIZE = 8192;

    private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
    private static final Map<String, Integer> SUPPORTED_EC_CURVE_NAME_TO_SIZE =
            new HashMap<String, Integer>();
    private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
    private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
    private static final List<String> SUPPORTED_EC_CURVE_NAMES = new ArrayList<String>();
    private static final List<Integer> SUPPORTED_EC_CURVE_SIZES = new ArrayList<Integer>();
    private static final String CURVE_X_25519 = NamedParameterSpec.X25519.getName();
    private static final String CURVE_ED_25519 = NamedParameterSpec.ED25519.getName();


    static {
        // Aliases for NIST P-224
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-224", 224);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp224r1", 224);


        // Aliases for NIST P-256
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-256", 256);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
        // Aliases for Curve 25519
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_X_25519.toLowerCase(Locale.US), 256);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_ED_25519.toLowerCase(Locale.US), 256);

        // Aliases for NIST P-384
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-384", 384);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp384r1", 384);

        // Aliases for NIST P-521
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-521", 521);
        SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp521r1", 521);

        SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
        Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
        SUPPORTED_EC_CURVE_NAMES.addAll(SUPPORTED_EC_CURVE_NAME_TO_SIZE.keySet());
        Collections.sort(SUPPORTED_EC_CURVE_NAMES);

        SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
                new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
        Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
        SUPPORTED_EC_CURVE_SIZES.addAll(
                new HashSet<Integer>(SUPPORTED_EC_CURVE_NAME_TO_SIZE.values()));
        Collections.sort(SUPPORTED_EC_CURVE_SIZES);
    }

    private final int mOriginalKeymasterAlgorithm;
@@ -164,6 +171,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
    private int mKeySizeBits;
    private SecureRandom mRng;
    private KeyDescriptor mAttestKeyDescriptor;
    private String mEcCurveName;

    private int[] mKeymasterPurposes;
    private int[] mKeymasterBlockModes;
@@ -177,12 +185,15 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
        mOriginalKeymasterAlgorithm = keymasterAlgorithm;
    }

    private @EcCurve int keySize2EcCurve(int keySizeBits)
    private static @EcCurve int keySizeAndNameToEcCurve(int keySizeBits, String ecCurveName)
            throws InvalidAlgorithmParameterException {
        switch (keySizeBits) {
            case 224:
                return EcCurve.P_224;
            case 256:
                if (isCurve25519(ecCurveName)) {
                    return EcCurve.CURVE_25519;
                }
                return EcCurve.P_256;
            case 384:
                return EcCurve.P_384;
@@ -247,7 +258,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
            if (mKeySizeBits == -1) {
                mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
            }
            checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
            checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked(),
                    mEcCurveName);

            if (spec.getKeystoreAlias() == null) {
                throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
@@ -299,6 +311,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato

            mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec);
            checkAttestKeyPurpose(spec);
            checkCorrectKeyPurposeForCurve(spec);

            success = true;
        } finally {
@@ -317,6 +330,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
        }
    }

    private void checkCorrectKeyPurposeForCurve(KeyGenParameterSpec spec)
            throws InvalidAlgorithmParameterException {
        // Validate the key usage purposes against the curve. x25519 should be
        // key exchange only, ed25519 signing and attesting.

        if (!isCurve25519(mEcCurveName)) {
            return;
        }

        if (mEcCurveName.equalsIgnoreCase(CURVE_X_25519)
                && spec.getPurposes() != KeyProperties.PURPOSE_AGREE_KEY) {
            throw new InvalidAlgorithmParameterException(
                    "x25519 may only be used for key agreement.");
        } else if (mEcCurveName.equalsIgnoreCase(CURVE_ED_25519)
                && !hasOnlyAllowedPurposeForEd25519(spec.getPurposes())) {
            throw new InvalidAlgorithmParameterException(
                    "ed25519 may not be used for key agreement.");
        }
    }

    private static boolean isCurve25519(String ecCurveName) {
        if (ecCurveName == null) {
            return false;
        }
        return ecCurveName.equalsIgnoreCase(CURVE_X_25519)
                || ecCurveName.equalsIgnoreCase(CURVE_ED_25519);
    }

    private static boolean hasOnlyAllowedPurposeForEd25519(@KeyProperties.PurposeEnum int purpose) {
        final int allowedPurposes = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY
                | KeyProperties.PURPOSE_ATTEST_KEY;
        boolean hasAllowedPurpose = (purpose & allowedPurposes) != 0;
        boolean hasDisallowedPurpose = (purpose & ~allowedPurposes) != 0;
        return hasAllowedPurpose && !hasDisallowedPurpose;
    }

    private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec)
            throws InvalidAlgorithmParameterException {
        if (spec.getAttestKeyAlias() != null) {
@@ -473,6 +522,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
        mRSAPublicExponent = null;
        mRng = null;
        mKeyStore = null;
        mEcCurveName = null;
    }

    private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
@@ -514,13 +564,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
            case KeymasterDefs.KM_ALGORITHM_EC:
                if (algSpecificSpec instanceof ECGenParameterSpec) {
                    ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
                    String curveName = ecSpec.getName();
                    Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
                            curveName.toLowerCase(Locale.US));
                    mEcCurveName = ecSpec.getName();
                    final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get(
                            mEcCurveName.toLowerCase(Locale.US));
                    if (ecSpecKeySizeBits == null) {
                        throw new InvalidAlgorithmParameterException(
                                "Unsupported EC curve name: " + curveName
                                        + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
                                "Unsupported EC curve name: " + mEcCurveName
                                        + ". Supported: " + SUPPORTED_EC_CURVE_NAMES);
                    }
                    if (mKeySizeBits == -1) {
                        mKeySizeBits = ecSpecKeySizeBits;
@@ -744,7 +794,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato

        if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
            params.add(KeyStore2ParameterUtils.makeEnum(
                    Tag.EC_CURVE, keySize2EcCurve(mKeySizeBits)
                    Tag.EC_CURVE, keySizeAndNameToEcCurve(mKeySizeBits, mEcCurveName)
            ));
        }

@@ -864,7 +914,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
    private static void checkValidKeySize(
            int keymasterAlgorithm,
            int keySize,
            boolean isStrongBoxBacked)
            boolean isStrongBoxBacked,
            String mEcCurveName)
            throws InvalidAlgorithmParameterException {
        switch (keymasterAlgorithm) {
            case KeymasterDefs.KM_ALGORITHM_EC:
@@ -873,9 +924,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
                            "Unsupported StrongBox EC key size: "
                                    + keySize + " bits. Supported: 256");
                }
                if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
                if (isStrongBoxBacked && isCurve25519(mEcCurveName)) {
                    throw new InvalidAlgorithmParameterException(
                            "Unsupported StrongBox EC: " + mEcCurveName);
                }
                if (!SUPPORTED_EC_CURVE_SIZES.contains(keySize)) {
                    throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
                            + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
                            + keySize + " bits. Supported: " + SUPPORTED_EC_CURVE_SIZES);
                }
                break;
            case KeymasterDefs.KM_ALGORITHM_RSA:
+17 −1
Original line number Diff line number Diff line
@@ -66,6 +66,11 @@ public class AndroidKeyStoreProvider extends Provider {
    private static final String DESEDE_SYSTEM_PROPERTY =
            "ro.hardware.keystore_desede";

    // Conscrypt returns the Ed25519 OID as the JCA key algorithm.
    private static final String ED25519_OID = "1.3.101.112";
    // Conscrypt returns "XDH" as the X25519 JCA key algorithm.
    private static final String X25519_ALIAS = "XDH";

    /** @hide **/
    public AndroidKeyStoreProvider() {
        super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
@@ -78,10 +83,16 @@ public class AndroidKeyStoreProvider extends Provider {
        // java.security.KeyPairGenerator
        put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
        put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
        put("KeyPairGenerator." + X25519_ALIAS,
                PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
        put("KeyPairGenerator." + ED25519_OID,
                PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");

        // java.security.KeyFactory
        putKeyFactoryImpl("EC");
        putKeyFactoryImpl("RSA");
        putKeyFactoryImpl(X25519_ALIAS);
        putKeyFactoryImpl(ED25519_OID);

        // javax.crypto.KeyGenerator
        put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
@@ -219,12 +230,17 @@ public class AndroidKeyStoreProvider extends Provider {

        KeyStoreSecurityLevel securityLevel = iSecurityLevel;
        if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {

            return new AndroidKeyStoreECPublicKey(descriptor, metadata,
                    iSecurityLevel, (ECPublicKey) publicKey);
        } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(jcaKeyAlgorithm)) {
            return new AndroidKeyStoreRSAPublicKey(descriptor, metadata,
                    iSecurityLevel, (RSAPublicKey) publicKey);
        } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) {
            //TODO(b/214203951) missing classes in conscrypt
            throw new ProviderException("Curve " + ED25519_OID + " not supported yet");
        } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
            //TODO(b/214203951) missing classes in conscrypt
            throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
        } else {
            throw new ProviderException("Unsupported Android Keystore public key algorithm: "
                    + jcaKeyAlgorithm);