Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fuzz: add fuzzer to test internal gcrypt code #1920

Merged
merged 1 commit into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
/fuzz/fuzz_ds_ahocorasick
/fuzz/fuzz_libinjection
/fuzz/fuzz_tls_certificate
/fuzz/fuzz_gcrypt_light
/fuzz/fuzz_ndpi_reader_alloc_fail_seed_corpus.zip
/fuzz/fuzz_ndpi_reader_seed_corpus.zip
/fuzz/fuzz_quic_get_crypto_data_seed_corpus.zip
Expand Down
17 changes: 17 additions & 0 deletions fuzz/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ bin_PROGRAMS += fuzz_alg_bins fuzz_alg_hll fuzz_alg_hw_rsi_outliers_da fuzz_alg_
bin_PROGRAMS += fuzz_ds_patricia fuzz_ds_ahocorasick fuzz_ds_libcache fuzz_ds_tree fuzz_ds_ptree
#Third party
bin_PROGRAMS += fuzz_libinjection
#Internal crypto
bin_PROGRAMS += fuzz_gcrypt_light

fuzz_process_packet_SOURCES = fuzz_process_packet.c fuzz_common_code.c
fuzz_process_packet_CFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS)
Expand Down Expand Up @@ -305,6 +307,21 @@ fuzz_tls_certificate_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \
$(fuzz_tls_certificate_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@

fuzz_gcrypt_light_SOURCES = fuzz_gcrypt_light.cpp fuzz_common_code.c
fuzz_gcrypt_light_CXXFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS) -I ../src/lib/third_party/include/
fuzz_gcrypt_light_CFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS) -I ../src/lib/third_party/include/
fuzz_gcrypt_light_LDADD = ../src/lib/libndpi.a $(ADDITIONAL_LIBS)
fuzz_gcrypt_light_LDFLAGS = $(LIBS)
if HAS_FUZZLDFLAGS
fuzz_gcrypt_light_CXXFLAGS += $(LIB_FUZZING_ENGINE)
fuzz_gcrypt_light_CFLAGS += $(LIB_FUZZING_ENGINE)
fuzz_gcrypt_light_LDFLAGS += $(LIB_FUZZING_ENGINE)
endif
# force usage of CXX for linker
fuzz_gcrypt_light_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \
$(fuzz_gcrypt_light_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@

# required for Google oss-fuzz
# see https://github.com/google/oss-fuzz/tree/master/projects/ndpi
testpcaps := $(wildcard ../tests/pcap/*.pcap*)
Expand Down
124 changes: 124 additions & 0 deletions fuzz/fuzz_gcrypt_light.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include "fuzz_common_code.h"

#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include "fuzzer/FuzzedDataProvider.h"

#ifdef HAVE_LIBGCRYPT
#include "gcrypt.h"
#define HMAC_SHA256_DIGEST_SIZE 32
#else
#include "../src/lib/third_party/include/gcrypt_light.h"
#endif

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fuzzed_data(data, size);
gcry_md_hd_t hh;
gcry_cipher_hd_t h;
gcry_error_t rc;
int algo = 0, flags = 0, mode = 0; /* Invalid values */
int key_len, iv_len, auth_len;
u_int8_t out[HMAC_SHA256_DIGEST_SIZE];
char buf_err[16];
void *enc_out;

/* To allow memory allocation failures */
fuzz_set_alloc_callbacks_and_seed(size);

/* MD */

if(fuzzed_data.ConsumeBool())
algo = GCRY_MD_SHA256;
if(fuzzed_data.ConsumeBool())
flags = GCRY_MD_FLAG_HMAC;
key_len = fuzzed_data.ConsumeIntegralInRange(0, 65); /* Max valid key length is 64 */
std::vector<u_int8_t>key = fuzzed_data.ConsumeBytes<u_int8_t>(key_len);
std::vector<u_int8_t>src = fuzzed_data.ConsumeBytes<uint8_t>(300);

gcry_md_get_algo_dlen(algo);
rc = gcry_md_open(&hh, algo, flags);
if (rc == 0) {
gcry_md_reset(hh);
rc = gcry_md_setkey(hh, key.data(), key.size());
if (rc == 0) {
if(fuzzed_data.ConsumeBool()) { /* To trigger MBEDTLS_ERR_MD_REKEY */
rc = gcry_md_setkey(hh, key.data(), key.size());
} else {
rc = gcry_md_write(hh, src.data(), src.size());
if (rc == 0) {
memcpy(out, gcry_md_read(hh, 0), gcry_md_get_algo_dlen(algo));
gcry_md_get_algo(hh);
}
}
}
gcry_md_close(hh);
}
gpg_strerror_r(rc, buf_err, sizeof(buf_err));


/* Encryption */

/* ECB */

if(fuzzed_data.ConsumeBool())
algo = GCRY_CIPHER_AES128;
if(fuzzed_data.ConsumeBool())
flags = 1; /* Invalid value */
if(fuzzed_data.ConsumeBool())
mode = GCRY_CIPHER_MODE_ECB;
key_len = fuzzed_data.ConsumeIntegralInRange(16, 17); /* Only 16 is a valid key length */
std::vector<u_int8_t>key2 = fuzzed_data.ConsumeBytes<u_int8_t>(key_len);
enc_out = ndpi_malloc(src.size());
if (!enc_out)
return 0;

rc = gcry_cipher_open(&h, algo, mode, flags);
if (rc == 0) {
rc = gcry_cipher_setkey(h, key2.data(), key2.size());
if (rc == 0) {
if(fuzzed_data.ConsumeBool()) { /* To trigger MBEDTLS_ERR_CIPHER_BAD_KEY */
rc = gcry_cipher_setkey(h, key2.data(), key2.size());
} else {
rc = gcry_cipher_encrypt(h, enc_out, src.size(), src.data(), src.size());
}
}
gcry_cipher_ctl(h, 0, NULL, 0);
gcry_cipher_close(h);
}
gpg_strerror_r(rc, buf_err, sizeof(buf_err));

/* GCM */

if(fuzzed_data.ConsumeBool())
mode = GCRY_CIPHER_MODE_GCM;
iv_len = fuzzed_data.ConsumeIntegralInRange(12, 12); /* Only 12 is a valid key length */
std::vector<u_int8_t>iv = fuzzed_data.ConsumeBytes<u_int8_t>(iv_len);
auth_len = fuzzed_data.ConsumeIntegralInRange(0, 257); /* 257 is an invalid value */
std::vector<u_int8_t>auth = fuzzed_data.ConsumeBytes<u_int8_t>(auth_len);

rc = gcry_cipher_open(&h, algo, mode, flags);
if (rc == 0) {
rc = gcry_cipher_setkey(h, key2.data(), key2.size());
if (rc == 0) {
gcry_cipher_reset(h);
rc = gcry_cipher_setiv(h, iv.data(), iv.size());
if (rc == 0) {
if(fuzzed_data.ConsumeBool()) { /* To trigger MBEDTLS_ERR_CIPHER_BAD_KEY */
rc = gcry_cipher_setiv(h, iv.data(), iv.size());
} else {
rc = gcry_cipher_authenticate(h, auth.data(), auth.size());
if (rc == 0) {
rc = gcry_cipher_decrypt(h, enc_out, src.size(), src.data(), src.size());
}
}
}
}
gcry_cipher_close(h);
}
gpg_strerror_r(rc, buf_err, sizeof(buf_err));

ndpi_free(enc_out);

return 0;
}
8 changes: 8 additions & 0 deletions src/lib/third_party/include/gcrypt_light.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

#ifdef __cplusplus
extern "C" {
#endif

#ifndef GCRY_LIGHT_H
#define GCRY_LIGHT_H

Expand Down Expand Up @@ -84,4 +88,8 @@ size_t gcry_cipher_get_algo_keylen (int algo);

#endif /* GCRY_LIGHT_H */

#ifdef __cplusplus
}
#endif

/* vim: set ts=4 sw=4 et foldmethod=marker foldmarker={{{{,}}}}: */
27 changes: 15 additions & 12 deletions src/lib/third_party/src/gcrypt_light.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const char *gcry_check_version(void *unused) {
gcry_error_t gcry_md_open(gcry_md_hd_t *h,int algo,int flags) {
gcry_md_hd_t ctx;
if(!(algo == GCRY_MD_SHA256 && flags == GCRY_MD_FLAG_HMAC)) return MBEDTLS_ERR_MD_NOT_SUPPORT;
ctx = ndpi_calloc(1,sizeof(struct gcry_md_hd));
ctx = (gcry_md_hd_t)ndpi_calloc(1,sizeof(struct gcry_md_hd));
if(!ctx) return MBEDTLS_ERR_MD_ALLOC_FAILED;
*h = ctx;
return GPG_ERR_NO_ERROR;
Expand All @@ -133,13 +133,15 @@ void gcry_md_reset(gcry_md_hd_t h) {
gcry_error_t gcry_md_setkey(gcry_md_hd_t h,const uint8_t *key,size_t key_len) {
if(h->key_len) return MBEDTLS_ERR_MD_REKEY;
h->key_len = key_len <= sizeof(h->key) ? key_len : sizeof(h->key);
memcpy(h->key,key,h->key_len);
if(h->key_len > 0)
memcpy(h->key,key,h->key_len);
return GPG_ERR_NO_ERROR;
}

gcry_error_t gcry_md_write(gcry_md_hd_t h,const uint8_t *data,size_t data_len) {
if(h->data_len + data_len > GCRY_MD_BUFF_SIZE) return MBEDTLS_ERR_MD_DATA_TOO_BIG;
memcpy(&h->data_buf[h->data_len],data,data_len);
if(data_len > 0)
memcpy(&h->data_buf[h->data_len],data,data_len);
h->data_len += data_len;
return GPG_ERR_NO_ERROR;
}
Expand Down Expand Up @@ -178,7 +180,7 @@ size_t s_len = ROUND_SIZE8(sizeof(struct gcry_cipher_hd));;

switch(mode) {
case GCRY_CIPHER_MODE_ECB:
r = ndpi_calloc(1,s_len + sizeof(mbedtls_aes_context));
r = (struct gcry_cipher_hd *)ndpi_calloc(1,s_len + sizeof(mbedtls_aes_context));
if(!r) return MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
r->ctx.ecb = (mbedtls_aes_context *)(r+1);
mbedtls_aes_init(r->ctx.ecb);
Expand All @@ -188,7 +190,7 @@ size_t s_len = ROUND_SIZE8(sizeof(struct gcry_cipher_hd));;
size_t aes_ctx_size = ROUND_SIZE8(sizeof( mbedtls_aes_context ));
size_t gcm_ctx_size = ROUND_SIZE8(sizeof( mbedtls_gcm_context ));

r = ndpi_calloc(1,s_len + gcm_ctx_size + aes_ctx_size);
r = (struct gcry_cipher_hd *)ndpi_calloc(1,s_len + gcm_ctx_size + aes_ctx_size);
if(!r) return MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
r->ctx.gcm = (mbedtls_gcm_context *)(r+1);
mbedtls_gcm_init(r->ctx.gcm,(void *)(((char *)(r+1)) + gcm_ctx_size));
Expand Down Expand Up @@ -250,10 +252,10 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t h, const void *key, size_t key
if( keylen != gcry_cipher_get_algo_keylen(h->algo)) return MBEDTLS_ERR_CIPHER_BAD_KEY;
switch(h->mode) {
case GCRY_CIPHER_MODE_ECB:
r = mbedtls_aes_setkey_enc( h->ctx.ecb, key, keylen*8 );
r = mbedtls_aes_setkey_enc( h->ctx.ecb, (const unsigned char *)key, keylen*8 );
break;
case GCRY_CIPHER_MODE_GCM:
r = mbedtls_gcm_setkey( h->ctx.gcm, MBEDTLS_CIPHER_ID_AES, key, keylen*8 );
r = mbedtls_gcm_setkey( h->ctx.gcm, MBEDTLS_CIPHER_ID_AES, (const unsigned char *)key, keylen*8 );
break;
}
if(!r) {
Expand Down Expand Up @@ -285,7 +287,8 @@ gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t h, const void *abuf, siz
if(abuflen > sizeof(h->auth)) return MBEDTLS_ERR_CIPHER_BAD_KEY;
h->s_auth = 1;
h->authlen = abuflen;
memcpy(h->auth,abuf,abuflen);
if(abuflen > 0)
memcpy(h->auth,abuf,abuflen);
return 0;
}
return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
Expand All @@ -298,7 +301,7 @@ gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t h, const void *intag, size_t
if(h->s_crypt_ok && h->taglen == taglen) {
size_t i;
int diff;
const uint8_t *ctag = intag;
const uint8_t *ctag = (const uint8_t *)intag;
for( diff = 0, i = 0; i < taglen; i++ )
diff |= ctag[i] ^ h->tag[i];
if(!diff) return 0;
Expand Down Expand Up @@ -326,7 +329,7 @@ static gcry_error_t _gcry_cipher_crypt (gcry_cipher_hd_t h,
if(check_valid_algo_mode(h)) return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
if(!inlen && !outsize) return MBEDTLS_ERR_GCM_BAD_INPUT;
if(!in && !inlen) {
src = ndpi_malloc(outsize);
src = (uint8_t *)ndpi_malloc(outsize);
if(!src) return MBEDTLS_ERR_GCM_ALLOC_FAILED;
srclen = outsize;
memcpy(src,out,outsize);
Expand All @@ -338,7 +341,7 @@ static gcry_error_t _gcry_cipher_crypt (gcry_cipher_hd_t h,
if(!encrypt) return MBEDTLS_ERR_GCM_NOT_SUPPORT;
if(!( h->s_key && !h->s_crypt_ok)) return MBEDTLS_ERR_AES_MISSING_KEY;
rv = mbedtls_aes_crypt_ecb(h->ctx.ecb, MBEDTLS_AES_ENCRYPT,
src ? src:in, out);
src ? src:(const unsigned char *)in, (unsigned char *)out);
break;
case GCRY_CIPHER_MODE_GCM:
if(encrypt) return MBEDTLS_ERR_GCM_NOT_SUPPORT;
Expand All @@ -349,7 +352,7 @@ static gcry_error_t _gcry_cipher_crypt (gcry_cipher_hd_t h,
src ? srclen:outsize,
h->iv,h->ivlen,
h->auth,h->authlen,
src ? src:in,out,
src ? src:(const unsigned char *)in, (unsigned char *)out,
h->taglen, h->tag);
break;
}
Expand Down