]> git.ipfire.org Git - thirdparty/strongswan.git/blame_incremental - src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
nm: Don't set DL_LIBS to 'none required' in configure script
[thirdparty/strongswan.git] / src / libstrongswan / plugins / openssl / openssl_ec_public_key.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
4 *
5 * Copyright (C) secunet Security Networks AG
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.
16 */
17
18#include <openssl/opensslconf.h>
19
20#ifndef OPENSSL_NO_ECDSA
21
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 >= 0x30000000L
32#include <openssl/core_names.h>
33#endif
34
35#if OPENSSL_VERSION_NUMBER < 0x10100000L
36OPENSSL_KEY_FALLBACK(ECDSA_SIG, r, s)
37#endif
38
39typedef struct private_openssl_ec_public_key_t private_openssl_ec_public_key_t;
40
41/**
42 * Private data structure with signing context.
43 */
44struct private_openssl_ec_public_key_t {
45 /**
46 * Public interface for this signer.
47 */
48 openssl_ec_public_key_t public;
49
50 /**
51 * EC key object
52 */
53 EVP_PKEY *key;
54
55 /**
56 * reference counter
57 */
58 refcount_t ref;
59};
60
61/**
62 * Verification of a DER encoded signature as in RFC 3279
63 */
64static bool verify_der_signature(private_openssl_ec_public_key_t *this,
65 int nid_hash, chunk_t data, chunk_t signature)
66{
67 EVP_MD_CTX *ctx;
68 const EVP_MD *md;
69
70 /* remove any preceding 0-bytes from signature */
71 while (signature.len && signature.ptr[0] == 0x00)
72 {
73 signature = chunk_skip(signature, 1);
74 }
75 md = EVP_get_digestbynid(nid_hash);
76 if (!md)
77 {
78 return FALSE;
79 }
80 ctx = EVP_MD_CTX_create();
81 if (!ctx ||
82 EVP_DigestVerifyInit(ctx, NULL, md, NULL, this->key) <= 0 ||
83 EVP_DigestVerifyUpdate(ctx, data.ptr, data.len) <= 0 ||
84 EVP_DigestVerifyFinal(ctx, signature.ptr, signature.len) != 1)
85 {
86 EVP_MD_CTX_destroy(ctx);
87 return FALSE;
88 }
89 EVP_MD_CTX_destroy(ctx);
90 return TRUE;
91}
92
93/**
94 * Verification of a signature as in RFC 4754
95 */
96static bool verify_signature(private_openssl_ec_public_key_t *this,
97 int nid_hash, chunk_t data, chunk_t signature)
98{
99 EVP_PKEY_CTX *ctx;
100 BIGNUM *r, *s;
101 ECDSA_SIG *sig;
102 chunk_t der_sig;
103 bool valid = FALSE;
104
105 sig = ECDSA_SIG_new();
106 if (sig)
107 {
108 r = BN_new();
109 s = BN_new();
110 if (!openssl_bn_split(signature, r, s))
111 {
112 BN_free(r);
113 BN_free(s);
114 ECDSA_SIG_free(sig);
115 return FALSE;
116 }
117 if (ECDSA_SIG_set0(sig, r, s))
118 {
119 der_sig = openssl_i2chunk(ECDSA_SIG, sig);
120 if (!nid_hash)
121 { /* EVP_DigestVerify*() has issues with NULL EVP_MD */
122 ctx = EVP_PKEY_CTX_new(this->key, NULL);
123 valid = ctx && EVP_PKEY_verify_init(ctx) > 0 &&
124 EVP_PKEY_verify(ctx, der_sig.ptr, der_sig.len,
125 data.ptr, data.len) > 0;
126 EVP_PKEY_CTX_free(ctx);
127 }
128 else
129 {
130 valid = verify_der_signature(this, nid_hash, data, der_sig);
131 }
132 chunk_free(&der_sig);
133 }
134 ECDSA_SIG_free(sig);
135 }
136 return valid;
137}
138
139/**
140 * Check that the given key's curve matches a specific one. Also used by
141 * private key.
142 */
143bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve)
144{
145 EC_GROUP *req_group, *my_group = NULL;
146 bool matches = FALSE;
147
148 req_group = EC_GROUP_new_by_curve_name(nid_curve);
149 if (!req_group)
150 {
151 goto error;
152 }
153
154#if OPENSSL_VERSION_NUMBER >= 0x30000000L
155 char name[BUF_LEN];
156 OSSL_PARAM params[] = {
157 OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, name, sizeof(name)),
158 OSSL_PARAM_END,
159 };
160
161 if (!EVP_PKEY_get_group_name(key, name, sizeof(name), NULL))
162 {
163 goto error;
164 }
165 my_group = EC_GROUP_new_from_params(params, NULL, NULL);
166#elif OPENSSL_VERSION_NUMBER >= 0x1010000fL
167 EC_KEY *ec = EVP_PKEY_get0_EC_KEY(key);
168 my_group = EC_GROUP_dup(EC_KEY_get0_group(ec));
169#else
170 EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
171 my_group = EC_GROUP_dup(EC_KEY_get0_group(ec));
172 EC_KEY_free(ec);
173#endif
174
175 if (EC_GROUP_cmp(my_group, req_group, NULL) == 0)
176 {
177 matches = TRUE;
178 }
179
180error:
181 EC_GROUP_free(my_group);
182 EC_GROUP_free(req_group);
183 return matches;
184}
185
186/**
187 * Verify a RFC 4754 signature for a specified curve and hash algorithm
188 */
189static bool verify_curve_signature(private_openssl_ec_public_key_t *this,
190 signature_scheme_t scheme, int nid_hash,
191 int nid_curve, chunk_t data, chunk_t signature)
192{
193 if (!openssl_check_ec_key_curve(this->key, nid_curve))
194 {
195 DBG1(DBG_LIB, "signature scheme %N not supported by key",
196 signature_scheme_names, scheme);
197 return FALSE;
198 }
199 return verify_signature(this, nid_hash, data, signature);
200}
201
202METHOD(public_key_t, get_type, key_type_t,
203 private_openssl_ec_public_key_t *this)
204{
205 return KEY_ECDSA;
206}
207
208METHOD(public_key_t, verify, bool,
209 private_openssl_ec_public_key_t *this, signature_scheme_t scheme,
210 void *params, chunk_t data, chunk_t signature)
211{
212 switch (scheme)
213 {
214 case SIGN_ECDSA_WITH_SHA1_DER:
215 return verify_der_signature(this, NID_sha1, data, signature);
216 case SIGN_ECDSA_WITH_SHA256_DER:
217 return verify_der_signature(this, NID_sha256, data, signature);
218 case SIGN_ECDSA_WITH_SHA384_DER:
219 return verify_der_signature(this, NID_sha384, data, signature);
220 case SIGN_ECDSA_WITH_SHA512_DER:
221 return verify_der_signature(this, NID_sha512, data, signature);
222 case SIGN_ECDSA_WITH_NULL:
223 return verify_signature(this, 0, data, signature);
224 case SIGN_ECDSA_256:
225 return verify_curve_signature(this, scheme, NID_sha256,
226 NID_X9_62_prime256v1, data, signature);
227 case SIGN_ECDSA_384:
228 return verify_curve_signature(this, scheme, NID_sha384,
229 NID_secp384r1, data, signature);
230 case SIGN_ECDSA_521:
231 return verify_curve_signature(this, scheme, NID_sha512,
232 NID_secp521r1, data, signature);
233 default:
234 DBG1(DBG_LIB, "signature scheme %N not supported in EC",
235 signature_scheme_names, scheme);
236 return FALSE;
237 }
238}
239
240METHOD(public_key_t, encrypt, bool,
241 private_openssl_ec_public_key_t *this, encryption_scheme_t scheme,
242 void *params, chunk_t crypto, chunk_t *plain)
243{
244 DBG1(DBG_LIB, "EC public key encryption not implemented");
245 return FALSE;
246}
247
248METHOD(public_key_t, get_keysize, int,
249 private_openssl_ec_public_key_t *this)
250{
251 return EVP_PKEY_bits(this->key);
252}
253
254METHOD(public_key_t, get_fingerprint, bool,
255 private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
256 chunk_t *fingerprint)
257{
258 return openssl_fingerprint(this->key, type, fingerprint);
259}
260
261METHOD(public_key_t, get_encoding, bool,
262 private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
263 chunk_t *encoding)
264{
265 bool success = TRUE;
266
267 *encoding = openssl_i2chunk(PUBKEY, this->key);
268
269 if (type != PUBKEY_SPKI_ASN1_DER)
270 {
271 chunk_t asn1_encoding = *encoding;
272
273 success = lib->encoding->encode(lib->encoding, type,
274 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
275 asn1_encoding, CRED_PART_END);
276 chunk_clear(&asn1_encoding);
277 }
278 return success;
279}
280
281METHOD(public_key_t, get_ref, public_key_t*,
282 private_openssl_ec_public_key_t *this)
283{
284 ref_get(&this->ref);
285 return &this->public.key;
286}
287
288METHOD(public_key_t, destroy, void,
289 private_openssl_ec_public_key_t *this)
290{
291 if (ref_put(&this->ref))
292 {
293 if (this->key)
294 {
295 lib->encoding->clear_cache(lib->encoding, this->key);
296 EVP_PKEY_free(this->key);
297 }
298 free(this);
299 }
300}
301
302/**
303 * Check whether the EC key was decoded with explicit curve parameters instead
304 * of a named curve.
305 */
306bool openssl_check_explicit_params(const EVP_PKEY *key)
307{
308 int explicit = 0;
309
310#if OPENSSL_VERSION_NUMBER >= 0x30000000L
311 if (!EVP_PKEY_get_int_param(key, OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS,
312 &explicit))
313 {
314 return FALSE;
315 }
316#elif OPENSSL_VERSION_NUMBER >= 0x1010108fL
317 explicit = EC_KEY_decoded_from_explicit_params(EVP_PKEY_get0_EC_KEY((EVP_PKEY*)key));
318#endif
319 return explicit == 1;
320}
321
322/**
323 * See header.
324 */
325openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
326 va_list args)
327{
328 private_openssl_ec_public_key_t *this;
329 chunk_t blob = chunk_empty;
330 EVP_PKEY *key;
331
332 while (TRUE)
333 {
334 switch (va_arg(args, builder_part_t))
335 {
336 case BUILD_BLOB_ASN1_DER:
337 blob = va_arg(args, chunk_t);
338 continue;
339 case BUILD_END:
340 break;
341 default:
342 return NULL;
343 }
344 break;
345 }
346 key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
347 if (!key || EVP_PKEY_base_id(key) != EVP_PKEY_EC ||
348 openssl_check_explicit_params(key))
349 {
350 EVP_PKEY_free(key);
351 return NULL;
352 }
353
354 INIT(this,
355 .public = {
356 .key = {
357 .get_type = _get_type,
358 .verify = _verify,
359 .encrypt = _encrypt,
360 .get_keysize = _get_keysize,
361 .equals = public_key_equals,
362 .get_fingerprint = _get_fingerprint,
363 .has_fingerprint = public_key_has_fingerprint,
364 .get_encoding = _get_encoding,
365 .get_ref = _get_ref,
366 .destroy = _destroy,
367 },
368 },
369 .ref = 1,
370 .key = key,
371 );
372 return &this->public;
373}
374
375#endif /* OPENSSL_NO_ECDSA */