diff --git a/src/modules/chilldkg/main_impl.h b/src/modules/chilldkg/main_impl.h index 310ce4c2..122911a4 100644 --- a/src/modules/chilldkg/main_impl.h +++ b/src/modules/chilldkg/main_impl.h @@ -703,6 +703,10 @@ size_t secp256k1_chilldkg_investigation_msg_len(size_t n_participants) { return 65 * n_participants; } +/* Maximum length of the recovery data: 4 + 33*t + 162*n bytes with + * t, n <= SECP256K1_CHILLDKG_MAX_PARTICIPANTS. */ +#define SECP256K1_CHILLDKG_MAX_RECOVERY_LEN (4 + 195 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS) + /* Parse the self-delimiting recovery data (deserialize_recovery_data in * chilldkg_ref/chilldkg.py): * u32be(t) || sum_coms (33*t) || hostpubkeys (33*n) || pubnonces (33*n) || @@ -717,10 +721,16 @@ static int secp256k1_chilldkg_deserialize_recovery_data(uint32_t *t_out, size_t const unsigned char *ptr; int overflow; - if (recovery_len < 4) { + if (recovery_len < 4 || recovery_len > SECP256K1_CHILLDKG_MAX_RECOVERY_LEN) { return 0; } t = secp256k1_read_be32(recovery); + /* Bound t before using it as a loop bound over the fixed-size sum_coms + * array: the recovery data is untrusted input. (The reference gets this + * implicitly from Python's dynamically-sized lists.) */ + if (t < 1 || t > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) { + return 0; + } rest_len = recovery_len - 4; if (rest_len < 33 * t || (rest_len - 33 * t) % 162 != 0) { return 0; @@ -920,10 +930,6 @@ static void secp256k1_chilldkg_recovery_ack_message(unsigned char *msg, const un memcpy(msg + 37, recovery, recovery_len); } -/* The maximum length of recovery data: 4 + 33*t + 162*n with t, n <= - * SECP256K1_CHILLDKG_MAX_PARTICIPANTS. */ -#define SECP256K1_CHILLDKG_MAX_RECOVERY_LEN (4 + 195 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS) - /* Check that the recovery data parses and matches the given session * parameters (part of participant_recovery_ack_sign and * participant_recovery_acks_verify in the reference). Returns 1 on match, 0