12f264267efc3eecc014a987cfcb14734011b7fb
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_ec_private_key.c
1 /*
2 * Copyright (C) 2008-2012 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <openssl/opensslconf.h>
18
19 #ifndef OPENSSL_NO_ECDSA
20
21 #include "openssl_ec_private_key.h"
22 #include "openssl_ec_public_key.h"
23 #include "openssl_util.h"
24
25 #include <utils/debug.h>
26
27 #include <openssl/evp.h>
28 #include <openssl/ecdsa.h>
29 #include <openssl/x509.h>
30
31 typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t;
32
33 /**
34 * Private data of a openssl_ec_private_key_t object.
35 */
36 struct private_openssl_ec_private_key_t {
37 /**
38 * Public interface for this signer.
39 */
40 openssl_ec_private_key_t public;
41
42 /**
43 * EC key object
44 */
45 EC_KEY *ec;
46
47 /**
48 * reference count
49 */
50 refcount_t ref;
51 };
52
53 /* from ec public key */
54 bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp);
55
56 /**
57 * Build a signature as in RFC 4754
58 */
59 static bool build_signature(private_openssl_ec_private_key_t *this,
60 chunk_t hash, chunk_t *signature)
61 {
62 bool built = FALSE;
63 ECDSA_SIG *sig;
64
65 sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec);
66 if (sig)
67 {
68 /* concatenate BNs r/s to a signature chunk */
69 built = openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec)),
70 sig->r, sig->s, signature);
71 ECDSA_SIG_free(sig);
72 }
73 return built;
74 }
75
76 /**
77 * Build a RFC 4754 signature for a specified curve and hash algorithm
78 */
79 static bool build_curve_signature(private_openssl_ec_private_key_t *this,
80 signature_scheme_t scheme, int nid_hash,
81 int nid_curve, chunk_t data, chunk_t *signature)
82 {
83 const EC_GROUP *my_group;
84 EC_GROUP *req_group;
85 chunk_t hash;
86 bool built;
87
88 req_group = EC_GROUP_new_by_curve_name(nid_curve);
89 if (!req_group)
90 {
91 DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve "
92 "not supported)", signature_scheme_names, scheme);
93 return FALSE;
94 }
95 my_group = EC_KEY_get0_group(this->ec);
96 if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
97 {
98 DBG1(DBG_LIB, "signature scheme %N not supported by private key",
99 signature_scheme_names, scheme);
100 return FALSE;
101 }
102 EC_GROUP_free(req_group);
103 if (!openssl_hash_chunk(nid_hash, data, &hash))
104 {
105 return FALSE;
106 }
107 built = build_signature(this, hash, signature);
108 chunk_free(&hash);
109 return built;
110 }
111
112 /**
113 * Build a DER encoded signature as in RFC 3279
114 */
115 static bool build_der_signature(private_openssl_ec_private_key_t *this,
116 int hash_nid, chunk_t data, chunk_t *signature)
117 {
118 chunk_t hash, sig;
119 int siglen = 0;
120 bool built;
121
122 if (!openssl_hash_chunk(hash_nid, data, &hash))
123 {
124 return FALSE;
125 }
126 sig = chunk_alloc(ECDSA_size(this->ec));
127 built = ECDSA_sign(0, hash.ptr, hash.len, sig.ptr, &siglen, this->ec) == 1;
128 sig.len = siglen;
129 if (built)
130 {
131 *signature = sig;
132 }
133 else
134 {
135 free(sig.ptr);
136 }
137 free(hash.ptr);
138 return built;
139 }
140
141 METHOD(private_key_t, sign, bool,
142 private_openssl_ec_private_key_t *this, signature_scheme_t scheme,
143 chunk_t data, chunk_t *signature)
144 {
145 switch (scheme)
146 {
147 case SIGN_ECDSA_WITH_NULL:
148 return build_signature(this, data, signature);
149 case SIGN_ECDSA_WITH_SHA1_DER:
150 return build_der_signature(this, NID_sha1, data, signature);
151 case SIGN_ECDSA_WITH_SHA256_DER:
152 return build_der_signature(this, NID_sha256, data, signature);
153 case SIGN_ECDSA_WITH_SHA384_DER:
154 return build_der_signature(this, NID_sha384, data, signature);
155 case SIGN_ECDSA_WITH_SHA512_DER:
156 return build_der_signature(this, NID_sha512, data, signature);
157 case SIGN_ECDSA_256:
158 return build_curve_signature(this, scheme, NID_sha256,
159 NID_X9_62_prime256v1, data, signature);
160 case SIGN_ECDSA_384:
161 return build_curve_signature(this, scheme, NID_sha384,
162 NID_secp384r1, data, signature);
163 case SIGN_ECDSA_521:
164 return build_curve_signature(this, scheme, NID_sha512,
165 NID_secp521r1, data, signature);
166 default:
167 DBG1(DBG_LIB, "signature scheme %N not supported",
168 signature_scheme_names, scheme);
169 return FALSE;
170 }
171 }
172
173 METHOD(private_key_t, decrypt, bool,
174 private_openssl_ec_private_key_t *this, encryption_scheme_t scheme,
175 chunk_t crypto, chunk_t *plain)
176 {
177 DBG1(DBG_LIB, "EC private key decryption not implemented");
178 return FALSE;
179 }
180
181 METHOD(private_key_t, get_keysize, int,
182 private_openssl_ec_private_key_t *this)
183 {
184 switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(this->ec)))
185 {
186 case NID_X9_62_prime256v1:
187 return 256;
188 case NID_secp384r1:
189 return 384;
190 case NID_secp521r1:
191 return 521;
192 default:
193 return 0;
194 }
195 }
196
197 METHOD(private_key_t, get_type, key_type_t,
198 private_openssl_ec_private_key_t *this)
199 {
200 return KEY_ECDSA;
201 }
202
203 METHOD(private_key_t, get_public_key, public_key_t*,
204 private_openssl_ec_private_key_t *this)
205 {
206 public_key_t *public;
207 chunk_t key;
208 u_char *p;
209
210 key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
211 p = key.ptr;
212 i2d_EC_PUBKEY(this->ec, &p);
213
214 public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
215 BUILD_BLOB_ASN1_DER, key, BUILD_END);
216 free(key.ptr);
217 return public;
218 }
219
220 METHOD(private_key_t, get_fingerprint, bool,
221 private_openssl_ec_private_key_t *this, cred_encoding_type_t type,
222 chunk_t *fingerprint)
223 {
224 return openssl_ec_fingerprint(this->ec, type, fingerprint);
225 }
226
227 METHOD(private_key_t, get_encoding, bool,
228 private_openssl_ec_private_key_t *this, cred_encoding_type_t type,
229 chunk_t *encoding)
230 {
231 u_char *p;
232
233 switch (type)
234 {
235 case PRIVKEY_ASN1_DER:
236 case PRIVKEY_PEM:
237 {
238 bool success = TRUE;
239
240 *encoding = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL));
241 p = encoding->ptr;
242 i2d_ECPrivateKey(this->ec, &p);
243
244 if (type == PRIVKEY_PEM)
245 {
246 chunk_t asn1_encoding = *encoding;
247
248 success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
249 NULL, encoding, CRED_PART_ECDSA_PRIV_ASN1_DER,
250 asn1_encoding, CRED_PART_END);
251 chunk_clear(&asn1_encoding);
252 }
253 return success;
254 }
255 default:
256 return FALSE;
257 }
258 }
259
260 METHOD(private_key_t, get_ref, private_key_t*,
261 private_openssl_ec_private_key_t *this)
262 {
263 ref_get(&this->ref);
264 return &this->public.key;
265 }
266
267 METHOD(private_key_t, destroy, void,
268 private_openssl_ec_private_key_t *this)
269 {
270 if (ref_put(&this->ref))
271 {
272 if (this->ec)
273 {
274 lib->encoding->clear_cache(lib->encoding, this->ec);
275 EC_KEY_free(this->ec);
276 }
277 free(this);
278 }
279 }
280
281 /**
282 * Internal generic constructor
283 */
284 static private_openssl_ec_private_key_t *create_empty(void)
285 {
286 private_openssl_ec_private_key_t *this;
287
288 INIT(this,
289 .public = {
290 .key = {
291 .get_type = _get_type,
292 .sign = _sign,
293 .decrypt = _decrypt,
294 .get_keysize = _get_keysize,
295 .get_public_key = _get_public_key,
296 .equals = private_key_equals,
297 .belongs_to = private_key_belongs_to,
298 .get_fingerprint = _get_fingerprint,
299 .has_fingerprint = private_key_has_fingerprint,
300 .get_encoding = _get_encoding,
301 .get_ref = _get_ref,
302 .destroy = _destroy,
303 },
304 },
305 .ref = 1,
306 );
307
308 return this;
309 }
310
311 /**
312 * See header.
313 */
314 openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type,
315 va_list args)
316 {
317 private_openssl_ec_private_key_t *this;
318 u_int key_size = 0;
319
320 while (TRUE)
321 {
322 switch (va_arg(args, builder_part_t))
323 {
324 case BUILD_KEY_SIZE:
325 key_size = va_arg(args, u_int);
326 continue;
327 case BUILD_END:
328 break;
329 default:
330 return NULL;
331 }
332 break;
333 }
334 if (!key_size)
335 {
336 return NULL;
337 }
338 this = create_empty();
339 switch (key_size)
340 {
341 case 256:
342 this->ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
343 break;
344 case 384:
345 this->ec = EC_KEY_new_by_curve_name(NID_secp384r1);
346 break;
347 case 521:
348 this->ec = EC_KEY_new_by_curve_name(NID_secp521r1);
349 break;
350 default:
351 DBG1(DBG_LIB, "EC private key size %d not supported", key_size);
352 destroy(this);
353 return NULL;
354 }
355 if (EC_KEY_generate_key(this->ec) != 1)
356 {
357 DBG1(DBG_LIB, "EC private key generation failed", key_size);
358 destroy(this);
359 return NULL;
360 }
361 /* encode as a named curve key (no parameters), uncompressed public key */
362 EC_KEY_set_asn1_flag(this->ec, OPENSSL_EC_NAMED_CURVE);
363 EC_KEY_set_conv_form(this->ec, POINT_CONVERSION_UNCOMPRESSED);
364 return &this->public;
365 }
366
367 /**
368 * See header.
369 */
370 openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
371 va_list args)
372 {
373 private_openssl_ec_private_key_t *this;
374 chunk_t par = chunk_empty, key = chunk_empty;
375
376 while (TRUE)
377 {
378 switch (va_arg(args, builder_part_t))
379 {
380 case BUILD_BLOB_ALGID_PARAMS:
381 par = va_arg(args, chunk_t);
382 continue;
383 case BUILD_BLOB_ASN1_DER:
384 key = va_arg(args, chunk_t);
385 continue;
386 case BUILD_END:
387 break;
388 default:
389 return NULL;
390 }
391 break;
392 }
393
394 this = create_empty();
395
396 if (par.ptr)
397 {
398 this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len);
399 if (!this->ec)
400 {
401 goto error;
402 }
403 if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len))
404 {
405 goto error;
406 }
407 }
408 else
409 {
410 this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len);
411 if (!this->ec)
412 {
413 goto error;
414 }
415 }
416 if (!EC_KEY_check_key(this->ec))
417 {
418 goto error;
419 }
420 return &this->public;
421
422 error:
423 destroy(this);
424 return NULL;
425 }
426 #endif /* OPENSSL_NO_ECDSA */