/src/cryptofuzz/modules/nss/module.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "module.h" |
2 | | #include <cryptofuzz/repository.h> |
3 | | #include <fuzzing/datasource/id.hpp> |
4 | | #include <boost/multiprecision/cpp_int.hpp> |
5 | | #include <nss.h> |
6 | | #include <pk11pub.h> |
7 | | #include <nss_scoped_ptrs.h> |
8 | | #include <blapi.h> |
9 | | #include "bn_ops.h" |
10 | | |
11 | | namespace cryptofuzz { |
12 | | namespace module { |
13 | | |
14 | | NSS::NSS(void) : |
15 | 2 | Module("NSS") { |
16 | 2 | setenv("NSS_STRICT_NOFORK", "DISABLED", 1); |
17 | 2 | const SECStatus rv = NSS_NoDB_Init(NULL); |
18 | 2 | if(rv != SECSuccess) { |
19 | 0 | printf("Cannot initialize NSS\n"); |
20 | 0 | abort(); |
21 | 0 | } |
22 | | |
23 | 2 | NSS_bignum::Initialize(); |
24 | 2 | } |
25 | | |
26 | 0 | NSS::~NSS(void) { |
27 | 0 | NSS_Shutdown(); |
28 | 0 | } |
29 | | |
30 | | namespace nss_detail { |
31 | 806 | std::optional<SECOidTag> toOID(const component::DigestType& digestType) { |
32 | 806 | static const std::map<uint64_t, SECOidTag> LUT = { |
33 | 806 | { CF_DIGEST("SHA1"), SEC_OID_SHA1 }, |
34 | 806 | { CF_DIGEST("SHA224"), SEC_OID_SHA224 }, |
35 | 806 | { CF_DIGEST("SHA256"), SEC_OID_SHA256 }, |
36 | 806 | { CF_DIGEST("SHA384"), SEC_OID_SHA384 }, |
37 | 806 | { CF_DIGEST("SHA512"), SEC_OID_SHA512 }, |
38 | | /* awaiting fix https://bugzilla.mozilla.org/show_bug.cgi?id=1575923 { CF_DIGEST("MD2"), SEC_OID_MD2 }, */ |
39 | 806 | { CF_DIGEST("MD4"), SEC_OID_MD4 }, |
40 | 806 | { CF_DIGEST("MD5"), SEC_OID_MD5 }, |
41 | 806 | }; |
42 | | |
43 | 806 | if ( LUT.find(digestType.Get()) == LUT.end() ) { |
44 | 726 | return std::nullopt; |
45 | 726 | } |
46 | | |
47 | 80 | return LUT.at(digestType.Get()); |
48 | 806 | } |
49 | | } |
50 | | |
51 | 806 | std::optional<component::Digest> NSS::OpDigest(operation::Digest& op) { |
52 | 806 | std::optional<component::Digest> ret = std::nullopt; |
53 | 806 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
54 | | |
55 | 806 | util::Multipart parts; |
56 | 806 | unsigned char out[256]; |
57 | | |
58 | | /* TODO scoped ? */ |
59 | 806 | PK11Context* ctx = nullptr; |
60 | | |
61 | | /* Initialize */ |
62 | 806 | { |
63 | 806 | std::optional<SECOidTag> oid; |
64 | 806 | CF_CHECK_NE(oid = nss_detail::toOID(op.digestType), std::nullopt); |
65 | 80 | CF_CHECK_NE(ctx = PK11_CreateDigestContext(*oid), nullptr); |
66 | 64 | CF_CHECK_EQ(PK11_DigestBegin(ctx), SECSuccess); |
67 | 64 | parts = util::ToParts(ds, op.cleartext); |
68 | 64 | } |
69 | | |
70 | | /* Process */ |
71 | 27.3k | for (const auto& part : parts) { |
72 | 27.3k | CF_CHECK_EQ(PK11_DigestOp(ctx, part.first, part.second), SECSuccess); |
73 | 27.3k | } |
74 | | |
75 | | /* Finalize */ |
76 | 64 | { |
77 | 64 | unsigned int outlen; |
78 | 64 | CF_CHECK_EQ(PK11_DigestFinal(ctx, out, &outlen, sizeof(out)), SECSuccess); |
79 | 64 | ret = component::Digest(out, outlen); |
80 | 64 | } |
81 | | |
82 | 806 | end: |
83 | 806 | if ( ctx != nullptr ) { |
84 | 64 | PK11_DestroyContext(ctx, PR_TRUE); |
85 | 64 | } |
86 | | |
87 | 806 | return ret; |
88 | 64 | } |
89 | | |
90 | | namespace nss_detail { |
91 | 445 | std::optional<CK_MECHANISM_TYPE> toHMACCKM(const component::DigestType& digestType) { |
92 | 445 | static const std::map<uint64_t, uint64_t> LUT = { |
93 | 445 | { CF_DIGEST("SHA1"), CKM_SHA_1_HMAC }, |
94 | 445 | { CF_DIGEST("SHA224"), CKM_SHA224_HMAC }, |
95 | 445 | { CF_DIGEST("SHA256"), CKM_SHA256_HMAC }, |
96 | 445 | { CF_DIGEST("SHA384"), CKM_SHA384_HMAC }, |
97 | 445 | { CF_DIGEST("SHA512"), CKM_SHA512_HMAC }, |
98 | | /* awaiting fix https://bugzilla.mozilla.org/show_bug.cgi?id=1575923 { CF_DIGEST("MD2"), CKM_MD2_HMAC }, */ |
99 | 445 | { CF_DIGEST("MD5"), CKM_MD5_HMAC }, |
100 | 445 | { CF_DIGEST("RIPEMD128"), CKM_RIPEMD128_HMAC }, |
101 | 445 | { CF_DIGEST("RIPEMD160"), CKM_RIPEMD160_HMAC }, |
102 | 445 | }; |
103 | | |
104 | 445 | if ( LUT.find(digestType.Get()) == LUT.end() ) { |
105 | 351 | return std::nullopt; |
106 | 351 | } |
107 | | |
108 | 94 | return LUT.at(digestType.Get()); |
109 | 445 | } |
110 | | } |
111 | | |
112 | 445 | std::optional<component::MAC> NSS::OpHMAC(operation::HMAC& op) { |
113 | 445 | std::optional<component::Digest> ret = std::nullopt; |
114 | 445 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
115 | | |
116 | 445 | util::Multipart parts; |
117 | 445 | unsigned char out[256]; |
118 | | |
119 | 445 | PK11Context* ctx = nullptr; |
120 | 445 | PK11SymKey* key = nullptr; |
121 | 445 | PK11SlotInfo* slot = nullptr; |
122 | | |
123 | 445 | std::vector<uint8_t> keyvec(op.cipher.key.GetPtr(), op.cipher.key.GetPtr() + op.cipher.key.GetSize()); |
124 | | |
125 | | /* Initialize */ |
126 | 445 | { |
127 | 445 | CF_CHECK_NE(slot = PK11_GetInternalSlot(), nullptr); |
128 | | |
129 | 445 | std::optional<CK_MECHANISM_TYPE> ckm; |
130 | 445 | CF_CHECK_NE(ckm = nss_detail::toHMACCKM(op.digestType), std::nullopt); |
131 | | |
132 | 94 | { |
133 | 94 | SECItem keyItem; |
134 | 94 | keyItem.data = keyvec.data(); |
135 | 94 | keyItem.len = keyvec.size(); |
136 | 94 | CF_CHECK_NE(key = PK11_ImportSymKey(slot, *ckm, PK11_OriginDerive, |
137 | 94 | CKA_SIGN, &keyItem, nullptr), nullptr); |
138 | 94 | } |
139 | | |
140 | 0 | { |
141 | 94 | SECItem noParams; |
142 | 94 | noParams.data = 0; |
143 | 94 | noParams.len = 0; |
144 | 94 | CF_CHECK_NE(ctx = PK11_CreateContextBySymKey(*ckm, CKA_SIGN, key, &noParams), nullptr); |
145 | 68 | } |
146 | | |
147 | 68 | CF_CHECK_EQ(PK11_DigestBegin(ctx), SECSuccess); |
148 | 68 | parts = util::ToParts(ds, op.cleartext); |
149 | 68 | } |
150 | | |
151 | | /* Process */ |
152 | 20.3k | for (const auto& part : parts) { |
153 | 20.3k | CF_CHECK_EQ(PK11_DigestOp(ctx, part.first, part.second), SECSuccess); |
154 | 20.3k | } |
155 | | |
156 | | /* Finalize */ |
157 | 68 | { |
158 | 68 | unsigned int outlen; |
159 | 68 | CF_CHECK_EQ(PK11_DigestFinal(ctx, out, &outlen, sizeof(out)), SECSuccess); |
160 | 68 | ret = component::MAC(out, outlen); |
161 | 68 | } |
162 | | |
163 | 445 | end: |
164 | 445 | if ( ctx != nullptr ) { |
165 | 68 | PK11_DestroyContext(ctx, PR_TRUE); |
166 | 68 | } |
167 | 445 | if ( key != nullptr ) { |
168 | 94 | PK11_FreeSymKey(key); |
169 | 94 | } |
170 | 445 | if ( slot != nullptr ) { |
171 | 445 | PK11_FreeSlot(slot); |
172 | 445 | } |
173 | | |
174 | 445 | return ret; |
175 | 68 | } |
176 | | |
177 | 125 | std::optional<component::MAC> NSS::OpCMAC(operation::CMAC& op) { |
178 | 125 | if ( op.cipher.cipherType.Get() != CF_CIPHER("AES") ) { |
179 | 123 | return std::nullopt; |
180 | 123 | } |
181 | | |
182 | 2 | std::optional<component::MAC> ret = std::nullopt; |
183 | | |
184 | 2 | std::vector<uint8_t> output(AES_BLOCK_SIZE); |
185 | 2 | std::vector<uint8_t> keyvec(op.cipher.key.GetPtr(), op.cipher.key.GetPtr() + op.cipher.key.GetSize()); |
186 | 2 | std::vector<uint8_t> ctvec(op.cleartext.GetPtr(), op.cleartext.GetPtr() + op.cleartext.GetSize()); |
187 | | |
188 | 2 | SECItem key_item = {siBuffer, keyvec.data(), static_cast<uint32_t>(keyvec.size())}; |
189 | 2 | SECItem output_item = {siBuffer, output.data(), AES_BLOCK_SIZE}; |
190 | 2 | SECItem data_item = {siBuffer, ctvec.data(), static_cast<uint32_t>(ctvec.size())}; |
191 | | |
192 | 2 | PK11SlotInfo* slot = nullptr; |
193 | 2 | PK11SymKey* p11_key = nullptr; |
194 | 2 | CF_CHECK_NE(slot = PK11_GetInternalSlot(), nullptr); |
195 | | |
196 | 2 | CF_CHECK_NE(p11_key = PK11_ImportSymKey(slot, CKM_AES_CMAC, PK11_OriginUnwrap, CKA_SIGN, &key_item, nullptr), nullptr); |
197 | 1 | CF_CHECK_EQ(PK11_SignWithSymKey(p11_key, CKM_AES_CMAC, nullptr, &output_item, &data_item), SECSuccess); |
198 | | |
199 | 1 | ret = component::MAC(output.data(), output.size()); |
200 | | |
201 | 2 | end: |
202 | 2 | if ( p11_key != nullptr ) { |
203 | 1 | PK11_FreeSymKey(p11_key); |
204 | 1 | } |
205 | 2 | if ( slot != nullptr ) { |
206 | 2 | PK11_FreeSlot(slot); |
207 | 2 | } |
208 | | |
209 | 2 | return ret; |
210 | 1 | } |
211 | | |
212 | | namespace nss_detail { |
213 | 730 | std::optional<CK_MECHANISM_TYPE> toCipherCKM(const component::SymmetricCipherType& cipherType) { |
214 | 730 | static const std::map<uint64_t, uint64_t> LUT = { |
215 | | //{ CF_CIPHER("RC2_CBC"), CKM_RC2_CBC }, |
216 | | //{ CF_CIPHER("RC4"), CKM_RC4 }, |
217 | 730 | { CF_CIPHER("DES_CBC"), CKM_DES_CBC }, |
218 | 730 | { CF_CIPHER("DES_ECB"), CKM_DES_ECB }, |
219 | 730 | { CF_CIPHER("AES_128_CBC"), CKM_AES_CBC }, |
220 | 730 | { CF_CIPHER("AES_128_ECB"), CKM_AES_ECB }, |
221 | 730 | { CF_CIPHER("AES_128_CTR"), CKM_AES_CTR }, |
222 | 730 | { CF_CIPHER("AES_128_CCM"), CKM_AES_CCM }, |
223 | 730 | { CF_CIPHER("IDEA_CBC"), CKM_IDEA_CBC }, |
224 | 730 | { CF_CIPHER("IDEA_ECB"), CKM_IDEA_ECB }, |
225 | 730 | { CF_CIPHER("BF_CBC"), CKM_BLOWFISH_CBC }, |
226 | 730 | { CF_CIPHER("SEED_CBC"), CKM_SEED_CBC }, |
227 | 730 | { CF_CIPHER("CAST5_CBC"), CKM_CAST5_CBC }, |
228 | 730 | { CF_CIPHER("CAST5_ECB"), CKM_CAST5_ECB }, |
229 | 730 | { CF_CIPHER("CAMELLIA_128_CBC"), CKM_CAMELLIA_CBC }, |
230 | 730 | { CF_CIPHER("CAMELLIA_128_ECB"), CKM_CAMELLIA_ECB }, |
231 | 730 | { CF_CIPHER("SEED_ECB"), CKM_SEED_ECB }, |
232 | 730 | { CF_CIPHER("AES_128_GCM"), CKM_AES_GCM }, |
233 | 730 | { CF_CIPHER("AES_192_GCM"), CKM_AES_GCM }, |
234 | 730 | { CF_CIPHER("AES_256_GCM"), CKM_AES_GCM }, |
235 | 730 | { CF_CIPHER("CHACHA20_POLY1305"), CKM_NSS_CHACHA20_POLY1305}, |
236 | 730 | #if 1 |
237 | 730 | { 30, CKM_CAST3_CBC }, |
238 | 730 | { 31, CKM_CAST3_ECB }, |
239 | 730 | { 32, CKM_CDMF_CBC}, |
240 | 730 | { 0, CKM_BATON_CBC128}, |
241 | 730 | { 1, CKM_BATON_COUNTER}, |
242 | 730 | { 2, CKM_BATON_ECB128}, |
243 | 730 | { 3, CKM_BATON_ECB96}, |
244 | 730 | { 4, CKM_BATON_KEY_GEN}, |
245 | 730 | { 5, CKM_BATON_SHUFFLE}, |
246 | 730 | { 6, CKM_BATON_WRAP}, |
247 | 730 | { 7, CKM_SKIPJACK_CBC64}, |
248 | 730 | { 8, CKM_SKIPJACK_CFB16}, |
249 | 730 | { 9, CKM_SKIPJACK_CFB32}, |
250 | 730 | {10, CKM_SKIPJACK_CFB64}, |
251 | 730 | {11, CKM_SKIPJACK_CFB8}, |
252 | 730 | {12, CKM_SKIPJACK_ECB64}, |
253 | 730 | {13, CKM_SKIPJACK_KEY_GEN}, |
254 | 730 | {14, CKM_SKIPJACK_OFB64}, |
255 | 730 | {15, CKM_SKIPJACK_PRIVATE_WRAP}, |
256 | 730 | {16, CKM_SKIPJACK_RELAYX}, |
257 | 730 | {17, CKM_SKIPJACK_WRAP}, |
258 | 730 | #endif |
259 | 730 | }; |
260 | | |
261 | 730 | if ( LUT.find(cipherType.Get()) == LUT.end() ) { |
262 | 646 | return std::nullopt; |
263 | 646 | } |
264 | | |
265 | 84 | return LUT.at(cipherType.Get()); |
266 | 730 | } |
267 | | } |
268 | | |
269 | | namespace nss_detail { |
270 | | template <class OperationType> |
271 | | util::Multipart ToParts(Datasource& ds, const OperationType& op); |
272 | | |
273 | | template <> |
274 | 3 | util::Multipart ToParts<>(Datasource& ds, const operation::SymmetricEncrypt& op) { |
275 | 3 | return util::ToParts(ds, op.cleartext); |
276 | 3 | } |
277 | | |
278 | | template <> |
279 | 5 | util::Multipart ToParts<>(Datasource& ds, const operation::SymmetricDecrypt& op) { |
280 | 5 | return util::ToParts(ds, op.ciphertext); |
281 | 5 | } |
282 | | |
283 | | template <class OperationType> |
284 | | CK_ATTRIBUTE_TYPE GetAttributeType(void); |
285 | | |
286 | | template <> |
287 | 12 | CK_ATTRIBUTE_TYPE GetAttributeType<operation::SymmetricEncrypt>(void) { |
288 | 12 | return CKA_ENCRYPT; |
289 | 12 | } |
290 | | |
291 | | template <> |
292 | 8 | CK_ATTRIBUTE_TYPE GetAttributeType<operation::SymmetricDecrypt>(void) { |
293 | 8 | return CKA_DECRYPT; |
294 | 8 | } |
295 | | |
296 | | template <class OperationType> |
297 | | size_t GetInSize(const OperationType& op); |
298 | | |
299 | 385 | template <> size_t GetInSize<>(const operation::SymmetricEncrypt& op) { |
300 | 385 | return op.cleartext.GetSize(); |
301 | 385 | } |
302 | | |
303 | | template <class OperationType> |
304 | | const uint8_t* GetInPtr(const OperationType& op); |
305 | | |
306 | 16 | template <> const uint8_t* GetInPtr<>(const operation::SymmetricEncrypt& op) { |
307 | 16 | return op.cleartext.GetPtr(); |
308 | 16 | } |
309 | | |
310 | | template <class OperationType> |
311 | | size_t GetOutSize(const OperationType& op); |
312 | | |
313 | 524 | template <> size_t GetOutSize<>(const operation::SymmetricEncrypt& op) { |
314 | 524 | return op.ciphertextSize; |
315 | 524 | } |
316 | | |
317 | 396 | template <> size_t GetInSize<>(const operation::SymmetricDecrypt& op) { |
318 | 396 | return op.ciphertext.GetSize(); |
319 | 396 | } |
320 | | |
321 | 35 | template <> const uint8_t* GetInPtr<>(const operation::SymmetricDecrypt& op) { |
322 | 35 | return op.ciphertext.GetPtr(); |
323 | 35 | } |
324 | | |
325 | 570 | template <> size_t GetOutSize<>(const operation::SymmetricDecrypt& op) { |
326 | 570 | return op.cleartextSize; |
327 | 570 | } |
328 | | |
329 | | template <class OperationType> |
330 | | size_t GetTagSize(const OperationType& op); |
331 | | |
332 | | template <> |
333 | 10 | size_t GetTagSize<>(const operation::SymmetricEncrypt& op) { |
334 | 10 | return op.tagSize == std::nullopt ? 0 : *op.tagSize; |
335 | 10 | } |
336 | | |
337 | | template <> |
338 | 16 | size_t GetTagSize<>(const operation::SymmetricDecrypt& op) { |
339 | 16 | return op.tag == std::nullopt ? 0 : op.tag->GetSize(); |
340 | 16 | } |
341 | | |
342 | | template <class OperationType> |
343 | | SECStatus CryptOneShot(PK11SymKey* key, CK_MECHANISM_TYPE ckm, SECItem* param, uint8_t* out, OperationType& op, unsigned int* outLen); |
344 | | |
345 | 16 | template <> SECStatus CryptOneShot<>(PK11SymKey* key, CK_MECHANISM_TYPE ckm, SECItem* param, uint8_t* out, operation::SymmetricEncrypt& op, unsigned int* outLen) { |
346 | 16 | return PK11_Encrypt( |
347 | 16 | key, |
348 | 16 | ckm, |
349 | 16 | param, |
350 | 16 | out, |
351 | 16 | outLen, |
352 | 16 | GetOutSize(op), |
353 | 16 | GetInPtr(op), |
354 | 16 | GetInSize(op)); |
355 | 16 | } |
356 | | |
357 | 25 | template <> SECStatus CryptOneShot<>(PK11SymKey* key, CK_MECHANISM_TYPE ckm, SECItem* param, uint8_t* out, operation::SymmetricDecrypt& op, unsigned int* outLen) { |
358 | 25 | uint8_t const* inPtr; |
359 | 25 | size_t inSize; |
360 | | |
361 | 25 | std::vector<uint8_t> invec; |
362 | 25 | if ( repository::IsAEAD(op.cipher.cipherType.Get()) && op.tag != std::nullopt ) { |
363 | 10 | std::vector<uint8_t> ciphertextvec(GetInPtr(op), GetInPtr(op) + GetInSize(op)); |
364 | 10 | std::vector<uint8_t> tagvec(op.tag->GetPtr(), op.tag->GetPtr() + op.tag->GetSize()); |
365 | | |
366 | 10 | std::copy(ciphertextvec.begin(), ciphertextvec.end(), std::back_inserter(invec)); |
367 | 10 | std::copy(tagvec.begin(), tagvec.end(), std::back_inserter(invec)); |
368 | | |
369 | 10 | inPtr = invec.data(); |
370 | 10 | inSize = invec.size(); |
371 | 15 | } else { |
372 | 15 | inPtr = GetInPtr(op), |
373 | 15 | inSize = GetInSize(op); |
374 | 15 | } |
375 | | |
376 | 25 | return PK11_Decrypt( |
377 | 25 | key, |
378 | 25 | ckm, |
379 | 25 | param, |
380 | 25 | out, |
381 | 25 | outLen, |
382 | 25 | GetOutSize(op), |
383 | 25 | inPtr, |
384 | 25 | inSize); |
385 | 25 | } |
386 | | |
387 | | template <class ReturnType, class OperationType> |
388 | | ReturnType CreateReturnValue( |
389 | | const OperationType& op, |
390 | | const uint8_t* data, |
391 | | const size_t size); |
392 | | |
393 | | template <> component::Ciphertext CreateReturnValue( |
394 | | const operation::SymmetricEncrypt& op, |
395 | | const uint8_t* data, |
396 | 0 | const size_t size) { |
397 | 0 | if ( repository::IsAEAD(op.cipher.cipherType.Get()) ) { |
398 | 0 | if ( size != op.cleartext.GetSize() + GetTagSize(op) ) { |
399 | 0 | printf("%zu, %zu %zu\n", size, op.cleartext.GetSize(), GetTagSize(op)); |
400 | 0 | abort(); |
401 | 0 | } |
402 | 0 | return component::Ciphertext( |
403 | 0 | Buffer(data, op.cleartext.GetSize()), |
404 | 0 | Buffer(data + op.cleartext.GetSize(), GetTagSize(op))); |
405 | 0 | } else { |
406 | 0 | return component::Ciphertext(Buffer(data, size)); |
407 | 0 | } |
408 | 0 | } |
409 | | |
410 | | template <> component::Cleartext CreateReturnValue( |
411 | | const operation::SymmetricDecrypt& op, |
412 | | const uint8_t* data, |
413 | 1 | const size_t size) { |
414 | 1 | (void)op; |
415 | 1 | return component::Cleartext(Buffer(data, size)); |
416 | 1 | } |
417 | | |
418 | | template <class ReturnType, class OperationType> |
419 | 959 | std::optional<ReturnType> Crypt(OperationType& op) { |
420 | 959 | std::optional<ReturnType> ret = std::nullopt; |
421 | 959 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
422 | | |
423 | 959 | uint8_t* out = util::malloc(GetOutSize(op)); |
424 | | |
425 | 959 | PK11SymKey* key = nullptr; |
426 | 959 | PK11SlotInfo* slot = nullptr; |
427 | 959 | SECItem* param = nullptr; |
428 | 959 | PK11Context* ctx = nullptr; |
429 | 959 | CK_NSS_AEAD_PARAMS* aead_params = nullptr; |
430 | 959 | CK_NSS_GCM_PARAMS* gcm_params = nullptr; |
431 | | |
432 | 959 | size_t outIdx = 0; |
433 | 959 | util::Multipart parts; |
434 | 959 | bool useOneShot = true; |
435 | | |
436 | 959 | std::vector<uint8_t> keyvec(op.cipher.key.GetPtr(), op.cipher.key.GetPtr() + op.cipher.key.GetSize()); |
437 | 959 | std::vector<uint8_t> ivvec(op.cipher.iv.GetPtr(), op.cipher.iv.GetPtr() + op.cipher.iv.GetSize()); |
438 | 959 | std::vector<uint8_t> aadvec; |
439 | 959 | if ( op.aad != std::nullopt ) { |
440 | 250 | aadvec = std::vector<uint8_t>(op.aad->GetPtr(), op.aad->GetPtr() + op.aad->GetSize()); |
441 | 250 | } |
442 | | |
443 | 959 | std::optional<CK_MECHANISM_TYPE> ckm; |
444 | | |
445 | | /* Initialize */ |
446 | 959 | { |
447 | 959 | CF_CHECK_GT(op.cipher.key.GetSize(), 0); |
448 | 842 | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); |
449 | 740 | CF_CHECK_GT(GetInSize(op), 0); |
450 | | |
451 | 730 | CF_CHECK_NE(ckm = nss_detail::toCipherCKM(op.cipher.cipherType), std::nullopt); |
452 | | |
453 | 84 | CF_CHECK_NE(slot = PK11_GetInternalSlot(), nullptr); |
454 | | |
455 | 84 | CF_CHECK_GT(GetOutSize(op), 0); |
456 | | |
457 | 79 | { |
458 | 79 | SECItem keyItem; |
459 | 79 | keyItem.data = keyvec.data(); |
460 | 79 | keyItem.len = keyvec.size(); |
461 | 79 | CF_CHECK_NE(key = PK11_ImportSymKey(slot, *ckm, PK11_OriginDerive, |
462 | 79 | CKA_SIGN, &keyItem, nullptr), nullptr); |
463 | 63 | } |
464 | | |
465 | 63 | if ( op.cipher.cipherType.Get() == CF_CIPHER("AES_128_CTR") ) { |
466 | 2 | CK_AES_CTR_PARAMS* aes_ctr_params = nullptr; |
467 | 2 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 16); |
468 | |
|
469 | 0 | CF_CHECK_NE(param = (SECItem *)PORT_Alloc(sizeof(SECItem)), nullptr); |
470 | 0 | CF_CHECK_NE(aes_ctr_params = (CK_AES_CTR_PARAMS*)PORT_Alloc(sizeof(CK_AES_CTR_PARAMS)), nullptr); |
471 | |
|
472 | 0 | aes_ctr_params->ulCounterBits = 128; |
473 | 0 | memcpy(aes_ctr_params->cb, op.cipher.iv.GetPtr(), 16); |
474 | |
|
475 | 0 | param->type = siBuffer; |
476 | 0 | param->data = (unsigned char *)aes_ctr_params; |
477 | 0 | param->len = sizeof(*aes_ctr_params); |
478 | 61 | } else if ( repository::IsAEAD(op.cipher.cipherType.Get()) == false ) { |
479 | 35 | SECItem ivItem = {siBuffer, ivvec.data(), (unsigned int)ivvec.size()}; |
480 | 35 | CF_CHECK_NE(param = PK11_ParamFromIV(*ckm, &ivItem), nullptr); |
481 | 35 | } else { |
482 | 26 | CF_CHECK_NE(param = (SECItem *)PORT_Alloc(sizeof(SECItem)), nullptr); |
483 | | |
484 | 26 | if ( repository::IsGCM(op.cipher.cipherType.Get()) ) { |
485 | 12 | CF_CHECK_NE(gcm_params = (CK_NSS_GCM_PARAMS*)PORT_Alloc(sizeof(CK_NSS_GCM_PARAMS)), nullptr); |
486 | | |
487 | 12 | gcm_params->pIv = ivvec.data(); |
488 | 12 | gcm_params->ulIvLen = ivvec.size(); |
489 | 12 | gcm_params->pAAD = aadvec.data(); |
490 | 12 | gcm_params->ulAADLen = aadvec.size(); |
491 | 12 | gcm_params->ulTagBits = GetTagSize(op) * 8; |
492 | | |
493 | 12 | param->type = siBuffer; |
494 | 12 | param->data = (unsigned char *)gcm_params; |
495 | 12 | param->len = sizeof(*gcm_params); |
496 | 14 | } else { |
497 | 14 | CF_CHECK_NE(aead_params = (CK_NSS_AEAD_PARAMS*)PORT_Alloc(sizeof(CK_NSS_AEAD_PARAMS)), nullptr); |
498 | 14 | aead_params->pNonce = ivvec.data(); |
499 | 14 | aead_params->ulNonceLen = ivvec.size(); |
500 | 14 | aead_params->pAAD = aadvec.data(); |
501 | 14 | aead_params->ulAADLen = aadvec.size(); |
502 | 14 | aead_params->ulTagLen = GetTagSize(op); |
503 | | |
504 | 14 | param->type = siBuffer; |
505 | 14 | param->data = (unsigned char *)aead_params; |
506 | 14 | param->len = sizeof(*aead_params); |
507 | 14 | } |
508 | 26 | } |
509 | | |
510 | 61 | if ( repository::IsAEAD(op.cipher.cipherType.Get()) == false ) { |
511 | 35 | try { |
512 | 35 | useOneShot = ds.Get<bool>(); |
513 | 35 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { |
514 | 1 | } |
515 | 35 | } |
516 | | |
517 | 61 | if ( useOneShot == false ) { |
518 | 20 | CF_CHECK_NE(ctx = PK11_CreateContextBySymKey(*ckm, GetAttributeType<OperationType>(), key, param), nullptr); |
519 | 8 | parts = ToParts(ds, op); |
520 | 8 | } |
521 | 61 | } |
522 | | |
523 | 49 | if ( useOneShot == true ) { |
524 | 41 | unsigned int outLen; |
525 | 41 | const auto res = CryptOneShot<OperationType>(key, *ckm, param, out, op, &outLen); |
526 | 41 | if ( res == SECSuccess ) { |
527 | 1 | if ( GetOutSize(op) > 0 ) /* Workaround for crash */ { |
528 | 1 | ret = CreateReturnValue<ReturnType, OperationType>(op, out, outLen); |
529 | 1 | } |
530 | 1 | } |
531 | 41 | } else { |
532 | | /* Process */ |
533 | 8 | { |
534 | 10 | for (const auto& part : parts) { |
535 | 10 | if ( part.second == 0 ) { |
536 | 1 | continue; |
537 | 1 | } |
538 | | |
539 | 9 | int outLen; |
540 | 9 | CF_CHECK_EQ(PK11_CipherOp( |
541 | 9 | ctx, |
542 | 9 | out + outIdx, |
543 | 9 | &outLen, |
544 | 9 | GetOutSize(op) - outIdx, |
545 | 9 | part.first, |
546 | 9 | part.second), SECSuccess); |
547 | 1 | if ( outLen < 0 ) abort(); /* XXX ? */ |
548 | 1 | outIdx += outLen; |
549 | 1 | } |
550 | 8 | } |
551 | | |
552 | | /* Finalize */ |
553 | 0 | { |
554 | 0 | unsigned int outLen; |
555 | 0 | CF_CHECK_EQ(PK11_DigestFinal(ctx, out + outIdx, &outLen, GetOutSize(op) - outIdx), SECSuccess); |
556 | 0 | outIdx += outLen; |
557 | 0 | if ( GetOutSize(op) > 0 ) /* Workaround for crash */ { |
558 | 0 | ret = CreateReturnValue<ReturnType, OperationType>(op, out, outIdx); |
559 | 0 | } |
560 | 0 | } |
561 | 0 | } |
562 | | |
563 | 959 | end: |
564 | 959 | util::free(out); |
565 | | |
566 | 959 | if ( key != nullptr ) { |
567 | 63 | PK11_FreeSymKey(key); |
568 | 63 | } |
569 | 959 | if ( param != nullptr ) { |
570 | 61 | SECITEM_FreeItem(param, PR_TRUE); |
571 | 61 | } |
572 | 959 | if ( slot != nullptr ) { |
573 | 84 | PK11_FreeSlot(slot); |
574 | 84 | } |
575 | 959 | if ( ctx != nullptr ) { |
576 | 8 | PK11_DestroyContext(ctx, PR_TRUE); |
577 | 8 | } |
578 | 959 | return ret; |
579 | 49 | } std::__1::optional<cryptofuzz::component::Ciphertext> cryptofuzz::module::nss_detail::Crypt<cryptofuzz::component::Ciphertext, cryptofuzz::operation::SymmetricEncrypt>(cryptofuzz::operation::SymmetricEncrypt&) Line | Count | Source | 419 | 464 | std::optional<ReturnType> Crypt(OperationType& op) { | 420 | 464 | std::optional<ReturnType> ret = std::nullopt; | 421 | 464 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); | 422 | | | 423 | 464 | uint8_t* out = util::malloc(GetOutSize(op)); | 424 | | | 425 | 464 | PK11SymKey* key = nullptr; | 426 | 464 | PK11SlotInfo* slot = nullptr; | 427 | 464 | SECItem* param = nullptr; | 428 | 464 | PK11Context* ctx = nullptr; | 429 | 464 | CK_NSS_AEAD_PARAMS* aead_params = nullptr; | 430 | 464 | CK_NSS_GCM_PARAMS* gcm_params = nullptr; | 431 | | | 432 | 464 | size_t outIdx = 0; | 433 | 464 | util::Multipart parts; | 434 | 464 | bool useOneShot = true; | 435 | | | 436 | 464 | std::vector<uint8_t> keyvec(op.cipher.key.GetPtr(), op.cipher.key.GetPtr() + op.cipher.key.GetSize()); | 437 | 464 | std::vector<uint8_t> ivvec(op.cipher.iv.GetPtr(), op.cipher.iv.GetPtr() + op.cipher.iv.GetSize()); | 438 | 464 | std::vector<uint8_t> aadvec; | 439 | 464 | if ( op.aad != std::nullopt ) { | 440 | 134 | aadvec = std::vector<uint8_t>(op.aad->GetPtr(), op.aad->GetPtr() + op.aad->GetSize()); | 441 | 134 | } | 442 | | | 443 | 464 | std::optional<CK_MECHANISM_TYPE> ckm; | 444 | | | 445 | | /* Initialize */ | 446 | 464 | { | 447 | 464 | CF_CHECK_GT(op.cipher.key.GetSize(), 0); | 448 | 402 | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); | 449 | 369 | CF_CHECK_GT(GetInSize(op), 0); | 450 | | | 451 | 363 | CF_CHECK_NE(ckm = nss_detail::toCipherCKM(op.cipher.cipherType), std::nullopt); | 452 | | | 453 | 41 | CF_CHECK_NE(slot = PK11_GetInternalSlot(), nullptr); | 454 | | | 455 | 41 | CF_CHECK_GT(GetOutSize(op), 0); | 456 | | | 457 | 38 | { | 458 | 38 | SECItem keyItem; | 459 | 38 | keyItem.data = keyvec.data(); | 460 | 38 | keyItem.len = keyvec.size(); | 461 | 38 | CF_CHECK_NE(key = PK11_ImportSymKey(slot, *ckm, PK11_OriginDerive, | 462 | 38 | CKA_SIGN, &keyItem, nullptr), nullptr); | 463 | 29 | } | 464 | | | 465 | 29 | if ( op.cipher.cipherType.Get() == CF_CIPHER("AES_128_CTR") ) { | 466 | 1 | CK_AES_CTR_PARAMS* aes_ctr_params = nullptr; | 467 | 1 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 16); | 468 | |
| 469 | 0 | CF_CHECK_NE(param = (SECItem *)PORT_Alloc(sizeof(SECItem)), nullptr); | 470 | 0 | CF_CHECK_NE(aes_ctr_params = (CK_AES_CTR_PARAMS*)PORT_Alloc(sizeof(CK_AES_CTR_PARAMS)), nullptr); | 471 | |
| 472 | 0 | aes_ctr_params->ulCounterBits = 128; | 473 | 0 | memcpy(aes_ctr_params->cb, op.cipher.iv.GetPtr(), 16); | 474 | |
| 475 | 0 | param->type = siBuffer; | 476 | 0 | param->data = (unsigned char *)aes_ctr_params; | 477 | 0 | param->len = sizeof(*aes_ctr_params); | 478 | 28 | } else if ( repository::IsAEAD(op.cipher.cipherType.Get()) == false ) { | 479 | 18 | SECItem ivItem = {siBuffer, ivvec.data(), (unsigned int)ivvec.size()}; | 480 | 18 | CF_CHECK_NE(param = PK11_ParamFromIV(*ckm, &ivItem), nullptr); | 481 | 18 | } else { | 482 | 10 | CF_CHECK_NE(param = (SECItem *)PORT_Alloc(sizeof(SECItem)), nullptr); | 483 | | | 484 | 10 | if ( repository::IsGCM(op.cipher.cipherType.Get()) ) { | 485 | 6 | CF_CHECK_NE(gcm_params = (CK_NSS_GCM_PARAMS*)PORT_Alloc(sizeof(CK_NSS_GCM_PARAMS)), nullptr); | 486 | | | 487 | 6 | gcm_params->pIv = ivvec.data(); | 488 | 6 | gcm_params->ulIvLen = ivvec.size(); | 489 | 6 | gcm_params->pAAD = aadvec.data(); | 490 | 6 | gcm_params->ulAADLen = aadvec.size(); | 491 | 6 | gcm_params->ulTagBits = GetTagSize(op) * 8; | 492 | | | 493 | 6 | param->type = siBuffer; | 494 | 6 | param->data = (unsigned char *)gcm_params; | 495 | 6 | param->len = sizeof(*gcm_params); | 496 | 6 | } else { | 497 | 4 | CF_CHECK_NE(aead_params = (CK_NSS_AEAD_PARAMS*)PORT_Alloc(sizeof(CK_NSS_AEAD_PARAMS)), nullptr); | 498 | 4 | aead_params->pNonce = ivvec.data(); | 499 | 4 | aead_params->ulNonceLen = ivvec.size(); | 500 | 4 | aead_params->pAAD = aadvec.data(); | 501 | 4 | aead_params->ulAADLen = aadvec.size(); | 502 | 4 | aead_params->ulTagLen = GetTagSize(op); | 503 | | | 504 | 4 | param->type = siBuffer; | 505 | 4 | param->data = (unsigned char *)aead_params; | 506 | 4 | param->len = sizeof(*aead_params); | 507 | 4 | } | 508 | 10 | } | 509 | | | 510 | 28 | if ( repository::IsAEAD(op.cipher.cipherType.Get()) == false ) { | 511 | 18 | try { | 512 | 18 | useOneShot = ds.Get<bool>(); | 513 | 18 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 514 | 0 | } | 515 | 18 | } | 516 | | | 517 | 28 | if ( useOneShot == false ) { | 518 | 12 | CF_CHECK_NE(ctx = PK11_CreateContextBySymKey(*ckm, GetAttributeType<OperationType>(), key, param), nullptr); | 519 | 3 | parts = ToParts(ds, op); | 520 | 3 | } | 521 | 28 | } | 522 | | | 523 | 19 | if ( useOneShot == true ) { | 524 | 16 | unsigned int outLen; | 525 | 16 | const auto res = CryptOneShot<OperationType>(key, *ckm, param, out, op, &outLen); | 526 | 16 | if ( res == SECSuccess ) { | 527 | 0 | if ( GetOutSize(op) > 0 ) /* Workaround for crash */ { | 528 | 0 | ret = CreateReturnValue<ReturnType, OperationType>(op, out, outLen); | 529 | 0 | } | 530 | 0 | } | 531 | 16 | } else { | 532 | | /* Process */ | 533 | 3 | { | 534 | 3 | for (const auto& part : parts) { | 535 | 3 | if ( part.second == 0 ) { | 536 | 0 | continue; | 537 | 0 | } | 538 | | | 539 | 3 | int outLen; | 540 | 3 | CF_CHECK_EQ(PK11_CipherOp( | 541 | 3 | ctx, | 542 | 3 | out + outIdx, | 543 | 3 | &outLen, | 544 | 3 | GetOutSize(op) - outIdx, | 545 | 3 | part.first, | 546 | 3 | part.second), SECSuccess); | 547 | 0 | if ( outLen < 0 ) abort(); /* XXX ? */ | 548 | 0 | outIdx += outLen; | 549 | 0 | } | 550 | 3 | } | 551 | | | 552 | | /* Finalize */ | 553 | 0 | { | 554 | 0 | unsigned int outLen; | 555 | 0 | CF_CHECK_EQ(PK11_DigestFinal(ctx, out + outIdx, &outLen, GetOutSize(op) - outIdx), SECSuccess); | 556 | 0 | outIdx += outLen; | 557 | 0 | if ( GetOutSize(op) > 0 ) /* Workaround for crash */ { | 558 | 0 | ret = CreateReturnValue<ReturnType, OperationType>(op, out, outIdx); | 559 | 0 | } | 560 | 0 | } | 561 | 0 | } | 562 | | | 563 | 464 | end: | 564 | 464 | util::free(out); | 565 | | | 566 | 464 | if ( key != nullptr ) { | 567 | 29 | PK11_FreeSymKey(key); | 568 | 29 | } | 569 | 464 | if ( param != nullptr ) { | 570 | 28 | SECITEM_FreeItem(param, PR_TRUE); | 571 | 28 | } | 572 | 464 | if ( slot != nullptr ) { | 573 | 41 | PK11_FreeSlot(slot); | 574 | 41 | } | 575 | 464 | if ( ctx != nullptr ) { | 576 | 3 | PK11_DestroyContext(ctx, PR_TRUE); | 577 | 3 | } | 578 | 464 | return ret; | 579 | 19 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::nss_detail::Crypt<cryptofuzz::Buffer, cryptofuzz::operation::SymmetricDecrypt>(cryptofuzz::operation::SymmetricDecrypt&) Line | Count | Source | 419 | 495 | std::optional<ReturnType> Crypt(OperationType& op) { | 420 | 495 | std::optional<ReturnType> ret = std::nullopt; | 421 | 495 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); | 422 | | | 423 | 495 | uint8_t* out = util::malloc(GetOutSize(op)); | 424 | | | 425 | 495 | PK11SymKey* key = nullptr; | 426 | 495 | PK11SlotInfo* slot = nullptr; | 427 | 495 | SECItem* param = nullptr; | 428 | 495 | PK11Context* ctx = nullptr; | 429 | 495 | CK_NSS_AEAD_PARAMS* aead_params = nullptr; | 430 | 495 | CK_NSS_GCM_PARAMS* gcm_params = nullptr; | 431 | | | 432 | 495 | size_t outIdx = 0; | 433 | 495 | util::Multipart parts; | 434 | 495 | bool useOneShot = true; | 435 | | | 436 | 495 | std::vector<uint8_t> keyvec(op.cipher.key.GetPtr(), op.cipher.key.GetPtr() + op.cipher.key.GetSize()); | 437 | 495 | std::vector<uint8_t> ivvec(op.cipher.iv.GetPtr(), op.cipher.iv.GetPtr() + op.cipher.iv.GetSize()); | 438 | 495 | std::vector<uint8_t> aadvec; | 439 | 495 | if ( op.aad != std::nullopt ) { | 440 | 116 | aadvec = std::vector<uint8_t>(op.aad->GetPtr(), op.aad->GetPtr() + op.aad->GetSize()); | 441 | 116 | } | 442 | | | 443 | 495 | std::optional<CK_MECHANISM_TYPE> ckm; | 444 | | | 445 | | /* Initialize */ | 446 | 495 | { | 447 | 495 | CF_CHECK_GT(op.cipher.key.GetSize(), 0); | 448 | 440 | CF_CHECK_GT(op.cipher.iv.GetSize(), 0); | 449 | 371 | CF_CHECK_GT(GetInSize(op), 0); | 450 | | | 451 | 367 | CF_CHECK_NE(ckm = nss_detail::toCipherCKM(op.cipher.cipherType), std::nullopt); | 452 | | | 453 | 43 | CF_CHECK_NE(slot = PK11_GetInternalSlot(), nullptr); | 454 | | | 455 | 43 | CF_CHECK_GT(GetOutSize(op), 0); | 456 | | | 457 | 41 | { | 458 | 41 | SECItem keyItem; | 459 | 41 | keyItem.data = keyvec.data(); | 460 | 41 | keyItem.len = keyvec.size(); | 461 | 41 | CF_CHECK_NE(key = PK11_ImportSymKey(slot, *ckm, PK11_OriginDerive, | 462 | 41 | CKA_SIGN, &keyItem, nullptr), nullptr); | 463 | 34 | } | 464 | | | 465 | 34 | if ( op.cipher.cipherType.Get() == CF_CIPHER("AES_128_CTR") ) { | 466 | 1 | CK_AES_CTR_PARAMS* aes_ctr_params = nullptr; | 467 | 1 | CF_CHECK_EQ(op.cipher.iv.GetSize(), 16); | 468 | |
| 469 | 0 | CF_CHECK_NE(param = (SECItem *)PORT_Alloc(sizeof(SECItem)), nullptr); | 470 | 0 | CF_CHECK_NE(aes_ctr_params = (CK_AES_CTR_PARAMS*)PORT_Alloc(sizeof(CK_AES_CTR_PARAMS)), nullptr); | 471 | |
| 472 | 0 | aes_ctr_params->ulCounterBits = 128; | 473 | 0 | memcpy(aes_ctr_params->cb, op.cipher.iv.GetPtr(), 16); | 474 | |
| 475 | 0 | param->type = siBuffer; | 476 | 0 | param->data = (unsigned char *)aes_ctr_params; | 477 | 0 | param->len = sizeof(*aes_ctr_params); | 478 | 33 | } else if ( repository::IsAEAD(op.cipher.cipherType.Get()) == false ) { | 479 | 17 | SECItem ivItem = {siBuffer, ivvec.data(), (unsigned int)ivvec.size()}; | 480 | 17 | CF_CHECK_NE(param = PK11_ParamFromIV(*ckm, &ivItem), nullptr); | 481 | 17 | } else { | 482 | 16 | CF_CHECK_NE(param = (SECItem *)PORT_Alloc(sizeof(SECItem)), nullptr); | 483 | | | 484 | 16 | if ( repository::IsGCM(op.cipher.cipherType.Get()) ) { | 485 | 6 | CF_CHECK_NE(gcm_params = (CK_NSS_GCM_PARAMS*)PORT_Alloc(sizeof(CK_NSS_GCM_PARAMS)), nullptr); | 486 | | | 487 | 6 | gcm_params->pIv = ivvec.data(); | 488 | 6 | gcm_params->ulIvLen = ivvec.size(); | 489 | 6 | gcm_params->pAAD = aadvec.data(); | 490 | 6 | gcm_params->ulAADLen = aadvec.size(); | 491 | 6 | gcm_params->ulTagBits = GetTagSize(op) * 8; | 492 | | | 493 | 6 | param->type = siBuffer; | 494 | 6 | param->data = (unsigned char *)gcm_params; | 495 | 6 | param->len = sizeof(*gcm_params); | 496 | 10 | } else { | 497 | 10 | CF_CHECK_NE(aead_params = (CK_NSS_AEAD_PARAMS*)PORT_Alloc(sizeof(CK_NSS_AEAD_PARAMS)), nullptr); | 498 | 10 | aead_params->pNonce = ivvec.data(); | 499 | 10 | aead_params->ulNonceLen = ivvec.size(); | 500 | 10 | aead_params->pAAD = aadvec.data(); | 501 | 10 | aead_params->ulAADLen = aadvec.size(); | 502 | 10 | aead_params->ulTagLen = GetTagSize(op); | 503 | | | 504 | 10 | param->type = siBuffer; | 505 | 10 | param->data = (unsigned char *)aead_params; | 506 | 10 | param->len = sizeof(*aead_params); | 507 | 10 | } | 508 | 16 | } | 509 | | | 510 | 33 | if ( repository::IsAEAD(op.cipher.cipherType.Get()) == false ) { | 511 | 17 | try { | 512 | 17 | useOneShot = ds.Get<bool>(); | 513 | 17 | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 514 | 1 | } | 515 | 17 | } | 516 | | | 517 | 33 | if ( useOneShot == false ) { | 518 | 8 | CF_CHECK_NE(ctx = PK11_CreateContextBySymKey(*ckm, GetAttributeType<OperationType>(), key, param), nullptr); | 519 | 5 | parts = ToParts(ds, op); | 520 | 5 | } | 521 | 33 | } | 522 | | | 523 | 30 | if ( useOneShot == true ) { | 524 | 25 | unsigned int outLen; | 525 | 25 | const auto res = CryptOneShot<OperationType>(key, *ckm, param, out, op, &outLen); | 526 | 25 | if ( res == SECSuccess ) { | 527 | 1 | if ( GetOutSize(op) > 0 ) /* Workaround for crash */ { | 528 | 1 | ret = CreateReturnValue<ReturnType, OperationType>(op, out, outLen); | 529 | 1 | } | 530 | 1 | } | 531 | 25 | } else { | 532 | | /* Process */ | 533 | 5 | { | 534 | 7 | for (const auto& part : parts) { | 535 | 7 | if ( part.second == 0 ) { | 536 | 1 | continue; | 537 | 1 | } | 538 | | | 539 | 6 | int outLen; | 540 | 6 | CF_CHECK_EQ(PK11_CipherOp( | 541 | 6 | ctx, | 542 | 6 | out + outIdx, | 543 | 6 | &outLen, | 544 | 6 | GetOutSize(op) - outIdx, | 545 | 6 | part.first, | 546 | 6 | part.second), SECSuccess); | 547 | 1 | if ( outLen < 0 ) abort(); /* XXX ? */ | 548 | 1 | outIdx += outLen; | 549 | 1 | } | 550 | 5 | } | 551 | | | 552 | | /* Finalize */ | 553 | 0 | { | 554 | 0 | unsigned int outLen; | 555 | 0 | CF_CHECK_EQ(PK11_DigestFinal(ctx, out + outIdx, &outLen, GetOutSize(op) - outIdx), SECSuccess); | 556 | 0 | outIdx += outLen; | 557 | 0 | if ( GetOutSize(op) > 0 ) /* Workaround for crash */ { | 558 | 0 | ret = CreateReturnValue<ReturnType, OperationType>(op, out, outIdx); | 559 | 0 | } | 560 | 0 | } | 561 | 0 | } | 562 | | | 563 | 495 | end: | 564 | 495 | util::free(out); | 565 | | | 566 | 495 | if ( key != nullptr ) { | 567 | 34 | PK11_FreeSymKey(key); | 568 | 34 | } | 569 | 495 | if ( param != nullptr ) { | 570 | 33 | SECITEM_FreeItem(param, PR_TRUE); | 571 | 33 | } | 572 | 495 | if ( slot != nullptr ) { | 573 | 43 | PK11_FreeSlot(slot); | 574 | 43 | } | 575 | 495 | if ( ctx != nullptr ) { | 576 | 5 | PK11_DestroyContext(ctx, PR_TRUE); | 577 | 5 | } | 578 | 495 | return ret; | 579 | 30 | } |
|
580 | | |
581 | | } |
582 | | |
583 | 464 | std::optional<component::Ciphertext> NSS::OpSymmetricEncrypt(operation::SymmetricEncrypt& op) { |
584 | 464 | std::optional<component::Ciphertext> ret = nss_detail::Crypt<component::Ciphertext, operation::SymmetricEncrypt>(op); |
585 | 464 | if ( repository::IsCBC(op.cipher.cipherType.Get()) ) { |
586 | 65 | return std::nullopt; |
587 | 399 | } else { |
588 | 399 | return ret; |
589 | 399 | } |
590 | 464 | } |
591 | | |
592 | 495 | std::optional<component::Cleartext> NSS::OpSymmetricDecrypt(operation::SymmetricDecrypt& op) { |
593 | 495 | std::optional<component::Cleartext> ret = nss_detail::Crypt<component::Cleartext, operation::SymmetricDecrypt>(op); |
594 | 495 | if ( repository::IsCBC(op.cipher.cipherType.Get()) ) { |
595 | 61 | return std::nullopt; |
596 | 434 | } else { |
597 | 434 | return ret; |
598 | 434 | } |
599 | 495 | } |
600 | | |
601 | | namespace nss_detail { |
602 | 362 | std::optional<CK_MECHANISM_TYPE> toHKDFCKM(const component::DigestType& digestType) { |
603 | 362 | static const std::map<uint64_t, uint64_t> LUT = { |
604 | 362 | { CF_DIGEST("SHA1"), CKM_NSS_HKDF_SHA1 }, |
605 | 362 | { CF_DIGEST("SHA256"), CKM_NSS_HKDF_SHA256 }, |
606 | 362 | { CF_DIGEST("SHA384"), CKM_NSS_HKDF_SHA384 }, |
607 | 362 | { CF_DIGEST("SHA512"), CKM_NSS_HKDF_SHA512 }, |
608 | 362 | }; |
609 | | |
610 | 362 | if ( LUT.find(digestType.Get()) == LUT.end() ) { |
611 | 310 | return std::nullopt; |
612 | 310 | } |
613 | | |
614 | 52 | return LUT.at(digestType.Get()); |
615 | 362 | } |
616 | | } |
617 | | |
618 | 362 | std::optional<component::Key> NSS::OpKDF_HKDF(operation::KDF_HKDF& op) { |
619 | 362 | std::optional<component::Key> ret = std::nullopt; |
620 | 362 | std::optional<CK_MECHANISM_TYPE> ckm; |
621 | 362 | SECItem ikmItem = {siBuffer, const_cast<uint8_t *>(op.password.GetPtr()), static_cast<uint32_t>(op.password.GetSize())}; |
622 | 362 | SECItem* okmItem = nullptr; |
623 | 362 | ScopedPK11SlotInfo slot; |
624 | 362 | ScopedPK11SymKey ikm; |
625 | 362 | ScopedPK11SymKey okm; |
626 | | |
627 | | /* Initialize */ |
628 | 362 | CK_NSS_HKDFParams hkdfParams = {true, const_cast<unsigned char*>(op.salt.GetPtr()), op.salt.GetSize(), |
629 | 362 | true, const_cast<unsigned char*>(op.info.GetPtr()), op.info.GetSize()}; |
630 | 362 | SECItem kdfParams = {siBuffer, (unsigned char*)&hkdfParams, sizeof(hkdfParams)}; |
631 | | |
632 | 362 | CF_CHECK_NE(ckm = nss_detail::toHKDFCKM(op.digestType), std::nullopt); |
633 | 52 | slot = ScopedPK11SlotInfo(PK11_GetInternalSlot()); |
634 | 52 | CF_CHECK_NE(slot.get(), nullptr); |
635 | 52 | ikm = ScopedPK11SymKey(PK11_ImportSymKey(slot.get(), CKM_GENERIC_SECRET_KEY_GEN, PK11_OriginUnwrap, CKA_DERIVE, |
636 | 52 | &ikmItem, nullptr)); |
637 | 52 | CF_CHECK_NE(ikm.get(), nullptr); |
638 | | |
639 | | /* Derive */ |
640 | 52 | okm = ScopedPK11SymKey(PK11_Derive(ikm.get(), *ckm, &kdfParams, CKM_AES_KEY_GEN, CKA_DERIVE, static_cast<int32_t>(op.keySize))); |
641 | 52 | CF_CHECK_NE(okm.get(), nullptr); |
642 | 0 | CF_CHECK_EQ(PK11_ExtractKeyValue(okm.get()), SECSuccess); |
643 | 0 | CF_CHECK_NE(okmItem = PK11_GetKeyData(okm.get()), nullptr); |
644 | |
|
645 | 0 | ret = component::Key(okmItem->data, okmItem->len); |
646 | |
|
647 | 362 | end: |
648 | 362 | return ret; |
649 | 0 | } |
650 | | |
651 | | namespace nss_detail { |
652 | 228 | std::optional<SECOidTag> toHMACOID(const component::DigestType& digestType) { |
653 | 228 | static const std::map<uint64_t, SECOidTag> LUT = { |
654 | 228 | { CF_DIGEST("SHA1"), SEC_OID_HMAC_SHA1 }, |
655 | 228 | { CF_DIGEST("SHA224"), SEC_OID_HMAC_SHA224 }, |
656 | 228 | { CF_DIGEST("SHA256"), SEC_OID_HMAC_SHA256 }, |
657 | 228 | { CF_DIGEST("SHA384"), SEC_OID_HMAC_SHA384 }, |
658 | 228 | { CF_DIGEST("SHA512"), SEC_OID_HMAC_SHA512 }, |
659 | 228 | { CF_DIGEST("MD5"), SEC_OID_HMAC_MD5 }, |
660 | 228 | }; |
661 | | |
662 | 228 | if ( LUT.find(digestType.Get()) == LUT.end() ) { |
663 | 160 | return std::nullopt; |
664 | 160 | } |
665 | | |
666 | 68 | return LUT.at(digestType.Get()); |
667 | 228 | } |
668 | | } |
669 | | |
670 | 587 | std::optional<component::Key> NSS::OpKDF_PBKDF2(operation::KDF_PBKDF2& op) { |
671 | 587 | std::optional<component::Key> ret = std::nullopt; |
672 | 587 | ScopedSECAlgorithmID algId; |
673 | 587 | std::optional<SECOidTag> oid; |
674 | 587 | SECItem* keyData = nullptr; |
675 | 587 | PK11SymKey* key = nullptr; |
676 | 587 | PK11SlotInfo* slot = nullptr; |
677 | | |
678 | | /* Initialize */ |
679 | 587 | SECItem passItem = {siBuffer, const_cast<uint8_t *>(op.password.GetPtr()), static_cast<uint32_t>(op.password.GetSize())}; |
680 | 587 | SECItem saltItem = {siBuffer, const_cast<uint8_t *>(op.salt.GetPtr()), static_cast<uint32_t>(op.salt.GetSize())}; |
681 | 587 | CF_CHECK_GT(op.salt.GetSize(), 0); |
682 | 542 | CF_CHECK_GT(op.keySize, 0); |
683 | 522 | CF_CHECK_LTE(op.keySize, 256); /* Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1591363 */ |
684 | 228 | CF_CHECK_NE(oid = nss_detail::toHMACOID(op.digestType), std::nullopt); |
685 | 68 | algId = ScopedSECAlgorithmID(PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, /* unused */ SEC_OID_PKCS5_PBKDF2, *oid, op.keySize, |
686 | 68 | op.iterations, &saltItem)); |
687 | 68 | CF_CHECK_NE(algId.get(), nullptr); |
688 | | |
689 | | /* Derive */ |
690 | 62 | CF_CHECK_NE(slot = PK11_GetInternalSlot(), nullptr); |
691 | 62 | CF_CHECK_NE(key = PK11_PBEKeyGen(slot, algId.get(), &passItem, false, nullptr), nullptr); |
692 | 56 | CF_CHECK_EQ(PK11_ExtractKeyValue(key), SECSuccess); |
693 | 56 | CF_CHECK_NE(keyData = PK11_GetKeyData(key), nullptr); |
694 | | |
695 | 56 | ret = component::Key(keyData->data, keyData->len); |
696 | | |
697 | 587 | end: |
698 | 587 | if ( key != nullptr ) { |
699 | 56 | PK11_FreeSymKey(key); |
700 | 56 | } |
701 | 587 | if ( slot != nullptr ) { |
702 | 62 | PK11_FreeSlot(slot); |
703 | 62 | } |
704 | | |
705 | 587 | return ret; |
706 | 56 | } |
707 | | |
708 | | namespace nss_detail { |
709 | 793 | ECParams* ToECParams(const component::CurveType curveType) { |
710 | 793 | ECParams* ret = nullptr; |
711 | 793 | ECParams* ecparams = nullptr; |
712 | 793 | static std::vector<uint8_t> oid_secp256r1{0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}; |
713 | 793 | static std::vector<uint8_t> oid_secp384r1{0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22}; |
714 | 793 | static std::vector<uint8_t> oid_secp521r1{0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23}; |
715 | | |
716 | 793 | SECItem encodedparams; |
717 | | |
718 | 793 | if ( curveType.Is(CF_ECC_CURVE("secp256r1")) ) { |
719 | 126 | encodedparams = {siBuffer, oid_secp256r1.data(), static_cast<unsigned int>(oid_secp256r1.size())}; |
720 | 667 | } else if ( curveType.Is(CF_ECC_CURVE("secp384r1")) ) { |
721 | 196 | encodedparams = {siBuffer, oid_secp384r1.data(), static_cast<unsigned int>(oid_secp384r1.size())}; |
722 | 471 | } else if ( curveType.Is(CF_ECC_CURVE("secp521r1")) ) { |
723 | 117 | encodedparams = {siBuffer, oid_secp521r1.data(), static_cast<unsigned int>(oid_secp521r1.size())}; |
724 | 354 | } else { |
725 | 354 | goto end; |
726 | 354 | } |
727 | | |
728 | 439 | CF_CHECK_EQ(EC_DecodeParams(&encodedparams, &ecparams), SECSuccess); |
729 | | |
730 | 439 | ret = ecparams; |
731 | 793 | end: |
732 | 793 | return ret; |
733 | 439 | } |
734 | | |
735 | 272 | ECPrivateKey* ToECPrivateKey(ECParams* ecparams, const std::string priv) { |
736 | 272 | ECPrivateKey* privKey = nullptr, *ret = nullptr;; |
737 | 272 | const auto priv_bytes = util::DecToBin(priv); |
738 | 272 | CF_CHECK_NE(priv_bytes, std::nullopt); |
739 | | |
740 | 272 | CF_CHECK_EQ(EC_NewKeyFromSeed(ecparams, &privKey, priv_bytes->data(), priv_bytes->size()), SECSuccess); |
741 | | |
742 | 258 | ret = privKey; |
743 | | |
744 | 272 | end: |
745 | 272 | return ret; |
746 | 258 | } |
747 | | |
748 | 231 | bool IsValidPrivKey(const component::CurveType& curveType, const std::string privStr) { |
749 | 231 | bool ret = false; |
750 | | |
751 | 231 | const auto priv = boost::multiprecision::cpp_int(privStr); |
752 | | |
753 | 231 | CF_CHECK_NE(priv, 0); |
754 | | |
755 | | /* Check if private key is below curve order. |
756 | | * If it is not, NSS gives a different result than other libraries like Botan. |
757 | | */ |
758 | 231 | if ( curveType.Is(CF_ECC_CURVE("secp256r1")) ) { |
759 | 60 | CF_CHECK_LT(priv, boost::multiprecision::cpp_int("115792089210356248762697446949407573529996955224135760342422259061068512044369")); |
760 | 171 | } else if ( curveType.Is(CF_ECC_CURVE("secp384r1")) ) { |
761 | 113 | CF_CHECK_LT(priv, boost::multiprecision::cpp_int("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643")); |
762 | 109 | } else if ( curveType.Is(CF_ECC_CURVE("secp521r1")) ) { |
763 | 58 | CF_CHECK_LT(priv, boost::multiprecision::cpp_int("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449")); |
764 | 58 | } else { |
765 | 0 | abort(); |
766 | 0 | } |
767 | 222 | ret = true; |
768 | | |
769 | 231 | end: |
770 | 231 | return ret; |
771 | 222 | } |
772 | | |
773 | 230 | std::pair<std::string, std::string> ToPublicKey(ECPrivateKey* privKey) { |
774 | 230 | CF_ASSERT(privKey->publicValue.len != 0, "NSS: Public key is empty"); |
775 | 230 | CF_ASSERT(privKey->publicValue.data[0] == 0x04, "NSS: Public key doesn't start with 0x04"); |
776 | 230 | CF_ASSERT(((privKey->publicValue.len - 1) % 2) == 0, "NSS: Public key isn't multiple of 2"); |
777 | | |
778 | 230 | const auto halfSize = (privKey->publicValue.len - 1) / 2; |
779 | 230 | const auto X = util::BinToDec(privKey->publicValue.data + 1, halfSize); |
780 | 230 | const auto Y = util::BinToDec(privKey->publicValue.data + 1 + halfSize, halfSize); |
781 | | |
782 | 230 | return {X, Y}; |
783 | 230 | } |
784 | | } |
785 | 340 | std::optional<component::ECC_PublicKey> NSS::OpECC_PrivateToPublic(operation::ECC_PrivateToPublic& op) { |
786 | 340 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
787 | | |
788 | 340 | ECParams* ecparams = nullptr; |
789 | 340 | ECPrivateKey* privKey = nullptr; |
790 | 340 | std::pair<std::string, std::string> pubkey; |
791 | | |
792 | 340 | CF_CHECK_NE(ecparams = nss_detail::ToECParams(op.curveType), nullptr); |
793 | 149 | CF_CHECK_NE(privKey = nss_detail::ToECPrivateKey(ecparams, op.priv.ToTrimmedString()), nullptr); |
794 | 135 | pubkey = nss_detail::ToPublicKey(privKey); |
795 | 135 | CF_CHECK_TRUE(nss_detail::IsValidPrivKey(op.curveType, op.priv.ToTrimmedString())); |
796 | 127 | ret = {pubkey.first, pubkey.second}; |
797 | | |
798 | 340 | end: |
799 | 340 | if ( privKey ) { |
800 | 135 | PORT_FreeArena(privKey->ecParams.arena, PR_FALSE); |
801 | 135 | } |
802 | 340 | if (ecparams) { |
803 | 149 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
804 | 149 | } |
805 | | |
806 | 340 | return ret; |
807 | 127 | } |
808 | | |
809 | 227 | std::optional<bool> NSS::OpECDSA_Verify(operation::ECDSA_Verify& op) { |
810 | 227 | std::optional<bool> ret = std::nullopt; |
811 | 227 | SECItem sig_item, hash_item; |
812 | 227 | ECParams* ecparams = nullptr; |
813 | 227 | ECPublicKey ecpub; |
814 | 227 | ecpub.ecParams.arena = nullptr; |
815 | 227 | std::vector<uint8_t> sig; |
816 | 227 | std::vector<uint8_t> pub; |
817 | | |
818 | 227 | auto ct = op.cleartext.Get(); |
819 | | |
820 | 227 | CF_CHECK_NE(ecparams = nss_detail::ToECParams(op.curveType), nullptr); |
821 | | |
822 | | /* If ct is empty, crash will occur: |
823 | | * mp_err mp_read_unsigned_octets(mp_int *, const unsigned char *, mp_size): Assertion `mp != ((void*)0) && str != ((void*)0) && len > 0' failed. |
824 | | */ |
825 | 135 | CF_CHECK_FALSE(ct.empty()); |
826 | | |
827 | 135 | CF_CHECK_TRUE(op.digestType.Is(CF_DIGEST("NULL"))); |
828 | | |
829 | 110 | { |
830 | 110 | std::optional<std::vector<uint8_t>> sig_r, sig_s; |
831 | 110 | CF_CHECK_NE(sig_r = util::DecToBin(op.signature.signature.first.ToTrimmedString(), ecparams->order.len), std::nullopt); |
832 | 109 | CF_CHECK_NE(sig_s = util::DecToBin(op.signature.signature.second.ToTrimmedString(), ecparams->order.len), std::nullopt); |
833 | 108 | sig.insert(std::end(sig), std::begin(*sig_r), std::end(*sig_r)); |
834 | 108 | sig.insert(std::end(sig), std::begin(*sig_s), std::end(*sig_s)); |
835 | 108 | sig_item = {siBuffer, sig.data(), static_cast<unsigned int>(sig.size())}; |
836 | 108 | } |
837 | | |
838 | 0 | { |
839 | 108 | std::optional<std::vector<uint8_t>> pub_x, pub_y; |
840 | 108 | CF_CHECK_NE(pub_x = util::DecToBin(op.signature.pub.first.ToTrimmedString(), ecparams->order.len), std::nullopt); |
841 | 108 | CF_CHECK_NE(pub_y = util::DecToBin(op.signature.pub.second.ToTrimmedString(), ecparams->order.len), std::nullopt); |
842 | 108 | pub.push_back(0x04); |
843 | 108 | pub.insert(std::end(pub), std::begin(*pub_x), std::end(*pub_x)); |
844 | 108 | pub.insert(std::end(pub), std::begin(*pub_y), std::end(*pub_y)); |
845 | 108 | ecpub.ecParams.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
846 | 108 | CF_CHECK_EQ(EC_CopyParams(ecpub.ecParams.arena, &ecpub.ecParams, ecparams), SECSuccess); |
847 | 108 | ecpub.publicValue = {siBuffer, pub.data(), static_cast<unsigned int>(pub.size())}; |
848 | 108 | if ( EC_ValidatePublicKey(ecparams, &ecpub.publicValue) != SECSuccess ) { |
849 | 2 | ret = false; |
850 | 2 | goto end; |
851 | 2 | } |
852 | 108 | } |
853 | | |
854 | 106 | hash_item = {siBuffer, ct.data(), static_cast<unsigned int>(ct.size())}; |
855 | | |
856 | 106 | ret = ECDSA_VerifyDigest(&ecpub, &sig_item, &hash_item) == SECSuccess; |
857 | | |
858 | 227 | end: |
859 | 227 | if (ecparams) { |
860 | 135 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
861 | 135 | } |
862 | 227 | if (ecpub.ecParams.arena) { |
863 | 108 | PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE); |
864 | 108 | } |
865 | | |
866 | 227 | return ret; |
867 | 106 | } |
868 | | |
869 | 87 | std::optional<bool> NSS::OpECC_ValidatePubkey(operation::ECC_ValidatePubkey& op) { |
870 | 87 | std::optional<bool> ret = std::nullopt; |
871 | 87 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
872 | | |
873 | 87 | ECParams* ecparams = nullptr; |
874 | 87 | std::vector<uint8_t> pub; |
875 | 87 | SECItem publicValue; |
876 | | |
877 | 87 | CF_CHECK_NE(ecparams = nss_detail::ToECParams(op.curveType), nullptr); |
878 | | |
879 | 32 | { |
880 | 32 | std::optional<std::vector<uint8_t>> pub_x, pub_y; |
881 | 32 | CF_CHECK_NE(pub_x = util::DecToBin(op.pub.first.ToTrimmedString(), ecparams->order.len), std::nullopt); |
882 | 30 | CF_CHECK_NE(pub_y = util::DecToBin(op.pub.second.ToTrimmedString(), ecparams->order.len), std::nullopt); |
883 | 28 | pub.push_back(0x04); |
884 | 28 | pub.insert(std::end(pub), std::begin(*pub_x), std::end(*pub_x)); |
885 | 28 | pub.insert(std::end(pub), std::begin(*pub_y), std::end(*pub_y)); |
886 | 28 | publicValue = {siBuffer, pub.data(), static_cast<unsigned int>(pub.size())}; |
887 | 28 | } |
888 | | |
889 | 0 | ret = EC_ValidatePublicKey(ecparams, &publicValue) == SECSuccess; |
890 | | |
891 | 87 | end: |
892 | 87 | if (ecparams) { |
893 | 32 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
894 | 32 | } |
895 | | |
896 | 87 | return ret; |
897 | 28 | } |
898 | | |
899 | 389 | std::optional<component::ECDSA_Signature> NSS::OpECDSA_Sign(operation::ECDSA_Sign& op) { |
900 | 389 | std::optional<component::ECDSA_Signature> ret = std::nullopt; |
901 | 389 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
902 | | |
903 | 389 | SECItem sig_item, hash_item; |
904 | 389 | ECParams* ecparams = nullptr; |
905 | 389 | uint8_t* sig = nullptr; |
906 | 389 | uint8_t sigSize = 2 * MAX_ECKEY_LEN; |
907 | 389 | auto ct = op.cleartext.Get(); |
908 | 389 | ECPrivateKey* privKey = nullptr; |
909 | | |
910 | 389 | if ( op.UseRandomNonce() == false && op.UseSpecifiedNonce() == false ) { |
911 | 138 | return ret; |
912 | 138 | } |
913 | 251 | CF_CHECK_TRUE(op.digestType.Is(CF_DIGEST("NULL"))); |
914 | | |
915 | | /* If ct is empty, crash will occur: |
916 | | * mp_err mp_read_unsigned_octets(mp_int *, const unsigned char *, mp_size): Assertion `mp != ((void*)0) && str != ((void*)0) && len > 0' failed. |
917 | | */ |
918 | 147 | CF_CHECK_FALSE(ct.empty()); |
919 | | |
920 | 139 | CF_CHECK_NE(ecparams = nss_detail::ToECParams(op.curveType), nullptr); |
921 | 123 | CF_CHECK_NE(privKey = nss_detail::ToECPrivateKey(ecparams, op.priv.ToTrimmedString()), nullptr); |
922 | | |
923 | 123 | hash_item = {siBuffer, ct.data(), static_cast<unsigned int>(ct.size())}; |
924 | | |
925 | 123 | try { sigSize = ds.Get<uint8_t>(); } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
926 | 123 | sig = util::malloc(sigSize); |
927 | 123 | CF_CHECK_NE(sig, nullptr); |
928 | 123 | sig_item = {siBuffer, sig, static_cast<unsigned int>(sigSize)}; |
929 | | |
930 | 123 | if ( op.UseSpecifiedNonce() == true ) { |
931 | 43 | std::optional<std::vector<uint8_t>> nonce_bytes; |
932 | 43 | CF_CHECK_NE(nonce_bytes = util::DecToBin(op.nonce.ToTrimmedString()), std::nullopt); |
933 | 43 | CF_CHECK_EQ(ECDSA_SignDigestWithSeed(privKey, &sig_item, &hash_item, nonce_bytes->data(), nonce_bytes->size()), SECSuccess); |
934 | 80 | } else if ( op.UseRandomNonce() == true ) { |
935 | 80 | CF_CHECK_EQ(ECDSA_SignDigest(privKey, &sig_item, &hash_item), SECSuccess); |
936 | 54 | } else { |
937 | 0 | abort(); |
938 | 0 | } |
939 | | |
940 | 96 | CF_ASSERT((sig_item.len % 2) == 0, "NSS: Signature isn't multiple of 2"); |
941 | | |
942 | 96 | CF_CHECK_TRUE(nss_detail::IsValidPrivKey(op.curveType, op.priv.ToTrimmedString())); |
943 | | |
944 | 95 | { |
945 | 95 | const size_t halfSize = sig_item.len / 2; |
946 | | |
947 | 95 | const auto R = util::BinToDec(sig_item.data, halfSize); |
948 | 95 | const auto S = util::BinToDec(sig_item.data + halfSize, halfSize); |
949 | | |
950 | 95 | const auto pubkey = nss_detail::ToPublicKey(privKey); |
951 | | |
952 | 95 | ret = {{R, S}, {pubkey.first, pubkey.second} }; |
953 | 95 | } |
954 | 251 | end: |
955 | 251 | if ( privKey ) { |
956 | 123 | PORT_FreeArena(privKey->ecParams.arena, PR_FALSE); |
957 | 123 | } |
958 | 251 | if (ecparams) { |
959 | 123 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
960 | 123 | } |
961 | | |
962 | 251 | util::free(sig); |
963 | | |
964 | 251 | return ret; |
965 | 95 | } |
966 | | |
967 | 35 | std::optional<component::Key> NSS::OpKDF_TLS1_PRF(operation::KDF_TLS1_PRF& op) { |
968 | 35 | std::optional<component::Key> ret = std::nullopt; |
969 | | |
970 | 35 | if ( !op.digestType.Is(CF_DIGEST("MD5_SHA1")) ) { |
971 | 22 | return ret; |
972 | 22 | } |
973 | | |
974 | 13 | uint8_t* out = nullptr; |
975 | 13 | const SECItem secret = {siBuffer, const_cast<uint8_t *>(op.secret.GetPtr()), static_cast<uint32_t>(op.secret.GetSize())}; |
976 | 13 | SECItem seed = {siBuffer, const_cast<uint8_t *>(op.seed.GetPtr()), static_cast<uint32_t>(op.seed.GetSize())}; |
977 | 13 | CF_CHECK_NE(secret.data, nullptr); |
978 | 9 | CF_CHECK_NE(seed.data, nullptr); |
979 | | |
980 | 9 | SECItem out_item; |
981 | 9 | out = util::malloc(op.keySize); |
982 | 9 | CF_CHECK_NE(out, nullptr); |
983 | 9 | out_item = {siBuffer, out, static_cast<unsigned int>(op.keySize)}; |
984 | | |
985 | 9 | CF_CHECK_EQ(TLS_PRF(&secret, "", &seed, &out_item, false), SECSuccess); |
986 | | |
987 | 9 | ret = component::Key(out, op.keySize); |
988 | | |
989 | 13 | end: |
990 | 13 | util::free(out); |
991 | 13 | return ret; |
992 | 9 | } |
993 | | |
994 | 3.66k | std::optional<component::Bignum> NSS::OpBignumCalc(operation::BignumCalc& op) { |
995 | 3.66k | std::optional<component::Bignum> ret = std::nullopt; |
996 | 3.66k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
997 | | |
998 | 3.66k | std::vector<NSS_bignum::Bignum> bn(4); |
999 | 3.66k | NSS_bignum::Bignum res; |
1000 | 3.66k | std::unique_ptr<NSS_bignum::Operation> opRunner = nullptr; |
1001 | | |
1002 | 3.66k | CF_CHECK_EQ(res.Set("0"), true); |
1003 | 3.66k | CF_CHECK_EQ(bn[0].Set(op.bn0.ToTrimmedString()), true); |
1004 | 3.66k | CF_CHECK_EQ(bn[1].Set(op.bn1.ToTrimmedString()), true); |
1005 | 3.66k | CF_CHECK_EQ(bn[2].Set(op.bn2.ToTrimmedString()), true); |
1006 | 3.66k | CF_CHECK_EQ(bn[3].Set(op.bn3.ToTrimmedString()), true); |
1007 | | |
1008 | 3.66k | switch ( op.calcOp.Get() ) { |
1009 | 17 | case CF_CALCOP("Add(A,B)"): |
1010 | 17 | opRunner = std::make_unique<NSS_bignum::Add>(); |
1011 | 17 | break; |
1012 | 45 | case CF_CALCOP("Sub(A,B)"): |
1013 | 45 | opRunner = std::make_unique<NSS_bignum::Sub>(); |
1014 | 45 | break; |
1015 | 23 | case CF_CALCOP("Mul(A,B)"): |
1016 | 23 | opRunner = std::make_unique<NSS_bignum::Mul>(); |
1017 | 23 | break; |
1018 | 63 | case CF_CALCOP("Div(A,B)"): |
1019 | 63 | opRunner = std::make_unique<NSS_bignum::Div>(); |
1020 | 63 | break; |
1021 | 14 | case CF_CALCOP("Mod(A,B)"): |
1022 | 14 | opRunner = std::make_unique<NSS_bignum::Mod>(); |
1023 | 14 | break; |
1024 | 1.35k | case CF_CALCOP("ExpMod(A,B,C)"): |
1025 | 1.35k | opRunner = std::make_unique<NSS_bignum::ExpMod>(); |
1026 | 1.35k | break; |
1027 | 22 | case CF_CALCOP("Sqr(A)"): |
1028 | 22 | opRunner = std::make_unique<NSS_bignum::Sqr>(); |
1029 | 22 | break; |
1030 | 123 | case CF_CALCOP("GCD(A,B)"): |
1031 | 123 | opRunner = std::make_unique<NSS_bignum::GCD>(); |
1032 | 123 | break; |
1033 | 67 | case CF_CALCOP("ExtGCD_X(A,B)"): |
1034 | 67 | opRunner = std::make_unique<NSS_bignum::ExtGCD_X>(); |
1035 | 67 | break; |
1036 | 38 | case CF_CALCOP("ExtGCD_Y(A,B)"): |
1037 | 38 | opRunner = std::make_unique<NSS_bignum::ExtGCD_Y>(); |
1038 | 38 | break; |
1039 | 17 | case CF_CALCOP("AddMod(A,B,C)"): |
1040 | 17 | opRunner = std::make_unique<NSS_bignum::AddMod>(); |
1041 | 17 | break; |
1042 | 19 | case CF_CALCOP("SubMod(A,B,C)"): |
1043 | 19 | opRunner = std::make_unique<NSS_bignum::SubMod>(); |
1044 | 19 | break; |
1045 | 18 | case CF_CALCOP("MulMod(A,B,C)"): |
1046 | 18 | opRunner = std::make_unique<NSS_bignum::MulMod>(); |
1047 | 18 | break; |
1048 | 12 | case CF_CALCOP("SqrMod(A,B)"): |
1049 | 12 | opRunner = std::make_unique<NSS_bignum::SqrMod>(); |
1050 | 12 | break; |
1051 | 352 | case CF_CALCOP("InvMod(A,B)"): |
1052 | 352 | opRunner = std::make_unique<NSS_bignum::InvMod>(); |
1053 | 352 | break; |
1054 | 12 | case CF_CALCOP("Cmp(A,B)"): |
1055 | 12 | opRunner = std::make_unique<NSS_bignum::Cmp>(); |
1056 | 12 | break; |
1057 | 89 | case CF_CALCOP("LCM(A,B)"): |
1058 | 89 | opRunner = std::make_unique<NSS_bignum::LCM>(); |
1059 | 89 | break; |
1060 | 11 | case CF_CALCOP("Abs(A)"): |
1061 | 11 | opRunner = std::make_unique<NSS_bignum::Abs>(); |
1062 | 11 | break; |
1063 | 15 | case CF_CALCOP("Neg(A)"): |
1064 | 15 | opRunner = std::make_unique<NSS_bignum::Neg>(); |
1065 | 15 | break; |
1066 | 1 | case CF_CALCOP("IsEven(A)"): |
1067 | 1 | opRunner = std::make_unique<NSS_bignum::IsEven>(); |
1068 | 1 | break; |
1069 | 1 | case CF_CALCOP("IsOdd(A)"): |
1070 | 1 | opRunner = std::make_unique<NSS_bignum::IsOdd>(); |
1071 | 1 | break; |
1072 | 1 | case CF_CALCOP("Exp(A,B)"): |
1073 | 1 | opRunner = std::make_unique<NSS_bignum::Exp>(); |
1074 | 1 | break; |
1075 | | #if 0 |
1076 | | case CF_CALCOP("Mod_NIST_256(A)"): |
1077 | | opRunner = std::make_unique<NSS_bignum::Mod_NIST_256>(); |
1078 | | break; |
1079 | | case CF_CALCOP("Mod_NIST_384(A)"): |
1080 | | opRunner = std::make_unique<NSS_bignum::Mod_NIST_384>(); |
1081 | | break; |
1082 | | case CF_CALCOP("Mod_NIST_521(A)"): |
1083 | | opRunner = std::make_unique<NSS_bignum::Mod_NIST_521>(); |
1084 | | break; |
1085 | | #endif |
1086 | 3.66k | } |
1087 | | |
1088 | 3.66k | CF_CHECK_NE(opRunner, nullptr); |
1089 | 2.31k | CF_CHECK_EQ(opRunner->Run(ds, res, bn), true); |
1090 | | |
1091 | 2.15k | ret = res.ToComponentBignum(); |
1092 | | |
1093 | 3.66k | end: |
1094 | 3.66k | return ret; |
1095 | 2.15k | } |
1096 | | |
1097 | | } /* namespace module */ |
1098 | | } /* namespace cryptofuzz */ |