-
Notifications
You must be signed in to change notification settings - Fork 381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace SignedLogRoot.LogID
with SignedLogRoot.KeyHint
.
#1049
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1049 +/- ##
==========================================
+ Coverage 62.63% 62.65% +0.02%
==========================================
Files 103 103
Lines 8432 8448 +16
==========================================
+ Hits 5281 5293 +12
- Misses 2624 2627 +3
- Partials 527 528 +1
Continue to review full report at Codecov.
|
'Diffbase' isn't really something that works with GitHub -- could you rebase and regenerate please? |
It kind of works if one reviews commit by commit, but it's certainly not great. |
storage/cloudspanner/log_storage.go
Outdated
@@ -357,9 +356,6 @@ func (tx *logTX) StoreSignedLogRoot(ctx context.Context, root trillian.SignedLog | |||
return err | |||
} | |||
|
|||
if got, want := root.LogId, tx.treeID; got != want { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we're not storing LogID
inside LogRootV1
there is no longer duplicate fields to keep in sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really getting the general point here -- it looks like you're replacing an int
encoded as an int
with an int
encoded as [8]byte
; what's the gain?
crypto/signer.go
Outdated
Hash crypto.Hash | ||
Signer crypto.Signer | ||
} | ||
|
||
// NewSigner returns a new annotated signer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a comment to explain what "annotated" means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done where?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must have gotten lost. Fixed comment again.
crypto/signer.go
Outdated
@@ -35,10 +35,20 @@ var sigpbHashLookup = map[crypto.Hash]sigpb.DigitallySigned_HashAlgorithm{ | |||
// Signer is responsible for signing log-related data and producing the appropriate | |||
// application specific signature objects. | |||
type Signer struct { | |||
KeyID int64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, is this used for anything other than diagnostics/logging?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment it's only used for logging to my knowledge.
In the future when we have gossip, this will help gossipers identify which public key to use to verify SignedLogRoot
s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I understand better I wonder: should this be KeyHint []byte
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be more consistent. Done.
crypto/signer.go
Outdated
Signer: signer, | ||
} | ||
} | ||
|
||
// NewSHA256Signer creates a new SHA256 based Signer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this function going to stick around?
If it is, then it should probably get some comment to indicate that the resulting signed isn't associated with a particular key ID. Also, the changes to various ..._test.go
files might not be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to remove NewSha256Signer
. I've got a PR queued up for the certificatetransparency-go
repo, but obviously this PR needs to be merged first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a TODO to remove it.
quota/mysqlqm/mysql_quota_test.go
Outdated
@@ -304,7 +304,9 @@ func createTree(ctx context.Context, db *sql.DB) (*trillian.Tree, error) { | |||
{ | |||
ls := mysql.NewLogStorage(db, nil) | |||
err := ls.ReadWriteTransaction(ctx, tree, func(ctx context.Context, tx storage.LogTreeTX) error { | |||
return tx.StoreSignedLogRoot(ctx, trillian.SignedLogRoot{LogId: tree.TreeId, RootHash: []byte{0}, Signature: &sigpb.DigitallySigned{}}) | |||
return tx.StoreSignedLogRoot(ctx, trillian.SignedLogRoot{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(nit) Although it's just a test, why not use types.SerializeKeyHint
here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll use a proper signer.
storage/mysql/storage_test.go
Outdated
@@ -260,7 +260,6 @@ func createLogForTests(db *sql.DB) int64 { | |||
l := NewLogStorage(db, nil) | |||
err = l.ReadWriteTransaction(ctx, tree, func(ctx context.Context, tx storage.LogTreeTX) error { | |||
if err := tx.StoreSignedLogRoot(ctx, trillian.SignedLogRoot{ | |||
LogId: tree.TreeId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
trillian.proto
Outdated
@@ -217,8 +217,9 @@ message SignedLogRoot { | |||
int64 tree_size = 3; | |||
sigpb.DigitallySigned signature = 4; | |||
|
|||
int64 log_id = 5; | |||
reserved 5; // (moved to key_hint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an API change - are you sure no Trillian users rely on the presence of log_id
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an API change indeed. I'm a little less clear on whether there are no Trillian users that use log_id. I've run the ct-go
unit tests against it, so I'm pretty confident that nothing in the Google ecosystem uses it. Not sure how to detect other uses.
trillian.proto
Outdated
int64 tree_revision = 6; | ||
bytes key_hint = 7; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trillian.proto
file is effectively the external API definition, so it would be good to have a comment explaining what's in the bytes
, and what format it's in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea.
(and thanks for the rebase -- much easier to see diffs now) |
The idea is that Using |
OK, after some offline chats I think I'm catching up -- sorry for missing out on the background to all of this. Let me try explaining things back to see if I've got it right: Thing A: as a general rule, it's safest to check a signature before doing any decoding, so you only decode things that are trusted. So we should be shipping things around the place as blob + signature-of-blob, and only after checking signature-of-blob is it safe to (say) TLS-decode blob into a structure. But which public key do you use to verify the signature? From the perspective of a Trillian client getting an RPC response, this is actually easy: the client only gets back a signed log root (SLR) as a response from a Trillian server after a request for a specific tree, so the client only ever tries to verify the signature with the public key associated with that <trillian-server + treeID>. Easy peasy, O(1), and no need for any identification of which tree is involved. However, these SLRs may get gossiped around the place, at which point anyone who wants to look at them after the fact doesn't know where they came from, and can't trust anyone who claims to tell them where they came from. So checking the signature (thing A) has the O(N) problem of trying every public key they know about. Here's where the key hint helps, to make the normal case O(1) again: use the key hint to find the right public key, verify-sig then deserialize-blob. However, if we're dealing with a big pile of SLRs from all sorts of places, the treeID isn't enough as a unique identifier -- different Trillian servers can re-use the same treeIDs, so something like (say) <trillian-log-uri, treeID> might be needed. In other words, the key hint is context-specific:
This also means that the contents of the key hint will change as context changes. For example, a client of a specific Trillian server may get an SLR with a key hint, but when it forwards that SLR onwards into a bigger pool it would change the key hint to <serverURI, treeID> -- without needing to change the blob, signature-over-blob parts. (Of course, anything that's having to parse a tree_hint will need to do so carefully in case of malicious contents, but any key hint format for a particular environment should be simple enough that it's possible to do safely...) Is that roughly right? |
|
You got it. All of the above is correct. I'll add the following two thoughts:
|
trillian.proto
Outdated
// key_hint is a hint to identify the public key for signature verification. | ||
// key_hint is not authenticated and may be incorrect or missing, in which | ||
// case all known public keys may be used to verify the signature. | ||
// key_hint MAY contain the LogID encoded as a big endian 64 bit integer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add something about context: "When directly communicating with a Trillian gRPC server, the key_hint will typically contain the LogID encoded as a big-endian 64-bit integer; however, in other contexts the key_hint is likely to have different contents (e.g. it could be Trillian URL + tree ID, or it could be data derived from the public key itself)."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Added additional key_hint context documentation. |
Trillian logs can misrepresent their
LogID
inSignedLogRoot
. Clients SHOULD derive theLogID
associated with aSignedLogRoot
object via a valid signature with that log's public key.In situations where a
SignedLogRoot
could be coming from any number of known logs, theKeyHint
field is provided as a shortcut to quickly identify the correct public key to use for verification.This PR associates
LogID
/KeyID
with the signer object, which will automatically include it when generating aSignedLogRoot
object.#958