diff options
author | Alex Klyubin <klyubin@google.com> | 2015-04-30 00:01:59 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-04-30 00:01:59 +0000 |
commit | 789d9dc733d4a3a15e83eb2aa0e49f548fe81618 (patch) | |
tree | e7f5b72eff167f8b7f480c62adb85c72b90b53f2 | |
parent | 850c1888f5855b340e8e26c4d7bc0580644dbcb8 (diff) | |
parent | 33c9dde90d480fe457295dde37baa730d0cbc819 (diff) | |
download | frameworks_base-789d9dc733d4a3a15e83eb2aa0e49f548fe81618.zip frameworks_base-789d9dc733d4a3a15e83eb2aa0e49f548fe81618.tar.gz frameworks_base-789d9dc733d4a3a15e83eb2aa0e49f548fe81618.tar.bz2 |
am 33c9dde9: Merge "Add KeyPermanentlyInvalidatedException." into mnc-dev
* commit '33c9dde90d480fe457295dde37baa730d0cbc819':
Add KeyPermanentlyInvalidatedException.
-rw-r--r-- | api/current.txt | 11 | ||||
-rw-r--r-- | api/system-current.txt | 11 | ||||
-rw-r--r-- | core/java/android/security/keymaster/KeyCharacteristics.java | 22 | ||||
-rw-r--r-- | keystore/java/android/security/GateKeeper.java | 8 | ||||
-rw-r--r-- | keystore/java/android/security/KeyPermanentlyInvalidatedException.java | 55 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStore.java | 73 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreCipherSpi.java | 2 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreHmacSpi.java | 2 | ||||
-rw-r--r-- | keystore/java/android/security/KeymasterUtils.java | 20 | ||||
-rw-r--r-- | keystore/java/android/security/NewFingerprintEnrolledException.java | 41 | ||||
-rw-r--r-- | keystore/java/android/security/UserNotAuthenticatedException.java | 2 |
11 files changed, 164 insertions, 83 deletions
diff --git a/api/current.txt b/api/current.txt index bc4931b..f67270e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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); diff --git a/api/system-current.txt b/api/system-current.txt index 503ccba..bac38d9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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); diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java index 458f153..03248e5 100644 --- a/core/java/android/security/keymaster/KeyCharacteristics.java +++ b/core/java/android/security/keymaster/KeyCharacteristics.java @@ -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) { diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java index c9f06e9..5617836 100644 --- a/keystore/java/android/security/GateKeeper.java +++ b/keystore/java/android/security/GateKeeper.java @@ -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); diff --git a/keystore/java/android/security/KeyPermanentlyInvalidatedException.java b/keystore/java/android/security/KeyPermanentlyInvalidatedException.java new file mode 100644 index 0000000..229eab0 --- /dev/null +++ b/keystore/java/android/security/KeyPermanentlyInvalidatedException.java @@ -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); + } +} diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 5d863c2..f3b447e 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -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)); } } diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java index 3b13e83..9393e32 100644 --- a/keystore/java/android/security/KeyStoreCipherSpi.java +++ b/keystore/java/android/security/KeyStoreCipherSpi.java @@ -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) { diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java index 175369c..8d71d1d 100644 --- a/keystore/java/android/security/KeyStoreHmacSpi.java +++ b/keystore/java/android/security/KeyStoreHmacSpi.java @@ -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"); diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java index 7bf5475..3ccb588 100644 --- a/keystore/java/android/security/KeymasterUtils.java +++ b/keystore/java/android/security/KeymasterUtils.java @@ -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"); diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java deleted file mode 100644 index 4fe210b..0000000 --- a/keystore/java/android/security/NewFingerprintEnrolledException.java +++ /dev/null @@ -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); - } -} diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java index 66f4dd8..2954fa7 100644 --- a/keystore/java/android/security/UserNotAuthenticatedException.java +++ b/keystore/java/android/security/UserNotAuthenticatedException.java @@ -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 { |