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

Commit 7adc233c authored by Kenny Root's avatar Kenny Root Committed by Gerrit Code Review
Browse files

Merge "Add support for DSA and ECDSA key types"

parents 6110d16b f64386fc
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -244,7 +244,8 @@ public interface IKeystoreService extends IInterface {
                return _result;
            }

            public int generate(String name, int uid, int flags) throws RemoteException {
            public int generate(String name, int uid, int keyType, int keySize, int flags,
                    byte[][] args) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
@@ -252,7 +253,17 @@ public interface IKeystoreService extends IInterface {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    _data.writeInt(uid);
                    _data.writeInt(keyType);
                    _data.writeInt(keySize);
                    _data.writeInt(flags);
                    if (args == null) {
                        _data.writeInt(0);
                    } else {
                        _data.writeInt(args.length);
                        for (int i = 0; i < args.length; i++) {
                            _data.writeByteArray(args[i]);
                        }
                    }
                    mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
@@ -560,7 +571,8 @@ public interface IKeystoreService extends IInterface {

    public int zero() throws RemoteException;

    public int generate(String name, int uid, int flags) throws RemoteException;
    public int generate(String name, int uid, int keyType, int keySize, int flags, byte[][] args)
            throws RemoteException;

    public int import_key(String name, byte[] data, int uid, int flags) throws RemoteException;

+43 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.security;

import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;

import com.android.org.conscrypt.NativeCrypto;
import com.android.org.conscrypt.OpenSSLEngine;

import java.security.InvalidAlgorithmParameterException;
@@ -33,7 +34,10 @@ import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAKeyGenParameterSpec;
import java.security.spec.X509EncodedKeySpec;

/**
@@ -87,8 +91,12 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {

        Credentials.deleteAllTypesForAlias(mKeyStore, alias);

        final int keyType = KeyStore.getKeyTypeForAlgorithm(mSpec.getKeyType());
        byte[][] args = getArgsForKeyType(keyType, mSpec.getAlgorithmParameterSpec());

        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
        if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mSpec.getFlags())) {
        if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, keyType,
                mSpec.getKeySize(), mSpec.getFlags(), args)) {
            throw new IllegalStateException("could not generate key in keystore");
        }

@@ -104,10 +112,10 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {

        final PublicKey pubKey;
        try {
            final KeyFactory keyFact = KeyFactory.getInstance("RSA");
            final KeyFactory keyFact = KeyFactory.getInstance(mSpec.getKeyType());
            pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("Can't instantiate RSA key generator", e);
            throw new IllegalStateException("Can't instantiate key generator", e);
        } catch (InvalidKeySpecException e) {
            throw new IllegalStateException("keystore returned invalid key encoding", e);
        }
@@ -119,7 +127,7 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
        certGen.setIssuerDN(mSpec.getSubjectDN());
        certGen.setNotBefore(mSpec.getStartDate());
        certGen.setNotAfter(mSpec.getEndDate());
        certGen.setSignatureAlgorithm("sha1WithRSA");
        certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyType(mSpec.getKeyType()));

        final X509Certificate cert;
        try {
@@ -146,6 +154,37 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
        return new KeyPair(pubKey, privKey);
    }

    private static String getDefaultSignatureAlgorithmForKeyType(String keyType) {
        if ("RSA".equalsIgnoreCase(keyType)) {
            return "sha256WithRSA";
        } else if ("DSA".equalsIgnoreCase(keyType)) {
            return "sha1WithDSA";
        } else if ("EC".equalsIgnoreCase(keyType)) {
            return "sha256WithECDSA";
        } else {
            throw new IllegalArgumentException("Unsupported key type " + keyType);
        }
    }

    private static byte[][] getArgsForKeyType(int keyType, AlgorithmParameterSpec spec) {
        switch (keyType) {
            case NativeCrypto.EVP_PKEY_RSA:
                if (spec instanceof RSAKeyGenParameterSpec) {
                    RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
                    return new byte[][] { rsaSpec.getPublicExponent().toByteArray() };
                }
                break;
            case NativeCrypto.EVP_PKEY_DSA:
                if (spec instanceof DSAParameterSpec) {
                    DSAParameterSpec dsaSpec = (DSAParameterSpec) spec;
                    return new byte[][] { dsaSpec.getG().toByteArray(),
                            dsaSpec.getP().toByteArray(), dsaSpec.getQ().toByteArray() };
                }
                break;
        }
        return null;
    }

    @Override
    public void initialize(int keysize, SecureRandom random) {
        throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator");
+183 −9
Original line number Diff line number Diff line
@@ -16,13 +16,18 @@

package android.security;

import com.android.org.conscrypt.NativeCrypto;

import android.content.Context;
import android.text.TextUtils;

import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Date;

import javax.security.auth.x500.X500Principal;
@@ -50,10 +55,35 @@ import javax.security.auth.x500.X500Principal;
 * certificate signed by a real Certificate Authority.
 */
public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
    private final String mKeystoreAlias;
    /*
     * These must be kept in sync with system/security/keystore/defaults.h
     */

    /* DSA */
    private static final int DSA_DEFAULT_KEY_SIZE = 1024;
    private static final int DSA_MIN_KEY_SIZE = 512;
    private static final int DSA_MAX_KEY_SIZE = 8192;

    /* EC */
    private static final int EC_DEFAULT_KEY_SIZE = 256;
    private static final int EC_MIN_KEY_SIZE = 192;
    private static final int EC_MAX_KEY_SIZE = 521;

    /* RSA */
    private static final int RSA_DEFAULT_KEY_SIZE = 2048;
    private static final int RSA_MIN_KEY_SIZE = 512;
    private static final int RSA_MAX_KEY_SIZE = 8192;

    private final Context mContext;

    private final String mKeystoreAlias;

    private final String mKeyType;

    private final int mKeySize;

    private final AlgorithmParameterSpec mSpec;

    private final X500Principal mSubjectDN;

    private final BigInteger mSerialNumber;
@@ -84,6 +114,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
     * @param context Android context for the activity
     * @param keyStoreAlias name to use for the generated key in the Android
     *            keystore
     * @param keyType key algorithm to use (RSA, DSA, EC)
     * @param keySize size of key to generate
     * @param spec the underlying key type parameters
     * @param subjectDN X.509 v3 Subject Distinguished Name
     * @param serialNumber X509 v3 certificate serial number
     * @param startDate the start of the self-signed certificate validity period
@@ -93,9 +126,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
     *             {@code endDate} is before {@code startDate}.
     * @hide should be built with KeyPairGeneratorSpecBuilder
     */
    public KeyPairGeneratorSpec(Context context, String keyStoreAlias,
            X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate,
            int flags) {
    public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
            AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
            Date startDate, Date endDate, int flags) {
        if (context == null) {
            throw new IllegalArgumentException("context == null");
        } else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -112,8 +145,18 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
            throw new IllegalArgumentException("endDate < startDate");
        }

        final int keyTypeInt = KeyStore.getKeyTypeForAlgorithm(keyType);
        if (keySize == -1) {
            keySize = getDefaultKeySizeForType(keyTypeInt);
        }
        checkCorrectParametersSpec(keyTypeInt, keySize, spec);
        checkValidKeySize(keyTypeInt, keySize);

        mContext = context;
        mKeystoreAlias = keyStoreAlias;
        mKeyType = keyType;
        mKeySize = keySize;
        mSpec = spec;
        mSubjectDN = subjectDN;
        mSerialNumber = serialNumber;
        mStartDate = startDate;
@@ -121,6 +164,64 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
        mFlags = flags;
    }

    private static int getDefaultKeySizeForType(int keyType) {
        if (keyType == NativeCrypto.EVP_PKEY_DSA) {
            return DSA_DEFAULT_KEY_SIZE;
        } else if (keyType == NativeCrypto.EVP_PKEY_EC) {
            return EC_DEFAULT_KEY_SIZE;
        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
            return RSA_DEFAULT_KEY_SIZE;
        }
        throw new IllegalArgumentException("Invalid key type " + keyType);
    }

    private static void checkValidKeySize(int keyType, int keySize) {
        if (keyType == NativeCrypto.EVP_PKEY_DSA) {
            if (keySize < DSA_MIN_KEY_SIZE || keySize > DSA_MAX_KEY_SIZE) {
                throw new IllegalArgumentException("DSA keys must be >= " + DSA_MIN_KEY_SIZE
                        + " and <= " + DSA_MAX_KEY_SIZE);
            }
        } else if (keyType == NativeCrypto.EVP_PKEY_EC) {
            if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
                throw new IllegalArgumentException("EC keys must be >= " + EC_MIN_KEY_SIZE
                        + " and <= " + EC_MAX_KEY_SIZE);
            }
        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
            if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
                throw new IllegalArgumentException("RSA keys must be >= " + RSA_MIN_KEY_SIZE
                        + " and <= " + RSA_MAX_KEY_SIZE);
            }
        } else {
            throw new IllegalArgumentException("Invalid key type " + keyType);
        }
    }

    private static void checkCorrectParametersSpec(int keyType, int keySize,
            AlgorithmParameterSpec spec) {
        if (keyType == NativeCrypto.EVP_PKEY_DSA && spec != null) {
            if (!(spec instanceof DSAParameterSpec)) {
                throw new IllegalArgumentException("DSA keys must have DSAParameterSpec specified");
            }
        } else if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) {
            if (spec instanceof RSAKeyGenParameterSpec) {
                RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
                if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
                    throw new IllegalArgumentException("RSA key size must match: " + keySize
                            + " vs " + rsaSpec.getKeysize());
                }
            } else {
                throw new IllegalArgumentException("RSA may only use RSAKeyGenParameterSpec");
            }
        }
    }

    /**
     * Gets the Android context used for operations with this instance.
     */
    public Context getContext() {
        return mContext;
    }

    /**
     * Returns the alias that will be used in the {@code java.security.KeyStore}
     * in conjunction with the {@code AndroidKeyStore}.
@@ -130,10 +231,31 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
    }

    /**
     * Gets the Android context used for operations with this instance.
     * Returns the key type (e.g., "RSA", "DSA", "EC") specified by this
     * parameter.
     * @hide
     */
    public Context getContext() {
        return mContext;
    public String getKeyType() {
        return mKeyType;
    }

    /**
     * Returns the key size specified by this parameter. For instance, for RSA
     * this will return the modulus size and for EC it will return the field
     * size.
     * @hide
     */
    public int getKeySize() {
        return mKeySize;
    }

    /**
     * Returns the {@link AlgorithmParameterSpec} that will be used for creation
     * of the key pair.
     * @hide
     */
    public AlgorithmParameterSpec getAlgorithmParameterSpec() {
        return mSpec;
    }

    /**
@@ -209,6 +331,12 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {

        private String mKeystoreAlias;

        private String mKeyType = "RSA";

        private int mKeySize = -1;

        private AlgorithmParameterSpec mSpec;

        private X500Principal mSubjectDN;

        private BigInteger mSerialNumber;
@@ -245,6 +373,52 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
            return this;
        }

        /**
         * Sets the key type (e.g., RSA, DSA, EC) of the keypair to be created.
         * @hide
         */
        public Builder setKeyType(String keyType) throws NoSuchAlgorithmException {
            if (keyType == null) {
                throw new NullPointerException("keyType == null");
            } else {
                try {
                    KeyStore.getKeyTypeForAlgorithm(keyType);
                } catch (IllegalArgumentException e) {
                    throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
                }
            }
            mKeyType = keyType;
            return this;
        }

        /**
         * Sets the key size for the keypair to be created. For instance, for a
         * key type of RSA this will set the modulus size and for a key type of
         * EC it will select a curve with a matching field size.
         * @hide
         */
        public Builder setKeySize(int keySize) {
            if (keySize < 0) {
                throw new IllegalArgumentException("keySize < 0");
            }
            mKeySize = keySize;
            return this;
        }

        /**
         * Sets the underlying key type's parameters. This is required for DSA
         * where you must set this to an instance of
         * {@link java.security.spec.DSAParameterSpec}.
         * @hide
         */
        public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) {
            if (spec == null) {
                throw new NullPointerException("spec == null");
            }
            mSpec = spec;
            return this;
        }

        /**
         * Sets the subject used for the self-signed certificate of the
         * generated key pair.
@@ -311,8 +485,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
         * @return built instance of {@code KeyPairGeneratorSpec}
         */
        public KeyPairGeneratorSpec build() {
            return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
                    mSerialNumber, mStartDate, mEndDate, mFlags);
            return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mKeyType, mKeySize, mSpec,
                    mSubjectDN, mSerialNumber, mStartDate, mEndDate, mFlags);
        }
    }
}
+17 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.security;

import com.android.org.conscrypt.NativeCrypto;

import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -64,6 +66,18 @@ public class KeyStore {
        return new KeyStore(keystore);
    }

    static int getKeyTypeForAlgorithm(String keyType) throws IllegalArgumentException {
        if ("RSA".equalsIgnoreCase(keyType)) {
            return NativeCrypto.EVP_PKEY_RSA;
        } else if ("DSA".equalsIgnoreCase(keyType)) {
            return NativeCrypto.EVP_PKEY_DSA;
        } else if ("EC".equalsIgnoreCase(keyType)) {
            return NativeCrypto.EVP_PKEY_EC;
        } else {
            throw new IllegalArgumentException("Unsupported key type: " + keyType);
        }
    }

    public State state() {
        final int ret;
        try {
@@ -188,9 +202,10 @@ public class KeyStore {
        }
    }

    public boolean generate(String key, int uid, int flags) {
    public boolean generate(String key, int uid, int keyType, int keySize, int flags,
            byte[][] args) {
        try {
            return mBinder.generate(key, uid, flags) == NO_ERROR;
            return mBinder.generate(key, uid, keyType, keySize, flags, args) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
+267 −13

File changed.

Preview size limit exceeded, changes collapsed.

Loading