]>
Commit | Line | Data |
---|---|---|
c92eade8 SP |
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> | |
d3329ee5 | 34 | #include <wolfssl/wolfcrypt/asn.h> |
c92eade8 SP |
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 { | |
d3329ee5 | 42 | |
c92eade8 | 43 | /** |
d3329ee5 | 44 | * Public interface |
c92eade8 SP |
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 | /** | |
d3329ee5 | 59 | * Reference count |
c92eade8 SP |
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 | { | |
d3329ee5 | 70 | int stat = 1, ret = -1; |
c92eade8 SP |
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 | } | |
c92eade8 SP |
88 | mp_free(&s); |
89 | mp_free(&r); | |
c92eade8 SP |
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, | |
d3329ee5 TB |
97 | signature_scheme_t scheme, |
98 | enum wc_HashType hash, ecc_curve_id curve_id, | |
99 | chunk_t data, chunk_t signature) | |
c92eade8 SP |
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, | |
d3329ee5 TB |
124 | enum wc_HashType hash, chunk_t data, |
125 | chunk_t signature) | |
c92eade8 | 126 | { |
c92eade8 | 127 | chunk_t dgst; |
d3329ee5 | 128 | int stat = 1, ret = -1; |
c92eade8 | 129 | |
d3329ee5 | 130 | signature = chunk_skip_zero(signature); |
c92eade8 SP |
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); | |
c92eade8 | 135 | } |
c92eade8 | 136 | chunk_free(&dgst); |
d3329ee5 | 137 | return ret == 0 && stat == 1; |
c92eade8 SP |
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 | { | |
d3329ee5 | 152 | #ifndef NO_SHA |
c92eade8 SP |
153 | case SIGN_ECDSA_WITH_SHA1_DER: |
154 | return verify_der_signature(this, WC_HASH_TYPE_SHA, data, | |
155 | signature); | |
d3329ee5 TB |
156 | #endif |
157 | #ifndef NO_SHA256 | |
c92eade8 SP |
158 | case SIGN_ECDSA_WITH_SHA256_DER: |
159 | return verify_der_signature(this, WC_HASH_TYPE_SHA256, data, | |
160 | signature); | |
d3329ee5 TB |
161 | #endif |
162 | #ifdef WOLFSSL_SHA384 | |
c92eade8 SP |
163 | case SIGN_ECDSA_WITH_SHA384_DER: |
164 | return verify_der_signature(this, WC_HASH_TYPE_SHA384, data, | |
165 | signature); | |
d3329ee5 TB |
166 | #endif |
167 | #ifdef WOLFSSL_SHA512 | |
c92eade8 SP |
168 | case SIGN_ECDSA_WITH_SHA512_DER: |
169 | return verify_der_signature(this, WC_HASH_TYPE_SHA512, data, | |
170 | signature); | |
d3329ee5 | 171 | #endif |
c92eade8 SP |
172 | case SIGN_ECDSA_WITH_NULL: |
173 | return verify_signature(this, data, signature); | |
d3329ee5 | 174 | #ifndef NO_SHA256 |
c92eade8 SP |
175 | case SIGN_ECDSA_256: |
176 | return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA256, | |
177 | ECC_SECP256R1, data, signature); | |
d3329ee5 TB |
178 | #endif |
179 | #ifdef WOLFSSL_SHA384 | |
c92eade8 SP |
180 | case SIGN_ECDSA_384: |
181 | return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA384, | |
182 | ECC_SECP384R1, data, signature); | |
d3329ee5 TB |
183 | #endif |
184 | #ifdef WOLFSSL_SHA512 | |
c92eade8 SP |
185 | case SIGN_ECDSA_521: |
186 | return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA512, | |
187 | ECC_SECP521R1, data, signature); | |
d3329ee5 | 188 | #endif |
c92eade8 | 189 | default: |
d3329ee5 | 190 | DBG1(DBG_LIB, "signature scheme %N not supported via wolfssl", |
c92eade8 SP |
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, | |
4abb29f6 | 198 | void *params, chunk_t crypto, chunk_t *plain) |
c92eade8 SP |
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 | /** | |
d3329ee5 | 211 | * Calculate fingerprint from an EC key, also used in ec private key. |
c92eade8 SP |
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; | |
d3329ee5 | 217 | int len; |
c92eade8 SP |
218 | |
219 | if (lib->encoding->get_cache(lib->encoding, type, ec, fp)) | |
220 | { | |
221 | return TRUE; | |
222 | } | |
223 | ||
c92eade8 SP |
224 | switch (type) |
225 | { | |
226 | case KEYID_PUBKEY_SHA1: | |
d3329ee5 TB |
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); | |
c92eade8 SP |
238 | break; |
239 | default: | |
d3329ee5 | 240 | return FALSE; |
c92eade8 | 241 | } |
d3329ee5 TB |
242 | if (len < 0) |
243 | { | |
244 | return FALSE; | |
245 | } | |
246 | key.len = len; | |
c92eade8 SP |
247 | |
248 | hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); | |
249 | if (!hasher || !hasher->allocate_hash(hasher, key, fp)) | |
250 | { | |
d3329ee5 | 251 | DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed"); |
c92eade8 | 252 | DESTROY_IF(hasher); |
c92eade8 SP |
253 | return FALSE; |
254 | } | |
255 | hasher->destroy(hasher); | |
c92eade8 SP |
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; | |
d3329ee5 | 272 | int len; |
c92eade8 | 273 | |
d3329ee5 TB |
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) | |
c92eade8 SP |
279 | { |
280 | chunk_free(encoding); | |
281 | return FALSE; | |
282 | } | |
d3329ee5 | 283 | encoding->len = len; |
c92eade8 | 284 | |
d3329ee5 | 285 | if (type != PUBKEY_SPKI_ASN1_DER) |
c92eade8 SP |
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 | } | |
c92eade8 SP |
345 | return this; |
346 | } | |
347 | ||
d3329ee5 TB |
348 | /* |
349 | * Described in header | |
c92eade8 SP |
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 | ||
c92eade8 SP |
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(); | |
d3329ee5 TB |
374 | if (!this) |
375 | { | |
376 | return NULL; | |
377 | } | |
378 | ||
c92eade8 SP |
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 | } | |
c92eade8 | 402 | |
d3329ee5 | 403 | #endif /* HAVE_ECC_VERIFY */ |