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.content.pm.PackageManager; 20 import android.hardware.face.FaceManager; 21 import android.hardware.fingerprint.FingerprintManager; 22 import android.security.GateKeeper; 23 import android.security.KeyStore; 24 import android.security.keymaster.KeymasterArguments; 25 import android.security.keymaster.KeymasterDefs; 26 27 import java.security.ProviderException; 28 import java.util.ArrayList; 29 import java.util.List; 30 31 /** 32 * @hide 33 */ 34 public abstract class KeymasterUtils { 35 KeymasterUtils()36 private KeymasterUtils() {} 37 getDigestOutputSizeBits(int keymasterDigest)38 public static int getDigestOutputSizeBits(int keymasterDigest) { 39 switch (keymasterDigest) { 40 case KeymasterDefs.KM_DIGEST_NONE: 41 return -1; 42 case KeymasterDefs.KM_DIGEST_MD5: 43 return 128; 44 case KeymasterDefs.KM_DIGEST_SHA1: 45 return 160; 46 case KeymasterDefs.KM_DIGEST_SHA_2_224: 47 return 224; 48 case KeymasterDefs.KM_DIGEST_SHA_2_256: 49 return 256; 50 case KeymasterDefs.KM_DIGEST_SHA_2_384: 51 return 384; 52 case KeymasterDefs.KM_DIGEST_SHA_2_512: 53 return 512; 54 default: 55 throw new IllegalArgumentException("Unknown digest: " + keymasterDigest); 56 } 57 } 58 isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto( int keymasterBlockMode)59 public static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto( 60 int keymasterBlockMode) { 61 switch (keymasterBlockMode) { 62 case KeymasterDefs.KM_MODE_ECB: 63 return false; 64 case KeymasterDefs.KM_MODE_CBC: 65 case KeymasterDefs.KM_MODE_CTR: 66 case KeymasterDefs.KM_MODE_GCM: 67 return true; 68 default: 69 throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode); 70 } 71 } 72 isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto( int keymasterPadding)73 public static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto( 74 int keymasterPadding) { 75 switch (keymasterPadding) { 76 case KeymasterDefs.KM_PAD_NONE: 77 return false; 78 case KeymasterDefs.KM_PAD_RSA_OAEP: 79 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT: 80 return true; 81 default: 82 throw new IllegalArgumentException( 83 "Unsupported asymmetric encryption padding scheme: " + keymasterPadding); 84 } 85 } 86 87 /** 88 * Adds keymaster arguments to express the key's authorization policy supported by user 89 * authentication. 90 * 91 * @param userAuthenticationRequired whether user authentication is required to authorize the 92 * use of the key. 93 * @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user 94 * authentication is valid as authorization for using the key or {@code -1} if every 95 * use of the key needs authorization. 96 * @param boundToSpecificSecureUserId if non-zero, specify which SID the key will be bound to, 97 * overriding the default logic in this method where the key is bound to either the root 98 * SID of the current user, or the fingerprint SID if explicit fingerprint authorization 99 * is requested. 100 * @param userConfirmationRequired whether user confirmation is required to authorize the use 101 * of the key. 102 * @throws IllegalStateException if user authentication is required but the system is in a wrong 103 * state (e.g., secure lock screen not set up) for generating or importing keys that 104 * require user authentication. 105 */ addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec)106 public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) { 107 108 if (spec.isUserConfirmationRequired()) { 109 args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED); 110 } 111 112 if (spec.isUserPresenceRequired()) { 113 args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED); 114 } 115 116 if (spec.isUnlockedDeviceRequired()) { 117 args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED); 118 } 119 120 if (!spec.isUserAuthenticationRequired()) { 121 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); 122 return; 123 } 124 125 if (spec.getUserAuthenticationValidityDurationSeconds() == -1) { 126 PackageManager pm = KeyStore.getApplicationContext().getPackageManager(); 127 // Every use of this key needs to be authorized by the user. This currently means 128 // fingerprint or face auth. 129 FingerprintManager fingerprintManager = null; 130 FaceManager faceManager = null; 131 132 if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 133 fingerprintManager = KeyStore.getApplicationContext() 134 .getSystemService(FingerprintManager.class); 135 } 136 if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { 137 faceManager = KeyStore.getApplicationContext().getSystemService(FaceManager.class); 138 } 139 140 // TODO: Restore USE_FINGERPRINT permission check in 141 // FingerprintManager.getAuthenticatorId once the ID is no longer needed here. 142 final long fingerprintOnlySid = 143 (fingerprintManager != null) ? fingerprintManager.getAuthenticatorId() : 0; 144 final long faceOnlySid = 145 (faceManager != null) ? faceManager.getAuthenticatorId() : 0; 146 147 if (fingerprintOnlySid == 0 && faceOnlySid == 0) { 148 throw new IllegalStateException( 149 "At least one biometric must be enrolled to create keys requiring user" 150 + " authentication for every use"); 151 } 152 153 List<Long> sids = new ArrayList<>(); 154 if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) { 155 sids.add(spec.getBoundToSpecificSecureUserId()); 156 } else if (spec.isInvalidatedByBiometricEnrollment()) { 157 // The biometric-only SIDs will change on biometric enrollment or removal of all 158 // enrolled templates, invalidating the key. 159 sids.add(fingerprintOnlySid); 160 sids.add(faceOnlySid); 161 } else { 162 // The root SID will *not* change on fingerprint enrollment, or removal of all 163 // enrolled fingerprints, allowing the key to remain valid. 164 sids.add(getRootSid()); 165 } 166 167 for (int i = 0; i < sids.size(); i++) { 168 args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, 169 KeymasterArguments.toUint64(sids.get(i))); 170 } 171 args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_BIOMETRIC); 172 173 if (spec.isUserAuthenticationValidWhileOnBody()) { 174 throw new ProviderException("Key validity extension while device is on-body is not " 175 + "supported for keys requiring fingerprint authentication"); 176 } 177 } else { 178 long sid; 179 if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) { 180 sid = spec.getBoundToSpecificSecureUserId(); 181 } else { 182 // The key is authorized for use for the specified amount of time after the user has 183 // authenticated. Whatever unlocks the secure lock screen should authorize this key. 184 sid = getRootSid(); 185 } 186 args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, 187 KeymasterArguments.toUint64(sid)); 188 args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 189 KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_BIOMETRIC); 190 args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, 191 spec.getUserAuthenticationValidityDurationSeconds()); 192 if (spec.isUserAuthenticationValidWhileOnBody()) { 193 args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY); 194 } 195 } 196 } 197 198 /** 199 * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for 200 * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC, 201 * AES-GCM). 202 */ addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args, int keymasterAlgorithm, int[] keymasterBlockModes, int[] keymasterDigests)203 public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args, 204 int keymasterAlgorithm, 205 int[] keymasterBlockModes, 206 int[] keymasterDigests) { 207 switch (keymasterAlgorithm) { 208 case KeymasterDefs.KM_ALGORITHM_AES: 209 if (com.android.internal.util.ArrayUtils.contains( 210 keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) { 211 // AES GCM key needs the minimum length of AEAD tag specified. 212 args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, 213 AndroidKeyStoreAuthenticatedAESCipherSpi.GCM 214 .MIN_SUPPORTED_TAG_LENGTH_BITS); 215 } 216 break; 217 case KeymasterDefs.KM_ALGORITHM_HMAC: 218 // HMAC key needs the minimum length of MAC set to the output size of the associated 219 // digest. This is because we do not offer a way to generate shorter MACs and 220 // don't offer a way to verify MACs (other than by generating them). 221 if (keymasterDigests.length != 1) { 222 throw new ProviderException( 223 "Unsupported number of authorized digests for HMAC key: " 224 + keymasterDigests.length 225 + ". Exactly one digest must be authorized"); 226 } 227 int keymasterDigest = keymasterDigests[0]; 228 int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest); 229 if (digestOutputSizeBits == -1) { 230 throw new ProviderException( 231 "HMAC key authorized for unsupported digest: " 232 + KeyProperties.Digest.fromKeymaster(keymasterDigest)); 233 } 234 args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits); 235 break; 236 } 237 } 238 getRootSid()239 private static long getRootSid() { 240 long rootSid = GateKeeper.getSecureUserId(); 241 if (rootSid == 0) { 242 throw new IllegalStateException("Secure lock screen must be enabled" 243 + " to create keys requiring user authentication"); 244 } 245 return rootSid; 246 } 247 } 248