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