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

Commit 4b79bbea authored by Alex Klyubin's avatar Alex Klyubin Committed by Android Git Automerger
Browse files

am 558184f5: Merge "Make the new AndroidKeyStore API conformant."

* commit '558184f5':
  Make the new AndroidKeyStore API conformant.
parents aa94389b 558184f5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -171,6 +171,9 @@ public final class KeymasterDefs {
    public static final int KM_KEY_FORMAT_PKCS12 = 2;
    public static final int KM_KEY_FORMAT_RAW = 3;

    // User authenticators.
    public static final int HW_AUTH_PASSWORD = 1 << 0;

    // Error codes.
    public static final int KM_ERROR_OK = 0;
    public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
+36 −45
Original line number Diff line number Diff line
@@ -466,81 +466,72 @@ public class AndroidKeyStore extends KeyStoreSpi {
            throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
        }

        if ((params.getAlgorithm() != null) && (params.getAlgorithm() != keyAlgorithm)) {
            throw new KeyStoreException("Key algorithm mismatch. Key: " + keyAlgorithmString
                    + ", parameter spec: "
                    + KeyStoreKeyConstraints.Algorithm.toString(params.getAlgorithm()));
        }

        KeymasterArguments args = new KeymasterArguments();
        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
                KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm));

        @KeyStoreKeyConstraints.DigestEnum int digests;
        if (params.isDigestsSpecified()) {
            // Digest(s) specified in parameters
            if (digest != null) {
            // Digest available from JCA key algorithm
            if (params.getDigest() != null) {
                // Digest also specified in parameters -- check that these two match
                if (digest != params.getDigest()) {
                    throw new KeyStoreException("Key digest mismatch. Key: " + keyAlgorithmString
                // Digest also specified in the JCA key algorithm name.
                if ((params.getDigests() & digest) != digest) {
                    throw new KeyStoreException("Key digest mismatch"
                            + ". Key: " + keyAlgorithmString
                            + ", parameter spec: "
                            + KeyStoreKeyConstraints.Digest.toString(params.getDigest()));
                            + KeyStoreKeyConstraints.Digest.allToString(params.getDigests()));
                }
            }
            digests = params.getDigests();
        } else {
            // Digest not available from JCA key algorithm
            digest = params.getDigest();
        }
            // No digest specified in parameters
            if (digest != null) {
            args.addInt(KeymasterDefs.KM_TAG_DIGEST,
                    KeyStoreKeyConstraints.Digest.toKeymaster(digest));
                // Digest specified in the JCA key algorithm name.
                digests = digest;
            } else {
                digests = 0;
            }
        }
        for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) {
            args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest);
        }
        if (digests != 0) {
            // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
            // This code will blow up if mode than one digest is specified.
            Integer digestOutputSizeBytes =
                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
            if (digestOutputSizeBytes != null) {
                // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
                // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
                args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
            }
        }
        if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
            if (digest == null) {
                throw new IllegalStateException("Digest algorithm must be specified for key"
                        + " algorithm " + keyAlgorithmString);
            if (digests == 0) {
                throw new KeyStoreException("At least one digest algorithm must be specified"
                        + " for key algorithm " + keyAlgorithmString);
            }
        }

        @KeyStoreKeyConstraints.PurposeEnum int purposes = (params.getPurposes() != null)
                ? params.getPurposes()
                : (KeyStoreKeyConstraints.Purpose.ENCRYPT
                        | KeyStoreKeyConstraints.Purpose.DECRYPT
                        | KeyStoreKeyConstraints.Purpose.SIGN
                        | KeyStoreKeyConstraints.Purpose.VERIFY);
        for (int keymasterPurpose :
            KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
        int purposes = params.getPurposes();
        for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
            args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
        }
        if (params.getBlockMode() != null) {
            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE,
                    KeyStoreKeyConstraints.BlockMode.toKeymaster(params.getBlockMode()));
        }
        if (params.getPadding() != null) {
            args.addInt(KeymasterDefs.KM_TAG_PADDING,
                    KeyStoreKeyConstraints.Padding.toKeymaster(params.getPadding()));
        }
        if (params.getMaxUsesPerBoot() != null) {
            args.addInt(KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT, params.getMaxUsesPerBoot());
        for (int keymasterBlockMode :
            KeyStoreKeyConstraints.BlockMode.allToKeymaster(params.getBlockModes())) {
            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
        }
        if (params.getMinSecondsBetweenOperations() != null) {
            args.addInt(KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS,
                    params.getMinSecondsBetweenOperations());
        for (int keymasterPadding :
            KeyStoreKeyConstraints.Padding.allToKeymaster(params.getPaddings())) {
            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
        }
        if (params.getUserAuthenticators().isEmpty()) {
        if (params.getUserAuthenticators() == 0) {
            args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
        } else {
            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
                            params.getUserAuthenticators()));
        }
        if (params.getUserAuthenticationValidityDurationSeconds() != null) {
        if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
            args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
                    params.getUserAuthenticationValidityDurationSeconds());
        }
+63 −149
Original line number Diff line number Diff line
@@ -19,12 +19,8 @@ package android.security;
import android.content.Context;
import android.text.TextUtils;

import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@@ -33,13 +29,13 @@ import javax.crypto.SecretKey;
 * {@link AlgorithmParameterSpec} for initializing a {@code KeyGenerator} that works with
 * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>.
 *
 * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API
 * using the {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up
 * some UI to ask the user to unlock or initialize the Android KeyStore facility.
 * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API using the
 * {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up some UI to
 * ask the user to unlock or initialize the Android KeyStore facility.
 *
 * <p>After generation, the {@code keyStoreAlias} is used with the
 * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
 * interface to retrieve the {@link SecretKey} and its associated {@link Certificate} chain.
 * interface to retrieve the {@link SecretKey}.
 *
 * @hide
 */
@@ -52,13 +48,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
    private final Date mKeyValidityStart;
    private final Date mKeyValidityForOriginationEnd;
    private final Date mKeyValidityForConsumptionEnd;
    private final @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
    private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
    private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
    private final Integer mMinSecondsBetweenOperations;
    private final Integer mMaxUsesPerBoot;
    private final Set<Integer> mUserAuthenticators;
    private final Integer mUserAuthenticationValidityDurationSeconds;
    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
    private final int mUserAuthenticationValidityDurationSeconds;

    private KeyGeneratorSpec(
            Context context,
@@ -68,19 +62,17 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
            Date keyValidityStart,
            Date keyValidityForOriginationEnd,
            Date keyValidityForConsumptionEnd,
            @KeyStoreKeyConstraints.PurposeEnum Integer purposes,
            @KeyStoreKeyConstraints.PaddingEnum Integer padding,
            @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
            Integer minSecondsBetweenOperations,
            Integer maxUsesPerBoot,
            Set<Integer> userAuthenticators,
            Integer userAuthenticationValidityDurationSeconds) {
            @KeyStoreKeyConstraints.PurposeEnum int purposes,
            @KeyStoreKeyConstraints.PaddingEnum int paddings,
            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
            int userAuthenticationValidityDurationSeconds) {
        if (context == null) {
            throw new IllegalArgumentException("context == null");
        } else if (TextUtils.isEmpty(keyStoreAlias)) {
            throw new IllegalArgumentException("keyStoreAlias must not be empty");
        } else if ((userAuthenticationValidityDurationSeconds != null)
                && (userAuthenticationValidityDurationSeconds < 0)) {
        } else if ((userAuthenticationValidityDurationSeconds < 0)
                && (userAuthenticationValidityDurationSeconds != -1)) {
            throw new IllegalArgumentException(
                    "userAuthenticationValidityDurationSeconds must not be negative");
        }
@@ -93,13 +85,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
        mPurposes = purposes;
        mPadding = padding;
        mBlockMode = blockMode;
        mMinSecondsBetweenOperations = minSecondsBetweenOperations;
        mMaxUsesPerBoot = maxUsesPerBoot;
        mUserAuthenticators = (userAuthenticators != null)
                ? new HashSet<Integer>(userAuthenticators)
                : Collections.<Integer>emptySet();
        mPaddings = paddings;
        mBlockModes = blockModes;
        mUserAuthenticators = userAuthenticators;
        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
    }

@@ -145,8 +133,6 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
     * Gets the time instant after which the key is no longer valid for decryption and verification.
     *
     * @return instant or {@code null} if not restricted.
     *
     * @hide
     */
    public Date getKeyValidityForConsumptionEnd() {
        return mKeyValidityForConsumptionEnd;
@@ -163,78 +149,43 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {

    /**
     * Gets the set of purposes for which the key can be used.
     *
     * @return set of purposes or {@code null} if the key can be used for any purpose.
     */
    public @KeyStoreKeyConstraints.PurposeEnum Integer getPurposes() {
    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
        return mPurposes;
    }

    /**
     * Gets the padding scheme to which the key is restricted.
     *
     * @return padding scheme or {@code null} if the padding scheme is not restricted.
     * Gets the set of padding schemes to which the key is restricted.
     */
    public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
        return mPadding;
    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
        return mPaddings;
    }

    /**
     * Gets the block mode to which the key is restricted when used for encryption or decryption.
     *
     * @return block more or {@code null} if block mode is not restricted.
     *
     * @hide
     * Gets the set of block modes to which the key is restricted.
     */
    public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
        return mBlockMode;
    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
        return mBlockModes;
    }

    /**
     * Gets the minimum number of seconds that must expire since the most recent use of the key
     * before it can be used again.
     *
     * @return number of seconds or {@code null} if there is no restriction on how frequently a key
     *         can be used.
     * Gets the set of user authenticators which protect access to this key. The key can only be
     * used iff the user has authenticated to at least one of these user authenticators.
     *
     * @hide
     */
    public Integer getMinSecondsBetweenOperations() {
        return mMinSecondsBetweenOperations;
    }

    /**
     * Gets the number of times the key can be used without rebooting the device.
     *
     * @return maximum number of times or {@code null} if there is no restriction.
     * @hide
     * @return user authenticators or {@code 0} if the key can be used without user authentication.
     */
    public Integer getMaxUsesPerBoot() {
        return mMaxUsesPerBoot;
    }

    /**
     * Gets the user authenticators which protect access to this key. The key can only be used iff
     * the user has authenticated to at least one of these user authenticators.
     *
     * @return user authenticators or empty set if the key can be used without user authentication.
     *
     * @hide
     */
    public Set<Integer> getUserAuthenticators() {
        return new HashSet<Integer>(mUserAuthenticators);
    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
        return mUserAuthenticators;
    }

    /**
     * Gets the duration of time (seconds) for which this key can be used after the user
     * successfully authenticates to one of the associated user authenticators.
     *
     * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
     * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
     *         is required for every use of the key.
     *
     * @hide
     */
    public Integer getUserAuthenticationValidityDurationSeconds() {
    public int getUserAuthenticationValidityDurationSeconds() {
        return mUserAuthenticationValidityDurationSeconds;
    }

@@ -253,13 +204,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
        private Date mKeyValidityStart;
        private Date mKeyValidityForOriginationEnd;
        private Date mKeyValidityForConsumptionEnd;
        private @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
        private @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
        private @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
        private Integer mMinSecondsBetweenOperations;
        private Integer mMaxUsesPerBoot;
        private Set<Integer> mUserAuthenticators;
        private Integer mUserAuthenticationValidityDurationSeconds;
        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
        private int mUserAuthenticationValidityDurationSeconds = -1;

        /**
         * Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -318,8 +267,6 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         * <b>By default, the key is valid at any instant.
         *
         * @see #setKeyValidityEnd(Date)
         *
         * @hide
         */
        public Builder setKeyValidityStart(Date startDate) {
            mKeyValidityStart = startDate;
@@ -334,8 +281,6 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         * @see #setKeyValidityStart(Date)
         * @see #setKeyValidityForConsumptionEnd(Date)
         * @see #setKeyValidityForOriginationEnd(Date)
         *
         * @hide
         */
        public Builder setKeyValidityEnd(Date endDate) {
            setKeyValidityForOriginationEnd(endDate);
@@ -349,8 +294,6 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         * <b>By default, the key is valid at any instant.
         *
         * @see #setKeyValidityForConsumptionEnd(Date)
         *
         * @hide
         */
        public Builder setKeyValidityForOriginationEnd(Date endDate) {
            mKeyValidityForOriginationEnd = endDate;
@@ -364,8 +307,6 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         * <b>By default, the key is valid at any instant.
         *
         * @see #setKeyValidityForOriginationEnd(Date)
         *
         * @hide
         */
        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
            mKeyValidityForConsumptionEnd = endDate;
@@ -373,11 +314,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
        }

        /**
         * Restricts the purposes for which the key can be used to the provided set of purposes.
         *
         * <p>By default, the key can be used for encryption, decryption, signing, and verification.
         * Restricts the key to being used only for the provided set of purposes.
         *
         * @hide
         * <p>This restriction must be specified. There is no default.
         */
        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
            mPurposes = purposes;
@@ -385,53 +324,24 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
        }

        /**
         * Restricts the key to being used only with the provided padding scheme. Attempts to use
         * Restricts the key to being used only with the provided padding schemes. Attempts to use
         * the key with any other padding will be rejected.
         *
         * <p>This restriction must be specified for keys which are used for encryption/decryption.
         *
         * @hide
         */
        public Builder setPadding(@KeyStoreKeyConstraints.PaddingEnum int padding) {
            mPadding = padding;
        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
            mPaddings = paddings;
            return this;
        }

        /**
         * Restricts the key to being used only with the provided block mode when encrypting or
         * decrypting. Attempts to use the key with any other block modes will be rejected.
         * Restricts the key to being used only with the provided block modes. Attempts to use the
         * key with any other block modes will be rejected.
         *
         * <p>This restriction must be specified for keys which are used for encryption/decryption.
         *
         * @hide
         */
        public Builder setBlockMode(@KeyStoreKeyConstraints.BlockModeEnum int blockMode) {
            mBlockMode = blockMode;
            return this;
        }

        /**
         * Sets the minimum number of seconds that must expire since the most recent use of the key
         * before it can be used again.
         *
         * <p>By default, there is no restriction on how frequently a key can be used.
         *
         * @hide
         */
        public Builder setMinSecondsBetweenOperations(int seconds) {
            mMinSecondsBetweenOperations = seconds;
            return this;
        }

        /**
         * Sets the maximum number of times a key can be used without rebooting the device.
         *
         * <p>By default, the key can be used for an unlimited number of times.
         *
         * @hide
         */
        public Builder setMaxUsesPerBoot(int count) {
            mMaxUsesPerBoot = count;
        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
            mBlockModes = blockModes;
            return this;
        }

@@ -445,12 +355,10 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         *        without user authentication.
         *
         * @see #setUserAuthenticationValidityDurationSeconds(int)
         *
         * @hide
         */
        public Builder setUserAuthenticators(Set<Integer> userAuthenticators) {
            mUserAuthenticators =
                    (userAuthenticators != null) ? new HashSet<Integer>(userAuthenticators) : null;
        public Builder setUserAuthenticators(
                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
            mUserAuthenticators = userAuthenticators;
            return this;
        }

@@ -463,9 +371,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
         *        every use of the key.
         *
         * @see #setUserAuthenticators(Set)
         *
         * @hide
         * @see #setUserAuthenticators(int)
         */
        public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
            mUserAuthenticationValidityDurationSeconds = seconds;
@@ -478,10 +384,18 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
         * @throws IllegalArgumentException if a required field is missing or violates a constraint.
         */
        public KeyGeneratorSpec build() {
            return new KeyGeneratorSpec(mContext, mKeystoreAlias, mFlags, mKeySize,
                    mKeyValidityStart, mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd,
                    mPurposes, mPadding, mBlockMode, mMinSecondsBetweenOperations, mMaxUsesPerBoot,
                    mUserAuthenticators, mUserAuthenticationValidityDurationSeconds);
            return new KeyGeneratorSpec(mContext,
                    mKeystoreAlias,
                    mFlags,
                    mKeySize,
                    mKeyValidityStart,
                    mKeyValidityForOriginationEnd,
                    mKeyValidityForConsumptionEnd,
                    mPurposes,
                    mPaddings,
                    mBlockModes,
                    mUserAuthenticators,
                    mUserAuthenticationValidityDurationSeconds);
        }
    }
}
+60 −149

File changed.

Preview size limit exceeded, changes collapsed.

+149 −60

File changed.

Preview size limit exceeded, changes collapsed.

Loading