Merge "Adding KEY_PERMANENTLY_INVALIDATED int"
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index c43a666..a88aa8c 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -28,6 +28,7 @@
 import android.os.ServiceSpecificException;
 import android.security.KeyStore;
 import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
 
 import com.android.internal.widget.ILockSettings;
 
@@ -548,7 +549,7 @@
             return getKeyFromGrant(grantAlias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (UnrecoverableKeyException e) {
+        } catch (KeyPermanentlyInvalidatedException | UnrecoverableKeyException e) {
             throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
         } catch (ServiceSpecificException e) {
             if (e.errorCode == ERROR_INSECURE_USER) {
@@ -589,7 +590,7 @@
             return getKeyFromGrant(grantAlias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (UnrecoverableKeyException e) {
+        } catch (KeyPermanentlyInvalidatedException | UnrecoverableKeyException  e) {
             throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
         } catch (ServiceSpecificException e) {
             if (e.errorCode == ERROR_INSECURE_USER) {
@@ -622,7 +623,7 @@
             return getKeyFromGrant(grantAlias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (UnrecoverableKeyException e) {
+        } catch (KeyPermanentlyInvalidatedException | UnrecoverableKeyException e) {
             throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
         } catch (ServiceSpecificException e) {
             if (e.errorCode == ERROR_INSECURE_USER) {
@@ -665,7 +666,7 @@
             return getKeyFromGrant(grantAlias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (UnrecoverableKeyException e) {
+        } catch (KeyPermanentlyInvalidatedException | UnrecoverableKeyException e) {
             throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
         } catch (ServiceSpecificException e) {
             if (e.errorCode == ERROR_INSECURE_USER) {
@@ -695,6 +696,8 @@
             return getKeyFromGrant(grantAlias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (KeyPermanentlyInvalidatedException | UnrecoverableKeyException e) {
+            throw new UnrecoverableKeyException(e.getMessage());
         } catch (ServiceSpecificException e) {
             throw wrapUnexpectedServiceSpecificException(e);
         }
@@ -703,7 +706,8 @@
     /**
      * Returns the key with the given {@code grantAlias}.
      */
-    @NonNull Key getKeyFromGrant(@NonNull String grantAlias) throws UnrecoverableKeyException {
+    @NonNull Key getKeyFromGrant(@NonNull String grantAlias)
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
         return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
                 mKeyStore,
                 grantAlias,
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 42e7182..2b2438a 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -22,6 +22,7 @@
 import android.annotation.SystemApi;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -174,7 +175,7 @@
             Key key;
             try {
                 key = mRecoveryController.getKeyFromGrant(grantAlias);
-            } catch (UnrecoverableKeyException e) {
+            } catch (KeyPermanentlyInvalidatedException | UnrecoverableKeyException e) {
                 throw new InternalRecoveryServiceException(
                         String.format(
                                 Locale.US,
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index eb169be..1829d2f 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
 
 import com.android.org.conscrypt.TrustedCertificateStore;
@@ -592,7 +593,7 @@
             try {
                 return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
                         KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
-            } catch (RuntimeException | UnrecoverableKeyException e) {
+            } catch (RuntimeException | UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
                 throw new KeyChainException(e);
             }
         }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 213ed7d..bfce17c 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -98,6 +98,9 @@
      */
     public static final int OP_AUTH_NEEDED = 15;
 
+    // Used when a user changes their pin, invalidating old auth bound keys.
+    public static final int KEY_PERMANENTLY_INVALIDATED = 17;
+
     // Used for UID field to indicate the calling UID.
     public static final int UID_SELF = -1;
 
@@ -1200,6 +1203,8 @@
                     return new KeyStoreException(errorCode, "Key blob corrupted");
                 case OP_AUTH_NEEDED:
                     return new KeyStoreException(errorCode, "Operation requires authorization");
+                case KEY_PERMANENTLY_INVALIDATED:
+                    return new KeyStoreException(errorCode, "Key permanently invalidated");
                 default:
                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
             }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index d44c894..91aac83 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -526,7 +526,7 @@
                                 + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
             }
             return result;
-        } catch (UnrecoverableKeyException e) {
+        } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
             throw new ProviderException("Failed to load generated key pair from keystore", e);
         }
     }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index c7c9ee4..234615d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -228,10 +228,16 @@
     @NonNull
     private static KeyCharacteristics getKeyCharacteristics(@NonNull KeyStore keyStore,
             @NonNull String alias, int uid)
-            throws UnrecoverableKeyException {
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = keyStore.getKeyCharacteristics(
                 alias, null, null, uid, keyCharacteristics);
+        if (errorCode == KeyStore.KEY_PERMANENTLY_INVALIDATED) {
+            throw (KeyPermanentlyInvalidatedException)
+                new KeyPermanentlyInvalidatedException(
+                            "User changed or deleted their auth credentials",
+                            KeyStore.getKeyStoreException(errorCode));
+        }
         if (errorCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain information about key")
@@ -276,7 +282,7 @@
     @NonNull
     public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
-            throws UnrecoverableKeyException {
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
         return loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
                 getKeyCharacteristics(keyStore, privateKeyAlias, uid));
     }
@@ -297,7 +303,7 @@
     @NonNull
     public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
-            throws UnrecoverableKeyException {
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
         return loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
                 getKeyCharacteristics(keyStore, privateKeyAlias, uid));
     }
@@ -315,7 +321,7 @@
     @NonNull
     public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
-            throws UnrecoverableKeyException {
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
         return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, privateKeyAlias, uid,
                 getKeyCharacteristics(keyStore, privateKeyAlias, uid));
     }
@@ -354,7 +360,7 @@
     @NonNull
     public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
-            throws UnrecoverableKeyException  {
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException  {
         KeyCharacteristics keyCharacteristics = getKeyCharacteristics(keyStore, userKeyAlias, uid);
 
         Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 4c007cb..105af6e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -24,6 +24,7 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 import android.security.keystore.SecureKeyImportUnavailableException;
@@ -93,13 +94,20 @@
     public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
             UnrecoverableKeyException {
         String userKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+        AndroidKeyStoreKey key;
         if (!mKeyStore.contains(userKeyAlias, mUid)) {
             // try legacy prefix for backward compatibility
             userKeyAlias = Credentials.USER_SECRET_KEY + alias;
             if (!mKeyStore.contains(userKeyAlias, mUid)) return null;
         }
-        return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore, userKeyAlias,
-                mUid);
+        try {
+            key = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore,
+                                                                             userKeyAlias,
+                                                                             mUid);
+        } catch (KeyPermanentlyInvalidatedException e) {
+            throw new UnrecoverableKeyException(e.getMessage());
+        }
+        return key;
     }
 
     @Override