Skip to content

[MTC] Fetch subtree cosignatures and populate AddTBS responses with them. - #1132

Merged
phbnf merged 2 commits into
transparency-dev:mainfrom
phbnf:witnesssubtree
Aug 24, 2026
Merged

[MTC] Fetch subtree cosignatures and populate AddTBS responses with them.#1132
phbnf merged 2 commits into
transparency-dev:mainfrom
phbnf:witnesssubtree

Conversation

@phbnf

@phbnf phbnf commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Towards #945.

With this PR, an MTC log requests subtree cosignatures when processing AddTBS() requests, and inserts them accordingly in the MTCProof.

For the time being, only accept subtree cosignatures from witnesses that have also cosigned a checkpoint.

This design allows two things:

  • enforcing that mirrors MUST have signed a checkpoint before signing a subtree
  • allows to re-use checkpoint policy checking code, without re-implementing policy checking for subtree signatures

I expect that some of this implementation will change in the near future, as we iterate on the mirror client with request deduplication against multiple instances, and maybe providing a way to pass all checkpoint signatures to the MTC log.

@phbnf
phbnf force-pushed the witnesssubtree branch 9 times, most recently from 5092e3c to 4d6c4d4 Compare August 24, 2026 09:37
@phbnf
phbnf requested a review from roger2hk August 24, 2026 09:41
@phbnf
phbnf marked this pull request as ready for review August 24, 2026 09:41
@phbnf
phbnf requested a review from a team as a code owner August 24, 2026 09:41
@phbnf phbnf changed the title Witnesssubtree [MTC] Fetch subtree cosignatures are populate AddTBS responses with them. Aug 24, 2026
@phbnf phbnf changed the title [MTC] Fetch subtree cosignatures are populate AddTBS responses with them. [MTC] Fetch subtree cosignatures and populate AddTBS responses with them. Aug 24, 2026
@phbnf

phbnf commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

I forgot to mention in the description, CosignSubtree uses the parallel request code that Tessera used to rely on before #1099. I agreed with Al to start with this, and iterate on top of it.

Comment on lines +190 to +195
k := witnessKey{name: s.Name, keyHash: keyHash}
// SPEC: draft-ietf-plants-merkle-tree-certs section 6.2.
// "An MTCProof parser MUST reject the input if there are duplicate cosigner_id values"
if _, ok := verifiedSubtreeSigs[k]; ok {
continue
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here verifies the witness keys instead of cosigner ID. Is the witness key always one-to-one mapped to the cosigner ID? If multiple keys are mapped to the same cosigner ID due to key rotation, the rejection check requirement from the specification seems to be wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s.Name() is the cosigner ID, I've added a comment. We already verify that it is a valid cosigner ID on line 44.

Comment on lines +112 to +117
if len(gw.witnesses) == 0 {
if gw.policy.Satisfied(rawCp) {
return nil, nil
}
return nil, ErrPolicyNotSatisfied
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part of the TODO?

If a witness group consists of non-subtree verifiers, the len(gw.witnesses) is 0, the logic will then go to return nil, nil. It is possible to bypass the policy.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct, and I think it is fine for now. I've added a TODO.

For now, it is the responsibility of log operators to set a valid policy for their operations with ML-DSA verifiers.

Further down the line, I don't think it should be possible to start an MTC log with a policy that lists non-subtree verifiers. It shouldn't be possible to start one with a policy that doesn't comply with Chrome requirements either. In the meantime, I've put TODOs in main.go. I don't really know where we'll enforce that, maybe this will be a special policy parser. There's also a TODO and warning if not enough signatures have been collected.

}
n := unverified.Note

// reconstructCp is used for policy checking.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it reconstructedCp or reconstructCp?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's reconstructedCp, fixed, thanks.

Comment thread cmd/mtc/log/mtc.go Outdated
// "Standalone certificates MUST have at least 2 cosignatures. One of these
// MUST be from the MTC CA Operator, and one MUST be from a Mirroring
// Cosigner recognized by Chrome and not operated by the MTC CA Operator."
slog.WarnContext(ctx, "collected less than 2 subtree signatures", slog.Int("num_sigs", numSigs))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
slog.WarnContext(ctx, "collected less than 2 subtree signatures", slog.Int("num_sigs", numSigs))
slog.WarnContext(ctx, "Collected less than 2 subtree signatures", slog.Int("num_sigs", numSigs))

"slices"
"sync"

f_note "github.com/transparency-dev/formats/note"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Go, package names must be concise and use only lowercase letters and numbers (e.g., k8s, oauth2). Multi-word package names should remain unbroken and in all lowercase (e.g., tabwriter instead of tabWriter, TabWriter, or tab_writer).

https://google.github.io/styleguide/go/decisions.html#package-names

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm following the pattern we've used in this repo so far, https://github.com/search?q=repo%3Atransparency-dev%2Ftessera+f_note&type=code. Maybe we can change this in a followup PR?

@phbnf
phbnf merged commit d89999f into transparency-dev:main Aug 24, 2026
20 checks passed
@phbnf phbnf mentioned this pull request Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants