whitelist: honour the documented parse initialization guarantee

This commit is contained in:
DarkWindman
2026-08-10 15:01:13 +03:00
parent 1de3864ff9
commit e8c3396597
2 changed files with 22 additions and 4 deletions

View File

@@ -133,19 +133,28 @@ size_t secp256k1_whitelist_signature_n_keys(const secp256k1_whitelist_signature
}
int secp256k1_whitelist_signature_parse(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const unsigned char *input, size_t input_len) {
size_t n_keys;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input != NULL);
/* The header guarantees sig is initialized on every path and that a failed
* parse fails validation for any key set. MAX_KEYS + 1 is that canonical
* invalid state: _verify rejects it on sig->n_keys > MAX_KEYS regardless of
* the count the caller supplies. */
memset(sig, 0, sizeof(*sig));
sig->n_keys = MAX_KEYS + 1;
if (input_len == 0) {
return 0;
}
sig->n_keys = input[0];
if (sig->n_keys > MAX_KEYS || input_len != 1 + 32 * (sig->n_keys + 1)) {
n_keys = input[0];
if (n_keys > MAX_KEYS || input_len != 1 + 32 * (n_keys + 1)) {
return 0;
}
memcpy(&sig->data[0], &input[1], 32 * (sig->n_keys + 1));
sig->n_keys = n_keys;
memcpy(&sig->data[0], &input[1], 32 * (n_keys + 1));
return 1;
}
@@ -156,6 +165,10 @@ int secp256k1_whitelist_signature_serialize(const secp256k1_context* ctx, unsign
ARG_CHECK(output_len != NULL);
ARG_CHECK(sig != NULL);
/* Do not trust n_keys to have come from _parse. */
if (sig->n_keys > MAX_KEYS) {
return 0;
}
if (*output_len < 1 + 32 * (sig->n_keys + 1)) {
return 0;
}

View File

@@ -23,12 +23,17 @@ static void test_whitelist_end_to_end_internal(const unsigned char *summed_secke
/* Serialization round trip */
CHECK(secp256k1_whitelist_signature_serialize(CTX, serialized, &slen, &sig) == 1);
CHECK(slen == 33 + 32 * n_keys);
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);
/* A failed parse must leave a signature that fails validation for any
* key set, as documented on secp256k1_whitelist_signature_parse. */
CHECK(secp256k1_whitelist_signature_n_keys(&sig1) > SECP256K1_WHITELIST_MAX_N_KEYS);
CHECK(secp256k1_whitelist_verify(CTX, &sig1, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 0);
/* Re-parse to restore a valid state. */
CHECK(secp256k1_whitelist_signature_parse(CTX, &sig1, serialized, slen) == 1);
CHECK(secp256k1_whitelist_verify(CTX, &sig1, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 1);
CHECK(secp256k1_whitelist_verify(CTX, &sig1, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1);