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

Commit f7592b23 authored by Alex Klyubin's avatar Alex Klyubin Committed by Android (Google) Code Review
Browse files

Merge "HMAC keys are authorized for exactly one digest." into mnc-dev

parents d4b566bf c58153b2
Loading
Loading
Loading
Loading
+21 −33
Original line number Diff line number Diff line
@@ -197,48 +197,36 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
                        }
                    }
                }

                if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
                    // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
                    // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
                    // one digest, we don't let algorithm parameter spec override the digest implied
                    // by the key. If the spec specifies digests at all, it must specify only one
                    // digest, the only implied by key algorithm.
                    mKeymasterDigests = new int[] {mKeymasterDigest};
                    if (spec.isDigestsSpecified()) {
                    // Digest(s) explicitly specified in the spec
                    mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
                    if (mKeymasterDigest != -1) {
                        // Key algorithm implies a digest -- ensure it's specified in the spec as
                        // first digest.
                        if (!com.android.internal.util.ArrayUtils.contains(
                                mKeymasterDigests, mKeymasterDigest)) {
                        // Digest(s) explicitly specified in the spec. Check that the list
                        // consists of exactly one digest, the one implied by key algorithm.
                        int[] keymasterDigestsFromSpec =
                                KeyProperties.Digest.allToKeymaster(spec.getDigests());
                        if ((keymasterDigestsFromSpec.length != 1)
                                || (keymasterDigestsFromSpec[0] != mKeymasterDigest)) {
                            throw new InvalidAlgorithmParameterException(
                                    "Digests specified in algorithm parameters ("
                                    + Arrays.asList(spec.getDigests()) + ") must include "
                                    + " the digest "
                                    "Unsupported digests specification: "
                                    + Arrays.asList(spec.getDigests()) + ". Only "
                                    + KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
                                    + " implied by key algorithm");
                        }
                        if (mKeymasterDigests[0] != mKeymasterDigest) {
                            // The first digest is not the one implied by the key algorithm.
                            // Swap the implied digest with the first one.
                            for (int i = 0; i < mKeymasterDigests.length; i++) {
                                if (mKeymasterDigests[i] == mKeymasterDigest) {
                                    mKeymasterDigests[i] = mKeymasterDigests[0];
                                    mKeymasterDigests[0] = mKeymasterDigest;
                                    break;
                                }
                            }
                                    + " supported for this HMAC key algorithm");
                        }
                    }
                } else {
                    // No digest specified in the spec
                    if (mKeymasterDigest != -1) {
                        // Key algorithm implies a digest -- use that digest
                        mKeymasterDigests = new int[] {mKeymasterDigest};
                    // Key algorithm does not imply a digest.
                    if (spec.isDigestsSpecified()) {
                        mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
                    } else {
                        mKeymasterDigests = EmptyArray.INT;
                    }
                }
                if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
                    if (mKeymasterDigests.length == 0) {
                        throw new InvalidAlgorithmParameterException(
                                "At least one digest algorithm must be specified");
                    }
                }

                // Check that user authentication related parameters are acceptable. This method
                // will throw an IllegalStateException if there are issues (e.g., secure lock screen
+30 −36
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.ProviderException;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
@@ -605,50 +606,43 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
            args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);

            int[] keymasterDigests;
            int keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
            if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
                // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
                // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
                // digest, we don't let import parameters override the digest implied by the key.
                // If the parameters specify digests at all, they must specify only one digest, the
                // only implied by key algorithm.
                int keymasterImpliedDigest =
                        KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
                if (keymasterImpliedDigest == -1) {
                    throw new ProviderException(
                            "HMAC key algorithm digest unknown for key algorithm "
                                    + key.getAlgorithm());
                }
                keymasterDigests = new int[] {keymasterImpliedDigest};
                if (params.isDigestsSpecified()) {
                // Digest(s) specified in parameters
                keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
                if (keymasterDigest != -1) {
                    // Digest also specified in the JCA key algorithm name.
                    if (!com.android.internal.util.ArrayUtils.contains(
                            keymasterDigests, keymasterDigest)) {
                        throw new KeyStoreException("Digest specified in key algorithm "
                                + key.getAlgorithm() + " not specified in protection parameters: "
                                + Arrays.asList(params.getDigests()));
                    }
                    // When the key is read back from keystore we reconstruct the JCA key algorithm
                    // name from the KM_TAG_ALGORITHM and the first KM_TAG_DIGEST. Thus we need to
                    // ensure that the digest reflected in the JCA key algorithm name is the first
                    // KM_TAG_DIGEST tag.
                    if (keymasterDigests[0] != keymasterDigest) {
                        // The first digest is not the one implied by the JCA key algorithm name.
                        // Swap the implied digest with the first one.
                        for (int i = 0; i < keymasterDigests.length; i++) {
                            if (keymasterDigests[i] == keymasterDigest) {
                                keymasterDigests[i] = keymasterDigests[0];
                                keymasterDigests[0] = keymasterDigest;
                                break;
                            }
                        }
                    // Digest(s) explicitly specified in params -- check that the list consists of
                    // exactly one digest, the one implied by key algorithm.
                    int[] keymasterDigestsFromParams =
                            KeyProperties.Digest.allToKeymaster(params.getDigests());
                    if ((keymasterDigestsFromParams.length != 1)
                            || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
                        throw new KeyStoreException(
                                "Unsupported digests specification: "
                                + Arrays.asList(params.getDigests()) + ". Only "
                                + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)
                                + " supported for HMAC key algorithm " + key.getAlgorithm());
                    }
                }
            } else {
                // No digest specified in parameters
                if (keymasterDigest != -1) {
                    // Digest specified in the JCA key algorithm name.
                    keymasterDigests = new int[] {keymasterDigest};
                // Key algorithm does not imply a digest.
                if (params.isDigestsSpecified()) {
                    keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
                } else {
                    keymasterDigests = EmptyArray.INT;
                }
            }
            args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
            if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
                if (keymasterDigests.length == 0) {
                    throw new KeyStoreException("At least one digest algorithm must be specified"
                            + " for key algorithm " + key.getAlgorithm());
                }
            }

            @KeyProperties.PurposeEnum int purposes = params.getPurposes();
            int[] keymasterBlockModes =
+2 −1
Original line number Diff line number Diff line
@@ -642,7 +642,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
         * <p>This must be specified for signing/verification keys and RSA encryption/decryption
         * keys used with RSA OAEP padding scheme because these operations involve a digest. For
         * HMAC keys, the default is the digest associated with the key algorithm (e.g.,
         * {@code SHA-256} for key algorithm {@code HmacSHA256}).
         * {@code SHA-256} for key algorithm {@code HmacSHA256}). HMAC keys cannot be authorized
         * for more than one digest.
         *
         * <p>For private keys used for TLS/SSL client or server authentication it is usually
         * necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is
+2 −1
Original line number Diff line number Diff line
@@ -423,7 +423,8 @@ public final class KeyProtection implements ProtectionParameter {
         * <p>This must be specified for signing/verification keys and RSA encryption/decryption
         * keys used with RSA OAEP padding scheme because these operations involve a digest. For
         * HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()} (e.g.,
         * {@code SHA-256} for key algorithm {@code HmacSHA256}).
         * {@code SHA-256} for key algorithm {@code HmacSHA256}). HMAC keys cannot be authorized
         * for more than one digest.
         *
         * <p>For private keys used for TLS/SSL client or server authentication it is usually
         * necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is