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