diff --git a/src/key.cpp b/src/key.cpp --- a/src/key.cpp +++ b/src/key.cpp @@ -37,8 +37,8 @@ * * out32 must point to an output buffer of length at least 32 bytes. */ -static int ec_privkey_import_der(const secp256k1_context *ctx, uint8_t *out32, - const uint8_t *privkey, size_t privkeylen) { +int ec_privkey_import_der(const secp256k1_context *ctx, uint8_t *out32, + const uint8_t *privkey, size_t privkeylen) { const uint8_t *end = privkey + privkeylen; memset(out32, 0, 32); /* sequence header */ @@ -98,9 +98,9 @@ * the privkey buffer. Upon return it will be set to the number of bytes used in * the buffer. key32 must point to a 32-byte raw private key. */ -static int ec_privkey_export_der(const secp256k1_context *ctx, uint8_t *privkey, - size_t *privkeylen, const uint8_t *key32, - bool compressed) { +int ec_privkey_export_der(const secp256k1_context *ctx, uint8_t *privkey, + size_t *privkeylen, const uint8_t *key32, + bool compressed) { assert(*privkeylen >= CKey::SIZE); secp256k1_pubkey pubkey; size_t pubkeylen = 0; @@ -224,7 +224,7 @@ } // Check that the sig has a low R value and will be less than 71 bytes -static bool SigHasLowR(const secp256k1_ecdsa_signature *sig) { +bool SigHasLowR(const secp256k1_ecdsa_signature *sig) { uint8_t compact_sig[64]; secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_sign, compact_sig, sig); diff --git a/src/pubkey.cpp b/src/pubkey.cpp --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -25,10 +25,9 @@ * DER before being passed to this module, and we know it supports all * violations present in the blockchain before that point. */ -static int ecdsa_signature_parse_der_lax(const secp256k1_context *ctx, - secp256k1_ecdsa_signature *sig, - const uint8_t *input, - size_t inputlen) { +int ecdsa_signature_parse_der_lax(const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const uint8_t *input, size_t inputlen) { size_t rpos, rlen, spos, slen; size_t pos = 0; size_t lenbyte; diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -151,6 +151,8 @@ script_sigcache script_sign scriptnum_ops + secp256k1_ecdsa_signature_parse_der_lax + secp256k1_ec_seckey_import_export_der signature_checker span spanparsing diff --git a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp new file mode 100644 --- /dev/null +++ b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <key.h> +#include <secp256k1.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <cstdint> +#include <vector> + +int ec_privkey_import_der(const secp256k1_context *ctx, uint8_t *out32, + const uint8_t *seckey, size_t seckeylen); +int ec_privkey_export_der(const secp256k1_context *ctx, uint8_t *seckey, + size_t *seckeylen, const uint8_t *key32, + bool compressed); + +void test_one_input(const std::vector<uint8_t> &buffer) { + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + secp256k1_context *secp256k1_context_sign = + secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + { + std::vector<uint8_t> out32(32); + (void)ec_privkey_import_der( + secp256k1_context_sign, out32.data(), + ConsumeFixedLengthByteVector(fuzzed_data_provider, CKey::SIZE) + .data(), + CKey::SIZE); + } + { + std::vector<uint8_t> seckey(CKey::SIZE); + const std::vector<uint8_t> key32 = + ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); + size_t seckeylen = CKey::SIZE; + const bool compressed = fuzzed_data_provider.ConsumeBool(); + const bool exported = + ec_privkey_export_der(secp256k1_context_sign, seckey.data(), + &seckeylen, key32.data(), compressed); + if (exported) { + std::vector<uint8_t> out32(32); + const bool imported = + ec_privkey_import_der(secp256k1_context_sign, out32.data(), + seckey.data(), seckey.size()) == 1; + assert(imported && key32 == out32); + } + } + secp256k1_context_destroy(secp256k1_context_sign); +} diff --git a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp new file mode 100644 --- /dev/null +++ b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <key.h> +#include <secp256k1.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <cstdint> +#include <vector> + +bool SigHasLowR(const secp256k1_ecdsa_signature *sig); +int ecdsa_signature_parse_der_lax(const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const uint8_t *input, size_t inputlen); + +void test_one_input(const std::vector<uint8_t> &buffer) { + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + const std::vector<uint8_t> signature_bytes = + ConsumeRandomLengthByteVector(fuzzed_data_provider); + if (signature_bytes.data() == nullptr) { + return; + } + secp256k1_context *secp256k1_context_verify = + secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_ecdsa_signature sig_der_lax; + const bool parsed_der_lax = + ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig_der_lax, + signature_bytes.data(), + signature_bytes.size()) == 1; + if (parsed_der_lax) { + ECC_Start(); + (void)SigHasLowR(&sig_der_lax); + ECC_Stop(); + } + secp256k1_context_destroy(secp256k1_context_verify); +}