From 73f32d788d1dc72cac0f635210edd3c9b9e11f59 Mon Sep 17 00:00:00 2001
From: "Jan Winkelmann (keks)"
A member of the group applies a Commit message by taking the following steps:
'' -let desc = types.RfcRef/single descText "section-12.4.2" +let desc = + types.DocumentRef/single descText types.Document.MlsRfc "section-12.4.2" let checks = [ types.Check/new 1 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify that the epoch field of the enclosing FramedContent is equal to the epoch field of the current GroupContext object. '' + types.Document.MlsRfc "section-12.4.2-2.1" ) types.Status.Complete @@ -26,11 +28,12 @@ let checks = types.Notes/empty , types.Check/new 2 - ( types.RfcRef/new + ( types.DocumentRef/new '' Unprotect the Commit using the keys from the current epoch: If the message is encoded as PublicMessage, verify the membership MAC using the membership_key. '' + types.Document.MlsRfc [ "section-12.4.2-2.2.1", "section-12.4.2-2.2.2.1" ] ) types.Status.Complete @@ -38,10 +41,11 @@ let checks = types.Notes/empty , types.Check/new 3 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify the signature on the FramedContent message as described in Section 6.1. '' + types.Document.MlsRfc "section-12.4.2-2.3" ) types.Status.Complete @@ -49,10 +53,11 @@ let checks = types.Notes/empty , types.Check/new 4 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify that the proposals vector is valid according to the rules in Section 12.2. '' + types.Document.MlsRfc "section-12.4.2-2.4" ) types.Status.Complete @@ -60,10 +65,11 @@ let checks = types.Notes/empty , types.Check/new 5 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify that all PreSharedKey proposals in the proposals vector are available. '' + types.Document.MlsRfc "section-12.4.2-2.5" ) types.Status.Complete @@ -71,12 +77,13 @@ let checks = types.Notes/empty , types.Check/new 6 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify that the path value is populated if the proposals vector contains any Update or Remove proposals, or if it's empty. Otherwise, the path value MAY be omitted. '' + types.Document.MlsRfc "section-12.4.2-2.7" ) types.Status.Complete @@ -84,12 +91,13 @@ let checks = types.Notes/empty , types.Check/new 7 - ( types.RfcRef/new + ( types.DocumentRef/new '' If the path value is populated, validate it and apply it to the tree: Validate the LeafNode as specified in Section 7.3. The leaf_node_source field MUST be set to commit. '' + types.Document.MlsRfc [ "section-12.4.2-2.8.1", "section-12.4.2-2.8.2.2" ] ) types.Status.Complete @@ -101,12 +109,13 @@ let checks = ) , types.Check/new 8 - ( types.RfcRef/new + ( types.DocumentRef/new '' If the path value is populated, validate it and apply it to the tree: Verify that the encryption_key value in the LeafNode is different from the committer's current leaf node. '' + types.Document.MlsRfc [ "section-12.4.2-2.8.1", "section-12.4.2-2.8.2.3" ] ) types.Status.Complete @@ -116,12 +125,13 @@ let checks = ) , types.Check/new 9 - ( types.RfcRef/new + ( types.DocumentRef/new '' If the path value is populated, validate it and apply it to the tree: Verify that none of the public keys in the UpdatePath appear in any node of the new ratchet tree. '' + types.Document.MlsRfc [ "section-12.4.2-2.8.1", "section-12.4.2-2.8.2.4" ] ) types.Status.Complete diff --git a/checksets/13-framing.dhall b/checksets/13-framing.dhall index 04474da..1fc90b6 100644 --- a/checksets/13-framing.dhall +++ b/checksets/13-framing.dhall @@ -13,16 +13,17 @@ let descText = '' -let desc = types.RfcRef/single descText "section-7.6" +let desc = types.DocumentRef/single descText types.Document.MlsRfc "section-7.6" let checks = [ types.Check/new 1 - ( types.RfcRef/single + ( types.DocumentRef/single '' Recipients of an MLSMessage MUST verify the signature with the key depending on the sender_type of the sender as described above. '' + types.Document.MlsRfc "section-6.1-6" ) types.Status.Complete @@ -32,11 +33,12 @@ let checks = ) , types.Check/new 2 - ( types.RfcRef/single + ( types.DocumentRef/single '' When decoding a PublicMessage into an AuthenticatedContent, the application MUST check membership_tag and MUST check that the FramedContentAuthData is valid. '' + types.Document.MlsRfc "section-6.2-6" ) types.Status.Complete @@ -44,7 +46,7 @@ let checks = types.Notes/empty , types.Check/new 3 - ( types.RfcRef/single + ( types.DocumentRef/single '' The padding field is set by the sender, by first encoding the content (via the select) and the auth field, and then appending the chosen number of zero bytes. A receiver @@ -56,6 +58,7 @@ let checks = check ensures that the padding process is deterministic, so that, for example, padding cannot be used as a covert channel. '' + types.Document.MlsRfc "section-6.3.1-3" ) types.Status.Complete @@ -63,11 +66,12 @@ let checks = types.Notes/empty , types.Check/new 4 - ( types.RfcRef/single + ( types.DocumentRef/single '' When decoding a PrivateMessageContent, the application MUST check that the FramedContentAuthData is valid. '' + types.Document.MlsRfc "section-6.3.1-10" ) types.Status.Complete @@ -75,11 +79,12 @@ let checks = types.Notes/empty , types.Check/new 5 - ( types.RfcRef/single + ( types.DocumentRef/single '' When constructing a SenderData object from a Sender object, the sender MUST verify Sender.sender_type is member and use Sender.leaf_index for SenderData.leaf_index. '' + types.Document.MlsRfc "section-6.3.2-3" ) types.Status.Complete @@ -87,12 +92,13 @@ let checks = types.Notes/empty , types.Check/new 6 - ( types.RfcRef/single + ( types.DocumentRef/single '' When parsing a SenderData struct as part of message decryption, the recipient MUST verify that the leaf index indicated in the leaf_index field identifies a non-blank node. '' + types.Document.MlsRfc "section-6.3.2-9" ) types.Status.Complete @@ -100,7 +106,7 @@ let checks = types.Notes/empty , types.Check/new 7 - ( types.RfcRef/single + ( types.DocumentRef/single '' On receiving a FramedContent containing a Proposal, a client MUST verify the signature inside FramedContentAuthData and that the epoch field of the enclosing FramedContent @@ -108,6 +114,7 @@ let checks = successful, then the Proposal should be cached in such a way that it can be retrieved by hash (as a ProposalOrRef object) in a later Commit message. '' + types.Document.MlsRfc "section-12.1-3" ) types.Status.Complete diff --git a/checksets/14-welcome.dhall b/checksets/14-welcome.dhall index 12a880b..39501ac 100644 --- a/checksets/14-welcome.dhall +++ b/checksets/14-welcome.dhall @@ -11,17 +11,22 @@ let descText = '' -let desc = types.RfcRef/single descText "section-12.4.3.1-7" +let desc = + types.DocumentRef/single + descText + types.Document.MlsRfc + "section-12.4.3.1-7" let checks = [ types.Check/new 1 - ( types.RfcRef/single + ( types.DocumentRef/single '' If a PreSharedKeyID is part of the GroupSecrets and the client is not in possession of the corresponding PSK, return an error. Additionally, if a PreSharedKeyID has type resumption with usage reinit or branch, verify that it is the only such PSK. '' + types.Document.MlsRfc "section-12.4.3.1-10.1" ) types.Status.Missing @@ -29,13 +34,14 @@ let checks = (types.Notes/single "reinit and branch are not implement so far") , types.Check/new 2 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify the signature on the GroupInfo object. The signature input comprises all of the fields in the GroupInfo object except the signature field. The public key is taken from the LeafNode of the ratchet tree with leaf index signer. If the node is blank or if signature verification fails, return an error. '' + types.Document.MlsRfc "section-12.4.3.1-12.1" ) types.Status.Complete @@ -43,11 +49,12 @@ let checks = types.Notes/empty , types.Check/new 3 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify that the group_id is unique among the groups that the client is currently participating in. '' + types.Document.MlsRfc "section-12.4.3.1-12.2" ) types.Status.Missing @@ -57,11 +64,12 @@ let checks = ) , types.Check/new 4 - ( types.RfcRef/single + ( types.DocumentRef/single '' Verify that the cipher_suite in the GroupInfo matches the cipher_suite in the KeyPackage. '' + types.Document.MlsRfc "section-12.4.3.1-12.3" ) types.Status.Complete @@ -82,11 +90,12 @@ let checks = ) , types.Check/new 5 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: Verify that the tree hash of the ratchet tree matches the tree_hash field in GroupInfo. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.4.2.1" ] ) types.Status.Complete @@ -94,12 +103,13 @@ let checks = types.Notes/empty , types.Check/new 6 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For each non-empty parent node, verify that it is "parent-hash valid", as described in Section 7.9.2. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.4.2.2" ] ) types.Status.Complete @@ -107,11 +117,12 @@ let checks = types.Notes/empty , types.Check/new 7 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For each non-empty leaf node, validate the LeafNode as described in Section 7.3. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.4.2.3" ] ) types.Status.Complete @@ -119,13 +130,14 @@ let checks = types.Notes/empty , types.Check/new 8 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For each non-empty parent node and each entry in the node's unmerged_leaves field: Verify that the entry represents a non-blank leaf node that is a descendant of the parent node. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1" , "section-12.4.3.1-12.4.2.4.1" , "section-12.4.3.1-12.4.2.4.2.1" @@ -136,13 +148,14 @@ let checks = types.Notes/empty , types.Check/new 9 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For each non-empty parent node and each entry in the node's unmerged_leaves field: Verify that every non-blank intermediate node between the leaf node and the parent node also has an entry for the leaf node in its unmerged_leaves. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1" , "section-12.4.3.1-12.4.2.4.1" , "section-12.4.3.1-12.4.2.4.2.2" @@ -153,13 +166,14 @@ let checks = types.Notes/empty , types.Check/new 10 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For each non-empty parent node and each entry in the node's unmerged_leaves field: Verify that the encryption key in the parent node does not appear in any other node of the tree. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1" , "section-12.4.3.1-12.4.2.4.1" , "section-12.4.3.1-12.4.2.4.2.3" @@ -170,12 +184,13 @@ let checks = types.Notes/empty , types.Check/new 11 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: Verify the confirmation tag in the GroupInfo using the derived confirmation key and the confirmed_transcript_hash from the GroupInfo. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.9" ] ) types.Status.Complete @@ -183,12 +198,13 @@ let checks = types.Notes/empty , types.Check/new 12 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: If a PreSharedKeyID was used that has type resumption with usage reinit or branch, verify that the epoch field in the GroupInfo is equal to 1. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.11.1" ] ) types.Status.Missing @@ -196,7 +212,7 @@ let checks = (types.Notes/single "reinit isn't currently implemented") , types.Check/new 13 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For usage reinit, verify that the last Commit to the referenced group contains a @@ -205,6 +221,7 @@ let checks = Additionally, verify that all the members of the old group are also members of the new group, according to the application. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.11.2.1" ] ) types.Status.Missing @@ -212,13 +229,14 @@ let checks = (types.Notes/single "reinit isn't currently implemented") , types.Check/new 14 - ( types.RfcRef/new + ( types.DocumentRef/new '' Verify the integrity of the ratchet tree: For usage branch, verify that the version and cipher_suite of the new group match those of the old group, and that the members of the new group compose a subset of the members of the old group, according to the application. '' + types.Document.MlsRfc [ "section-12.4.3.1-12.4.1", "section-12.4.3.1-12.11.2.2" ] ) types.Status.Missing diff --git a/checksets/15-external_proposal.dhall b/checksets/15-external_proposal.dhall index 38c3ef6..81b7ab5 100644 --- a/checksets/15-external_proposal.dhall +++ b/checksets/15-external_proposal.dhall @@ -11,15 +11,17 @@ let descText = '' -let desc = types.RfcRef/single descText "section-12.1.8-1" +let desc = + types.DocumentRef/single descText types.Document.MlsRfc "section-12.1.8-1" let checks = [ types.Check/new 1 - ( types.RfcRef/new + ( types.DocumentRef/new '' sender_type: external: The content_type of the message MUST be proposal. '' + types.Document.MlsRfc [ "section-6.1-4", "section-6.1-5.2" ] ) types.Status.Complete @@ -29,10 +31,11 @@ let checks = ) , types.Check/new 2 - ( types.RfcRef/new + ( types.DocumentRef/new '' sender_type: external: the proposal_type MUST be a value that is allowed for external senders. Only the following types may be sent by an external sender: add, remove, psk, reinit, group_context_extensions. '' + types.Document.MlsRfc [ "section-6.1-4", "section-6.1-5.2", "section-12.1.8-5" ] ) types.Status.Complete @@ -42,10 +45,11 @@ let checks = ) , types.Check/new 3 - ( types.RfcRef/new + ( types.DocumentRef/new '' sender_type: new_member_proposal: The content_type of the message MUST be proposal. '' + types.Document.MlsRfc [ "section-6.1-4", "section-6.1-5.4" ] ) types.Status.Complete @@ -55,10 +59,11 @@ let checks = ) , types.Check/new 4 - ( types.RfcRef/new + ( types.DocumentRef/new '' sender_type: new_member_proposal: The proposal_type of the Proposal MUST be add. '' + types.Document.MlsRfc [ "section-6.1-4", "section-6.1-5.4" ] ) types.Status.Complete diff --git a/checksets/16-extension_types.dhall b/checksets/16-extension_types.dhall index c76069e..3fd620a 100644 --- a/checksets/16-extension_types.dhall +++ b/checksets/16-extension_types.dhall @@ -20,15 +20,17 @@ let descText = '' -let desc = types.RfcRef/single descText "section-17.3" +let desc = + types.DocumentRef/single descText types.Document.MlsRfc "section-17.3" let checks = [ types.Check/new 1 - ( types.RfcRef/new + ( types.DocumentRef/new '' LeafNode: application_id, GREASE '' + types.Document.MlsRfc [ "section-17.3-3.3.1", "section-17.3-4" ] ) types.Status.Unknown @@ -36,10 +38,11 @@ let checks = types.Notes/empty , types.Check/new 2 - ( types.RfcRef/new + ( types.DocumentRef/new '' GroupInfo: ratchet_tree, external_pub, GREASE '' + types.Document.MlsRfc [ "section-17.3-3.3.1", "section-17.3-4" ] ) types.Status.Unknown @@ -47,10 +50,11 @@ let checks = types.Notes/empty , types.Check/new 3 - ( types.RfcRef/new + ( types.DocumentRef/new '' GroupContext: required_capabilities, external_senders '' + types.Document.MlsRfc [ "section-17.3-3.3.1", "section-17.3-4" ] ) types.Status.Unknown @@ -58,10 +62,11 @@ let checks = types.Notes/empty , types.Check/new 4 - ( types.RfcRef/new + ( types.DocumentRef/new '' KeyPackage: GREASE '' + types.Document.MlsRfc [ "section-17.3-3.3.1", "section-17.3-4" ] ) types.Status.Unknown diff --git a/types.dhall b/types.dhall index cbf026a..3214cc6 100644 --- a/types.dhall +++ b/types.dhall @@ -41,44 +41,73 @@ let Url/new : Text -> Url = \(url : Text) -> url -let RfcRef +let Document : Type - = { text : Text, rfcFragments : List Text } + = < MlsRfc | MlsExtensions | Other > -let RfcRef/single - : Text -> Text -> RfcRef +let Document/show + : Document -> Text + = \(doc : Document) -> + merge + { MlsRfc = "RFC 9420" + , MlsExtensions = "MLS Extensions" + , Other = "Other" + } + doc + +let Document/baseUrl + : Document -> Text + = \(doc : Document) -> + merge + { MlsRfc = "https://www.rfc-editor.org/rfc/rfc9420.html" + , MlsExtensions = + "https://datatracker.ietf.org/doc/html/draft-ietf-mls-extensions" + , Other = "https://" + } + doc + +let DocumentRef + : Type + = { text : Text, document : Document, fragments : List Text } + +let DocumentRef/single + : Text -> Document -> Text -> DocumentRef = \(text : Text) -> - \(rfcFragment : Text) -> - let rfcFragments = [ rfcFragment ] in { text, rfcFragments } - -let RfcRef/new - : Text -> List Text -> RfcRef - = \(text : Text) -> \(rfcFragments : List Text) -> { text, rfcFragments } - -let RfcRef/urls - : RfcRef -> List Url - = \(ref : RfcRef) -> - Prelude.List.map - Text - Url - ( \(fragment : Text) -> - "https://www.rfc-editor.org/rfc/rfc9420.html#${fragment}" - ) - ref.rfcFragments + \(doc : Document) -> + \(fragment : Text) -> + { text, document = doc, fragments = [ fragment ] } + +let DocumentRef/new + : Text -> Document -> List Text -> DocumentRef + = \(text : Text) -> + \(doc : Document) -> + \(fragments : List Text) -> + { text, document = doc, fragments } + +let DocumentRef/urls + : DocumentRef -> List Url + = \(ref : DocumentRef) -> + let baseUrl = Document/baseUrl ref.document + + in Prelude.List.map + Text + Url + (\(fragment : Text) -> "${baseUrl}#${fragment}") + ref.fragments let Check : Type = { id : Natural - , desc : RfcRef + , desc : DocumentRef , implStatus : Status , testStatus : Status , notes : Notes } let Check/new - : Natural -> RfcRef -> Status -> Status -> Notes -> Check + : Natural -> DocumentRef -> Status -> Status -> Notes -> Check = \(id : Natural) -> - \(desc : RfcRef) -> + \(desc : DocumentRef) -> \(implStatus : Status) -> \(testStatus : Status) -> \(notes : Notes) -> @@ -86,13 +115,13 @@ let Check/new let CheckSet : Type - = { id : Natural, name : Text, desc : RfcRef, checks : List Check } + = { id : Natural, name : Text, desc : DocumentRef, checks : List Check } let CheckSet/new - : Natural -> Text -> RfcRef -> List Check -> CheckSet + : Natural -> Text -> DocumentRef -> List Check -> CheckSet = \(id : Natural) -> \(name : Text) -> - \(desc : RfcRef) -> + \(desc : DocumentRef) -> \(checks : List Check) -> let checks = Prelude.List.map @@ -138,10 +167,13 @@ in { Notes , Notes/empty , Url , Url/new - , RfcRef - , RfcRef/single - , RfcRef/new - , RfcRef/urls + , Document + , Document/show + , Document/baseUrl + , DocumentRef + , DocumentRef/single + , DocumentRef/new + , DocumentRef/urls , Check , Check/new , CheckSet diff --git a/utils/html.dhall b/utils/html.dhall index 31904fd..4e7e060 100644 --- a/utils/html.dhall +++ b/utils/html.dhall @@ -82,16 +82,16 @@ let XML/p , content = [ XML.text text ] } -let RfcRef/links - : Types.RfcRef -> XML.Type - = \(ref : Types.RfcRef) -> +let DocumentRef/links + : Types.DocumentRef -> XML.Type + = \(ref : Types.DocumentRef) -> XML/asUl "rfcref-links" ( Prelude.List.map Types.Url XML.Type (Url/link "ref") - (Types.RfcRef/urls ref) + (Types.DocumentRef/urls ref) ) let Check/tableRow @@ -132,7 +132,8 @@ let Check/tableRow XML.element { name = "td" , attributes = XML.emptyAttributes - , content = [ XML/p check.desc.text, RfcRef/links check.desc ] + , content = + [ XML/p check.desc.text, DocumentRef/links check.desc ] } let notesUl = @@ -233,7 +234,7 @@ let CheckSet/table , attributes = [ XML.attribute "class" "check-set-desc" ] , content = [ XML.rawText checkSet.desc.text - , RfcRef/links checkSet.desc + , DocumentRef/links checkSet.desc ] } , XML.element diff --git a/views/bookmarkletPage.dhall b/views/bookmarkletPage.dhall index 5a409b6..e00a5fc 100644 --- a/views/bookmarkletPage.dhall +++ b/views/bookmarkletPage.dhall @@ -12,7 +12,7 @@ let checksets = ../checksets.dhall let XML = Prelude.XML -let Check/fragments = \(check : Types.Check) -> check.desc.rfcFragments +let Check/fragments = \(check : Types.Check) -> check.desc.fragments let CheckSet/fragments = \(checkSet : Types.CheckSet) ->