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.keystore2; 18 19 import android.annotation.NonNull; 20 import android.security.GateKeeper; 21 import android.security.KeyStore; 22 import android.security.keymaster.KeymasterArguments; 23 import android.security.keymaster.KeymasterDefs; 24 import android.security.keystore.KeyGenParameterSpec; 25 import android.security.keystore.KeyInfo; 26 import android.security.keystore.KeyProperties; 27 import android.system.keystore2.Authorization; 28 29 import java.math.BigInteger; 30 import java.security.InvalidKeyException; 31 import java.security.ProviderException; 32 import java.security.spec.InvalidKeySpecException; 33 import java.security.spec.KeySpec; 34 import java.util.ArrayList; 35 import java.util.Date; 36 import java.util.List; 37 38 import javax.crypto.SecretKey; 39 import javax.crypto.SecretKeyFactorySpi; 40 import javax.crypto.spec.SecretKeySpec; 41 42 /** 43 * {@link SecretKeyFactorySpi} backed by Android Keystore. 44 * 45 * @hide 46 */ 47 public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { 48 49 private final KeyStore mKeyStore = KeyStore.getInstance(); 50 51 @Override engineGetKeySpec(SecretKey key, @SuppressWarnings(R) Class keySpecClass)52 protected KeySpec engineGetKeySpec(SecretKey key, 53 @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException { 54 if (keySpecClass == null) { 55 throw new InvalidKeySpecException("keySpecClass == null"); 56 } 57 if (!(key instanceof AndroidKeyStoreSecretKey)) { 58 throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " + 59 ((key != null) ? key.getClass().getName() : "null")); 60 } 61 if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) { 62 throw new InvalidKeySpecException( 63 "Key material export of Android KeyStore keys is not supported"); 64 } 65 if (!KeyInfo.class.equals(keySpecClass)) { 66 throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName()); 67 } 68 AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key; 69 70 return getKeyInfo(keystoreKey); 71 } 72 getKeyInfo(@onNull AndroidKeyStoreKey key)73 static @NonNull KeyInfo getKeyInfo(@NonNull AndroidKeyStoreKey key) { 74 75 @KeyProperties.SecurityLevelEnum int securityLevel = 76 KeyProperties.SECURITY_LEVEL_SOFTWARE; 77 boolean insideSecureHardware = false; 78 @KeyProperties.OriginEnum int origin = -1; 79 int keySize = -1; 80 @KeyProperties.PurposeEnum int purposes = 0; 81 String[] encryptionPaddings; 82 String[] signaturePaddings; 83 List<String> digestsList = new ArrayList<>(); 84 List<String> blockModesList = new ArrayList<>(); 85 int keymasterSwEnforcedUserAuthenticators = 0; 86 int keymasterHwEnforcedUserAuthenticators = 0; 87 List<BigInteger> keymasterSecureUserIds = new ArrayList<BigInteger>(); 88 List<String> encryptionPaddingsList = new ArrayList<String>(); 89 List<String> signaturePaddingsList = new ArrayList<String>(); 90 Date keyValidityStart = null; 91 Date keyValidityForOriginationEnd = null; 92 Date keyValidityForConsumptionEnd = null; 93 long userAuthenticationValidityDurationSeconds = 0; 94 boolean userAuthenticationRequired = true; 95 boolean userAuthenticationValidWhileOnBody = false; 96 boolean trustedUserPresenceRequired = false; 97 boolean trustedUserConfirmationRequired = false; 98 int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT; 99 try { 100 for (Authorization a : key.getAuthorizations()) { 101 switch (a.keyParameter.tag) { 102 case KeymasterDefs.KM_TAG_ORIGIN: 103 insideSecureHardware = 104 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel); 105 securityLevel = a.securityLevel; 106 origin = KeyProperties.Origin.fromKeymaster( 107 a.keyParameter.value.getOrigin()); 108 break; 109 case KeymasterDefs.KM_TAG_KEY_SIZE: 110 long keySizeUnsigned = KeyStore2ParameterUtils.getUnsignedInt(a); 111 if (keySizeUnsigned > Integer.MAX_VALUE) { 112 throw new ProviderException( 113 "Key too large: " + keySizeUnsigned + " bits"); 114 } 115 keySize = (int) keySizeUnsigned; 116 break; 117 case KeymasterDefs.KM_TAG_PURPOSE: 118 purposes |= KeyProperties.Purpose.fromKeymaster( 119 a.keyParameter.value.getKeyPurpose()); 120 break; 121 case KeymasterDefs.KM_TAG_PADDING: 122 int paddingMode = a.keyParameter.value.getPaddingMode(); 123 try { 124 if (paddingMode == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN 125 || paddingMode == KeymasterDefs.KM_PAD_RSA_PSS) { 126 @KeyProperties.SignaturePaddingEnum String padding = 127 KeyProperties.SignaturePadding.fromKeymaster( 128 paddingMode); 129 signaturePaddingsList.add(padding); 130 } else { 131 @KeyProperties.EncryptionPaddingEnum String jcaPadding = 132 KeyProperties.EncryptionPadding.fromKeymaster( 133 paddingMode); 134 encryptionPaddingsList.add(jcaPadding); 135 } 136 } catch (IllegalArgumentException e) { 137 throw new ProviderException("Unsupported padding: " 138 + paddingMode); 139 } 140 break; 141 case KeymasterDefs.KM_TAG_DIGEST: 142 digestsList.add(KeyProperties.Digest.fromKeymaster( 143 a.keyParameter.value.getDigest())); 144 break; 145 case KeymasterDefs.KM_TAG_BLOCK_MODE: 146 blockModesList.add( 147 KeyProperties.BlockMode.fromKeymaster( 148 a.keyParameter.value.getBlockMode()) 149 ); 150 break; 151 case KeymasterDefs.KM_TAG_USER_AUTH_TYPE: 152 int authenticatorType = a.keyParameter.value.getHardwareAuthenticatorType(); 153 if (KeyStore2ParameterUtils.isSecureHardware(a.securityLevel)) { 154 keymasterHwEnforcedUserAuthenticators = authenticatorType; 155 } else { 156 keymasterSwEnforcedUserAuthenticators = authenticatorType; 157 } 158 break; 159 case KeymasterDefs.KM_TAG_USER_SECURE_ID: 160 keymasterSecureUserIds.add( 161 KeymasterArguments.toUint64( 162 a.keyParameter.value.getLongInteger())); 163 break; 164 case KeymasterDefs.KM_TAG_ACTIVE_DATETIME: 165 keyValidityStart = KeyStore2ParameterUtils.getDate(a); 166 break; 167 case KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME: 168 keyValidityForOriginationEnd = 169 KeyStore2ParameterUtils.getDate(a); 170 break; 171 case KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME: 172 keyValidityForConsumptionEnd = 173 KeyStore2ParameterUtils.getDate(a); 174 break; 175 case KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED: 176 userAuthenticationRequired = false; 177 break; 178 case KeymasterDefs.KM_TAG_AUTH_TIMEOUT: 179 userAuthenticationValidityDurationSeconds = 180 KeyStore2ParameterUtils.getUnsignedInt(a); 181 if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) { 182 throw new ProviderException( 183 "User authentication timeout validity too long: " 184 + userAuthenticationValidityDurationSeconds + " seconds"); 185 } 186 break; 187 case KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY: 188 userAuthenticationValidWhileOnBody = 189 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel); 190 break; 191 case KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED: 192 trustedUserPresenceRequired = 193 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel); 194 break; 195 case KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED: 196 trustedUserConfirmationRequired = 197 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel); 198 break; 199 case KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT: 200 long remainingUsageCountUnsigned = 201 KeyStore2ParameterUtils.getUnsignedInt(a); 202 if (remainingUsageCountUnsigned > Integer.MAX_VALUE) { 203 throw new ProviderException( 204 "Usage count of limited use key too long: " 205 + remainingUsageCountUnsigned); 206 } 207 remainingUsageCount = (int) remainingUsageCountUnsigned; 208 break; 209 } 210 } 211 } catch (IllegalArgumentException e) { 212 throw new ProviderException("Unsupported key characteristic", e); 213 } 214 if (keySize == -1) { 215 throw new ProviderException("Key size not available"); 216 } 217 if (origin == -1) { 218 throw new ProviderException("Key origin not available"); 219 } 220 221 encryptionPaddings = 222 encryptionPaddingsList.toArray(new String[0]); 223 signaturePaddings = 224 signaturePaddingsList.toArray(new String[0]); 225 226 boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired) 227 && (keymasterHwEnforcedUserAuthenticators != 0) 228 && (keymasterSwEnforcedUserAuthenticators == 0); 229 230 String[] digests = digestsList.toArray(new String[0]); 231 String[] blockModes = blockModesList.toArray(new String[0]); 232 233 boolean invalidatedByBiometricEnrollment = false; 234 if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC 235 || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC) { 236 // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list. 237 invalidatedByBiometricEnrollment = !keymasterSecureUserIds.isEmpty() 238 && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId()); 239 } 240 241 return new KeyInfo(key.getUserKeyDescriptor().alias, 242 insideSecureHardware, 243 origin, 244 keySize, 245 keyValidityStart, 246 keyValidityForOriginationEnd, 247 keyValidityForConsumptionEnd, 248 purposes, 249 encryptionPaddings, 250 signaturePaddings, 251 digests, 252 blockModes, 253 userAuthenticationRequired, 254 (int) userAuthenticationValidityDurationSeconds, 255 userAuthenticationRequirementEnforcedBySecureHardware 256 ? keymasterHwEnforcedUserAuthenticators 257 : keymasterSwEnforcedUserAuthenticators, 258 userAuthenticationRequirementEnforcedBySecureHardware, 259 userAuthenticationValidWhileOnBody, 260 trustedUserPresenceRequired, 261 invalidatedByBiometricEnrollment, 262 trustedUserConfirmationRequired, 263 securityLevel, 264 remainingUsageCount); 265 } 266 getGateKeeperSecureUserId()267 private static BigInteger getGateKeeperSecureUserId() throws ProviderException { 268 try { 269 return BigInteger.valueOf(GateKeeper.getSecureUserId()); 270 } catch (IllegalStateException e) { 271 throw new ProviderException("Failed to get GateKeeper secure user ID", e); 272 } 273 } 274 275 @Override engineGenerateSecret(KeySpec keySpec)276 protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException { 277 throw new InvalidKeySpecException( 278 "To generate secret key in Android Keystore, use KeyGenerator initialized with " 279 + KeyGenParameterSpec.class.getName()); 280 } 281 282 @Override engineTranslateKey(SecretKey key)283 protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException { 284 if (key == null) { 285 throw new InvalidKeyException("key == null"); 286 } else if (!(key instanceof AndroidKeyStoreSecretKey)) { 287 throw new InvalidKeyException( 288 "To import a secret key into Android Keystore, use KeyStore.setEntry"); 289 } 290 291 return key; 292 } 293 } 294