am 33c9dde9: Merge "Add KeyPermanentlyInvalidatedException." into mnc-dev

* commit '33c9dde90d480fe457295dde37baa730d0cbc819':
  Add KeyPermanentlyInvalidatedException.
This commit is contained in:
Alex Klyubin
2015-04-30 00:01:59 +00:00
committed by Android Git Automerger
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); 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 { public abstract class KeyStoreKeyProperties {
} }
@ -28696,11 +28702,6 @@ package android.security {
method public boolean isCleartextTrafficPermitted(); 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 { public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException();
ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String);

View File

@ -30629,6 +30629,12 @@ package android.security {
method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); 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 { public abstract class KeyStoreKeyProperties {
} }
@ -30709,11 +30715,6 @@ package android.security {
method public boolean isCleartextTrafficPermitted(); 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 { public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException();
ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String);

View File

@ -87,6 +87,28 @@ public class KeyCharacteristics implements Parcelable {
return result; 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) { public Date getDate(int tag) {
Date result = hwEnforced.getDate(tag, null); Date result = hwEnforced.getDate(tag, null);
if (result == null) { if (result == null) {

View File

@ -15,13 +15,17 @@ public abstract class GateKeeper {
private GateKeeper() {} private GateKeeper() {}
public static IGateKeeperService getService() { public static IGateKeeperService getService() {
return IGateKeeperService.Stub.asInterface( IGateKeeperService service = IGateKeeperService.Stub.asInterface(
ServiceManager.getService("android.service.gatekeeper.IGateKeeperService")); ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
if (service == null) {
throw new IllegalStateException("Gatekeeper service not available");
}
return service;
} }
public static long getSecureUserId() throws IllegalStateException { public static long getSecureUserId() throws IllegalStateException {
try { try {
return GateKeeper.getService().getSecureUserId(UserHandle.myUserId()); return getService().getSecureUserId(UserHandle.myUserId());
} catch (RemoteException e) { } catch (RemoteException e) {
throw new IllegalStateException( throw new IllegalStateException(
"Failed to obtain secure user ID from gatekeeper", e); "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 com.android.org.conscrypt.NativeConstants;
import android.content.Context;
import android.hardware.fingerprint.IFingerprintService;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@ -31,6 +33,7 @@ import android.security.keymaster.OperationResult;
import android.util.Log; import android.util.Log;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@ -490,7 +493,8 @@ public class KeyStore {
/** /**
* Check if the operation referenced by {@code token} is currently authorized. * 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) { public boolean isOperationAuthorized(IBinder token) {
try { try {
@ -561,27 +565,80 @@ public class KeyStore {
* Returns an {@link InvalidKeyException} corresponding to the provided * Returns an {@link InvalidKeyException} corresponding to the provided
* {@link KeyStoreException}. * {@link KeyStoreException}.
*/ */
static InvalidKeyException getInvalidKeyException(KeyStoreException e) { InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, KeyStoreException e) {
switch (e.getErrorCode()) { switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_KEY_EXPIRED: case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
return new KeyExpiredException(); return new KeyExpiredException();
case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
return new KeyNotYetValidException(); return new KeyNotYetValidException();
case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
return new UserNotAuthenticatedException(); {
// TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled" // We now need to determine whether the key/operation can become usable if user
// case KeymasterDefs.KM_ERROR_TBD // authentication is performed, or whether it can never become usable again.
// return new NewFingerprintEnrolledException(); // 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: default:
return new InvalidKeyException("Keystore operation failed", e); 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 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
* code. * code.
*/ */
static InvalidKeyException getInvalidKeyException(int errorCode) { InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
return getInvalidKeyException(getKeyStoreException(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: case KeymasterDefs.KM_ERROR_INVALID_NONCE:
throw new InvalidAlgorithmParameterException("Invalid IV"); throw new InvalidAlgorithmParameterException("Invalid IV");
} }
throw KeyStore.getInvalidKeyException(opResult.resultCode); throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
} }
if (opResult.token == null) { if (opResult.token == null) {

View File

@ -169,7 +169,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 KeyStore.getInvalidKeyException(opResult.resultCode); throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
} }
if (opResult.token == null) { if (opResult.token == null) {
throw new IllegalStateException("Keystore returned null operation token"); throw new IllegalStateException("Keystore returned null operation token");

View File

@ -18,12 +18,8 @@ package android.security;
import android.content.Context; import android.content.Context;
import android.hardware.fingerprint.FingerprintManager; 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.KeymasterArguments;
import android.security.keymaster.KeymasterDefs; import android.security.keymaster.KeymasterDefs;
import android.service.gatekeeper.IGateKeeperService;
import libcore.util.EmptyArray; import libcore.util.EmptyArray;
@ -347,20 +343,6 @@ public abstract class KeymasterUtils {
return result; 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 * Adds keymaster arguments to express the key's authorization policy supported by user
* authentication. * authentication.
@ -402,7 +384,7 @@ public abstract class KeymasterUtils {
} else { } else {
// The key is authorized for use for the specified amount of time after the user has // 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. // authenticated. Whatever unlocks the secure lock screen should authorize this key.
long rootSid = getRootSid(); long rootSid = GateKeeper.getSecureUserId();
if (rootSid == 0) { if (rootSid == 0) {
throw new IllegalStateException("Secure lock screen must be enabled" throw new IllegalStateException("Secure lock screen must be enabled"
+ " to create keys requiring user authentication"); + " 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 * 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 { public class UserNotAuthenticatedException extends InvalidKeyException {