Skip to content

Commit

Permalink
Move HPKE, Sig Keys, Export, PSK forward
Browse files Browse the repository at this point in the history
  • Loading branch information
Rohan Mahy committed Jan 23, 2025
1 parent 916c437 commit e1daa5e
Showing 1 changed file with 163 additions and 163 deletions.
326 changes: 163 additions & 163 deletions draft-ietf-mls-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,169 @@ struct {
~~~


## Hybrid Public Key Encryption (HPKE) {#safe-hpke}

This component of the Safe Extension API allows extensions to make use of all
HPKE key pairs generated by MLS. An extension identified by an ExtensionType can
use any HPKE key pair for any operation defined in {{!RFC9180}}, such as
encryption, exporting keys and the PSK mode, as long as the `info` input to
`Setup<MODE>S` and `Setup<MODE>R` is set to LabeledExtensionContent with
`extension_type` set to ExtensionType. The `extension_data` can be set to an
arbitrary Context specified by the extension designer (and can be empty if not
needed). For example, an extension can use a key pair PublicKey, PrivateKey to
encrypt data as follows:

~~~ tls
SafeEncryptWithContext(ExtensionType, PublicKey, Context, Plaintext) =
SealBase(PublicKey, LabeledExtensionContent, "", Plaintext)

SafeDecryptWithContext(ExtensionType, PrivateKey, Context, KEMOutput, Ciphertext) =
OpenBase(KEMOutput, PrivateKey, LabeledExtensionContent, "", Ciphertext)
~~~

Where the fields of LabeledExtensionContent are set to

~~~ tls
label = "MLS 1.0 ExtensionData"
extension_type = ExtensionType
extension_data = Context
~~~

For operations involving the secret key, ExtensionType MUST be set to the
ExtensionType of the implemented extension, and not to the type of any other
extension. In particular, this means that an extension cannot decrypt data meant
for another extension, while extensions can encrypt data to other extensions.

In general, a ciphertext encrypted with a PublicKey can be decrypted by any
entity who has the corresponding PrivateKey at a given point in time according
to the MLS protocol (or extension). For convenience, the following list
summarizes lifetimes of MLS key pairs.

- The key pair of a non-blank ratchet tree node. The PrivateKey of such a key pair
is known to all members in the node’s subtree. In particular, a PrivateKey of a
leaf node is known only to the member in that leaf. A member in the subtree
stores the PrivateKey for a number of epochs, as long as the PublicKey does not
change. The key pair of the root node SHOULD NOT be used, since the external key
pair recalled below gives better security.
- The external_priv, external_pub key pair used for external initialization. The
external_priv key is known to all group members in the current epoch. A member
stores external_priv only for the current epoch. Using this key pair gives
better security guarantees than using the key pair of the root of the ratchet
tree and should always be preferred.
- The init_key in a KeyPackage and the corresponding secret key. The secret key
is known only to the owner of the KeyPackage and is deleted immediately after it
is used to join a group.

## Signature Keys

MLS session states contain a number of signature keys including the ones in the
LeafNode structs. Extensions can safely sign content and verify signatures using
these keys via the SafeSignWithLabel and SafeVerifyWithLabel functions,
respectively, much like how the basic MLS protocol uses SignWithLabel and
VerifyWithLabel.

In more detail, an extension identified by ExtensionType should sign and verify using:

~~~ tls
SafeSignWithLabel(ExtensionType, SignatureKey, Label, Content) =
SignWithLabel(SignatureKey, "LabeledExtensionContent", LabeledExtensionContent)

SafeVerifyWithLabel(ExtensionType, VerificationKey, Label, Content, SignatureValue) =
VerifyWithLabel(VerificationKey, "LabeledExtensionContent", LabeledExtensionContent, SignatureValue)
~~~

Where the fields of LabeledExtensionContent are set to

~~~ tls
label = Label
extension_type = ExtensionType
extension_data = Content
~~~

For signing operations, the ExtensionType MUST be set to the ExtensionType of
the implemented extension, and not to the type of any other extension. In
particular, this means that an extension cannot produce signatures in place of
other extensions. However, extensions can verify signatures computed by other
extensions. Note that domain separation is ensured by explicitly including the
ExtensionType with every operation.

## Exporting Secrets

An extension can use MLS as a group key agreement protocol by exporting symmetric keys.
Such keys can be exported (i.e. derived from MLS key material) in two phases per
epoch: Either at the start of the epoch, or during the epoch. Derivation at the
start of the epoch has the added advantage that the source key material is
deleted after use, allowing the derived key material to be deleted later even
during the same MLS epoch to achieve forward secrecy. The following protocol
secrets can be used to derive key from for use by extensions:

- epoch_secret at the beginning of an epoch
- extension_secret during an epoch

The extension_secret is an additional secret derived from the epoch_secret at
the beginning of the epoch in the same way as the other secrets listed in Table
4 of {{!RFC9420}} using the label "extension".

Any derivation performed by an extension either from the epoch_secret or the
extension_secret has to use the following function:

~~~ tls
DeriveExtensionSecret(Secret, Label) =
ExpandWithLabel(Secret, "ExtensionExport " + ExtensionType + " " + Label)
~~~

Where ExpandWithLabel is defined in {{Section 8 of !RFC9420}} and where ExtensionType
MUST be set to the ExtensionType of the implemented extension.

## Pre-Shared Keys (PSKs)

PSKs represent key material that is injected into the MLS key schedule when
creating or processing a commit as defined in {{Section 8.4 of !RFC9420}}. Its
injection into the key schedule means that all group members have to agree on
the value of the PSK.

While PSKs are typically cryptographic keys which due to their properties add to
the overall security of the group, the PSK mechanism can also be used to ensure
that all members of a group agree on arbitrary pieces of data represented as
octet strings (without the necessity of sending the data itself over the wire).
For example, an extension can use the PSK mechanism to enforce that all group
members have access to and agree on a password or a shared file.

This is achieved by creating a new epoch via a PSK proposal. Transitioning to
the new epoch requires using the information agreed upon.

To facilitate using PSKs in a safe way, this document defines a new PSKType for
extensions. This provides domain separation between pre-shared keys used by the
core MLS protocol and applications, and between those used by different extensions.

~~~tls
enum {
reserved(0),
external(1),
resumption(2),
extensions(3),
(255)
} PSKType;

struct {
PSKType psktype;
select (PreSharedKeyID.psktype) {
case external:
opaque psk_id<V>;

case resumption:
ResumptionPSKUsage usage;
opaque psk_group_id<V>;
uint64 psk_epoch;

case extensions:
ExtensionType extension_type;
opaque psk_id<V>;
};
opaque psk_nonce<V>;
} PreSharedKeyID;
~~~

# Safe Extensions

The MLS specification is extensible in a variety of ways (see {{Section 13 of
Expand Down Expand Up @@ -406,169 +569,6 @@ struct {
~~~


### Hybrid Public Key Encryption (HPKE) {#safe-hpke}

This component of the Safe Extension API allows extensions to make use of all
HPKE key pairs generated by MLS. An extension identified by an ExtensionType can
use any HPKE key pair for any operation defined in {{!RFC9180}}, such as
encryption, exporting keys and the PSK mode, as long as the `info` input to
`Setup<MODE>S` and `Setup<MODE>R` is set to LabeledExtensionContent with
`extension_type` set to ExtensionType. The `extension_data` can be set to an
arbitrary Context specified by the extension designer (and can be empty if not
needed). For example, an extension can use a key pair PublicKey, PrivateKey to
encrypt data as follows:

~~~ tls
SafeEncryptWithContext(ExtensionType, PublicKey, Context, Plaintext) =
SealBase(PublicKey, LabeledExtensionContent, "", Plaintext)

SafeDecryptWithContext(ExtensionType, PrivateKey, Context, KEMOutput, Ciphertext) =
OpenBase(KEMOutput, PrivateKey, LabeledExtensionContent, "", Ciphertext)
~~~

Where the fields of LabeledExtensionContent are set to

~~~ tls
label = "MLS 1.0 ExtensionData"
extension_type = ExtensionType
extension_data = Context
~~~

For operations involving the secret key, ExtensionType MUST be set to the
ExtensionType of the implemented extension, and not to the type of any other
extension. In particular, this means that an extension cannot decrypt data meant
for another extension, while extensions can encrypt data to other extensions.

In general, a ciphertext encrypted with a PublicKey can be decrypted by any
entity who has the corresponding PrivateKey at a given point in time according
to the MLS protocol (or extension). For convenience, the following list
summarizes lifetimes of MLS key pairs.

- The key pair of a non-blank ratchet tree node. The PrivateKey of such a key pair
is known to all members in the node’s subtree. In particular, a PrivateKey of a
leaf node is known only to the member in that leaf. A member in the subtree
stores the PrivateKey for a number of epochs, as long as the PublicKey does not
change. The key pair of the root node SHOULD NOT be used, since the external key
pair recalled below gives better security.
- The external_priv, external_pub key pair used for external initialization. The
external_priv key is known to all group members in the current epoch. A member
stores external_priv only for the current epoch. Using this key pair gives
better security guarantees than using the key pair of the root of the ratchet
tree and should always be preferred.
- The init_key in a KeyPackage and the corresponding secret key. The secret key
is known only to the owner of the KeyPackage and is deleted immediately after it
is used to join a group.

### Signature Keys

MLS session states contain a number of signature keys including the ones in the
LeafNode structs. Extensions can safely sign content and verify signatures using
these keys via the SafeSignWithLabel and SafeVerifyWithLabel functions,
respectively, much like how the basic MLS protocol uses SignWithLabel and
VerifyWithLabel.

In more detail, an extension identified by ExtensionType should sign and verify using:

~~~ tls
SafeSignWithLabel(ExtensionType, SignatureKey, Label, Content) =
SignWithLabel(SignatureKey, "LabeledExtensionContent", LabeledExtensionContent)

SafeVerifyWithLabel(ExtensionType, VerificationKey, Label, Content, SignatureValue) =
VerifyWithLabel(VerificationKey, "LabeledExtensionContent", LabeledExtensionContent, SignatureValue)
~~~

Where the fields of LabeledExtensionContent are set to

~~~ tls
label = Label
extension_type = ExtensionType
extension_data = Content
~~~

For signing operations, the ExtensionType MUST be set to the ExtensionType of
the implemented extension, and not to the type of any other extension. In
particular, this means that an extension cannot produce signatures in place of
other extensions. However, extensions can verify signatures computed by other
extensions. Note that domain separation is ensured by explicitly including the
ExtensionType with every operation.

### Exporting Secrets

An extension can use MLS as a group key agreement protocol by exporting symmetric keys.
Such keys can be exported (i.e. derived from MLS key material) in two phases per
epoch: Either at the start of the epoch, or during the epoch. Derivation at the
start of the epoch has the added advantage that the source key material is
deleted after use, allowing the derived key material to be deleted later even
during the same MLS epoch to achieve forward secrecy. The following protocol
secrets can be used to derive key from for use by extensions:

- epoch_secret at the beginning of an epoch
- extension_secret during an epoch

The extension_secret is an additional secret derived from the epoch_secret at
the beginning of the epoch in the same way as the other secrets listed in Table
4 of {{!RFC9420}} using the label "extension".

Any derivation performed by an extension either from the epoch_secret or the
extension_secret has to use the following function:

~~~ tls
DeriveExtensionSecret(Secret, Label) =
ExpandWithLabel(Secret, "ExtensionExport " + ExtensionType + " " + Label)
~~~

Where ExpandWithLabel is defined in {{Section 8 of !RFC9420}} and where ExtensionType
MUST be set to the ExtensionType of the implemented extension.

### Pre-Shared Keys (PSKs)

PSKs represent key material that is injected into the MLS key schedule when
creating or processing a commit as defined in {{Section 8.4 of !RFC9420}}. Its
injection into the key schedule means that all group members have to agree on
the value of the PSK.

While PSKs are typically cryptographic keys which due to their properties add to
the overall security of the group, the PSK mechanism can also be used to ensure
that all members of a group agree on arbitrary pieces of data represented as
octet strings (without the necessity of sending the data itself over the wire).
For example, an extension can use the PSK mechanism to enforce that all group
members have access to and agree on a password or a shared file.

This is achieved by creating a new epoch via a PSK proposal. Transitioning to
the new epoch requires using the information agreed upon.

To facilitate using PSKs in a safe way, this document defines a new PSKType for
extensions. This provides domain separation between pre-shared keys used by the
core MLS protocol and applications, and between those used by different extensions.

~~~tls
enum {
reserved(0),
external(1),
resumption(2),
extensions(3),
(255)
} PSKType;

struct {
PSKType psktype;
select (PreSharedKeyID.psktype) {
case external:
opaque psk_id<V>;

case resumption:
ResumptionPSKUsage usage;
opaque psk_group_id<V>;
uint64 psk_epoch;

case extensions:
ExtensionType extension_type;
opaque psk_id<V>;
};
opaque psk_nonce<V>;
} PreSharedKeyID;
~~~

### Extension Designer Tools

The safe extension API allows extension designers to sign and encrypt payloads
Expand Down

0 comments on commit e1daa5e

Please sign in to comment.