]>
Commit | Line | Data |
---|---|---|
448be743 DSH |
1 | /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL |
2 | * project 2006. | |
3 | */ | |
4 | /* ==================================================================== | |
5 | * Copyright (c) 2005 The OpenSSL Project. All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in | |
16 | * the documentation and/or other materials provided with the | |
17 | * distribution. | |
18 | * | |
19 | * 3. All advertising materials mentioning features or use of this | |
20 | * software must display the following acknowledgment: | |
21 | * "This product includes software developed by the OpenSSL Project | |
22 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
23 | * | |
24 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
25 | * endorse or promote products derived from this software without | |
26 | * prior written permission. For written permission, please contact | |
27 | * licensing@OpenSSL.org. | |
28 | * | |
29 | * 5. Products derived from this software may not be called "OpenSSL" | |
30 | * nor may "OpenSSL" appear in their names without prior written | |
31 | * permission of the OpenSSL Project. | |
32 | * | |
33 | * 6. Redistributions of any form whatsoever must retain the following | |
34 | * acknowledgment: | |
35 | * "This product includes software developed by the OpenSSL Project | |
36 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
37 | * | |
38 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
39 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
41 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
42 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
47 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
49 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
50 | * ==================================================================== | |
51 | * | |
52 | * This product includes cryptographic software written by Eric Young | |
53 | * (eay@cryptsoft.com). This product includes software written by Tim | |
54 | * Hudson (tjh@cryptsoft.com). | |
55 | * | |
56 | */ | |
57 | ||
58 | #include <stdio.h> | |
59 | #include "cryptlib.h" | |
60 | #include <openssl/x509.h> | |
61 | #include <openssl/ec.h> | |
62 | ||
63 | static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) | |
64 | { | |
65 | const EC_GROUP *group; | |
66 | int nid; | |
67 | if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) | |
68 | { | |
69 | ECerr(EC_F_ECKEY_PARAM2TYPE, EC_R_MISSING_PARAMETERS); | |
70 | return 0; | |
71 | } | |
72 | if (EC_GROUP_get_asn1_flag(group) | |
73 | && (nid = EC_GROUP_get_curve_name(group))) | |
74 | /* we have a 'named curve' => just set the OID */ | |
75 | { | |
76 | *ppval = OBJ_nid2obj(nid); | |
77 | *pptype = V_ASN1_OBJECT; | |
78 | } | |
79 | else /* explicit parameters */ | |
80 | { | |
81 | ASN1_STRING *pstr = NULL; | |
82 | pstr = ASN1_STRING_new(); | |
83 | if (!pstr) | |
84 | return 0; | |
85 | pstr->length = i2d_ECParameters(ec_key, &pstr->data); | |
86 | if (pstr->length < 0) | |
87 | { | |
88 | ASN1_STRING_free(pstr); | |
89 | ECerr(EC_F_ECKEY_PARAM2TYPE, ERR_R_EC_LIB); | |
90 | return 0; | |
91 | } | |
92 | *ppval = pstr; | |
93 | *pptype = V_ASN1_SEQUENCE; | |
94 | } | |
95 | return 1; | |
96 | } | |
97 | ||
98 | static int eckey_pub_encode(X509_PUBKEY *pk, EVP_PKEY *pkey) | |
99 | { | |
100 | EC_KEY *ec_key = pkey->pkey.ec; | |
101 | void *pval = NULL; | |
102 | int ptype; | |
103 | unsigned char *penc = NULL, *p; | |
104 | int penclen; | |
105 | ||
106 | if (!eckey_param2type(&ptype, &pval, ec_key)) | |
107 | { | |
108 | ECerr(EC_F_ECKEY_PUB_ENCODE, ERR_R_EC_LIB); | |
109 | return 0; | |
110 | } | |
111 | penclen = i2o_ECPublicKey(ec_key, NULL); | |
112 | if (penclen <= 0) | |
113 | goto err; | |
114 | penc = OPENSSL_malloc(penclen); | |
115 | if (!penc) | |
116 | goto err; | |
117 | p = penc; | |
118 | penclen = i2o_ECPublicKey(ec_key, &p); | |
119 | if (penclen <= 0) | |
120 | goto err; | |
121 | if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DSA), | |
122 | ptype, pval, penc, penclen)) | |
123 | return 1; | |
124 | err: | |
125 | if (ptype == V_ASN1_OBJECT) | |
126 | ASN1_OBJECT_free(pval); | |
127 | else | |
128 | ASN1_STRING_free(pval); | |
129 | if (penc) | |
130 | OPENSSL_free(penc); | |
131 | return 0; | |
132 | } | |
133 | ||
134 | static EC_KEY *eckey_type2param(int ptype, void *pval) | |
135 | { | |
136 | EC_KEY *eckey = NULL; | |
137 | if (ptype == V_ASN1_SEQUENCE) | |
138 | { | |
139 | ASN1_STRING *pstr = pval; | |
140 | const unsigned char *pm = NULL; | |
141 | int pmlen; | |
142 | pm = pstr->data; | |
143 | pmlen = pstr->length; | |
144 | if (!(eckey = d2i_ECParameters(NULL, &pm, pmlen))) | |
145 | { | |
146 | ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR); | |
147 | goto ecerr; | |
148 | } | |
149 | } | |
150 | else if (ptype == V_ASN1_OBJECT) | |
151 | { | |
152 | ASN1_OBJECT *poid = pval; | |
153 | EC_GROUP *group; | |
154 | ||
155 | /* type == V_ASN1_OBJECT => the parameters are given | |
156 | * by an asn1 OID | |
157 | */ | |
158 | if ((eckey = EC_KEY_new()) == NULL) | |
159 | { | |
160 | ECerr(EC_F_ECKEY_TYPE2PARAM, ERR_R_MALLOC_FAILURE); | |
161 | goto ecerr; | |
162 | } | |
163 | group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid)); | |
164 | if (group == NULL) | |
165 | goto ecerr; | |
166 | EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); | |
167 | if (EC_KEY_set_group(eckey, group) == 0) | |
168 | goto ecerr; | |
169 | EC_GROUP_free(group); | |
170 | } | |
171 | else | |
172 | { | |
173 | ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR); | |
174 | goto ecerr; | |
175 | } | |
176 | ||
177 | return eckey; | |
178 | ||
179 | ecerr: | |
180 | if (eckey) | |
181 | EC_KEY_free(eckey); | |
182 | return NULL; | |
183 | } | |
184 | ||
185 | static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) | |
186 | { | |
187 | const unsigned char *p = NULL; | |
188 | void *pval; | |
189 | int ptype, pklen; | |
190 | EC_KEY *eckey = NULL; | |
191 | X509_ALGOR *palg; | |
192 | ||
193 | if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) | |
194 | return 0; | |
195 | X509_ALGOR_get0(NULL, &ptype, &pval, palg); | |
196 | ||
197 | eckey = eckey_type2param(ptype, pval); | |
198 | ||
199 | if (!eckey) | |
200 | { | |
201 | ECerr(EC_F_ECKEY_PUB_DECODE, ERR_R_EC_LIB); | |
202 | return 0; | |
203 | } | |
204 | ||
205 | /* We have parameters now set public key */ | |
206 | if (!o2i_ECPublicKey(&eckey, &p, pklen)) | |
207 | { | |
208 | ECerr(EC_F_ECKEY_PUB_DECODE, EC_R_DECODE_ERROR); | |
209 | goto ecerr; | |
210 | } | |
211 | ||
212 | EVP_PKEY_assign_EC_KEY(pkey, eckey); | |
213 | return 1; | |
214 | ||
215 | ecerr: | |
216 | if (eckey) | |
217 | EC_KEY_free(eckey); | |
218 | return 0; | |
219 | } | |
220 | ||
221 | static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) | |
222 | { | |
223 | const unsigned char *p = NULL; | |
224 | void *pval; | |
225 | int ptype, pklen; | |
226 | EC_KEY *eckey = NULL; | |
227 | X509_ALGOR *palg; | |
228 | ||
229 | if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) | |
230 | return 0; | |
231 | X509_ALGOR_get0(NULL, &ptype, &pval, palg); | |
232 | ||
233 | eckey = eckey_type2param(ptype, pval); | |
234 | ||
235 | if (!eckey) | |
236 | goto ecliberr; | |
237 | ||
238 | /* We have parameters now set private key */ | |
239 | if (!d2i_ECPrivateKey(&eckey, &p, pklen)) | |
240 | { | |
241 | ECerr(EC_F_ECKEY_PRIV_DECODE, EC_R_DECODE_ERROR); | |
242 | goto ecerr; | |
243 | } | |
244 | ||
245 | /* calculate public key (if necessary) */ | |
246 | if (EC_KEY_get0_public_key(eckey) == NULL) | |
247 | { | |
248 | const BIGNUM *priv_key; | |
249 | const EC_GROUP *group; | |
250 | EC_POINT *pub_key; | |
251 | /* the public key was not included in the SEC1 private | |
252 | * key => calculate the public key */ | |
253 | group = EC_KEY_get0_group(eckey); | |
254 | pub_key = EC_POINT_new(group); | |
255 | if (pub_key == NULL) | |
256 | { | |
257 | ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); | |
258 | goto ecliberr; | |
259 | } | |
260 | if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) | |
261 | { | |
262 | EC_POINT_free(pub_key); | |
263 | ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); | |
264 | goto ecliberr; | |
265 | } | |
266 | priv_key = EC_KEY_get0_private_key(eckey); | |
267 | if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) | |
268 | { | |
269 | EC_POINT_free(pub_key); | |
270 | ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); | |
271 | goto ecliberr; | |
272 | } | |
273 | if (EC_KEY_set_public_key(eckey, pub_key) == 0) | |
274 | { | |
275 | EC_POINT_free(pub_key); | |
276 | ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); | |
277 | goto ecliberr; | |
278 | } | |
279 | EC_POINT_free(pub_key); | |
280 | } | |
281 | ||
282 | EVP_PKEY_assign_EC_KEY(pkey, eckey); | |
283 | return 1; | |
284 | ||
285 | ecliberr: | |
286 | ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); | |
287 | ecerr: | |
288 | if (eckey) | |
289 | EC_KEY_free(eckey); | |
290 | return 0; | |
291 | } | |
292 | ||
293 | static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, EVP_PKEY *pkey) | |
294 | { | |
295 | EC_KEY *ec_key; | |
296 | unsigned char *ep, *p; | |
297 | int eplen, ptype; | |
298 | void *pval; | |
299 | unsigned int tmp_flags, old_flags; | |
300 | ||
301 | ec_key = pkey->pkey.ec; | |
302 | ||
303 | if (!eckey_param2type(&ptype, &pval, ec_key)) | |
304 | { | |
305 | ECerr(EC_F_ECKEY_PRIV_ENCODE, EC_R_DECODE_ERROR); | |
306 | return 0; | |
307 | } | |
308 | ||
309 | /* set the private key */ | |
310 | ||
311 | /* do not include the parameters in the SEC1 private key | |
312 | * see PKCS#11 12.11 */ | |
313 | old_flags = EC_KEY_get_enc_flags(ec_key); | |
314 | tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS; | |
315 | EC_KEY_set_enc_flags(ec_key, tmp_flags); | |
316 | eplen = i2d_ECPrivateKey(ec_key, NULL); | |
317 | if (!eplen) | |
318 | { | |
319 | EC_KEY_set_enc_flags(ec_key, old_flags); | |
320 | ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB); | |
321 | return 0; | |
322 | } | |
323 | ep = (unsigned char *) OPENSSL_malloc(eplen); | |
324 | if (!ep) | |
325 | { | |
326 | EC_KEY_set_enc_flags(ec_key, old_flags); | |
327 | ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); | |
328 | return 0; | |
329 | } | |
330 | p = ep; | |
331 | if (!i2d_ECPrivateKey(ec_key, &p)) | |
332 | { | |
333 | EC_KEY_set_enc_flags(ec_key, old_flags); | |
334 | OPENSSL_free(ep); | |
335 | ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB); | |
336 | } | |
337 | /* restore old encoding flags */ | |
338 | EC_KEY_set_enc_flags(ec_key, old_flags); | |
339 | ||
340 | if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), 0, | |
341 | ptype, pval, ep, eplen)) | |
342 | return 0; | |
343 | ||
344 | return 1; | |
345 | } | |
346 | ||
347 | EVP_PKEY_ASN1_METHOD eckey_asn1_meth = | |
348 | { | |
349 | EVP_PKEY_EC, | |
350 | 0, | |
351 | 0, | |
352 | eckey_pub_decode, | |
353 | eckey_pub_encode, | |
354 | 0, | |
355 | eckey_priv_decode, | |
356 | eckey_priv_encode, | |
357 | 0, | |
358 | 0, | |
359 | 0 | |
360 | }; |