Use bits instead of bytes for a private/public key
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_ec_private_key.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
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_EC
20
21 #include "openssl_ec_private_key.h"
22 #include "openssl_ec_public_key.h"
23 #include "openssl_util.h"
24
25 #include <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.key = {
290 .get_type = _get_type,
291 .sign = _sign,
292 .decrypt = _decrypt,
293 .get_keysize = _get_keysize,
294 .get_public_key = _get_public_key,
295 .equals = private_key_equals,
296 .belongs_to = private_key_belongs_to,
297 .get_fingerprint = _get_fingerprint,
298 .has_fingerprint = private_key_has_fingerprint,
299 .get_encoding = _get_encoding,
300 .get_ref = _get_ref,
301 .destroy = _destroy,
302 },
303 .ref = 1,
304 );
305
306 return this;
307 }
308
309 /**
310 * See header.
311 */
312 openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type,
313 va_list args)
314 {
315 private_openssl_ec_private_key_t *this;
316 u_int key_size = 0;
317
318 while (TRUE)
319 {
320 switch (va_arg(args, builder_part_t))
321 {
322 case BUILD_KEY_SIZE:
323 key_size = va_arg(args, u_int);
324 continue;
325 case BUILD_END:
326 break;
327 default:
328 return NULL;
329 }
330 break;
331 }
332 if (!key_size)
333 {
334 return NULL;
335 }
336 this = create_empty();
337 switch (key_size)
338 {
339 case 256:
340 this->ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
341 break;
342 case 384:
343 this->ec = EC_KEY_new_by_curve_name(NID_secp384r1);
344 break;
345 case 521:
346 this->ec = EC_KEY_new_by_curve_name(NID_secp521r1);
347 break;
348 default:
349 DBG1(DBG_LIB, "EC private key size %d not supported", key_size);
350 destroy(this);
351 return NULL;
352 }
353 if (EC_KEY_generate_key(this->ec) != 1)
354 {
355 DBG1(DBG_LIB, "EC private key generation failed", key_size);
356 destroy(this);
357 return NULL;
358 }
359 /* encode as a named curve key (no parameters), uncompressed public key */
360 EC_KEY_set_asn1_flag(this->ec, OPENSSL_EC_NAMED_CURVE);
361 EC_KEY_set_conv_form(this->ec, POINT_CONVERSION_UNCOMPRESSED);
362 return &this->public;
363 }
364
365 /**
366 * See header.
367 */
368 openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
369 va_list args)
370 {
371 private_openssl_ec_private_key_t *this;
372 chunk_t blob = chunk_empty;
373
374 while (TRUE)
375 {
376 switch (va_arg(args, builder_part_t))
377 {
378 case BUILD_BLOB_ASN1_DER:
379 blob = va_arg(args, chunk_t);
380 continue;
381 case BUILD_END:
382 break;
383 default:
384 return NULL;
385 }
386 break;
387 }
388
389 this = create_empty();
390 this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&blob.ptr, blob.len);
391 if (!this->ec)
392 {
393 destroy(this);
394 return NULL;
395 }
396 if (!EC_KEY_check_key(this->ec))
397 {
398 destroy(this);
399 return NULL;
400 }
401 return &this->public;
402 }
403 #endif /* OPENSSL_NO_EC */
404