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(session, keyID, "EC", 256 params.getCurve().getField().getFieldSize(), 257 attributes, true); 258 } finally { 259 token.releaseSession(session); 260 } 261 } 262 263 private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params) 264 throws PKCS11Exception { 265 byte[] encodedParams = 266 ECUtil.encodeECParameterSpec(getSunECProvider(), params); 267 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 268 new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), 269 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), 270 new CK_ATTRIBUTE(CKA_VALUE, s), 271 new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), 272 }; 273 attributes = token.getAttributes 274 (O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attributes); 275 Session session = null; 276 try { 277 session = token.getObjSession(); 278 long keyID = token.p11.C_CreateObject(session.id(), attributes); 279 return P11Key.privateKey(session, keyID, "EC", 280 params.getCurve().getField().getFieldSize(), 281 attributes, true); 282 } finally { 283 token.releaseSession(session); 284 } 285 } 286 287 <T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec, 288 Session[] session) throws PKCS11Exception, InvalidKeySpecException { 289 if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) { 290 session[0] = token.getObjSession(); 291 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 292 new CK_ATTRIBUTE(CKA_EC_POINT), 293 new CK_ATTRIBUTE(CKA_EC_PARAMS), 294 }; 295 key.incNativeKeyRef(); 296 try { 297 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, 298 attributes); 299 } finally { 300 key.decNativeKeyRef(); 301 } 302 try { 303 ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); 304 ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve()); 305 return keySpec.cast(new ECPublicKeySpec(point, params)); 306 } catch (IOException e) { 307 throw new InvalidKeySpecException("Could not parse key", e); 308 } 309 } else { // X.509 handled in superclass 310 throw new InvalidKeySpecException("Only ECPublicKeySpec and " 311 + "X509EncodedKeySpec supported for EC public keys"); 312 } 313 } 314 315 <T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec, 316 Session[] session) throws PKCS11Exception, InvalidKeySpecException { 317 if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { 318 session[0] = token.getObjSession(); 319 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 320 new CK_ATTRIBUTE(CKA_VALUE), 321 new CK_ATTRIBUTE(CKA_EC_PARAMS), 322 }; 323 key.incNativeKeyRef(); 324 try { 325 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, 326 attributes); 327 } finally { 328 key.decNativeKeyRef(); 329 } 330 try { 331 ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); 332 return keySpec.cast( 333 new ECPrivateKeySpec(attributes[0].getBigInteger(), params)); 334 } catch (IOException e) { 335 throw new InvalidKeySpecException("Could not parse key", e); 336 } 337 } else { // PKCS#8 handled in superclass 338 throw new InvalidKeySpecException("Only ECPrivateKeySpec " 339 + "and PKCS8EncodedKeySpec supported for EC private keys"); 340 } 341 } 342 343 KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { 344 return KeyFactory.getInstance("EC", getSunECProvider()); 345 } 346 347 }