Home | History | Annotate | Download | only in keystore
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.security.keystore;
     18 
     19 import android.security.Credentials;
     20 import android.security.GateKeeper;
     21 import android.security.KeyStore;
     22 import android.security.keymaster.KeyCharacteristics;
     23 import android.security.keymaster.KeymasterDefs;
     24 
     25 import java.math.BigInteger;
     26 import java.security.InvalidKeyException;
     27 import java.security.ProviderException;
     28 import java.security.spec.InvalidKeySpecException;
     29 import java.security.spec.KeySpec;
     30 import java.util.ArrayList;
     31 import java.util.Date;
     32 import java.util.List;
     33 
     34 import javax.crypto.SecretKey;
     35 import javax.crypto.SecretKeyFactorySpi;
     36 import javax.crypto.spec.SecretKeySpec;
     37 
     38 /**
     39  * {@link SecretKeyFactorySpi} backed by Android Keystore.
     40  *
     41  * @hide
     42  */
     43 public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
     44 
     45     private final KeyStore mKeyStore = KeyStore.getInstance();
     46 
     47     @Override
     48     protected KeySpec engineGetKeySpec(SecretKey key,
     49             @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
     50         if (keySpecClass == null) {
     51             throw new InvalidKeySpecException("keySpecClass == null");
     52         }
     53         if (!(key instanceof AndroidKeyStoreSecretKey)) {
     54             throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
     55                     ((key != null) ? key.getClass().getName() : "null"));
     56         }
     57         if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
     58             throw new InvalidKeySpecException(
     59                     "Key material export of Android KeyStore keys is not supported");
     60         }
     61         if (!KeyInfo.class.equals(keySpecClass)) {
     62             throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
     63         }
     64         AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
     65         String keyAliasInKeystore = keystoreKey.getAlias();
     66         String entryAlias;
     67         if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
     68             entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
     69         } else if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)){
     70             // key has legacy prefix
     71             entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
     72         } else {
     73             throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
     74         }
     75 
     76         return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
     77     }
     78 
     79     static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
     80             int keyUid) {
     81         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
     82         int errorCode = keyStore.getKeyCharacteristics(
     83                 keyAliasInKeystore, null, null, keyUid, keyCharacteristics);
     84         if (errorCode != KeyStore.NO_ERROR) {
     85             throw new ProviderException("Failed to obtain information about key."
     86                     + " Keystore error: " + errorCode);
     87         }
     88 
     89         boolean insideSecureHardware;
     90         @KeyProperties.OriginEnum int origin;
     91         int keySize;
     92         @KeyProperties.PurposeEnum int purposes;
     93         String[] encryptionPaddings;
     94         String[] signaturePaddings;
     95         @KeyProperties.DigestEnum String[] digests;
     96         @KeyProperties.BlockModeEnum String[] blockModes;
     97         int keymasterSwEnforcedUserAuthenticators;
     98         int keymasterHwEnforcedUserAuthenticators;
     99         List<BigInteger> keymasterSecureUserIds;
    100         try {
    101             if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
    102                 insideSecureHardware = true;
    103                 origin = KeyProperties.Origin.fromKeymaster(
    104                         keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
    105             } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
    106                 insideSecureHardware = false;
    107                 origin = KeyProperties.Origin.fromKeymaster(
    108                         keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
    109             } else {
    110                 throw new ProviderException("Key origin not available");
    111             }
    112             long keySizeUnsigned =
    113                     keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
    114             if (keySizeUnsigned == -1) {
    115                 throw new ProviderException("Key size not available");
    116             } else if (keySizeUnsigned > Integer.MAX_VALUE) {
    117                 throw new ProviderException("Key too large: " + keySizeUnsigned + " bits");
    118             }
    119             keySize = (int) keySizeUnsigned;
    120             purposes = KeyProperties.Purpose.allFromKeymaster(
    121                     keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PURPOSE));
    122 
    123             List<String> encryptionPaddingsList = new ArrayList<String>();
    124             List<String> signaturePaddingsList = new ArrayList<String>();
    125             // Keymaster stores both types of paddings in the same array -- we split it into two.
    126             for (int keymasterPadding : keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PADDING)) {
    127                 try {
    128                     @KeyProperties.EncryptionPaddingEnum String jcaPadding =
    129                             KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
    130                     encryptionPaddingsList.add(jcaPadding);
    131                 } catch (IllegalArgumentException e) {
    132                     try {
    133                         @KeyProperties.SignaturePaddingEnum String padding =
    134                                 KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding);
    135                         signaturePaddingsList.add(padding);
    136                     } catch (IllegalArgumentException e2) {
    137                         throw new ProviderException(
    138                                 "Unsupported encryption padding: " + keymasterPadding);
    139                     }
    140                 }
    141 
    142             }
    143             encryptionPaddings =
    144                     encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
    145             signaturePaddings =
    146                     signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]);
    147 
    148             digests = KeyProperties.Digest.allFromKeymaster(
    149                     keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST));
    150             blockModes = KeyProperties.BlockMode.allFromKeymaster(
    151                     keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_BLOCK_MODE));
    152             keymasterSwEnforcedUserAuthenticators =
    153                     keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
    154             keymasterHwEnforcedUserAuthenticators =
    155                     keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
    156             keymasterSecureUserIds =
    157                 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
    158         } catch (IllegalArgumentException e) {
    159             throw new ProviderException("Unsupported key characteristic", e);
    160         }
    161 
    162         Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
    163         Date keyValidityForOriginationEnd =
    164                 keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
    165         Date keyValidityForConsumptionEnd =
    166                 keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
    167         boolean userAuthenticationRequired =
    168                 !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
    169         long userAuthenticationValidityDurationSeconds =
    170                 keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
    171         if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) {
    172             throw new ProviderException("User authentication timeout validity too long: "
    173                     + userAuthenticationValidityDurationSeconds + " seconds");
    174         }
    175         boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
    176                 && (keymasterHwEnforcedUserAuthenticators != 0)
    177                 && (keymasterSwEnforcedUserAuthenticators == 0);
    178         boolean userAuthenticationValidWhileOnBody =
    179                 keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
    180         boolean trustedUserPresenceRequred =
    181                 keyCharacteristics.hwEnforced.getBoolean(
    182                     KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
    183 
    184         boolean invalidatedByBiometricEnrollment = false;
    185         if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT
    186             || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) {
    187             // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
    188             invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
    189                     && !keymasterSecureUserIds.isEmpty()
    190                     && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
    191         }
    192 
    193         boolean userConfirmationRequired = keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
    194 
    195         return new KeyInfo(entryAlias,
    196                 insideSecureHardware,
    197                 origin,
    198                 keySize,
    199                 keyValidityStart,
    200                 keyValidityForOriginationEnd,
    201                 keyValidityForConsumptionEnd,
    202                 purposes,
    203                 encryptionPaddings,
    204                 signaturePaddings,
    205                 digests,
    206                 blockModes,
    207                 userAuthenticationRequired,
    208                 (int) userAuthenticationValidityDurationSeconds,
    209                 userAuthenticationRequirementEnforcedBySecureHardware,
    210                 userAuthenticationValidWhileOnBody,
    211                 trustedUserPresenceRequred,
    212                 invalidatedByBiometricEnrollment,
    213                 userConfirmationRequired);
    214     }
    215 
    216     private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
    217     	try {
    218     		return BigInteger.valueOf(GateKeeper.getSecureUserId());
    219     	} catch (IllegalStateException e) {
    220     		throw new ProviderException("Failed to get GateKeeper secure user ID", e);
    221     	}
    222     }
    223 
    224     @Override
    225     protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
    226         throw new InvalidKeySpecException(
    227                 "To generate secret key in Android Keystore, use KeyGenerator initialized with "
    228                         + KeyGenParameterSpec.class.getName());
    229     }
    230 
    231     @Override
    232     protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
    233         if (key == null) {
    234             throw new InvalidKeyException("key == null");
    235         } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
    236             throw new InvalidKeyException(
    237                     "To import a secret key into Android Keystore, use KeyStore.setEntry");
    238         }
    239 
    240         return key;
    241     }
    242 }
    243