am c461452e: Merge "Hook in user authenticators and their exceptions."
* commit 'c461452eb78867032092b2fce14c2fcb3e7ab34e': Hook in user authenticators and their exceptions.
This commit is contained in:
@@ -536,10 +536,9 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
|||||||
if (params.getUserAuthenticators().isEmpty()) {
|
if (params.getUserAuthenticators().isEmpty()) {
|
||||||
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
|
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
|
||||||
// for (int userAuthenticatorId : params.getUserAuthenticators()) {
|
KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
|
||||||
// args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
|
params.getUserAuthenticators()));
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
if (params.getUserAuthenticationValidityDurationSeconds() != null) {
|
if (params.getUserAuthenticationValidityDurationSeconds() != null) {
|
||||||
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
|
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
|
||||||
|
|||||||
@@ -224,8 +224,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
|
|||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
||||||
throw new CryptoOperationException("Failed to start keystore operation",
|
throw KeymasterUtils.getCryptoOperationException(opResult.resultCode);
|
||||||
KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opResult.token == null) {
|
if (opResult.token == null) {
|
||||||
@@ -252,7 +251,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
|
|||||||
try {
|
try {
|
||||||
output = mMainDataStreamer.update(input, inputOffset, inputLen);
|
output = mMainDataStreamer.update(input, inputOffset, inputLen);
|
||||||
} catch (KeymasterException e) {
|
} catch (KeymasterException e) {
|
||||||
throw new CryptoOperationException("Keystore operation failed", e);
|
throw KeymasterUtils.getCryptoOperationException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.length == 0) {
|
if (output.length == 0) {
|
||||||
@@ -297,7 +296,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
|
|||||||
case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
|
case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
|
||||||
throw new AEADBadTagException();
|
throw new AEADBadTagException();
|
||||||
default:
|
default:
|
||||||
throw new CryptoOperationException("Keystore operation failed", e);
|
throw KeymasterUtils.getCryptoOperationException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
|||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
||||||
throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
|
throw KeymasterUtils.getKeymasterException(opResult.resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opResult.inputConsumed == chunk.length) {
|
if (opResult.inputConsumed == chunk.length) {
|
||||||
@@ -203,7 +203,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
|||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
||||||
throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
|
throw KeymasterUtils.getKeymasterException(opResult.resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return concat(output, opResult.output);
|
return concat(output, opResult.output);
|
||||||
@@ -227,7 +227,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
|||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
||||||
throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
|
throw KeymasterUtils.getKeymasterException(opResult.resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opResult.inputConsumed < chunk.length) {
|
if (opResult.inputConsumed < chunk.length) {
|
||||||
|
|||||||
@@ -103,8 +103,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
|
|||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
|
||||||
throw new CryptoOperationException("Failed to start keystore operation",
|
throw KeymasterUtils.getCryptoOperationException(opResult.resultCode);
|
||||||
KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode));
|
|
||||||
}
|
}
|
||||||
mOperationToken = opResult.token;
|
mOperationToken = opResult.token;
|
||||||
if (mOperationToken == null) {
|
if (mOperationToken == null) {
|
||||||
@@ -131,7 +130,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
|
|||||||
try {
|
try {
|
||||||
output = mChunkedStreamer.update(input, offset, len);
|
output = mChunkedStreamer.update(input, offset, len);
|
||||||
} catch (KeymasterException e) {
|
} catch (KeymasterException e) {
|
||||||
throw new CryptoOperationException("Keystore operation failed", e);
|
throw KeymasterUtils.getCryptoOperationException(e);
|
||||||
}
|
}
|
||||||
if ((output != null) && (output.length != 0)) {
|
if ((output != null) && (output.length != 0)) {
|
||||||
throw new CryptoOperationException("Update operation unexpectedly produced output");
|
throw new CryptoOperationException("Update operation unexpectedly produced output");
|
||||||
@@ -148,7 +147,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
|
|||||||
try {
|
try {
|
||||||
result = mChunkedStreamer.doFinal(null, 0, 0);
|
result = mChunkedStreamer.doFinal(null, 0, 0);
|
||||||
} catch (KeymasterException e) {
|
} catch (KeymasterException e) {
|
||||||
throw new CryptoOperationException("Keystore operation failed", e);
|
throw KeymasterUtils.getCryptoOperationException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
engineReset();
|
engineReset();
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constraints for {@code AndroidKeyStore} keys.
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,10 +136,9 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
|||||||
if (spec.getUserAuthenticators().isEmpty()) {
|
if (spec.getUserAuthenticators().isEmpty()) {
|
||||||
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
|
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
|
||||||
// for (int userAuthenticatorId : spec.getUserAuthenticators()) {
|
KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
|
||||||
// args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
|
spec.getUserAuthenticators()));
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
if (spec.getUserAuthenticationValidityDurationSeconds() != null) {
|
if (spec.getUserAuthenticationValidityDurationSeconds() != null) {
|
||||||
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
|
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
|
||||||
@@ -175,8 +174,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
|||||||
int errorCode = mKeyStore.generateKey(
|
int errorCode = mKeyStore.generateKey(
|
||||||
keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
|
keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
|
||||||
if (errorCode != KeyStore.NO_ERROR) {
|
if (errorCode != KeyStore.NO_ERROR) {
|
||||||
throw new CryptoOperationException("Failed to generate key",
|
throw KeymasterUtils.getCryptoOperationException(errorCode);
|
||||||
KeymasterUtils.getExceptionForKeymasterError(errorCode));
|
|
||||||
}
|
}
|
||||||
String keyAlgorithmJCA =
|
String keyAlgorithmJCA =
|
||||||
KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
|
KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import android.security.keymaster.KeymasterDefs;
|
|||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.KeySpec;
|
import java.security.spec.KeySpec;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
@@ -113,13 +112,16 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
|||||||
throw new InvalidKeySpecException("Unsupported key characteristic", e);
|
throw new InvalidKeySpecException("Unsupported key characteristic", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Read user authentication IDs once the Keymaster API has stabilized
|
int swEnforcedUserAuthenticatorIds =
|
||||||
Set<Integer> userAuthenticators = Collections.emptySet();
|
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||||
Set<Integer> teeBackedUserAuthenticators = Collections.emptySet();
|
int hwEnforcedUserAuthenticatorIds =
|
||||||
// Set<Integer> userAuthenticators = new HashSet<Integer>(
|
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||||
// getInts(keyCharacteristics, KeymasterDefs.KM_TAG_USER_AUTH_ID));
|
int userAuthenticatorIds = swEnforcedUserAuthenticatorIds | hwEnforcedUserAuthenticatorIds;
|
||||||
// Set<Integer> teeBackedUserAuthenticators = new HashSet<Integer>(
|
Set<Integer> userAuthenticators =
|
||||||
// keyCharacteristics.hwEnforced.getInts(KeymasterDefs.KM_TAG_USER_AUTH_ID));
|
KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(userAuthenticatorIds);
|
||||||
|
Set<Integer> teeBackedUserAuthenticators =
|
||||||
|
KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
|
||||||
|
hwEnforcedUserAuthenticatorIds);
|
||||||
|
|
||||||
return new KeyStoreKeySpec(entryAlias,
|
return new KeyStoreKeySpec(entryAlias,
|
||||||
origin,
|
origin,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.util.List;
|
|||||||
public abstract class KeymasterUtils {
|
public abstract class KeymasterUtils {
|
||||||
private KeymasterUtils() {}
|
private KeymasterUtils() {}
|
||||||
|
|
||||||
public static KeymasterException getExceptionForKeymasterError(int keymasterErrorCode) {
|
public static KeymasterException getKeymasterException(int keymasterErrorCode) {
|
||||||
switch (keymasterErrorCode) {
|
switch (keymasterErrorCode) {
|
||||||
case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
|
case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
|
||||||
// The name of this parameter significantly differs between Keymaster and framework
|
// 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) {
|
public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
|
||||||
if (keyCharacteristics.hwEnforced.containsTag(tag)) {
|
if (keyCharacteristics.hwEnforced.containsTag(tag)) {
|
||||||
return keyCharacteristics.hwEnforced.getInt(tag, -1);
|
return keyCharacteristics.hwEnforced.getInt(tag, -1);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user