added fuzzing with libFuzzer and OSS-Fuzz

makes cmocka detection not required for building tests
This commit is contained in:
Frank Morgner 2019-06-03 07:56:56 +02:00
parent 7159400086
commit 755ac78a02
11 changed files with 480 additions and 26 deletions

View File

@ -129,9 +129,16 @@ case "${host}" in
;;
esac
AX_CHECK_COMPILE_FLAG(-Wunknown-warning-option, [have_unknown_warning_option="yes"], [have_unknown_warning_option="no"], [-Werror])
AX_CHECK_COMPILE_FLAG([-Wunknown-warning-option], [have_unknown_warning_option="yes"], [have_unknown_warning_option="no"], [-Werror])
AM_CONDITIONAL([HAVE_UNKNOWN_WARNING_OPTION], [test "${have_unknown_warning_option}" = "yes"])
AC_ARG_ENABLE(
[fuzzing],
[AS_HELP_STRING([--enable-fuzzing],[enable compile of fuzzing tests @<:@disabled@:>@, note that CFLAGS should be set accoringly, e.g. to something like "-fsanitize=address,fuzzer"])],
,
[enable_fuzzing="no"]
)
AC_ARG_ENABLE(
[strict],
[AS_HELP_STRING([--disable-strict],[disable strict compile mode @<:@enabled@:>@])],
@ -266,10 +273,10 @@ AC_ARG_ENABLE(
)
AC_ARG_ENABLE(
[tests],
[AS_HELP_STRING([--enable-tests],[Build tests in src/tests/ directory @<:@detect@:>@])],
[cmocka],
[AS_HELP_STRING([--enable-cmocka],[Build tests in src/tests/p11test directory @<:@detect@:>@])],
,
[enable_tests="detect"]
[enable_cmocka="detect"]
)
AC_ARG_WITH(
@ -664,21 +671,18 @@ else
OPENSSL_LIBS=""
fi
if test "${enable_tests}" = "detect"; then
if test "${enable_cmocka}" = "detect"; then
if test "${have_cmocka}" = "yes" -a "${have_openssl}" = "yes"; then
enable_tests="yes"
enable_cmocka="yes"
else
enable_tests="no"
enable_cmocka="no"
fi
fi
if test "${enable_tests}" = "yes"; then
if test "${enable_cmocka}" = "yes"; then
if test "${have_cmocka}" != "yes"; then
AC_MSG_ERROR([Tests required, but cmocka is not available])
fi
if test "${have_openssl}" != "yes"; then
AC_MSG_ERROR([Tests required, but openssl is not available])
fi
fi
@ -1054,9 +1058,9 @@ AM_CONDITIONAL([ENABLE_SM], [test "${enable_sm}" = "yes"])
AM_CONDITIONAL([ENABLE_DNIE_UI], [test "${enable_dnie_ui}" = "yes"])
AM_CONDITIONAL([ENABLE_NPATOOL], [test "${ENABLE_NPATOOL}" = "yes"])
AM_CONDITIONAL([ENABLE_AUTOSTART], [test "${enable_autostart}" = "yes"])
AM_CONDITIONAL([ENABLE_TESTS], [test "${enable_tests}" = "yes"])
AM_CONDITIONAL([ENABLE_CMOCKA], [test "${enable_cmocka}" = "yes"])
AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"])
AM_CONDITIONAL([ENABLE_FUZZING], [test "${enable_fuzzing}" = "yes"])
AM_CONDITIONAL([ENABLE_SHARED], [test "${enable_shared}" = "yes"])
AS_IF([test "${enable_shared}" = "yes"], [AC_DEFINE([ENABLE_SHARED], [1], [Enable shared libraries])])
@ -1089,6 +1093,7 @@ AC_CONFIG_FILES([
src/tests/Makefile
src/tests/regression/Makefile
src/tests/p11test/Makefile
src/tests/fuzzing/Makefile
src/tools/Makefile
src/tools/versioninfo-tools.rc
src/tools/versioninfo-opensc-notify.rc
@ -1149,7 +1154,6 @@ SM default module: ${DEFAULT_SM_MODULE}
SM default path: $(eval eval eval echo "${DEFAULT_SM_MODULE_PATH}")
DNIe UI support: ${enable_dnie_ui}
Notification support: ${enable_notify}
Build tests: ${enable_tests}
PC/SC default provider: ${DEFAULT_PCSC_PROVIDER}
PKCS11 default provider: $(eval eval eval echo "${DEFAULT_PKCS11_PROVIDER}")

View File

@ -3,12 +3,8 @@ EXTRA_DIST = Makefile.mak
# Order IS important
SUBDIRS = common scconf ui pkcs15init sm \
libopensc pkcs11 tools minidriver
libopensc pkcs11 tools minidriver tests
if ENABLE_SM
SUBDIRS += smm
endif
if ENABLE_TESTS
SUBDIRS += tests
endif

View File

@ -150,6 +150,8 @@ sc_pkcs15_cache_file
sc_pkcs15_card_clear
sc_pkcs15_card_free
sc_pkcs15_card_new
sc_pkcs15_tokeninfo_new
sc_pkcs15_free_tokeninfo
sc_pkcs15_change_pin
sc_pkcs15_compare_id
sc_pkcs15_compute_signature

View File

@ -1305,12 +1305,13 @@ __sc_pkcs15_search_objects(struct sc_pkcs15_card *p15card, unsigned int class_ma
/* Make sure the class mask we have makes sense */
if (class_mask == 0
|| (class_mask & ~(SC_PKCS15_SEARCH_CLASS_PRKEY |
SC_PKCS15_SEARCH_CLASS_PUBKEY |
SC_PKCS15_SEARCH_CLASS_SKEY |
SC_PKCS15_SEARCH_CLASS_CERT |
SC_PKCS15_SEARCH_CLASS_DATA |
SC_PKCS15_SEARCH_CLASS_AUTH))) {
|| (class_mask & ~(
SC_PKCS15_SEARCH_CLASS_PRKEY |
SC_PKCS15_SEARCH_CLASS_PUBKEY |
SC_PKCS15_SEARCH_CLASS_SKEY |
SC_PKCS15_SEARCH_CLASS_CERT |
SC_PKCS15_SEARCH_CLASS_DATA |
SC_PKCS15_SEARCH_CLASS_AUTH))) {
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}

View File

@ -3,7 +3,7 @@ include $(top_srcdir)/win32/ltrc.inc
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
EXTRA_DIST = Makefile.mak
SUBDIRS = regression p11test
SUBDIRS = regression p11test fuzzing
noinst_PROGRAMS = base64 lottery p15dump pintest prngtest
AM_CPPFLAGS = -I$(top_srcdir)/src

View File

@ -0,0 +1,15 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
AM_CFLAGS = -g -O0 $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_READLINE_CFLAGS) $(PTHREAD_CFLAGS)
LIBS = \
$(top_builddir)/src/libopensc/libopensc.la \
$(top_builddir)/src/common/libscdl.la \
$(top_builddir)/src/common/libcompat.la
if ENABLE_FUZZING
noinst_PROGRAMS = fuzz_asn1_print fuzz_asn1_sig_value fuzz_pkcs15_decode fuzz_pkcs15_reader
endif
fuzz_asn1_print_SOURCES = fuzz_asn1_print.c
fuzz_asn1_sig_value_SOURCES = fuzz_asn1_sig_value.c
fuzz_pkcs15_decode_SOURCES = fuzz_pkcs15_decode.c
fuzz_pkcs15_reader_SOURCES = fuzz_pkcs15_reader.c

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2019 Frank Morgner <frankmorgner@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "libopensc/asn1.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
fclose(stdout);
sc_asn1_print_tags(Data, Size);
return 0;
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2019 Frank Morgner <frankmorgner@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "libopensc/asn1.h"
#include <stdlib.h>
#include <string.h>
static unsigned char *in = NULL, *out = NULL;
static size_t inlen = 0, outlen = 0;
static struct sc_context *ctx = NULL;
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
if (!ctx)
sc_establish_context(&ctx, "fuzz");
if (outlen < Size*2) {
unsigned char *p = realloc(out, Size*2);
if (p) {
out = p;
outlen = Size*2;
}
}
if (inlen < Size) {
unsigned char *p = realloc(in, Size);
if (p) {
in = p;
}
}
memcpy(in, Data, Size);
sc_asn1_sig_value_sequence_to_rs(ctx,
Data, Size,
out, outlen);
unsigned char *p = NULL;
size_t plen = 0;
sc_asn1_sig_value_rs_to_sequence(ctx,
in, Size,
&p, &plen);
free(p);
return 0;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2019 Frank Morgner <frankmorgner@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "libopensc/pkcs15.h"
#include "libopensc/internal.h"
#include <stdlib.h>
#include <string.h>
static struct sc_context *ctx = NULL;
static struct sc_pkcs15_card *p15card = NULL;
static sc_card_t card = {0};
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
int (* decode_entries[])(struct sc_pkcs15_card *, struct sc_pkcs15_object *,
const u8 **nbuf, size_t *nbufsize) = {
sc_pkcs15_decode_prkdf_entry, sc_pkcs15_decode_pukdf_entry,
sc_pkcs15_decode_skdf_entry, sc_pkcs15_decode_cdf_entry,
sc_pkcs15_decode_dodf_entry, sc_pkcs15_decode_aodf_entry
};
size_t i;
if (!ctx)
sc_establish_context(&ctx, "fuzz");
if (!p15card) {
card.ctx = ctx;
p15card = sc_pkcs15_card_new();
if (p15card) {
p15card->card = &card;
}
}
for (i = 0; i < sizeof decode_entries/sizeof *decode_entries; i++) {
struct sc_pkcs15_object *obj;
const u8 *p = Data;
size_t len = Size;
obj = calloc(1, sizeof *obj);
while (SC_SUCCESS == decode_entries[i](p15card, obj, &p, &len)) {
sc_pkcs15_free_object(obj);
}
sc_pkcs15_free_object(obj);
}
struct sc_pkcs15_pubkey *pubkey = calloc(1, sizeof *pubkey);
sc_pkcs15_decode_pubkey(ctx, pubkey, Data, Size);
sc_pkcs15_free_pubkey(pubkey);
struct sc_pkcs15_tokeninfo *tokeninfo = sc_pkcs15_tokeninfo_new();
sc_pkcs15_parse_tokeninfo(ctx, tokeninfo, Data, Size);
sc_pkcs15_free_tokeninfo(tokeninfo);
sc_pkcs15_parse_unusedspace(Data, Size, p15card);
return 0;
}

View File

@ -0,0 +1,264 @@
/*
* Copyright (C) 2019 Frank Morgner <frankmorgner@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "libopensc/pkcs15.h"
#include "libopensc/internal.h"
#include <stdlib.h>
#include <string.h>
const char *__asan_default_options() {
return "verbosity=0:mallocator_may_return_null=1";
}
/* private data structures */
struct driver_data {
const uint8_t *Data;
size_t Size;
};
static struct sc_reader_operations fuzz_ops = {0};
static struct sc_reader_driver fuzz_drv = {
"Fuzzing reader",
"fuzz",
&fuzz_ops,
NULL
};
void fuzz_get_chunk(sc_reader_t *reader, const uint8_t **chunk, uint16_t *chunk_size)
{
struct driver_data *data;
if (chunk)
*chunk = NULL;
if (chunk_size)
*chunk_size = 0;
if (!chunk || !chunk_size || !reader) {
sc_debug(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Invalid Arguments");
return;
}
data = reader->drv_data;
if (!data || !data->Data || data->Size < sizeof *chunk_size) {
sc_debug(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Invalid Arguments");
return;
}
data->Size -= sizeof *chunk_size;
*chunk_size = (uint16_t) data->Data;
data->Data += sizeof *chunk_size;
*chunk = data->Data;
if (data->Size < *chunk_size) {
*chunk_size = data->Size;
}
sc_debug_hex(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
"Returning fuzzing chunk", *chunk, *chunk_size);
}
static int fuzz_reader_release(sc_reader_t *reader)
{
if (reader) {
free(reader->drv_data);
reader->drv_data = NULL;
}
return SC_SUCCESS;
}
static int fuzz_reader_connect(sc_reader_t *reader)
{
uint16_t chunk_size;
const uint8_t *chunk;
fuzz_get_chunk(reader, &chunk, &chunk_size);
if (chunk_size > reader->atr.len)
chunk_size = reader->atr.len;
else
reader->atr.len = chunk_size;
if (chunk_size > 0)
memcpy(reader->atr.value, chunk, chunk_size);
return SC_SUCCESS;
}
static int fuzz_reader_disconnect(sc_reader_t *reader)
{
return SC_SUCCESS;
}
static int fuzz_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
{
const uint8_t *chunk;
uint16_t chunk_size;
fuzz_get_chunk(reader, &chunk, &chunk_size);
if (chunk_size >= 2) {
/* set the SW1 and SW2 status bytes (the last two bytes of
* the response */
apdu->sw1 = (unsigned int)chunk[chunk_size - 2];
apdu->sw2 = (unsigned int)chunk[chunk_size - 1];
chunk_size -= 2;
/* set output length and copy the returned data if necessary */
if (chunk_size <= apdu->resplen)
apdu->resplen = chunk_size;
if (apdu->resplen != 0)
memcpy(apdu->resp, chunk, apdu->resplen);
} else {
apdu->sw1 = 0x6D;
apdu->sw2 = 0x00;
apdu->resplen = 0;
}
return SC_SUCCESS;
}
struct sc_reader_driver *sc_get_fuzz_driver(void)
{
fuzz_ops.release = fuzz_reader_release;
fuzz_ops.connect = fuzz_reader_connect;
fuzz_ops.disconnect = fuzz_reader_disconnect;
fuzz_ops.transmit = fuzz_reader_transmit;
return &fuzz_drv;
}
void fuzz_add_reader(struct sc_context *ctx, const uint8_t *Data, size_t Size)
{
sc_reader_t *reader;
struct driver_data *data;
char name[64] = {0};
if (!(reader = calloc(1, sizeof(*reader)))
|| !(data = (calloc(1, sizeof(*data))))) {
free(reader);
return;
}
data->Data = Data;
data->Size = Size;
reader->driver = &fuzz_drv;
reader->ops = &fuzz_ops;
reader->drv_data = data;
snprintf(name, sizeof name - 1, "%zu random byte%s reader (%p)",
Size, Size == 1 ? "" : "s", Data);
reader->name = strdup(name);
reader->ctx = ctx;
list_append(&ctx->readers, reader);
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
struct sc_context *ctx = NULL;
struct sc_card *card = NULL;
struct sc_pkcs15_card *p15card = NULL;
struct sc_reader *reader;
struct sc_pkcs15_object *obj;
sc_establish_context(&ctx, "fuzz");
if (!ctx)
return 0;
/* copied from sc_release_context() */
while (list_size(&ctx->readers)) {
sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, 0);
_sc_delete_reader(ctx, rdr);
}
if (ctx->reader_driver->ops->finish != NULL)
ctx->reader_driver->ops->finish(ctx);
ctx->reader_driver = sc_get_fuzz_driver();
fuzz_add_reader(ctx, Data, Size);
reader = sc_ctx_get_reader(ctx, 0);
sc_connect_card(reader, &card);
sc_pkcs15_bind(card, NULL, &p15card);
if (p15card) {
const uint8_t *in, *param;
uint16_t in_len, param_len;
fuzz_get_chunk(reader, &in, &in_len);
fuzz_get_chunk(reader, &param, &param_len);
for (obj = p15card->obj_list; obj != NULL; obj = obj->next) {
u8 buf[0xFFFF];
size_t i;
int decipher_flags[] = {SC_ALGORITHM_RSA_RAW,
SC_ALGORITHM_RSA_PAD_PKCS1, SC_ALGORITHM_RSA_PAD_ANSI,
SC_ALGORITHM_RSA_PAD_ISO9796};
for (i = 0; i < sizeof decipher_flags; i++) {
sc_pkcs15_decipher(p15card, obj, decipher_flags[i],
in, in_len, buf, sizeof buf);
}
i = sizeof buf;
sc_pkcs15_derive(p15card, obj, 0,
in, in_len, buf, &i);
int wrap_flags[] = {0, SC_ALGORITHM_AES_ECB, SC_ALGORITHM_AES_CBC_PAD,
SC_ALGORITHM_AES_CBC};
for (i = 0; i < sizeof wrap_flags; i++) {
struct sc_pkcs15_object target_key;
sc_pkcs15_unwrap(p15card, obj, &target_key, wrap_flags[i],
in, in_len, param, param_len);
unsigned long l = sizeof buf;
sc_pkcs15_wrap(p15card, obj, &target_key, wrap_flags[i],
buf, &l, in, in_len);
}
int signature_flags[] = {SC_ALGORITHM_RSA_RAW,
SC_ALGORITHM_RSA_PAD_PKCS1, SC_ALGORITHM_RSA_PAD_ANSI,
SC_ALGORITHM_RSA_PAD_ISO9796,
SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_MGF1_SHA1,
SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_MGF1_SHA256,
SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_MGF1_SHA384,
SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_MGF1_SHA512,
SC_ALGORITHM_RSA_PAD_PSS|SC_ALGORITHM_MGF1_SHA224,
SC_ALGORITHM_ECDSA_RAW, SC_ALGORITHM_ECDSA_HASH_SHA1,
SC_ALGORITHM_ECDSA_HASH_SHA224, SC_ALGORITHM_ECDSA_HASH_SHA256,
SC_ALGORITHM_ECDSA_HASH_SHA384, SC_ALGORITHM_ECDSA_HASH_SHA512,
SC_ALGORITHM_GOSTR3410_RAW, SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411,
SC_ALGORITHM_GOSTR3410_HASHES,
};
for (i = 0; i < sizeof signature_flags; i++) {
sc_pkcs15_compute_signature(p15card, obj, signature_flags[i],
in, in_len, buf, sizeof buf);
}
sc_pkcs15_verify_pin(p15card, obj, in, in_len);
sc_pkcs15_change_pin(p15card, obj, in, in_len, param, param_len);
sc_pkcs15_unblock_pin(p15card, obj, in, in_len, param, param_len);
sc_pkcs15_get_pin_info(p15card, obj);
}
sc_pkcs15_unbind(p15card);
}
sc_disconnect_card(card);
sc_release_context(ctx);
return 0;
}

View File

@ -3,7 +3,12 @@ include $(top_srcdir)/win32/ltrc.inc
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
EXTRA_DIST = Makefile.mak
if ENABLE_OPENSSL
if ENABLE_CMOCKA
noinst_PROGRAMS = p11test
endif
endif
noinst_HEADERS = p11test_loader.h p11test_case_common.h \
p11test_case_readonly.h p11test_case_multipart.h \
p11test_case_mechs.h p11test_case_ec_sign.h \