1 /* 2 * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.pkcs11; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 31 import java.security.*; 32 import java.security.interfaces.*; 33 import java.security.spec.*; 34 35 import static sun.security.pkcs11.TemplateManager.*; 36 import sun.security.pkcs11.wrapper.*; 37 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 38 39 import sun.security.util.DerValue; 40 import sun.security.util.ECUtil; 41 42 /** 43 * EC KeyFactory implementation. 44 * 45 * @author Andreas Sterbenz 46 * @since 1.6 47 */ 48 final class P11ECKeyFactory extends P11KeyFactory { 49 private static Provider sunECprovider; 50 51 private static Provider getSunECProvider() { 52 if (sunECprovider == null) { 53 sunECprovider = Security.getProvider("SunEC"); 54 if (sunECprovider == null) { 55 throw new RuntimeException("Cannot load SunEC provider"); 56 } 57 } 58 59 return sunECprovider; 60 } 61 62 P11ECKeyFactory(Token token, String algorithm) { 63 super(token, algorithm); 64 } 65 66 static ECParameterSpec getECParameterSpec(String name) { 67 return ECUtil.getECParameterSpec(getSunECProvider(), name); 68 } 69 70 static ECParameterSpec getECParameterSpec(int keySize) { 71 return ECUtil.getECParameterSpec(getSunECProvider(), keySize); 72 } 73 74 // Check that spec is a known supported curve and convert it to our 75 // ECParameterSpec subclass. If not possible, return null. 76 static ECParameterSpec getECParameterSpec(ECParameterSpec spec) { 77 return ECUtil.getECParameterSpec(getSunECProvider(), spec); 78 } 79 80 static ECParameterSpec decodeParameters(byte[] params) throws IOException { 81 return ECUtil.getECParameterSpec(getSunECProvider(), params); 82 } 83 84 static byte[] encodeParameters(ECParameterSpec params) { 85 return ECUtil.encodeECParameterSpec(getSunECProvider(), params); 86 } 87 88 static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) throws IOException { 89 return ECUtil.decodePoint(encoded, curve); 90 } 91 92 // Used by ECDH KeyAgreement 93 static byte[] getEncodedPublicValue(PublicKey key) throws InvalidKeyException { 94 if (key instanceof ECPublicKey) { 95 ECPublicKey ecKey = (ECPublicKey)key; 96 ECPoint w = ecKey.getW(); 97 ECParameterSpec params = ecKey.getParams(); 98 return ECUtil.encodePoint(w, params.getCurve()); 99 } else { 100 // should never occur 101 throw new InvalidKeyException 102 ("Key class not yet supported: " + key.getClass().getName()); 103 } 104 } 105 106 PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { 107 try { 108 if (key instanceof ECPublicKey) { 109 ECPublicKey ecKey = (ECPublicKey)key; 110 return generatePublic( 111 ecKey.getW(), 112 ecKey.getParams() 113 ); 114 } else if ("X.509".equals(key.getFormat())) { 115 // let Sun provider parse for us, then recurse 116 byte[] encoded = key.getEncoded(); 117 118 try { 119 key = ECUtil.decodeX509ECPublicKey(encoded); 120 } catch (InvalidKeySpecException ikse) { 121 throw new InvalidKeyException(ikse); 122 } 123 124 return implTranslatePublicKey(key); 125 } else { 126 throw new InvalidKeyException("PublicKey must be instance " 127 + "of ECPublicKey or have X.509 encoding"); 128 } 129 } catch (PKCS11Exception e) { 130 throw new InvalidKeyException("Could not create EC public key", e); 131 } 132 } 133 134 PrivateKey implTranslatePrivateKey(PrivateKey key) 135 throws InvalidKeyException { 136 try { 137 if (key instanceof ECPrivateKey) { 138 ECPrivateKey ecKey = (ECPrivateKey)key; 139 return generatePrivate( 140 ecKey.getS(), 141 ecKey.getParams() 142 ); 143 } else if ("PKCS#8".equals(key.getFormat())) { 144 // let Sun provider parse for us, then recurse 145 byte[] encoded = key.getEncoded(); 146 147 try { 148 key = ECUtil.decodePKCS8ECPrivateKey(encoded); 149 } catch (InvalidKeySpecException ikse) { 150 throw new InvalidKeyException(ikse); 151 } 152 153 return implTranslatePrivateKey(key); 154 } else { 155 throw new InvalidKeyException("PrivateKey must be instance " 156 + "of ECPrivateKey or have PKCS#8 encoding"); 157 } 158 } catch (PKCS11Exception e) { 159 throw new InvalidKeyException("Could not create EC private key", e); 160 } 161 } 162 163 // see JCA spec 164 protected PublicKey engineGeneratePublic(KeySpec keySpec) 165 throws InvalidKeySpecException { 166 token.ensureValid(); 167 if (keySpec instanceof X509EncodedKeySpec) { 168 try { 169 byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded(); 170 PublicKey key = ECUtil.decodeX509ECPublicKey(encoded); 171 return implTranslatePublicKey(key); 172 } catch (InvalidKeyException e) { 173 throw new InvalidKeySpecException 174 ("Could not create EC public key", e); 175 } 176 } 177 if (keySpec instanceof ECPublicKeySpec == false) { 178 throw new InvalidKeySpecException("Only ECPublicKeySpec and " 179 + "X509EncodedKeySpec supported for EC public keys"); 180 } 181 try { 182 ECPublicKeySpec ec = (ECPublicKeySpec)keySpec; 183 return generatePublic( 184 ec.getW(), 185 ec.getParams() 186 ); 187 } catch (PKCS11Exception e) { 188 throw new InvalidKeySpecException 189 ("Could not create EC public key", e); 190 } 191 } 192 193 // see JCA spec 194 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) 195 throws InvalidKeySpecException { 196 token.ensureValid(); 197 if (keySpec instanceof PKCS8EncodedKeySpec) { 198 try { 199 byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); 200 PrivateKey key = ECUtil.decodePKCS8ECPrivateKey(encoded); 201 return implTranslatePrivateKey(key); 202 } catch (GeneralSecurityException e) { 203 throw new InvalidKeySpecException 204 ("Could not create EC private key", e); 205 } 206 } 207 if (keySpec instanceof ECPrivateKeySpec == false) { 208 throw new InvalidKeySpecException("Only ECPrivateKeySpec and " 209 + "PKCS8EncodedKeySpec supported for EC private keys"); 210 } 211 try { 212 ECPrivateKeySpec ec = (ECPrivateKeySpec)keySpec; 213 return generatePrivate( 214 ec.getS(), 215 ec.getParams() 216 ); 217 } catch (PKCS11Exception e) { 218 throw new InvalidKeySpecException 219 ("Could not create EC private key", e); 220 } 221 } 222 223 private PublicKey generatePublic(ECPoint point, ECParameterSpec params) 224 throws PKCS11Exception { 225 byte[] encodedParams = 226 ECUtil.encodeECParameterSpec(getSunECProvider(), params); 227 byte[] encodedPoint = 228 ECUtil.encodePoint(point, params.getCurve()); 229 230 // Check whether the X9.63 encoding of an EC point shall be wrapped 231 // in an ASN.1 OCTET STRING 232 if (!token.config.getUseEcX963Encoding()) { 233 try { 234 encodedPoint = 235 new DerValue(DerValue.tag_OctetString, encodedPoint) 236 .toByteArray(); 237 } catch (IOException e) { 238 throw new 239 IllegalArgumentException("Could not DER encode point", e); 240 } 241 } 242 243 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 244 new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), 245 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), 246 new CK_ATTRIBUTE(CKA_EC_POINT, encodedPoint), 247 new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), 248 }; 249 attributes = token.getAttributes 250 (O_IMPORT, CKO_PUBLIC_KEY, CKK_EC, attributes); 251 Session session = null; 252 try { 253 session = token.getObjSession(); 254 long keyID = token.p11.C_CreateObject(session.id(), attributes); 255 return P11Key.publicKey 256 (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); 257 } finally { 258 token.releaseSession(session); 259 } 260 } 261 262 private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params) 263 throws PKCS11Exception { 264 byte[] encodedParams = 265 ECUtil.encodeECParameterSpec(getSunECProvider(), params); 266 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 267 new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), 268 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), 269 new CK_ATTRIBUTE(CKA_VALUE, s), 270 new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), 271 }; 272 attributes = token.getAttributes 273 (O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attributes); 274 Session session = null; 275 try { 276 session = token.getObjSession(); 277 long keyID = token.p11.C_CreateObject(session.id(), attributes); 278 return P11Key.privateKey 279 (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); 280 } finally { 281 token.releaseSession(session); 282 } 283 } 284 285 <T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec, 286 Session[] session) throws PKCS11Exception, InvalidKeySpecException { 287 if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) { 288 session[0] = token.getObjSession(); 289 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 290 new CK_ATTRIBUTE(CKA_EC_POINT), 291 new CK_ATTRIBUTE(CKA_EC_PARAMS), 292 }; 293 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); 294 try { 295 ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); 296 ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve()); 297 return keySpec.cast(new ECPublicKeySpec(point, params)); 298 } catch (IOException e) { 299 throw new InvalidKeySpecException("Could not parse key", e); 300 } 301 } else { // X.509 handled in superclass 302 throw new InvalidKeySpecException("Only ECPublicKeySpec and " 303 + "X509EncodedKeySpec supported for EC public keys"); 304 } 305 } 306 307 <T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec, 308 Session[] session) throws PKCS11Exception, InvalidKeySpecException { 309 if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { 310 session[0] = token.getObjSession(); 311 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 312 new CK_ATTRIBUTE(CKA_VALUE), 313 new CK_ATTRIBUTE(CKA_EC_PARAMS), 314 }; 315 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); 316 try { 317 ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); 318 return keySpec.cast( 319 new ECPrivateKeySpec(attributes[0].getBigInteger(), params)); 320 } catch (IOException e) { 321 throw new InvalidKeySpecException("Could not parse key", e); 322 } 323 } else { // PKCS#8 handled in superclass 324 throw new InvalidKeySpecException("Only ECPrivateKeySpec " 325 + "and PKCS8EncodedKeySpec supported for EC private keys"); 326 } 327 } 328 329 KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { 330 return KeyFactory.getInstance("EC", getSunECProvider()); 331 } 332 333 }