Merge "Add KeyPermanentlyInvalidatedException." into mnc-dev

This commit is contained in:
Alex Klyubin
2015-04-29 23:48:13 +00:00
committed by Android (Google) Code Review
11 changed files with 164 additions and 83 deletions

View File

@ -28616,6 +28616,12 @@ package android.security {
method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
ctor public KeyPermanentlyInvalidatedException();
ctor public KeyPermanentlyInvalidatedException(java.lang.String);
ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
}
public abstract class KeyStoreKeyProperties {
}
@ -28696,11 +28702,6 @@ package android.security {
method public boolean isCleartextTrafficPermitted();
}
public class NewFingerprintEnrolledException extends java.security.InvalidKeyException {
ctor public NewFingerprintEnrolledException();
ctor public NewFingerprintEnrolledException(java.lang.String);
}
public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
ctor public UserNotAuthenticatedException();
ctor public UserNotAuthenticatedException(java.lang.String);

View File

@ -30629,6 +30629,12 @@ package android.security {
method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
ctor public KeyPermanentlyInvalidatedException();
ctor public KeyPermanentlyInvalidatedException(java.lang.String);
ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
}
public abstract class KeyStoreKeyProperties {
}
@ -30709,11 +30715,6 @@ package android.security {
method public boolean isCleartextTrafficPermitted();
}
public class NewFingerprintEnrolledException extends java.security.InvalidKeyException {
ctor public NewFingerprintEnrolledException();
ctor public NewFingerprintEnrolledException(java.lang.String);
}
public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
ctor public UserNotAuthenticatedException();
ctor public UserNotAuthenticatedException(java.lang.String);

View File

@ -87,6 +87,28 @@ public class KeyCharacteristics implements Parcelable {
return result;
}
public Long getLong(int tag) {
if (hwEnforced.containsTag(tag)) {
return hwEnforced.getLong(tag, -1);
} else if (swEnforced.containsTag(tag)) {
return swEnforced.getLong(tag, -1);
} else {
return null;
}
}
public long getLong(int tag, long defaultValue) {
Long result = getLong(tag);
return (result != null) ? result : defaultValue;
}
public List<Long> getLongs(int tag) {
List<Long> result = new ArrayList<Long>();
result.addAll(hwEnforced.getLongs(tag));
result.addAll(swEnforced.getLongs(tag));
return result;
}
public Date getDate(int tag) {
Date result = hwEnforced.getDate(tag, null);
if (result == null) {

View File

@ -15,13 +15,17 @@ public abstract class GateKeeper {
private GateKeeper() {}
public static IGateKeeperService getService() {
return IGateKeeperService.Stub.asInterface(
IGateKeeperService service = IGateKeeperService.Stub.asInterface(
ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
if (service == null) {
throw new IllegalStateException("Gatekeeper service not available");
}
return service;
}
public static long getSecureUserId() throws IllegalStateException {
try {
return GateKeeper.getService().getSecureUserId(UserHandle.myUserId());
return getService().getSecureUserId(UserHandle.myUserId());
} catch (RemoteException e) {
throw new IllegalStateException(
"Failed to obtain secure user ID from gatekeeper", e);

View File

@ -0,0 +1,55 @@
/*
* 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;
import java.security.InvalidKeyException;
/**
* Indicates that the key can no longer be used because it has been permanently invalidated.
*
* <p>This can currently occur only for keys that require user authentication. Such keys are
* permanently invalidated once the secure lock screen is disabled (i.e., reconfigured to None,
* Swipe or other mode which does not authenticate the user) or when the secure lock screen is
* forcibly reset (e.g., by Device Admin). Additionally, keys configured to require user
* authentication for every use of the key are also permanently invalidated once a new fingerprint
* is enrolled or once no more fingerprints are enrolled.
*/
public class KeyPermanentlyInvalidatedException extends InvalidKeyException {
/**
* Constructs a new {@code KeyPermanentlyInvalidatedException} without detail message and cause.
*/
public KeyPermanentlyInvalidatedException() {
super("Key permanently invalidated");
}
/**
* Constructs a new {@code KeyPermanentlyInvalidatedException} with the provided detail message
* and no cause.
*/
public KeyPermanentlyInvalidatedException(String message) {
super(message);
}
/**
* Constructs a new {@code KeyPermanentlyInvalidatedException} with the provided detail message
* and cause.
*/
public KeyPermanentlyInvalidatedException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -18,6 +18,8 @@ package android.security;
import com.android.org.conscrypt.NativeConstants;
import android.content.Context;
import android.hardware.fingerprint.IFingerprintService;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@ -31,6 +33,7 @@ import android.security.keymaster.OperationResult;
import android.util.Log;
import java.security.InvalidKeyException;
import java.util.List;
import java.util.Locale;
/**
@ -490,7 +493,8 @@ public class KeyStore {
/**
* Check if the operation referenced by {@code token} is currently authorized.
*
* @param token An operation token returned by a call to {@link KeyStore.begin}.
* @param token An operation token returned by a call to
* {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
*/
public boolean isOperationAuthorized(IBinder token) {
try {
@ -561,27 +565,80 @@ public class KeyStore {
* Returns an {@link InvalidKeyException} corresponding to the provided
* {@link KeyStoreException}.
*/
static InvalidKeyException getInvalidKeyException(KeyStoreException e) {
InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, KeyStoreException e) {
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
return new KeyExpiredException();
case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
return new KeyNotYetValidException();
case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
return new UserNotAuthenticatedException();
// TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
// case KeymasterDefs.KM_ERROR_TBD
// return new NewFingerprintEnrolledException();
{
// We now need to determine whether the key/operation can become usable if user
// authentication is performed, or whether it can never become usable again.
// User authentication requirements are contained in the key's characteristics. We
// need to check whether these requirements can be be satisfied by asking the user
// to authenticate.
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
int getKeyCharacteristicsErrorCode =
getKeyCharacteristics(keystoreKeyAlias, null, null, keyCharacteristics);
if (getKeyCharacteristicsErrorCode != NO_ERROR) {
return new InvalidKeyException(
"Failed to obtained key characteristics",
getKeyStoreException(getKeyCharacteristicsErrorCode));
}
List<Long> keySids =
keyCharacteristics.getLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
if (keySids.isEmpty()) {
// Key is not bound to any SIDs -- no amount of authentication will help here.
return new KeyPermanentlyInvalidatedException();
}
long rootSid = GateKeeper.getSecureUserId();
if ((rootSid != 0) && (keySids.contains(Long.valueOf(rootSid)))) {
// One of the key's SIDs is the current root SID -- user can be authenticated
// against that SID.
return new UserNotAuthenticatedException();
}
long fingerprintOnlySid = getFingerprintOnlySid();
if ((fingerprintOnlySid != 0)
&& (keySids.contains(Long.valueOf(fingerprintOnlySid)))) {
// One of the key's SIDs is the current fingerprint SID -- user can be
// authenticated against that SID.
return new UserNotAuthenticatedException();
}
// None of the key's SIDs can ever be authenticated
return new KeyPermanentlyInvalidatedException();
}
default:
return new InvalidKeyException("Keystore operation failed", e);
}
}
private static long getFingerprintOnlySid() {
IFingerprintService service = IFingerprintService.Stub.asInterface(
ServiceManager.getService(Context.FINGERPRINT_SERVICE));
if (service == null) {
return 0;
}
try {
long deviceId = 0; // TODO: plumb hardware id to FPMS
if (!service.isHardwareDetected(deviceId)) {
return 0;
}
return service.getAuthenticatorId();
} catch (RemoteException e) {
throw new IllegalStateException("Failed to communicate with fingerprint service", e);
}
}
/**
* Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
* code.
*/
static InvalidKeyException getInvalidKeyException(int errorCode) {
return getInvalidKeyException(getKeyStoreException(errorCode));
InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
return getInvalidKeyException(keystoreKeyAlias, getKeyStoreException(errorCode));
}
}

View File

@ -303,7 +303,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
case KeymasterDefs.KM_ERROR_INVALID_NONCE:
throw new InvalidAlgorithmParameterException("Invalid IV");
}
throw KeyStore.getInvalidKeyException(opResult.resultCode);
throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
}
if (opResult.token == null) {

View File

@ -169,7 +169,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
if (opResult == null) {
throw new KeyStoreConnectException();
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
throw KeyStore.getInvalidKeyException(opResult.resultCode);
throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
}
if (opResult.token == null) {
throw new IllegalStateException("Keystore returned null operation token");

View File

@ -18,12 +18,8 @@ package android.security;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.service.gatekeeper.IGateKeeperService;
import libcore.util.EmptyArray;
@ -347,20 +343,6 @@ public abstract class KeymasterUtils {
return result;
}
private static long getRootSid() {
IGateKeeperService gatekeeperService = IGateKeeperService.Stub.asInterface(
ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
if (gatekeeperService == null) {
throw new IllegalStateException("Gatekeeper service not available");
}
try {
return gatekeeperService.getSecureUserId(UserHandle.myUserId());
} catch (RemoteException e) {
throw new IllegalStateException("Failed to obtain root SID");
}
}
/**
* Adds keymaster arguments to express the key's authorization policy supported by user
* authentication.
@ -402,7 +384,7 @@ public abstract class KeymasterUtils {
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
long rootSid = getRootSid();
long rootSid = GateKeeper.getSecureUserId();
if (rootSid == 0) {
throw new IllegalStateException("Secure lock screen must be enabled"
+ " to create keys requiring user authentication");

View File

@ -1,41 +0,0 @@
/*
* 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;
import java.security.InvalidKeyException;
/**
* Indicates that a cryptographic operation could not be performed because the key used by the
* operation is permanently invalid because a new fingerprint was enrolled.
*/
public class NewFingerprintEnrolledException extends InvalidKeyException {
/**
* Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
*/
public NewFingerprintEnrolledException() {
super("Invalid key: new fingerprint enrolled");
}
/**
* Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
* no cause.
*/
public NewFingerprintEnrolledException(String message) {
super(message);
}
}

View File

@ -20,7 +20,7 @@ import java.security.InvalidKeyException;
/**
* Indicates that a cryptographic operation could not be performed because the user has not been
* authenticated recently enough.
* authenticated recently enough. Authenticating the user will resolve this issue.
*/
public class UserNotAuthenticatedException extends InvalidKeyException {