diff --git a/include/secp256k1_whitelist.h b/include/secp256k1_whitelist.h index c3175ce0..19412883 100644 --- a/include/secp256k1_whitelist.h +++ b/include/secp256k1_whitelist.h @@ -43,6 +43,7 @@ typedef struct { * Args: ctx: a secp256k1 context object * Out: sig: a pointer to a signature object * In: input: a pointer to the array to parse + * input_len: the length of the above array * * The signature must consist of a 1-byte n_keys value, followed by a 32-byte * big endian e0 value, followed by n_keys many 32-byte big endian s values. @@ -50,6 +51,7 @@ typedef struct { * is invalid. * * The total length of the input array must therefore be 33 + 32 * n_keys. + * If the length `input_len` does not match this value, parsing will fail. * * After the call, sig will always be initialized. If parsing failed or any * scalar values overflow or are zero, the resulting sig value is guaranteed @@ -58,7 +60,8 @@ typedef struct { SECP256K1_API int secp256k1_whitelist_signature_parse( const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, - const unsigned char *input + const unsigned char *input, + size_t input_len ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Returns the number of keys a signature expects to have. @@ -73,15 +76,17 @@ SECP256K1_API size_t secp256k1_whitelist_signature_n_keys( /** Serialize a whitelist signature * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to an array to store the serialization - * In: sig: a pointer to an initialized signature object + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to an array to store the serialization + * In/Out: output_len: length of the above array, updated with the actual serialized length + * In: sig: a pointer to an initialized signature object * * See secp256k1_whitelist_signature_parse for details about the encoding. */ SECP256K1_API int secp256k1_whitelist_signature_serialize( const secp256k1_context* ctx, unsigned char *output, + size_t *output_len, const secp256k1_whitelist_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); diff --git a/src/modules/whitelist/main_impl.h b/src/modules/whitelist/main_impl.h index 0de178fc..7445d6e3 100644 --- a/src/modules/whitelist/main_impl.h +++ b/src/modules/whitelist/main_impl.h @@ -136,13 +136,13 @@ size_t secp256k1_whitelist_signature_n_keys(const secp256k1_whitelist_signature return sig->n_keys; } -int secp256k1_whitelist_signature_parse(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const unsigned char *input) { +int secp256k1_whitelist_signature_parse(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const unsigned char *input, size_t input_len) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(input != NULL); sig->n_keys = input[0]; - if (sig->n_keys >= MAX_KEYS) { + if (sig->n_keys >= MAX_KEYS || input_len != 1 + 32 * (sig->n_keys + 1)) { return 0; } memcpy(&sig->data[0], &input[1], 32 * (sig->n_keys + 1)); @@ -150,13 +150,18 @@ int secp256k1_whitelist_signature_parse(const secp256k1_context* ctx, secp256k1_ return 1; } -int secp256k1_whitelist_signature_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_whitelist_signature *sig) { +int secp256k1_whitelist_signature_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *output_len, const secp256k1_whitelist_signature *sig) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(output != NULL); ARG_CHECK(sig != NULL); + if (*output_len < 1 + 32 * (sig->n_keys + 1)) { + return 0; + } + output[0] = sig->n_keys; memcpy(&output[1], &sig->data[0], 32 * (sig->n_keys + 1)); + *output_len = 1 + 32 * (sig->n_keys + 1); return 1; } diff --git a/src/modules/whitelist/tests_impl.h b/src/modules/whitelist/tests_impl.h index e307de16..dcaf3baa 100644 --- a/src/modules/whitelist/tests_impl.h +++ b/src/modules/whitelist/tests_impl.h @@ -53,6 +53,7 @@ void test_whitelist_end_to_end(const size_t n_keys) { /* Sign/verify with each one */ for (i = 0; i < n_keys; i++) { unsigned char serialized[32 + 4 + 32 * SECP256K1_WHITELIST_MAX_N_KEYS] = {0}; + size_t slen = sizeof(serialized); secp256k1_whitelist_signature sig; secp256k1_whitelist_signature sig1; @@ -61,8 +62,13 @@ void test_whitelist_end_to_end(const size_t n_keys) { /* Check that exchanging keys causes a failure */ CHECK(secp256k1_whitelist_verify(ctx, &sig, offline_pubkeys, online_pubkeys, &sub_pubkey) != 1); /* Serialization round trip */ - CHECK(secp256k1_whitelist_signature_serialize(ctx, serialized, &sig) == 1); - CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized) == 1); + CHECK(secp256k1_whitelist_signature_serialize(ctx, serialized, &slen, &sig) == 1); + CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized, slen) == 1); + /* (Check various bad-length conditions) */ + CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized, slen + 32) == 0); + CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized, slen + 1) == 0); + CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized, slen - 1) == 0); + CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized, 0) == 0); CHECK(secp256k1_whitelist_verify(ctx, &sig1, online_pubkeys, offline_pubkeys, &sub_pubkey) == 1); CHECK(secp256k1_whitelist_verify(ctx, &sig1, offline_pubkeys, online_pubkeys, &sub_pubkey) != 1); /* Test n_keys */ @@ -93,7 +99,7 @@ void test_whitelist_bad_parse(void) { }; secp256k1_whitelist_signature sig; - CHECK(secp256k1_whitelist_signature_parse(ctx, &sig, serialized) == 0); + CHECK(secp256k1_whitelist_signature_parse(ctx, &sig, serialized, sizeof(serialized)) == 0); } void run_whitelist_tests(void) {