Repository navigation
Align our MTC implementation with draft-07 - #9134
beautifulentropy wants to merge 9 commits into
Conversation
b040461 to
7c3fc46
Compare
|
Apologies for the force-push. I missed some bullets on one of the Claude reviews. I reviewed the findings and pushed up the necessary changes, and updated the PR description. |
| // construction in https://c2sp.org/tlog-cosignature#cosigners, which log | ||
| // origins also follow: a non-empty UTF-8 string of at most 255 bytes with no | ||
| // Unicode spaces, plus signs, or control characters below U+0020. | ||
| func CheckName(name string) error { |
There was a problem hiding this comment.
I kind of went back and forth on the correct home for this and couldn't make a decision if y'all have better ideas feel free to chime in.
There was a problem hiding this comment.
IMO somewhere in the cosignature package, e.g. cosignature.ValidCosignerName (a mouthful I know). My rationale for there, even though this is shared by log origins, is that a log origin is also a cosigner. Also it's fine here. 🤷🏻
There was a problem hiding this comment.
The requirements for this are defined by the C2SP tlog-cosignature doc, therefore the enforcement of it belongs in the cosignature package, IMO.
(In general, I think it would be nice for future maintenance purposes if we had a very clean mapping of source packages to C2SP documents -- one that implements signed-note, one that implements tlog-cosignature, one that implements tlog-checkpoint, etc.)
aarongable
left a comment
There was a problem hiding this comment.
core: Cap the serial index at trees.MaxSize-1, since a log holds at most 2^48-1 entries per section 5.2.
It took me like four reads to understand this correctly. It seems like it is saying "cap the serial index to 2^48-1", because both mathematical statements have a -1 in them. What it's actually saying is that trees.MaxSize is 2^48-1, and our max index needs to be one less than that (i.e. 2^48-2) because entries are zero-indexed.
I suggest rephrasing as:
core: Cap the serial index at trees.MaxSize-1, rather than recomputing the max serial index directly and getting an off-by-one error
| caID, err := reloid.FromString("44947.4.2.1") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| idRDNATrustAnchorID := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 25, 3} |
There was a problem hiding this comment.
completely optional hyper-nit: idRDNATrustAnchorID is used before caID is, so create it first as well
| caID, err := reloid.FromString("44947.4.2.1") | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| idRDNATrustAnchorID := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 25, 3} | |
| idRDNATrustAnchorID := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 25, 3} | |
| caID, err := reloid.FromString("44947.4.2.1") | |
| if err != nil { | |
| t.Fatal(err) | |
| } |
| // construction in https://c2sp.org/tlog-cosignature#cosigners, which log | ||
| // origins also follow: a non-empty UTF-8 string of at most 255 bytes with no | ||
| // Unicode spaces, plus signs, or control characters below U+0020. | ||
| func CheckName(name string) error { |
There was a problem hiding this comment.
The requirements for this are defined by the C2SP tlog-cosignature doc, therefore the enforcement of it belongs in the cosignature package, IMO.
(In general, I think it would be nice for future maintenance purposes if we had a very clean mapping of source packages to C2SP documents -- one that implements signed-note, one that implements tlog-cosignature, one that implements tlog-checkpoint, etc.)
| // TestCosignSubtree checks that a subtree starting at 0 is signed as a | ||
| // checkpoint of its size is, and that a later subtree verifies over its own | ||
| // message. | ||
| // checkpoint of its size is, that a later subtree verifies over its own |
There was a problem hiding this comment.
I think the first part of this comment is no longer true -- a subtree starting at zero is not signed the same way as a checkpoint of the same size, because the checkpoint includes a timestamp.
|
|
||
| // marshalCheckpointMessage serializes the cosigned.Message for a checkpoint | ||
| // marshalCheckpointMessage serializes the cosigned.Subtree for a checkpoint | ||
| // cosignature, with start 0 and end the tree size as the MTC draft section |
There was a problem hiding this comment.
"and end the tree size" both reads poorly and doesn't seem relevant here, given that the input to this function is end, not treeSize.
| // It errors if cosigner_name or log_origin are not valid names. It does not validate semantic constraints, | ||
| // like [start, end) being a valid subtree. |
There was a problem hiding this comment.
FWIW I think it would just be a single call to subtree.Valid to do this now.
There was a problem hiding this comment.
One message->subtree renaming you didn't do is the name of this file. Unsure whether that rename is worth it or not.
| // above x, an exclusive ceiling. BIT_CEIL(x) is inclusive, the smallest | ||
| // power of two at least x, so we apply it to end-start-1. | ||
| bitCeil := uint64(1) << bits.Len64(uint64(end-start-1)) //nolint:gosec // G115: the start >= end check above leaves end-start positive, so end-start-1 is non-negative. | ||
| bitCeil := uint64(1) << bits.Len64(uint64(end-start-1)) //nolint:gosec // G115: the start == end return above leaves end-start positive, so end-start-1 is non-negative. |
There was a problem hiding this comment.
| bitCeil := uint64(1) << bits.Len64(uint64(end-start-1)) //nolint:gosec // G115: the start == end return above leaves end-start positive, so end-start-1 is non-negative. | |
| bitCeil := uint64(1) << bits.Len64(uint64(end-start-1)) //nolint:gosec // G115: the checks above mean that end-start is positive, so end-start-1 is non-negative. |
| const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" | ||
| nonCanonical := bytes.Clone(line) | ||
| last := bytes.IndexByte(nonCanonical, '=') - 1 | ||
| nonCanonical[last] = alphabet[strings.IndexByte(alphabet, nonCanonical[last])+1] |
There was a problem hiding this comment.
A few comments here:
- It took me a while to figure out exactly what's going on here; there should be a comment explaining it (like there is for the similar code down on line 607).
- If
lineis a length that doesn't require padding characters, this will fail:lastwill be set to -2, and indexingnonCanonical[-2]will panic. - If
lineends with.../=, then this will fail:alphabet[36]will panic.
Comments 2 and 3 also apply down on line 607.
Given that rejecting non-canonical encodings is happens very early in VerifySubtreeSignatureLine, I think it would be much cleaner to just hard-code a base64 string literal that has one or more padding bits set to 1. Something like TWF= (from the wikipedia examples) should work.
id-alg-mtcProof, 1.3.6.1.5.5.7.6.67, which draft 07 allocated, in place of the experimental 1.3.6.1.4.1.44363.47.0.[x, x), per section 4.1 (introduced in draft 06).ConsistencyProofreturns an empty proof for them. The appendix C.1 digests move to their new values, the C.2.1 validity cases are added, andmirror.SignSubtreeRequestusessubtree.Valid.cosigned.Messagetocosigned.Subtreeandproof.SubtreeSignaturetoproof.Cosignature, matching the renamedCosignedSubtreeandCosignaturestructures, andtimestamped_signaturetoTimestampedSignaturein comments.trees.MaxSize-1, since a log holds at most 2^48-1 entries per section 5.2.id-rdna-trustAnchorIDand a RELATIVE-OID value, removing the last use of the experimental attribute.Part of #9082