Skip to content

Commit d7a08a5

Browse files
author
Chandra Pratap
committed
fuzz-tests: Add differential test for HMAC-SHA256
Changelog-None: 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 d7a08a5

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

tests/fuzz/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LIBFUZZ_OBJS := $(LIBFUZZ_SRC:.c=.o)
55
tests/fuzz/fuzz-connectd-handshake-act*.o: tests/fuzz/connectd_handshake.h
66
tests/fuzz/fuzz-ripemd160: LDLIBS += -lcrypto
77
tests/fuzz/fuzz-sha256: LDLIBS += -lcrypto
8+
tests/fuzz/fuzz-hmac-sha256: LDLIBS += -lcrypto
89
tests/fuzz/fuzz-wire-*.o: tests/fuzz/wire.h
910
tests/fuzz/fuzz-bolt12-*.o: tests/fuzz/bolt12.h
1011

tests/fuzz/fuzz-hmac-sha256.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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+
static unsigned char *hmac_key;
14+
static size_t hmac_key_len;
15+
16+
static EVP_MAC *hmac_sha256_algo;
17+
18+
void init(int *argc, char ***argv)
19+
{
20+
hmac_sha256_algo = EVP_MAC_fetch(NULL, "HMAC", NULL);
21+
assert(hmac_sha256_algo);
22+
}
23+
24+
/* Test that splitting the data and updating via multiple calls yields the same
25+
* result as processing the data in a single pass.
26+
*/
27+
static void test_split_update(int num_splits, const struct hmac_sha256 *expected,
28+
const u8 *data, size_t size)
29+
{
30+
const size_t split_size = size / (num_splits + 1);
31+
struct hmac_sha256_ctx ctx;
32+
struct hmac_sha256 actual;
33+
34+
hmac_sha256_init(&ctx, hmac_key, hmac_key_len);
35+
for (int i = 0; i < num_splits; ++i) {
36+
hmac_sha256_update(&ctx, data, split_size);
37+
data += split_size;
38+
size -= split_size;
39+
}
40+
hmac_sha256_update(&ctx, data, size); /* Process remaining data. */
41+
hmac_sha256_done(&ctx, &actual);
42+
assert(memeq(expected, sizeof(*expected), &actual, sizeof(actual)));
43+
}
44+
45+
/* Test that the HMAC calculated by CCAN matches OpenSSL's HMAC. */
46+
static void test_vs_openssl(const struct hmac_sha256 *expected, const u8 *data, size_t size)
47+
{
48+
u8 openssl_hash[SHA256_DIGEST_LENGTH];
49+
size_t hash_size;
50+
EVP_MAC_CTX *ctx;
51+
OSSL_PARAM params[] = {
52+
OSSL_PARAM_construct_utf8_string("digest", "SHA256", 0),
53+
OSSL_PARAM_END
54+
};
55+
56+
ctx = EVP_MAC_CTX_new(hmac_sha256_algo);
57+
assert(ctx);
58+
59+
assert(EVP_MAC_init(ctx, hmac_key, hmac_key_len, params));
60+
assert(EVP_MAC_update(ctx, data, size));
61+
assert(EVP_MAC_final(ctx, openssl_hash, &hash_size, sizeof(openssl_hash)));
62+
EVP_MAC_CTX_free(ctx);
63+
64+
assert(hash_size == SHA256_DIGEST_LENGTH);
65+
assert(memeq(expected, sizeof(*expected), openssl_hash, sizeof(openssl_hash)));
66+
}
67+
68+
void run(const u8 *data, size_t size)
69+
{
70+
struct hmac_sha256 expected;
71+
u8 num_splits;
72+
73+
if (size < 1)
74+
return;
75+
hmac_key_len = (size_t) data[0];
76+
++data; --size;
77+
78+
if (size < hmac_key_len)
79+
return;
80+
hmac_key = (unsigned char*) data;
81+
data += hmac_key_len; size -= hmac_key_len;
82+
83+
if (size < 1)
84+
return;
85+
num_splits = *data;
86+
++data; --size;
87+
88+
/* Compute expected HMAC using the one-shot function. */
89+
hmac_sha256(&expected, hmac_key, hmac_key_len, data, size);
90+
test_split_update(num_splits, &expected, data, size);
91+
test_vs_openssl(&expected, data, size);
92+
}
93+

0 commit comments

Comments
 (0)