[MLS] Syntax and mechanics for external commit

Richard Barnes <rlb@ipv.sx> Wed, 07 October 2020 01:20 UTC

Return-Path: <rlb@ipv.sx>
X-Original-To: mls@ietfa.amsl.com
Delivered-To: mls@ietfa.amsl.com
Received: from localhost (localhost []) by ietfa.amsl.com (Postfix) with ESMTP id 6E0833A1554 for <mls@ietfa.amsl.com>; Tue, 6 Oct 2020 18:20:30 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.897
X-Spam-Status: No, score=-1.897 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=ipv-sx.20150623.gappssmtp.com
Received: from mail.ietf.org ([]) by localhost (ietfa.amsl.com []) (amavisd-new, port 10024) with ESMTP id 3h5bKZmGOHRH for <mls@ietfa.amsl.com>; Tue, 6 Oct 2020 18:20:29 -0700 (PDT)
Received: from mail-qv1-xf36.google.com (mail-qv1-xf36.google.com [IPv6:2607:f8b0:4864:20::f36]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id CA20C3A1446 for <mls@ietf.org>; Tue, 6 Oct 2020 18:20:23 -0700 (PDT)
Received: by mail-qv1-xf36.google.com with SMTP id bl9so207349qvb.10 for <mls@ietf.org>; Tue, 06 Oct 2020 18:20:23 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipv-sx.20150623.gappssmtp.com; s=20150623; h=mime-version:from:date:message-id:subject:to; bh=uPkfusi2RacTrxD1JjXEgACkqJ+HBtkhZiMVH6U5OkU=; b=aHudOM3EeMkOEwrs0KY18E+gVdVyOmpFxTa4qL2KBeU9QLUgOIW36eerT92+VhbcjL IFG+4ietqhByDsSHXa52gW507dSu1f7PWXUQ7TLANs6W2A7MLDNP17VrXkwzWXLTcLNH pBBv2P6VjXsy9QudJ4p3CNrIEuZ7lXti3E/t5MDO6Sq9BZoW/Bzsg/lZ0sJlswgPjpm5 0WoZiNr2a2taz6MtlNa3hsrGUXyeaKCi+cAs/fm6SVvm6qV9ldAESuqpMH1k91J+VpXz +iGl4trvkuB6V710K0UIWtS15ut2ARSYBRtXlZZMAe/aJqLOsKmlEssN4F5Mly6pzzO+ BZNg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=uPkfusi2RacTrxD1JjXEgACkqJ+HBtkhZiMVH6U5OkU=; b=lRZ5X9H0nFdtGc2ihVcNOAdvAXeGrL3eTMj5zYLva9GX0sxcEcfYJAruOhaYkGRa87 u9VS8rjWGJE+U6E8vNYT3vGGqk+nj7LK8PIn6pNMdx161JVKl1vW5VC01dhwb5ccK6fl s1GkMF/cwujEkDHmwV1Euu7bgTaqxSbaRcyf3UbfGtD1JOFPPEk5lYcB1zsFfkTvHS87 hPlDXpDECu3Ab6QR8d4sKB903v8xxIubZ78zLOYNKBSkTh2dwVuc3uutZAaX7eiwIlVR Jtij7kJ5TKk2zBrQTIu9AldGx6kc/m5q9adD+jWtCHF2QqyJUALgh48VfzXTobFWUdXq R2Bg==
X-Gm-Message-State: AOAM531LIUlg8F7I4zaXGFz990UecpCvDVKWkepqgGQ+KTlkvV/se/GA sJ657ZUhrAbogEcxGQEw5bofMjNNCN4SzQQVORnV3XPWgEvsCg==
X-Google-Smtp-Source: ABdhPJz4jPrRTJvqmVsPYkPEYRJle2mGJ6PodfwKNeC2YZdwCXtMGN2s4M61D/6T22CtqWfHEThyv99JNxgI8RHRlsk=
X-Received: by 2002:a0c:cdc4:: with SMTP id a4mr976506qvn.31.1602033622210; Tue, 06 Oct 2020 18:20:22 -0700 (PDT)
MIME-Version: 1.0
From: Richard Barnes <rlb@ipv.sx>
Date: Tue, 6 Oct 2020 21:20:10 -0400
Message-ID: <CAL02cgQCQtJS-_SWcaGDVaDBpKHsmu4P2Lkrq20ukEM3OkdRnQ@mail.gmail.com>
To: Messaging Layer Security WG <mls@ietf.org>
Content-Type: multipart/alternative; boundary="000000000000f86fad05b10a8483"
Archived-At: <https://mailarchive.ietf.org/arch/msg/mls/dpzGL9p3_dkvjMkILUaXkDonTNo>
Subject: [MLS] Syntax and mechanics for external commit
X-BeenThere: mls@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Messaging Layer Security <mls.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/mls>, <mailto:mls-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/mls/>
List-Post: <mailto:mls@ietf.org>
List-Help: <mailto:mls-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/mls>, <mailto:mls-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 07 Oct 2020 01:20:30 -0000

Hey all,

I wanted to send some thoughts on how to implement external commit, as a
prelude to a PR.  This is a little bit of an essay, so tl;dr, the proposal

- Rather than re-using Proposal/Commit, we should make a new ExternalCommit
message, parallel to Proposal/Commit
- We should also define a syntax for telling the joiner the requisite
information about the group

# HPKE-based init secret

The concept here is as follows:

- An HPKE/KEM key pair `(skG, pkG)` is derived off of the key schedule for
each epoch
- The public key `pkG` of that key pair is published along with with other
group metadata
- The joiner calls SetupBaseS(pkG, some_public_group_context) to get an
encapsulated key `enc` and an HPKE context `ctx`
- The joiner sends the encapsulated key to the group with their external
- The members of the group call SetupBaseS(enc, skG,
some_public_group_context) to get an equivalent HPKE context `ctx`
- Everyone calls `ctx.export(MLS_export_label, init_secret_size)` to derive
the init secret

So there are two syntactic requirements:

1. Publishing the group’s public key `pkG`
2. Sending the encapsulated key `enc` to the group

# What Proposals?

The current PR correctly requires that the external Commit MUST cover an
Add proposal for the new member.   It does not forbid the Commit covering
*other* proposals.  It seems like it might be useful in a couple of cases
to keep that option open:
* Including PSK proposals for additional authentication when joining
* Including a Remove proposal for your prior appearance when re-joining

The only current proposal that would be nonsensical is an Update.

Whether we do this has some impact on the syntax, as discussed below.

# External commit syntax: Separate or Together

Assume for the moment that we are not going to do the above asymmetric
calculation for every commit.  Then we need some extra, optional syntax  to
carry `enc`, either as an optional field on Commit or as a new Proposal,
which is the agreed mechanism for extending Commits.  (If we do it every
time, we can just make this part of Commit.)  In the below, I’ll assume a
new Proposal, say ExternalInitSecret.

struct {
  opaque kem_output<0..2^16-1>;
} ExternalInitSecret;

Given the requirement for an Add proposal, the joiner now has to send a
“flight of messages”:

- Proposal(Add)
- Proposal(ExternalInitSecret)
- Commit

Let’s call this the Separate Option.  It’s a bit heavyweight, since each of
these is signed separately.  It’s duplicative, since the KeyPackage in the
Add is immediately overwritten by the (necessarily different) KP in the
Commit.  And you have potential fate-sharing issues, since all three need
to succeed or fail.

You could also envision a Together Option, where we define another
top-level content type (parallel to Proposal and Commit) for this purpose:

struct {
  opaque kem_output<0..2^16-1>;
  UpdatePath path;
} ExternalCommit;

That would avoid all of the challenges above, but it optimizes out all of
the flexibility to include other proposals.  So maybe it’s worth
considering an Extensible Together Option, where we can put extra proposals
into an ExternalCommit

struct {
  Proposal proposals<0..2^32-1>;
  opaque kem_output<0..2^16-1>;
  UpdatePath path;
} ExternalCommit;

Personally, I kind of like the Flexible Together Option, since it provides
simplicity and extensibility.  And to be honest, I’ve been wondering if we
should allow inline proposals in Commit for a while, along just these
lines.  If we do this option, we should probably back-port it to Commit as

# Syntax for what the Joiner Needs

The PR notes that the joiner needs to know a bunch of information about the
group in order to make a well-formed ExternalCommit.  In earlier iterations
of this style of join, we had a GroupInitKey that carried the right
information. Following that pattern here, we get something like the

struct {
  CipherSuite cipher_suite;
  opaque group_id<0..255>;
  uint64 epoch;
  opaque tree_hash<0..255>;
  opaque confirmed_transcript_hash<0..255>;
  Extension extensions<0..2^32-1>;
} GroupKeyPackage;

Note that this object is essentially the same as a GroupInfo object.  The
only things it is missing are interim_transcript_hash and signature, both
of which might be useful.  So maybe all we need to do here is say that
clients can publish GroupInfo unencrypted if they want to enable self-adds,
in addition to distributing it in encrypted form in Welcome.

In any case, it seems like it would be useful to have some syntax for this.

Hope this helps,