265 lines
8.0 KiB
C
265 lines
8.0 KiB
C
/*
|
|
* 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, ¶m, ¶m_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;
|
|
}
|