]>
Commit | Line | Data |
---|---|---|
ea0823df | 1 | /* |
4a6f97d0 | 2 | * Copyright (C) 2008-2016 Tobias Brunner |
e35c3e2a | 3 | * Copyright (C) 2009 Martin Willi |
19ef2aec TB |
4 | * |
5 | * Copyright (C) secunet Security Networks AG | |
ea0823df TB |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
ea0823df TB |
16 | */ |
17 | ||
5a367e99 TB |
18 | #include <openssl/opensslconf.h> |
19 | ||
a3a190b7 | 20 | #ifndef OPENSSL_NO_ECDSA |
5a367e99 | 21 | |
ea0823df TB |
22 | #include "openssl_ec_private_key.h" |
23 | #include "openssl_ec_public_key.h" | |
24 | #include "openssl_util.h" | |
25 | ||
f05b4272 | 26 | #include <utils/debug.h> |
ea0823df TB |
27 | |
28 | #include <openssl/evp.h> | |
29 | #include <openssl/ecdsa.h> | |
e35c3e2a | 30 | #include <openssl/x509.h> |
ea0823df | 31 | |
6688f798 TB |
32 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
33 | OPENSSL_KEY_FALLBACK(ECDSA_SIG, r, s) | |
34 | #endif | |
35 | ||
ea0823df TB |
36 | typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t; |
37 | ||
38 | /** | |
39 | * Private data of a openssl_ec_private_key_t object. | |
40 | */ | |
41 | struct private_openssl_ec_private_key_t { | |
42 | /** | |
43 | * Public interface for this signer. | |
44 | */ | |
45 | openssl_ec_private_key_t public; | |
7daf5226 | 46 | |
ea0823df TB |
47 | /** |
48 | * EC key object | |
49 | */ | |
293a912c | 50 | EVP_PKEY *key; |
7daf5226 | 51 | |
b2266280 TB |
52 | /** |
53 | * TRUE if the key is from an OpenSSL ENGINE and might not be readable | |
54 | */ | |
55 | bool engine; | |
56 | ||
ea0823df TB |
57 | /** |
58 | * reference count | |
59 | */ | |
472cb4ce | 60 | refcount_t ref; |
ea0823df TB |
61 | }; |
62 | ||
293a912c TB |
63 | /* from openssl_ec_public_key */ |
64 | bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve); | |
65 | ||
66 | /** | |
67 | * Build a DER encoded signature as in RFC 3279 | |
68 | */ | |
69 | static bool build_der_signature(private_openssl_ec_private_key_t *this, | |
70 | int nid_hash, chunk_t data, chunk_t *signature) | |
71 | { | |
72 | EVP_MD_CTX *ctx; | |
73 | const EVP_MD *md; | |
74 | ||
75 | md = EVP_get_digestbynid(nid_hash); | |
76 | if (!md) | |
77 | { | |
78 | return FALSE; | |
79 | } | |
80 | *signature = chunk_alloc(EVP_PKEY_size(this->key)); | |
81 | ctx = EVP_MD_CTX_create(); | |
82 | if (!ctx || | |
83 | EVP_DigestSignInit(ctx, NULL, md, NULL, this->key) <= 0 || | |
84 | EVP_DigestSignUpdate(ctx, data.ptr, data.len) <= 0 || | |
85 | EVP_DigestSignFinal(ctx, signature->ptr, &signature->len) != 1) | |
86 | { | |
87 | chunk_free(signature); | |
88 | EVP_MD_CTX_destroy(ctx); | |
89 | return FALSE; | |
90 | } | |
91 | EVP_MD_CTX_destroy(ctx); | |
92 | return TRUE; | |
93 | } | |
b12c6d16 | 94 | |
ea0823df | 95 | /** |
472cb4ce | 96 | * Build a signature as in RFC 4754 |
ea0823df TB |
97 | */ |
98 | static bool build_signature(private_openssl_ec_private_key_t *this, | |
293a912c | 99 | int nid_hash, chunk_t data, chunk_t *signature) |
ea0823df | 100 | { |
293a912c | 101 | EVP_PKEY_CTX *ctx; |
e35c3e2a | 102 | ECDSA_SIG *sig; |
293a912c TB |
103 | const BIGNUM *r, *s; |
104 | const u_char *p; | |
105 | chunk_t der_sig; | |
6688f798 | 106 | bool built = FALSE; |
7daf5226 | 107 | |
293a912c TB |
108 | if (!nid_hash) |
109 | { /* EVP_DigestSign*() has issues with NULL EVP_MD */ | |
110 | der_sig = chunk_alloc(EVP_PKEY_size(this->key)); | |
111 | ctx = EVP_PKEY_CTX_new(this->key, NULL); | |
112 | if (!ctx || | |
113 | EVP_PKEY_sign_init(ctx) <= 0 || | |
114 | EVP_PKEY_sign(ctx, der_sig.ptr, &der_sig.len, data.ptr, data.len) <= 0) | |
115 | { | |
116 | chunk_free(&der_sig); | |
117 | EVP_PKEY_CTX_free(ctx); | |
118 | return FALSE; | |
119 | } | |
120 | EVP_PKEY_CTX_free(ctx); | |
121 | } | |
122 | else if (!build_der_signature(this, nid_hash, data, &der_sig)) | |
123 | { | |
124 | return FALSE; | |
125 | } | |
126 | /* extract r and s from the DER-encoded signature */ | |
127 | p = der_sig.ptr; | |
128 | sig = d2i_ECDSA_SIG(NULL, &p, der_sig.len); | |
129 | chunk_free(&der_sig); | |
472cb4ce | 130 | if (sig) |
ea0823df | 131 | { |
6688f798 | 132 | ECDSA_SIG_get0(sig, &r, &s); |
472cb4ce | 133 | /* concatenate BNs r/s to a signature chunk */ |
293a912c | 134 | built = openssl_bn_cat((EVP_PKEY_bits(this->key) + 7) / 8, |
6688f798 | 135 | r, s, signature); |
472cb4ce | 136 | ECDSA_SIG_free(sig); |
ea0823df | 137 | } |
472cb4ce | 138 | return built; |
ea0823df TB |
139 | } |
140 | ||
141 | /** | |
472cb4ce | 142 | * Build a RFC 4754 signature for a specified curve and hash algorithm |
ea0823df | 143 | */ |
472cb4ce MW |
144 | static bool build_curve_signature(private_openssl_ec_private_key_t *this, |
145 | signature_scheme_t scheme, int nid_hash, | |
146 | int nid_curve, chunk_t data, chunk_t *signature) | |
ea0823df | 147 | { |
293a912c | 148 | if (!openssl_check_ec_key_curve(this->key, nid_curve)) |
472cb4ce | 149 | { |
293a912c | 150 | DBG1(DBG_LIB, "signature scheme %N not supported by key", |
472cb4ce MW |
151 | signature_scheme_names, scheme); |
152 | return FALSE; | |
153 | } | |
293a912c | 154 | return build_signature(this, nid_hash, data, signature); |
472cb4ce MW |
155 | } |
156 | ||
57202484 MW |
157 | METHOD(private_key_t, sign, bool, |
158 | private_openssl_ec_private_key_t *this, signature_scheme_t scheme, | |
de280c2e | 159 | void *params, chunk_t data, chunk_t *signature) |
472cb4ce MW |
160 | { |
161 | switch (scheme) | |
162 | { | |
163 | case SIGN_ECDSA_WITH_NULL: | |
293a912c | 164 | return build_signature(this, 0, data, signature); |
472cb4ce MW |
165 | case SIGN_ECDSA_WITH_SHA1_DER: |
166 | return build_der_signature(this, NID_sha1, data, signature); | |
167 | case SIGN_ECDSA_WITH_SHA256_DER: | |
168 | return build_der_signature(this, NID_sha256, data, signature); | |
169 | case SIGN_ECDSA_WITH_SHA384_DER: | |
170 | return build_der_signature(this, NID_sha384, data, signature); | |
171 | case SIGN_ECDSA_WITH_SHA512_DER: | |
172 | return build_der_signature(this, NID_sha512, data, signature); | |
173 | case SIGN_ECDSA_256: | |
7daf5226 | 174 | return build_curve_signature(this, scheme, NID_sha256, |
1dbaec21 | 175 | NID_X9_62_prime256v1, data, signature); |
472cb4ce | 176 | case SIGN_ECDSA_384: |
1dbaec21 AS |
177 | return build_curve_signature(this, scheme, NID_sha384, |
178 | NID_secp384r1, data, signature); | |
472cb4ce | 179 | case SIGN_ECDSA_521: |
1dbaec21 AS |
180 | return build_curve_signature(this, scheme, NID_sha512, |
181 | NID_secp521r1, data, signature); | |
472cb4ce | 182 | default: |
8b0e0910 | 183 | DBG1(DBG_LIB, "signature scheme %N not supported", |
472cb4ce | 184 | signature_scheme_names, scheme); |
11e6d285 | 185 | return FALSE; |
472cb4ce | 186 | } |
ea0823df TB |
187 | } |
188 | ||
57202484 | 189 | METHOD(private_key_t, decrypt, bool, |
33ddaaab | 190 | private_openssl_ec_private_key_t *this, encryption_scheme_t scheme, |
4abb29f6 | 191 | void *params, chunk_t crypto, chunk_t *plain) |
ea0823df | 192 | { |
8b0e0910 | 193 | DBG1(DBG_LIB, "EC private key decryption not implemented"); |
ea0823df TB |
194 | return FALSE; |
195 | } | |
196 | ||
a944d209 | 197 | METHOD(private_key_t, get_keysize, int, |
57202484 | 198 | private_openssl_ec_private_key_t *this) |
ea0823df | 199 | { |
293a912c | 200 | return EVP_PKEY_bits(this->key); |
ea0823df TB |
201 | } |
202 | ||
57202484 MW |
203 | METHOD(private_key_t, get_type, key_type_t, |
204 | private_openssl_ec_private_key_t *this) | |
472cb4ce MW |
205 | { |
206 | return KEY_ECDSA; | |
207 | } | |
208 | ||
57202484 MW |
209 | METHOD(private_key_t, get_public_key, public_key_t*, |
210 | private_openssl_ec_private_key_t *this) | |
ea0823df | 211 | { |
e35c3e2a MW |
212 | public_key_t *public; |
213 | chunk_t key; | |
7daf5226 | 214 | |
293a912c | 215 | key = openssl_i2chunk(PUBKEY, this->key); |
e35c3e2a MW |
216 | public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, |
217 | BUILD_BLOB_ASN1_DER, key, BUILD_END); | |
218 | free(key.ptr); | |
219 | return public; | |
ea0823df TB |
220 | } |
221 | ||
57202484 MW |
222 | METHOD(private_key_t, get_fingerprint, bool, |
223 | private_openssl_ec_private_key_t *this, cred_encoding_type_t type, | |
224 | chunk_t *fingerprint) | |
ea0823df | 225 | { |
293a912c | 226 | return openssl_fingerprint(this->key, type, fingerprint); |
ea0823df TB |
227 | } |
228 | ||
57202484 MW |
229 | METHOD(private_key_t, get_encoding, bool, |
230 | private_openssl_ec_private_key_t *this, cred_encoding_type_t type, | |
231 | chunk_t *encoding) | |
ea0823df | 232 | { |
b2266280 TB |
233 | if (this->engine) |
234 | { | |
235 | return FALSE; | |
236 | } | |
b12c6d16 MW |
237 | switch (type) |
238 | { | |
da9724e6 MW |
239 | case PRIVKEY_ASN1_DER: |
240 | case PRIVKEY_PEM: | |
b12c6d16 | 241 | { |
29cf15a9 AS |
242 | bool success = TRUE; |
243 | ||
293a912c | 244 | *encoding = openssl_i2chunk(PrivateKey, this->key); |
29cf15a9 | 245 | |
da9724e6 | 246 | if (type == PRIVKEY_PEM) |
29cf15a9 AS |
247 | { |
248 | chunk_t asn1_encoding = *encoding; | |
249 | ||
da9724e6 MW |
250 | success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM, |
251 | NULL, encoding, CRED_PART_ECDSA_PRIV_ASN1_DER, | |
252 | asn1_encoding, CRED_PART_END); | |
29cf15a9 | 253 | chunk_clear(&asn1_encoding); |
0a4dc787 | 254 | } |
29cf15a9 | 255 | return success; |
b12c6d16 MW |
256 | } |
257 | default: | |
258 | return FALSE; | |
259 | } | |
ea0823df TB |
260 | } |
261 | ||
57202484 MW |
262 | METHOD(private_key_t, get_ref, private_key_t*, |
263 | private_openssl_ec_private_key_t *this) | |
ea0823df TB |
264 | { |
265 | ref_get(&this->ref); | |
57202484 | 266 | return &this->public.key; |
ea0823df TB |
267 | } |
268 | ||
57202484 MW |
269 | METHOD(private_key_t, destroy, void, |
270 | private_openssl_ec_private_key_t *this) | |
ea0823df TB |
271 | { |
272 | if (ref_put(&this->ref)) | |
273 | { | |
293a912c | 274 | if (this->key) |
ea0823df | 275 | { |
293a912c TB |
276 | lib->encoding->clear_cache(lib->encoding, this->key); |
277 | EVP_PKEY_free(this->key); | |
ea0823df | 278 | } |
ea0823df TB |
279 | free(this); |
280 | } | |
281 | } | |
282 | ||
283 | /** | |
284 | * Internal generic constructor | |
285 | */ | |
293a912c | 286 | static private_openssl_ec_private_key_t *create_internal(EVP_PKEY *key) |
ea0823df | 287 | { |
57202484 MW |
288 | private_openssl_ec_private_key_t *this; |
289 | ||
290 | INIT(this, | |
ba31fe1f MW |
291 | .public = { |
292 | .key = { | |
293 | .get_type = _get_type, | |
294 | .sign = _sign, | |
295 | .decrypt = _decrypt, | |
296 | .get_keysize = _get_keysize, | |
297 | .get_public_key = _get_public_key, | |
298 | .equals = private_key_equals, | |
299 | .belongs_to = private_key_belongs_to, | |
300 | .get_fingerprint = _get_fingerprint, | |
301 | .has_fingerprint = private_key_has_fingerprint, | |
302 | .get_encoding = _get_encoding, | |
303 | .get_ref = _get_ref, | |
304 | .destroy = _destroy, | |
305 | }, | |
57202484 MW |
306 | }, |
307 | .ref = 1, | |
293a912c | 308 | .key = key, |
57202484 | 309 | ); |
7daf5226 | 310 | |
ea0823df TB |
311 | return this; |
312 | } | |
313 | ||
4a6f97d0 TB |
314 | /* |
315 | * See header. | |
316 | */ | |
b2266280 | 317 | private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine) |
4a6f97d0 TB |
318 | { |
319 | private_openssl_ec_private_key_t *this; | |
4a6f97d0 | 320 | |
293a912c | 321 | if (EVP_PKEY_base_id(key) != EVP_PKEY_EC) |
4a6f97d0 | 322 | { |
293a912c | 323 | EVP_PKEY_free(key); |
4a6f97d0 TB |
324 | return NULL; |
325 | } | |
293a912c | 326 | this = create_internal(key); |
b2266280 | 327 | this->engine = engine; |
4a6f97d0 TB |
328 | return &this->public.key; |
329 | } | |
330 | ||
331 | /* | |
30c06407 | 332 | * See header. |
08ed551c | 333 | */ |
30c06407 MW |
334 | openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type, |
335 | va_list args) | |
08ed551c | 336 | { |
30c06407 | 337 | private_openssl_ec_private_key_t *this; |
293a912c | 338 | EVP_PKEY *key = NULL; |
30c06407 | 339 | u_int key_size = 0; |
7daf5226 | 340 | |
30c06407 MW |
341 | while (TRUE) |
342 | { | |
343 | switch (va_arg(args, builder_part_t)) | |
344 | { | |
345 | case BUILD_KEY_SIZE: | |
346 | key_size = va_arg(args, u_int); | |
347 | continue; | |
348 | case BUILD_END: | |
349 | break; | |
350 | default: | |
351 | return NULL; | |
352 | } | |
353 | break; | |
354 | } | |
355 | if (!key_size) | |
356 | { | |
357 | return NULL; | |
358 | } | |
293a912c TB |
359 | |
360 | #if OPENSSL_VERSION_NUMBER >= 0x30000000L | |
08ed551c MW |
361 | switch (key_size) |
362 | { | |
363 | case 256: | |
293a912c | 364 | key = EVP_EC_gen("P-256"); |
08ed551c MW |
365 | break; |
366 | case 384: | |
293a912c | 367 | key = EVP_EC_gen("P-384"); |
08ed551c MW |
368 | break; |
369 | case 521: | |
293a912c | 370 | key = EVP_EC_gen("P-521"); |
08ed551c MW |
371 | break; |
372 | default: | |
8b0e0910 | 373 | DBG1(DBG_LIB, "EC private key size %d not supported", key_size); |
08ed551c MW |
374 | return NULL; |
375 | } | |
293a912c TB |
376 | #else /* OPENSSL_VERSION_NUMBER */ |
377 | EC_KEY *ec; | |
378 | ||
379 | switch (key_size) | |
380 | { | |
381 | case 256: | |
382 | ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); | |
383 | break; | |
384 | case 384: | |
385 | ec = EC_KEY_new_by_curve_name(NID_secp384r1); | |
386 | break; | |
387 | case 521: | |
388 | ec = EC_KEY_new_by_curve_name(NID_secp521r1); | |
389 | break; | |
390 | default: | |
391 | DBG1(DBG_LIB, "EC private key size %d not supported", key_size); | |
392 | return NULL; | |
393 | } | |
394 | if (ec && EC_KEY_generate_key(ec) == 1) | |
395 | { | |
396 | key = EVP_PKEY_new(); | |
397 | if (!EVP_PKEY_assign_EC_KEY(key, ec)) | |
398 | { | |
399 | EC_KEY_free(ec); | |
400 | EVP_PKEY_free(key); | |
401 | key = NULL; | |
402 | } | |
403 | } | |
404 | #endif /* OPENSSL_VERSION_NUMBER */ | |
405 | ||
406 | if (!key) | |
08ed551c | 407 | { |
08ed551c MW |
408 | return NULL; |
409 | } | |
293a912c | 410 | this = create_internal(key); |
08ed551c MW |
411 | return &this->public; |
412 | } | |
413 | ||
ea0823df | 414 | /** |
30c06407 | 415 | * See header. |
ea0823df | 416 | */ |
30c06407 MW |
417 | openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, |
418 | va_list args) | |
ea0823df | 419 | { |
30c06407 | 420 | private_openssl_ec_private_key_t *this; |
293a912c TB |
421 | chunk_t par = chunk_empty, blob = chunk_empty; |
422 | EVP_PKEY *key = NULL; | |
7daf5226 | 423 | |
30c06407 | 424 | while (TRUE) |
ea0823df | 425 | { |
30c06407 | 426 | switch (va_arg(args, builder_part_t)) |
ea0823df | 427 | { |
27f8a61d TB |
428 | case BUILD_BLOB_ALGID_PARAMS: |
429 | par = va_arg(args, chunk_t); | |
430 | continue; | |
f7c17aa1 | 431 | case BUILD_BLOB_ASN1_DER: |
293a912c | 432 | blob = va_arg(args, chunk_t); |
30c06407 MW |
433 | continue; |
434 | case BUILD_END: | |
f7c17aa1 | 435 | break; |
30c06407 MW |
436 | default: |
437 | return NULL; | |
ea0823df | 438 | } |
30c06407 | 439 | break; |
ea0823df | 440 | } |
30c06407 | 441 | |
27f8a61d | 442 | if (par.ptr) |
f7c17aa1 | 443 | { |
293a912c TB |
444 | /* for OpenSSL 3, the combination of d2i_KeyParams/d2i_PrivateKey, which |
445 | * are intended to replace the functions below, does currently not work | |
446 | * because OpenSSL does not pass the internal EC_KEY that stores the | |
447 | * parameters from the first call to the call that parses the private | |
448 | * key. however, since parsing PKCS#8 is the only use case for this and | |
449 | * OpenSSL 3 parses this format directly, there isn't really any need | |
450 | * for it anyway */ | |
451 | #if OPENSSL_VERSION_NUMBER < 0x30000000L | |
452 | EC_KEY *ec; | |
453 | ||
454 | ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len); | |
455 | if (ec && d2i_ECPrivateKey(&ec, (const u_char**)&blob.ptr, blob.len)) | |
27f8a61d | 456 | { |
293a912c TB |
457 | key = EVP_PKEY_new(); |
458 | if (!EVP_PKEY_assign_EC_KEY(key, ec)) | |
459 | { | |
460 | EC_KEY_free(ec); | |
461 | EVP_PKEY_free(key); | |
462 | key = NULL; | |
463 | } | |
27f8a61d | 464 | } |
293a912c | 465 | else |
27f8a61d | 466 | { |
293a912c | 467 | EC_KEY_free(ec); |
27f8a61d | 468 | } |
293a912c | 469 | #endif |
27f8a61d TB |
470 | } |
471 | else | |
472 | { | |
293a912c TB |
473 | key = d2i_PrivateKey(EVP_PKEY_EC, NULL, (const u_char**)&blob.ptr, |
474 | blob.len); | |
f7c17aa1 | 475 | } |
293a912c TB |
476 | |
477 | if (!key) | |
ea0823df | 478 | { |
293a912c | 479 | return NULL; |
ea0823df | 480 | } |
293a912c | 481 | this = create_internal(key); |
ea0823df TB |
482 | return &this->public; |
483 | } | |
a3a190b7 | 484 | #endif /* OPENSSL_NO_ECDSA */ |