15

Android 6.0+ has a KeyInfo class to get info on a key saved in the AndroidKeyStore. On the KeyInfo class, we have isInsideSecureHardware() and isUserAuthenticationRequirementEnforcedBySecureHardware() methods. We also have isUserAuthenticationRequired(). The documentation, as usual, sucks.

Based on method names and the (limited) documentation, it would seem as though isUserAuthenticationRequirementEnforcedBySecureHardware() is simply a logical AND of isInsideSecureHardware() and isUserAuthenticationRequired().

Is there something more to it than that? If so, what does it mean for the user authentication requirement to be enforced by secure hardware, beyond just the key being in secure hardware?

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    _"As an additional security measure, for keys whose key material is inside secure hardware, **some** key use authorizations **may** be enforced by secure hardware, depending on the Android device. Cryptographic and user authentication authorizations are **likely** to be enforced by secure hardware. Temporal validity interval authorizations are unlikely to be enforced by the secure hardware because it normally does not have an independent secure real-time clock."_ ([source](https://developer.android.com/training/articles/keystore)). – Michael Aug 02 '18 at 09:03
  • I interpret that as `isUserAuthenticationRequirementEnforcedBySecureHardware` **not** simply being a logical AND of `isInsideSecureHardware` and `isUserAuthenticationRequired`. – Michael Aug 02 '18 at 09:07

3 Answers3

6

The method isUserAuthenticationRequirementEnforcedBySecureHardware() is not a logical AND of isInsideSecureHardware() and isUserAuthenticationRequired().

But if you dig into the code, you can see that it is a logical AND of 3 things:

  1. isUserAuthenticationRequired()
  2. 0 SW Enforced User Authenticators
  3. 1 or more HW Enforced User Authenticators

Snippet of code:

boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
                && (keymasterHwEnforcedUserAuthenticators != 0)
                && (keymasterSwEnforcedUserAuthenticators == 0);

The difference is not whether the key is secure in hardware, but if user authentication is backed by hardware, not software. For most, if not all devices with fingerprint readers, user authentication in secure hardware means the TEE would contain two things that interact with the Keymaster Trusted App:

  1. Gatekeeper Trusted App for pin/password/pattern
  2. Fingerprint Trusted App for fingerprint authentication

Example scenarios:

  • isUserAuthenticationRequirementEnforcedBySecureHardware() could return false if both isInsideSecureHardware() and isUserAuthenticationRequired() return true, but the user authentication is done in SW and not in the TEE. (not likely)
  • isUserAuthenticationRequirementEnforcedBySecureHardware() could return true if isInsideSecureHardware() returns false (key is not supported in device's secure hardware) and isUserAuthenticationRequired() returns true with the user authentication done in HW. (possible)
Steve Miskovetz
  • 2,360
  • 13
  • 29
2

isUserAuthenticationRequirementEnforcedBySecureHardware() is simply a logical AND of isInsideSecureHardware() and isUserAuthenticationRequired().

I think that's not true (see methods below) it comes via the key from KeyChain.

Is there something more to it than that?

KeyInfo.java is a container class for key info from a KeyChain. Whether the key is bound to the secure hardware is known only once the key has been imported.

To find out, use:

{
    PrivateKey key = ...; // private key from KeyChain

    KeyFactory keyFactory =
        KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
    KeyInfo keyInfo = keyFactory.getKeySpec(key, KeyInfo.class);
    if (keyInfo.isInsideSecureHardware()) 
    {
        // The key is bound to the secure hardware of this Android
    }
}

From KeyInfo.java:

/**
 * Returns {@code true} if the key resides inside secure hardware (e.g., Trusted Execution
 * Environment (TEE) or Secure Element (SE)). Key material of such keys is available in
 * plaintext only inside the secure hardware and is not exposed outside of it.
 */
public boolean isInsideSecureHardware() 
{
    return mInsideSecureHardware;
}

/**
 * Returns {@code true} if the requirement that this key can only be used if the user has been
 * authenticated is enforced by secure hardware (e.g., Trusted Execution Environment (TEE) or
 * Secure Element (SE)).
 *
 * @see #isUserAuthenticationRequired()
 */
public boolean isUserAuthenticationRequirementEnforcedBySecureHardware() 
{
    return mUserAuthenticationRequirementEnforcedBySecureHardware;
}

/**
 * Returns {@code true} if the key is authorized to be used only if the user has been
 * authenticated.
 *
 * <p>This authorization applies only to secret key and private key operations. Public key
 * operations are not restricted.
 *
 * @see #getUserAuthenticationValidityDurationSeconds()
 * @see KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean)
 * @see KeyProtection.Builder#setUserAuthenticationRequired(boolean)
 */
public boolean isUserAuthenticationRequired() 
{
    return mUserAuthenticationRequired;
}

See also: KeyStore.java

Jon Goodwin
  • 9,053
  • 5
  • 35
  • 54
  • 1
    That shows three separate fields in `KeyInfo`. It does not indicate whether those three fields are indeed independent (it would be based on whatever is calling the constructor). Also, it does not explain what it means for the user authentication requirement to be enforced by secure hardware, beyond just the key being in secure hardware. Thanks, though! – CommonsWare Feb 01 '18 at 14:34
  • Yes, as I said **KeyInfo.java** is a *container class* for *key* info from a *KeyChain*, and so it's methods are a simple relay of data from the constructor. I'm not saying how the data to the constructor was formed, I'm saying your *contention* that a "simply a logical AND" is *inferred* anywhere in documentation or the code I have displayed, is misplaced (at least to me). I guess I have to look further for the constructorcaller...but **secure hardware is known only once the key has been imported** hmm pondering, and why have the field if it can be reconstructed (I would not do it that way)? – Jon Goodwin Feb 03 '18 at 02:04
  • @CommonsWare I have in the course of my research on the subect come across the comment that some of these methods return *different results* on *multiple calls* on the *same device*, which *if true* is very *puzzling* and *extremely worrisome* about the integrity of the code.. – Jon Goodwin Feb 03 '18 at 18:45
1

isUserAuthenticationRequirementEnforcedBySecureHardware() is simply a logical AND of isInsideSecureHardware() and isUserAuthenticationRequired().

From the given documentation isUserAuthenticationRequirementEnforcedBySecureHardware method must not be logical AND of above two methods.

For observation purpose you can consider this link question, answer and comments.

DjP
  • 4,537
  • 2
  • 25
  • 34
  • 1
    "must not be logical AND of above two methods" -- and your proof of this is... what, exactly? And, if you do have proof, what does it mean for the user authentication requirement to be enforced by secure hardware, beyond just the key being in secure hardware? "For observation purpose you can consider this link question, answer and comments" -- none of that addresses this question. – CommonsWare Feb 06 '18 at 13:16