group_types.mx raw
1 package mls
2
3 // MLS group types (RFC 9420 §11, §12).
4 // Data types and serialization from group.go.
5 // Crypto operations (sign, encrypt, join) go in group_crypto.mx.
6
7 // --- Commit ---
8
9 type commit struct {
10 proposals []proposalOrRef
11 path *updatePath // optional
12 }
13
14 func (c *commit) unmarshal(r *Reader) error {
15 *c = commit{}
16
17 err := r.readVector(func(r *Reader) error {
18 var por proposalOrRef
19 if err := por.unmarshal(r); err != nil {
20 return err
21 }
22 c.proposals = append(c.proposals, por)
23 return nil
24 })
25 if err != nil {
26 return err
27 }
28
29 present, ok := r.readOptional()
30 if !ok {
31 return errUnexpectedEOF
32 }
33 if present {
34 c.path = &updatePath{}
35 if err := c.path.unmarshal(r); err != nil {
36 return err
37 }
38 }
39 return nil
40 }
41
42 func (c *commit) marshal(w *Writer) {
43 w.writeVector(len(c.proposals), func(w *Writer, i int) {
44 c.proposals[i].marshal(w)
45 })
46 w.writeOptional(c.path != nil)
47 if c.path != nil {
48 c.path.marshal(w)
49 }
50 }
51
52 // --- GroupInfo ---
53
54 type groupInfo struct {
55 groupContext groupContext
56 extensions []extension
57 confirmationTag []byte
58 signer leafIndex
59 signature []byte
60 }
61
62 func (info *groupInfo) unmarshal(r *Reader) error {
63 *info = groupInfo{}
64
65 if err := info.groupContext.unmarshal(r); err != nil {
66 return err
67 }
68
69 exts, err := unmarshalExtensionVec(r)
70 if err != nil {
71 return err
72 }
73 info.extensions = exts
74
75 var ok bool
76 info.confirmationTag, ok = r.readOpaqueVec()
77 if !ok {
78 return errUnexpectedEOF
79 }
80 v, ok := r.readUint32()
81 if !ok {
82 return errUnexpectedEOF
83 }
84 info.signer = leafIndex(v)
85 info.signature, ok = r.readOpaqueVec()
86 if !ok {
87 return errUnexpectedEOF
88 }
89 return nil
90 }
91
92 func (info *groupInfo) marshal(w *Writer) {
93 info.marshalTBS(w)
94 w.writeOpaqueVec(info.signature)
95 }
96
97 func (info *groupInfo) marshalTBS(w *Writer) {
98 info.groupContext.marshal(w)
99 marshalExtensionVec(w, info.extensions)
100 w.writeOpaqueVec(info.confirmationTag)
101 w.addUint32(uint32(info.signer))
102 }
103
104 // --- GroupSecrets ---
105
106 type groupSecrets struct {
107 joinerSecret []byte
108 pathSecret []byte // optional
109 psks []preSharedKeyID
110 }
111
112 func (sec *groupSecrets) unmarshal(r *Reader) error {
113 *sec = groupSecrets{}
114
115 var ok bool
116 sec.joinerSecret, ok = r.readOpaqueVec()
117 if !ok {
118 return errUnexpectedEOF
119 }
120
121 present, ok := r.readOptional()
122 if !ok {
123 return errUnexpectedEOF
124 }
125 if present {
126 sec.pathSecret, ok = r.readOpaqueVec()
127 if !ok {
128 return errUnexpectedEOF
129 }
130 }
131
132 return r.readVector(func(r *Reader) error {
133 var psk preSharedKeyID
134 if err := psk.unmarshal(r); err != nil {
135 return err
136 }
137 sec.psks = append(sec.psks, psk)
138 return nil
139 })
140 }
141
142 func (sec *groupSecrets) marshal(w *Writer) {
143 w.writeOpaqueVec(sec.joinerSecret)
144 w.writeOptional(sec.pathSecret != nil)
145 if sec.pathSecret != nil {
146 w.writeOpaqueVec(sec.pathSecret)
147 }
148 w.writeVector(len(sec.psks), func(w *Writer, i int) {
149 sec.psks[i].marshal(w)
150 })
151 }
152
153 func (sec *groupSecrets) verifySingleReinitOrBranchPSK() bool {
154 n := 0
155 for _, pskID := range sec.psks {
156 if pskID.pskType != pskTypeResumption {
157 continue
158 }
159 switch pskID.usage {
160 case resumptionPSKUsageReinit, resumptionPSKUsageBranch:
161 n++
162 }
163 }
164 return n <= 1
165 }
166
167 // --- EncryptedGroupSecrets ---
168
169 type encryptedGroupSecrets struct {
170 newMember KeyPackageRef
171 encryptedGroupSecrets hpkeCiphertext
172 }
173
174 func (sec *encryptedGroupSecrets) unmarshal(r *Reader) error {
175 *sec = encryptedGroupSecrets{}
176 var ok bool
177 sec.newMember, ok = r.readOpaqueVec()
178 if !ok {
179 return errUnexpectedEOF
180 }
181 return sec.encryptedGroupSecrets.unmarshal(r)
182 }
183
184 func (sec *encryptedGroupSecrets) marshal(w *Writer) {
185 w.writeOpaqueVec([]byte(sec.newMember))
186 sec.encryptedGroupSecrets.marshal(w)
187 }
188
189 // --- Welcome ---
190
191 // Welcome includes secret keying information to join a group.
192 type Welcome struct {
193 cipherSuite CipherSuite
194 secrets []encryptedGroupSecrets
195 encryptedGroupInfo []byte
196 }
197
198 // UnmarshalWelcome reads a welcome from an MLS message envelope.
199 func UnmarshalWelcome(raw []byte) (*Welcome, error) {
200 var msg mlsMessage
201 if err := unmarshalRaw(raw, &msg); err != nil {
202 return nil, err
203 }
204 if msg.wireFormat != wireFormatMLSWelcome {
205 return nil, errInvalidWireFormat
206 }
207 return msg.welcome, nil
208 }
209
210 // Bytes encodes the welcome in an MLSMessage envelope.
211 func (w *Welcome) Bytes() []byte {
212 raw, err := marshalRaw(&mlsMessage{
213 version: protocolVersionMLS10,
214 wireFormat: wireFormatMLSWelcome,
215 welcome: w,
216 })
217 if err != nil {
218 panic("mls: failed to marshal welcome")
219 }
220 return raw
221 }
222
223 func (w *Welcome) unmarshal(r *Reader) error {
224 *w = Welcome{}
225 v, ok := r.readUint16()
226 if !ok {
227 return errUnexpectedEOF
228 }
229 w.cipherSuite = CipherSuite(v)
230
231 err := r.readVector(func(r *Reader) error {
232 var sec encryptedGroupSecrets
233 if err := sec.unmarshal(r); err != nil {
234 return err
235 }
236 w.secrets = append(w.secrets, sec)
237 return nil
238 })
239 if err != nil {
240 return err
241 }
242
243 w.encryptedGroupInfo, ok = r.readOpaqueVec()
244 if !ok {
245 return errUnexpectedEOF
246 }
247 return nil
248 }
249
250 func (w *Welcome) marshal(wr *Writer) {
251 wr.addUint16(uint16(w.cipherSuite))
252 wr.writeVector(len(w.secrets), func(wr *Writer, i int) {
253 w.secrets[i].marshal(wr)
254 })
255 wr.writeOpaqueVec(w.encryptedGroupInfo)
256 }
257
258 // NewMembers returns key package refs this welcome contains secrets for.
259 func (w *Welcome) NewMembers() []KeyPackageRef {
260 refs := []KeyPackageRef{:len(w.secrets)}
261 for i, sec := range w.secrets {
262 refs[i] = sec.newMember
263 }
264 return refs
265 }
266
267 func (w *Welcome) findSecret(ref KeyPackageRef) *encryptedGroupSecrets {
268 for i, sec := range w.secrets {
269 if sec.newMember.equal(ref) {
270 return &w.secrets[i]
271 }
272 }
273 return nil
274 }
275