Coverage Report

Created: 2024-11-21 07:03

/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 */