/src/cryptofuzz/modules/bearssl/module.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "module.h" |
2 | | #include <cryptofuzz/util.h> |
3 | | #include <boost/multiprecision/cpp_int.hpp> |
4 | | #include <cryptofuzz/repository.h> |
5 | | #include <sstream> |
6 | | #include <algorithm> |
7 | | |
8 | | extern "C" { |
9 | | #include <bearssl.h> |
10 | | } |
11 | | |
12 | | namespace cryptofuzz { |
13 | | namespace module { |
14 | | |
15 | | namespace BearSSL_detail { |
16 | | static br_hmac_drbg_context rng; |
17 | | |
18 | | template <class Context, size_t Size> |
19 | | std::optional<component::Digest> digest( |
20 | | void(*init)(Context*), |
21 | | void(*update)(Context*, const void*, size_t), |
22 | | void(*finish)(const Context*, void*), |
23 | | const component::Cleartext& in, |
24 | | Datasource& ds |
25 | | ) |
26 | 817 | { |
27 | 817 | std::optional<component::Digest> ret = std::nullopt; |
28 | | |
29 | 817 | Context ctx; |
30 | 817 | uint8_t* out = util::malloc(Size); |
31 | | |
32 | 817 | init(&ctx); |
33 | | |
34 | 817 | const auto parts = util::ToParts(ds, in); |
35 | 101k | for (const auto& part : parts) { |
36 | 101k | update(&ctx, part.first, part.second); |
37 | 101k | } |
38 | | |
39 | 817 | finish(&ctx, out); |
40 | | |
41 | 817 | ret = component::Digest(out, Size); |
42 | | |
43 | 817 | util::free(out); |
44 | | |
45 | 817 | return ret; |
46 | 817 | } std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_md5_context, 16ul>(void (*)(br_md5_context*), void (*)(br_md5_context*, void const*, unsigned long), void (*)(br_md5_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 179 | { | 27 | 179 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 179 | Context ctx; | 30 | 179 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 179 | init(&ctx); | 33 | | | 34 | 179 | const auto parts = util::ToParts(ds, in); | 35 | 18.7k | for (const auto& part : parts) { | 36 | 18.7k | update(&ctx, part.first, part.second); | 37 | 18.7k | } | 38 | | | 39 | 179 | finish(&ctx, out); | 40 | | | 41 | 179 | ret = component::Digest(out, Size); | 42 | | | 43 | 179 | util::free(out); | 44 | | | 45 | 179 | return ret; | 46 | 179 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_md5sha1_context, 36ul>(void (*)(br_md5sha1_context*), void (*)(br_md5sha1_context*, void const*, unsigned long), void (*)(br_md5sha1_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 82 | { | 27 | 82 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 82 | Context ctx; | 30 | 82 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 82 | init(&ctx); | 33 | | | 34 | 82 | const auto parts = util::ToParts(ds, in); | 35 | 1.80k | for (const auto& part : parts) { | 36 | 1.80k | update(&ctx, part.first, part.second); | 37 | 1.80k | } | 38 | | | 39 | 82 | finish(&ctx, out); | 40 | | | 41 | 82 | ret = component::Digest(out, Size); | 42 | | | 43 | 82 | util::free(out); | 44 | | | 45 | 82 | return ret; | 46 | 82 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha1_context, 20ul>(void (*)(br_sha1_context*), void (*)(br_sha1_context*, void const*, unsigned long), void (*)(br_sha1_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 142 | { | 27 | 142 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 142 | Context ctx; | 30 | 142 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 142 | init(&ctx); | 33 | | | 34 | 142 | const auto parts = util::ToParts(ds, in); | 35 | 10.0k | for (const auto& part : parts) { | 36 | 10.0k | update(&ctx, part.first, part.second); | 37 | 10.0k | } | 38 | | | 39 | 142 | finish(&ctx, out); | 40 | | | 41 | 142 | ret = component::Digest(out, Size); | 42 | | | 43 | 142 | util::free(out); | 44 | | | 45 | 142 | return ret; | 46 | 142 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha224_context, 28ul>(void (*)(br_sha224_context*), void (*)(br_sha224_context*, void const*, unsigned long), void (*)(br_sha224_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 107 | { | 27 | 107 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 107 | Context ctx; | 30 | 107 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 107 | init(&ctx); | 33 | | | 34 | 107 | const auto parts = util::ToParts(ds, in); | 35 | 17.0k | for (const auto& part : parts) { | 36 | 17.0k | update(&ctx, part.first, part.second); | 37 | 17.0k | } | 38 | | | 39 | 107 | finish(&ctx, out); | 40 | | | 41 | 107 | ret = component::Digest(out, Size); | 42 | | | 43 | 107 | util::free(out); | 44 | | | 45 | 107 | return ret; | 46 | 107 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha224_context, 32ul>(void (*)(br_sha224_context*), void (*)(br_sha224_context*, void const*, unsigned long), void (*)(br_sha224_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 116 | { | 27 | 116 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 116 | Context ctx; | 30 | 116 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 116 | init(&ctx); | 33 | | | 34 | 116 | const auto parts = util::ToParts(ds, in); | 35 | 14.2k | for (const auto& part : parts) { | 36 | 14.2k | update(&ctx, part.first, part.second); | 37 | 14.2k | } | 38 | | | 39 | 116 | finish(&ctx, out); | 40 | | | 41 | 116 | ret = component::Digest(out, Size); | 42 | | | 43 | 116 | util::free(out); | 44 | | | 45 | 116 | return ret; | 46 | 116 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha384_context, 48ul>(void (*)(br_sha384_context*), void (*)(br_sha384_context*, void const*, unsigned long), void (*)(br_sha384_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 93 | { | 27 | 93 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 93 | Context ctx; | 30 | 93 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 93 | init(&ctx); | 33 | | | 34 | 93 | const auto parts = util::ToParts(ds, in); | 35 | 9.45k | for (const auto& part : parts) { | 36 | 9.45k | update(&ctx, part.first, part.second); | 37 | 9.45k | } | 38 | | | 39 | 93 | finish(&ctx, out); | 40 | | | 41 | 93 | ret = component::Digest(out, Size); | 42 | | | 43 | 93 | util::free(out); | 44 | | | 45 | 93 | return ret; | 46 | 93 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::BearSSL_detail::digest<br_sha384_context, 64ul>(void (*)(br_sha384_context*), void (*)(br_sha384_context*, void const*, unsigned long), void (*)(br_sha384_context const*, void*), cryptofuzz::Buffer const&, fuzzing::datasource::Datasource&) Line | Count | Source | 26 | 98 | { | 27 | 98 | std::optional<component::Digest> ret = std::nullopt; | 28 | | | 29 | 98 | Context ctx; | 30 | 98 | uint8_t* out = util::malloc(Size); | 31 | | | 32 | 98 | init(&ctx); | 33 | | | 34 | 98 | const auto parts = util::ToParts(ds, in); | 35 | 30.3k | for (const auto& part : parts) { | 36 | 30.3k | update(&ctx, part.first, part.second); | 37 | 30.3k | } | 38 | | | 39 | 98 | finish(&ctx, out); | 40 | | | 41 | 98 | ret = component::Digest(out, Size); | 42 | | | 43 | 98 | util::free(out); | 44 | | | 45 | 98 | return ret; | 46 | 98 | } |
|
47 | | |
48 | 3.11k | const br_hash_class* To_br_hash_class(const component::DigestType& digestType) { |
49 | 3.11k | switch ( digestType.Get() ) { |
50 | 514 | case CF_DIGEST("MD5"): |
51 | 514 | return &br_md5_vtable; |
52 | 569 | case CF_DIGEST("SHA1"): |
53 | 569 | return &br_sha1_vtable; |
54 | 239 | case CF_DIGEST("MD5_SHA1"): |
55 | 239 | return &br_md5sha1_vtable; |
56 | 327 | case CF_DIGEST("SHA224"): |
57 | 327 | return &br_sha224_vtable; |
58 | 708 | case CF_DIGEST("SHA256"): |
59 | 708 | return &br_sha256_vtable; |
60 | 293 | case CF_DIGEST("SHA384"): |
61 | 293 | return &br_sha384_vtable; |
62 | 372 | case CF_DIGEST("SHA512"): |
63 | 372 | return &br_sha512_vtable; |
64 | 94 | default: |
65 | 94 | return nullptr; |
66 | 3.11k | } |
67 | 3.11k | } |
68 | | |
69 | 5.98k | static bool EncodeBignum(const std::string s, uint8_t* out, const size_t maxSize, const bool reverse = false) { |
70 | 5.98k | std::vector<uint8_t> v; |
71 | 5.98k | boost::multiprecision::cpp_int c(s); |
72 | 5.98k | boost::multiprecision::export_bits(c, std::back_inserter(v), 8); |
73 | 5.98k | if ( v.size() > maxSize ) { |
74 | 103 | return false; |
75 | 103 | } |
76 | 5.87k | const auto diff = maxSize - v.size(); |
77 | | |
78 | 5.87k | memset(out, 0, maxSize); |
79 | 5.87k | memcpy(out + diff, v.data(), v.size()); |
80 | | |
81 | 5.87k | if ( reverse == true ) { |
82 | 371 | std::reverse(out, out + maxSize); |
83 | 371 | } |
84 | | |
85 | 5.87k | return true; |
86 | 5.98k | } |
87 | | |
88 | 4.22k | static std::string toString(const uint8_t* data, const size_t size) { |
89 | 4.22k | boost::multiprecision::cpp_int i; |
90 | 4.22k | boost::multiprecision::import_bits(i, data, data + size); |
91 | | |
92 | 4.22k | std::stringstream ss; |
93 | 4.22k | ss << i; |
94 | | |
95 | 4.22k | if ( ss.str().empty() ) { |
96 | 0 | return "0"; |
97 | 4.22k | } else { |
98 | 4.22k | return ss.str(); |
99 | 4.22k | } |
100 | 4.22k | } |
101 | | |
102 | 6.50k | int toCurveID(const component::CurveType& curveType) { |
103 | 6.50k | static const std::map<uint64_t, int> LUT = { |
104 | 6.50k | { CF_ECC_CURVE("brainpool256r1"), BR_EC_brainpoolP256r1}, |
105 | 6.50k | { CF_ECC_CURVE("brainpool384r1"), BR_EC_brainpoolP384r1}, |
106 | 6.50k | { CF_ECC_CURVE("brainpool512r1"), BR_EC_brainpoolP512r1}, |
107 | 6.50k | { CF_ECC_CURVE("x25519"), BR_EC_curve25519}, |
108 | | #if 0 |
109 | | { CF_ECC_CURVE("x448"), BR_EC_curve448}, |
110 | | #endif |
111 | 6.50k | { CF_ECC_CURVE("secp160k1"), BR_EC_secp160k1}, |
112 | 6.50k | { CF_ECC_CURVE("secp160r1"), BR_EC_secp160r1}, |
113 | 6.50k | { CF_ECC_CURVE("secp160r2"), BR_EC_secp160r2}, |
114 | 6.50k | { CF_ECC_CURVE("secp192k1"), BR_EC_secp192k1}, |
115 | 6.50k | { CF_ECC_CURVE("secp192r1"), BR_EC_secp192r1}, |
116 | 6.50k | { CF_ECC_CURVE("secp224k1"), BR_EC_secp224k1}, |
117 | 6.50k | { CF_ECC_CURVE("secp224r1"), BR_EC_secp224r1}, |
118 | 6.50k | { CF_ECC_CURVE("secp256k1"), BR_EC_secp256k1}, |
119 | 6.50k | { CF_ECC_CURVE("secp256r1"), BR_EC_secp256r1}, |
120 | 6.50k | { CF_ECC_CURVE("secp384r1"), BR_EC_secp384r1}, |
121 | 6.50k | { CF_ECC_CURVE("secp521r1"), BR_EC_secp521r1}, |
122 | 6.50k | { CF_ECC_CURVE("sect163k1"), BR_EC_sect163k1}, |
123 | 6.50k | { CF_ECC_CURVE("sect163r1"), BR_EC_sect163r1}, |
124 | 6.50k | { CF_ECC_CURVE("sect163r2"), BR_EC_sect163r2}, |
125 | 6.50k | { CF_ECC_CURVE("sect193r1"), BR_EC_sect193r1}, |
126 | 6.50k | { CF_ECC_CURVE("sect193r2"), BR_EC_sect193r2}, |
127 | 6.50k | { CF_ECC_CURVE("sect233k1"), BR_EC_sect233k1}, |
128 | 6.50k | { CF_ECC_CURVE("sect233r1"), BR_EC_sect233r1}, |
129 | 6.50k | { CF_ECC_CURVE("sect239k1"), BR_EC_sect239k1}, |
130 | 6.50k | { CF_ECC_CURVE("sect283k1"), BR_EC_sect283k1}, |
131 | 6.50k | { CF_ECC_CURVE("sect283r1"), BR_EC_sect283r1}, |
132 | 6.50k | { CF_ECC_CURVE("sect409k1"), BR_EC_sect409k1}, |
133 | 6.50k | { CF_ECC_CURVE("sect409r1"), BR_EC_sect409r1}, |
134 | 6.50k | { CF_ECC_CURVE("sect571k1"), BR_EC_sect571k1}, |
135 | 6.50k | { CF_ECC_CURVE("sect571r1"), BR_EC_sect571r1}, |
136 | 6.50k | }; |
137 | | |
138 | 6.50k | if ( LUT.find(curveType.Get()) == LUT.end() ) { |
139 | 2.76k | return -1; |
140 | 2.76k | } |
141 | | |
142 | 3.73k | return LUT.at(curveType.Get()); |
143 | 6.50k | } |
144 | | |
145 | 1.64k | component::BignumPair EncodePubkey(const component::CurveType& curveType, const uint8_t* data, const size_t size) { |
146 | 1.64k | switch ( curveType.Get() ) { |
147 | 533 | case CF_ECC_CURVE("x25519"): |
148 | 533 | { |
149 | 533 | CF_ASSERT(size == 32, "x25519 pubkey is not 32 bytes"); |
150 | 533 | return { |
151 | 533 | BearSSL_detail::toString(data, 32), |
152 | 533 | "0" }; |
153 | 533 | } |
154 | 0 | break; |
155 | 1.10k | default: |
156 | 1.10k | { |
157 | 1.10k | if ( (size % 2) != 1 || data[0] != 0x04 ) { |
158 | 0 | abort(); |
159 | 0 | } |
160 | 1.10k | size_t halfSize = (size - 1) / 2; |
161 | | |
162 | 1.10k | return { |
163 | 1.10k | BearSSL_detail::toString(data + 1, halfSize), |
164 | 1.10k | BearSSL_detail::toString(data + 1 + halfSize, halfSize) }; |
165 | 1.10k | } |
166 | 1.64k | } |
167 | 1.64k | } |
168 | | |
169 | 4.69k | const br_block_ctrcbc_class* Get_br_block_ctrcbc_class(Datasource& ds) { |
170 | 4.69k | try { |
171 | 4.69k | switch ( ds.Get<uint8_t>() ) { |
172 | 103 | case 0: |
173 | 103 | return &br_aes_big_ctrcbc_vtable; |
174 | 922 | case 1: |
175 | 922 | return &br_aes_small_ctrcbc_vtable; |
176 | 288 | case 2: |
177 | 288 | return &br_aes_ct_ctrcbc_vtable; |
178 | 623 | case 3: |
179 | 623 | return &br_aes_ct64_ctrcbc_vtable; |
180 | 516 | case 4: |
181 | 516 | { |
182 | 516 | const auto ret = br_aes_x86ni_ctrcbc_get_vtable(); |
183 | 516 | if ( ret == nullptr ) { |
184 | 0 | goto end; |
185 | 0 | } |
186 | 516 | return ret; |
187 | 516 | } |
188 | 0 | break; |
189 | 180 | default: |
190 | 180 | goto end; |
191 | 4.69k | } |
192 | 4.69k | } catch ( ... ) { } |
193 | | |
194 | 2.24k | end: |
195 | 2.24k | return &br_aes_big_ctrcbc_vtable; |
196 | 4.69k | } |
197 | | |
198 | 6.57k | const br_ec_impl* Get_br_ec_impl(Datasource& ds, const component::CurveType& curveType) { |
199 | 6.57k | try { |
200 | 6.57k | switch ( ds.Get<uint8_t>() ) { |
201 | 1.14k | case 0: |
202 | 1.14k | switch ( curveType.Get() ) { |
203 | 73 | case CF_ECC_CURVE("secp256r1"): |
204 | 208 | case CF_ECC_CURVE("secp384r1"): |
205 | 314 | case CF_ECC_CURVE("secp521r1"): |
206 | 314 | return &br_ec_prime_i15; |
207 | 833 | default: |
208 | 833 | goto end; |
209 | 1.14k | } |
210 | 943 | case 1: |
211 | 943 | switch ( curveType.Get() ) { |
212 | 117 | case CF_ECC_CURVE("secp256r1"): |
213 | 236 | case CF_ECC_CURVE("secp384r1"): |
214 | 386 | case CF_ECC_CURVE("secp521r1"): |
215 | 386 | return &br_ec_prime_i31; |
216 | 557 | default: |
217 | 557 | goto end; |
218 | 943 | } |
219 | 272 | case 2: |
220 | 272 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1")); |
221 | 143 | return &br_ec_p256_m15; |
222 | 359 | case 3: |
223 | 359 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1")); |
224 | 211 | return &br_ec_p256_m31; |
225 | 206 | case 4: |
226 | 206 | { |
227 | 206 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1")); |
228 | 71 | const auto ret = br_ec_p256_m62_get(); |
229 | 71 | CF_CHECK_NE(ret, nullptr); |
230 | 71 | return ret; |
231 | 71 | } |
232 | 0 | break; |
233 | 128 | case 5: |
234 | 128 | { |
235 | 128 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("secp256r1")); |
236 | 16 | const auto ret = br_ec_p256_m64_get(); |
237 | 16 | CF_CHECK_NE(ret, nullptr); |
238 | 16 | return ret; |
239 | 16 | } |
240 | 0 | break; |
241 | 126 | case 6: |
242 | 126 | { |
243 | 126 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519")); |
244 | 18 | const auto ret = br_ec_c25519_m62_get(); |
245 | 18 | CF_CHECK_NE(ret, nullptr); |
246 | 18 | return ret; |
247 | 18 | } |
248 | 0 | break; |
249 | 111 | case 7: |
250 | 111 | { |
251 | 111 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519")); |
252 | 11 | const auto ret = br_ec_c25519_m64_get(); |
253 | 11 | CF_CHECK_NE(ret, nullptr); |
254 | 11 | return ret; |
255 | 11 | } |
256 | 0 | break; |
257 | 127 | case 8: |
258 | 127 | { |
259 | 127 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519")); |
260 | 21 | return &br_ec_c25519_i15; |
261 | 127 | } |
262 | 0 | break; |
263 | 131 | case 9: |
264 | 131 | { |
265 | 131 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519")); |
266 | 15 | return &br_ec_c25519_i31; |
267 | 131 | } |
268 | 0 | break; |
269 | 143 | case 10: |
270 | 143 | { |
271 | 143 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519")); |
272 | 16 | return &br_ec_c25519_m15; |
273 | 143 | } |
274 | 0 | break; |
275 | 143 | case 11: |
276 | 143 | { |
277 | 143 | CF_CHECK_EQ(curveType.Get(), CF_ECC_CURVE("x25519")); |
278 | 16 | return &br_ec_c25519_m31; |
279 | 143 | } |
280 | 0 | break; |
281 | 1.48k | default: |
282 | 1.48k | goto end; |
283 | 6.57k | } |
284 | 6.57k | } catch ( ... ) { } |
285 | | |
286 | 5.33k | end: |
287 | 5.33k | return br_ec_get_default(); |
288 | 6.57k | } |
289 | | |
290 | 1.32k | br_chacha20_run Get_br_chacha20_run(Datasource& ds) { |
291 | 1.32k | try { |
292 | 1.32k | switch ( ds.Get<uint8_t>() ) { |
293 | 109 | case 0: |
294 | 109 | return &br_chacha20_ct_run; |
295 | 467 | case 1: |
296 | 467 | { |
297 | 467 | const auto ret = br_chacha20_sse2_get(); |
298 | 467 | if ( ret == nullptr ) { |
299 | 0 | goto end; |
300 | 0 | } |
301 | 467 | return ret; |
302 | 467 | } |
303 | 0 | break; |
304 | 126 | default: |
305 | 126 | goto end; |
306 | 1.32k | } |
307 | 1.32k | } catch ( ... ) { } |
308 | | |
309 | 749 | end: |
310 | 749 | return &br_chacha20_ct_run; |
311 | 1.32k | } |
312 | | |
313 | 629 | br_ecdsa_sign Get_br_ecdsa_sign(Datasource& ds) { |
314 | 629 | try { |
315 | 629 | switch ( ds.Get<uint8_t>() ) { |
316 | 17 | case 0: |
317 | 17 | return &br_ecdsa_i31_sign_raw; |
318 | 189 | case 1: |
319 | 189 | return &br_ecdsa_i15_sign_raw; |
320 | 187 | default: |
321 | 187 | goto end; |
322 | 629 | } |
323 | 629 | } catch ( ... ) { } |
324 | | |
325 | 423 | end: |
326 | 423 | return &br_ecdsa_i31_sign_raw; |
327 | 629 | } |
328 | | |
329 | 1.20k | br_ecdsa_vrfy Get_br_ecdsa_vrfy(Datasource& ds) { |
330 | 1.20k | try { |
331 | 1.20k | switch ( ds.Get<uint8_t>() ) { |
332 | 20 | case 0: |
333 | 20 | return &br_ecdsa_i31_vrfy_raw; |
334 | 244 | case 1: |
335 | 244 | return &br_ecdsa_i15_vrfy_raw; |
336 | 235 | default: |
337 | 235 | goto end; |
338 | 1.20k | } |
339 | 1.20k | } catch ( ... ) { } |
340 | | |
341 | 936 | end: |
342 | 936 | return &br_ecdsa_i31_vrfy_raw; |
343 | 1.20k | } |
344 | | |
345 | 1.52k | bool IsValidPrivateKey(const component::Bignum& priv, const component::CurveType& curveType) { |
346 | 1.52k | if ( curveType.Is(CF_ECC_CURVE("x25519")) ) { |
347 | 418 | return true; |
348 | 418 | } |
349 | | |
350 | 1.10k | const auto s = priv.ToTrimmedString(); |
351 | 1.10k | if ( s == "0" ) { |
352 | 27 | return false; |
353 | 27 | } |
354 | | |
355 | 1.07k | const auto order = repository::ECC_CurveToOrder(curveType.Get()); |
356 | 1.07k | if ( order == std::nullopt ) { |
357 | 0 | return false; |
358 | 0 | } |
359 | | |
360 | 1.07k | boost::multiprecision::cpp_int priv_cpp_int(s); |
361 | 1.07k | boost::multiprecision::cpp_int order_cpp_int(*order); |
362 | | |
363 | 1.07k | return priv_cpp_int < order_cpp_int; |
364 | 1.07k | } |
365 | | } |
366 | | |
367 | | BearSSL::BearSSL(void) : |
368 | 2 | Module("BearSSL") { |
369 | 2 | /* noret */ br_hmac_drbg_init(&BearSSL_detail::rng, &br_sha256_vtable, NULL, 0); |
370 | 2 | br_prng_seeder seeder = br_prng_seeder_system(NULL); |
371 | 2 | if ( seeder == 0 ) { |
372 | 0 | printf("Cannot initialize PRNG seeder\n"); |
373 | 0 | abort(); |
374 | 0 | } |
375 | 2 | if ( seeder(&BearSSL_detail::rng.vtable) == 0 ) { |
376 | 0 | printf("Cannot seed PRNG\n"); |
377 | 0 | abort(); |
378 | 0 | } |
379 | 2 | } |
380 | | |
381 | | |
382 | 1.14k | std::optional<component::Digest> BearSSL::OpDigest(operation::Digest& op) { |
383 | 1.14k | std::optional<component::Digest> ret = std::nullopt; |
384 | 1.14k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
385 | | |
386 | 1.14k | switch ( op.digestType.Get() ) { |
387 | 179 | case CF_DIGEST("MD5"): |
388 | 179 | return BearSSL_detail::digest<br_md5_context, br_md5_SIZE>(br_md5_init, br_md5_update, br_md5_out, op.cleartext, ds); |
389 | 82 | case CF_DIGEST("MD5_SHA1"): |
390 | 82 | return BearSSL_detail::digest<br_md5sha1_context, br_md5sha1_SIZE>(br_md5sha1_init, br_md5sha1_update, br_md5sha1_out, op.cleartext, ds); |
391 | 142 | case CF_DIGEST("SHA1"): |
392 | 142 | return BearSSL_detail::digest<br_sha1_context, br_sha1_SIZE>(br_sha1_init, br_sha1_update, br_sha1_out, op.cleartext, ds); |
393 | 107 | case CF_DIGEST("SHA224"): |
394 | 107 | return BearSSL_detail::digest<br_sha224_context, br_sha224_SIZE>(br_sha224_init, br_sha224_update, br_sha224_out, op.cleartext, ds); |
395 | 116 | case CF_DIGEST("SHA256"): |
396 | 116 | return BearSSL_detail::digest<br_sha256_context, br_sha256_SIZE>(br_sha256_init, br_sha256_update, br_sha256_out, op.cleartext, ds); |
397 | 93 | case CF_DIGEST("SHA384"): |
398 | 93 | return BearSSL_detail::digest<br_sha384_context, br_sha384_SIZE>(br_sha384_init, br_sha384_update, br_sha384_out, op.cleartext, ds); |
399 | 98 | case CF_DIGEST("SHA512"): |
400 | 98 | return BearSSL_detail::digest<br_sha512_context, br_sha512_SIZE>(br_sha512_init, br_sha512_update, br_sha512_out, op.cleartext, ds); |
401 | 153 | case CF_DIGEST("SHAKE128"): |
402 | 153 | { |
403 | 153 | uint8_t out[16]; |
404 | 153 | br_shake_context ctx; |
405 | 153 | const auto parts = util::ToParts(ds, op.cleartext); |
406 | | |
407 | | /* noret */ br_shake_init(&ctx, 128); |
408 | 3.01k | for (const auto& part : parts) { |
409 | 3.01k | /* noret */ br_shake_inject(&ctx, part.first, part.second); |
410 | 3.01k | } |
411 | 153 | /* noret */ br_shake_flip(&ctx); |
412 | 153 | /* noret */ br_shake_produce(&ctx, out, 16); |
413 | | |
414 | 153 | ret = component::Digest(out, sizeof(out)); |
415 | 153 | } |
416 | 153 | break; |
417 | 173 | case CF_DIGEST("SHAKE256"): |
418 | 173 | { |
419 | 173 | uint8_t out[32]; |
420 | 173 | br_shake_context ctx; |
421 | 173 | const auto parts = util::ToParts(ds, op.cleartext); |
422 | | |
423 | | /* noret */ br_shake_init(&ctx, 256); |
424 | 7.50k | for (const auto& part : parts) { |
425 | 7.50k | /* noret */ br_shake_inject(&ctx, part.first, part.second); |
426 | 7.50k | } |
427 | 173 | /* noret */ br_shake_flip(&ctx); |
428 | 173 | /* noret */ br_shake_produce(&ctx, out, 32); |
429 | | |
430 | 173 | ret = component::Digest(out, sizeof(out)); |
431 | 173 | } |
432 | 173 | break; |
433 | 1.14k | } |
434 | | |
435 | 326 | return ret; |
436 | 1.14k | } |
437 | | |
438 | 560 | std::optional<component::MAC> BearSSL::OpHMAC(operation::HMAC& op) { |
439 | 560 | std::optional<component::MAC> ret = std::nullopt; |
440 | 560 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
441 | | |
442 | 560 | br_hmac_context ctx; |
443 | 560 | br_hmac_key_context kctx; |
444 | 560 | uint8_t out[64]; |
445 | 560 | const auto parts = util::ToParts(ds, op.cleartext); |
446 | 560 | const br_hash_class* hash_class; |
447 | | |
448 | | /* Initialize */ |
449 | 560 | { |
450 | 560 | CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr); |
451 | | |
452 | | /* noret */ br_hmac_key_init(&kctx, hash_class, op.cipher.key.GetPtr(), op.cipher.key.GetSize()); |
453 | 512 | /* noret */ br_hmac_init(&ctx, &kctx, 0); |
454 | 512 | } |
455 | | |
456 | | /* Process */ |
457 | 46.3k | for (const auto& part : parts) { |
458 | 46.3k | br_hmac_update(&ctx, part.first, part.second); |
459 | 46.3k | } |
460 | | |
461 | 512 | { |
462 | 512 | const auto size = br_hmac_out(&ctx, out); |
463 | | |
464 | 512 | ret = component::MAC(out, size); |
465 | 512 | } |
466 | | |
467 | 560 | end: |
468 | 560 | return ret; |
469 | 512 | } |
470 | | |
471 | 4.14k | std::optional<component::Ciphertext> BearSSL::OpSymmetricEncrypt(operation::SymmetricEncrypt& op) { |
472 | 4.14k | std::optional<component::Ciphertext> ret = std::nullopt; |
473 | 4.14k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
474 | 4.14k | uint8_t* tag = nullptr; |
475 | | |
476 | 4.14k | switch ( op.cipher.cipherType.Get() ) { |
477 | 767 | case CF_CIPHER("AES_128_GCM"): |
478 | 1.01k | case CF_CIPHER("AES_192_GCM"): |
479 | 1.28k | case CF_CIPHER("AES_256_GCM"): |
480 | 1.28k | { |
481 | 1.28k | br_aes_ct_ctr_keys bc; |
482 | 1.28k | br_gcm_context gc; |
483 | 1.28k | tag = util::malloc(16); |
484 | 1.28k | auto in = op.cleartext.Get(); |
485 | 1.28k | auto parts = util::ToParts(ds, in); |
486 | | |
487 | 1.28k | switch ( op.cipher.cipherType.Get() ) { |
488 | 767 | case CF_CIPHER("AES_128_GCM"): |
489 | 767 | CF_CHECK_EQ(op.cipher.key.GetSize(), 16); |
490 | 703 | break; |
491 | 245 | case CF_CIPHER("AES_192_GCM"): |
492 | 245 | CF_CHECK_EQ(op.cipher.key.GetSize(), 24); |
493 | 187 | break; |
494 | 268 | case CF_CIPHER("AES_256_GCM"): |
495 | 268 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
496 | 163 | break; |
497 | 1.28k | } |
498 | | |
499 | 1.05k | if ( op.tagSize != std::nullopt ) { |
500 | 356 | CF_CHECK_EQ(*op.tagSize, 16); |
501 | 220 | } |
502 | | |
503 | 917 | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); |
504 | | |
505 | | /* noret */ br_aes_ct_ctr_init(&bc, op.cipher.key.GetPtr(), op.cipher.key.GetSize()); |
506 | 850 | /* noret */ br_gcm_init(&gc, &bc.vtable, br_ghash_ctmul32); |
507 | | |
508 | | /* noret */ br_gcm_reset(&gc, op.cipher.iv.GetPtr(), op.cipher.iv.GetSize()); |
509 | 850 | if ( op.aad != std::nullopt ) { |
510 | 210 | const auto aadParts = util::ToParts(ds, *op.aad); |
511 | | /* "Additional data may be provided in several chunks of arbitrary length" */ |
512 | 969 | for (auto& part : aadParts) { |
513 | 969 | /* noret */ br_gcm_aad_inject(&gc, part.first, part.second); |
514 | 969 | } |
515 | 210 | } |
516 | 850 | /* noret */ br_gcm_flip(&gc); |
517 | | |
518 | 20.7k | for (auto& part : parts) { |
519 | | /* "Data may be provided in several chunks of arbitrary length" */ |
520 | 20.7k | /* noret */ br_gcm_run(&gc, 1, (void*)part.first, part.second); |
521 | 20.7k | } |
522 | | |
523 | 850 | if ( op.tagSize != std::nullopt ) { |
524 | 219 | /* noret */ br_gcm_get_tag(&gc, tag); |
525 | 219 | ret = component::Ciphertext(Buffer(in), Buffer(tag, 16)); |
526 | 631 | } else { |
527 | 631 | ret = component::Ciphertext(Buffer(in)); |
528 | 631 | } |
529 | 850 | } |
530 | 0 | break; |
531 | 957 | case CF_CIPHER("AES_128_CCM"): |
532 | 1.47k | case CF_CIPHER("AES_192_CCM"): |
533 | 1.84k | case CF_CIPHER("AES_256_CCM"): |
534 | 1.84k | { |
535 | 1.84k | br_aes_gen_ctrcbc_keys bc; |
536 | 1.84k | br_ccm_context ec; |
537 | 1.84k | auto in = op.cleartext.Get(); |
538 | 1.84k | auto parts = util::ToParts(ds, in); |
539 | 1.84k | const auto vt = BearSSL_detail::Get_br_block_ctrcbc_class(ds); |
540 | 1.84k | CF_CHECK_NE(vt, nullptr); |
541 | | |
542 | 1.84k | switch ( op.cipher.cipherType.Get() ) { |
543 | 957 | case CF_CIPHER("AES_128_CCM"): |
544 | 957 | CF_CHECK_EQ(op.cipher.key.GetSize(), 16); |
545 | 812 | break; |
546 | 516 | case CF_CIPHER("AES_192_CCM"): |
547 | 516 | CF_CHECK_EQ(op.cipher.key.GetSize(), 24); |
548 | 475 | break; |
549 | 376 | case CF_CIPHER("AES_256_CCM"): |
550 | 376 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
551 | 339 | break; |
552 | 1.84k | } |
553 | | |
554 | 1.62k | if ( op.tagSize != std::nullopt ) { |
555 | 1.35k | tag = util::malloc(*op.tagSize); |
556 | 1.35k | } |
557 | | |
558 | 1.62k | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); |
559 | | |
560 | | /* noret */ vt->init(&bc.vtable, op.cipher.key.GetPtr(), op.cipher.key.GetSize()); |
561 | 1.56k | /* noret */ br_ccm_init(&ec, &bc.vtable); |
562 | | |
563 | 1.56k | CF_CHECK_NE(br_ccm_reset(&ec, |
564 | 1.56k | op.cipher.iv.GetPtr(), op.cipher.iv.GetSize(), |
565 | 1.56k | op.aad == std::nullopt ? 0 : op.aad->GetSize(), |
566 | 1.56k | op.cleartext.GetSize(), |
567 | 1.56k | op.tagSize == std::nullopt ? 0 : *op.tagSize), 0); |
568 | | |
569 | 1.22k | if ( op.aad != std::nullopt ) { |
570 | 773 | const auto aadParts = util::ToParts(ds, *op.aad); |
571 | | /* "Additional data may be provided in several chunks of arbitrary length" */ |
572 | 3.87k | for (auto& part : aadParts) { |
573 | 3.87k | /* noret */ br_ccm_aad_inject(&ec, part.first, part.second); |
574 | 3.87k | } |
575 | 773 | } |
576 | 1.22k | /* noret */ br_ccm_flip(&ec); |
577 | | |
578 | 22.3k | for (auto& part : parts) { |
579 | | /* "Data may be provided in several chunks of arbitrary length" */ |
580 | 22.3k | /* noret */ br_ccm_run(&ec, 1, (void*)part.first, part.second); |
581 | 22.3k | } |
582 | | |
583 | 1.22k | if ( op.tagSize != std::nullopt ) { |
584 | 1.22k | /* noret */ br_ccm_get_tag(&ec, tag); |
585 | 1.22k | ret = component::Ciphertext(Buffer(in), Buffer(tag, *op.tagSize)); |
586 | 1.22k | } else { |
587 | 0 | ret = component::Ciphertext(Buffer(in)); |
588 | 0 | } |
589 | 1.22k | } |
590 | 0 | break; |
591 | 428 | case CF_CIPHER("CHACHA20"): |
592 | 428 | { |
593 | 428 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
594 | 329 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 12); |
595 | | |
596 | 266 | auto in = op.cleartext.Get(); |
597 | | |
598 | 266 | auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds); |
599 | 266 | cc20(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), 0, in.data(), in.size()); |
600 | 266 | ret = component::Ciphertext(Buffer(in)); |
601 | 266 | } |
602 | 0 | break; |
603 | 590 | case CF_CIPHER("CHACHA20_POLY1305"): |
604 | 590 | { |
605 | 590 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
606 | 483 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 12); |
607 | | |
608 | 448 | if ( op.tagSize != std::nullopt ) { |
609 | 89 | CF_CHECK_EQ(*op.tagSize, 16); |
610 | 35 | } |
611 | | |
612 | 394 | uint8_t tag[16]; |
613 | 394 | auto in = op.cleartext.Get(); |
614 | 394 | auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds); |
615 | | |
616 | 394 | br_poly1305_ctmul_run( |
617 | 394 | op.cipher.key.GetPtr(), |
618 | 394 | op.cipher.iv.GetPtr(), |
619 | 394 | in.data(), |
620 | 394 | in.size(), |
621 | 394 | op.aad == std::nullopt ? nullptr : op.aad->GetPtr(), |
622 | 394 | op.aad == std::nullopt ? 0 : op.aad->GetSize(), |
623 | 394 | tag, |
624 | 394 | cc20, |
625 | 394 | 1); |
626 | | |
627 | 394 | if ( op.tagSize != std::nullopt ) { |
628 | 35 | ret = component::Ciphertext(Buffer(in), Buffer(tag, 16)); |
629 | 359 | } else { |
630 | 359 | ret = component::Ciphertext(Buffer(in)); |
631 | 359 | } |
632 | 394 | } |
633 | 0 | break; |
634 | 4.14k | } |
635 | | |
636 | 4.14k | end: |
637 | 4.14k | util::free(tag); |
638 | | |
639 | 4.14k | return ret; |
640 | 4.14k | } |
641 | | |
642 | 4.96k | std::optional<component::Cleartext> BearSSL::OpSymmetricDecrypt(operation::SymmetricDecrypt& op) { |
643 | 4.96k | std::optional<component::Cleartext> ret = std::nullopt; |
644 | 4.96k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
645 | | |
646 | 4.96k | switch ( op.cipher.cipherType.Get() ) { |
647 | 689 | case CF_CIPHER("AES_128_GCM"): |
648 | 931 | case CF_CIPHER("AES_192_GCM"): |
649 | 1.12k | case CF_CIPHER("AES_256_GCM"): |
650 | 1.12k | { |
651 | 1.12k | br_aes_ct_ctr_keys bc; |
652 | 1.12k | br_gcm_context gc; |
653 | 1.12k | auto in = op.ciphertext.Get(); |
654 | 1.12k | auto parts = util::ToParts(ds, in); |
655 | | |
656 | 1.12k | switch ( op.cipher.cipherType.Get() ) { |
657 | 689 | case CF_CIPHER("AES_128_GCM"): |
658 | 689 | CF_CHECK_EQ(op.cipher.key.GetSize(), 16); |
659 | 634 | break; |
660 | 242 | case CF_CIPHER("AES_192_GCM"): |
661 | 242 | CF_CHECK_EQ(op.cipher.key.GetSize(), 24); |
662 | 183 | break; |
663 | 196 | case CF_CIPHER("AES_256_GCM"): |
664 | 196 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
665 | 166 | break; |
666 | 1.12k | } |
667 | | |
668 | 983 | if ( op.tag != std::nullopt ) { |
669 | 261 | CF_CHECK_EQ(op.tag->GetSize(), 16); |
670 | 199 | } |
671 | | |
672 | 921 | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); |
673 | | |
674 | | /* noret */ br_aes_ct_ctr_init(&bc, op.cipher.key.GetPtr(), op.cipher.key.GetSize()); |
675 | 887 | /* noret */ br_gcm_init(&gc, &bc.vtable, br_ghash_ctmul32); |
676 | | |
677 | | /* noret */ br_gcm_reset(&gc, op.cipher.iv.GetPtr(), op.cipher.iv.GetSize()); |
678 | 887 | if ( op.aad != std::nullopt ) { |
679 | 221 | const auto aadParts = util::ToParts(ds, *op.aad); |
680 | | /* "Additional data may be provided in several chunks of arbitrary length" */ |
681 | 873 | for (auto& part : aadParts) { |
682 | 873 | /* noret */ br_gcm_aad_inject(&gc, part.first, part.second); |
683 | 873 | } |
684 | 221 | } |
685 | 887 | /* noret */ br_gcm_flip(&gc); |
686 | | |
687 | 9.91k | for (auto& part : parts) { |
688 | | /* "Data may be provided in several chunks of arbitrary length" */ |
689 | 9.91k | /* noret */ br_gcm_run(&gc, 0, (void*)part.first, part.second); |
690 | 9.91k | } |
691 | | |
692 | 887 | if ( op.tag != std::nullopt ) { |
693 | 199 | CF_CHECK_EQ(br_gcm_check_tag(&gc, op.tag->GetPtr()), 1); |
694 | 150 | } |
695 | | |
696 | 838 | ret = component::Cleartext(Buffer(in)); |
697 | 838 | } |
698 | 0 | break; |
699 | 1.39k | case CF_CIPHER("AES_128_CCM"): |
700 | 2.33k | case CF_CIPHER("AES_192_CCM"): |
701 | 2.84k | case CF_CIPHER("AES_256_CCM"): |
702 | 2.84k | { |
703 | 2.84k | br_aes_gen_ctrcbc_keys bc; |
704 | 2.84k | br_ccm_context ec; |
705 | 2.84k | auto in = op.ciphertext.Get(); |
706 | 2.84k | auto parts = util::ToParts(ds, in); |
707 | 2.84k | const auto vt = BearSSL_detail::Get_br_block_ctrcbc_class(ds); |
708 | 2.84k | CF_CHECK_NE(vt, nullptr); |
709 | | |
710 | 2.84k | switch ( op.cipher.cipherType.Get() ) { |
711 | 1.39k | case CF_CIPHER("AES_128_CCM"): |
712 | 1.39k | CF_CHECK_EQ(op.cipher.key.GetSize(), 16); |
713 | 1.19k | break; |
714 | 946 | case CF_CIPHER("AES_192_CCM"): |
715 | 946 | CF_CHECK_EQ(op.cipher.key.GetSize(), 24); |
716 | 901 | break; |
717 | 511 | case CF_CIPHER("AES_256_CCM"): |
718 | 511 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
719 | 470 | break; |
720 | 2.84k | } |
721 | | |
722 | 2.56k | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); |
723 | | |
724 | | /* noret */ vt->init(&bc.vtable, op.cipher.key.GetPtr(), op.cipher.key.GetSize()); |
725 | 2.50k | /* noret */ br_ccm_init(&ec, &bc.vtable); |
726 | | |
727 | 2.50k | CF_CHECK_NE(br_ccm_reset(&ec, |
728 | 2.50k | op.cipher.iv.GetPtr(), op.cipher.iv.GetSize(), |
729 | 2.50k | op.aad == std::nullopt ? 0 : op.aad->GetSize(), |
730 | 2.50k | op.ciphertext.GetSize(), |
731 | 2.50k | op.tag == std::nullopt ? 0 : op.tag->GetSize()), 0); |
732 | | |
733 | 2.39k | if ( op.aad != std::nullopt ) { |
734 | 1.07k | const auto aadParts = util::ToParts(ds, *op.aad); |
735 | | /* "Additional data may be provided in several chunks of arbitrary length" */ |
736 | 5.68k | for (auto& part : aadParts) { |
737 | 5.68k | /* noret */ br_ccm_aad_inject(&ec, part.first, part.second); |
738 | 5.68k | } |
739 | 1.07k | } |
740 | 2.39k | /* noret */ br_ccm_flip(&ec); |
741 | | |
742 | 9.56k | for (auto& part : parts) { |
743 | | /* "Data may be provided in several chunks of arbitrary length" */ |
744 | 9.56k | /* noret */ br_ccm_run(&ec, 0, (void*)part.first, part.second); |
745 | 9.56k | } |
746 | | |
747 | 2.39k | if ( op.tag != std::nullopt ) { |
748 | 2.39k | CF_CHECK_EQ(br_ccm_check_tag(&ec, op.tag->GetPtr()), 1); |
749 | 1.06k | } |
750 | | |
751 | 1.06k | ret = component::Cleartext(Buffer(in)); |
752 | 1.06k | } |
753 | 0 | break; |
754 | 361 | case CF_CIPHER("CHACHA20"): |
755 | 361 | { |
756 | 361 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
757 | 278 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 12); |
758 | | |
759 | 227 | auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds); |
760 | 227 | auto in = op.ciphertext.Get(); |
761 | | |
762 | 227 | cc20(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), 0, in.data(), in.size()); |
763 | 227 | ret = component::Cleartext(Buffer(in)); |
764 | 227 | } |
765 | 0 | break; |
766 | 625 | case CF_CIPHER("CHACHA20_POLY1305"): |
767 | 625 | { |
768 | 625 | CF_CHECK_EQ(op.cipher.key.GetSize(), 32); |
769 | 508 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 12); |
770 | | |
771 | 484 | if ( op.tag != std::nullopt ) { |
772 | 123 | CF_CHECK_EQ(op.tag->GetSize(), 16); |
773 | 77 | } |
774 | | |
775 | 438 | uint8_t tag[16]; |
776 | 438 | auto in = op.ciphertext.Get(); |
777 | 438 | auto cc20 = BearSSL_detail::Get_br_chacha20_run(ds); |
778 | | |
779 | 438 | br_poly1305_ctmul_run( |
780 | 438 | op.cipher.key.GetPtr(), |
781 | 438 | op.cipher.iv.GetPtr(), |
782 | 438 | in.data(), |
783 | 438 | in.size(), |
784 | 438 | op.aad == std::nullopt ? nullptr : op.aad->GetPtr(), |
785 | 438 | op.aad == std::nullopt ? 0 : op.aad->GetSize(), |
786 | 438 | tag, |
787 | 438 | cc20, |
788 | 438 | 0); |
789 | | |
790 | 438 | if ( op.tag != std::nullopt ) { |
791 | 77 | CF_CHECK_EQ(memcmp(op.tag->GetPtr(), tag, 16), 0); |
792 | 21 | } |
793 | | |
794 | 382 | ret = component::Cleartext(Buffer(in)); |
795 | 382 | } |
796 | 0 | break; |
797 | 4.96k | } |
798 | | |
799 | 4.96k | end: |
800 | 4.96k | return ret; |
801 | 4.96k | } |
802 | | |
803 | 968 | std::optional<component::Key> BearSSL::OpKDF_HKDF(operation::KDF_HKDF& op) { |
804 | 968 | std::optional<component::Key> ret = std::nullopt; |
805 | 968 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
806 | | |
807 | 968 | br_hkdf_context ctx; |
808 | 968 | const br_hash_class* hash_class; |
809 | 968 | uint8_t* out = util::malloc(op.keySize); |
810 | | |
811 | | /* Initialize */ |
812 | 968 | { |
813 | 968 | const auto digestSize = repository::DigestSize(op.digestType.Get()); |
814 | 968 | CF_CHECK_NE(digestSize, std::nullopt); |
815 | 880 | CF_CHECK_LTE(op.keySize, 255 * *digestSize); |
816 | | |
817 | 756 | CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr); |
818 | 756 | /* noret */ br_hkdf_init(&ctx, hash_class, op.salt.GetPtr(), op.salt.GetSize()); |
819 | 756 | } |
820 | | |
821 | | /* Process */ |
822 | 0 | { |
823 | 756 | const auto parts = util::ToParts(ds, op.password); |
824 | | |
825 | | /* "This function may be called several times" https://bearssl.org/apidoc/bearssl__kdf_8h.html */ |
826 | 82.7k | for (const auto& part : parts) { |
827 | 82.7k | /* noret */ br_hkdf_inject(&ctx, part.first, part.second); |
828 | 82.7k | } |
829 | 756 | } |
830 | | |
831 | | /* noret */ br_hkdf_flip(&ctx); |
832 | | |
833 | | /* Finalize */ |
834 | 756 | { |
835 | 756 | br_hkdf_produce(&ctx, op.info.GetPtr(), op.info.GetSize(), out, op.keySize); |
836 | | |
837 | 756 | ret = component::Key(out, op.keySize); |
838 | 756 | } |
839 | | |
840 | 968 | end: |
841 | 968 | util::free(out); |
842 | | |
843 | 968 | return ret; |
844 | 756 | } |
845 | | |
846 | 310 | std::optional<component::Key> BearSSL::OpKDF_TLS1_PRF(operation::KDF_TLS1_PRF& op) { |
847 | 310 | std::optional<component::Key> ret = std::nullopt; |
848 | 310 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
849 | | |
850 | 310 | const auto parts = util::ToParts(ds, op.seed); |
851 | 310 | br_tls_prf_seed_chunk* seed_chunks = (br_tls_prf_seed_chunk*)util::malloc(parts.size() * sizeof(br_tls_prf_seed_chunk)); |
852 | 310 | uint8_t* out = util::malloc(op.keySize); |
853 | | |
854 | 310 | CF_CHECK_EQ(op.digestType.Get(), CF_DIGEST("MD5_SHA1")); |
855 | | |
856 | 259 | { |
857 | 259 | size_t i = 0; |
858 | 1.39k | for (const auto& part : parts) { |
859 | 1.39k | seed_chunks[i].data = part.first; |
860 | 1.39k | seed_chunks[i].len = part.second; |
861 | 1.39k | i++; |
862 | 1.39k | } |
863 | 259 | } |
864 | | |
865 | | /* noret */ br_tls10_prf( |
866 | 259 | out, |
867 | 259 | op.keySize, |
868 | 259 | op.secret.GetPtr(), op.secret.GetSize(), |
869 | 259 | "", |
870 | 259 | parts.size(), |
871 | 259 | seed_chunks); |
872 | | |
873 | 259 | ret = component::Key(out, op.keySize); |
874 | | |
875 | 310 | end: |
876 | 310 | util::free(out); |
877 | 310 | util::free(seed_chunks); |
878 | | |
879 | 310 | return ret; |
880 | 259 | } |
881 | | |
882 | 3.48k | std::optional<component::ECC_KeyPair> BearSSL::OpECC_GenerateKeyPair(operation::ECC_GenerateKeyPair& op) { |
883 | 3.48k | std::optional<component::ECC_KeyPair> ret = std::nullopt; |
884 | 3.48k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
885 | | |
886 | 3.48k | br_ec_private_key sk; |
887 | 3.48k | br_ec_public_key pk; |
888 | 3.48k | uint8_t priv[BR_EC_KBUF_PRIV_MAX_SIZE]; |
889 | 3.48k | uint8_t pub[BR_EC_KBUF_PUB_MAX_SIZE]; |
890 | 3.48k | size_t privSize, pubSize; |
891 | 3.48k | int curve; |
892 | 3.48k | const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType); |
893 | | |
894 | 3.48k | CF_CHECK_NE(curve = BearSSL_detail::toCurveID(op.curveType), -1); |
895 | | |
896 | 1.04k | CF_CHECK_NE(privSize = br_ec_keygen(&BearSSL_detail::rng.vtable, ec_impl, &sk, priv, curve), 0); |
897 | 608 | CF_CHECK_NE(pubSize = br_ec_compute_pub(ec_impl, &pk, pub, &sk), 0); |
898 | | |
899 | 608 | if ( op.curveType.Is(CF_ECC_CURVE("x25519")) ) { |
900 | 162 | std::reverse(priv, priv + privSize); |
901 | 162 | } |
902 | | |
903 | 608 | ret = { BearSSL_detail::toString(priv, privSize), BearSSL_detail::EncodePubkey(op.curveType, pub, pubSize) }; |
904 | 3.48k | end: |
905 | 3.48k | return ret; |
906 | 608 | } |
907 | | |
908 | 1.26k | std::optional<component::ECC_PublicKey> BearSSL::OpECC_PrivateToPublic(operation::ECC_PrivateToPublic& op) { |
909 | 1.26k | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
910 | 1.26k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
911 | | |
912 | 1.26k | br_ec_private_key sk; |
913 | 1.26k | br_ec_public_key pk; |
914 | 1.26k | uint8_t priv[BR_EC_KBUF_PRIV_MAX_SIZE]; |
915 | 1.26k | uint8_t pub[BR_EC_KBUF_PUB_MAX_SIZE]; |
916 | 1.26k | size_t privSize; |
917 | 1.26k | size_t pubSize; |
918 | 1.26k | const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType); |
919 | | |
920 | 1.26k | CF_CHECK_NE(sk.curve = BearSSL_detail::toCurveID(op.curveType), -1); |
921 | 932 | CF_CHECK_EQ(BearSSL_detail::IsValidPrivateKey(op.priv, op.curveType), true); |
922 | 849 | { |
923 | 849 | bool reverse; |
924 | | |
925 | 849 | if ( op.curveType.Is(CF_ECC_CURVE("x25519")) ) { |
926 | 418 | privSize = 32; |
927 | 418 | reverse = true; |
928 | 431 | } else { |
929 | 431 | reverse = false; |
930 | 431 | privSize = sizeof(priv); |
931 | 431 | } |
932 | 849 | CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.priv.ToTrimmedString(), priv, privSize, reverse), true); |
933 | 802 | } |
934 | | |
935 | 0 | sk.x = priv; |
936 | 802 | sk.xlen = privSize; |
937 | | |
938 | 802 | memset(&pk, 0, sizeof(pk)); |
939 | 802 | CF_CHECK_NE(pubSize = br_ec_compute_pub(ec_impl, &pk, pub, &sk), 0); |
940 | 598 | ret = BearSSL_detail::EncodePubkey(op.curveType, pub, pubSize); |
941 | | |
942 | 1.26k | end: |
943 | 1.26k | return ret; |
944 | 598 | } |
945 | | |
946 | 2.13k | std::optional<bool> BearSSL::OpECDSA_Verify(operation::ECDSA_Verify& op) { |
947 | 2.13k | std::optional<bool> ret = std::nullopt; |
948 | 2.13k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
949 | | |
950 | 2.13k | size_t generator_len; |
951 | 2.13k | size_t signature_len; |
952 | 2.13k | switch ( op.curveType.Get() ) { |
953 | 572 | case CF_ECC_CURVE("secp256r1"): |
954 | 572 | generator_len = 65; |
955 | 572 | signature_len = 64; |
956 | 572 | break; |
957 | 330 | case CF_ECC_CURVE("secp384r1"): |
958 | 330 | generator_len = 97; |
959 | 330 | signature_len = 96; |
960 | 330 | break; |
961 | 298 | case CF_ECC_CURVE("secp521r1"): |
962 | 298 | generator_len = 133; |
963 | 298 | signature_len = 132; |
964 | 298 | break; |
965 | 930 | default: |
966 | 930 | return std::nullopt; |
967 | 2.13k | } |
968 | | |
969 | 1.20k | size_t pubkeyHalfSize = (generator_len - 1) / 2; |
970 | 1.20k | size_t signatureHalfSize = signature_len / 2; |
971 | 1.20k | uint8_t* signature = util::malloc(signature_len); |
972 | 1.20k | uint8_t* pub = util::malloc(generator_len); |
973 | 1.20k | br_ec_public_key pk; |
974 | 1.20k | const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType); |
975 | 1.20k | auto verify = BearSSL_detail::Get_br_ecdsa_vrfy(ds); |
976 | 1.20k | const br_hash_class* hash_class; |
977 | 1.20k | uint8_t _hash[64]; |
978 | 1.20k | const uint8_t* hash; |
979 | 1.20k | size_t hash_size = 0; |
980 | | |
981 | 1.20k | if ( op.digestType.Get() == CF_DIGEST("NULL") ) { |
982 | 0 | hash = op.cleartext.GetPtr(); |
983 | 0 | hash_size = op.cleartext.GetSize(); |
984 | 1.20k | } else { |
985 | 1.20k | br_hash_compat_context hc; |
986 | | |
987 | 1.20k | CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr); |
988 | | |
989 | 1.16k | hash_class->init(&hc.vtable); |
990 | 1.16k | hash_class->update(&hc.vtable, op.cleartext.GetPtr(), op.cleartext.GetSize()); |
991 | 1.16k | hash_class->out(&hc.vtable, _hash); |
992 | 1.16k | hash = _hash; |
993 | 1.16k | hash_size = (hash_class->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; |
994 | 1.16k | } |
995 | 1.16k | CF_CHECK_NE(pk.curve = BearSSL_detail::toCurveID(op.curveType), -1); |
996 | | |
997 | 1.16k | CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.signature.first.ToTrimmedString(), signature, signatureHalfSize), true); |
998 | 1.14k | CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.signature.second.ToTrimmedString(), signature + signatureHalfSize, signatureHalfSize), true); |
999 | | |
1000 | 1.12k | pub[0] = 0x04; |
1001 | 1.12k | CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.pub.first.ToTrimmedString(), pub + 1, pubkeyHalfSize), true); |
1002 | 1.11k | CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.signature.pub.second.ToTrimmedString(), pub + 1 + pubkeyHalfSize, pubkeyHalfSize), true); |
1003 | | |
1004 | 1.10k | pk.q = pub; |
1005 | 1.10k | pk.qlen = generator_len; |
1006 | | |
1007 | 1.10k | ret = verify( |
1008 | 1.10k | ec_impl, |
1009 | 1.10k | hash, |
1010 | 1.10k | hash_size, |
1011 | 1.10k | &pk, |
1012 | 1.10k | signature, |
1013 | 1.10k | signature_len); |
1014 | 1.20k | end: |
1015 | | |
1016 | 1.20k | util::free(signature); |
1017 | 1.20k | util::free(pub); |
1018 | | |
1019 | 1.20k | return ret; |
1020 | 1.10k | } |
1021 | | |
1022 | 1.46k | std::optional<component::ECDSA_Signature> BearSSL::OpECDSA_Sign(operation::ECDSA_Sign& op) { |
1023 | 1.46k | std::optional<component::ECDSA_Signature> ret = std::nullopt; |
1024 | 1.46k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
1025 | | |
1026 | 1.46k | size_t signature_len; |
1027 | 1.46k | switch ( op.curveType.Get() ) { |
1028 | 167 | case CF_ECC_CURVE("secp256r1"): |
1029 | 167 | signature_len = 64; |
1030 | 167 | break; |
1031 | 237 | case CF_ECC_CURVE("secp384r1"): |
1032 | 237 | signature_len = 96; |
1033 | 237 | break; |
1034 | 225 | case CF_ECC_CURVE("secp521r1"): |
1035 | 225 | signature_len = 132; |
1036 | 225 | break; |
1037 | 835 | default: |
1038 | 835 | return std::nullopt; |
1039 | 1.46k | } |
1040 | | |
1041 | 629 | br_ec_private_key sk; |
1042 | 629 | br_ec_public_key pk; |
1043 | 629 | uint8_t priv[BR_EC_KBUF_PRIV_MAX_SIZE]; |
1044 | 629 | uint8_t pub[BR_EC_KBUF_PUB_MAX_SIZE]; |
1045 | 629 | size_t pubSize; |
1046 | 629 | uint8_t* signature = util::malloc(signature_len); |
1047 | 629 | size_t sigSize; |
1048 | 629 | uint8_t hash[64]; |
1049 | 629 | br_hash_compat_context hc; |
1050 | 629 | const br_hash_class* hash_class; |
1051 | 629 | const auto ec_impl = BearSSL_detail::Get_br_ec_impl(ds, op.curveType); |
1052 | 629 | auto sign = BearSSL_detail::Get_br_ecdsa_sign(ds); |
1053 | | |
1054 | 629 | CF_CHECK_EQ(op.UseRFC6979Nonce(), true); |
1055 | 600 | CF_CHECK_NE(hash_class = BearSSL_detail::To_br_hash_class(op.digestType), nullptr); |
1056 | | |
1057 | 590 | CF_CHECK_NE(sk.curve = BearSSL_detail::toCurveID(op.curveType), -1); |
1058 | 590 | CF_CHECK_EQ(BearSSL_detail::IsValidPrivateKey(op.priv, op.curveType), true); |
1059 | 580 | CF_CHECK_EQ(BearSSL_detail::EncodeBignum(op.priv.ToTrimmedString(), priv, sizeof(priv)), true); |
1060 | | |
1061 | 580 | hash_class->init(&hc.vtable); |
1062 | 580 | hash_class->update(&hc.vtable, op.cleartext.GetPtr(), op.cleartext.GetSize()); |
1063 | 580 | hash_class->out(&hc.vtable, hash); |
1064 | | |
1065 | 580 | sk.x = priv; |
1066 | 580 | sk.xlen = sizeof(priv); |
1067 | | |
1068 | 580 | memset(&pk, 0, sizeof(pk)); |
1069 | 580 | CF_CHECK_NE(pubSize = br_ec_compute_pub(ec_impl, &pk, pub, &sk), 0); |
1070 | | |
1071 | 580 | CF_CHECK_NE(sigSize = sign(ec_impl, hash_class, hash, &sk, signature), 0); |
1072 | | |
1073 | 580 | if ( sigSize % 2 != 0 ) { |
1074 | 0 | abort(); |
1075 | 0 | } |
1076 | | |
1077 | | /* Disabled because signature S needs to be corrected for compatibility with Botan/Trezor */ |
1078 | 580 | CF_CHECK_NE(op.curveType.Get(), CF_ECC_CURVE("secp256r1")); |
1079 | | |
1080 | 434 | ret = { |
1081 | 434 | {BearSSL_detail::toString(signature, sigSize / 2), BearSSL_detail::toString(signature + (sigSize/2), sigSize / 2) }, |
1082 | 434 | BearSSL_detail::EncodePubkey(op.curveType, pub, pubSize) |
1083 | 434 | }; |
1084 | | |
1085 | 629 | end: |
1086 | 629 | util::free(signature); |
1087 | 629 | return ret; |
1088 | 434 | } |
1089 | | |
1090 | | } /* namespace module */ |
1091 | | } /* namespace cryptofuzz */ |