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 @Internal 40 public final class OpenSSLECKeyFactory extends KeyFactorySpi { 41 OpenSSLECKeyFactory()42 public OpenSSLECKeyFactory() {} 43 44 @Override engineGeneratePublic(KeySpec keySpec)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 engineGeneratePrivate(KeySpec keySpec)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 engineGetKeySpec(Key key, Class<T> keySpec)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 engineTranslateKey(Key key)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