Home | History | Annotate | Download | only in keystore
      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
     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
    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
    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
    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