Coverage Report

Created: 2026-02-14 07:18

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