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 /**
     37  * An implementation of a {@link KeyFactorySpi} for EC keys based on BoringSSL.
     38  *
     39  * @hide
     40  */
     41 @Internal
     42 public final class OpenSSLECKeyFactory extends KeyFactorySpi {
     43 
     44     @Override
     45     protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
     46         if (keySpec == null) {
     47             throw new InvalidKeySpecException("keySpec == null");
     48         }
     49 
     50         if (keySpec instanceof ECPublicKeySpec) {
     51             return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
     52         } else if (keySpec instanceof X509EncodedKeySpec) {
     53             return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_EC);
     54         }
     55         throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
     56                 + keySpec.getClass().getName());
     57     }
     58 
     59     @Override
     60     protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
     61         if (keySpec == null) {
     62             throw new InvalidKeySpecException("keySpec == null");
     63         }
     64 
     65         if (keySpec instanceof ECPrivateKeySpec) {
     66             return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec);
     67         } else if (keySpec instanceof PKCS8EncodedKeySpec) {
     68             return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
     69                     NativeConstants.EVP_PKEY_EC);
     70         }
     71         throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was "
     72                 + keySpec.getClass().getName());
     73     }
     74 
     75     @Override
     76     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
     77             throws InvalidKeySpecException {
     78         if (key == null) {
     79             throw new InvalidKeySpecException("key == null");
     80         }
     81 
     82         if (keySpec == null) {
     83             throw new InvalidKeySpecException("keySpec == null");
     84         }
     85 
     86         if (!"EC".equals(key.getAlgorithm())) {
     87             throw new InvalidKeySpecException("Key must be an EC key");
     88         }
     89 
     90         if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
     91             ECPublicKey ecKey = (ECPublicKey) key;
     92             @SuppressWarnings("unchecked")
     93             T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
     94             return result;
     95         } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
     96             final byte[] encoded = key.getEncoded();
     97             if (!"X.509".equals(key.getFormat()) || encoded == null) {
     98                 throw new InvalidKeySpecException("Not a valid X.509 encoding");
     99             }
    100             ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
    101             @SuppressWarnings("unchecked")
    102             T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
    103             return result;
    104         } else if (key instanceof ECPrivateKey
    105                 && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
    106             ECPrivateKey ecKey = (ECPrivateKey) key;
    107             @SuppressWarnings("unchecked")
    108             T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
    109             return result;
    110         } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
    111             final byte[] encoded = key.getEncoded();
    112             if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
    113                 throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
    114             }
    115             ECPrivateKey ecKey =
    116                     (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
    117             @SuppressWarnings("unchecked")
    118             T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
    119             return result;
    120         } else if (key instanceof PrivateKey
    121                 && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
    122             final byte[] encoded = key.getEncoded();
    123             if (!"PKCS#8".equals(key.getFormat())) {
    124                 throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
    125                         + key.getFormat());
    126             } else if (encoded == null) {
    127                 throw new InvalidKeySpecException("Key is not encodable");
    128             }
    129             @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded);
    130             return result;
    131         } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
    132             final byte[] encoded = key.getEncoded();
    133             if (!"X.509".equals(key.getFormat())) {
    134                 throw new InvalidKeySpecException("Encoding type must be X.509; was "
    135                         + key.getFormat());
    136             } else if (encoded == null) {
    137                 throw new InvalidKeySpecException("Key is not encodable");
    138             }
    139             @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded);
    140             return result;
    141         } else {
    142             throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
    143                     + key.getClass().getName() + ", keySpec=" + keySpec.getName());
    144         }
    145     }
    146 
    147     @Override
    148     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
    149         if (key == null) {
    150             throw new InvalidKeyException("key == null");
    151         }
    152         if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) {
    153             return key;
    154         } else if (key instanceof ECPublicKey) {
    155             ECPublicKey ecKey = (ECPublicKey) key;
    156 
    157             ECPoint w = ecKey.getW();
    158 
    159             ECParameterSpec params = ecKey.getParams();
    160 
    161             try {
    162                 return engineGeneratePublic(new ECPublicKeySpec(w, params));
    163             } catch (InvalidKeySpecException e) {
    164                 throw new InvalidKeyException(e);
    165             }
    166         } else if (key instanceof ECPrivateKey) {
    167             ECPrivateKey ecKey = (ECPrivateKey) key;
    168 
    169             BigInteger s = ecKey.getS();
    170 
    171             ECParameterSpec params = ecKey.getParams();
    172 
    173             try {
    174                 return engineGeneratePrivate(new ECPrivateKeySpec(s, params));
    175             } catch (InvalidKeySpecException e) {
    176                 throw new InvalidKeyException(e);
    177             }
    178         } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
    179             byte[] encoded = key.getEncoded();
    180             if (encoded == null) {
    181                 throw new InvalidKeyException("Key does not support encoding");
    182             }
    183             try {
    184                 return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
    185             } catch (InvalidKeySpecException e) {
    186                 throw new InvalidKeyException(e);
    187             }
    188         } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
    189             byte[] encoded = key.getEncoded();
    190             if (encoded == null) {
    191                 throw new InvalidKeyException("Key does not support encoding");
    192             }
    193             try {
    194                 return engineGeneratePublic(new X509EncodedKeySpec(encoded));
    195             } catch (InvalidKeySpecException e) {
    196                 throw new InvalidKeyException(e);
    197             }
    198         } else {
    199             throw new InvalidKeyException("Key must be EC public or private key; was "
    200                     + key.getClass().getName());
    201         }
    202     }
    203 }
    204