1 /* 2 * Copyright (C) 2012 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.KeyStore2; 21 import android.security.KeyStoreSecurityLevel; 22 import android.security.keymaster.KeymasterDefs; 23 import android.security.keystore.KeyPermanentlyInvalidatedException; 24 import android.security.keystore.KeyProperties; 25 import android.security.keystore.KeyStoreCryptoOperation; 26 import android.system.keystore2.Authorization; 27 import android.system.keystore2.Domain; 28 import android.system.keystore2.KeyDescriptor; 29 import android.system.keystore2.KeyEntryResponse; 30 import android.system.keystore2.KeyMetadata; 31 import android.system.keystore2.ResponseCode; 32 33 import java.security.KeyPair; 34 import java.security.Provider; 35 import java.security.ProviderException; 36 import java.security.PublicKey; 37 import java.security.Security; 38 import java.security.Signature; 39 import java.security.UnrecoverableKeyException; 40 import java.security.cert.X509Certificate; 41 import java.security.interfaces.ECPublicKey; 42 import java.security.interfaces.RSAPublicKey; 43 44 import javax.crypto.Cipher; 45 import javax.crypto.KeyAgreement; 46 import javax.crypto.Mac; 47 import javax.crypto.SecretKey; 48 49 /** 50 * A provider focused on providing JCA interfaces for the Android KeyStore. 51 * 52 * @hide 53 */ 54 public class AndroidKeyStoreProvider extends Provider { 55 private static final String PROVIDER_NAME = "AndroidKeyStore"; 56 57 // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these 58 // classes when this provider is instantiated and installed early on during each app's 59 // initialization process. 60 // 61 // Crypto operations operating on the AndroidKeyStore keys must not be offered by this provider. 62 // Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc 63 // for details. 64 65 private static final String PACKAGE_NAME = "android.security.keystore2"; 66 67 private static final String DESEDE_SYSTEM_PROPERTY = 68 "ro.hardware.keystore_desede"; 69 70 // Conscrypt returns the Ed25519 OID as the JCA key algorithm. 71 private static final String ED25519_OID = "1.3.101.112"; 72 // Conscrypt returns "XDH" as the X25519 JCA key algorithm. 73 private static final String X25519_ALIAS = "XDH"; 74 75 /** @hide **/ AndroidKeyStoreProvider()76 public AndroidKeyStoreProvider() { 77 super(PROVIDER_NAME, 1.0, "Android KeyStore security provider"); 78 79 boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY)); 80 81 // java.security.KeyStore 82 put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi"); 83 84 // java.security.KeyPairGenerator 85 put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC"); 86 put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); 87 put("KeyPairGenerator.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$XDH"); 88 put("KeyPairGenerator.ED25519", PACKAGE_NAME 89 + ".AndroidKeyStoreKeyPairGeneratorSpi$ED25519"); 90 91 // java.security.KeyFactory 92 putKeyFactoryImpl("EC"); 93 putKeyFactoryImpl("RSA"); 94 putKeyFactoryImpl("XDH"); 95 putKeyFactoryImpl("ED25519"); 96 97 // javax.crypto.KeyGenerator 98 put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES"); 99 put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1"); 100 put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224"); 101 put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256"); 102 put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA384"); 103 put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA512"); 104 105 if (supports3DES) { 106 put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede"); 107 } 108 109 // javax.crypto.KeyAgreement 110 put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH"); 111 put("KeyAgreement.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$XDH"); 112 113 // java.security.SecretKeyFactory 114 putSecretKeyFactoryImpl("AES"); 115 if (supports3DES) { 116 putSecretKeyFactoryImpl("DESede"); 117 } 118 putSecretKeyFactoryImpl("HmacSHA1"); 119 putSecretKeyFactoryImpl("HmacSHA224"); 120 putSecretKeyFactoryImpl("HmacSHA256"); 121 putSecretKeyFactoryImpl("HmacSHA384"); 122 putSecretKeyFactoryImpl("HmacSHA512"); 123 } 124 125 /** 126 * Installs a new instance of this provider (and the 127 * {@link AndroidKeyStoreBCWorkaroundProvider}). 128 * @hide 129 */ install()130 public static void install() { 131 Provider[] providers = Security.getProviders(); 132 int bcProviderIndex = -1; 133 for (int i = 0; i < providers.length; i++) { 134 Provider provider = providers[i]; 135 if ("BC".equals(provider.getName())) { 136 bcProviderIndex = i; 137 break; 138 } 139 } 140 141 Security.addProvider(new AndroidKeyStoreProvider()); 142 Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider(); 143 if (bcProviderIndex != -1) { 144 // Bouncy Castle provider found -- install the workaround provider above it. 145 // insertProviderAt uses 1-based positions. 146 Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1); 147 } else { 148 // Bouncy Castle provider not found -- install the workaround provider at lowest 149 // priority. 150 Security.addProvider(workaroundProvider); 151 } 152 } 153 putSecretKeyFactoryImpl(String algorithm)154 private void putSecretKeyFactoryImpl(String algorithm) { 155 put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreSecretKeyFactorySpi"); 156 } 157 putKeyFactoryImpl(String algorithm)158 private void putKeyFactoryImpl(String algorithm) { 159 put("KeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreKeyFactorySpi"); 160 } 161 162 /** 163 * Gets the Android KeyStore operation handle corresponding to the provided JCA crypto 164 * primitive. 165 * 166 * <p>The following primitives are supported: {@link Cipher}, {@link Signature} and {@link Mac}. 167 * 168 * @return Android KeyStore operation handle or {@code 0} if the provided primitive's Android 169 * KeyStore operation is not in progress. 170 * 171 * @throws IllegalArgumentException if the provided primitive is not supported or is not backed 172 * by AndroidKeyStore provider. 173 * @throws IllegalStateException if the provided primitive is not initialized. 174 * @hide 175 */ getKeyStoreOperationHandle(Object cryptoPrimitive)176 public static long getKeyStoreOperationHandle(Object cryptoPrimitive) { 177 if (cryptoPrimitive == null) { 178 throw new NullPointerException(); 179 } 180 Object spi; 181 if (cryptoPrimitive instanceof Signature) { 182 spi = ((Signature) cryptoPrimitive).getCurrentSpi(); 183 } else if (cryptoPrimitive instanceof Mac) { 184 spi = ((Mac) cryptoPrimitive).getCurrentSpi(); 185 } else if (cryptoPrimitive instanceof Cipher) { 186 spi = ((Cipher) cryptoPrimitive).getCurrentSpi(); 187 } else if (cryptoPrimitive instanceof KeyAgreement) { 188 spi = ((KeyAgreement) cryptoPrimitive).getCurrentSpi(); 189 } else { 190 throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive 191 + ". Supported: Signature, Mac, Cipher"); 192 } 193 if (spi == null) { 194 throw new IllegalStateException("Crypto primitive not initialized"); 195 } else if (!(spi instanceof KeyStoreCryptoOperation)) { 196 throw new IllegalArgumentException( 197 "Crypto primitive not backed by AndroidKeyStore provider: " + cryptoPrimitive 198 + ", spi: " + spi); 199 } 200 return ((KeyStoreCryptoOperation) spi).getOperationHandle(); 201 } 202 203 /** 204 * This helper function gets called if the key loaded from the keystore daemon 205 * is for an asymmetric algorithm. It constructs an instance of {@link AndroidKeyStorePublicKey} 206 * which implements {@link PublicKey}. 207 * 208 * @param descriptor The original key descriptor that was used to load the key. 209 * 210 * @param metadata The key metadata which includes the public key material, a reference to the 211 * stored private key material, the key characteristics. 212 * @param iSecurityLevel A binder interface that allows using the private key. 213 * @param algorithm Must indicate EC or RSA. 214 * @return AndroidKeyStorePublicKey 215 * @throws UnrecoverableKeyException 216 * @hide 217 */ 218 @NonNull makeAndroidKeyStorePublicKeyFromKeyEntryResponse( @onNull KeyDescriptor descriptor, @NonNull KeyMetadata metadata, @NonNull KeyStoreSecurityLevel iSecurityLevel, int algorithm)219 static AndroidKeyStorePublicKey makeAndroidKeyStorePublicKeyFromKeyEntryResponse( 220 @NonNull KeyDescriptor descriptor, 221 @NonNull KeyMetadata metadata, 222 @NonNull KeyStoreSecurityLevel iSecurityLevel, int algorithm) 223 throws UnrecoverableKeyException { 224 if (metadata.certificate == null) { 225 throw new UnrecoverableKeyException("Failed to obtain X.509 form of public key." 226 + " Keystore has no public certificate stored."); 227 } 228 final byte[] x509PublicCert = metadata.certificate; 229 230 final X509Certificate parsedX509Certificate = 231 AndroidKeyStoreSpi.toCertificate(x509PublicCert); 232 if (parsedX509Certificate == null) { 233 throw new UnrecoverableKeyException("Failed to parse the X.509 certificate containing" 234 + " the public key. This likely indicates a hardware problem."); 235 } 236 237 PublicKey publicKey = parsedX509Certificate.getPublicKey(); 238 239 String jcaKeyAlgorithm = publicKey.getAlgorithm(); 240 241 if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) { 242 return new AndroidKeyStoreECPublicKey(descriptor, metadata, 243 iSecurityLevel, (ECPublicKey) publicKey); 244 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(jcaKeyAlgorithm)) { 245 return new AndroidKeyStoreRSAPublicKey(descriptor, metadata, 246 iSecurityLevel, (RSAPublicKey) publicKey); 247 } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) { 248 final byte[] publicKeyEncoded = publicKey.getEncoded(); 249 return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID, 250 iSecurityLevel, publicKeyEncoded); 251 } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) { 252 return new AndroidKeyStoreXDHPublicKey(descriptor, metadata, X25519_ALIAS, 253 iSecurityLevel, publicKey.getEncoded()); 254 } else { 255 throw new ProviderException("Unsupported Android Keystore public key algorithm: " 256 + jcaKeyAlgorithm); 257 } 258 } 259 260 /** @hide **/ 261 @NonNull loadAndroidKeyStorePublicKeyFromKeystore( @onNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace)262 public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore( 263 @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace) 264 throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { 265 AndroidKeyStoreKey key = 266 loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace); 267 if (key instanceof AndroidKeyStorePublicKey) { 268 return (AndroidKeyStorePublicKey) key; 269 } else { 270 throw new UnrecoverableKeyException("No asymmetric key found by the given alias."); 271 } 272 } 273 274 /** @hide **/ 275 @NonNull loadAndroidKeyStoreKeyPairFromKeystore( @onNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)276 public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore( 277 @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) 278 throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { 279 AndroidKeyStoreKey key = 280 loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); 281 if (key instanceof AndroidKeyStorePublicKey) { 282 AndroidKeyStorePublicKey publicKey = (AndroidKeyStorePublicKey) key; 283 return new KeyPair(publicKey, publicKey.getPrivateKey()); 284 } else { 285 throw new UnrecoverableKeyException("No asymmetric key found by the given alias."); 286 } 287 } 288 289 /** @hide **/ 290 @NonNull loadAndroidKeyStorePrivateKeyFromKeystore( @onNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace)291 public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore( 292 @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace) 293 throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { 294 AndroidKeyStoreKey key = 295 loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace); 296 if (key instanceof AndroidKeyStorePublicKey) { 297 return ((AndroidKeyStorePublicKey) key).getPrivateKey(); 298 } else { 299 throw new UnrecoverableKeyException("No asymmetric key found by the given alias."); 300 } 301 } 302 303 /** @hide **/ 304 @NonNull loadAndroidKeyStoreSecretKeyFromKeystore( @onNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)305 public static SecretKey loadAndroidKeyStoreSecretKeyFromKeystore( 306 @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) 307 throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { 308 309 AndroidKeyStoreKey key = 310 loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); 311 if (key instanceof SecretKey) { 312 return (SecretKey) key; 313 } else { 314 throw new UnrecoverableKeyException("No secret key found by the given alias."); 315 } 316 } 317 318 @NonNull makeAndroidKeyStoreSecretKeyFromKeyEntryResponse( @onNull KeyDescriptor descriptor, @NonNull KeyEntryResponse response, int algorithm, int digest)319 private static AndroidKeyStoreSecretKey makeAndroidKeyStoreSecretKeyFromKeyEntryResponse( 320 @NonNull KeyDescriptor descriptor, 321 @NonNull KeyEntryResponse response, int algorithm, int digest) 322 throws UnrecoverableKeyException { 323 @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString; 324 try { 325 keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( 326 algorithm, digest); 327 } catch (IllegalArgumentException e) { 328 throw (UnrecoverableKeyException) 329 new UnrecoverableKeyException("Unsupported secret key type").initCause(e); 330 } 331 332 return new AndroidKeyStoreSecretKey(descriptor, 333 response.metadata, keyAlgorithmString, 334 new KeyStoreSecurityLevel(response.iSecurityLevel)); 335 } 336 337 /** 338 * Loads an an AndroidKeyStoreKey from the AndroidKeyStore backend. 339 * 340 * @param keyStore The keystore2 backend. 341 * @param alias The alias of the key in the Keystore database. 342 * @param namespace The a Keystore namespace. This is used by system api only to request 343 * Android system specific keystore namespace, which can be configured 344 * in the device's SEPolicy. Third party apps and most system components 345 * set this parameter to -1 to indicate their application specific namespace. 346 * See <a href="https://source.android.com/security/keystore#access-control"> 347 * Keystore 2.0 access control</a> 348 * @hide 349 **/ 350 @NonNull loadAndroidKeyStoreKeyFromKeystore( @onNull KeyStore2 keyStore, @NonNull String alias, int namespace)351 public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( 352 @NonNull KeyStore2 keyStore, @NonNull String alias, int namespace) 353 throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { 354 KeyDescriptor descriptor = new KeyDescriptor(); 355 if (namespace == KeyProperties.NAMESPACE_APPLICATION) { 356 descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored; 357 descriptor.domain = Domain.APP; 358 } else { 359 descriptor.nspace = namespace; 360 descriptor.domain = Domain.SELINUX; 361 } 362 descriptor.alias = alias; 363 descriptor.blob = null; 364 365 final AndroidKeyStoreKey key = loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); 366 if (key instanceof AndroidKeyStorePublicKey) { 367 return ((AndroidKeyStorePublicKey) key).getPrivateKey(); 368 } else { 369 return key; 370 } 371 } 372 loadAndroidKeyStoreKeyFromKeystore( @onNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)373 private static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( 374 @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) 375 throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { 376 KeyEntryResponse response = null; 377 try { 378 response = keyStore.getKeyEntry(descriptor); 379 } catch (android.security.KeyStoreException e) { 380 switch (e.getErrorCode()) { 381 case ResponseCode.KEY_NOT_FOUND: 382 return null; 383 case ResponseCode.KEY_PERMANENTLY_INVALIDATED: 384 throw new KeyPermanentlyInvalidatedException( 385 "User changed or deleted their auth credentials", 386 e); 387 default: 388 throw (UnrecoverableKeyException) 389 new UnrecoverableKeyException("Failed to obtain information about key") 390 .initCause(e); 391 } 392 } 393 394 if (response.iSecurityLevel == null) { 395 // This seems to be a pure certificate entry, nothing to return here. 396 return null; 397 } 398 399 Integer keymasterAlgorithm = null; 400 // We just need one digest for the algorithm name 401 int keymasterDigest = -1; 402 for (Authorization a : response.metadata.authorizations) { 403 switch (a.keyParameter.tag) { 404 case KeymasterDefs.KM_TAG_ALGORITHM: 405 keymasterAlgorithm = a.keyParameter.value.getAlgorithm(); 406 break; 407 case KeymasterDefs.KM_TAG_DIGEST: 408 if (keymasterDigest == -1) keymasterDigest = a.keyParameter.value.getDigest(); 409 break; 410 } 411 } 412 if (keymasterAlgorithm == null) { 413 throw new UnrecoverableKeyException("Key algorithm unknown"); 414 } 415 416 if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC || 417 keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES || 418 keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) { 419 return makeAndroidKeyStoreSecretKeyFromKeyEntryResponse(descriptor, response, 420 keymasterAlgorithm, keymasterDigest); 421 } else if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA || 422 keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) { 423 return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata, 424 new KeyStoreSecurityLevel(response.iSecurityLevel), 425 keymasterAlgorithm); 426 } else { 427 throw new UnrecoverableKeyException("Key algorithm unknown"); 428 } 429 } 430 } 431