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