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