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

Commit 0ee5912b authored by Prashant Patil's avatar Prashant Patil
Browse files

Keystore:Expected exception for invalid Keys

If EC curves of Public and Private keys are different, an
InvalidKeyException is expected.

But the current implementation does not throw exception from doPhase method
and fails in generateSecret method.

The fix is in AndroidKeyStoreECPublicKey to provide
correct ECParameterSpec while creating a PrivateKey object.

Bug: 215175472
Test: run cts -m CtsKeystoreWycheproofTestCases -t com.google.security.wycheproof.JsonEcdhTest#testSecp224r1
Test: run cts -m CtsKeystoreWycheproofTestCases -t com.google.security.wycheproof.JsonEcdhTest#testSecp256r1
Test: run cts -m CtsKeystoreWycheproofTestCases -t com.google.security.wycheproof.JsonEcdhTest#testSecp384r1
Test: run cts -m CtsKeystoreWycheproofTestCases -t com.google.security.wycheproof.JsonEcdhTest#testSecp521r1
Test: run cts -m CtsKeystoreTestCases -t android.keystore.cts.KeyAgreementTest#testDoPhase_withDifferentCurveKey_fails
Change-Id: Ie221926d8a3be3fe6679e723575c5021cafba98e
parent 11cf8289
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ public final class KeymasterDefs {
    public static final int KM_TAG_PADDING = Tag.PADDING; // KM_ENUM_REP | 6;
    public static final int KM_TAG_CALLER_NONCE = Tag.CALLER_NONCE; // KM_BOOL | 7;
    public static final int KM_TAG_MIN_MAC_LENGTH = Tag.MIN_MAC_LENGTH; // KM_UINT | 8;
    public static final int KM_TAG_EC_CURVE = Tag.EC_CURVE; // KM_ENUM | 10;

    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200;
    public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202;
+41 −1
Original line number Diff line number Diff line
@@ -18,13 +18,19 @@ package android.security.keystore2;

import android.annotation.NonNull;
import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
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.
@@ -56,11 +62,45 @@ 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(
                            a.keyParameter.value.getEcCurve()));
                    break;
                }
            } catch (Exception e) {
                throw new RuntimeException("Unable to parse EC curve "
                        + a.keyParameter.value.getEcCurve());
            }
        }
        return new AndroidKeyStoreECPrivateKey(
                getUserKeyDescriptor(), getKeyIdDescriptor().nspace, getAuthorizations(),
                getSecurityLevel(), mParams);
                getSecurityLevel(), params);
    }

    @Override
+11 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import java.security.NoSuchAlgorithmException;
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;
@@ -132,6 +134,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)) {
            throw new InvalidKeyException(
                    "Public and Private key should be of the same type:");
        } else if (mKey instanceof ECKey
                && !((ECKey) key).getParams().getCurve()
                .equals(((ECKey) mKey).getParams().getCurve())) {
            throw new InvalidKeyException(
                    "Public and Private key parameters should be same.");
        } else if (!lastPhase) {
            throw new IllegalStateException(
                    "Only one other party supported. lastPhase must be set to true.");
+13 −3
Original line number Diff line number Diff line
@@ -22,16 +22,18 @@ import android.system.keystore2.Authorization;
import android.system.keystore2.KeyDescriptor;

import java.security.PrivateKey;
import java.security.interfaces.EdECKey;
import java.security.interfaces.XECPrivateKey;
import java.security.spec.NamedParameterSpec;
import java.util.Optional;

/**
 * X25519 Private Key backed by Keystore.
 * instance of {@link PrivateKey} and {@link EdECKey}
 * instance of {@link PrivateKey} and {@link XECPrivateKey}
 *
 * @hide
 */
public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey
        implements XECPrivateKey {
    public AndroidKeyStoreXDHPrivateKey(
            @NonNull KeyDescriptor descriptor, long keyId,
            @NonNull Authorization[] authorizations,
@@ -44,4 +46,12 @@ public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey impl
    public NamedParameterSpec getParams() {
        return NamedParameterSpec.X25519;
    }

    @Override
    public Optional<byte[]> getScalar() {
        /* An empty Optional if the scalar cannot be extracted (e.g. if the provider is a hardware
         * token and the private key is not allowed to leave the crypto boundary).
         */
        return Optional.empty();
    }
}