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()) {
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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