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.security.KeyStore; 20 import android.security.keystore.KeyGenParameterSpec; 21 import android.security.keystore.KeyInfo; 22 23 import java.security.InvalidKeyException; 24 import java.security.Key; 25 import java.security.KeyFactorySpi; 26 import java.security.PrivateKey; 27 import java.security.PublicKey; 28 import java.security.spec.ECPublicKeySpec; 29 import java.security.spec.InvalidKeySpecException; 30 import java.security.spec.KeySpec; 31 import java.security.spec.PKCS8EncodedKeySpec; 32 import java.security.spec.RSAPublicKeySpec; 33 import java.security.spec.X509EncodedKeySpec; 34 35 /** 36 * {@link KeyFactorySpi} backed by Android KeyStore. 37 * 38 * @hide 39 */ 40 public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi { 41 42 private final KeyStore mKeyStore = KeyStore.getInstance(); 43 44 @Override engineGetKeySpec(Key key, Class<T> keySpecClass)45 protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpecClass) 46 throws InvalidKeySpecException { 47 if (key == null) { 48 throw new InvalidKeySpecException("key == null"); 49 } else if ((!(key instanceof AndroidKeyStorePrivateKey)) 50 && (!(key instanceof AndroidKeyStorePublicKey))) { 51 throw new InvalidKeySpecException( 52 "Unsupported key type: " + key.getClass().getName() 53 + ". This KeyFactory supports only Android Keystore asymmetric keys"); 54 } 55 56 // key is an Android Keystore private or public key 57 58 if (keySpecClass == null) { 59 throw new InvalidKeySpecException("keySpecClass == null"); 60 } else if (KeyInfo.class.equals(keySpecClass)) { 61 if (!(key instanceof AndroidKeyStorePrivateKey)) { 62 throw new InvalidKeySpecException( 63 "Unsupported key type: " + key.getClass().getName() 64 + ". KeyInfo can be obtained only for Android Keystore private keys"); 65 } 66 AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key; 67 @SuppressWarnings("unchecked") 68 T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(keystorePrivateKey); 69 return result; 70 } else if (X509EncodedKeySpec.class.equals(keySpecClass)) { 71 if (!(key instanceof AndroidKeyStorePublicKey)) { 72 throw new InvalidKeySpecException( 73 "Unsupported key type: " + key.getClass().getName() 74 + ". X509EncodedKeySpec can be obtained only for Android Keystore public" 75 + " keys"); 76 } 77 @SuppressWarnings("unchecked") 78 T result = (T) new X509EncodedKeySpec(((AndroidKeyStorePublicKey) key).getEncoded()); 79 return result; 80 } else if (PKCS8EncodedKeySpec.class.equals(keySpecClass)) { 81 if (key instanceof AndroidKeyStorePrivateKey) { 82 throw new InvalidKeySpecException( 83 "Key material export of Android Keystore private keys is not supported"); 84 } else { 85 throw new InvalidKeySpecException( 86 "Cannot export key material of public key in PKCS#8 format." 87 + " Only X.509 format (X509EncodedKeySpec) supported for public keys."); 88 } 89 } else if (RSAPublicKeySpec.class.equals(keySpecClass)) { 90 if (key instanceof AndroidKeyStoreRSAPublicKey) { 91 AndroidKeyStoreRSAPublicKey rsaKey = (AndroidKeyStoreRSAPublicKey) key; 92 @SuppressWarnings("unchecked") 93 T result = 94 (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent()); 95 return result; 96 } else { 97 throw new InvalidKeySpecException( 98 "Obtaining RSAPublicKeySpec not supported for " + key.getAlgorithm() + " " 99 + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public") 100 + " key"); 101 } 102 } else if (ECPublicKeySpec.class.equals(keySpecClass)) { 103 if (key instanceof AndroidKeyStoreECPublicKey) { 104 AndroidKeyStoreECPublicKey ecKey = (AndroidKeyStoreECPublicKey) key; 105 @SuppressWarnings("unchecked") 106 T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams()); 107 return result; 108 } else { 109 throw new InvalidKeySpecException( 110 "Obtaining ECPublicKeySpec not supported for " + key.getAlgorithm() + " " 111 + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public") 112 + " key"); 113 } 114 } else { 115 throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName()); 116 } 117 } 118 119 @Override engineGeneratePrivate(KeySpec spec)120 protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException { 121 throw new InvalidKeySpecException( 122 "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with" 123 + " " + KeyGenParameterSpec.class.getName()); 124 } 125 126 @Override engineGeneratePublic(KeySpec spec)127 protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException { 128 throw new InvalidKeySpecException( 129 "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with" 130 + " " + KeyGenParameterSpec.class.getName()); 131 } 132 133 @Override engineTranslateKey(Key key)134 protected Key engineTranslateKey(Key key) throws InvalidKeyException { 135 if (key == null) { 136 throw new InvalidKeyException("key == null"); 137 } else if ((!(key instanceof AndroidKeyStorePrivateKey)) 138 && (!(key instanceof AndroidKeyStorePublicKey))) { 139 throw new InvalidKeyException( 140 "To import a key into Android Keystore, use KeyStore.setEntry"); 141 } 142 return key; 143 } 144 } 145