]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.c
wolfssl: Add wolfSSL plugin for cryptographic implementations
[thirdparty/strongswan.git] / src / libstrongswan / plugins / wolfssl / wolfssl_ec_public_key.c
1 /*
2 * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 #include "wolfssl_common.h"
24
25 #ifdef HAVE_ECC_VERIFY
26
27 #include "wolfssl_ec_public_key.h"
28 #include "wolfssl_util.h"
29
30 #include <utils/debug.h>
31
32 #include <wolfssl/wolfcrypt/ecc.h>
33 #include <wolfssl/wolfcrypt/hash.h>
34
35
36 typedef struct private_wolfssl_ec_public_key_t private_wolfssl_ec_public_key_t;
37
38 /**
39 * Private data structure with signing context.
40 */
41 struct private_wolfssl_ec_public_key_t {
42 /**
43 * Public interface for this signer.
44 */
45 wolfssl_ec_public_key_t public;
46
47 /**
48 * Key size
49 */
50 int keysize;
51
52 /**
53 * EC key object
54 */
55 ecc_key ec;
56
57 /**
58 * reference counter
59 */
60 refcount_t ref;
61 };
62
63 /**
64 * Verification of a signature as in RFC 4754
65 */
66 static bool verify_signature(private_wolfssl_ec_public_key_t *this,
67 chunk_t hash, chunk_t signature)
68 {
69 int stat = 1;
70 int ret = -1;
71 mp_int r, s;
72
73 if (mp_init(&r) < 0)
74 {
75 return FALSE;
76 }
77 if (mp_init(&s) < 0)
78 {
79 mp_free(&r);
80 return FALSE;
81 }
82
83 if (wolfssl_mp_split(signature, &r, &s))
84 {
85 ret = wc_ecc_verify_hash_ex(&r, &s, hash.ptr, hash.len, &stat,
86 &this->ec);
87 }
88
89 mp_free(&s);
90 mp_free(&r);
91
92 return ret == 0 && stat == 1;
93 }
94
95 /**
96 * Verify a RFC 4754 signature for a specified curve and hash algorithm
97 */
98 static bool verify_curve_signature(private_wolfssl_ec_public_key_t *this,
99 signature_scheme_t scheme, enum wc_HashType hash, ecc_curve_id curve_id,
100 chunk_t data, chunk_t signature)
101 {
102 bool success = FALSE;
103 chunk_t dgst;
104
105 if (curve_id != this->ec.dp->id)
106 {
107 DBG1(DBG_LIB, "signature scheme %N not supported by private key",
108 signature_scheme_names, scheme);
109 return FALSE;
110 }
111
112 if (wolfssl_hash_chunk(hash, data, &dgst))
113 {
114 success = verify_signature(this, dgst, signature);
115 }
116
117 chunk_free(&dgst);
118 return success;
119 }
120
121 /**
122 * Verification of a DER encoded signature as in RFC 3279
123 */
124 static bool verify_der_signature(private_wolfssl_ec_public_key_t *this,
125 enum wc_HashType hash, chunk_t data, chunk_t signature)
126 {
127 bool success = FALSE;
128 chunk_t dgst;
129 int stat = 1;
130 int ret;
131
132 /* remove any preceding 0-bytes from signature */
133 while (signature.len && signature.ptr[0] == 0x00)
134 {
135 signature = chunk_skip(signature, 1);
136 }
137 if (wolfssl_hash_chunk(hash, data, &dgst))
138 {
139 ret = wc_ecc_verify_hash(signature.ptr, signature.len, dgst.ptr,
140 dgst.len, &stat, &this->ec);
141 if (ret == 0 && stat == 1)
142 {
143 success = TRUE;
144 }
145 }
146
147 chunk_free(&dgst);
148 return success;
149 }
150
151 METHOD(public_key_t, get_type, key_type_t,
152 private_wolfssl_ec_public_key_t *this)
153 {
154 return KEY_ECDSA;
155 }
156
157 METHOD(public_key_t, verify, bool,
158 private_wolfssl_ec_public_key_t *this, signature_scheme_t scheme,
159 void *params, chunk_t data, chunk_t signature)
160 {
161 switch (scheme)
162 {
163 #ifndef NO_SHA
164 case SIGN_ECDSA_WITH_SHA1_DER:
165 return verify_der_signature(this, WC_HASH_TYPE_SHA, data,
166 signature);
167 #endif
168 #ifndef NO_SHA256
169 case SIGN_ECDSA_WITH_SHA256_DER:
170 return verify_der_signature(this, WC_HASH_TYPE_SHA256, data,
171 signature);
172 #endif
173 #ifdef WOLFSSL_SHA384
174 case SIGN_ECDSA_WITH_SHA384_DER:
175 return verify_der_signature(this, WC_HASH_TYPE_SHA384, data,
176 signature);
177 #endif
178 #ifdef WOLFSSL_SHA512
179 case SIGN_ECDSA_WITH_SHA512_DER:
180 return verify_der_signature(this, WC_HASH_TYPE_SHA512, data,
181 signature);
182 #endif
183 case SIGN_ECDSA_WITH_NULL:
184 return verify_signature(this, data, signature);
185 #ifndef NO_SHA256
186 case SIGN_ECDSA_256:
187 return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA256,
188 ECC_SECP256R1, data, signature);
189 #endif
190 #ifdef WOLFSSL_SHA384
191 case SIGN_ECDSA_384:
192 return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA384,
193 ECC_SECP384R1, data, signature);
194 #endif
195 #ifdef WOLFSSL_SHA512
196 case SIGN_ECDSA_521:
197 return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA512,
198 ECC_SECP521R1, data, signature);
199 #endif
200 default:
201 DBG1(DBG_LIB, "signature scheme %N not supported in EC",
202 signature_scheme_names, scheme);
203 return FALSE;
204 }
205 }
206
207 METHOD(public_key_t, encrypt, bool,
208 private_wolfssl_ec_public_key_t *this, encryption_scheme_t scheme,
209 chunk_t crypto, chunk_t *plain)
210 {
211 DBG1(DBG_LIB, "EC public key encryption not implemented");
212 return FALSE;
213 }
214
215 METHOD(public_key_t, get_keysize, int,
216 private_wolfssl_ec_public_key_t *this)
217 {
218 return this->keysize;
219 }
220
221 /**
222 * Calculate fingerprint from a EC_KEY, also used in ec private key.
223 */
224 bool wolfssl_ec_fingerprint(ecc_key *ec, cred_encoding_type_t type, chunk_t *fp)
225 {
226 hasher_t *hasher;
227 chunk_t key;
228 int ret;
229 bool success;
230
231 if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
232 {
233 return TRUE;
234 }
235
236 key = chunk_alloc(ec->dp->size * 4 + 30);
237 ret = wc_EccPublicKeyToDer(ec, key.ptr, key.len, 1);
238 if (ret < 0)
239 {
240 free(key.ptr);
241 return FALSE;
242 }
243 key.len = ret;
244
245 switch (type)
246 {
247 case KEYID_PUBKEY_SHA1:
248 break;
249 default:
250 success = lib->encoding->encode(lib->encoding, type, ec, fp,
251 CRED_PART_ECDSA_PUB_ASN1_DER, key,
252 CRED_PART_END);
253 chunk_free(&key);
254 return success;
255 }
256
257 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
258 if (!hasher || !hasher->allocate_hash(hasher, key, fp))
259 {
260 DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
261 DESTROY_IF(hasher);
262 free(key.ptr);
263 return FALSE;
264 }
265 hasher->destroy(hasher);
266 free(key.ptr);
267 lib->encoding->cache(lib->encoding, type, ec, *fp);
268 return TRUE;
269 }
270
271 METHOD(public_key_t, get_fingerprint, bool,
272 private_wolfssl_ec_public_key_t *this, cred_encoding_type_t type,
273 chunk_t *fingerprint)
274 {
275 return wolfssl_ec_fingerprint(&this->ec, type, fingerprint);
276 }
277
278 METHOD(public_key_t, get_encoding, bool,
279 private_wolfssl_ec_public_key_t *this, cred_encoding_type_t type,
280 chunk_t *encoding)
281 {
282 bool success = TRUE;
283 int ret;
284
285 *encoding = chunk_alloc(this->ec.dp->size * 2 + 30);
286 ret = wc_EccPublicKeyToDer(&this->ec, encoding->ptr, encoding->len, 1);
287 if (ret < 0)
288 {
289 chunk_free(encoding);
290 return FALSE;
291 }
292 encoding->len = ret;
293
294 if (type != PUBKEY_ASN1_DER)
295 {
296 chunk_t asn1_encoding = *encoding;
297
298 success = lib->encoding->encode(lib->encoding, type,
299 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
300 asn1_encoding, CRED_PART_END);
301 chunk_clear(&asn1_encoding);
302 }
303 return success;
304 }
305
306 METHOD(public_key_t, get_ref, public_key_t*,
307 private_wolfssl_ec_public_key_t *this)
308 {
309 ref_get(&this->ref);
310 return &this->public.key;
311 }
312
313 METHOD(public_key_t, destroy, void,
314 private_wolfssl_ec_public_key_t *this)
315 {
316 if (ref_put(&this->ref))
317 {
318 lib->encoding->clear_cache(lib->encoding, &this->ec);
319 wc_ecc_free(&this->ec);
320 free(this);
321 }
322 }
323
324 /**
325 * Generic private constructor
326 */
327 static private_wolfssl_ec_public_key_t *create_empty()
328 {
329 private_wolfssl_ec_public_key_t *this;
330
331 INIT(this,
332 .public = {
333 .key = {
334 .get_type = _get_type,
335 .verify = _verify,
336 .encrypt = _encrypt,
337 .get_keysize = _get_keysize,
338 .equals = public_key_equals,
339 .get_fingerprint = _get_fingerprint,
340 .has_fingerprint = public_key_has_fingerprint,
341 .get_encoding = _get_encoding,
342 .get_ref = _get_ref,
343 .destroy = _destroy,
344 },
345 },
346 .ref = 1,
347 );
348
349 if (wc_ecc_init(&this->ec) < 0)
350 {
351 free(this);
352 return NULL;
353 }
354
355 return this;
356 }
357
358 /**
359 * See header.
360 */
361 wolfssl_ec_public_key_t *wolfssl_ec_public_key_load(key_type_t type,
362 va_list args)
363 {
364 private_wolfssl_ec_public_key_t *this;
365 chunk_t blob = chunk_empty;
366 word32 idx;
367 int ret;
368
369 if (type != KEY_ECDSA)
370 {
371 return NULL;
372 }
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 this = create_empty();
389 idx = 0;
390 ret = wc_EccPublicKeyDecode(blob.ptr, &idx, &this->ec, blob.len);
391 if (ret < 0)
392 {
393 destroy(this);
394 return NULL;
395 }
396 switch (this->ec.dp->id)
397 {
398 case ECC_SECP256R1:
399 this->keysize = 256;
400 break;
401 case ECC_SECP384R1:
402 this->keysize = 384;
403 break;
404 case ECC_SECP521R1:
405 this->keysize = 521;
406 break;
407 default:
408 break;
409 }
410 return &this->public;
411 }
412 #endif /* HAVE_ECC_VERIFY */
413