]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
d6b442ae98354a1d488590929f925919c288e874
[people/ms/strongswan.git] / src / libstrongswan / plugins / openssl / openssl_ec_private_key.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "openssl_ec_private_key.h"
17 #include "openssl_ec_public_key.h"
18 #include "openssl_util.h"
19
20 #include <debug.h>
21
22 #include <openssl/evp.h>
23 #include <openssl/ecdsa.h>
24
25 typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t;
26
27 /**
28 * Private data of a openssl_ec_private_key_t object.
29 */
30 struct private_openssl_ec_private_key_t {
31 /**
32 * Public interface for this signer.
33 */
34 openssl_ec_private_key_t public;
35
36 /**
37 * EC key object
38 */
39 EC_KEY *ec;
40
41 /**
42 * Keyid formed as a SHA-1 hash of a privateKey object
43 */
44 identification_t* keyid;
45
46 /**
47 * Keyid formed as a SHA-1 hash of a privateKeyInfo object
48 */
49 identification_t* keyid_info;
50
51 /**
52 * reference count
53 */
54 refcount_t ref;
55 };
56
57 /**
58 * Mapping from the signature scheme defined in (RFC 4754) to the elliptic
59 * curve and the hash algorithm
60 */
61 typedef struct {
62 /**
63 * Scheme specified in RFC 4754
64 */
65 int scheme;
66
67 /**
68 * NID of the hash
69 */
70 int hash;
71
72 /**
73 * NID of the curve
74 */
75 int curve;
76 } openssl_ecdsa_scheme_t;
77
78 #define END_OF_LIST -1
79
80 /**
81 * Signature schemes
82 */
83 static openssl_ecdsa_scheme_t ecdsa_schemes[] = {
84 {SIGN_ECDSA_256, NID_sha256, NID_X9_62_prime256v1},
85 {SIGN_ECDSA_384, NID_sha384, NID_secp384r1},
86 {SIGN_ECDSA_521, NID_sha512, NID_secp521r1},
87 {END_OF_LIST, 0, 0},
88 };
89
90 /**
91 * Look up the hash and curve of a signature scheme
92 */
93 static bool lookup_scheme(int scheme, int *hash, int *curve)
94 {
95 openssl_ecdsa_scheme_t *ecdsa_scheme = ecdsa_schemes;
96 while (ecdsa_scheme->scheme != END_OF_LIST)
97 {
98 if (scheme == ecdsa_scheme->scheme)
99 {
100 *hash = ecdsa_scheme->hash;
101 *curve = ecdsa_scheme->curve;
102 return TRUE;
103 }
104 ecdsa_scheme++;
105 }
106 return FALSE;
107 }
108
109 /**
110 * shared functions, implemented in openssl_ec_public_key.c
111 */
112 bool openssl_ec_public_key_build_id(EC_KEY *ec, identification_t **keyid,
113 identification_t **keyid_info);
114
115 openssl_ec_public_key_t *openssl_ec_public_key_create_from_private_key(EC_KEY *ec);
116
117
118 /**
119 * Convert an ECDSA_SIG to a chunk by concatenating r and s.
120 * This function allocates memory for the chunk.
121 */
122 static bool sig2chunk(const EC_GROUP *group, ECDSA_SIG *sig, chunk_t *chunk)
123 {
124 return openssl_bn_cat(EC_FIELD_ELEMENT_LEN(group), sig->r, sig->s, chunk);
125 }
126
127 /**
128 * Build the signature
129 */
130 static bool build_signature(private_openssl_ec_private_key_t *this,
131 chunk_t hash, chunk_t *signature)
132 {
133 ECDSA_SIG *sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec);
134 bool success;
135
136 if (!sig)
137 {
138 return FALSE;
139 }
140 success = sig2chunk(EC_KEY_get0_group(this->ec), sig, signature);
141 ECDSA_SIG_free(sig);
142 return success;
143 }
144
145 /**
146 * Implementation of private_key_t.get_type.
147 */
148 static key_type_t get_type(private_openssl_ec_private_key_t *this)
149 {
150 return KEY_ECDSA;
151 }
152
153 /**
154 * Implementation of private_key_t.sign.
155 */
156 static bool sign(private_openssl_ec_private_key_t *this, signature_scheme_t scheme,
157 chunk_t data, chunk_t *signature)
158 {
159 bool success;
160
161 if (scheme == SIGN_ECDSA_WITH_NULL)
162 {
163 success = build_signature(this, data, signature);
164 }
165 else
166 {
167 EC_GROUP *req_group;
168 const EC_GROUP *my_group;
169 chunk_t hash = chunk_empty;
170 int hash_type, curve;
171
172 if (!lookup_scheme(scheme, &hash_type, &curve))
173 {
174 DBG1("signature scheme %N not supported in EC",
175 signature_scheme_names, scheme);
176 return FALSE;
177 }
178
179 req_group = EC_GROUP_new_by_curve_name(curve);
180 if (!req_group)
181 {
182 DBG1("signature scheme %N not supported in EC (required curve not supported)",
183 signature_scheme_names, scheme);
184 return FALSE;
185 }
186
187 my_group = EC_KEY_get0_group(this->ec);
188 if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
189 {
190 DBG1("signature scheme %N not supported by private key",
191 signature_scheme_names, scheme);
192 return FALSE;
193 }
194 EC_GROUP_free(req_group);
195
196 if (!openssl_hash_chunk(hash_type, data, &hash))
197 {
198 return FALSE;
199 }
200 success = build_signature(this, hash, signature);
201 chunk_free(&hash);
202 }
203 return success;
204 }
205
206 /**
207 * Implementation of private_key_t.destroy.
208 */
209 static bool decrypt(private_openssl_ec_private_key_t *this,
210 chunk_t crypto, chunk_t *plain)
211 {
212 DBG1("EC private key decryption not implemented");
213 return FALSE;
214 }
215
216 /**
217 * Implementation of private_key_t.get_keysize.
218 */
219 static size_t get_keysize(private_openssl_ec_private_key_t *this)
220 {
221 return EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec));
222 }
223
224 /**
225 * Implementation of private_key_t.get_id.
226 */
227 static identification_t* get_id(private_openssl_ec_private_key_t *this,
228 id_type_t type)
229 {
230 switch (type)
231 {
232 case ID_PUBKEY_INFO_SHA1:
233 return this->keyid_info;
234 case ID_PUBKEY_SHA1:
235 return this->keyid;
236 default:
237 return NULL;
238 }
239 }
240
241 /**
242 * Implementation of private_key_t.get_public_key.
243 */
244 static openssl_ec_public_key_t* get_public_key(private_openssl_ec_private_key_t *this)
245 {
246 return openssl_ec_public_key_create_from_private_key(this->ec);
247 }
248
249 /**
250 * Implementation of private_key_t.belongs_to.
251 */
252 static bool belongs_to(private_openssl_ec_private_key_t *this, public_key_t *public)
253 {
254 identification_t *keyid;
255
256 if (public->get_type(public) != KEY_ECDSA)
257 {
258 return FALSE;
259 }
260 keyid = public->get_id(public, ID_PUBKEY_SHA1);
261 if (keyid && keyid->equals(keyid, this->keyid))
262 {
263 return TRUE;
264 }
265 keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
266 if (keyid && keyid->equals(keyid, this->keyid_info))
267 {
268 return TRUE;
269 }
270 return FALSE;
271 }
272
273 /**
274 * Implementation of private_key_t.get_encoding.
275 */
276 static chunk_t get_encoding(private_openssl_ec_private_key_t *this)
277 {
278 chunk_t enc = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL));
279 u_char *p = enc.ptr;
280 i2d_ECPrivateKey(this->ec, &p);
281 return enc;
282 }
283
284 /**
285 * Implementation of private_key_t.get_ref.
286 */
287 static private_openssl_ec_private_key_t* get_ref(private_openssl_ec_private_key_t *this)
288 {
289 ref_get(&this->ref);
290 return this;
291
292 }
293
294 /**
295 * Implementation of private_key_t.destroy.
296 */
297 static void destroy(private_openssl_ec_private_key_t *this)
298 {
299 if (ref_put(&this->ref))
300 {
301 if (this->ec)
302 {
303 EC_KEY_free(this->ec);
304 }
305 DESTROY_IF(this->keyid);
306 DESTROY_IF(this->keyid_info);
307 free(this);
308 }
309 }
310
311 /**
312 * Internal generic constructor
313 */
314 static private_openssl_ec_private_key_t *openssl_ec_private_key_create_empty(void)
315 {
316 private_openssl_ec_private_key_t *this = malloc_thing(private_openssl_ec_private_key_t);
317
318 this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
319 this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
320 this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
321 this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
322 this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
323 this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
324 this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
325 this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
326 this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
327 this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
328
329 this->ec = NULL;
330 this->keyid = NULL;
331 this->keyid_info = NULL;
332 this->ref = 1;
333
334 return this;
335 }
336
337 /**
338 * load private key from an ASN1 encoded blob
339 */
340 static openssl_ec_private_key_t *load(chunk_t blob)
341 {
342 u_char *p = blob.ptr;
343 private_openssl_ec_private_key_t *this = openssl_ec_private_key_create_empty();
344
345 this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&p, blob.len);
346
347 chunk_clear(&blob);
348
349 if (!this->ec)
350 {
351 destroy(this);
352 return NULL;
353 }
354
355 if (!openssl_ec_public_key_build_id(this->ec, &this->keyid, &this->keyid_info))
356 {
357 destroy(this);
358 return NULL;
359 }
360
361 if (!EC_KEY_check_key(this->ec))
362 {
363 destroy(this);
364 return NULL;
365 }
366
367 return &this->public;
368 }
369
370 typedef struct private_builder_t private_builder_t;
371 /**
372 * Builder implementation for key loading/generation
373 */
374 struct private_builder_t {
375 /** implements the builder interface */
376 builder_t public;
377 /** loaded/generated private key */
378 openssl_ec_private_key_t *key;
379 };
380
381 /**
382 * Implementation of builder_t.build
383 */
384 static openssl_ec_private_key_t *build(private_builder_t *this)
385 {
386 openssl_ec_private_key_t *key = this->key;
387
388 free(this);
389 return key;
390 }
391
392 /**
393 * Implementation of builder_t.add
394 */
395 static void add(private_builder_t *this, builder_part_t part, ...)
396 {
397 if (!this->key)
398 {
399 va_list args;
400 chunk_t chunk;
401
402 switch (part)
403 {
404 case BUILD_BLOB_ASN1_DER:
405 {
406 va_start(args, part);
407 chunk = va_arg(args, chunk_t);
408 this->key = load(chunk_clone(chunk));
409 va_end(args);
410 return;
411 }
412 default:
413 break;
414 }
415 }
416 if (this->key)
417 {
418 destroy((private_openssl_ec_private_key_t*)this->key);
419 }
420 builder_cancel(&this->public);
421 }
422
423 /**
424 * Builder construction function
425 */
426 builder_t *openssl_ec_private_key_builder(key_type_t type)
427 {
428 private_builder_t *this;
429
430 if (type != KEY_ECDSA)
431 {
432 return NULL;
433 }
434
435 this = malloc_thing(private_builder_t);
436
437 this->key = NULL;
438 this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
439 this->public.build = (void*(*)(builder_t *this))build;
440
441 return &this->public;
442 }
443