/src/cryptofuzz/modules/wolfcrypt/ecdsa_25519.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | #include "ecdsa_25519.h"  | 
2  |  | #include "module_internal.h"  | 
3  |  | #include "shared.h"  | 
4  |  | #include "bn_ops.h"  | 
5  |  | #include <cryptofuzz/util.h>  | 
6  |  |  | 
7  |  | extern "C" { | 
8  |  | #include <wolfssl/options.h>  | 
9  |  | #include <wolfssl/wolfcrypt/curve25519.h>  | 
10  |  | #include <wolfssl/wolfcrypt/ed25519.h>  | 
11  |  | }  | 
12  |  |  | 
13  |  | namespace cryptofuzz { | 
14  |  | namespace module { | 
15  |  | namespace wolfCrypt_detail { | 
16  |  |  | 
17  |  | #if defined(CRYPTOFUZZ_WOLFCRYPT_ALLOCATION_FAILURES)  | 
18  |  |     extern bool haveAllocFailure;  | 
19  |  | #endif  | 
20  |  |  | 
21  | 74  | static bool ed25519LoadPrivateKey(ed25519_key& key, component::Bignum priv, Datasource& ds) { | 
22  | 74  |     bool ret = false;  | 
23  |  |  | 
24  | 74  |     uint8_t priv_bytes[ED25519_KEY_SIZE];  | 
25  |  |  | 
26  | 74  |     CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, priv, priv_bytes, sizeof(priv_bytes)), true);  | 
27  | 71  |     CF_CHECK_EQ(wc_ed25519_import_private_only(priv_bytes, sizeof(priv_bytes), &key), 0);  | 
28  |  |  | 
29  | 71  |     ret = true;  | 
30  | 74  | end:  | 
31  | 74  |     return ret;  | 
32  | 71  | }  | 
33  |  |  | 
34  | 87  | static bool ed25519LoadPublicKey(ed25519_key& key, component::Bignum pub, Datasource& ds, const bool mustSucceed = false) { | 
35  | 87  |     bool ret = false;  | 
36  |  |  | 
37  | 87  |     uint8_t pub_bytes[ED25519_PUB_KEY_SIZE];  | 
38  | 87  |     CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, pub, pub_bytes, sizeof(pub_bytes), mustSucceed), true);  | 
39  | 86  |     CF_CHECK_EQ(wc_ed25519_import_public(pub_bytes, sizeof(pub_bytes), &key), 0);  | 
40  |  |  | 
41  | 86  |     ret = true;  | 
42  | 87  | end:  | 
43  | 87  |     return ret;  | 
44  | 86  | }  | 
45  |  |  | 
46  | 103  | static std::optional<std::vector<uint8_t>> ed25519GetPublicKeyAsVector(ed25519_key& key) { | 
47  | 103  |     std::optional<std::vector<uint8_t>> ret = std::nullopt;  | 
48  | 103  |     uint8_t pub_bytes[ED25519_PUB_KEY_SIZE];  | 
49  |  |  | 
50  | 103  |     WC_CHECK_EQ(wc_ed25519_make_public(&key, pub_bytes, sizeof(pub_bytes)), MP_OKAY);  | 
51  |  |  | 
52  | 92  |     ret = std::vector<uint8_t>(pub_bytes, pub_bytes + sizeof(pub_bytes));  | 
53  | 103  | end:  | 
54  | 103  |     return ret;  | 
55  | 92  | }  | 
56  |  |  | 
57  | 54  | static std::optional<component::ECC_PublicKey> ed25519GetPublicKey(ed25519_key& key, Datasource& ds) { | 
58  | 54  |     std::optional<component::ECC_PublicKey> ret = std::nullopt;  | 
59  | 54  |     std::optional<std::vector<uint8_t>> pubv = std::nullopt;  | 
60  | 54  |     std::optional<component::Bignum> pub = std::nullopt;  | 
61  |  |  | 
62  | 54  |     CF_CHECK_NE(pubv = ed25519GetPublicKeyAsVector(key), std::nullopt);  | 
63  | 47  |     CF_CHECK_NE(pub = wolfCrypt_bignum::Bignum::BinToBignum(ds, pubv->data(), pubv->size()), std::nullopt);  | 
64  |  |  | 
65  | 45  |     ret = {pub->ToString(), "0"}; | 
66  |  |  | 
67  | 54  | end:  | 
68  | 54  |     return ret;  | 
69  | 45  | }  | 
70  |  |  | 
71  | 49  | static bool ed25519DerivePublicKey(ed25519_key& key) { | 
72  | 49  |     std::optional<std::vector<uint8_t>> pubv = std::nullopt;  | 
73  | 49  |     bool ret = false;  | 
74  |  |  | 
75  | 49  |     CF_CHECK_NE(pubv = ed25519GetPublicKeyAsVector(key), std::nullopt);  | 
76  | 45  |     memcpy(key.p, pubv->data(), ED25519_PUB_KEY_SIZE);  | 
77  | 45  |     key.pubKeySet = 1;  | 
78  |  |  | 
79  | 45  |     ret = true;  | 
80  |  |  | 
81  | 49  | end:  | 
82  | 49  |     return ret;  | 
83  | 45  | }  | 
84  |  |  | 
85  | 75  | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Curve25519(operation::ECC_PrivateToPublic& op) { | 
86  | 75  |     std::optional<component::ECC_PublicKey> ret = std::nullopt;  | 
87  | 75  |     Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());  | 
88  | 75  |     wolfCrypt_detail::SetGlobalDs(&ds);  | 
89  |  |  | 
90  | 75  |     wolfCrypt_bignum::Bignum priv(ds), pub(ds);  | 
91  | 75  |     uint8_t pub_bytes[CURVE25519_KEYSIZE];  | 
92  | 75  |     uint8_t priv_bytes[CURVE25519_KEYSIZE];  | 
93  |  |  | 
94  |  |     /* Load private key */  | 
95  | 75  |     { | 
96  | 75  |         CF_CHECK_EQ(priv.Set(op.priv.ToString(ds)), true);  | 
97  | 71  |         CF_CHECK_TRUE(priv.ToBin(priv_bytes, sizeof(priv_bytes)));  | 
98  | 66  |         priv_bytes[0] &= 248;  | 
99  | 66  |         priv_bytes[31] &= 127;  | 
100  | 66  |         priv_bytes[31] |= 64;  | 
101  | 66  |     }  | 
102  |  |  | 
103  |  |     /* Convert to public key */  | 
104  | 0  |     { | 
105  | 66  |         WC_CHECK_EQ(wc_curve25519_make_pub(sizeof(pub_bytes), pub_bytes, sizeof(priv_bytes), priv_bytes), MP_OKAY);  | 
106  | 66  |     }  | 
107  |  |  | 
108  |  |     /* Convert public key */  | 
109  | 0  |     { | 
110  | 66  |         std::optional<std::string> pub_x_str;  | 
111  | 66  |         CF_CHECK_EQ(mp_read_unsigned_bin(pub.GetPtr(), pub_bytes, sizeof(pub_bytes)), MP_OKAY);  | 
112  | 64  |         CF_CHECK_NE(pub_x_str = pub.ToDecString(), std::nullopt);  | 
113  | 59  |         ret = { *pub_x_str, "0" }; | 
114  | 59  |     }  | 
115  |  |  | 
116  | 75  | end:  | 
117  | 75  |     wolfCrypt_detail::UnsetGlobalDs();  | 
118  | 75  |     return ret;  | 
119  | 59  | }  | 
120  |  |  | 
121  | 23  | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Ed25519(operation::ECC_PrivateToPublic& op) { | 
122  | 23  |     std::optional<component::ECC_PublicKey> ret = std::nullopt;  | 
123  | 23  |     Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());  | 
124  | 23  |     wolfCrypt_detail::SetGlobalDs(&ds);  | 
125  |  |  | 
126  | 23  |     wolfCrypt_bignum::Bignum priv(ds), pub(ds);  | 
127  |  |  | 
128  | 23  |     ed25519_key key;  | 
129  | 23  |     bool e25519_key_inited = false;  | 
130  |  |  | 
131  | 23  |     WC_CHECK_EQ(wc_ed25519_init(&key), 0);  | 
132  | 23  |     e25519_key_inited = true;  | 
133  |  |  | 
134  | 23  |     CF_CHECK_EQ(ed25519LoadPrivateKey(key, op.priv, ds), true);  | 
135  | 22  |     ret = ed25519GetPublicKey(key, ds);  | 
136  |  |  | 
137  | 23  | end:  | 
138  | 23  |     if ( e25519_key_inited == true ) { | 
139  | 23  |         wc_ed25519_free(&key);  | 
140  | 23  |     }  | 
141  |  |  | 
142  | 23  |     wolfCrypt_detail::UnsetGlobalDs();  | 
143  | 23  |     return ret;  | 
144  | 22  | }  | 
145  |  |  | 
146  | 0  | std::optional<bool> OpECC_ValidatePubkey_Curve25519(operation::ECC_ValidatePubkey& op) { | 
147  | 0  |     std::optional<bool> ret = std::nullopt;  | 
148  | 0  |     Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());  | 
149  | 0  |     wolfCrypt_detail::SetGlobalDs(&ds);  | 
150  |  | 
  | 
151  | 0  |     wolfCrypt_bignum::Bignum pub(ds);  | 
152  | 0  |     uint8_t pub_bytes[CURVE25519_KEYSIZE];  | 
153  |  | 
  | 
154  | 0  |     CF_CHECK_EQ(pub.Set(op.pub.first.ToString(ds)), true);  | 
155  | 0  |     CF_CHECK_TRUE(pub.ToBin(pub_bytes, sizeof(pub_bytes)));  | 
156  |  | 
  | 
157  | 0  |     haveAllocFailure = false;  | 
158  | 0  |     ret = wc_curve25519_check_public(pub_bytes, sizeof(pub_bytes), EC25519_BIG_ENDIAN) == 0;  | 
159  | 0  |     if ( *ret == false && haveAllocFailure == true ) { | 
160  | 0  |         ret = std::nullopt;  | 
161  | 0  |     }  | 
162  |  | 
  | 
163  | 0  | end:  | 
164  |  | 
  | 
165  | 0  |     wolfCrypt_detail::UnsetGlobalDs();  | 
166  | 0  |     return ret;  | 
167  | 0  | }  | 
168  |  |  | 
169  | 0  | std::optional<bool> OpECC_ValidatePubkey_Ed25519(operation::ECC_ValidatePubkey& op) { | 
170  | 0  |     std::optional<bool> ret = std::nullopt;  | 
171  | 0  |     Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());  | 
172  | 0  |     wolfCrypt_detail::SetGlobalDs(&ds);  | 
173  |  | 
  | 
174  | 0  |     ed25519_key key;  | 
175  | 0  |     bool e25519_key_inited = false;  | 
176  |  | 
  | 
177  | 0  |     WC_CHECK_EQ(wc_ed25519_init(&key), 0);  | 
178  | 0  |     e25519_key_inited = true;  | 
179  |  | 
  | 
180  | 0  |     CF_CHECK_EQ(ed25519LoadPublicKey(key, op.pub.first, ds), true);  | 
181  |  | 
  | 
182  | 0  |     haveAllocFailure = false;  | 
183  | 0  |     ret = wc_ed25519_check_key(&key) == 0;  | 
184  | 0  |     if ( *ret == false && haveAllocFailure == true ) { | 
185  | 0  |         ret = std::nullopt;  | 
186  | 0  |     }  | 
187  |  | 
  | 
188  | 0  | end:  | 
189  | 0  |     if ( e25519_key_inited == true ) { | 
190  | 0  |         wc_ed25519_free(&key);  | 
191  | 0  |     }  | 
192  |  | 
  | 
193  | 0  |     wolfCrypt_detail::UnsetGlobalDs();  | 
194  | 0  |     return ret;  | 
195  | 0  | }  | 
196  |  |  | 
197  | 51  | std::optional<component::ECDSA_Signature> OpECDSA_Sign_ed25519(operation::ECDSA_Sign& op) { | 
198  | 51  |     std::optional<component::ECDSA_Signature> ret = std::nullopt;  | 
199  | 51  |     Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());  | 
200  | 51  |     wolfCrypt_detail::SetGlobalDs(&ds);  | 
201  |  |  | 
202  | 51  |     ed25519_key key;  | 
203  | 51  |     bool e25519_key_inited = false;  | 
204  | 51  |     uint8_t sig[ED25519_SIG_SIZE];  | 
205  | 51  |     word32 sigSz = sizeof(sig);  | 
206  |  |  | 
207  | 51  |     WC_CHECK_EQ(wc_ed25519_init(&key), 0);  | 
208  | 51  |     e25519_key_inited = true;  | 
209  |  |  | 
210  | 51  |     CF_CHECK_EQ(wolfCrypt_detail::ed25519LoadPrivateKey(key, op.priv, ds), true);  | 
211  | 49  |     CF_CHECK_EQ(wolfCrypt_detail::ed25519DerivePublicKey(key), true);  | 
212  |  |  | 
213  |  |     /* Sign message */  | 
214  | 45  |     WC_CHECK_EQ(wc_ed25519_sign_msg(op.cleartext.GetPtr(), op.cleartext.GetSize(), sig, &sigSz, &key), MP_OKAY);  | 
215  | 34  |     CF_CHECK_EQ(sigSz, ED25519_SIG_SIZE);  | 
216  | 34  |     static_assert(ED25519_SIG_SIZE % 2 == 0);  | 
217  |  |  | 
218  | 34  |     { | 
219  | 34  |         std::optional<component::BignumPair> ret_sig;  | 
220  | 34  |         std::optional<component::BignumPair> ret_pub;  | 
221  |  |  | 
222  | 34  |         CF_CHECK_NE(ret_sig = wolfCrypt_bignum::Bignum::BinToBignumPair(ds, sig, ED25519_SIG_SIZE), std::nullopt);  | 
223  | 32  |         CF_CHECK_NE(ret_pub = wolfCrypt_detail::ed25519GetPublicKey(key, ds), std::nullopt);  | 
224  |  |  | 
225  | 32  |         ret = component::ECDSA_Signature(*ret_sig, *ret_pub);  | 
226  | 32  |     }  | 
227  |  |  | 
228  | 51  | end:  | 
229  | 51  |     if ( e25519_key_inited == true ) { | 
230  | 51  |         wc_ed25519_free(&key);  | 
231  | 51  |     }  | 
232  |  |  | 
233  | 51  |     wolfCrypt_detail::UnsetGlobalDs();  | 
234  | 51  |     return ret;  | 
235  | 32  | }  | 
236  |  |  | 
237  | 87  | std::optional<bool> OpECDSA_Verify_ed25519(operation::ECDSA_Verify& op) { | 
238  | 87  |     std::optional<bool> ret = std::nullopt;  | 
239  | 87  |     Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());  | 
240  | 87  |     wolfCrypt_detail::SetGlobalDs(&ds);  | 
241  |  |  | 
242  | 87  |     ed25519_key key;  | 
243  | 87  |     bool e25519_key_inited = false;  | 
244  | 87  |     uint8_t ed25519sig[ED25519_SIG_SIZE];  | 
245  | 87  |     int verify;  | 
246  | 87  |     bool oneShot = true;  | 
247  | 87  |     bool haveEmptyPart = false;  | 
248  |  |  | 
249  | 87  |     haveAllocFailure = false;  | 
250  | 87  |     ret = false;  | 
251  |  |  | 
252  | 87  |     WC_CHECK_EQ(wc_ed25519_init(&key), 0);  | 
253  | 87  |     e25519_key_inited = true;  | 
254  |  |  | 
255  | 87  |     CF_CHECK_EQ(ed25519LoadPublicKey(key, op.signature.pub.first, ds, true), true);  | 
256  | 86  |     CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, op.signature.signature, ed25519sig, sizeof(ed25519sig), true), true);  | 
257  |  |  | 
258  | 82  | #if defined(WOLFSSL_ED25519_STREAMING_VERIFY)  | 
259  | 82  |     try { oneShot = ds.Get<bool>(); } catch ( ... ) { } | 
260  | 82  | #endif  | 
261  |  |  | 
262  | 82  |     if ( oneShot == true ) { | 
263  | 43  |         WC_CHECK_EQ(wc_ed25519_verify_msg(ed25519sig, sizeof(ed25519sig), op.cleartext.GetPtr(), op.cleartext.GetSize(), &verify, &key), 0);  | 
264  | 39  |     } else { | 
265  |  | #if !defined(WOLFSSL_ED25519_STREAMING_VERIFY)  | 
266  |  |         CF_UNREACHABLE();  | 
267  |  | #else  | 
268  | 39  |         const auto parts = util::ToParts(ds, op.cleartext);  | 
269  |  |  | 
270  | 39  |         WC_CHECK_EQ(wc_ed25519_verify_msg_init(ed25519sig, sizeof(ed25519sig), &key, (byte)Ed25519, nullptr, 0), 0);  | 
271  |  |  | 
272  | 53  |         for (const auto& part : parts) { | 
273  | 53  |             if ( part.second == 0 ) { | 
274  | 3  |                 haveEmptyPart = true;  | 
275  | 3  |             }  | 
276  | 53  |             WC_CHECK_EQ(wc_ed25519_verify_msg_update(part.first, part.second, &key), 0);  | 
277  | 49  |         }  | 
278  |  |  | 
279  | 41  |         WC_CHECK_EQ(wc_ed25519_verify_msg_final(ed25519sig, sizeof(ed25519sig), &verify, &key), 0);  | 
280  | 41  | #endif  | 
281  | 41  |     }  | 
282  |  |  | 
283  | 25  |     ret = verify ? true : false;  | 
284  |  |  | 
285  | 87  | end:  | 
286  | 87  |     if ( e25519_key_inited == true ) { | 
287  | 87  |         wc_ed25519_free(&key);  | 
288  | 87  |     }  | 
289  |  |  | 
290  | 87  |     wolfCrypt_detail::UnsetGlobalDs();  | 
291  |  |  | 
292  | 87  |     if ( ret && *ret == false ) { | 
293  | 62  |         if ( haveAllocFailure ) { | 
294  | 18  |             ret = std::nullopt;  | 
295  | 44  |         } else if ( haveEmptyPart ) { | 
296  | 3  |             ret = std::nullopt;  | 
297  | 41  |         } else if ( op.cleartext.IsZero() ) { | 
298  | 5  |             ret = std::nullopt;  | 
299  | 5  |         }  | 
300  |  |  | 
301  | 62  |     }  | 
302  | 87  |     return ret;  | 
303  | 25  | }  | 
304  |  |  | 
305  |  | } /* namespace wolfCrypt_detail */  | 
306  |  | } /* namespace module */  | 
307  |  | } /* namespace cryptofuzz */  |