1 /* 2 * Copyright (c) 2006, 2010, 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 sun.security.ec.ECPublicKeyImpl; 36 import sun.security.ec.ECParameters; 37 import sun.security.ec.NamedCurve; 38 39 import static sun.security.pkcs11.TemplateManager.*; 40 import sun.security.pkcs11.wrapper.*; 41 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 42 43 import sun.security.util.DerValue; 44 45 /** 46 * EC KeyFactory implemenation. 47 * 48 * @author Andreas Sterbenz 49 * @since 1.6 50 */ 51 final class P11ECKeyFactory extends P11KeyFactory { 52 53 P11ECKeyFactory(Token token, String algorithm) { 54 super(token, algorithm); 55 } 56 57 static ECParameterSpec getECParameterSpec(String name) { 58 return NamedCurve.getECParameterSpec(name); 59 } 60 61 static ECParameterSpec getECParameterSpec(int keySize) { 62 return NamedCurve.getECParameterSpec(keySize); 63 } 64 65 // Check that spec is a known supported curve and convert it to our 66 // ECParameterSpec subclass. If not possible, return null. 67 static ECParameterSpec getECParameterSpec(ECParameterSpec spec) { 68 return ECParameters.getNamedCurve(spec); 69 } 70 71 static ECParameterSpec decodeParameters(byte[] params) throws IOException { 72 return ECParameters.decodeParameters(params); 73 } 74 75 static byte[] encodeParameters(ECParameterSpec params) { 76 return ECParameters.encodeParameters(params); 77 } 78 79 static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) throws IOException { 80 return ECParameters.decodePoint(encoded, curve); 81 } 82 83 // Used by ECDH KeyAgreement 84 static byte[] getEncodedPublicValue(PublicKey key) throws InvalidKeyException { 85 if (key instanceof ECPublicKeyImpl) { 86 return ((ECPublicKeyImpl)key).getEncodedPublicValue(); 87 } else if (key instanceof ECPublicKey) { 88 ECPublicKey ecKey = (ECPublicKey)key; 89 ECPoint w = ecKey.getW(); 90 ECParameterSpec params = ecKey.getParams(); 91 return ECParameters.encodePoint(w, params.getCurve()); 92 } else { 93 // should never occur 94 throw new InvalidKeyException 95 ("Key class not yet supported: " + key.getClass().getName()); 96 } 97 } 98 99 PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { 100 try { 101 if (key instanceof ECPublicKey) { 102 ECPublicKey ecKey = (ECPublicKey)key; 103 return generatePublic( 104 ecKey.getW(), 105 ecKey.getParams() 106 ); 107 } else if ("X.509".equals(key.getFormat())) { 108 // let Sun provider parse for us, then recurse 109 byte[] encoded = key.getEncoded(); 110 key = new sun.security.ec.ECPublicKeyImpl(encoded); 111 return implTranslatePublicKey(key); 112 } else { 113 throw new InvalidKeyException("PublicKey must be instance " 114 + "of ECPublicKey or have X.509 encoding"); 115 } 116 } catch (PKCS11Exception e) { 117 throw new InvalidKeyException("Could not create EC public key", e); 118 } 119 } 120 121 PrivateKey implTranslatePrivateKey(PrivateKey key) 122 throws InvalidKeyException { 123 try { 124 if (key instanceof ECPrivateKey) { 125 ECPrivateKey ecKey = (ECPrivateKey)key; 126 return generatePrivate( 127 ecKey.getS(), 128 ecKey.getParams() 129 ); 130 } else if ("PKCS#8".equals(key.getFormat())) { 131 // let Sun provider parse for us, then recurse 132 byte[] encoded = key.getEncoded(); 133 key = new sun.security.ec.ECPrivateKeyImpl(encoded); 134 return implTranslatePrivateKey(key); 135 } else { 136 throw new InvalidKeyException("PrivateKey must be instance " 137 + "of ECPrivateKey or have PKCS#8 encoding"); 138 } 139 } catch (PKCS11Exception e) { 140 throw new InvalidKeyException("Could not create EC private key", e); 141 } 142 } 143 144 // see JCA spec 145 protected PublicKey engineGeneratePublic(KeySpec keySpec) 146 throws InvalidKeySpecException { 147 token.ensureValid(); 148 if (keySpec instanceof X509EncodedKeySpec) { 149 try { 150 byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded(); 151 PublicKey key = new sun.security.ec.ECPublicKeyImpl(encoded); 152 return implTranslatePublicKey(key); 153 } catch (InvalidKeyException e) { 154 throw new InvalidKeySpecException 155 ("Could not create EC public key", e); 156 } 157 } 158 if (keySpec instanceof ECPublicKeySpec == false) { 159 throw new InvalidKeySpecException("Only ECPublicKeySpec and " 160 + "X509EncodedKeySpec supported for EC public keys"); 161 } 162 try { 163 ECPublicKeySpec ec = (ECPublicKeySpec)keySpec; 164 return generatePublic( 165 ec.getW(), 166 ec.getParams() 167 ); 168 } catch (PKCS11Exception e) { 169 throw new InvalidKeySpecException 170 ("Could not create EC public key", e); 171 } 172 } 173 174 // see JCA spec 175 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) 176 throws InvalidKeySpecException { 177 token.ensureValid(); 178 if (keySpec instanceof PKCS8EncodedKeySpec) { 179 try { 180 byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); 181 PrivateKey key = new sun.security.ec.ECPrivateKeyImpl(encoded); 182 return implTranslatePrivateKey(key); 183 } catch (GeneralSecurityException e) { 184 throw new InvalidKeySpecException 185 ("Could not create EC private key", e); 186 } 187 } 188 if (keySpec instanceof ECPrivateKeySpec == false) { 189 throw new InvalidKeySpecException("Only ECPrivateKeySpec and " 190 + "PKCS8EncodedKeySpec supported for EC private keys"); 191 } 192 try { 193 ECPrivateKeySpec ec = (ECPrivateKeySpec)keySpec; 194 return generatePrivate( 195 ec.getS(), 196 ec.getParams() 197 ); 198 } catch (PKCS11Exception e) { 199 throw new InvalidKeySpecException 200 ("Could not create EC private key", e); 201 } 202 } 203 204 private PublicKey generatePublic(ECPoint point, ECParameterSpec params) throws PKCS11Exception { 205 byte[] encodedParams = ECParameters.encodeParameters(params); 206 byte[] encodedPoint = null; 207 DerValue pkECPoint = new DerValue(DerValue.tag_OctetString, 208 ECParameters.encodePoint(point, params.getCurve())); 209 210 try { 211 encodedPoint = pkECPoint.toByteArray(); 212 } catch (IOException e) { 213 throw new IllegalArgumentException("Could not DER encode point", e); 214 } 215 216 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 217 new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), 218 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), 219 new CK_ATTRIBUTE(CKA_EC_POINT, encodedPoint), 220 new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), 221 }; 222 attributes = token.getAttributes 223 (O_IMPORT, CKO_PUBLIC_KEY, CKK_EC, attributes); 224 Session session = null; 225 try { 226 session = token.getObjSession(); 227 long keyID = token.p11.C_CreateObject(session.id(), attributes); 228 return P11Key.publicKey 229 (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); 230 } finally { 231 token.releaseSession(session); 232 } 233 } 234 235 private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params) throws PKCS11Exception { 236 byte[] encodedParams = ECParameters.encodeParameters(params); 237 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 238 new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), 239 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), 240 new CK_ATTRIBUTE(CKA_VALUE, s), 241 new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), 242 }; 243 attributes = token.getAttributes 244 (O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attributes); 245 Session session = null; 246 try { 247 session = token.getObjSession(); 248 long keyID = token.p11.C_CreateObject(session.id(), attributes); 249 return P11Key.privateKey 250 (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); 251 } finally { 252 token.releaseSession(session); 253 } 254 } 255 256 KeySpec implGetPublicKeySpec(P11Key key, Class keySpec, Session[] session) 257 throws PKCS11Exception, InvalidKeySpecException { 258 if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) { 259 session[0] = token.getObjSession(); 260 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 261 new CK_ATTRIBUTE(CKA_EC_POINT), 262 new CK_ATTRIBUTE(CKA_EC_PARAMS), 263 }; 264 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); 265 try { 266 ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); 267 ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve()); 268 return new ECPublicKeySpec(point, params); 269 } catch (IOException e) { 270 throw new InvalidKeySpecException("Could not parse key", e); 271 } 272 } else { // X.509 handled in superclass 273 throw new InvalidKeySpecException("Only ECPublicKeySpec and " 274 + "X509EncodedKeySpec supported for EC public keys"); 275 } 276 } 277 278 KeySpec implGetPrivateKeySpec(P11Key key, Class keySpec, Session[] session) 279 throws PKCS11Exception, InvalidKeySpecException { 280 if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { 281 session[0] = token.getObjSession(); 282 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 283 new CK_ATTRIBUTE(CKA_VALUE), 284 new CK_ATTRIBUTE(CKA_EC_PARAMS), 285 }; 286 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); 287 try { 288 ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); 289 return new ECPrivateKeySpec(attributes[0].getBigInteger(), params); 290 } catch (IOException e) { 291 throw new InvalidKeySpecException("Could not parse key", e); 292 } 293 } else { // PKCS#8 handled in superclass 294 throw new InvalidKeySpecException("Only ECPrivateKeySpec " 295 + "and PKCS8EncodedKeySpec supported for EC private keys"); 296 } 297 } 298 299 KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { 300 return sun.security.ec.ECKeyFactory.INSTANCE; 301 } 302 303 }