Skip to content

Commit db2faeb

Browse files
author
Chandra Pratap
committed
fuzz-tests: Add differential test for HMAC-SHA256
Changelog-Added: Add a differential fuzz test for HMAC-SHA256, similar to those for SHA256 and RIPEMD160, to verify CCAN’s implementation against OpenSSL’s.
1 parent 63e15c1 commit db2faeb

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ ifeq ($(STATIC),1)
283283
# But that doesn't static link.
284284
LDLIBS = -L$(CPATH) -Wl,-dn $(SQLITE3_LDLIBS) -Wl,-dy -lm -lpthread -ldl $(COVFLAGS)
285285
else
286-
LDLIBS = -L$(CPATH) -lm $(SQLITE3_LDLIBS) $(COVFLAGS)
286+
LDLIBS = -L$(CPATH) -lm $(SQLITE3_LDLIBS) -lcrypto $(COVFLAGS)
287287
endif
288288

289289
# If we have the postgres client library we need to link against it as well

tests/fuzz/fuzz-hmac-sha256.c

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* This is a differential fuzz test comparing CCAN's HMAC‑SHA256 implementation
2+
* against OpenSSL's HMAC.
3+
*/
4+
#include "config.h"
5+
#include <assert.h>
6+
#include <ccan/crypto/hmac_sha256/hmac_sha256.h>
7+
#include <ccan/mem/mem.h>
8+
#include <openssl/hmac.h>
9+
#include <openssl/evp.h>
10+
#include <openssl/sha.h>
11+
#include <tests/fuzz/libfuzz.h>
12+
13+
/* Fixed key for testing purposes */
14+
static const unsigned char hmac_key[] = "fuzz";
15+
static const size_t hmac_key_len = sizeof(hmac_key) - 1;
16+
17+
static EVP_MAC *hmac_sha256_algo;
18+
19+
void init(int *argc, char ***argv)
20+
{
21+
hmac_sha256_algo = EVP_MAC_fetch(NULL, "HMAC", NULL);
22+
assert(hmac_sha256_algo);
23+
}
24+
25+
/* Test that splitting the data and updating via multiple calls yields the same
26+
* result as processing the data in a single pass.
27+
*/
28+
static void test_split_update(int num_splits, const struct hmac_sha256 *expected,
29+
const u8 *data, size_t size)
30+
{
31+
const size_t split_size = size / (num_splits + 1);
32+
struct hmac_sha256_ctx ctx;
33+
struct hmac_sha256 actual;
34+
35+
hmac_sha256_init(&ctx, hmac_key, hmac_key_len);
36+
for (int i = 0; i < num_splits; ++i) {
37+
hmac_sha256_update(&ctx, data, split_size);
38+
data += split_size;
39+
size -= split_size;
40+
}
41+
hmac_sha256_update(&ctx, data, size); /* Process remaining data. */
42+
hmac_sha256_done(&ctx, &actual);
43+
assert(memeq(expected, sizeof(*expected), &actual, sizeof(actual)));
44+
}
45+
46+
/* Test that the HMAC calculated by CCAN matches OpenSSL's HMAC. */
47+
static void test_vs_openssl(const struct hmac_sha256 *expected, const u8 *data, size_t size)
48+
{
49+
u8 openssl_hash[SHA256_DIGEST_LENGTH];
50+
size_t hash_size;
51+
EVP_MAC_CTX *ctx;
52+
OSSL_PARAM params[] = {
53+
OSSL_PARAM_construct_utf8_string("digest", "SHA256", 0),
54+
OSSL_PARAM_END
55+
};
56+
57+
ctx = EVP_MAC_CTX_new(hmac_sha256_algo);
58+
assert(ctx);
59+
60+
assert(EVP_MAC_init(ctx, hmac_key, hmac_key_len, params));
61+
assert(EVP_MAC_update(ctx, data, size));
62+
assert(EVP_MAC_final(ctx, openssl_hash, &hash_size, sizeof(openssl_hash)));
63+
EVP_MAC_CTX_free(ctx);
64+
65+
assert(hash_size == SHA256_DIGEST_LENGTH);
66+
assert(memeq(expected, sizeof(*expected), openssl_hash, sizeof(openssl_hash)));
67+
}
68+
69+
void run(const u8 *data, size_t size)
70+
{
71+
struct hmac_sha256 expected;
72+
u8 num_splits;
73+
74+
if (size < 1)
75+
return;
76+
77+
num_splits = *data;
78+
++data;
79+
--size;
80+
81+
/* Compute expected HMAC using the one-shot function. */
82+
hmac_sha256(&expected, hmac_key, hmac_key_len, data, size);
83+
84+
test_split_update(num_splits, &expected, data, size);
85+
test_vs_openssl(&expected, data, size);
86+
}
87+

0 commit comments

Comments
 (0)