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

Commit e5795a90 authored by Janis Danisevskis's avatar Janis Danisevskis
Browse files

Keystore 2.0 SPI: KeyStoreKeys adopt Keystore 2.0

KeyStoreKeys can now be constructed from key entry metadata and key
descriptors as defined by the new Keystore AIDL spec.
AndroidKeystorePublicKey can now create the private key proxy.
KeyStoreKeys also cache the key characteristic, which should drastically
reduce the frequency by which the SPI has to call into the Keystore 2.0
daemon.

Test: None
Bug: 159476414
Change-Id: Ia0a7841582621897760be49d39dd5442b70b3aa0
parent ebd964a0
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package android.security.keystore2;

import android.annotation.NonNull;
import android.security.KeyStoreSecurityLevel;
import android.security.keystore.KeyProperties;
import android.system.keystore2.Authorization;
import android.system.keystore2.KeyDescriptor;

import java.security.PrivateKey;
import java.security.interfaces.ECKey;
@@ -30,8 +34,12 @@ import java.security.spec.ECParameterSpec;
public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
    private final ECParameterSpec mParams;

    public AndroidKeyStoreECPrivateKey(String alias, int uid, ECParameterSpec params) {
        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC);
    public AndroidKeyStoreECPrivateKey(@NonNull KeyDescriptor descriptor,
            long keyId,
            Authorization[] authorizations,
            @NonNull KeyStoreSecurityLevel securityLevel,
            @NonNull ECParameterSpec params) {
        super(descriptor, keyId, authorizations, KeyProperties.KEY_ALGORITHM_EC, securityLevel);
        mParams = params;
    }

+21 −6
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package android.security.keystore2;

import android.annotation.NonNull;
import android.security.KeyStoreSecurityLevel;
import android.security.keystore.KeyProperties;
import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyMetadata;

import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
@@ -32,21 +36,32 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme
    private final ECParameterSpec mParams;
    private final ECPoint mW;

    public AndroidKeyStoreECPublicKey(String alias, int uid, byte[] x509EncodedForm, ECParameterSpec params,
            ECPoint w) {
        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
    public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor,
            @NonNull KeyMetadata metadata,
            @NonNull KeyStoreSecurityLevel securityLevel,
            @NonNull ECParameterSpec params, @NonNull ECPoint w) {
        super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_EC, securityLevel);
        mParams = params;
        mW = w;
    }

    public AndroidKeyStoreECPublicKey(String alias, int uid, ECPublicKey info) {
        this(alias, uid, info.getEncoded(), info.getParams(), info.getW());
    public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor,
            @NonNull KeyMetadata metadata,
            @NonNull KeyStoreSecurityLevel securityLevel, @NonNull ECPublicKey info) {
        this(descriptor, metadata, securityLevel, info.getParams(), info.getW());
        if (!"X.509".equalsIgnoreCase(info.getFormat())) {
            throw new IllegalArgumentException(
                    "Unsupported key export format: " + info.getFormat());
        }
    }

    @Override
    public AndroidKeyStorePrivateKey getPrivateKey() {
        return new AndroidKeyStoreECPrivateKey(
                getUserKeyDescriptor(), getKeyIdDescriptor().nspace, getAuthorizations(),
                getSecurityLevel(), mParams);
    }

    @Override
    public ECParameterSpec getParams() {
        return mParams;
+62 −24
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@

package android.security.keystore2;

import android.annotation.NonNull;
import android.security.KeyStoreSecurityLevel;
import android.system.keystore2.Authorization;
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
import android.util.Log;

import java.security.Key;

/**
@@ -24,24 +31,56 @@ import java.security.Key;
 * @hide
 */
public class AndroidKeyStoreKey implements Key {
    private final String mAlias;
    private final int mUid;
    // This is the original KeyDescriptor by which the key was loaded from
    // with alias and domain.
    private final KeyDescriptor mDescriptor;
    // The key id can be used make certain manipulations to the keystore database
    // assuring that the manipulation is made to the exact key that was loaded
    // from the database. Alias based manipulations can not assure this, because
    // aliases can be rebound to other keys at any time.
    private final long mKeyId;
    private final Authorization[] mAuthorizations;
    // TODO extract algorithm string from metadata.
    private final String mAlgorithm;

    public AndroidKeyStoreKey(String alias, int uid, String algorithm) {
        mAlias = alias;
        mUid = uid;
    // This is the security level interface, that this key is associated with.
    // We do not include this member in comparisons.
    private final KeyStoreSecurityLevel mSecurityLevel;

    AndroidKeyStoreKey(@NonNull KeyDescriptor descriptor,
            long keyId,
            @NonNull Authorization[] authorizations,
            @NonNull String algorithm,
            @NonNull KeyStoreSecurityLevel securityLevel) {
        mDescriptor = descriptor;
        mKeyId = keyId;
        mAuthorizations = authorizations;
        mAlgorithm = algorithm;
        mSecurityLevel = securityLevel;
    }

    KeyDescriptor getUserKeyDescriptor() {
        return mDescriptor;
    }

    String getAlias() {
        return mAlias;
    KeyDescriptor getKeyIdDescriptor() {
        KeyDescriptor descriptor = new KeyDescriptor();
        descriptor.nspace = mKeyId;
        descriptor.domain = Domain.KEY_ID;
        descriptor.alias = null;
        descriptor.blob = null;
        return descriptor;
    }

    int getUid() {
        return mUid;
    Authorization[] getAuthorizations() {
        return mAuthorizations;
    }

    KeyStoreSecurityLevel getSecurityLevel() {
        return mSecurityLevel;
    }


    @Override
    public String getAlgorithm() {
        return mAlgorithm;
@@ -63,9 +102,12 @@ public class AndroidKeyStoreKey implements Key {
    public int hashCode() {
        final int prime = 31;
        int result = 1;

        result = prime * result + ((mDescriptor == null) ? 0 : mDescriptor.hashCode());
        result = prime * result + (int) (mKeyId >>> 32);
        result = prime * result + (int) (mKeyId & 0xffffffff);
        result = prime * result + ((mAuthorizations == null) ? 0 : mAuthorizations.hashCode());
        result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
        result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
        result = prime * result + mUid;
        return result;
    }

@@ -81,21 +123,17 @@ public class AndroidKeyStoreKey implements Key {
            return false;
        }
        AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
        if (mAlgorithm == null) {
            if (other.mAlgorithm != null) {
        if (mKeyId != other.mKeyId) {
            return false;
        }
        } else if (!mAlgorithm.equals(other.mAlgorithm)) {
            return false;
        }
        if (mAlias == null) {
            if (other.mAlias != null) {
                return false;
            }
        } else if (!mAlias.equals(other.mAlias)) {
            return false;
        }
        if (mUid != other.mUid) {

        // If the key ids are equal and the class matches all the other fields cannot differ
        // unless we have a bug.
        if (!mAlgorithm.equals(other.mAlgorithm)
                || !mAuthorizations.equals(other.mAuthorizations)
                || !mDescriptor.equals(other.mDescriptor)) {
            Log.e("AndroidKeyStoreKey", "Bug: key ids are identical, but key metadata"
                    + "differs.");
            return false;
        }
        return true;
+10 −2
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@

package android.security.keystore2;

import android.annotation.NonNull;
import android.security.KeyStoreSecurityLevel;
import android.system.keystore2.Authorization;
import android.system.keystore2.KeyDescriptor;

import java.security.PrivateKey;

/**
@@ -25,7 +30,10 @@ import java.security.PrivateKey;
 */
public class AndroidKeyStorePrivateKey extends AndroidKeyStoreKey implements PrivateKey {

    public AndroidKeyStorePrivateKey(String alias, int uid, String algorithm) {
        super(alias, uid, algorithm);
    public AndroidKeyStorePrivateKey(@NonNull KeyDescriptor descriptor,
            long keyId, @NonNull Authorization[] authorizations, @NonNull String algorithm,
            @NonNull KeyStoreSecurityLevel securityLevel) {
        super(descriptor, keyId, authorizations, algorithm, securityLevel);
    }

}
+22 −14
Original line number Diff line number Diff line
@@ -16,25 +16,33 @@

package android.security.keystore2;

import android.annotation.NonNull;
import android.security.KeyStoreSecurityLevel;
import android.security.keystore.ArrayUtils;
import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyMetadata;

import java.security.PublicKey;
import java.util.Arrays;

/**
 * {@link PublicKey} backed by Android Keystore.
 *
 * @hide
 */
public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
public abstract class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
    private final byte[] mCertificate;
    private final byte[] mCertificateChain;

    private final byte[] mEncoded;

    public AndroidKeyStorePublicKey(String alias, int uid, String algorithm, byte[] x509EncodedForm) {
        super(alias, uid, algorithm);
        mEncoded = ArrayUtils.cloneIfNotEmpty(x509EncodedForm);
    public AndroidKeyStorePublicKey(@NonNull KeyDescriptor descriptor,
            @NonNull KeyMetadata metadata, @NonNull String algorithm,
            @NonNull KeyStoreSecurityLevel securityLevel) {
        super(descriptor, metadata.key.nspace, metadata.authorizations, algorithm, securityLevel);
        mCertificate = metadata.certificate;
        mCertificateChain = metadata.certificateChain;
    }

    abstract AndroidKeyStorePrivateKey getPrivateKey();

    @Override
    public String getFormat() {
        return "X.509";
@@ -42,14 +50,18 @@ public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements Publ

    @Override
    public byte[] getEncoded() {
        return ArrayUtils.cloneIfNotEmpty(mEncoded);
        return ArrayUtils.cloneIfNotEmpty(mCertificate);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + Arrays.hashCode(mEncoded);
        int result = 1;

        result = prime * result + super.hashCode();
        result = prime * result + ((mCertificate == null) ? 0 : mCertificate.hashCode());
        result = prime * result + ((mCertificateChain == null) ? 0 : mCertificateChain.hashCode());

        return result;
    }

@@ -64,10 +76,6 @@ public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements Publ
        if (getClass() != obj.getClass()) {
            return false;
        }
        AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
        if (!Arrays.equals(mEncoded, other.mEncoded)) {
            return false;
        }
        return true;
    }
}
Loading