/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 | 0 | static bool ed25519LoadPrivateKey(ed25519_key& key, component::Bignum priv, Datasource& ds) { |
22 | 0 | bool ret = false; |
23 | |
|
24 | 0 | uint8_t priv_bytes[ED25519_KEY_SIZE]; |
25 | |
|
26 | 0 | CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, priv, priv_bytes, sizeof(priv_bytes)), true); |
27 | 0 | CF_CHECK_EQ(wc_ed25519_import_private_only(priv_bytes, sizeof(priv_bytes), &key), 0); |
28 | |
|
29 | 0 | ret = true; |
30 | 0 | end: |
31 | 0 | return ret; |
32 | 0 | } |
33 | | |
34 | 0 | static bool ed25519LoadPublicKey(ed25519_key& key, component::Bignum pub, Datasource& ds, const bool mustSucceed = false) { |
35 | 0 | bool ret = false; |
36 | |
|
37 | 0 | uint8_t pub_bytes[ED25519_PUB_KEY_SIZE]; |
38 | 0 | CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, pub, pub_bytes, sizeof(pub_bytes), mustSucceed), true); |
39 | 0 | CF_CHECK_EQ(wc_ed25519_import_public(pub_bytes, sizeof(pub_bytes), &key), 0); |
40 | |
|
41 | 0 | ret = true; |
42 | 0 | end: |
43 | 0 | return ret; |
44 | 0 | } |
45 | | |
46 | 0 | static std::optional<std::vector<uint8_t>> ed25519GetPublicKeyAsVector(ed25519_key& key) { |
47 | 0 | std::optional<std::vector<uint8_t>> ret = std::nullopt; |
48 | 0 | uint8_t pub_bytes[ED25519_PUB_KEY_SIZE]; |
49 | |
|
50 | 0 | WC_CHECK_EQ(wc_ed25519_make_public(&key, pub_bytes, sizeof(pub_bytes)), MP_OKAY); |
51 | |
|
52 | 0 | ret = std::vector<uint8_t>(pub_bytes, pub_bytes + sizeof(pub_bytes)); |
53 | 0 | end: |
54 | 0 | return ret; |
55 | 0 | } |
56 | | |
57 | 0 | static std::optional<component::ECC_PublicKey> ed25519GetPublicKey(ed25519_key& key, Datasource& ds) { |
58 | 0 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
59 | 0 | std::optional<std::vector<uint8_t>> pubv = std::nullopt; |
60 | 0 | std::optional<component::Bignum> pub = std::nullopt; |
61 | |
|
62 | 0 | CF_CHECK_NE(pubv = ed25519GetPublicKeyAsVector(key), std::nullopt); |
63 | 0 | CF_CHECK_NE(pub = wolfCrypt_bignum::Bignum::BinToBignum(ds, pubv->data(), pubv->size()), std::nullopt); |
64 | |
|
65 | 0 | ret = {pub->ToString(), "0"}; |
66 | |
|
67 | 0 | end: |
68 | 0 | return ret; |
69 | 0 | } |
70 | | |
71 | 0 | static bool ed25519DerivePublicKey(ed25519_key& key) { |
72 | 0 | std::optional<std::vector<uint8_t>> pubv = std::nullopt; |
73 | 0 | bool ret = false; |
74 | |
|
75 | 0 | CF_CHECK_NE(pubv = ed25519GetPublicKeyAsVector(key), std::nullopt); |
76 | 0 | memcpy(key.p, pubv->data(), ED25519_PUB_KEY_SIZE); |
77 | 0 | key.pubKeySet = 1; |
78 | |
|
79 | 0 | ret = true; |
80 | |
|
81 | 0 | end: |
82 | 0 | return ret; |
83 | 0 | } |
84 | | |
85 | 0 | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Curve25519(operation::ECC_PrivateToPublic& op) { |
86 | 0 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
87 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
88 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
89 | |
|
90 | 0 | wolfCrypt_bignum::Bignum priv(ds), pub(ds); |
91 | 0 | uint8_t pub_bytes[CURVE25519_KEYSIZE]; |
92 | 0 | uint8_t priv_bytes[CURVE25519_KEYSIZE]; |
93 | | |
94 | | /* Load private key */ |
95 | 0 | { |
96 | 0 | CF_CHECK_EQ(priv.Set(op.priv.ToString(ds)), true); |
97 | 0 | CF_CHECK_TRUE(priv.ToBin(priv_bytes, sizeof(priv_bytes))); |
98 | 0 | priv_bytes[0] &= 248; |
99 | 0 | priv_bytes[31] &= 127; |
100 | 0 | priv_bytes[31] |= 64; |
101 | 0 | } |
102 | | |
103 | | /* Convert to public key */ |
104 | 0 | { |
105 | 0 | WC_CHECK_EQ(wc_curve25519_make_pub(sizeof(pub_bytes), pub_bytes, sizeof(priv_bytes), priv_bytes), MP_OKAY); |
106 | 0 | } |
107 | | |
108 | | /* Convert public key */ |
109 | 0 | { |
110 | 0 | std::optional<std::string> pub_x_str; |
111 | 0 | CF_CHECK_EQ(mp_read_unsigned_bin(pub.GetPtr(), pub_bytes, sizeof(pub_bytes)), MP_OKAY); |
112 | 0 | CF_CHECK_NE(pub_x_str = pub.ToDecString(), std::nullopt); |
113 | 0 | ret = { *pub_x_str, "0" }; |
114 | 0 | } |
115 | | |
116 | 0 | end: |
117 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
118 | 0 | return ret; |
119 | 0 | } |
120 | | |
121 | 0 | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Ed25519(operation::ECC_PrivateToPublic& op) { |
122 | 0 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
123 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
124 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
125 | |
|
126 | 0 | wolfCrypt_bignum::Bignum priv(ds), pub(ds); |
127 | |
|
128 | 0 | ed25519_key key; |
129 | 0 | bool e25519_key_inited = false; |
130 | |
|
131 | 0 | WC_CHECK_EQ(wc_ed25519_init(&key), 0); |
132 | 0 | e25519_key_inited = true; |
133 | |
|
134 | 0 | CF_CHECK_EQ(ed25519LoadPrivateKey(key, op.priv, ds), true); |
135 | 0 | ret = ed25519GetPublicKey(key, ds); |
136 | |
|
137 | 0 | end: |
138 | 0 | if ( e25519_key_inited == true ) { |
139 | 0 | wc_ed25519_free(&key); |
140 | 0 | } |
141 | |
|
142 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
143 | 0 | return ret; |
144 | 0 | } |
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 | 0 | std::optional<component::ECDSA_Signature> OpECDSA_Sign_ed25519(operation::ECDSA_Sign& op) { |
198 | 0 | std::optional<component::ECDSA_Signature> ret = std::nullopt; |
199 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
200 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
201 | |
|
202 | 0 | ed25519_key key; |
203 | 0 | bool e25519_key_inited = false; |
204 | 0 | uint8_t sig[ED25519_SIG_SIZE]; |
205 | 0 | word32 sigSz = sizeof(sig); |
206 | |
|
207 | 0 | WC_CHECK_EQ(wc_ed25519_init(&key), 0); |
208 | 0 | e25519_key_inited = true; |
209 | |
|
210 | 0 | CF_CHECK_EQ(wolfCrypt_detail::ed25519LoadPrivateKey(key, op.priv, ds), true); |
211 | 0 | CF_CHECK_EQ(wolfCrypt_detail::ed25519DerivePublicKey(key), true); |
212 | | |
213 | | /* Sign message */ |
214 | 0 | WC_CHECK_EQ(wc_ed25519_sign_msg(op.cleartext.GetPtr(), op.cleartext.GetSize(), sig, &sigSz, &key), MP_OKAY); |
215 | 0 | CF_CHECK_EQ(sigSz, ED25519_SIG_SIZE); |
216 | 0 | static_assert(ED25519_SIG_SIZE % 2 == 0); |
217 | |
|
218 | 0 | { |
219 | 0 | std::optional<component::BignumPair> ret_sig; |
220 | 0 | std::optional<component::BignumPair> ret_pub; |
221 | |
|
222 | 0 | CF_CHECK_NE(ret_sig = wolfCrypt_bignum::Bignum::BinToBignumPair(ds, sig, ED25519_SIG_SIZE), std::nullopt); |
223 | 0 | CF_CHECK_NE(ret_pub = wolfCrypt_detail::ed25519GetPublicKey(key, ds), std::nullopt); |
224 | |
|
225 | 0 | ret = component::ECDSA_Signature(*ret_sig, *ret_pub); |
226 | 0 | } |
227 | | |
228 | 0 | end: |
229 | 0 | if ( e25519_key_inited == true ) { |
230 | 0 | wc_ed25519_free(&key); |
231 | 0 | } |
232 | |
|
233 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
234 | 0 | return ret; |
235 | 0 | } |
236 | | |
237 | 0 | std::optional<bool> OpECDSA_Verify_ed25519(operation::ECDSA_Verify& op) { |
238 | 0 | std::optional<bool> ret = std::nullopt; |
239 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
240 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
241 | |
|
242 | 0 | ed25519_key key; |
243 | 0 | bool e25519_key_inited = false; |
244 | 0 | uint8_t ed25519sig[ED25519_SIG_SIZE]; |
245 | 0 | int verify; |
246 | 0 | bool oneShot = true; |
247 | 0 | bool haveEmptyPart = false; |
248 | |
|
249 | 0 | haveAllocFailure = false; |
250 | 0 | ret = false; |
251 | |
|
252 | 0 | WC_CHECK_EQ(wc_ed25519_init(&key), 0); |
253 | 0 | e25519_key_inited = true; |
254 | |
|
255 | 0 | CF_CHECK_EQ(ed25519LoadPublicKey(key, op.signature.pub.first, ds, true), true); |
256 | 0 | CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, op.signature.signature, ed25519sig, sizeof(ed25519sig), true), true); |
257 | |
|
258 | 0 | #if defined(WOLFSSL_ED25519_STREAMING_VERIFY) |
259 | 0 | try { oneShot = ds.Get<bool>(); } catch ( ... ) { } |
260 | 0 | #endif |
261 | |
|
262 | 0 | if ( oneShot == true ) { |
263 | 0 | WC_CHECK_EQ(wc_ed25519_verify_msg(ed25519sig, sizeof(ed25519sig), op.cleartext.GetPtr(), op.cleartext.GetSize(), &verify, &key), 0); |
264 | 0 | } else { |
265 | | #if !defined(WOLFSSL_ED25519_STREAMING_VERIFY) |
266 | | CF_UNREACHABLE(); |
267 | | #else |
268 | 0 | const auto parts = util::ToParts(ds, op.cleartext); |
269 | |
|
270 | 0 | WC_CHECK_EQ(wc_ed25519_verify_msg_init(ed25519sig, sizeof(ed25519sig), &key, (byte)Ed25519, nullptr, 0), 0); |
271 | |
|
272 | 0 | for (const auto& part : parts) { |
273 | 0 | if ( part.second == 0 ) { |
274 | 0 | haveEmptyPart = true; |
275 | 0 | } |
276 | 0 | WC_CHECK_EQ(wc_ed25519_verify_msg_update(part.first, part.second, &key), 0); |
277 | 0 | } |
278 | | |
279 | 0 | WC_CHECK_EQ(wc_ed25519_verify_msg_final(ed25519sig, sizeof(ed25519sig), &verify, &key), 0); |
280 | 0 | #endif |
281 | 0 | } |
282 | | |
283 | 0 | ret = verify ? true : false; |
284 | |
|
285 | 0 | end: |
286 | 0 | if ( e25519_key_inited == true ) { |
287 | 0 | wc_ed25519_free(&key); |
288 | 0 | } |
289 | |
|
290 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
291 | |
|
292 | 0 | if ( ret && *ret == false ) { |
293 | 0 | if ( haveAllocFailure ) { |
294 | 0 | ret = std::nullopt; |
295 | 0 | } else if ( haveEmptyPart ) { |
296 | 0 | ret = std::nullopt; |
297 | 0 | } else if ( op.cleartext.IsZero() ) { |
298 | 0 | ret = std::nullopt; |
299 | 0 | } |
300 | |
|
301 | 0 | } |
302 | 0 | return ret; |
303 | 0 | } |
304 | | |
305 | | } /* namespace wolfCrypt_detail */ |
306 | | } /* namespace module */ |
307 | | } /* namespace cryptofuzz */ |