am c461452e: Merge "Hook in user authenticators and their exceptions."

* commit 'c461452eb78867032092b2fce14c2fcb3e7ab34e':
  Hook in user authenticators and their exceptions.
This commit is contained in:
Alex Klyubin
2015-04-01 17:57:06 +00:00
committed by Android Git Automerger
9 changed files with 159 additions and 30 deletions

View File

@@ -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,

View File

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

View File

@@ -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) {

View File

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

View File

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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

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