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