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