wolfssl: Fixes, code style changes and some refactorings
[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 #include <wolfssl/wolfcrypt/asn.h>
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 /**
44 * Public interface
45 */
46 wolfssl_ec_public_key_t public;
47
48 /**
49 * Key size
50 */
51 int keysize;
52
53 /**
54 * EC key object
55 */
56 ecc_key ec;
57
58 /**
59 * Reference count
60 */
61 refcount_t ref;
62 };
63
64 /**
65 * Verification of a signature as in RFC 4754
66 */
67 static bool verify_signature(private_wolfssl_ec_public_key_t *this,
68 chunk_t hash, chunk_t signature)
69 {
70 int stat = 1, 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 mp_free(&s);
89 mp_free(&r);
90 return ret == 0 && stat == 1;
91 }
92
93 /**
94 * Verify a RFC 4754 signature for a specified curve and hash algorithm
95 */
96 static bool verify_curve_signature(private_wolfssl_ec_public_key_t *this,
97 signature_scheme_t scheme,
98 enum wc_HashType hash, ecc_curve_id curve_id,
99 chunk_t data, chunk_t signature)
100 {
101 bool success = FALSE;
102 chunk_t dgst;
103
104 if (curve_id != this->ec.dp->id)
105 {
106 DBG1(DBG_LIB, "signature scheme %N not supported by private key",
107 signature_scheme_names, scheme);
108 return FALSE;
109 }
110
111 if (wolfssl_hash_chunk(hash, data, &dgst))
112 {
113 success = verify_signature(this, dgst, signature);
114 }
115
116 chunk_free(&dgst);
117 return success;
118 }
119
120 /**
121 * Verification of a DER encoded signature as in RFC 3279
122 */
123 static bool verify_der_signature(private_wolfssl_ec_public_key_t *this,
124 enum wc_HashType hash, chunk_t data,
125 chunk_t signature)
126 {
127 chunk_t dgst;
128 int stat = 1, ret = -1;
129
130 signature = chunk_skip_zero(signature);
131 if (wolfssl_hash_chunk(hash, data, &dgst))
132 {
133 ret = wc_ecc_verify_hash(signature.ptr, signature.len, dgst.ptr,
134 dgst.len, &stat, &this->ec);
135 }
136 chunk_free(&dgst);
137 return ret == 0 && stat == 1;
138 }
139
140 METHOD(public_key_t, get_type, key_type_t,
141 private_wolfssl_ec_public_key_t *this)
142 {
143 return KEY_ECDSA;
144 }
145
146 METHOD(public_key_t, verify, bool,
147 private_wolfssl_ec_public_key_t *this, signature_scheme_t scheme,
148 void *params, chunk_t data, chunk_t signature)
149 {
150 switch (scheme)
151 {
152 #ifndef NO_SHA
153 case SIGN_ECDSA_WITH_SHA1_DER:
154 return verify_der_signature(this, WC_HASH_TYPE_SHA, data,
155 signature);
156 #endif
157 #ifndef NO_SHA256
158 case SIGN_ECDSA_WITH_SHA256_DER:
159 return verify_der_signature(this, WC_HASH_TYPE_SHA256, data,
160 signature);
161 #endif
162 #ifdef WOLFSSL_SHA384
163 case SIGN_ECDSA_WITH_SHA384_DER:
164 return verify_der_signature(this, WC_HASH_TYPE_SHA384, data,
165 signature);
166 #endif
167 #ifdef WOLFSSL_SHA512
168 case SIGN_ECDSA_WITH_SHA512_DER:
169 return verify_der_signature(this, WC_HASH_TYPE_SHA512, data,
170 signature);
171 #endif
172 case SIGN_ECDSA_WITH_NULL:
173 return verify_signature(this, data, signature);
174 #ifndef NO_SHA256
175 case SIGN_ECDSA_256:
176 return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA256,
177 ECC_SECP256R1, data, signature);
178 #endif
179 #ifdef WOLFSSL_SHA384
180 case SIGN_ECDSA_384:
181 return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA384,
182 ECC_SECP384R1, data, signature);
183 #endif
184 #ifdef WOLFSSL_SHA512
185 case SIGN_ECDSA_521:
186 return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA512,
187 ECC_SECP521R1, data, signature);
188 #endif
189 default:
190 DBG1(DBG_LIB, "signature scheme %N not supported via wolfssl",
191 signature_scheme_names, scheme);
192 return FALSE;
193 }
194 }
195
196 METHOD(public_key_t, encrypt, bool,
197 private_wolfssl_ec_public_key_t *this, encryption_scheme_t scheme,
198 chunk_t crypto, chunk_t *plain)
199 {
200 DBG1(DBG_LIB, "EC public key encryption not implemented");
201 return FALSE;
202 }
203
204 METHOD(public_key_t, get_keysize, int,
205 private_wolfssl_ec_public_key_t *this)
206 {
207 return this->keysize;
208 }
209
210 /**
211 * Calculate fingerprint from an EC key, also used in ec private key.
212 */
213 bool wolfssl_ec_fingerprint(ecc_key *ec, cred_encoding_type_t type, chunk_t *fp)
214 {
215 hasher_t *hasher;
216 chunk_t key;
217 int len;
218
219 if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
220 {
221 return TRUE;
222 }
223
224 switch (type)
225 {
226 case KEYID_PUBKEY_SHA1:
227 case KEYID_PUBKEY_INFO_SHA1:
228 /* need an additional byte for the point type */
229 len = ec->dp->size * 2 + 1;
230 if (type == KEYID_PUBKEY_INFO_SHA1)
231 {
232 /* additional space for algorithmIdentifier/bitString */
233 len += 2 * MAX_SEQ_SZ + 2 * MAX_ALGO_SZ + TRAILING_ZERO;
234 }
235 key = chunk_alloca(len);
236 len = wc_EccPublicKeyToDer(ec, key.ptr, key.len,
237 type == KEYID_PUBKEY_INFO_SHA1);
238 break;
239 default:
240 return FALSE;
241 }
242 if (len < 0)
243 {
244 return FALSE;
245 }
246 key.len = len;
247
248 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
249 if (!hasher || !hasher->allocate_hash(hasher, key, fp))
250 {
251 DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed");
252 DESTROY_IF(hasher);
253 return FALSE;
254 }
255 hasher->destroy(hasher);
256 lib->encoding->cache(lib->encoding, type, ec, *fp);
257 return TRUE;
258 }
259
260 METHOD(public_key_t, get_fingerprint, bool,
261 private_wolfssl_ec_public_key_t *this, cred_encoding_type_t type,
262 chunk_t *fingerprint)
263 {
264 return wolfssl_ec_fingerprint(&this->ec, type, fingerprint);
265 }
266
267 METHOD(public_key_t, get_encoding, bool,
268 private_wolfssl_ec_public_key_t *this, cred_encoding_type_t type,
269 chunk_t *encoding)
270 {
271 bool success = TRUE;
272 int len;
273
274 /* space for algorithmIdentifier/bitString + one byte for the point type */
275 *encoding = chunk_alloc(2 * this->ec.dp->size + 2 * MAX_SEQ_SZ +
276 2 * MAX_ALGO_SZ + TRAILING_ZERO + 1);
277 len = wc_EccPublicKeyToDer(&this->ec, encoding->ptr, encoding->len, 1);
278 if (len < 0)
279 {
280 chunk_free(encoding);
281 return FALSE;
282 }
283 encoding->len = len;
284
285 if (type != PUBKEY_SPKI_ASN1_DER)
286 {
287 chunk_t asn1_encoding = *encoding;
288
289 success = lib->encoding->encode(lib->encoding, type,
290 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
291 asn1_encoding, CRED_PART_END);
292 chunk_clear(&asn1_encoding);
293 }
294 return success;
295 }
296
297 METHOD(public_key_t, get_ref, public_key_t*,
298 private_wolfssl_ec_public_key_t *this)
299 {
300 ref_get(&this->ref);
301 return &this->public.key;
302 }
303
304 METHOD(public_key_t, destroy, void,
305 private_wolfssl_ec_public_key_t *this)
306 {
307 if (ref_put(&this->ref))
308 {
309 lib->encoding->clear_cache(lib->encoding, &this->ec);
310 wc_ecc_free(&this->ec);
311 free(this);
312 }
313 }
314
315 /**
316 * Generic private constructor
317 */
318 static private_wolfssl_ec_public_key_t *create_empty()
319 {
320 private_wolfssl_ec_public_key_t *this;
321
322 INIT(this,
323 .public = {
324 .key = {
325 .get_type = _get_type,
326 .verify = _verify,
327 .encrypt = _encrypt,
328 .get_keysize = _get_keysize,
329 .equals = public_key_equals,
330 .get_fingerprint = _get_fingerprint,
331 .has_fingerprint = public_key_has_fingerprint,
332 .get_encoding = _get_encoding,
333 .get_ref = _get_ref,
334 .destroy = _destroy,
335 },
336 },
337 .ref = 1,
338 );
339
340 if (wc_ecc_init(&this->ec) < 0)
341 {
342 free(this);
343 return NULL;
344 }
345 return this;
346 }
347
348 /*
349 * Described in header
350 */
351 wolfssl_ec_public_key_t *wolfssl_ec_public_key_load(key_type_t type,
352 va_list args)
353 {
354 private_wolfssl_ec_public_key_t *this;
355 chunk_t blob = chunk_empty;
356 word32 idx;
357 int ret;
358
359 while (TRUE)
360 {
361 switch (va_arg(args, builder_part_t))
362 {
363 case BUILD_BLOB_ASN1_DER:
364 blob = va_arg(args, chunk_t);
365 continue;
366 case BUILD_END:
367 break;
368 default:
369 return NULL;
370 }
371 break;
372 }
373 this = create_empty();
374 if (!this)
375 {
376 return NULL;
377 }
378
379 idx = 0;
380 ret = wc_EccPublicKeyDecode(blob.ptr, &idx, &this->ec, blob.len);
381 if (ret < 0)
382 {
383 destroy(this);
384 return NULL;
385 }
386 switch (this->ec.dp->id)
387 {
388 case ECC_SECP256R1:
389 this->keysize = 256;
390 break;
391 case ECC_SECP384R1:
392 this->keysize = 384;
393 break;
394 case ECC_SECP521R1:
395 this->keysize = 521;
396 break;
397 default:
398 break;
399 }
400 return &this->public;
401 }
402
403 #endif /* HAVE_ECC_VERIFY */