fix(publisher): pad ECDSA P-384 signature to fixed width - #1457
JosephDoUrden wants to merge 3 commits into
Conversation
r.Bytes() and s.Bytes() drop leading zero bytes, so the R || S signature was occasionally shorter than 96 bytes and the registry rejected it with "invalid signature size for ECDSA P-384". Left-pad each component to 48 bytes with FillBytes, matching the googlekms signer.
a2271a0 to
a10ebed
Compare
|
Green and mergeable since 16 July with no review yet, so flagging it in case it slipped past. The failure mode is intermittent, which is what makes it awkward to diagnose: Base is 5 commits behind main — happy to rebase if that helps. @rdimitrov |
|
This is a real bug and the fix is correct. I reproduced the failure rate ReproductionSigned 30,000 random messages with a freshly generated P-384 key, encoded each Which matches the analysis in your comment exactly: each component drops its Both existing test suites pass on the head commit: Verifier assumption confirmedThe fixed-width encoding is not just one valid choice here — it is the only one if len(signature) != 96 {
return fmt.Errorf("invalid signature size for ECDSA P-384")
}
r := new(big.Int).SetBytes(signature[:48])
s := new(big.Int).SetBytes(signature[48:])A hard length check plus a split at a fixed offset, so the producer has to Worth noting for anyone reading this later: the old encoding could only ever I also checked the sibling signers for the same pattern. Two small notes, neither blocking
Magic numbers. Nice find on an intermittent bug — the ~1-in-128 rate is exactly the kind that |
|
Thanks for running the numbers, 234 out of 30000 landing right on the 1 in 128 estimate is satisfying to see. Agree with the framing too, publish reliability bug, not security, the hard length check means a short r can only ever fail clean. I'll add a short comment saying r and s are locally generated and bounded so FillBytes can't panic, and I'll rebase onto main so it's fresh. Keeping 96/48 as literals for now to keep the diff small. |
|
Done, brought the branch up to date with main and added the FillBytes bounds comment. |
|
Checked the updated branch ( The bounds comment is accurate as written: Nothing blocking from my side. CI is green and this is ready for a maintainer whenever one has a moment. |
The in-process ECDSA P-384 signer built the signature with
append(r.Bytes(), s.Bytes()...). big.Int.Bytes() strips leading zero bytes, so whenever r or s had a high zero byte (roughly 1 in 128 signatures) the concatenation came out shorter than 96 bytes and the registry rejected the publish with "invalid signature size for ECDSA P-384". Intermittent and confusing to debug. Fixed by left-padding each component to 48 bytes with FillBytes, same as the googlekms signer already does. Added a test pinning the fixed-width encoding plus a sign/verify round-trip.