1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 12:28:09 +00:00

feat(crypto): improve return code handling, clean up the code and extend documentation

This commit is contained in:
Christian Reitter 2023-02-08 12:08:11 +01:00 committed by matejcik
parent 770cd19899
commit e2416bcec2
2 changed files with 104 additions and 94 deletions

View File

@ -41,7 +41,7 @@ Advanced usage:
### Fuzzer-specific Configuration Flags ### Fuzzer-specific Configuration Flags
* `-DFUZZ_ALLOW_SLOW` to enable optional fuzzing targets of slow functions * `-DFUZZ_ALLOW_SLOW` to enable optional fuzzing targets of slow functions
* select a specific fuzz testing harness with `-DFUZZER_EXCLUSIVE_TARGET=` to disable the use of all other targets * select a specific fuzz testing harness with `-DFUZZ_EXCLUSIVE_TARGET=` to disable the use of all other targets
### Other Flags ### Other Flags
@ -59,6 +59,12 @@ To be determined:
* `-fsanitize-coverage=edge,trace-cmp,trace-div,indirect-calls,trace-gep,no-prune` to add program counter granularity * `-fsanitize-coverage=edge,trace-cmp,trace-div,indirect-calls,trace-gep,no-prune` to add program counter granularity
* starting with clang-15, the additional `trace-loads` and `trace-stores` sanitizer coverage options are also available * starting with clang-15, the additional `trace-loads` and `trace-stores` sanitizer coverage options are also available
### Architecture-specific Configuration
* aarch64 supports Hardware-assisted AddressSanitizer via `-fsanitize=hwaddress`
* initial testing suggests that this is usable but slower than Address Sanitizer on some systems
* use `lld` instead of the default linker
## Operation ## Operation
See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#options) for valid options and usage. Detailed fuzzer usage and relevant considerations are out of scope of this document. See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#options) for valid options and usage. Detailed fuzzer usage and relevant considerations are out of scope of this document.
@ -101,5 +107,7 @@ The resulting file can be used as a fuzzer dictionary.
## Using Honggfuzz Fuzzer ## Using Honggfuzz Fuzzer
Although this code is designed primarily for libFuzzer, it can also be used with [Honggfuzz](https://honggfuzz.dev). Although this code is designed primarily for libFuzzer, it can also be used with [Honggfuzz](https://honggfuzz.dev) in a hybrid Honggfuzz/libFuzzer mode. The setup and usage details are mostly out of scope of this document, but here are some helpful pointers:
However, the usage details are out of scope of this document.
* compile with a clang-based `hfuzz_cc` Honggfuzz compiler variant
* set `-DFUZZ_HONGGFUZZ=1` to suppress compatibility issues

View File

@ -72,22 +72,41 @@
#endif #endif
#endif #endif
/* code design notes #ifndef FUZZ_HONGGFUZZ
// Recent libFuzzer implementations support marking inputs as non-interesting
// via return -1; instead of the regular return 0;
// see
// https://github.com/llvm/llvm-project/commit/92fb310151d2b1e349695fc0f1c5d5d50afb3b52
#define FUZZ_MARK_UNINTERESTING -1
#else
// honggfuzz does not understand the special code
// use regular return code to avoid issues
#define FUZZ_MARK_UNINTERESTING 0
#endif
/* Code design notes
* *
* TODO note down design tradeoffs for this fuzzer style * By combining many individual function harnesses into one binary, a
* collection of target functions can be fuzzed collectively without handling
* dozens of individual binaries or corpus directories
* As a tradeoff, the fuzzing is expected to be less efficient due to
* statistically less successful input crossover or dictionary use
*
* If required, an exclusive target function can be picked at compile time
* for more narrow testing
*/ */
/* code performance notes /* Code performance notes
* *
* use #define over runtime checks for performance reasons * Use #define over runtime checks for performance reasons
* avoid VLA arrays for performance reasons * Avoid VLA arrays for performance reasons
* potential performance drawbacks of heap usage are accepted for better out of * Potential performance drawbacks of heap usage are accepted for better out of
* bounds error detection some expensive functions are hidden with compile-time * bounds error detection
* switches fuzzer harnesses are meant to exit early if the preconditions are * Some expensive functions are hidden with compile-time switches
* not met * Fuzzer harnesses are meant to exit early if the preconditions are not met
*/ */
/* fuzzer input data handling */ /* Fuzzer input data handling */
const uint8_t *fuzzer_ptr; const uint8_t *fuzzer_ptr;
size_t fuzzer_length; size_t fuzzer_length;
@ -102,7 +121,7 @@ const uint8_t *fuzzer_input(size_t len) {
return result; return result;
} }
/* fuzzer state handling */ /* Fuzzer state handling */
void fuzzer_reset_state(void) { void fuzzer_reset_state(void) {
// reset the PRNGs to make individual fuzzer runs deterministic // reset the PRNGs to make individual fuzzer runs deterministic
srand(0); srand(0);
@ -118,7 +137,7 @@ void fuzzer_reset_state(void) {
#endif #endif
} }
void crash(void) { __attribute__((noreturn)) void crash(void) {
// intentionally exit the program // intentionally exit the program
// the fuzzer framework treats this as a crash // the fuzzer framework treats this as a crash
exit(1); exit(1);
@ -146,11 +165,11 @@ void check_msan(void *pointer, size_t length) {
} }
// simplify the pointer check after a var_pointer = malloc() // simplify the pointer check after a var_pointer = malloc()
// return -1 to mark fuzz input as uninteresting for the fuzz engine // the return code marks the fuzz input as uninteresting for the fuzz engine
// warning: use only if no manual memory cleanup is needed // warning: use only if no manual memory cleanup is needed
#define RETURN_IF_NULL(var_pointer) \ #define RETURN_IF_NULL(var_pointer) \
if (var_pointer == NULL) { \ if (var_pointer == NULL) { \
return -1; \ return FUZZ_MARK_UNINTERESTING; \
} }
void zkp_initialize_context_or_crash(void) { void zkp_initialize_context_or_crash(void) {
@ -163,13 +182,13 @@ void zkp_initialize_context_or_crash(void) {
} }
} }
/* individual fuzzer harness functions */ /* Individual fuzzer harness functions */
int fuzz_bn_format(void) { int fuzz_bn_format(void) {
bignum256 target_bignum; bignum256 target_bignum;
// we need some amount of initial data // we need some amount of initial data
if (fuzzer_length < sizeof(target_bignum) + 1 + 1) { if (fuzzer_length < sizeof(target_bignum) + 1 + 1) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
#define FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE 512 #define FUZZ_BN_FORMAT_OUTPUT_BUFFER_SIZE 512
@ -191,7 +210,7 @@ int fuzz_bn_format(void) {
// check for the second half of the data // check for the second half of the data
if (fuzzer_length < (size_t)(prefixlen + suffixlen + 4 + 4 + 1 - 2)) { if (fuzzer_length < (size_t)(prefixlen + suffixlen + 4 + 4 + 1 - 2)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&decimals, fuzzer_input(4), 4); memcpy(&decimals, fuzzer_input(4), 4);
memcpy(&exponent, fuzzer_input(4), 4); memcpy(&exponent, fuzzer_input(4), 4);
@ -204,7 +223,7 @@ int fuzz_bn_format(void) {
char *suffix = malloc(suffixlen); char *suffix = malloc(suffixlen);
if (suffix == NULL) { if (suffix == NULL) {
free(prefix); free(prefix);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memset(prefix, 0, prefixlen); memset(prefix, 0, prefixlen);
@ -234,7 +253,7 @@ int fuzz_bn_format(void) {
int fuzz_base32_decode(void) { int fuzz_base32_decode(void) {
if (fuzzer_length < 2 || fuzzer_length > BASE32_DECODE_MAX_INPUT_LEN) { if (fuzzer_length < 2 || fuzzer_length > BASE32_DECODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char *in_buffer = malloc(fuzzer_length); char *in_buffer = malloc(fuzzer_length);
@ -243,7 +262,7 @@ int fuzz_base32_decode(void) {
uint8_t *out_buffer = malloc(fuzzer_length); uint8_t *out_buffer = malloc(fuzzer_length);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
size_t outlen = fuzzer_length; size_t outlen = fuzzer_length;
@ -269,7 +288,7 @@ int fuzz_base32_decode(void) {
int fuzz_base32_encode(void) { int fuzz_base32_encode(void) {
if (fuzzer_length > BASE32_ENCODE_MAX_INPUT_LEN) { if (fuzzer_length > BASE32_ENCODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t *in_buffer = malloc(fuzzer_length); uint8_t *in_buffer = malloc(fuzzer_length);
@ -279,7 +298,7 @@ int fuzz_base32_encode(void) {
char *out_buffer = malloc(outlen); char *out_buffer = malloc(outlen);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// mutate in_buffer // mutate in_buffer
@ -305,7 +324,7 @@ int fuzz_base32_encode(void) {
int fuzz_base58_encode_check(void) { int fuzz_base58_encode_check(void) {
if (fuzzer_length > BASE58_ENCODE_MAX_INPUT_LEN) { if (fuzzer_length > BASE58_ENCODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t *in_buffer = malloc(fuzzer_length); uint8_t *in_buffer = malloc(fuzzer_length);
@ -315,7 +334,7 @@ int fuzz_base58_encode_check(void) {
char *out_buffer = malloc(outlen); char *out_buffer = malloc(outlen);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// mutate in_buffer // mutate in_buffer
@ -347,7 +366,7 @@ int fuzz_base58_encode_check(void) {
int fuzz_base58_decode_check(void) { int fuzz_base58_decode_check(void) {
if (fuzzer_length > BASE58_DECODE_MAX_INPUT_LEN) { if (fuzzer_length > BASE58_DECODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t *in_buffer = malloc(fuzzer_length + 1); uint8_t *in_buffer = malloc(fuzzer_length + 1);
@ -379,7 +398,7 @@ int fuzz_base58_decode_check(void) {
int fuzz_xmr_base58_addr_decode_check(void) { int fuzz_xmr_base58_addr_decode_check(void) {
if (fuzzer_length > XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN) { if (fuzzer_length > XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// TODO no null termination used !? // TODO no null termination used !?
@ -390,7 +409,7 @@ int fuzz_xmr_base58_addr_decode_check(void) {
uint8_t *out_buffer = malloc(outlen); uint8_t *out_buffer = malloc(outlen);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// tag is only written to // tag is only written to
@ -419,7 +438,7 @@ int fuzz_xmr_base58_addr_decode_check(void) {
// a more focused variant of the xmr_base58_addr_decode_check() harness // a more focused variant of the xmr_base58_addr_decode_check() harness
int fuzz_xmr_base58_decode(void) { int fuzz_xmr_base58_decode(void) {
if (fuzzer_length > XMR_BASE58_DECODE_MAX_INPUT_LEN) { if (fuzzer_length > XMR_BASE58_DECODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// TODO better size heuristic // TODO better size heuristic
@ -429,7 +448,7 @@ int fuzz_xmr_base58_decode(void) {
uint8_t *out_buffer = malloc(outlen); uint8_t *out_buffer = malloc(outlen);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memset(out_buffer, 0, outlen); memset(out_buffer, 0, outlen);
@ -455,7 +474,7 @@ int fuzz_xmr_base58_addr_encode_check(void) {
size_t tag_size = sizeof(tag_in); size_t tag_size = sizeof(tag_in);
if (fuzzer_length < tag_size + 1 || if (fuzzer_length < tag_size + 1 ||
fuzzer_length > XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN) { fuzzer_length > XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// mutate tag_in // mutate tag_in
@ -468,7 +487,7 @@ int fuzz_xmr_base58_addr_encode_check(void) {
char *out_buffer = malloc(outlen); char *out_buffer = malloc(outlen);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memset(out_buffer, 0, outlen); memset(out_buffer, 0, outlen);
@ -506,7 +525,7 @@ int fuzz_xmr_base58_addr_encode_check(void) {
// a more focused variant of the xmr_base58_addr_encode_check() harness // a more focused variant of the xmr_base58_addr_encode_check() harness
int fuzz_xmr_base58_encode(void) { int fuzz_xmr_base58_encode(void) {
if (fuzzer_length > XMR_BASE58_ENCODE_MAX_INPUT_LEN) { if (fuzzer_length > XMR_BASE58_ENCODE_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
// TODO better size heuristic // TODO better size heuristic
@ -516,7 +535,7 @@ int fuzz_xmr_base58_encode(void) {
char *out_buffer = malloc(outlen); char *out_buffer = malloc(outlen);
if (out_buffer == NULL) { if (out_buffer == NULL) {
free(in_buffer); free(in_buffer);
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memset(out_buffer, 0, outlen); memset(out_buffer, 0, outlen);
@ -540,7 +559,7 @@ int fuzz_xmr_serialize_varint(void) {
size_t varint_in_size = sizeof(varint_in); size_t varint_in_size = sizeof(varint_in);
if (fuzzer_length <= varint_in_size || if (fuzzer_length <= varint_in_size ||
fuzzer_length > XMR_SERIALIZE_VARINT_MAX_INPUT_LEN) { fuzzer_length > XMR_SERIALIZE_VARINT_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t out_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0}; uint8_t out_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0};
@ -574,7 +593,7 @@ int fuzz_xmr_serialize_varint(void) {
int fuzz_nem_validate_address(void) { int fuzz_nem_validate_address(void) {
if (fuzzer_length < 1 || fuzzer_length > NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN) { if (fuzzer_length < 1 || fuzzer_length > NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t network = fuzzer_input(1)[0]; uint8_t network = fuzzer_input(1)[0];
@ -599,7 +618,7 @@ int fuzz_nem_get_address(void) {
// TODO switch to < comparison? // TODO switch to < comparison?
if (fuzzer_length != (sizeof(ed25519_public_key_fuzz) + sizeof(version))) { if (fuzzer_length != (sizeof(ed25519_public_key_fuzz) + sizeof(version))) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char address[NEM_ADDRESS_SIZE + 1] = {0}; char address[NEM_ADDRESS_SIZE + 1] = {0};
@ -619,7 +638,7 @@ int fuzz_xmr_get_subaddress_secret_key(void) {
uint32_t major = 0; uint32_t major = 0;
uint32_t minor = 0; uint32_t minor = 0;
if (fuzzer_length != (sizeof(bignum256modm) + 2 * sizeof(uint32_t))) { if (fuzzer_length != (sizeof(bignum256modm) + 2 * sizeof(uint32_t))) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
bignum256modm output = {0}; bignum256modm output = {0};
@ -641,7 +660,7 @@ int fuzz_xmr_derive_private_key(void) {
if (fuzzer_length != if (fuzzer_length !=
(sizeof(bignum256modm) + sizeof(ge25519) + sizeof(uint32_t))) { (sizeof(bignum256modm) + sizeof(ge25519) + sizeof(uint32_t))) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(base, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm)); memcpy(base, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
@ -661,7 +680,7 @@ int fuzz_xmr_derive_public_key(void) {
uint32_t idx = 0; uint32_t idx = 0;
if (fuzzer_length != (2 * sizeof(ge25519) + sizeof(uint32_t))) { if (fuzzer_length != (2 * sizeof(ge25519) + sizeof(uint32_t))) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&base, fuzzer_input(sizeof(ge25519)), sizeof(ge25519)); memcpy(&base, fuzzer_input(sizeof(ge25519)), sizeof(ge25519));
@ -680,7 +699,7 @@ int fuzz_xmr_derive_public_key(void) {
int fuzz_shamir_interpolate(void) { int fuzz_shamir_interpolate(void) {
if (fuzzer_length != (2 * sizeof(uint8_t) + SHAMIR_MAX_SHARE_COUNT + if (fuzzer_length != (2 * sizeof(uint8_t) + SHAMIR_MAX_SHARE_COUNT +
SHAMIR_MAX_DATA_LEN + sizeof(size_t))) { SHAMIR_MAX_DATA_LEN + sizeof(size_t))) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t result[SHAMIR_MAX_LEN] = {0}; uint8_t result[SHAMIR_MAX_LEN] = {0};
@ -727,7 +746,7 @@ int fuzz_ecdsa_sign_digest_functions(void) {
uint8_t sig2[64] = {0}; uint8_t sig2[64] = {0};
uint8_t pby1, pby2 = 0; uint8_t pby1, pby2 = 0;
if (fuzzer_length < 1 + sizeof(priv_key) + sizeof(digest)) { if (fuzzer_length < 1 + sizeof(priv_key) + sizeof(digest)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
const ecdsa_curve *curve; const ecdsa_curve *curve;
@ -788,7 +807,7 @@ int fuzz_ecdsa_verify_digest_functions(void) {
uint8_t pub_key[65] = {0}; uint8_t pub_key[65] = {0};
if (fuzzer_length < 1 + sizeof(hash) + sizeof(sig) + sizeof(pub_key)) { if (fuzzer_length < 1 + sizeof(hash) + sizeof(sig) + sizeof(pub_key)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&curve_decider, fuzzer_input(1), 1); memcpy(&curve_decider, fuzzer_input(1), 1);
@ -806,12 +825,6 @@ int fuzz_ecdsa_verify_digest_functions(void) {
int res1 = ecdsa_verify_digest(curve, (const uint8_t *)&pub_key, int res1 = ecdsa_verify_digest(curve, (const uint8_t *)&pub_key,
(const uint8_t *)&sig, (const uint8_t *)&hash); (const uint8_t *)&sig, (const uint8_t *)&hash);
if (res1 == 0) {
// See if the fuzzer ever manages to get find a correct verification
// intentionally trigger a crash to make this case observable
// TODO this is not an actual problem, remove in the future
crash();
}
// the zkp_ecdsa* function only accepts the secp256k1 curve // the zkp_ecdsa* function only accepts the secp256k1 curve
if (curve == &secp256k1) { if (curve == &secp256k1) {
@ -834,7 +847,7 @@ int fuzz_word_index(void) {
#define MAX_WORD_LENGTH 12 #define MAX_WORD_LENGTH 12
if (fuzzer_length < MAX_WORD_LENGTH) { if (fuzzer_length < MAX_WORD_LENGTH) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char word[MAX_WORD_LENGTH + 1] = {0}; char word[MAX_WORD_LENGTH + 1] = {0};
@ -849,7 +862,7 @@ int fuzz_word_index(void) {
int fuzz_slip39_word_completion_mask(void) { int fuzz_slip39_word_completion_mask(void) {
if (fuzzer_length != 2) { if (fuzzer_length != 2) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint16_t sequence = (fuzzer_ptr[0] << 8) + fuzzer_ptr[1]; uint16_t sequence = (fuzzer_ptr[0] << 8) + fuzzer_ptr[1];
fuzzer_input(2); fuzzer_input(2);
@ -863,7 +876,7 @@ int fuzz_slip39_word_completion_mask(void) {
#define MAX_MNEMONIC_FUZZ_LENGTH 256 #define MAX_MNEMONIC_FUZZ_LENGTH 256
int fuzz_mnemonic_check(void) { int fuzz_mnemonic_check(void) {
if (fuzzer_length < MAX_MNEMONIC_FUZZ_LENGTH) { if (fuzzer_length < MAX_MNEMONIC_FUZZ_LENGTH) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char mnemonic[MAX_MNEMONIC_FUZZ_LENGTH + 1] = {0}; char mnemonic[MAX_MNEMONIC_FUZZ_LENGTH + 1] = {0};
@ -885,7 +898,7 @@ int fuzz_mnemonic_check(void) {
int fuzz_mnemonic_from_data(void) { int fuzz_mnemonic_from_data(void) {
if (fuzzer_length < 16 || fuzzer_length > 32) { if (fuzzer_length < 16 || fuzzer_length > 32) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
const char *mnemo_result = mnemonic_from_data(fuzzer_ptr, fuzzer_length); const char *mnemo_result = mnemonic_from_data(fuzzer_ptr, fuzzer_length);
@ -910,7 +923,7 @@ int fuzz_mnemonic_from_data(void) {
#define MAX_PASSPHRASE_FUZZ_LENGTH 257 #define MAX_PASSPHRASE_FUZZ_LENGTH 257
int fuzz_mnemonic_to_seed(void) { int fuzz_mnemonic_to_seed(void) {
if (fuzzer_length < MAX_MNEMONIC_FUZZ_LENGTH + MAX_PASSPHRASE_FUZZ_LENGTH) { if (fuzzer_length < MAX_MNEMONIC_FUZZ_LENGTH + MAX_PASSPHRASE_FUZZ_LENGTH) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char mnemonic[MAX_PASSPHRASE_FUZZ_LENGTH + 1] = {0}; char mnemonic[MAX_PASSPHRASE_FUZZ_LENGTH + 1] = {0};
@ -934,7 +947,7 @@ int fuzz_ethereum_address_checksum(void) {
bool rskip60 = false; bool rskip60 = false;
if (fuzzer_length < sizeof(addr) + sizeof(address) + sizeof(chain_id) + 1) { if (fuzzer_length < sizeof(addr) + sizeof(address) + sizeof(chain_id) + 1) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(addr, fuzzer_input(sizeof(addr)), sizeof(addr)); memcpy(addr, fuzzer_input(sizeof(addr)), sizeof(addr));
@ -950,7 +963,7 @@ int fuzz_ethereum_address_checksum(void) {
int fuzz_aes(void) { int fuzz_aes(void) {
if (fuzzer_length < 1 + 16 + 16 + 32) { if (fuzzer_length < 1 + 16 + 16 + 32) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
aes_encrypt_ctx ctxe; aes_encrypt_ctx ctxe;
@ -1028,7 +1041,7 @@ int fuzz_chacha_drbg(void) {
if (fuzzer_length < CHACHA_DRBG_ENTROPY_LENGTH + CHACHA_DRBG_RESEED_LENGTH + if (fuzzer_length < CHACHA_DRBG_ENTROPY_LENGTH + CHACHA_DRBG_RESEED_LENGTH +
CHACHA_DRBG_NONCE_LENGTH) { CHACHA_DRBG_NONCE_LENGTH) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
uint8_t entropy[CHACHA_DRBG_ENTROPY_LENGTH] = {0}; uint8_t entropy[CHACHA_DRBG_ENTROPY_LENGTH] = {0};
@ -1063,7 +1076,7 @@ int fuzz_ed25519_sign_verify(void) {
if (fuzzer_length < if (fuzzer_length <
sizeof(secret_key) + sizeof(signature) + sizeof(message)) { sizeof(secret_key) + sizeof(signature) + sizeof(message)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&secret_key, fuzzer_input(sizeof(secret_key)), sizeof(secret_key)); memcpy(&secret_key, fuzzer_input(sizeof(secret_key)), sizeof(secret_key));
@ -1094,7 +1107,7 @@ int fuzz_zkp_bip340_sign_digest(void) {
if (fuzzer_length < if (fuzzer_length <
sizeof(priv_key) + sizeof(aux_input) + sizeof(digest) + sizeof(sig)) { sizeof(priv_key) + sizeof(aux_input) + sizeof(digest) + sizeof(sig)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key)); memcpy(priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key));
memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest)); memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest));
@ -1121,7 +1134,7 @@ int fuzz_zkp_bip340_verify_digest(void) {
uint8_t sig[64] = {0}; uint8_t sig[64] = {0};
if (fuzzer_length < sizeof(digest) + sizeof(pub_key) + sizeof(sig)) { if (fuzzer_length < sizeof(digest) + sizeof(pub_key) + sizeof(sig)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key)); memcpy(pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key));
memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest)); memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest));
@ -1129,11 +1142,7 @@ int fuzz_zkp_bip340_verify_digest(void) {
res = zkp_bip340_verify_digest(pub_key, sig, digest); res = zkp_bip340_verify_digest(pub_key, sig, digest);
// res == 0 is valid, but crash to make successful passes visible (void)res;
// TODO remove this later
if (res == 0) {
crash();
}
return 0; return 0;
} }
@ -1146,7 +1155,7 @@ int fuzz_zkp_bip340_tweak_keys(void) {
if (fuzzer_length < if (fuzzer_length <
sizeof(internal_priv) + sizeof(root_hash) + sizeof(internal_pub)) { sizeof(internal_priv) + sizeof(root_hash) + sizeof(internal_pub)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(internal_priv, fuzzer_input(sizeof(internal_priv)), memcpy(internal_priv, fuzzer_input(sizeof(internal_priv)),
sizeof(internal_priv)); sizeof(internal_priv));
@ -1172,7 +1181,7 @@ int fuzz_ecdsa_get_public_key_functions(void) {
const ecdsa_curve *curve = &secp256k1; const ecdsa_curve *curve = &secp256k1;
if (fuzzer_length < sizeof(privkey)) { if (fuzzer_length < sizeof(privkey)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(privkey, fuzzer_input(sizeof(privkey)), sizeof(privkey)); memcpy(privkey, fuzzer_input(sizeof(privkey)), sizeof(privkey));
@ -1182,7 +1191,7 @@ int fuzz_ecdsa_get_public_key_functions(void) {
int res_65_2 = zkp_ecdsa_get_public_key65(curve, privkey, pubkey65_2); int res_65_2 = zkp_ecdsa_get_public_key65(curve, privkey, pubkey65_2);
// the function pairs have different return error codes for the same input // the function pairs have different return error codes for the same input
// so only fail if the one succeeds where the other does not // only fail if the one succeeds where the other does not
if ((res_33_1 == 0 && res_33_2 != 0) || (res_33_1 != 0 && res_33_2 == 0)) { if ((res_33_1 == 0 && res_33_2 != 0) || (res_33_1 != 0 && res_33_2 == 0)) {
// function result mismatch // function result mismatch
crash(); crash();
@ -1216,7 +1225,7 @@ int fuzz_ecdsa_recover_pub_from_sig_functions(void) {
uint8_t pubkey2[65] = {0}; uint8_t pubkey2[65] = {0};
if (fuzzer_length < sizeof(digest) + sizeof(sig) + sizeof(recid)) { if (fuzzer_length < sizeof(digest) + sizeof(sig) + sizeof(recid)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest)); memcpy(digest, fuzzer_input(sizeof(digest)), sizeof(digest));
memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig)); memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig));
@ -1248,7 +1257,7 @@ int fuzz_ecdsa_sig_from_der(void) {
uint8_t out[72] = {0}; uint8_t out[72] = {0};
if (fuzzer_length < sizeof(der)) { if (fuzzer_length < sizeof(der)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(der, fuzzer_input(sizeof(der)), sizeof(der)); memcpy(der, fuzzer_input(sizeof(der)), sizeof(der));
// null-terminate // null-terminate
@ -1268,7 +1277,7 @@ int fuzz_ecdsa_sig_to_der(void) {
uint8_t der[72] = {0}; uint8_t der[72] = {0};
if (fuzzer_length < sizeof(sig)) { if (fuzzer_length < sizeof(sig)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig)); memcpy(sig, fuzzer_input(sizeof(sig)), sizeof(sig));
@ -1282,7 +1291,7 @@ int fuzz_ecdsa_sig_to_der(void) {
int fuzz_button_sequence_to_word(void) { int fuzz_button_sequence_to_word(void) {
uint16_t input = 0; uint16_t input = 0;
if (fuzzer_length < sizeof(input)) { if (fuzzer_length < sizeof(input)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&input, fuzzer_input(sizeof(input)), sizeof(input)); memcpy(&input, fuzzer_input(sizeof(input)), sizeof(input));
@ -1295,7 +1304,7 @@ int fuzz_xmr_add_keys(void) {
ge25519 A, B; ge25519 A, B;
if (fuzzer_length < sizeof(bignum256modm) * 2 + sizeof(ge25519) * 2) { if (fuzzer_length < sizeof(bignum256modm) * 2 + sizeof(ge25519) * 2) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&a, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm)); memcpy(&a, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
memcpy(&b, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm)); memcpy(&b, fuzzer_input(sizeof(bignum256modm)), sizeof(bignum256modm));
@ -1325,7 +1334,7 @@ int fuzz_ecdh_multiply(void) {
uint8_t pub_key[65]; uint8_t pub_key[65];
uint8_t decider; uint8_t decider;
if (fuzzer_length < sizeof(priv_key) + sizeof(pub_key) + sizeof(decider)) { if (fuzzer_length < sizeof(priv_key) + sizeof(pub_key) + sizeof(decider)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key)); memcpy(&priv_key, fuzzer_input(sizeof(priv_key)), sizeof(priv_key));
memcpy(&pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key)); memcpy(&pub_key, fuzzer_input(sizeof(pub_key)), sizeof(pub_key));
@ -1369,7 +1378,7 @@ int fuzz_segwit_addr_encode(void) {
char *hrp = "bc"; char *hrp = "bc";
if (fuzzer_length < sizeof(chosen_witver) + sizeof(chosen_witprog_len)) { if (fuzzer_length < sizeof(chosen_witver) + sizeof(chosen_witprog_len)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&chosen_witver, fuzzer_input(sizeof(chosen_witver)), memcpy(&chosen_witver, fuzzer_input(sizeof(chosen_witver)),
sizeof(chosen_witver)); sizeof(chosen_witver));
@ -1377,7 +1386,7 @@ int fuzz_segwit_addr_encode(void) {
sizeof(chosen_witprog_len)); sizeof(chosen_witprog_len));
if (chosen_witprog_len > fuzzer_length) { if (chosen_witprog_len > fuzzer_length) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char output_address[MAX_ADDR_SIZE] = {0}; char output_address[MAX_ADDR_SIZE] = {0};
@ -1395,8 +1404,6 @@ int fuzz_segwit_addr_encode(void) {
return 0; return 0;
} }
// int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len,
// const char* hrp, const char* addr) {
int fuzz_segwit_addr_decode(void) { int fuzz_segwit_addr_decode(void) {
int decoded_witver = 0; int decoded_witver = 0;
size_t decoded_witprog_len = 0; size_t decoded_witprog_len = 0;
@ -1405,14 +1412,14 @@ int fuzz_segwit_addr_decode(void) {
uint8_t chosen_addr_len = 0; uint8_t chosen_addr_len = 0;
if (fuzzer_length < sizeof(chosen_addr_len)) { if (fuzzer_length < sizeof(chosen_addr_len)) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
memcpy(&chosen_addr_len, fuzzer_input(sizeof(chosen_addr_len)), memcpy(&chosen_addr_len, fuzzer_input(sizeof(chosen_addr_len)),
sizeof(chosen_addr_len)); sizeof(chosen_addr_len));
if (chosen_addr_len > fuzzer_length) { if (chosen_addr_len > fuzzer_length) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
char *addr = malloc(chosen_addr_len + 1); char *addr = malloc(chosen_addr_len + 1);
@ -1433,14 +1440,14 @@ int fuzz_segwit_addr_decode(void) {
return 0; return 0;
} }
/* fuzzer main function */ /* Fuzzer main function */
#define META_HEADER_SIZE 3 #define META_HEADER_SIZE 3
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// reject input that is too short // reject input that is too short
if (size < META_HEADER_SIZE) { if (size < META_HEADER_SIZE) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
fuzzer_reset_state(); fuzzer_reset_state();
@ -1459,16 +1466,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// if active: reject all other inputs that are not the selected target // if active: reject all other inputs that are not the selected target
// this is helpful for directing the fuzzing focus on a specific case // this is helpful for directing the fuzzing focus on a specific case
#ifdef FUZZER_EXCLUSIVE_TARGET #ifdef FUZZ_EXCLUSIVE_TARGET
if (target_decision != FUZZER_EXCLUSIVE_TARGET) { if (target_decision != FUZZ_EXCLUSIVE_TARGET) {
return -1; return FUZZ_MARK_UNINTERESTING;
} }
#endif #endif
// recent libFuzzer implementations support marking inputs as non-interesting
// via return -1; instead of the regular return 0;
// see
// https://github.com/llvm/llvm-project/commit/92fb310151d2b1e349695fc0f1c5d5d50afb3b52
int target_result = 0; int target_result = 0;
// TODO reorder and regroup target functions // TODO reorder and regroup target functions
@ -1567,7 +1570,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
case 30: case 30:
target_result = fuzz_ethereum_address_checksum(); target_result = fuzz_ethereum_address_checksum();
break; break;
case 41: case 41:
zkp_initialize_context_or_crash(); zkp_initialize_context_or_crash();
target_result = fuzz_zkp_bip340_sign_digest(); target_result = fuzz_zkp_bip340_sign_digest();
@ -1608,8 +1610,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
break; break;
default: default:
// mark as uninteresting input return FUZZ_MARK_UNINTERESTING;
return -1; // break will never be reached
break; break;
} }
return target_result; return target_result;