/src/cryptofuzz/modules/wolfcrypt/ecdsa_generic.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "ecdsa_generic.h" |
2 | | #include "module_internal.h" |
3 | | #include "shared.h" |
4 | | #include "bn_ops.h" |
5 | | #include <cryptofuzz/util.h> |
6 | | #include <iostream> |
7 | | |
8 | | namespace cryptofuzz { |
9 | | namespace module { |
10 | | namespace wolfCrypt_detail { |
11 | | |
12 | | #if !defined(WOLFSSL_SP_MATH) |
13 | | #include "custom_curves.h" |
14 | | #endif |
15 | | |
16 | | #if defined(CRYPTOFUZZ_WOLFCRYPT_ALLOCATION_FAILURES) |
17 | | extern bool haveAllocFailure; |
18 | | #endif |
19 | | |
20 | | WC_RNG* GetRNG(void); |
21 | | |
22 | | ECCKey::ECCKey(Datasource& ds) : |
23 | 1.60k | ds(ds) { |
24 | 1.60k | if ( (key = wc_ecc_key_new(nullptr)) == nullptr ) { |
25 | 145 | throw std::exception(); |
26 | 145 | } |
27 | 1.60k | } |
28 | | |
29 | 1.46k | ECCKey::~ECCKey() { |
30 | 1.46k | CF_NORET(wc_ecc_key_free(key)); |
31 | 1.46k | } |
32 | | |
33 | 4.18k | ecc_key* ECCKey::GetPtr(void) { |
34 | 4.18k | uint8_t* x963 = nullptr; |
35 | 4.18k | ecc_key* newKey = nullptr; |
36 | | |
37 | 4.18k | bool exportToX963 = false; |
38 | 4.18k | try { |
39 | 4.18k | exportToX963 = ds.Get<bool>(); |
40 | 4.18k | } catch ( ... ) { } |
41 | | |
42 | 4.18k | if ( exportToX963 == true ) { |
43 | 476 | CF_CHECK_NE(newKey = wc_ecc_key_new(nullptr), nullptr); |
44 | | |
45 | 362 | word32 outLen = 0; |
46 | | |
47 | 362 | bool compressed = false; |
48 | 362 | try { compressed = ds.Get<bool>();} catch ( ... ) { } |
49 | | |
50 | 685 | WC_CHECK_EQ(wc_ecc_export_x963_ex(key, nullptr, &outLen, compressed), LENGTH_ONLY_E); |
51 | 685 | x963 = util::malloc(outLen); |
52 | 685 | WC_CHECK_EQ(wc_ecc_export_x963_ex(key, x963, &outLen, compressed), 0);; |
53 | | |
54 | | /* Get the curve id of the old key */ |
55 | 186 | int curveID; |
56 | 186 | CF_CHECK_NE(curveID = wc_ecc_get_curve_id(key->idx), ECC_CURVE_INVALID); |
57 | | |
58 | 186 | const bool valid = wc_ecc_check_key(key) == 0; |
59 | | |
60 | 186 | haveAllocFailure = false; |
61 | 186 | if ( wc_ecc_import_x963_ex(x963, outLen, newKey, curveID) != 0 ) { |
62 | | /* Allowed to fail if either: |
63 | | * |
64 | | * - Compression is used and the input key is invalid |
65 | | * - An allocation failure occured during wc_ecc_import_x963_ex |
66 | | */ |
67 | 102 | CF_ASSERT((compressed && !valid) || haveAllocFailure, "Cannot import X963-exported ECC key"); |
68 | 102 | goto end; |
69 | 102 | } |
70 | | |
71 | 84 | if ( compressed ) { |
72 | 47 | CF_CHECK_TRUE(valid); |
73 | 11 | } |
74 | | |
75 | 48 | CF_NORET(wc_ecc_key_free(key)); |
76 | 48 | key = newKey; |
77 | 48 | newKey = nullptr; |
78 | 48 | } |
79 | | |
80 | 4.18k | end: |
81 | 4.18k | util::free(x963); |
82 | 4.18k | CF_NORET(wc_ecc_key_free(newKey)); |
83 | | |
84 | 4.18k | return key; |
85 | 4.18k | } |
86 | | |
87 | 841 | bool ECCKey::SetCurve(const Type& curveType) { |
88 | 841 | bool ret = false; |
89 | | |
90 | 841 | #if !defined(WOLFSSL_SP_MATH) |
91 | 841 | bool useCustomCurve = false; |
92 | | |
93 | 841 | try { |
94 | 841 | useCustomCurve = ds.Get<uint8_t>(); |
95 | 841 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
96 | 841 | useCustomCurve = false; |
97 | | |
98 | 841 | if ( useCustomCurve == false ) |
99 | 841 | #endif |
100 | 841 | { |
101 | | #if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG) |
102 | | std::cout << "Using native curve" << std::endl; |
103 | | #endif |
104 | 841 | std::optional<int> curveID; |
105 | | |
106 | 841 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(curveType), std::nullopt); |
107 | 774 | this->curveID = *curveID; |
108 | | |
109 | 774 | WC_CHECK_EQ(wc_ecc_set_curve(GetPtr(), 0, *curveID), 0); |
110 | 709 | } |
111 | 0 | #if !defined(WOLFSSL_SP_MATH) |
112 | 0 | else { |
113 | | #if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG) |
114 | | std::cout << "Using custom curve" << std::endl; |
115 | | #endif |
116 | 0 | const ecc_set_type* curveSpec; |
117 | 0 | CF_CHECK_NE(curveSpec = GetCustomCurve(curveType.Get()), nullptr); |
118 | 0 | WC_CHECK_EQ(wc_ecc_set_custom_curve(GetPtr(), curveSpec), 0); |
119 | 0 | this->curveID = ECC_CURVE_CUSTOM; |
120 | 0 | } |
121 | 709 | #endif |
122 | | |
123 | 709 | ret = true; |
124 | | |
125 | 841 | end: |
126 | 841 | return ret; |
127 | 709 | } |
128 | | |
129 | 709 | bool ECCKey::LoadPrivateKey(const component::Bignum& priv) { |
130 | 709 | bool ret = false; |
131 | 709 | std::optional<std::vector<uint8_t>> priv_bytes; |
132 | | |
133 | 709 | CF_CHECK_NE(priv_bytes = wolfCrypt_bignum::Bignum::ToBin(ds, priv), std::nullopt); |
134 | | |
135 | 674 | WC_CHECK_EQ(wc_ecc_import_private_key_ex(priv_bytes->data(), priv_bytes->size(), nullptr, 0, GetPtr(), *curveID), 0); |
136 | | |
137 | 567 | ret = true; |
138 | | |
139 | 709 | end: |
140 | 709 | return ret; |
141 | 567 | } |
142 | | |
143 | 535 | std::optional<ECCPoint> ECCKey::MakePub(void) { |
144 | 535 | std::optional<ECCPoint> ret = std::nullopt; |
145 | | |
146 | 535 | ECCPoint pub(ds, *curveID); |
147 | 535 | WC_CHECK_EQ(wc_ecc_make_pub(GetPtr(), pub.GetPtr()), 0); |
148 | 510 | pub.SetInitialized(); |
149 | | |
150 | 510 | return pub; |
151 | | |
152 | 25 | end: |
153 | 25 | return ret; |
154 | 535 | } |
155 | | |
156 | 21 | bool ECCKey::SetRNG(void) { |
157 | 21 | bool ret = false; |
158 | | |
159 | 21 | WC_CHECK_EQ(wc_ecc_set_rng(GetPtr(), wolfCrypt_detail::GetRNG()), 0); |
160 | | |
161 | 21 | ret = true; |
162 | 21 | end: |
163 | 21 | return ret; |
164 | 21 | } |
165 | | |
166 | | ECCPoint::ECCPoint(Datasource& ds, const int curveID) : |
167 | | ds(ds), |
168 | 2.04k | curveID(curveID) { |
169 | 2.04k | if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) { |
170 | 177 | throw std::exception(); |
171 | 177 | } |
172 | 2.04k | } |
173 | | |
174 | | /* Copy constructor */ |
175 | | ECCPoint::ECCPoint(const ECCPoint& other) : |
176 | | ds(other.ds), |
177 | | curveID(other.curveID), |
178 | | locked(other.locked), |
179 | | initialized(other.initialized) |
180 | 508 | { |
181 | 508 | if ( (point = wc_ecc_new_point_h(nullptr)) == nullptr ) { |
182 | 0 | throw std::exception(); |
183 | 0 | } |
184 | | |
185 | 508 | if ( wc_ecc_copy_point(other.point, point) != 0 ) { |
186 | 0 | CF_NORET(wc_ecc_del_point(point)); |
187 | 0 | throw std::exception(); |
188 | 0 | } |
189 | 508 | } |
190 | | |
191 | 2.37k | ECCPoint::~ECCPoint() { |
192 | 2.37k | CF_NORET(wc_ecc_del_point(point)); |
193 | 2.37k | } |
194 | | |
195 | 3.31k | ecc_point* ECCPoint::GetPtr() { |
196 | 3.31k | uint8_t* out = nullptr; |
197 | 3.31k | ecc_point* newPoint = nullptr; |
198 | | |
199 | 3.31k | if ( locked == false && initialized == true ) { |
200 | 832 | bool exportToDER = false; |
201 | | |
202 | 832 | try { |
203 | 832 | exportToDER = ds.Get<bool>(); |
204 | 832 | } catch ( ... ) { } |
205 | | |
206 | 832 | if ( exportToDER == true ) { |
207 | 52 | bool compressed = false; |
208 | 52 | try { |
209 | 52 | compressed = ds.Get<bool>(); |
210 | 52 | } catch ( ... ) { } |
211 | | |
212 | 52 | const int curveIdx = wc_ecc_get_curve_idx(curveID); |
213 | 52 | CF_CHECK_NE(newPoint = wc_ecc_new_point_h(nullptr), nullptr); |
214 | | |
215 | 33 | word32 outSz = 0xFFFF; |
216 | 33 | try { outSz = ds.Get<word32>() & 0xFFFF; } catch ( ... ) { } |
217 | | |
218 | 33 | out = util::malloc(outSz); |
219 | | |
220 | 33 | if ( compressed == false ) { |
221 | 13 | WC_CHECK_EQ(wc_ecc_export_point_der(curveIdx, point, out, &outSz), 0); |
222 | 20 | } else { |
223 | 20 | WC_CHECK_EQ(wc_ecc_export_point_der(curveIdx, point, out, &outSz), 0); |
224 | | //WC_CHECK_EQ(wc_ecc_export_point_der_compressed(curveIdx, point, out, &outSz), 0); |
225 | 5 | } |
226 | | |
227 | 13 | { |
228 | 13 | haveAllocFailure = false; |
229 | 13 | const bool success = wc_ecc_import_point_der(out, outSz, curveIdx, newPoint) == 0; |
230 | | |
231 | 13 | if ( success ) { |
232 | | /* Point imported. Replace old point with new point. */ |
233 | | |
234 | 13 | CF_NORET(wc_ecc_del_point(point)); |
235 | 13 | point = newPoint; |
236 | 13 | newPoint = nullptr; |
237 | 13 | } else { |
238 | | /* Failure */ |
239 | |
|
240 | 0 | if ( haveAllocFailure == false ) { |
241 | | /* Failure is only acceptable if an allocation failure occured, crash otherwise */ |
242 | 0 | CF_ASSERT(0, "Cannot import DER-exported ECC point"); |
243 | 0 | } |
244 | 0 | } |
245 | 13 | } |
246 | 13 | } |
247 | 832 | } |
248 | | |
249 | 3.31k | end: |
250 | 3.31k | util::free(out); |
251 | 3.31k | CF_NORET(wc_ecc_del_point(newPoint)); |
252 | | |
253 | 3.31k | return point; |
254 | 3.31k | } |
255 | | |
256 | | bool ECCPoint::Set( |
257 | | const component::BignumPair& xy, |
258 | | const uint64_t curveType, |
259 | | const bool pointCheck, |
260 | 698 | const bool mp_init_size_ok) { |
261 | 698 | bool ret = false; |
262 | | |
263 | 698 | bool projective = false; |
264 | 698 | try { |
265 | 698 | projective = ds.Get<bool>(); |
266 | 698 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
267 | | |
268 | 698 | wolfCrypt_bignum::Bignum x(ds, mp_init_size_ok); |
269 | 698 | wolfCrypt_bignum::Bignum y(ds, mp_init_size_ok); |
270 | 698 | wolfCrypt_bignum::Bignum z(ds, mp_init_size_ok); |
271 | | |
272 | 698 | if ( projective == false ) { |
273 | 557 | CF_CHECK_TRUE(x.Set(xy.first)); |
274 | 555 | CF_CHECK_TRUE(y.Set(xy.second)); |
275 | 553 | CF_CHECK_TRUE(z.Set("1")); |
276 | 553 | } else { |
277 | 141 | const auto proj = util::ToRandomProjective( |
278 | 141 | ds, |
279 | 141 | xy.first.ToTrimmedString(), |
280 | 141 | xy.second.ToTrimmedString(), |
281 | 141 | curveType); |
282 | 141 | CF_CHECK_TRUE(x.Set(proj[0])); |
283 | 136 | CF_CHECK_TRUE(y.Set(proj[1])); |
284 | 133 | CF_CHECK_TRUE(z.Set(proj[2])); |
285 | 132 | } |
286 | | |
287 | 1.37k | WC_CHECK_EQ(mp_copy(x.GetPtr(), point->x), MP_OKAY); |
288 | 1.37k | WC_CHECK_EQ(mp_copy(y.GetPtr(), point->y), MP_OKAY); |
289 | 685 | WC_CHECK_EQ(mp_copy(z.GetPtr(), point->z), MP_OKAY); |
290 | | |
291 | 685 | if ( pointCheck ) { |
292 | 0 | CF_CHECK_TRUE(CurveCheck()); |
293 | 0 | } |
294 | | |
295 | 685 | SetInitialized(); |
296 | | |
297 | 685 | ret = true; |
298 | | |
299 | 698 | end: |
300 | 698 | return ret; |
301 | 685 | } |
302 | | |
303 | 429 | bool ECCPoint::ToProjective(wolfCrypt_bignum::Bignum& prime) { |
304 | 429 | bool ret = false; |
305 | | |
306 | 429 | wolfCrypt_bignum::Bignum mu(ds); |
307 | | |
308 | 429 | WC_CHECK_EQ(mp_montgomery_calc_normalization(mu.GetPtr(), prime.GetPtr()), MP_OKAY); |
309 | | |
310 | 425 | if ( mp_cmp_d(mu.GetPtr(), 1) != MP_EQ ) { |
311 | 329 | WC_CHECK_EQ(mp_mulmod(point->x, mu.GetPtr(), prime.GetPtr(), point->x), MP_OKAY); |
312 | 322 | WC_CHECK_EQ(mp_mulmod(point->y, mu.GetPtr(), prime.GetPtr(), point->y), MP_OKAY); |
313 | 311 | WC_CHECK_EQ(mp_mulmod(point->z, mu.GetPtr(), prime.GetPtr(), point->z), MP_OKAY); |
314 | 307 | } |
315 | | |
316 | | /* Lock so it isn't attempted to export/import the projective point in GetPtr(), |
317 | | * which will lead to incorrect results |
318 | | */ |
319 | 403 | Lock(); |
320 | | |
321 | 403 | ret = true; |
322 | | |
323 | 429 | end: |
324 | 429 | return ret; |
325 | 403 | } |
326 | | |
327 | 585 | bool ECCPoint::CurveCheck(void) const { |
328 | 585 | const int curveIdx = wc_ecc_get_curve_idx(curveID); |
329 | 585 | return wc_ecc_point_is_on_curve(point, curveIdx) == 0; |
330 | 585 | } |
331 | | |
332 | 1.16k | void ECCPoint::Lock(void) { |
333 | 1.16k | locked = true; |
334 | 1.16k | } |
335 | | |
336 | 1.19k | void ECCPoint::SetInitialized(void) { |
337 | 1.19k | initialized = true; |
338 | 1.19k | } |
339 | | |
340 | 510 | std::optional<component::BignumPair> ECCPoint::ToBignumPair(void) { |
341 | 510 | std::optional<component::BignumPair> ret = std::nullopt; |
342 | | |
343 | 510 | wolfCrypt_bignum::Bignum pub_x(GetPtr()->x, ds); |
344 | | |
345 | | /* Pointer is stored in pub_x; lock to prevent UAF */ |
346 | 510 | Lock(); |
347 | | |
348 | 510 | wolfCrypt_bignum::Bignum pub_y(GetPtr()->y, ds); |
349 | | |
350 | 510 | std::optional<std::string> pub_x_str, pub_y_str; |
351 | 510 | CF_CHECK_NE(pub_x_str = pub_x.ToDecString(), std::nullopt); |
352 | 508 | CF_CHECK_NE(pub_y_str = pub_y.ToDecString(), std::nullopt); |
353 | | |
354 | 506 | ret = { *pub_x_str, *pub_y_str }; |
355 | 510 | end: |
356 | | |
357 | 510 | return ret; |
358 | 506 | } |
359 | | |
360 | 120 | int ECCPoint::Compare(ECCPoint& other) { |
361 | 120 | return wc_ecc_cmp_point(GetPtr(), other.GetPtr()); |
362 | 120 | } |
363 | | |
364 | 135 | std::optional<bool> ECCPoint::IsNeg(ECCPoint& other, wolfCrypt_bignum::Bignum& prime) { |
365 | 135 | std::optional<bool> ret = std::nullopt; |
366 | | |
367 | 135 | wolfCrypt_bignum::Bignum neg(ds); |
368 | 135 | if ( mp_sub(prime.GetPtr(), other.GetPtr()->y, neg.GetPtr()) == MP_OKAY) { |
369 | 130 | ret = static_cast<bool>(mp_cmp(point->y, neg.GetPtr()) == MP_EQ); |
370 | 130 | } |
371 | | |
372 | 135 | return ret; |
373 | 135 | } |
374 | | |
375 | 481 | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Generic(operation::ECC_PrivateToPublic& op) { |
376 | 481 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
377 | 481 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
378 | 481 | wolfCrypt_detail::SetGlobalDs(&ds); |
379 | | |
380 | 481 | try { |
381 | 481 | ECCKey key(ds); |
382 | | |
383 | | /* Initialize */ |
384 | 481 | { |
385 | 481 | CF_CHECK_EQ(key.SetCurve(op.curveType), true); |
386 | 392 | CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true); |
387 | 283 | } |
388 | | |
389 | | /* Process/Finalize */ |
390 | 0 | { |
391 | 283 | auto pub = key.MakePub(); |
392 | 283 | CF_CHECK_NE(pub, std::nullopt); |
393 | | |
394 | 265 | ret = pub->ToBignumPair(); |
395 | 265 | } |
396 | 265 | } catch ( ... ) { } |
397 | | |
398 | 481 | end: |
399 | | |
400 | 481 | wolfCrypt_detail::UnsetGlobalDs(); |
401 | 481 | return ret; |
402 | 481 | } |
403 | | |
404 | 232 | std::optional<bool> OpECC_ValidatePubkey_Generic(operation::ECC_ValidatePubkey& op) { |
405 | 232 | std::optional<bool> ret = std::nullopt; |
406 | 232 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
407 | 232 | wolfCrypt_detail::SetGlobalDs(&ds); |
408 | | |
409 | 232 | std::optional<int> curveID; |
410 | | |
411 | 232 | try { |
412 | 232 | ECCKey key(ds); |
413 | 232 | { |
414 | 232 | const char* name = nullptr; |
415 | | |
416 | 232 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
417 | | |
418 | 221 | CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr); |
419 | | |
420 | 206 | WC_CHECK_EQ(wc_ecc_import_raw( |
421 | 188 | key.GetPtr(), |
422 | 188 | util::DecToHex(op.pub.first.ToTrimmedString()).c_str(), |
423 | 188 | util::DecToHex(op.pub.second.ToTrimmedString()).c_str(), |
424 | 188 | nullptr, |
425 | 188 | name), 0); |
426 | 188 | haveAllocFailure = false; |
427 | 188 | ret = wc_ecc_check_key(key.GetPtr()) == 0; |
428 | 188 | if ( *ret == false && haveAllocFailure == true ) { |
429 | 36 | ret = std::nullopt; |
430 | 36 | } |
431 | 188 | } |
432 | 188 | } catch ( ... ) { } |
433 | | |
434 | 232 | end: |
435 | | |
436 | 232 | wolfCrypt_detail::UnsetGlobalDs(); |
437 | 232 | return ret; |
438 | 232 | } |
439 | | |
440 | 458 | std::optional<bool> OpECDSA_Verify_Generic(operation::ECDSA_Verify& op) { |
441 | | /* These are currently not supported by wc_Hash |
442 | | * See also ZD 16119 |
443 | | */ |
444 | 458 | switch ( op.digestType.Get() ) { |
445 | 0 | case CF_DIGEST("MD2"): |
446 | 0 | case CF_DIGEST("MD4"): |
447 | 0 | case CF_DIGEST("BLAKE2B512"): |
448 | 0 | case CF_DIGEST("BLAKE2S256"): |
449 | 15 | case CF_DIGEST("SHA3-224"): |
450 | 35 | case CF_DIGEST("SHA3-256"): |
451 | 45 | case CF_DIGEST("SHA3-384"): |
452 | 50 | case CF_DIGEST("SHA3-512"): |
453 | 50 | return std::nullopt; |
454 | 458 | } |
455 | | |
456 | 408 | std::optional<bool> ret = std::nullopt; |
457 | 408 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
458 | 408 | wolfCrypt_detail::SetGlobalDs(&ds); |
459 | | |
460 | 408 | std::optional<int> curveID; |
461 | 408 | uint8_t* sig = nullptr; |
462 | 408 | uint8_t* hash = nullptr; |
463 | 408 | word32 sigSz = ECC_MAX_SIG_SIZE; |
464 | 408 | int verify; |
465 | | |
466 | 408 | bool ctIsEmpty = false; |
467 | 408 | bool randomSigSz = false; |
468 | 408 | bool hashNotFound = false; |
469 | | |
470 | 408 | { |
471 | 408 | try { |
472 | 408 | randomSigSz = ds.Get<bool>(); |
473 | 408 | if ( randomSigSz ) { |
474 | 128 | sigSz = ds.Get<uint8_t>(); |
475 | 128 | } |
476 | 408 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
477 | | |
478 | 408 | sig = util::malloc(sigSz); |
479 | 408 | } |
480 | | |
481 | 408 | try { |
482 | 408 | ECCKey key(ds); |
483 | 408 | { |
484 | 408 | const char* name = nullptr; |
485 | | |
486 | 408 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
487 | | |
488 | 403 | CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr); |
489 | | |
490 | 386 | haveAllocFailure = false; |
491 | 386 | ret = false; |
492 | | |
493 | 386 | WC_CHECK_EQ(wc_ecc_import_raw( |
494 | 371 | key.GetPtr(), |
495 | 371 | util::DecToHex(op.signature.pub.first.ToTrimmedString()).c_str(), |
496 | 371 | util::DecToHex(op.signature.pub.second.ToTrimmedString()).c_str(), |
497 | 371 | nullptr, |
498 | 371 | name), 0); |
499 | 371 | WC_CHECK_EQ(wc_ecc_check_key(key.GetPtr()), 0); |
500 | 302 | } |
501 | | |
502 | 302 | WC_CHECK_EQ(wc_ecc_rs_to_sig( |
503 | 289 | util::DecToHex(op.signature.signature.first.ToTrimmedString()).c_str(), |
504 | 289 | util::DecToHex(op.signature.signature.second.ToTrimmedString()).c_str(), |
505 | 289 | sig, &sigSz), 0); |
506 | | |
507 | 289 | if ( op.digestType.Get() == CF_DIGEST("NULL") ) { |
508 | 95 | const auto CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType); |
509 | 95 | ctIsEmpty = CT.GetSize() == 0; |
510 | 95 | WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0); |
511 | 194 | } else { |
512 | 194 | std::optional<wc_HashType> hashType; |
513 | 194 | hashNotFound = true; |
514 | 194 | CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt); |
515 | 187 | hashNotFound = false; |
516 | | |
517 | 187 | const auto hashSize = wc_HashGetDigestSize(*hashType); |
518 | 187 | hash = util::malloc(hashSize); |
519 | | |
520 | 187 | WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0); |
521 | | |
522 | 187 | const auto CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType); |
523 | 187 | ctIsEmpty = CT.GetSize() == 0; |
524 | 187 | WC_CHECK_EQ(wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()), 0); |
525 | 180 | } |
526 | | |
527 | 239 | ret = verify ? true : false; |
528 | 239 | } catch ( ... ) { } |
529 | | |
530 | 408 | end: |
531 | | |
532 | 408 | util::free(sig); |
533 | 408 | util::free(hash); |
534 | | |
535 | 408 | wolfCrypt_detail::UnsetGlobalDs(); |
536 | | |
537 | 408 | if ( ret && *ret == false ) { |
538 | 174 | if ( haveAllocFailure ) { |
539 | 91 | ret = std::nullopt; |
540 | 91 | } else if ( randomSigSz ) { |
541 | 12 | ret = std::nullopt; |
542 | 71 | } else if ( ctIsEmpty ) { |
543 | | /* wolfCrypt ECDSA verification will fail if the input msg is empty */ |
544 | 2 | ret = std::nullopt; |
545 | 69 | } else if ( hashNotFound ) { |
546 | 5 | ret = std::nullopt; |
547 | 64 | } else if ( op.digestType.Is(CF_DIGEST("NULL")) && op.cleartext.IsZero() ) { |
548 | 3 | ret = std::nullopt; |
549 | 3 | } |
550 | 174 | } |
551 | | |
552 | 408 | return ret; |
553 | 408 | } |
554 | | |
555 | 0 | std::optional<component::ECCSI_Signature> OpECCSI_Sign(operation::ECCSI_Sign& op) { |
556 | 0 | #if !defined(WOLFCRYPT_HAVE_ECCSI) |
557 | 0 | (void)op; |
558 | 0 | return std::nullopt; |
559 | | #else |
560 | | std::optional<component::ECCSI_Signature> ret = std::nullopt; |
561 | | |
562 | | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
563 | | wolfCrypt_detail::SetGlobalDs(&ds); |
564 | | |
565 | | uint8_t hashSz = WC_MAX_DIGEST_SIZE; |
566 | | static_assert(WC_MAX_DIGEST_SIZE < 256); |
567 | | |
568 | | uint8_t* hash = util::malloc(hashSz); |
569 | | |
570 | | uint8_t* encoded = nullptr; |
571 | | EccsiKey eccsi; |
572 | | bool eccsi_initialized = false; |
573 | | |
574 | | try { |
575 | | int size; |
576 | | std::optional<component::BignumPair> pubbn = std::nullopt; |
577 | | |
578 | | { |
579 | | /* Private to public */ |
580 | | ECCKey key(ds); |
581 | | CF_CHECK_EQ(key.SetCurve(op.curveType), true); |
582 | | CF_CHECK_GT(size = key.GetPtr()->dp->size, 0); |
583 | | CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true); |
584 | | auto pub = key.MakePub(); |
585 | | CF_CHECK_NE(pub, std::nullopt); |
586 | | CF_CHECK_NE(pubbn = pub->ToBignumPair(), std::nullopt); |
587 | | |
588 | | /* Encode private and public */ |
589 | | encoded = util::malloc(size * 3); |
590 | | |
591 | | WC_CHECK_EQ(mp_to_unsigned_bin_len(key.GetPtr()->k, encoded, size), 0); |
592 | | WC_CHECK_EQ(mp_to_unsigned_bin_len(pub->GetPtr()->x, encoded + size, size), 0); |
593 | | WC_CHECK_EQ(mp_to_unsigned_bin_len(pub->GetPtr()->y, encoded + (size * 2), size), 0); |
594 | | } |
595 | | |
596 | | { |
597 | | std::optional<int> curveId; |
598 | | CF_CHECK_NE(curveId = toCurveID(op.curveType), std::nullopt); |
599 | | |
600 | | WC_CHECK_EQ(wc_InitEccsiKey_ex(&eccsi, size, *curveId, nullptr, -1), 0); |
601 | | eccsi_initialized = true; |
602 | | |
603 | | WC_CHECK_EQ(wc_ImportEccsiKey(&eccsi, encoded, size * 3), 0); |
604 | | { |
605 | | uint8_t sig[257]; /* XXX random size */ |
606 | | word32 sigSz = sizeof(sig); |
607 | | ECCPoint pvt(ds, *curveId); |
608 | | wolfCrypt_bignum::Bignum ssk(ds); |
609 | | std::optional<wc_HashType> hashType; |
610 | | CF_CHECK_NE(hashType = toHashType(op.digestType), std::nullopt); |
611 | | WC_CHECK_EQ(wc_MakeEccsiPair( |
612 | | &eccsi, |
613 | | &rng, |
614 | | *hashType, |
615 | | op.id.GetPtr(), |
616 | | op.id.GetSize(), |
617 | | ssk.GetPtr(), |
618 | | pvt.GetPtr()), 0); |
619 | | WC_CHECK_EQ(wc_HashEccsiId( |
620 | | &eccsi, |
621 | | *hashType, |
622 | | op.id.GetPtr(), |
623 | | op.id.GetSize(), |
624 | | pvt.GetPtr(), |
625 | | hash, |
626 | | &hashSz), 0); |
627 | | WC_CHECK_EQ(wc_SetEccsiHash(&eccsi, hash, hashSz), 0); |
628 | | WC_CHECK_EQ(wc_SetEccsiPair(&eccsi, ssk.GetPtr(), pvt.GetPtr()), 0); |
629 | | WC_CHECK_EQ(wc_SignEccsiHash( |
630 | | &eccsi, |
631 | | &rng, |
632 | | *hashType, |
633 | | op.cleartext.GetPtr(), |
634 | | op.cleartext.GetSize(), |
635 | | sig, &sigSz), 0); |
636 | | CF_ASSERT(sigSz == static_cast<size_t>(size) * 4 + 1, "Unexpected signature size"); |
637 | | { |
638 | | wolfCrypt_bignum::Bignum r(ds), s(ds); |
639 | | std::optional<std::string> r_str, s_str; |
640 | | std::optional<component::BignumPair> pvtbn = std::nullopt; |
641 | | |
642 | | WC_CHECK_EQ(mp_read_unsigned_bin(r.GetPtr(), sig, size), 0); |
643 | | CF_CHECK_NE(r_str = r.ToDecString(), std::nullopt); |
644 | | |
645 | | WC_CHECK_EQ(mp_read_unsigned_bin(s.GetPtr(), sig + size, size), 0); |
646 | | CF_CHECK_NE(s_str = s.ToDecString(), std::nullopt); |
647 | | |
648 | | CF_CHECK_NE(pvtbn = pvt.ToBignumPair(), std::nullopt); |
649 | | |
650 | | ret = component::ECCSI_Signature{ |
651 | | component::BignumPair{*r_str, *s_str}, |
652 | | *pubbn, |
653 | | *pvtbn}; |
654 | | } |
655 | | } |
656 | | } |
657 | | } catch ( ... ) { } |
658 | | |
659 | | end: |
660 | | if ( eccsi_initialized ) { |
661 | | CF_NORET(wc_FreeEccsiKey(&eccsi)); |
662 | | } |
663 | | util::free(hash); |
664 | | util::free(encoded); |
665 | | wolfCrypt_detail::UnsetGlobalDs(); |
666 | | return ret; |
667 | | #endif |
668 | 0 | } |
669 | | |
670 | 0 | std::optional<bool> OpECCSI_Verify(operation::ECCSI_Verify& op) { |
671 | 0 | #if !defined(WOLFCRYPT_HAVE_ECCSI) |
672 | 0 | (void)op; |
673 | 0 | return std::nullopt; |
674 | | #else |
675 | | std::optional<bool> ret = std::nullopt; |
676 | | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
677 | | wolfCrypt_detail::SetGlobalDs(&ds); |
678 | | |
679 | | uint8_t hashSz = WC_MAX_DIGEST_SIZE; |
680 | | static_assert(WC_MAX_DIGEST_SIZE < 256); |
681 | | |
682 | | EccsiKey eccsi; |
683 | | |
684 | | uint8_t* hash = util::malloc(hashSz); |
685 | | std::optional<wc_HashType> hashType; |
686 | | std::optional<int> curveId; |
687 | | std::vector<uint8_t> pub, sig; |
688 | | int verified; |
689 | | int size; |
690 | | bool eccsi_initialized = false; |
691 | | |
692 | | CF_CHECK_NE(curveId = toCurveID(op.curveType), std::nullopt); |
693 | | CF_CHECK_NE(hashType = toHashType(op.digestType), std::nullopt); |
694 | | |
695 | | haveAllocFailure = false; |
696 | | ret = false; |
697 | | |
698 | | try { |
699 | | { |
700 | | ECCKey key(ds); |
701 | | CF_CHECK_EQ(key.SetCurve(op.curveType), true); |
702 | | CF_CHECK_GT(size = key.GetPtr()->dp->size, 0); |
703 | | } |
704 | | |
705 | | /* Pub to binary */ |
706 | | { |
707 | | const auto x = op.signature.pub.first.ToBin(size); |
708 | | CF_CHECK_NE(x, std::nullopt); |
709 | | pub.insert(pub.end(), x->begin(), x->end()); |
710 | | |
711 | | const auto y = op.signature.pub.second.ToBin(size); |
712 | | CF_CHECK_NE(y, std::nullopt); |
713 | | pub.insert(pub.end(), y->begin(), y->end()); |
714 | | } |
715 | | |
716 | | /* Sig to binary */ |
717 | | { |
718 | | const auto r = op.signature.signature.first.ToBin(size); |
719 | | CF_CHECK_NE(r, std::nullopt); |
720 | | sig.insert(sig.end(), r->begin(), r->end()); |
721 | | |
722 | | const auto s = op.signature.signature.second.ToBin(size); |
723 | | CF_CHECK_NE(s, std::nullopt); |
724 | | sig.insert(sig.end(), s->begin(), s->end()); |
725 | | |
726 | | sig.push_back(0x04); |
727 | | |
728 | | const auto pvt_x = op.signature.pvt.first.ToBin(size); |
729 | | CF_CHECK_NE(pvt_x, std::nullopt); |
730 | | sig.insert(sig.end(), pvt_x->begin(), pvt_x->end()); |
731 | | |
732 | | const auto pvt_y = op.signature.pvt.second.ToBin(size); |
733 | | CF_CHECK_NE(pvt_y, std::nullopt); |
734 | | sig.insert(sig.end(), pvt_y->begin(), pvt_y->end()); |
735 | | } |
736 | | |
737 | | { |
738 | | ECCPoint pvt(ds, *curveId); |
739 | | |
740 | | WC_CHECK_EQ(wc_InitEccsiKey_ex(&eccsi, size, *curveId, nullptr, -1), 0); |
741 | | eccsi_initialized = true; |
742 | | |
743 | | WC_CHECK_EQ(wc_ImportEccsiPublicKey(&eccsi, |
744 | | pub.data(), pub.size(), 0), 0); |
745 | | WC_CHECK_EQ(wc_DecodeEccsiPvtFromSig(&eccsi, sig.data(), sig.size(), pvt.GetPtr()), 0); |
746 | | WC_CHECK_EQ(wc_HashEccsiId( |
747 | | &eccsi, |
748 | | *hashType, |
749 | | op.id.GetPtr(&ds), op.id.GetSize(), |
750 | | pvt.GetPtr(), |
751 | | hash, |
752 | | &hashSz), 0); |
753 | | WC_CHECK_EQ(wc_SetEccsiHash(&eccsi, hash, hashSz), 0); |
754 | | WC_CHECK_EQ(wc_VerifyEccsiHash( |
755 | | &eccsi, |
756 | | *hashType, |
757 | | op.cleartext.GetPtr(&ds), op.cleartext.GetSize(), |
758 | | sig.data(), sig.size(), |
759 | | &verified), 0); |
760 | | ret = verified == 1; |
761 | | } |
762 | | } catch ( ... ) { } |
763 | | |
764 | | end: |
765 | | if ( eccsi_initialized ) { |
766 | | CF_NORET(wc_FreeEccsiKey(&eccsi)); |
767 | | } |
768 | | util::free(hash); |
769 | | wolfCrypt_detail::UnsetGlobalDs(); |
770 | | if ( ret && *ret == false ) { |
771 | | if ( haveAllocFailure ) { |
772 | | ret = std::nullopt; |
773 | | } |
774 | | } |
775 | | return ret; |
776 | | #endif |
777 | 0 | } |
778 | | |
779 | 504 | std::optional<component::ECDSA_Signature> OpECDSA_Sign_Generic(operation::ECDSA_Sign& op) { |
780 | 504 | std::optional<component::ECDSA_Signature> ret = std::nullopt; |
781 | 504 | if ( op.UseRandomNonce() == false && op.UseSpecifiedNonce() == false ) { |
782 | 113 | return ret; |
783 | 113 | } |
784 | | |
785 | 391 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
786 | 391 | wolfCrypt_detail::SetGlobalDs(&ds); |
787 | | |
788 | 391 | uint8_t* sig = nullptr; |
789 | 391 | word32 sigSz = ECC_MAX_SIG_SIZE; |
790 | 391 | Buffer CT; |
791 | 391 | uint8_t* hash = nullptr; |
792 | 391 | size_t hashSize = 0; |
793 | 391 | uint8_t* nonce_bytes = nullptr; |
794 | 391 | wolfCrypt_bignum::Bignum nonce(ds); |
795 | | |
796 | | /* Initialize r, s using mp_init(), not mp_init_size(), |
797 | | * as the latter is not compatible with DecodeECC_DSA_Sig(). |
798 | | * |
799 | | * See ZD 15728. |
800 | | */ |
801 | 391 | wolfCrypt_bignum::Bignum r(ds, false), s(ds, false); |
802 | | |
803 | 391 | CF_CHECK_NE(op.priv.ToTrimmedString(), "0"); |
804 | | |
805 | 389 | { |
806 | 389 | try { |
807 | 389 | sigSz = ds.Get<uint8_t>(); |
808 | 389 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
809 | | |
810 | 389 | sig = util::malloc(sigSz); |
811 | 389 | } |
812 | | |
813 | 389 | try { |
814 | 389 | ECCKey key(ds); |
815 | 389 | CF_CHECK_EQ(key.SetCurve(op.curveType), true); |
816 | 360 | CF_CHECK_EQ(key.LoadPrivateKey(op.priv), true); |
817 | 332 | key.GetPtr()->type = ECC_PRIVATEKEY_ONLY; |
818 | | |
819 | 332 | if ( op.UseSpecifiedNonce() == true ) { |
820 | 87 | CF_CHECK_EQ(nonce.Set(op.nonce.ToString(ds)), true); |
821 | | |
822 | 86 | const size_t nonce_bytes_size = mp_unsigned_bin_size(nonce.GetPtr()); |
823 | | |
824 | | /* Convert nonce to byte array */ |
825 | 86 | nonce_bytes = util::malloc(nonce_bytes_size); |
826 | 86 | CF_CHECK_EQ(mp_to_unsigned_bin(nonce.GetPtr(), nonce_bytes), 0); |
827 | | |
828 | | /* Set nonce */ |
829 | 81 | WC_CHECK_EQ(wc_ecc_sign_set_k(nonce_bytes, nonce_bytes_size, key.GetPtr()), 0); |
830 | 76 | } |
831 | | |
832 | 321 | auto pub = key.MakePub(); |
833 | 321 | CF_CHECK_NE(pub, std::nullopt); |
834 | | |
835 | 314 | if ( op.digestType.Get() == CF_DIGEST("NULL") ) { |
836 | 70 | CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType); |
837 | 244 | } else { |
838 | 244 | std::optional<wc_HashType> hashType; |
839 | 244 | CF_CHECK_NE(hashType = wolfCrypt_detail::toHashType(op.digestType), std::nullopt); |
840 | | |
841 | 228 | hashSize = wc_HashGetDigestSize(*hashType); |
842 | 228 | hash = util::malloc(hashSize); |
843 | | |
844 | 228 | WC_CHECK_EQ(wc_Hash(*hashType, op.cleartext.GetPtr(), op.cleartext.GetSize(), hash, hashSize), 0); |
845 | | |
846 | 228 | CT = Buffer(hash, hashSize).ECDSA_RandomPad(ds, op.curveType); |
847 | 228 | } |
848 | | |
849 | | /* Sign */ |
850 | 573 | WC_CHECK_EQ(wc_ecc_sign_hash(CT.GetPtr(), CT.GetSize(), sig, &sigSz, wolfCrypt_detail::GetRNG(), key.GetPtr()), 0); |
851 | | |
852 | | /* Verify */ |
853 | 573 | { |
854 | 573 | int verify; |
855 | 573 | haveAllocFailure = false; |
856 | 573 | if ( wc_ecc_verify_hash(sig, sigSz, CT.GetPtr(), CT.GetSize(), &verify, key.GetPtr()) == 0 && haveAllocFailure == false ) { |
857 | 219 | CF_ASSERT(verify, "Cannot verify generated signature"); |
858 | 219 | } |
859 | 573 | } |
860 | | |
861 | 275 | CF_CHECK_EQ(DecodeECC_DSA_Sig(sig, sigSz, r.GetPtr(), s.GetPtr()), 0); |
862 | 275 | { |
863 | 275 | std::optional<std::string> r_str, s_str; |
864 | | |
865 | 275 | if ( op.curveType.Get() == CF_ECC_CURVE("secp256k1") ) { |
866 | 34 | wolfCrypt_bignum::Bignum SMax(ds); |
867 | 34 | CF_CHECK_EQ(SMax.Set("57896044618658097711785492504343953926418782139537452191302581570759080747168"), true); |
868 | 34 | if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) { |
869 | 17 | wolfCrypt_bignum::Bignum SSub(ds); |
870 | 17 | CF_CHECK_EQ(SSub.Set("115792089237316195423570985008687907852837564279074904382605163141518161494337"), true); |
871 | 17 | CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0); |
872 | 17 | } |
873 | 241 | } else if ( op.curveType.Get() == CF_ECC_CURVE("secp256r1") ) { |
874 | 21 | wolfCrypt_bignum::Bignum SMax(ds); |
875 | 21 | CF_CHECK_EQ(SMax.Set("57896044605178124381348723474703786764998477612067880171211129530534256022184"), true); |
876 | 21 | if ( mp_cmp(s.GetPtr(), SMax.GetPtr()) == 1 ) { |
877 | 9 | wolfCrypt_bignum::Bignum SSub(ds); |
878 | 9 | CF_CHECK_EQ(SSub.Set("115792089210356248762697446949407573529996955224135760342422259061068512044369"), true); |
879 | 9 | CF_CHECK_EQ(mp_sub(SSub.GetPtr(), s.GetPtr(), s.GetPtr()), 0); |
880 | 9 | } |
881 | 21 | } |
882 | | |
883 | 275 | CF_CHECK_NE(r_str = r.ToDecString(), std::nullopt); |
884 | 275 | CF_CHECK_NE(s_str = s.ToDecString(), std::nullopt); |
885 | | |
886 | 274 | const auto pub2 = pub->ToBignumPair(); |
887 | 274 | CF_CHECK_NE(pub2, std::nullopt); |
888 | | |
889 | 273 | ret = component::ECDSA_Signature({*r_str, *s_str}, *pub2); |
890 | 273 | } |
891 | 273 | } catch ( ... ) { } |
892 | 391 | end: |
893 | | |
894 | 391 | util::free(sig); |
895 | 391 | util::free(hash); |
896 | 391 | util::free(nonce_bytes); |
897 | | |
898 | 391 | wolfCrypt_detail::UnsetGlobalDs(); |
899 | | |
900 | 391 | return ret; |
901 | 389 | } |
902 | | |
903 | 0 | std::optional<component::Ciphertext> OpECIES_Encrypt_Generic(operation::ECIES_Encrypt& op) { |
904 | 0 | std::optional<component::Ciphertext> ret = std::nullopt; |
905 | | #if !defined(HAVE_ECC_ENCRYPT) |
906 | | (void)op; |
907 | | #else |
908 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
909 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
910 | 0 | uint8_t* out = nullptr; |
911 | |
|
912 | 0 | CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC"))); |
913 | 0 | CF_CHECK_EQ(op.iv, std::nullopt); |
914 | |
|
915 | 0 | try { |
916 | 0 | ECCKey priv(ds), pub(ds); |
917 | 0 | word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF; |
918 | | |
919 | | /* Initialize private key */ |
920 | 0 | { |
921 | 0 | CF_CHECK_TRUE(priv.SetCurve(op.curveType)); |
922 | 0 | CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv)); |
923 | 0 | CF_CHECK_TRUE(priv.SetRNG()); |
924 | 0 | } |
925 | | |
926 | | /* Initialize public key */ |
927 | 0 | { |
928 | 0 | std::optional<int> curveID; |
929 | 0 | const char* name = nullptr; |
930 | |
|
931 | 0 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
932 | |
|
933 | 0 | CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr); |
934 | |
|
935 | 0 | WC_CHECK_EQ(wc_ecc_import_raw( |
936 | 0 | pub.GetPtr(), |
937 | 0 | util::DecToHex(op.pub.first.ToTrimmedString()).c_str(), |
938 | 0 | util::DecToHex(op.pub.second.ToTrimmedString()).c_str(), |
939 | 0 | nullptr, |
940 | 0 | name), 0); |
941 | |
|
942 | 0 | CF_CHECK_TRUE(pub.SetRNG()); |
943 | 0 | } |
944 | | |
945 | 0 | out = util::malloc(outSz); |
946 | |
|
947 | 0 | WC_CHECK_EQ(wc_ecc_encrypt(priv.GetPtr(), pub.GetPtr(), op.cleartext.GetPtr(), op.cleartext.GetSize(), out, &outSz, nullptr), 0); |
948 | |
|
949 | 0 | ret = component::Ciphertext(Buffer(out, outSz)); |
950 | 0 | } catch ( ... ) { } |
951 | | |
952 | 0 | end: |
953 | 0 | util::free(out); |
954 | |
|
955 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
956 | 0 | #endif |
957 | 0 | return ret; |
958 | 0 | } |
959 | | |
960 | 0 | std::optional<component::Cleartext> OpECIES_Decrypt_Generic(operation::ECIES_Decrypt& op) { |
961 | 0 | std::optional<component::Cleartext> ret = std::nullopt; |
962 | | #if !defined(HAVE_ECC_ENCRYPT) |
963 | | (void)op; |
964 | | #else |
965 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
966 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
967 | 0 | uint8_t* out = nullptr; |
968 | |
|
969 | 0 | CF_CHECK_TRUE(op.cipherType.Is(CF_CIPHER("AES_128_CBC"))); |
970 | 0 | CF_CHECK_EQ(op.iv, std::nullopt); |
971 | |
|
972 | 0 | try { |
973 | 0 | ECCKey priv(ds), pub(ds); |
974 | 0 | word32 outSz = ds.Get<uint32_t>() % 0xFFFFFF; |
975 | | |
976 | | /* Initialize private key */ |
977 | 0 | { |
978 | 0 | CF_CHECK_TRUE(priv.SetCurve(op.curveType)); |
979 | 0 | CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv)); |
980 | 0 | CF_CHECK_TRUE(priv.SetRNG()); |
981 | 0 | } |
982 | | |
983 | | /* Initialize public key */ |
984 | 0 | { |
985 | 0 | std::optional<int> curveID; |
986 | 0 | const char* name = nullptr; |
987 | |
|
988 | 0 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
989 | |
|
990 | 0 | CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr); |
991 | |
|
992 | 0 | WC_CHECK_EQ(wc_ecc_import_raw( |
993 | 0 | pub.GetPtr(), |
994 | 0 | util::DecToHex(op.pub.first.ToTrimmedString()).c_str(), |
995 | 0 | util::DecToHex(op.pub.second.ToTrimmedString()).c_str(), |
996 | 0 | nullptr, |
997 | 0 | name), 0); |
998 | |
|
999 | 0 | CF_CHECK_TRUE(pub.SetRNG()); |
1000 | 0 | } |
1001 | | |
1002 | 0 | out = util::malloc(outSz); |
1003 | |
|
1004 | 0 | WC_CHECK_EQ(wc_ecc_decrypt(priv.GetPtr(), pub.GetPtr(), op.ciphertext.GetPtr(), op.ciphertext.GetSize(), out, &outSz, nullptr), 0); |
1005 | |
|
1006 | 0 | ret = component::Cleartext(Buffer(out, outSz)); |
1007 | 0 | } catch ( ... ) { } |
1008 | | |
1009 | 0 | end: |
1010 | 0 | util::free(out); |
1011 | |
|
1012 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
1013 | 0 | #endif |
1014 | 0 | return ret; |
1015 | 0 | } |
1016 | | |
1017 | 54 | std::optional<component::Secret> OpECDH_Derive(operation::ECDH_Derive& op) { |
1018 | 54 | std::optional<component::Secret> ret = std::nullopt; |
1019 | 54 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
1020 | 54 | wolfCrypt_detail::SetGlobalDs(&ds); |
1021 | | |
1022 | | /* try/catch because ECCKey constructor may throw if allocation fails */ |
1023 | 54 | try { |
1024 | | /* TODO dynamic size */ |
1025 | 54 | uint8_t out[1024]; |
1026 | 54 | word32 outlen = sizeof(out); |
1027 | 54 | ECCKey priv(ds), pub(ds); |
1028 | | |
1029 | | /* Initialize private key */ |
1030 | 54 | { |
1031 | 54 | CF_CHECK_TRUE(priv.SetCurve(op.curveType)); |
1032 | 40 | CF_CHECK_TRUE(priv.LoadPrivateKey(op.priv)); |
1033 | 35 | CF_CHECK_TRUE(priv.SetRNG()); |
1034 | 35 | WC_CHECK_EQ( |
1035 | 35 | wc_ecc_set_flags(priv.GetPtr(), WC_ECC_FLAG_COFACTOR), 0); |
1036 | 35 | } |
1037 | | |
1038 | | /* Initialize public key */ |
1039 | 0 | { |
1040 | 35 | std::optional<int> curveID; |
1041 | 35 | const char* name = nullptr; |
1042 | | |
1043 | 35 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
1044 | | |
1045 | 35 | CF_CHECK_NE(name = wc_ecc_get_name(*curveID), nullptr); |
1046 | | |
1047 | 35 | WC_CHECK_EQ(wc_ecc_import_raw( |
1048 | 30 | pub.GetPtr(), |
1049 | 30 | util::DecToHex(op.pub.first.ToTrimmedString()).c_str(), |
1050 | 30 | util::DecToHex(op.pub.second.ToTrimmedString()).c_str(), |
1051 | 30 | nullptr, |
1052 | 30 | name), 0); |
1053 | 30 | WC_CHECK_EQ(wc_ecc_check_key(pub.GetPtr()), 0); |
1054 | 20 | } |
1055 | | |
1056 | 20 | WC_CHECK_EQ(wc_ecc_shared_secret(priv.GetPtr(), pub.GetPtr(), out, &outlen), 0); |
1057 | | |
1058 | 19 | ret = component::Secret(Buffer(out, outlen)); |
1059 | 19 | } catch ( ... ) { } |
1060 | | |
1061 | 54 | end: |
1062 | 54 | wolfCrypt_detail::UnsetGlobalDs(); |
1063 | | |
1064 | 54 | return ret; |
1065 | 54 | } |
1066 | | |
1067 | 253 | std::optional<component::ECC_Point> OpECC_Point_Add(operation::ECC_Point_Add& op) { |
1068 | 253 | std::optional<component::ECC_Point> ret = std::nullopt; |
1069 | 253 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
1070 | 253 | wolfCrypt_detail::SetGlobalDs(&ds); |
1071 | | |
1072 | 253 | std::optional<int> curveID; |
1073 | 253 | int curveIdx; |
1074 | 253 | const ecc_set_type* curve = nullptr; |
1075 | 253 | bool failed = false; |
1076 | 253 | bool valid = false; |
1077 | 253 | std::optional<bool> is_neg = std::nullopt; |
1078 | | |
1079 | 253 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
1080 | | |
1081 | 243 | CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID); |
1082 | 209 | CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr); |
1083 | | |
1084 | | /* try/catch because ECCPoint constructor may throw if allocation fails */ |
1085 | 209 | try { |
1086 | 209 | ECCPoint res(ds, *curveID), a(ds, *curveID), b(ds, *curveID); |
1087 | 209 | wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds); |
1088 | 209 | mp_digit mp; |
1089 | | |
1090 | | /* Set points */ |
1091 | 209 | CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get())); |
1092 | 207 | CF_CHECK_TRUE(b.Set(op.b, op.curveType.Get())); |
1093 | | |
1094 | 205 | valid = a.CurveCheck() && b.CurveCheck(); |
1095 | | |
1096 | | /* Retrieve curve parameter */ |
1097 | 205 | CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true); |
1098 | 204 | CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true); |
1099 | | |
1100 | 202 | is_neg = a.IsNeg(b, prime); |
1101 | | |
1102 | 202 | CF_CHECK_TRUE(a.ToProjective(prime)); |
1103 | 190 | CF_CHECK_TRUE(b.ToProjective(prime)); |
1104 | | |
1105 | 187 | WC_CHECK_EQ(mp_montgomery_setup(prime.GetPtr(), &mp), MP_OKAY); |
1106 | | |
1107 | | #if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_PUBLIC_ECC_ADD_DBL) |
1108 | | goto end; |
1109 | | #else |
1110 | 187 | { |
1111 | 187 | bool dbl = false; |
1112 | 187 | bool safe = false; |
1113 | | |
1114 | 187 | if ( a.Compare(b) == MP_EQ ) { |
1115 | 24 | try { dbl = ds.Get<bool>(); } catch ( ... ) { } |
1116 | 24 | } |
1117 | | |
1118 | 187 | #if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)) |
1119 | 187 | try { safe = ds.Get<bool>(); } catch ( ... ) { } |
1120 | 187 | #endif |
1121 | | |
1122 | 187 | if ( safe ) { |
1123 | | #if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL) |
1124 | | CF_UNREACHABLE(); |
1125 | | #else |
1126 | 9 | int infinity; |
1127 | | |
1128 | 9 | if ( dbl == true ) { |
1129 | 2 | failed = true; |
1130 | 2 | haveAllocFailure = false; |
1131 | 2 | WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0); |
1132 | 1 | failed = false; |
1133 | 7 | } else { |
1134 | 7 | failed = true; |
1135 | 7 | haveAllocFailure = false; |
1136 | 7 | WC_CHECK_EQ(ecc_projective_add_point_safe(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp, &infinity), 0); |
1137 | 5 | failed = false; |
1138 | 5 | } |
1139 | 9 | #endif |
1140 | 111 | } else { |
1141 | 111 | if ( dbl == true ) { |
1142 | 3 | failed = true; |
1143 | 3 | haveAllocFailure = false; |
1144 | 3 | WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0); |
1145 | 1 | failed = false; |
1146 | 108 | } else { |
1147 | 108 | failed = true; |
1148 | 108 | haveAllocFailure = false; |
1149 | 108 | WC_CHECK_EQ(ecc_projective_add_point(a.GetPtr(), b.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0); |
1150 | 101 | failed = false; |
1151 | | |
1152 | | /* Do not return result if inputs are negations of the same point */ |
1153 | 101 | CF_CHECK_NE(is_neg, std::nullopt); |
1154 | 98 | CF_CHECK_FALSE(*is_neg); |
1155 | 95 | } |
1156 | 111 | } |
1157 | | |
1158 | | /* Lock to prevent exporting the projective point */ |
1159 | 102 | res.Lock(); |
1160 | 102 | } |
1161 | 0 | #endif |
1162 | | |
1163 | | /* To affine */ |
1164 | 102 | WC_CHECK_EQ(ecc_map(res.GetPtr(), prime.GetPtr(), mp), MP_OKAY); |
1165 | | |
1166 | | /* Only return the result if the input points are valid */ |
1167 | 98 | CF_CHECK_TRUE(valid); |
1168 | | |
1169 | | /* Only return the result if the output point is valid */ |
1170 | 9 | CF_CHECK_TRUE(res.CurveCheck()); |
1171 | | |
1172 | 8 | ret = res.ToBignumPair(); |
1173 | 67 | } catch ( ... ) { } |
1174 | | |
1175 | 253 | end: |
1176 | 253 | wolfCrypt_detail::UnsetGlobalDs(); |
1177 | | |
1178 | 253 | if ( valid ) { |
1179 | 14 | if ( !haveAllocFailure ) { |
1180 | 11 | if ( is_neg && !*is_neg ) { |
1181 | 7 | CF_ASSERT(!failed, "Point adding failed"); |
1182 | 7 | } |
1183 | 11 | } |
1184 | 14 | } |
1185 | | |
1186 | 253 | return ret; |
1187 | 253 | } |
1188 | | |
1189 | 413 | std::optional<component::ECC_Point> OpECC_Point_Mul(operation::ECC_Point_Mul& op) { |
1190 | 413 | std::optional<component::ECC_Point> ret = std::nullopt; |
1191 | 413 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
1192 | 413 | wolfCrypt_detail::SetGlobalDs(&ds); |
1193 | | |
1194 | 413 | std::optional<int> curveID; |
1195 | 413 | int curveIdx; |
1196 | 413 | const ecc_set_type* curve = nullptr; |
1197 | | |
1198 | 413 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
1199 | | |
1200 | 400 | CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID); |
1201 | 305 | CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr); |
1202 | | |
1203 | | /* try/catch because ECCPoint constructor may throw if allocation fails */ |
1204 | 305 | try { |
1205 | 305 | ECCPoint res(ds, *curveID), a(ds, *curveID); |
1206 | 305 | wolfCrypt_bignum::Bignum b(ds), Af(ds), prime(ds); |
1207 | 305 | bool valid = false; |
1208 | | |
1209 | | /* Set point */ |
1210 | 305 | CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get())); |
1211 | 301 | valid = a.CurveCheck(); |
1212 | | |
1213 | | /* Set multiplier */ |
1214 | 301 | CF_CHECK_EQ(b.Set(op.b.ToString(ds)), true); |
1215 | | |
1216 | | /* Retrieve curve parameters */ |
1217 | 298 | CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true); |
1218 | 297 | CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true); |
1219 | | |
1220 | | /* Multiply */ |
1221 | 296 | WC_CHECK_EQ(wc_ecc_mulmod_ex(b.GetPtr(), a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), 1, nullptr), 0); |
1222 | | |
1223 | | /* Only return the result if the input point is valid */ |
1224 | 247 | CF_CHECK_TRUE(valid); |
1225 | | |
1226 | 88 | ret = res.ToBignumPair(); |
1227 | 88 | } catch ( ... ) { } |
1228 | | |
1229 | 413 | end: |
1230 | 413 | wolfCrypt_detail::UnsetGlobalDs(); |
1231 | | |
1232 | 413 | return ret; |
1233 | 305 | } |
1234 | | |
1235 | 265 | std::optional<component::ECC_Point> OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) { |
1236 | 265 | std::optional<component::ECC_Point> ret = std::nullopt; |
1237 | 265 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
1238 | 265 | wolfCrypt_detail::SetGlobalDs(&ds); |
1239 | | |
1240 | 265 | std::optional<int> curveID; |
1241 | 265 | int curveIdx; |
1242 | 265 | const ecc_set_type* curve = nullptr; |
1243 | 265 | bool failed = false; |
1244 | 265 | bool valid = false; |
1245 | | |
1246 | 265 | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
1247 | | |
1248 | 257 | CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID); |
1249 | 219 | CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr); |
1250 | | |
1251 | | /* try/catch because ECCPoint constructor may throw if allocation fails */ |
1252 | 219 | try { |
1253 | 219 | ECCPoint res(ds, *curveID), a(ds, *curveID); |
1254 | 219 | wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds); |
1255 | 219 | mp_digit mp; |
1256 | | |
1257 | | /* Set points */ |
1258 | 219 | CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get())); |
1259 | | |
1260 | 214 | valid = a.CurveCheck(); |
1261 | | |
1262 | | /* Retrieve curve parameter */ |
1263 | 214 | CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true); |
1264 | 213 | CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true); |
1265 | | |
1266 | 212 | CF_CHECK_TRUE(a.ToProjective(prime)); |
1267 | | |
1268 | 201 | WC_CHECK_EQ(mp_montgomery_setup(prime.GetPtr(), &mp), MP_OKAY); |
1269 | | |
1270 | | #if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_PUBLIC_ECC_ADD_DBL) |
1271 | | goto end; |
1272 | | #else |
1273 | 201 | { |
1274 | 201 | bool safe = false; |
1275 | | |
1276 | 201 | #if !(defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL)) |
1277 | 201 | try { safe = ds.Get<bool>(); } catch ( ... ) { } |
1278 | 201 | #endif |
1279 | | |
1280 | 201 | if ( safe ) { |
1281 | | #if defined(WOLFSSL_SP_MATH) && defined(WOLFSSL_PUBLIC_ECC_ADD_DBL) |
1282 | | CF_UNREACHABLE(); |
1283 | | #else |
1284 | 5 | failed = true; |
1285 | 5 | haveAllocFailure = false; |
1286 | 5 | WC_CHECK_EQ(ecc_projective_dbl_point_safe(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0); |
1287 | 3 | failed = false; |
1288 | 3 | #endif |
1289 | 155 | } else { |
1290 | 155 | failed = true; |
1291 | 155 | haveAllocFailure = false; |
1292 | 155 | WC_CHECK_EQ(ecc_projective_dbl_point(a.GetPtr(), res.GetPtr(), Af.GetPtr(), prime.GetPtr(), mp), 0); |
1293 | 149 | failed = false; |
1294 | 149 | } |
1295 | | |
1296 | | /* Lock to prevent exporting the projective point */ |
1297 | 152 | res.Lock(); |
1298 | 152 | } |
1299 | 0 | #endif |
1300 | | |
1301 | | /* To affine */ |
1302 | 152 | WC_CHECK_EQ(ecc_map(res.GetPtr(), prime.GetPtr(), mp), MP_OKAY); |
1303 | | |
1304 | | /* Only return the result if the input points are valid */ |
1305 | 151 | CF_CHECK_TRUE(valid); |
1306 | | |
1307 | | /* Only return the result if the output point is valid */ |
1308 | 14 | CF_CHECK_TRUE(res.CurveCheck()); |
1309 | | |
1310 | 13 | ret = res.ToBignumPair(); |
1311 | 41 | } catch ( ... ) { } |
1312 | | |
1313 | 265 | end: |
1314 | 265 | if ( valid ) { |
1315 | 16 | if ( !haveAllocFailure ) { |
1316 | 11 | CF_ASSERT(!failed, "Point doubling failed"); |
1317 | 11 | } |
1318 | 16 | } |
1319 | | |
1320 | 265 | wolfCrypt_detail::UnsetGlobalDs(); |
1321 | | |
1322 | 265 | return ret; |
1323 | 265 | } |
1324 | | |
1325 | 0 | std::optional<bool> OpECC_Point_Cmp(operation::ECC_Point_Cmp& op) { |
1326 | | #if 0 |
1327 | | std::optional<bool> ret = std::nullopt; |
1328 | | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
1329 | | wolfCrypt_detail::SetGlobalDs(&ds); |
1330 | | |
1331 | | std::optional<int> curveID; |
1332 | | int curveIdx; |
1333 | | const ecc_set_type* curve = nullptr; |
1334 | | |
1335 | | CF_CHECK_NE(curveID = wolfCrypt_detail::toCurveID(op.curveType), std::nullopt); |
1336 | | |
1337 | | CF_CHECK_NE(curveIdx = wc_ecc_get_curve_idx(*curveID), ECC_CURVE_INVALID); |
1338 | | CF_CHECK_NE(curve = wc_ecc_get_curve_params(curveIdx), nullptr); |
1339 | | |
1340 | | /* try/catch because ECCPoint constructor may throw if allocation fails */ |
1341 | | try { |
1342 | | ECCPoint res(ds, *curveID), a(ds, *curveID), b(ds, *curveID); |
1343 | | wolfCrypt_bignum::Bignum Af(ds), prime(ds), mu(ds); |
1344 | | bool valid = false; |
1345 | | |
1346 | | /* Set points */ |
1347 | | CF_CHECK_TRUE(a.Set(op.a, op.curveType.Get())); |
1348 | | CF_CHECK_TRUE(b.Set(op.b, op.curveType.Get())); |
1349 | | |
1350 | | valid = a.CurveCheck() && b.CurveCheck(); |
1351 | | (void)valid; |
1352 | | |
1353 | | /* Retrieve curve parameter */ |
1354 | | CF_CHECK_EQ(Af.Set(util::HexToDec(curve->Af)), true); |
1355 | | CF_CHECK_EQ(prime.Set(util::HexToDec(curve->prime)), true); |
1356 | | |
1357 | | CF_CHECK_TRUE(a.ToProjective(prime)); |
1358 | | CF_CHECK_TRUE(b.ToProjective(prime)); |
1359 | | |
1360 | | ret = wc_ecc_cmp_point(a.GetPtr(), b.GetPtr()) == MP_EQ; |
1361 | | } catch ( ... ) { } |
1362 | | |
1363 | | end: |
1364 | | wolfCrypt_detail::UnsetGlobalDs(); |
1365 | | |
1366 | | return ret; |
1367 | | #else |
1368 | | /* ZD 15599 */ |
1369 | 0 | (void)op; |
1370 | 0 | return std::nullopt; |
1371 | 0 | #endif |
1372 | 0 | } |
1373 | | |
1374 | | } /* namespace wolfCrypt_detail */ |
1375 | | } /* namespace module */ |
1376 | | } /* namespace cryptofuzz */ |