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