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
Unambiguous signatures #526
Conversation
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.
Great catch and a neat solution!
Something that is still bothering me is the
Since the first
What do you think about it? |
Nice one! Crafting collisions is probably not straightforward, but eliminating the the risk altogether is the way to go. |
It is actually quite easy to craft collisions, I made a script do find them: https://github.com/TWal/TLSCollisionFinder |
case preconfigured: | ||
case new_member: | ||
struct{}; | ||
} |
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 don't love the aesthetics here. Maybe we could solve this a little more elegantly by having a context
input to SignWithLabel
/VerifyWithLabel
?
Alternatively: Do we even need this field any more? This field was added before membership_tag
, and now the membership_tag
already (a) demonstrates knowledge of the GroupContext and (b) prevents a non-member from synthesizing a valid MLSPlaintext.
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 not sure the alternative is a good idea for several reasons, for example the membership_tag
is present only in MLSPlaintext
and not in MLSCiphertext
, also I'm not confident in removing things from the signature without a solid proof that it is not necessary (for example, signing the tree hash seems like a reasonable thing to do?).
I feel like adding a context
input is a bit weird. What do you think about this third option: adding an option<GroupContext> group_context;
and say something like "group_context MUST contain a value if sender_type = ..." below? This pattern already exists for confirmation_tag
for example.
draft-ietf-mls-protocol.md
Outdated
@@ -2536,7 +2561,7 @@ the right. | |||
* Validate the KeyPackage: | |||
|
|||
* Verify that the signature on the KeyPackage is valid using the public key | |||
in the KeyPackage's credential | |||
in the KeyPackage's credential and the label `"KeyPackage"` |
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 prefer that we put these descriptions with the structs they belong to, as opposed to down here in the instructions. We already have prose that says what the signature covers; that should just specify the label as well. You could also include it as a comment in the syntax specification:
struct {
...
// SignWithLabel(., "MLSPlaintextTBS", MLSPlaintextTBS)
opaque signature<0..2^16-1>;
} KeyPackage;
struct {
...
// SignWithLabel(., "GroupInfoTBS", GroupInfoTBS)
opaque signature<0..2^16-1>;
} GroupInfo;
struct {
...
// SignWithLabel(., "PublicGroupStateTBS", PublicGroupStateTBS)
opaque signature<0..2^16-1>;
} PublicGroupState;
struct {
...
// SignWithLabel(., "MLSPlaintextTBS", MLSPlaintextTBS)
opaque signature<0..2^16-1>;
// MAC(confirmation_key, GroupContext.confirmed_transcript_hash)
optional<MAC> confirmation_tag;
// MAC(membership_key, MLSPlaintextTBM);
optional<MAC> membership_tag;
} MLSPlaintext;
(Note: I don't think GroupInfoTBS exists, but it probably should.)
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.
(#529 adds a GroupInfoTBS
)
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.
If every structure has a TBS
associated with it, this seems like a nice formatting of how you must compute the signatures, however for KeyPackage
there is no TBS
(yet), it is said in the text above that the TBS contains "all of the fields except for the signature field".
Should we add a TBS
for every structure that we sign? This is for example done for PublicGroupState
where a TBS
is explicitly described even if it contains all fields except the signature field in PublicGroupState
.
Signatures as specified in the MLS protocol document are ambiguous, in the sense that signatures produced for one purpose in the protocol can be (maliciously) used in a different place of the protocol.
Indeed, we found that for example, a
KeyPackage
can have the same serialization asMLSPlaintextTBS
, which proves that one signature could be accepted for different structures.The collisions we have found so far are quite artificial, so it is not super clear how to exploit this, but at least it makes it impossible to have provable security.
The solution is pretty simple, we simply prefix each signed value with a label, in a fashion similar to
ExpandWithLabel
.That way, when calling
SignWithLabel
you can give the structure name in theLabel
argument.