content: /*
   * 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.keystore;
  
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  
  import java.security.PrivateKey;
  import java.security.spec.KeySpec;
  import java.util.Date;
  
  import javax.crypto.SecretKey;
  
  /**
   * Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
   * Keystore system</a>. This class describes whether the key material is available in
   * plaintext outside of secure hardware, whether user authentication is required for using the key
   * and whether this requirement is enforced by secure hardware, the key's origin, what uses the key
   * is authorized for (e.g., only in {@code GCM} mode, or signing only), whether the key should be
   * encrypted at rest, the key's and validity start and end dates.
   *
   * <p>Instances of this class are immutable.
   *
   * <p><h3>Example: Symmetric Key</h3>
   * The following example illustrates how to obtain a {@code KeyInfo} describing the provided Android
   * Keystore {@link SecretKey}.
   * <pre>{@code
   * SecretKey key = ...; // Android Keystore key
   *
   * SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
   * KeyInfo keyInfo;
   * try {
   *     keyInfo = (KeyInfo) factory.getKeySpec(key, KeyInfo.class);
   * } catch (InvalidKeySpecException e) {
   *     // Not an Android KeyStore key.
   * }}</pre>
   *
   * <p><h3>Example: Private Key</h3>
   * The following example illustrates how to obtain a {@code KeyInfo} describing the provided
   * Android KeyStore {@link PrivateKey}.
   * <pre>{@code
   * PrivateKey key = ...; // Android KeyStore key
   *
   * KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
   * KeyInfo keyInfo;
   * try {
   *     keyInfo = factory.getKeySpec(key, KeyInfo.class);
   * } catch (InvalidKeySpecException e) {
   *     // Not an Android KeyStore key.
   * }}</pre>
   */
  public class KeyInfo implements KeySpec {
      private final String mKeystoreAlias;
      private final int mKeySize;
      private final boolean mInsideSecureHardware;
      private final @KeyProperties.OriginEnum int mOrigin;
      private final Date mKeyValidityStart;
      private final Date mKeyValidityForOriginationEnd;
      private final Date mKeyValidityForConsumptionEnd;
      private final @KeyProperties.PurposeEnum int mPurposes;
      private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
      private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
      private final @KeyProperties.DigestEnum String[] mDigests;
      private final @KeyProperties.BlockModeEnum String[] mBlockModes;
      private final boolean mUserAuthenticationRequired;
      private final int mUserAuthenticationValidityDurationSeconds;
      private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
      private final boolean mUserAuthenticationValidWhileOnBody;
      private final boolean mTrustedUserPresenceRequired;
      private final boolean mInvalidatedByBiometricEnrollment;
      private final boolean mUserConfirmationRequired;
  
      /**
       * @hide
       */
      public KeyInfo(String keystoreKeyAlias,
              boolean insideSecureHardware,
              @KeyProperties.OriginEnum int origin,
              int keySize,
              Date keyValidityStart,
              Date keyValidityForOriginationEnd,
              Date keyValidityForConsumptionEnd,
              @KeyProperties.PurposeEnum int purposes,
              @KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
              @KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
              @KeyProperties.DigestEnum String[] digests,
              @KeyProperties.BlockModeEnum String[] blockModes,
              boolean userAuthenticationRequired,
              int userAuthenticationValidityDurationSeconds,
              boolean userAuthenticationRequirementEnforcedBySecureHardware,
              boolean userAuthenticationValidWhileOnBody,
              boolean trustedUserPresenceRequired,
              boolean invalidatedByBiometricEnrollment,
              boolean userConfirmationRequired) {
          mKeystoreAlias = keystoreKeyAlias;
          mInsideSecureHardware = insideSecureHardware;
          mOrigin = origin;
          mKeySize = keySize;
          mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
          mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
          mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
          mPurposes = purposes;
          mEncryptionPaddings =
                  ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
          mSignaturePaddings =
                  ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
          mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
          mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
          mUserAuthenticationRequired = userAuthenticationRequired;
          mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
          mUserAuthenticationRequirementEnforcedBySecureHardware =
                  userAuthenticationRequirementEnforcedBySecureHardware;
          mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
          mTrustedUserPresenceRequired = trustedUserPresenceRequired;
          mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
          mUserConfirmationRequired = userConfirmationRequired;
      }
  
      /**
       * Gets the entry alias under which the key is stored in the {@code AndroidKeyStore}.
       */
      public String getKeystoreAlias() {
          return mKeystoreAlias;
      }
  
      /**
       * 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;
      }
  
      /**
       * Gets the origin of the key. See {@link KeyProperties}.{@code ORIGIN} constants.
       */
      public @KeyProperties.OriginEnum int getOrigin() {
          return mOrigin;
      }
  
      /**
       * Gets the size of the key in bits.
       */
      public int getKeySize() {
          return mKeySize;
      }
  
      /**
       * Gets the time instant before which the key is not yet valid.
       *
       * @return instant or {@code null} if not restricted.
       */
      @Nullable
      public Date getKeyValidityStart() {
          return Utils.cloneIfNotNull(mKeyValidityStart);
      }
  
      /**
       * Gets the time instant after which the key is no long valid for decryption and verification.
       *
       * @return instant or {@code null} if not restricted.
       */
      @Nullable
      public Date getKeyValidityForConsumptionEnd() {
          return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd);
      }
  
      /**
       * Gets the time instant after which the key is no long valid for encryption and signing.
       *
       * @return instant or {@code null} if not restricted.
       */
      @Nullable
      public Date getKeyValidityForOriginationEnd() {
          return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd);
      }
  
      /**
       * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
       * Attempts to use the key for any other purpose will be rejected.
       *
       * <p>See {@link KeyProperties}.{@code PURPOSE} flags.
       */
      public @KeyProperties.PurposeEnum int getPurposes() {
          return mPurposes;
      }
  
      /**
       * Gets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be used
       * when encrypting/decrypting. Attempts to use the key with any other block modes will be
       * rejected.
       *
       * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
       */
      @NonNull
      public @KeyProperties.BlockModeEnum String[] getBlockModes() {
          return ArrayUtils.cloneIfNotEmpty(mBlockModes);
      }
  
      /**
       * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code PKCS1Padding},
       * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
       * the key with any other padding scheme will be rejected.
       *
       * <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
       */
      @NonNull
      public @KeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
          return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
      }
  
      /**
       * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
       * can be used when signing/verifying. Attempts to use the key with any other padding scheme
       * will be rejected.
       *
       * <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
       */
      @NonNull
      public @KeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
          return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
      }
  
      /**
       * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key
       * can be used.
       *
       * <p>See {@link KeyProperties}.{@code DIGEST} constants.
       */
      @NonNull
      public @KeyProperties.DigestEnum String[] getDigests() {
          return ArrayUtils.cloneIfNotEmpty(mDigests);
      }
  
      /**
       * 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;
      }
  
      /**
       * Returns {@code true} if the key is authorized to be used only for messages confirmed by the
       * user.
       *
       * Confirmation is separate from user authentication (see
       * {@link #isUserAuthenticationRequired()}). Keys can be created that require confirmation but
       * not user authentication, or user authentication but not confirmation, or both. Confirmation
       * verifies that some user with physical possession of the device has approved a displayed
       * message. User authentication verifies that the correct user is present and has
       * authenticated.
       *
       * <p>This authorization applies only to secret key and private key operations. Public key
       * operations are not restricted.
       *
       * @see KeyGenParameterSpec.Builder#setUserConfirmationRequired(boolean)
       * @see KeyProtection.Builder#setUserConfirmationRequired(boolean)
       */
      public boolean isUserConfirmationRequired() {
          return mUserConfirmationRequired;
      }
  
      /**
       * Gets the duration of time (seconds) for which this key is authorized to be used after the
       * user is successfully authenticated. This has effect only if user authentication is required
       * (see {@link #isUserAuthenticationRequired()}).
       *
       * <p>This authorization applies only to secret key and private key operations. Public key
       * operations are not restricted.
       *
       * @return duration in seconds or {@code -1} if authentication is required for every use of the
       *         key.
       *
       * @see #isUserAuthenticationRequired()
       */
      public int getUserAuthenticationValidityDurationSeconds() {
          return mUserAuthenticationValidityDurationSeconds;
      }
  
      /**
       * 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 this key will become unusable when the device is removed from the
       * user's body.  This is possible only for keys with a specified validity duration, and only on
       * devices with an on-body sensor.  Always returns {@code false} on devices that lack an on-body
       * sensor.
       */
      public boolean isUserAuthenticationValidWhileOnBody() {
          return mUserAuthenticationValidWhileOnBody;
      }
  
      /**
       * Returns {@code true} if the key will be invalidated by enrollment of a new fingerprint or
       * removal of all fingerprints.
       */
      public boolean isInvalidatedByBiometricEnrollment() {
          return mInvalidatedByBiometricEnrollment;
      }
  
      /**
       * Returns {@code true} if the key can only be only be used if a test for user presence has
       * succeeded since Signature.initSign() has been called.
       */
      public boolean isTrustedUserPresenceRequired() {
          return mTrustedUserPresenceRequired;
      }
  }
  