Subject: [MLS] Sending secrets in WelcomeInfo instead of keys

From: Michael Rosenberg <[email-masked]>
Date: Wed, 7 Aug 2019 13:58:41 -0400

Problem
-------

The special-casing required to use WelcomeInfo::add_key_nonce in unframing Add messages nontrivially increases code complexity.

Framing ordinarily depends on just a handshake_secret and sender_data_secret. From those, the framer/unframer derives the handshake key/nonce and sender data key/nonce.

But in the case of an Addee processing an incoming Add, the Addee's unframer needs to be told to use the handshake key / nonce from the previous WelcomeInfo, and be told to not attempt to decrypt MLSCiphertext::encrypted_sender_data, because

1) The only reason it would need to do this is to derive the handshake key/nonce, which it already has, and
2) the Addee doesn't even know sender_data_key.

This is complex enough that it becomes hard to reason about and painful to implement.

Proposal
--------

To reduce the amount of special casing necessary, the handshake_secret and sender_data_secret be included in WelcomeInfo instead of handshake_key and handshake_nonce. This way, the only steps in the algorithm that differ between the Addee and non-Addees is where the inputs to the unframer's constructor come from, i.e., Unframer(group_ctx.handshake_secret, group_ctx.sender_data_secret) versus Unframer(welcome_info.handshake_secret, welcome_info.sender_data_secret).

Benjamin mentioned that this is technically a violation of the secrecy invariant of TreeKEM: a user who is not a member of a group at epoch n cannot know secrets from epoch n. It should be noted though that this is already violated by the existence of WelcomeInfo::init_secret and WelcomeInfo::add_key_nonce.

-Michael

---

From: Richard Barnes <[email-masked]>
Date: Wed, 7 Aug 2019 14:49:14 -0400

Hey Michael,

Thanks for bringing this issue up.  WelcomeInfo::add_key_nonce does seem
like kind of a hack.

The change you propose seems sensible to me.  It's also coherent with the
"lazy operations" proposal I presented at IETF 105.  EKR asked there how
one does encrypted Add messages in that context.  After thinking about it
for a bit, the only approach that seems workable to me is to provide the
new joiner with the init_secret, sender_data_secret, and handshake_secret
for the epoch in which he is added.  That would enable the new joiner to
decrypt and process all of the handshake messages since the last Ratchet
message, and thus be joined to the group on the next Ratchet message.
Obviously, this aligns exactly with your proposal.

Benjamin's objection seems to reflect a problem in the invariant rather
than the solution here.  We have always leaked at least the init_secret for
an epoch to a new joiner; this proposal just expands that boundary a bit.
It seems like the right way to arrange this is to clarify which secrets
logically "belong" to which epoch.  The init_secret derived from an
epoch_secret, for example, would belong to the epoch after the
epoch_secret.  (And in your proposal, the handshake_secret and
sender_data_secret would also move to that side of the line.)  Then you
could properly require that the secrets in a given epoch are known only to
the members of the group in that epoch.

--Richard

On Wed, Aug 7, 2019 at 1:58 PM Michael Rosenberg <[email-masked]> wrote:

> Problem
> -------
>
> The special-casing required to use WelcomeInfo::add_key_nonce in unframing
> Add messages nontrivially increases code complexity.
>
> Framing ordinarily depends on just a handshake_secret and
> sender_data_secret. From those, the framer/unframer derives the handshake
> key/nonce and sender data key/nonce.
>
> But in the case of an Addee processing an incoming Add, the Addee's
> unframer needs to be told to use the handshake key / nonce from the
> previous WelcomeInfo, and be told to not attempt to decrypt
> MLSCiphertext::encrypted_sender_data, because
>
> To reduce the amount of special casing necessary, the handshake_secret and
> sender_data_secret be included in WelcomeInfo instead of handshake_key and
> handshake_nonce. This way, the only steps in the algorithm that differ
> between the Addee and non-Addees is where the inputs to the unframer's
> constructor come from, i.e., Unframer(group_ctx.handshake_secret,
> group_ctx.sender_data_secret) versus
> Unframer(welcome_info.handshake_secret, welcome_info.sender_data_secret).
>
> Benjamin mentioned that this is technically a violation of the secrecy
> invariant of TreeKEM: a user who is not a member of a group at epoch n
> cannot know secrets from epoch n. It should be noted though that this is
> already violated by the existence of WelcomeInfo::init_secret and
> WelcomeInfo::add_key_nonce.
>
> -Michael
> _______________________________________________
> MLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/mls
>