Description
verify_rsa_pubkey_in_tbs accepts an arbitrary prover-supplied pubkey_offset and verifies that the DSC modulus bytes appear at that offset. It does not assert:
pubkey_offset + DSC_KEY_SIZE <= tbs_certificate_len
A prover can point the offset into the unsigned (zero-padded) tail of the 1300-byte buffer, extract attacker-controlled bytes, and have them "verified" against the CSCA signature — even though those bytes were never signed by the CSCA.
Root Cause
verify_rsa_pubkey_in_tbs takes tbs: [u8; N] and pubkey_offset: u32 but has no access to the signed length. The function only checks that modulus bytes match at the offset, with no upper-bound constraint on the offset relative to the authenticated region.
Affected file(s):
| File |
Notes |
noir-examples/noir-passport-monolithic/utils/data-check/tbs-pubkey/src/lib.nr |
verify_rsa_pubkey_in_tbs — missing bound check |
noir-examples/noir-passport-monolithic/utils/passport_validity_check/src/lib.nr |
call site — must thread tbs_certificate_len through |
Fix
Add a tbs_certificate_len: u32 parameter to verify_rsa_pubkey_in_tbs and assert the bound before the byte comparison loop:
assert(pubkey_offset + DSC_KEY_SIZE <= tbs_certificate_len);
The call site in passport_validity_check/src/lib.nr must be updated to thread tbs_certificate_len through accordingly.