openssl: Report correct key length for EC keys when not using NIST curves
[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 return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec));
185 }
186
187 METHOD(private_key_t, get_type, key_type_t,
188 private_openssl_ec_private_key_t *this)
189 {
190 return KEY_ECDSA;
191 }
192
193 METHOD(private_key_t, get_public_key, public_key_t*,
194 private_openssl_ec_private_key_t *this)
195 {
196 public_key_t *public;
197 chunk_t key;
198 u_char *p;
199
200 key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
201 p = key.ptr;
202 i2d_EC_PUBKEY(this->ec, &p);
203
204 public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
205 BUILD_BLOB_ASN1_DER, key, BUILD_END);
206 free(key.ptr);
207 return public;
208 }
209
210 METHOD(private_key_t, get_fingerprint, bool,
211 private_openssl_ec_private_key_t *this, cred_encoding_type_t type,
212 chunk_t *fingerprint)
213 {
214 return openssl_ec_fingerprint(this->ec, type, fingerprint);
215 }
216
217 METHOD(private_key_t, get_encoding, bool,
218 private_openssl_ec_private_key_t *this, cred_encoding_type_t type,
219 chunk_t *encoding)
220 {
221 u_char *p;
222
223 switch (type)
224 {
225 case PRIVKEY_ASN1_DER:
226 case PRIVKEY_PEM:
227 {
228 bool success = TRUE;
229
230 *encoding = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL));
231 p = encoding->ptr;
232 i2d_ECPrivateKey(this->ec, &p);
233
234 if (type == PRIVKEY_PEM)
235 {
236 chunk_t asn1_encoding = *encoding;
237
238 success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
239 NULL, encoding, CRED_PART_ECDSA_PRIV_ASN1_DER,
240 asn1_encoding, CRED_PART_END);
241 chunk_clear(&asn1_encoding);
242 }
243 return success;
244 }
245 default:
246 return FALSE;
247 }
248 }
249
250 METHOD(private_key_t, get_ref, private_key_t*,
251 private_openssl_ec_private_key_t *this)
252 {
253 ref_get(&this->ref);
254 return &this->public.key;
255 }
256
257 METHOD(private_key_t, destroy, void,
258 private_openssl_ec_private_key_t *this)
259 {
260 if (ref_put(&this->ref))
261 {
262 if (this->ec)
263 {
264 lib->encoding->clear_cache(lib->encoding, this->ec);
265 EC_KEY_free(this->ec);
266 }
267 free(this);
268 }
269 }
270
271 /**
272 * Internal generic constructor
273 */
274 static private_openssl_ec_private_key_t *create_empty(void)
275 {
276 private_openssl_ec_private_key_t *this;
277
278 INIT(this,
279 .public = {
280 .key = {
281 .get_type = _get_type,
282 .sign = _sign,
283 .decrypt = _decrypt,
284 .get_keysize = _get_keysize,
285 .get_public_key = _get_public_key,
286 .equals = private_key_equals,
287 .belongs_to = private_key_belongs_to,
288 .get_fingerprint = _get_fingerprint,
289 .has_fingerprint = private_key_has_fingerprint,
290 .get_encoding = _get_encoding,
291 .get_ref = _get_ref,
292 .destroy = _destroy,
293 },
294 },
295 .ref = 1,
296 );
297
298 return this;
299 }
300
301 /**
302 * See header.
303 */
304 openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type,
305 va_list args)
306 {
307 private_openssl_ec_private_key_t *this;
308 u_int key_size = 0;
309
310 while (TRUE)
311 {
312 switch (va_arg(args, builder_part_t))
313 {
314 case BUILD_KEY_SIZE:
315 key_size = va_arg(args, u_int);
316 continue;
317 case BUILD_END:
318 break;
319 default:
320 return NULL;
321 }
322 break;
323 }
324 if (!key_size)
325 {
326 return NULL;
327 }
328 this = create_empty();
329 switch (key_size)
330 {
331 case 256:
332 this->ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
333 break;
334 case 384:
335 this->ec = EC_KEY_new_by_curve_name(NID_secp384r1);
336 break;
337 case 521:
338 this->ec = EC_KEY_new_by_curve_name(NID_secp521r1);
339 break;
340 default:
341 DBG1(DBG_LIB, "EC private key size %d not supported", key_size);
342 destroy(this);
343 return NULL;
344 }
345 if (EC_KEY_generate_key(this->ec) != 1)
346 {
347 DBG1(DBG_LIB, "EC private key generation failed", key_size);
348 destroy(this);
349 return NULL;
350 }
351 /* encode as a named curve key (no parameters), uncompressed public key */
352 EC_KEY_set_asn1_flag(this->ec, OPENSSL_EC_NAMED_CURVE);
353 EC_KEY_set_conv_form(this->ec, POINT_CONVERSION_UNCOMPRESSED);
354 return &this->public;
355 }
356
357 /**
358 * See header.
359 */
360 openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
361 va_list args)
362 {
363 private_openssl_ec_private_key_t *this;
364 chunk_t par = chunk_empty, key = chunk_empty;
365
366 while (TRUE)
367 {
368 switch (va_arg(args, builder_part_t))
369 {
370 case BUILD_BLOB_ALGID_PARAMS:
371 par = va_arg(args, chunk_t);
372 continue;
373 case BUILD_BLOB_ASN1_DER:
374 key = va_arg(args, chunk_t);
375 continue;
376 case BUILD_END:
377 break;
378 default:
379 return NULL;
380 }
381 break;
382 }
383
384 this = create_empty();
385
386 if (par.ptr)
387 {
388 this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len);
389 if (!this->ec)
390 {
391 goto error;
392 }
393 if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len))
394 {
395 goto error;
396 }
397 }
398 else
399 {
400 this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len);
401 if (!this->ec)
402 {
403 goto error;
404 }
405 }
406 if (!EC_KEY_check_key(this->ec))
407 {
408 goto error;
409 }
410 return &this->public;
411
412 error:
413 destroy(this);
414 return NULL;
415 }
416 #endif /* OPENSSL_NO_ECDSA */