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 17package android.security.keystore; 18 19import android.security.Credentials; 20import android.security.GateKeeper; 21import android.security.KeyStore; 22import android.security.keymaster.KeyCharacteristics; 23import android.security.keymaster.KeymasterDefs; 24 25import java.math.BigInteger; 26import java.security.InvalidKeyException; 27import java.security.ProviderException; 28import java.security.spec.InvalidKeySpecException; 29import java.security.spec.KeySpec; 30import java.util.ArrayList; 31import java.util.Date; 32import java.util.List; 33 34import javax.crypto.SecretKey; 35import javax.crypto.SecretKeyFactorySpi; 36import javax.crypto.spec.SecretKeySpec; 37 38/** 39 * {@link SecretKeyFactorySpi} backed by Android Keystore. 40 * 41 * @hide 42 */ 43public 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_SECRET_KEY)) { 68 entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length()); 69 } else { 70 throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore); 71 } 72 73 return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid()); 74 } 75 76 static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore, 77 int keyUid) { 78 KeyCharacteristics keyCharacteristics = new KeyCharacteristics(); 79 int errorCode = keyStore.getKeyCharacteristics( 80 keyAliasInKeystore, null, null, keyUid, keyCharacteristics); 81 if (errorCode != KeyStore.NO_ERROR) { 82 throw new ProviderException("Failed to obtain information about key." 83 + " Keystore error: " + errorCode); 84 } 85 86 boolean insideSecureHardware; 87 @KeyProperties.OriginEnum int origin; 88 int keySize; 89 @KeyProperties.PurposeEnum int purposes; 90 String[] encryptionPaddings; 91 String[] signaturePaddings; 92 @KeyProperties.DigestEnum String[] digests; 93 @KeyProperties.BlockModeEnum String[] blockModes; 94 int keymasterSwEnforcedUserAuthenticators; 95 int keymasterHwEnforcedUserAuthenticators; 96 List<BigInteger> keymasterSecureUserIds; 97 try { 98 if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) { 99 insideSecureHardware = true; 100 origin = KeyProperties.Origin.fromKeymaster( 101 keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1)); 102 } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) { 103 insideSecureHardware = false; 104 origin = KeyProperties.Origin.fromKeymaster( 105 keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1)); 106 } else { 107 throw new ProviderException("Key origin not available"); 108 } 109 long keySizeUnsigned = 110 keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1); 111 if (keySizeUnsigned == -1) { 112 throw new ProviderException("Key size not available"); 113 } else if (keySizeUnsigned > Integer.MAX_VALUE) { 114 throw new ProviderException("Key too large: " + keySizeUnsigned + " bits"); 115 } 116 keySize = (int) keySizeUnsigned; 117 purposes = KeyProperties.Purpose.allFromKeymaster( 118 keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PURPOSE)); 119 120 List<String> encryptionPaddingsList = new ArrayList<String>(); 121 List<String> signaturePaddingsList = new ArrayList<String>(); 122 // Keymaster stores both types of paddings in the same array -- we split it into two. 123 for (int keymasterPadding : keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PADDING)) { 124 try { 125 @KeyProperties.EncryptionPaddingEnum String jcaPadding = 126 KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding); 127 encryptionPaddingsList.add(jcaPadding); 128 } catch (IllegalArgumentException e) { 129 try { 130 @KeyProperties.SignaturePaddingEnum String padding = 131 KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding); 132 signaturePaddingsList.add(padding); 133 } catch (IllegalArgumentException e2) { 134 throw new ProviderException( 135 "Unsupported encryption padding: " + keymasterPadding); 136 } 137 } 138 139 } 140 encryptionPaddings = 141 encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]); 142 signaturePaddings = 143 signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]); 144 145 digests = KeyProperties.Digest.allFromKeymaster( 146 keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST)); 147 blockModes = KeyProperties.BlockMode.allFromKeymaster( 148 keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_BLOCK_MODE)); 149 keymasterSwEnforcedUserAuthenticators = 150 keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0); 151 keymasterHwEnforcedUserAuthenticators = 152 keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0); 153 keymasterSecureUserIds = 154 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); 155 } catch (IllegalArgumentException e) { 156 throw new ProviderException("Unsupported key characteristic", e); 157 } 158 159 Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME); 160 Date keyValidityForOriginationEnd = 161 keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME); 162 Date keyValidityForConsumptionEnd = 163 keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME); 164 boolean userAuthenticationRequired = 165 !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); 166 long userAuthenticationValidityDurationSeconds = 167 keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1); 168 if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) { 169 throw new ProviderException("User authentication timeout validity too long: " 170 + userAuthenticationValidityDurationSeconds + " seconds"); 171 } 172 boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired) 173 && (keymasterHwEnforcedUserAuthenticators != 0) 174 && (keymasterSwEnforcedUserAuthenticators == 0); 175 boolean userAuthenticationValidWhileOnBody = 176 keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY); 177 178 boolean invalidatedByBiometricEnrollment = false; 179 if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT 180 || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) { 181 // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list. 182 invalidatedByBiometricEnrollment = keymasterSecureUserIds != null 183 && !keymasterSecureUserIds.isEmpty() 184 && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId()); 185 } 186 187 return new KeyInfo(entryAlias, 188 insideSecureHardware, 189 origin, 190 keySize, 191 keyValidityStart, 192 keyValidityForOriginationEnd, 193 keyValidityForConsumptionEnd, 194 purposes, 195 encryptionPaddings, 196 signaturePaddings, 197 digests, 198 blockModes, 199 userAuthenticationRequired, 200 (int) userAuthenticationValidityDurationSeconds, 201 userAuthenticationRequirementEnforcedBySecureHardware, 202 userAuthenticationValidWhileOnBody, 203 invalidatedByBiometricEnrollment); 204 } 205 206 private static BigInteger getGateKeeperSecureUserId() throws ProviderException { 207 try { 208 return BigInteger.valueOf(GateKeeper.getSecureUserId()); 209 } catch (IllegalStateException e) { 210 throw new ProviderException("Failed to get GateKeeper secure user ID", e); 211 } 212 } 213 214 @Override 215 protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException { 216 throw new InvalidKeySpecException( 217 "To generate secret key in Android Keystore, use KeyGenerator initialized with " 218 + KeyGenParameterSpec.class.getName()); 219 } 220 221 @Override 222 protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException { 223 if (key == null) { 224 throw new InvalidKeyException("key == null"); 225 } else if (!(key instanceof AndroidKeyStoreSecretKey)) { 226 throw new InvalidKeyException( 227 "To import a secret key into Android Keystore, use KeyStore.setEntry"); 228 } 229 230 return key; 231 } 232} 233