Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2013 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 org.conscrypt;
     18 
     19 import java.math.BigInteger;
     20 import java.security.InvalidKeyException;
     21 import java.security.Key;
     22 import java.security.KeyFactorySpi;
     23 import java.security.PrivateKey;
     24 import java.security.PublicKey;
     25 import java.security.interfaces.ECPrivateKey;
     26 import java.security.interfaces.ECPublicKey;
     27 import java.security.spec.ECParameterSpec;
     28 import java.security.spec.ECPoint;
     29 import java.security.spec.ECPrivateKeySpec;
     30 import java.security.spec.ECPublicKeySpec;
     31 import java.security.spec.InvalidKeySpecException;
     32 import java.security.spec.KeySpec;
     33 import java.security.spec.PKCS8EncodedKeySpec;
     34 import java.security.spec.X509EncodedKeySpec;
     35 
     36 public class OpenSSLECKeyFactory extends KeyFactorySpi {
     37 
     38     @Override
     39     protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
     40         if (keySpec == null) {
     41             throw new InvalidKeySpecException("keySpec == null");
     42         }
     43 
     44         if (keySpec instanceof ECPublicKeySpec) {
     45             return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
     46         } else if (keySpec instanceof X509EncodedKeySpec) {
     47             return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_EC);
     48         }
     49         throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
     50                 + keySpec.getClass().getName());
     51     }
     52 
     53     @Override
     54     protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
     55         if (keySpec == null) {
     56             throw new InvalidKeySpecException("keySpec == null");
     57         }
     58 
     59         if (keySpec instanceof ECPrivateKeySpec) {
     60             return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec);
     61         } else if (keySpec instanceof PKCS8EncodedKeySpec) {
     62             return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
     63                     NativeCrypto.EVP_PKEY_EC);
     64         }
     65         throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was "
     66                 + keySpec.getClass().getName());
     67     }
     68 
     69     @Override
     70     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
     71             throws InvalidKeySpecException {
     72         if (key == null) {
     73             throw new InvalidKeySpecException("key == null");
     74         }
     75 
     76         if (keySpec == null) {
     77             throw new InvalidKeySpecException("keySpec == null");
     78         }
     79 
     80         if (!"EC".equals(key.getAlgorithm())) {
     81             throw new InvalidKeySpecException("Key must be an EC key");
     82         }
     83 
     84         if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
     85             ECPublicKey ecKey = (ECPublicKey) key;
     86             return (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
     87         } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
     88             final byte[] encoded = key.getEncoded();
     89             if (!"X.509".equals(key.getFormat()) || encoded == null) {
     90                 throw new InvalidKeySpecException("Not a valid X.509 encoding");
     91             }
     92             ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
     93             return (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
     94         } else if (key instanceof ECPrivateKey
     95                 && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
     96             ECPrivateKey ecKey = (ECPrivateKey) key;
     97             return (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
     98         } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
     99             final byte[] encoded = key.getEncoded();
    100             if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
    101                 throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
    102             }
    103             ECPrivateKey ecKey =
    104                     (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
    105             return (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
    106         } else if (key instanceof PrivateKey
    107                 && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
    108             final byte[] encoded = key.getEncoded();
    109             if (!"PKCS#8".equals(key.getFormat())) {
    110                 throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
    111                         + key.getFormat());
    112             } else if (encoded == null) {
    113                 throw new InvalidKeySpecException("Key is not encodable");
    114             }
    115             return (T) new PKCS8EncodedKeySpec(encoded);
    116         } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
    117             final byte[] encoded = key.getEncoded();
    118             if (!"X.509".equals(key.getFormat())) {
    119                 throw new InvalidKeySpecException("Encoding type must be X.509; was "
    120                         + key.getFormat());
    121             } else if (encoded == null) {
    122                 throw new InvalidKeySpecException("Key is not encodable");
    123             }
    124             return (T) new X509EncodedKeySpec(encoded);
    125         } else {
    126             throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
    127                     + key.getClass().getName() + ", keySpec=" + keySpec.getName());
    128         }
    129     }
    130 
    131     @Override
    132     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
    133         if (key == null) {
    134             throw new InvalidKeyException("key == null");
    135         }
    136         if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) {
    137             return key;
    138         } else if (key instanceof ECPublicKey) {
    139             ECPublicKey ecKey = (ECPublicKey) key;
    140 
    141             ECPoint w = ecKey.getW();
    142 
    143             ECParameterSpec params = ecKey.getParams();
    144 
    145             try {
    146                 return engineGeneratePublic(new ECPublicKeySpec(w, params));
    147             } catch (InvalidKeySpecException e) {
    148                 throw new InvalidKeyException(e);
    149             }
    150         } else if (key instanceof ECPrivateKey) {
    151             ECPrivateKey ecKey = (ECPrivateKey) key;
    152 
    153             BigInteger s = ecKey.getS();
    154 
    155             ECParameterSpec params = ecKey.getParams();
    156 
    157             try {
    158                 return engineGeneratePrivate(new ECPrivateKeySpec(s, params));
    159             } catch (InvalidKeySpecException e) {
    160                 throw new InvalidKeyException(e);
    161             }
    162         } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
    163             byte[] encoded = key.getEncoded();
    164             if (encoded == null) {
    165                 throw new InvalidKeyException("Key does not support encoding");
    166             }
    167             try {
    168                 return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
    169             } catch (InvalidKeySpecException e) {
    170                 throw new InvalidKeyException(e);
    171             }
    172         } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
    173             byte[] encoded = key.getEncoded();
    174             if (encoded == null) {
    175                 throw new InvalidKeyException("Key does not support encoding");
    176             }
    177             try {
    178                 return engineGeneratePublic(new X509EncodedKeySpec(encoded));
    179             } catch (InvalidKeySpecException e) {
    180                 throw new InvalidKeyException(e);
    181             }
    182         } else {
    183             throw new InvalidKeyException("Key must be EC public or private key; was "
    184                     + key.getClass().getName());
    185         }
    186     }
    187 
    188 }
    189