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

Commit 4b9fee53 authored by Frank Salim's avatar Frank Salim
Browse files

Make ImportWrappedKey work with real hardware:

  Get unwrapping params from WrappedKeyEntry

Add @hide API for StrongBox-backed imported keys (as opposed to wrapped or generated)
Enable 3DES conditionally based on a system property.

Bug: b/79986479
Bug: b/79986680
Test: CTS
Change-Id: If6beedc203337027576ecd3555d11ed2874f9768
parent 9e04425f
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -48,6 +48,8 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider {
    private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME =
    private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME =
            PACKAGE_NAME + ".AndroidKeyStorePublicKey";
            PACKAGE_NAME + ".AndroidKeyStorePublicKey";


    private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede";

    AndroidKeyStoreBCWorkaroundProvider() {
    AndroidKeyStoreBCWorkaroundProvider() {
        super("AndroidKeyStoreBCWorkaround",
        super("AndroidKeyStoreBCWorkaround",
                1.0,
                1.0,
@@ -93,7 +95,7 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider {
        putSymmetricCipherImpl("AES/CTR/NoPadding",
        putSymmetricCipherImpl("AES/CTR/NoPadding",
                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");


        if ("true".equals(System.getProperty("supports3DES"))) {
        if ("true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY))) {
            putSymmetricCipherImpl("DESede/CBC/NoPadding",
            putSymmetricCipherImpl("DESede/CBC/NoPadding",
                PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
                PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
            putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
            putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
+4 −1
Original line number Original line Diff line number Diff line
@@ -64,10 +64,13 @@ public class AndroidKeyStoreProvider extends Provider {


    private static final String PACKAGE_NAME = "android.security.keystore";
    private static final String PACKAGE_NAME = "android.security.keystore";


    private static final String DESEDE_SYSTEM_PROPERTY =
            "ro.hardware.keystore_desede";

    public AndroidKeyStoreProvider() {
    public AndroidKeyStoreProvider() {
        super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
        super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");


        boolean supports3DES = "true".equals(System.getProperty("supports3DES"));
        boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));


        // java.security.KeyStore
        // java.security.KeyStore
        put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
        put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
+69 −5
Original line number Original line Diff line number Diff line
@@ -353,6 +353,10 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
            if (spec.isCriticalToDeviceEncryption()) {
            if (spec.isCriticalToDeviceEncryption()) {
                flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
                flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
            }
            }

            if (spec.isStrongBoxBacked()) {
                flags |= KeyStore.FLAG_STRONGBOX;
            }
        } else {
        } else {
            throw new KeyStoreException(
            throw new KeyStoreException(
                    "Unsupported protection parameter class:" + param.getClass().getName()
                    "Unsupported protection parameter class:" + param.getClass().getName()
@@ -720,6 +724,9 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
        if (params.isCriticalToDeviceEncryption()) {
        if (params.isCriticalToDeviceEncryption()) {
            flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
            flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
        }
        }
        if (params.isStrongBoxBacked()) {
            flags |= KeyStore.FLAG_STRONGBOX;
        }


        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
        String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias;
        String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias;
@@ -737,19 +744,76 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
        }
        }
    }
    }


    private void setWrappedKeyEntry(String alias, byte[] wrappedKeyBytes, String wrappingKeyAlias,
    private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry,
            java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
            java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
        if (param != null) {
        if (param != null) {
            throw new KeyStoreException("Protection parameters are specified inside wrapped keys");
            throw new KeyStoreException("Protection parameters are specified inside wrapped keys");
        }
        }


        byte[] maskingKey = new byte[32];
        byte[] maskingKey = new byte[32];
        KeymasterArguments args = new KeymasterArguments(); // TODO: populate wrapping key args.


        KeymasterArguments args = new KeymasterArguments();
        String[] parts = entry.getTransformation().split("/");

        String algorithm = parts[0];
        if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
            args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
        } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
            args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
        }

        if (parts.length > 1) {
            String mode = parts[1];
            if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(mode)) {
                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
            } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(mode)) {
                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CBC);
            } else if (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(mode)) {
                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
            } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(mode)) {
                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
            }
        }

        if (parts.length > 2) {
            String padding = parts[2];
            if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
                // Noop
            } else if (KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
                args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
            } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) {
                args.addEnums(KeymasterDefs.KM_TAG_PADDING,
                    KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
            } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) {
                args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
            }
        }

        KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec();
        if (spec.isDigestsSpecified()) {
            String digest = spec.getDigests()[0];
            if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) {
                // Noop
            } else if (KeyProperties.DIGEST_MD5.equalsIgnoreCase(digest)) {
                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
            } else if (KeyProperties.DIGEST_SHA1.equalsIgnoreCase(digest)) {
                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
            } else if (KeyProperties.DIGEST_SHA224.equalsIgnoreCase(digest)) {
                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
            } else if (KeyProperties.DIGEST_SHA256.equalsIgnoreCase(digest)) {
                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
            } else if (KeyProperties.DIGEST_SHA384.equalsIgnoreCase(digest)) {
                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
            } else if (KeyProperties.DIGEST_SHA512.equalsIgnoreCase(digest)) {
                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
            }
        }


        int errorCode = mKeyStore.importWrappedKey(
        int errorCode = mKeyStore.importWrappedKey(
            Credentials.USER_SECRET_KEY + alias,
            Credentials.USER_SECRET_KEY + alias,
            wrappedKeyBytes,
            entry.getWrappedKeyBytes(),
            Credentials.USER_PRIVATE_KEY + wrappingKeyAlias,
            Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
            maskingKey,
            maskingKey,
            args,
            args,
            GateKeeper.getSecureUserId(),
            GateKeeper.getSecureUserId(),
@@ -996,7 +1060,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
            setSecretKeyEntry(alias, secE.getSecretKey(), param);
            setSecretKeyEntry(alias, secE.getSecretKey(), param);
        } else if (entry instanceof WrappedKeyEntry) {
        } else if (entry instanceof WrappedKeyEntry) {
            WrappedKeyEntry wke = (WrappedKeyEntry) entry;
            WrappedKeyEntry wke = (WrappedKeyEntry) entry;
            setWrappedKeyEntry(alias, wke.getWrappedKeyBytes(), wke.getWrappingKeyAlias(), param);
            setWrappedKeyEntry(alias, wke, param);
        } else {
        } else {
            throw new KeyStoreException(
            throw new KeyStoreException(
                    "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
                    "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
+25 −2
Original line number Original line Diff line number Diff line
@@ -232,6 +232,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
    private final boolean mCriticalToDeviceEncryption;
    private final boolean mCriticalToDeviceEncryption;
    private final boolean mUserConfirmationRequired;
    private final boolean mUserConfirmationRequired;
    private final boolean mUnlockedDeviceRequired;
    private final boolean mUnlockedDeviceRequired;
    private final boolean mIsStrongBoxBacked;


    private KeyProtection(
    private KeyProtection(
            Date keyValidityStart,
            Date keyValidityStart,
@@ -251,7 +252,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
            long boundToSecureUserId,
            long boundToSecureUserId,
            boolean criticalToDeviceEncryption,
            boolean criticalToDeviceEncryption,
            boolean userConfirmationRequired,
            boolean userConfirmationRequired,
            boolean unlockedDeviceRequired) {
            boolean unlockedDeviceRequired,
            boolean isStrongBoxBacked) {
        mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
        mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
        mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
        mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
        mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
        mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -272,6 +274,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
        mCriticalToDeviceEncryption = criticalToDeviceEncryption;
        mCriticalToDeviceEncryption = criticalToDeviceEncryption;
        mUserConfirmationRequired = userConfirmationRequired;
        mUserConfirmationRequired = userConfirmationRequired;
        mUnlockedDeviceRequired = unlockedDeviceRequired;
        mUnlockedDeviceRequired = unlockedDeviceRequired;
        mIsStrongBoxBacked = isStrongBoxBacked;
    }
    }


    /**
    /**
@@ -528,6 +531,14 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
        return mUnlockedDeviceRequired;
        return mUnlockedDeviceRequired;
    }
    }


    /**
     * Returns {@code true} if the key is protected by a Strongbox security chip.
     * @hide
     */
    public boolean isStrongBoxBacked() {
        return mIsStrongBoxBacked;
    }

    /**
    /**
     * Builder of {@link KeyProtection} instances.
     * Builder of {@link KeyProtection} instances.
     */
     */
@@ -552,6 +563,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {


        private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
        private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
        private boolean mCriticalToDeviceEncryption = false;
        private boolean mCriticalToDeviceEncryption = false;
        private boolean mIsStrongBoxBacked = false;


        /**
        /**
         * Creates a new instance of the {@code Builder}.
         * Creates a new instance of the {@code Builder}.
@@ -961,6 +973,16 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
            return this;
            return this;
        }
        }


        /**
         * Sets whether this key should be protected by a StrongBox security chip.
         * @hide
         */
        @NonNull
        public Builder setIsStrongBoxBacked(boolean isStrongBoxBacked) {
            mIsStrongBoxBacked = isStrongBoxBacked;
            return this;
        }

        /**
        /**
         * Builds an instance of {@link KeyProtection}.
         * Builds an instance of {@link KeyProtection}.
         *
         *
@@ -986,7 +1008,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
                    mBoundToSecureUserId,
                    mBoundToSecureUserId,
                    mCriticalToDeviceEncryption,
                    mCriticalToDeviceEncryption,
                    mUserConfirmationRequired,
                    mUserConfirmationRequired,
                    mUnlockedDeviceRequired);
                    mUnlockedDeviceRequired,
                    mIsStrongBoxBacked);
        }
        }
    }
    }
}
}