diff options
author | Alex Klyubin <klyubin@google.com> | 2015-04-01 17:34:36 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-04-01 17:34:37 +0000 |
commit | c461452eb78867032092b2fce14c2fcb3e7ab34e (patch) | |
tree | 5b338ecfe89e6901b712d9a40bb359e99dadd440 /keystore/java/android/security | |
parent | c6cc9d820d007a6b11df2bb3274d40743e1f1d87 (diff) | |
parent | c8e557470fc94733c9340c4c67ee69c225bbaa70 (diff) | |
download | frameworks_base-c461452eb78867032092b2fce14c2fcb3e7ab34e.zip frameworks_base-c461452eb78867032092b2fce14c2fcb3e7ab34e.tar.gz frameworks_base-c461452eb78867032092b2fce14c2fcb3e7ab34e.tar.bz2 |
Merge "Hook in user authenticators and their exceptions."
Diffstat (limited to 'keystore/java/android/security')
9 files changed, 159 insertions, 30 deletions
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java index 846d1f1..4650d27 100644 --- a/keystore/java/android/security/AndroidKeyStore.java +++ b/keystore/java/android/security/AndroidKeyStore.java @@ -536,10 +536,9 @@ public class AndroidKeyStore extends KeyStoreSpi { if (params.getUserAuthenticators().isEmpty()) { args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); } else { - // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized -// for (int userAuthenticatorId : params.getUserAuthenticators()) { -// args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId); -// } + args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, + KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster( + params.getUserAuthenticators())); } if (params.getUserAuthenticationValidityDurationSeconds() != null) { args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java index bdaa812..5219086 100644 --- a/keystore/java/android/security/KeyStoreCipherSpi.java +++ b/keystore/java/android/security/KeyStoreCipherSpi.java @@ -224,8 +224,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw new CryptoOperationException("Failed to start keystore operation", - KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode)); + throw KeymasterUtils.getCryptoOperationException(opResult.resultCode); } if (opResult.token == null) { @@ -252,7 +251,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry try { output = mMainDataStreamer.update(input, inputOffset, inputLen); } catch (KeymasterException e) { - throw new CryptoOperationException("Keystore operation failed", e); + throw KeymasterUtils.getCryptoOperationException(e); } if (output.length == 0) { @@ -297,7 +296,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED: throw new AEADBadTagException(); default: - throw new CryptoOperationException("Keystore operation failed", e); + throw KeymasterUtils.getCryptoOperationException(e); } } diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java index 2b279f6..993614b 100644 --- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java +++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java @@ -120,7 +120,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode); + throw KeymasterUtils.getKeymasterException(opResult.resultCode); } if (opResult.inputConsumed == chunk.length) { @@ -203,7 +203,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode); + throw KeymasterUtils.getKeymasterException(opResult.resultCode); } return concat(output, opResult.output); @@ -227,7 +227,7 @@ public class KeyStoreCryptoOperationChunkedStreamer { if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode); + throw KeymasterUtils.getKeymasterException(opResult.resultCode); } if (opResult.inputConsumed < chunk.length) { diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java index 841b90d..1297cc2 100644 --- a/keystore/java/android/security/KeyStoreHmacSpi.java +++ b/keystore/java/android/security/KeyStoreHmacSpi.java @@ -103,8 +103,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw new CryptoOperationException("Failed to start keystore operation", - KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode)); + throw KeymasterUtils.getCryptoOperationException(opResult.resultCode); } mOperationToken = opResult.token; if (mOperationToken == null) { @@ -131,7 +130,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp try { output = mChunkedStreamer.update(input, offset, len); } catch (KeymasterException e) { - throw new CryptoOperationException("Keystore operation failed", e); + throw KeymasterUtils.getCryptoOperationException(e); } if ((output != null) && (output.length != 0)) { throw new CryptoOperationException("Update operation unexpectedly produced output"); @@ -148,7 +147,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp try { result = mChunkedStreamer.doFinal(null, 0, 0); } catch (KeymasterException e) { - throw new CryptoOperationException("Keystore operation failed", e); + throw KeymasterUtils.getCryptoOperationException(e); } engineReset(); diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java index c011083..c27ccb1 100644 --- a/keystore/java/android/security/KeyStoreKeyConstraints.java +++ b/keystore/java/android/security/KeyStoreKeyConstraints.java @@ -23,7 +23,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; /** * Constraints for {@code AndroidKeyStore} keys. @@ -520,4 +523,87 @@ public abstract class KeyStoreKeyConstraints { } } } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({UserAuthenticator.LOCK_SCREEN}) + public @interface UserAuthenticatorEnum {} + + /** + * User authenticators which can be used to restrict/protect access to keys. + */ + public static abstract class UserAuthenticator { + private UserAuthenticator() {} + + /** Lock screen. */ + public static final int LOCK_SCREEN = 1; + + /** + * @hide + */ + public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) { + switch (userAuthenticator) { + case LOCK_SCREEN: + return LOCK_SCREEN; + default: + throw new IllegalArgumentException( + "Unknown user authenticator: " + userAuthenticator); + } + } + + /** + * @hide + */ + public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) { + switch (userAuthenticator) { + case LOCK_SCREEN: + return LOCK_SCREEN; + default: + throw new IllegalArgumentException( + "Unknown user authenticator: " + userAuthenticator); + } + } + + /** + * @hide + */ + public static int allToKeymaster(Set<Integer> userAuthenticators) { + int result = 0; + for (@UserAuthenticatorEnum int userAuthenticator : userAuthenticators) { + result |= toKeymaster(userAuthenticator); + } + return result; + } + + /** + * @hide + */ + public static Set<Integer> allFromKeymaster(int userAuthenticators) { + int userAuthenticator = 1; + Set<Integer> result = null; + while (userAuthenticators != 0) { + if ((userAuthenticators & 1) != 0) { + if (result == null) { + result = new HashSet<Integer>(); + } + result.add(fromKeymaster(userAuthenticator)); + } + userAuthenticators >>>= 1; + userAuthenticator <<= 1; + } + return (result != null) ? result : Collections.<Integer>emptySet(); + } + + /** + * @hide + */ + public static String toString(@UserAuthenticatorEnum int userAuthenticator) { + switch (userAuthenticator) { + case LOCK_SCREEN: + return "LOCK_SCREEN"; + default: + throw new IllegalArgumentException( + "Unknown user authenticator: " + userAuthenticator); + } + } + } } diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index 7796de8..09fee1b 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -136,10 +136,9 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { if (spec.getUserAuthenticators().isEmpty()) { args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); } else { - // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized -// for (int userAuthenticatorId : spec.getUserAuthenticators()) { -// args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId); -// } + args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, + KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster( + spec.getUserAuthenticators())); } if (spec.getUserAuthenticationValidityDurationSeconds() != null) { args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, @@ -175,8 +174,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { int errorCode = mKeyStore.generateKey( keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics()); if (errorCode != KeyStore.NO_ERROR) { - throw new CryptoOperationException("Failed to generate key", - KeymasterUtils.getExceptionForKeymasterError(errorCode)); + throw KeymasterUtils.getCryptoOperationException(errorCode); } String keyAlgorithmJCA = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest); diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java index 8921ba1..88255a8 100644 --- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java +++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java @@ -22,7 +22,6 @@ import android.security.keymaster.KeymasterDefs; import java.security.InvalidKeyException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; -import java.util.Collections; import java.util.Set; import javax.crypto.SecretKey; @@ -113,13 +112,16 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { throw new InvalidKeySpecException("Unsupported key characteristic", e); } - // TODO: Read user authentication IDs once the Keymaster API has stabilized - Set<Integer> userAuthenticators = Collections.emptySet(); - Set<Integer> teeBackedUserAuthenticators = Collections.emptySet(); -// Set<Integer> userAuthenticators = new HashSet<Integer>( -// getInts(keyCharacteristics, KeymasterDefs.KM_TAG_USER_AUTH_ID)); -// Set<Integer> teeBackedUserAuthenticators = new HashSet<Integer>( -// keyCharacteristics.hwEnforced.getInts(KeymasterDefs.KM_TAG_USER_AUTH_ID)); + int swEnforcedUserAuthenticatorIds = + keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0); + int hwEnforcedUserAuthenticatorIds = + keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0); + int userAuthenticatorIds = swEnforcedUserAuthenticatorIds | hwEnforcedUserAuthenticatorIds; + Set<Integer> userAuthenticators = + KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(userAuthenticatorIds); + Set<Integer> teeBackedUserAuthenticators = + KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster( + hwEnforcedUserAuthenticatorIds); return new KeyStoreKeySpec(entryAlias, origin, diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java index 6bb9636..2645cf4 100644 --- a/keystore/java/android/security/KeymasterUtils.java +++ b/keystore/java/android/security/KeymasterUtils.java @@ -29,7 +29,7 @@ import java.util.List; public abstract class KeymasterUtils { private KeymasterUtils() {} - public static KeymasterException getExceptionForKeymasterError(int keymasterErrorCode) { + public static KeymasterException getKeymasterException(int keymasterErrorCode) { switch (keymasterErrorCode) { case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT: // The name of this parameter significantly differs between Keymaster and framework @@ -42,6 +42,19 @@ public abstract class KeymasterUtils { } } + public static CryptoOperationException getCryptoOperationException(KeymasterException e) { + switch (e.getErrorCode()) { + case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: + return new UserNotAuthenticatedException(); + default: + return new CryptoOperationException("Crypto operation failed", e); + } + } + + public static CryptoOperationException getCryptoOperationException(int keymasterErrorCode) { + return getCryptoOperationException(getKeymasterException(keymasterErrorCode)); + } + public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) { if (keyCharacteristics.hwEnforced.containsTag(tag)) { return keyCharacteristics.hwEnforced.getInt(tag, -1); diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java new file mode 100644 index 0000000..b45817c --- /dev/null +++ b/keystore/java/android/security/UserNotAuthenticatedException.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * Indicates that a cryptographic operation could not be performed because the user has not been + * authenticated recently enough. + * + * @hide + */ +public class UserNotAuthenticatedException extends CryptoOperationException { + public UserNotAuthenticatedException() { + super("User not authenticated"); + } + + public UserNotAuthenticatedException(String message) { + super(message); + } +} |