framing.go raw
1 package mls
2
3 import (
4 "bytes"
5 "crypto/rand"
6 "fmt"
7 "io"
8
9 "golang.org/x/crypto/cryptobyte"
10 )
11
12 type protocolVersion uint16
13
14 const (
15 protocolVersionMLS10 protocolVersion = 1
16 )
17
18 type contentType uint8
19
20 const (
21 contentTypeApplication contentType = 1
22 contentTypeProposal contentType = 2
23 contentTypeCommit contentType = 3
24 )
25
26 func (ct *contentType) unmarshal(s *cryptobyte.String) error {
27 if !s.ReadUint8((*uint8)(ct)) {
28 return io.ErrUnexpectedEOF
29 }
30 switch *ct {
31 case contentTypeApplication, contentTypeProposal, contentTypeCommit:
32 return nil
33 default:
34 return fmt.Errorf("mls: invalid content type %d", *ct)
35 }
36 }
37
38 func (ct contentType) marshal(b *cryptobyte.Builder) {
39 b.AddUint8(uint8(ct))
40 }
41
42 type senderType uint8
43
44 const (
45 senderTypeMember senderType = 1
46 senderTypeExternal senderType = 2
47 senderTypeNewMemberProposal senderType = 3
48 senderTypeNewMemberCommit senderType = 4
49 )
50
51 func (st *senderType) unmarshal(s *cryptobyte.String) error {
52 if !s.ReadUint8((*uint8)(st)) {
53 return io.ErrUnexpectedEOF
54 }
55 switch *st {
56 case senderTypeMember, senderTypeExternal, senderTypeNewMemberProposal, senderTypeNewMemberCommit:
57 return nil
58 default:
59 return fmt.Errorf("mls: invalid sender type %d", *st)
60 }
61 }
62
63 func (st senderType) marshal(b *cryptobyte.Builder) {
64 b.AddUint8(uint8(st))
65 }
66
67 type sender struct {
68 senderType senderType
69 leafIndex leafIndex // for senderTypeMember
70 senderIndex uint32 // for senderTypeExternal
71 }
72
73 func (snd *sender) unmarshal(s *cryptobyte.String) error {
74 *snd = sender{}
75 if err := snd.senderType.unmarshal(s); err != nil {
76 return err
77 }
78 switch snd.senderType {
79 case senderTypeMember:
80 if !s.ReadUint32((*uint32)(&snd.leafIndex)) {
81 return io.ErrUnexpectedEOF
82 }
83 case senderTypeExternal:
84 if !s.ReadUint32(&snd.senderIndex) {
85 return io.ErrUnexpectedEOF
86 }
87 }
88 return nil
89 }
90
91 func (snd *sender) marshal(b *cryptobyte.Builder) {
92 snd.senderType.marshal(b)
93 switch snd.senderType {
94 case senderTypeMember:
95 b.AddUint32(uint32(snd.leafIndex))
96 case senderTypeExternal:
97 b.AddUint32(snd.senderIndex)
98 }
99 }
100
101 type wireFormat uint16
102
103 // http://www.iana.org/assignments/mls/mls.xhtml#mls-wire-formats
104 const (
105 wireFormatMLSPublicMessage wireFormat = 0x0001
106 wireFormatMLSPrivateMessage wireFormat = 0x0002
107 wireFormatMLSWelcome wireFormat = 0x0003
108 wireFormatMLSGroupInfo wireFormat = 0x0004
109 wireFormatMLSKeyPackage wireFormat = 0x0005
110 )
111
112 func (wf *wireFormat) unmarshal(s *cryptobyte.String) error {
113 if !s.ReadUint16((*uint16)(wf)) {
114 return io.ErrUnexpectedEOF
115 }
116 switch *wf {
117 case wireFormatMLSPublicMessage, wireFormatMLSPrivateMessage, wireFormatMLSWelcome, wireFormatMLSGroupInfo, wireFormatMLSKeyPackage:
118 return nil
119 default:
120 return fmt.Errorf("mls: invalid wire format %d", *wf)
121 }
122 }
123
124 func (wf wireFormat) marshal(b *cryptobyte.Builder) {
125 b.AddUint16(uint16(wf))
126 }
127
128 // GroupID is an application-specific group identifier.
129 type GroupID []byte
130
131 // Equal checks whether two key package references are equal.
132 func (ref GroupID) Equal(other GroupID) bool {
133 return bytes.Equal([]byte(ref), []byte(other))
134 }
135
136 type framedContent struct {
137 groupID GroupID
138 epoch uint64
139 sender sender
140 authenticatedData []byte
141
142 contentType contentType
143 applicationData []byte // for contentTypeApplication
144 proposal *proposal // for contentTypeProposal
145 commit *commit // for contentTypeCommit
146 }
147
148 func (content *framedContent) unmarshal(s *cryptobyte.String) error {
149 *content = framedContent{}
150
151 if !readOpaqueVec(s, (*[]byte)(&content.groupID)) || !s.ReadUint64(&content.epoch) {
152 return io.ErrUnexpectedEOF
153 }
154 if err := content.sender.unmarshal(s); err != nil {
155 return err
156 }
157 if !readOpaqueVec(s, &content.authenticatedData) {
158 return io.ErrUnexpectedEOF
159 }
160 if err := content.contentType.unmarshal(s); err != nil {
161 return err
162 }
163
164 switch content.contentType {
165 case contentTypeApplication:
166 if !readOpaqueVec(s, &content.applicationData) {
167 return io.ErrUnexpectedEOF
168 }
169 return nil
170 case contentTypeProposal:
171 content.proposal = new(proposal)
172 return content.proposal.unmarshal(s)
173 case contentTypeCommit:
174 content.commit = new(commit)
175 return content.commit.unmarshal(s)
176 default:
177 panic("unreachable")
178 }
179 }
180
181 func (content *framedContent) marshal(b *cryptobyte.Builder) {
182 writeOpaqueVec(b, []byte(content.groupID))
183 b.AddUint64(content.epoch)
184 content.sender.marshal(b)
185 writeOpaqueVec(b, content.authenticatedData)
186 content.contentType.marshal(b)
187 switch content.contentType {
188 case contentTypeApplication:
189 writeOpaqueVec(b, content.applicationData)
190 case contentTypeProposal:
191 content.proposal.marshal(b)
192 case contentTypeCommit:
193 content.commit.marshal(b)
194 default:
195 panic("unreachable")
196 }
197 }
198
199 type mlsMessage struct {
200 version protocolVersion
201 wireFormat wireFormat
202 publicMessage *publicMessage // for wireFormatMLSPublicMessage
203 privateMessage *privateMessage // for wireFormatMLSPrivateMessage
204 welcome *Welcome // for wireFormatMLSWelcome
205 groupInfo *groupInfo // for wireFormatMLSGroupInfo
206 keyPackage *KeyPackage // for wireFormatMLSKeyPackage
207 }
208
209 func (msg *mlsMessage) unmarshal(s *cryptobyte.String) error {
210 *msg = mlsMessage{}
211
212 if !s.ReadUint16((*uint16)(&msg.version)) {
213 return io.ErrUnexpectedEOF
214 }
215 if msg.version != protocolVersionMLS10 {
216 return fmt.Errorf("mls: invalid protocol version %d", msg.version)
217 }
218
219 if err := msg.wireFormat.unmarshal(s); err != nil {
220 return err
221 }
222
223 switch msg.wireFormat {
224 case wireFormatMLSPublicMessage:
225 msg.publicMessage = new(publicMessage)
226 return msg.publicMessage.unmarshal(s)
227 case wireFormatMLSPrivateMessage:
228 msg.privateMessage = new(privateMessage)
229 return msg.privateMessage.unmarshal(s)
230 case wireFormatMLSWelcome:
231 msg.welcome = new(Welcome)
232 return msg.welcome.unmarshal(s)
233 case wireFormatMLSGroupInfo:
234 msg.groupInfo = new(groupInfo)
235 return msg.groupInfo.unmarshal(s)
236 case wireFormatMLSKeyPackage:
237 msg.keyPackage = new(KeyPackage)
238 return msg.keyPackage.unmarshal(s)
239 default:
240 panic("unreachable")
241 }
242 }
243
244 func (msg *mlsMessage) marshal(b *cryptobyte.Builder) {
245 b.AddUint16(uint16(msg.version))
246 msg.wireFormat.marshal(b)
247 switch msg.wireFormat {
248 case wireFormatMLSPublicMessage:
249 msg.publicMessage.marshal(b)
250 case wireFormatMLSPrivateMessage:
251 msg.privateMessage.marshal(b)
252 case wireFormatMLSWelcome:
253 msg.welcome.marshal(b)
254 case wireFormatMLSGroupInfo:
255 msg.groupInfo.marshal(b)
256 case wireFormatMLSKeyPackage:
257 msg.keyPackage.marshal(b)
258 default:
259 panic("unreachable")
260 }
261 }
262
263 type authenticatedContent struct {
264 wireFormat wireFormat
265 content framedContent
266 auth framedContentAuthData
267 }
268
269 func signAuthenticatedContent(cs CipherSuite, signKey signaturePrivateKey, wf wireFormat, content *framedContent, ctx *groupContext) (*authenticatedContent, error) {
270 authContent := authenticatedContent{
271 wireFormat: wf,
272 content: *content,
273 }
274 tbs := authContent.framedContentTBS(ctx)
275 signature, err := signFramedContent(cs, signKey, tbs)
276 if err != nil {
277 return nil, err
278 }
279 authContent.auth.signature = signature
280 return &authContent, nil
281 }
282
283 func (authContent *authenticatedContent) unmarshal(s *cryptobyte.String) error {
284 if err := authContent.wireFormat.unmarshal(s); err != nil {
285 return err
286 }
287 if err := authContent.content.unmarshal(s); err != nil {
288 return err
289 }
290 if err := authContent.auth.unmarshal(s, authContent.content.contentType); err != nil {
291 return err
292 }
293 return nil
294 }
295
296 func (authContent *authenticatedContent) marshal(b *cryptobyte.Builder) {
297 authContent.wireFormat.marshal(b)
298 authContent.content.marshal(b)
299 authContent.auth.marshal(b, authContent.content.contentType)
300 }
301
302 func (authContent *authenticatedContent) confirmedTranscriptHashInput() *confirmedTranscriptHashInput {
303 return &confirmedTranscriptHashInput{
304 wireFormat: authContent.wireFormat,
305 content: authContent.content,
306 signature: authContent.auth.signature,
307 }
308 }
309
310 func (authContent *authenticatedContent) framedContentTBS(ctx *groupContext) *framedContentTBS {
311 return &framedContentTBS{
312 version: protocolVersionMLS10,
313 wireFormat: authContent.wireFormat,
314 content: authContent.content,
315 context: ctx,
316 }
317 }
318
319 func (authContent *authenticatedContent) verifySignature(verifKey signaturePublicKey, ctx *groupContext) bool {
320 return authContent.auth.verifySignature(ctx.cipherSuite, verifKey, authContent.framedContentTBS(ctx))
321 }
322
323 func (authContent *authenticatedContent) generateProposalRef(cs CipherSuite) (proposalRef, error) {
324 if authContent.content.contentType != contentTypeProposal {
325 panic("mls: AuthenticatedContent is not a proposal")
326 }
327
328 var b cryptobyte.Builder
329 authContent.marshal(&b)
330 raw, err := b.Bytes()
331 if err != nil {
332 return nil, err
333 }
334
335 hash, err := cs.refHash([]byte("MLS 1.0 Proposal Reference"), raw)
336 if err != nil {
337 return nil, err
338 }
339
340 return proposalRef(hash), nil
341 }
342
343 type framedContentAuthData struct {
344 signature []byte
345 confirmationTag []byte // for contentTypeCommit
346 }
347
348 func (authData *framedContentAuthData) unmarshal(s *cryptobyte.String, ct contentType) error {
349 *authData = framedContentAuthData{}
350
351 if !readOpaqueVec(s, &authData.signature) {
352 return io.ErrUnexpectedEOF
353 }
354
355 if ct == contentTypeCommit {
356 if !readOpaqueVec(s, &authData.confirmationTag) {
357 return io.ErrUnexpectedEOF
358 }
359 }
360
361 return nil
362 }
363
364 func (authData *framedContentAuthData) marshal(b *cryptobyte.Builder, ct contentType) {
365 writeOpaqueVec(b, authData.signature)
366
367 if ct == contentTypeCommit {
368 writeOpaqueVec(b, authData.confirmationTag)
369 }
370 }
371
372 func (authData *framedContentAuthData) verifyConfirmationTag(cs CipherSuite, confirmationKey, confirmedTranscriptHash []byte) bool {
373 if len(authData.confirmationTag) == 0 {
374 return false
375 }
376 return cs.verifyMAC(confirmationKey, confirmedTranscriptHash, authData.confirmationTag)
377 }
378
379 func (authData *framedContentAuthData) verifySignature(cs CipherSuite, verifKey signaturePublicKey, content *framedContentTBS) bool {
380 rawContent, err := marshal(content)
381 if err != nil {
382 return false
383 }
384 return cs.verifyWithLabel(verifKey, []byte("FramedContentTBS"), rawContent, authData.signature)
385 }
386
387 func signFramedContent(cs CipherSuite, signKey signaturePrivateKey, content *framedContentTBS) ([]byte, error) {
388 rawContent, err := marshal(content)
389 if err != nil {
390 return nil, err
391 }
392 return cs.signWithLabel(signKey, []byte("FramedContentTBS"), rawContent)
393 }
394
395 type framedContentTBS struct {
396 version protocolVersion
397 wireFormat wireFormat
398 content framedContent
399 context *groupContext // for senderTypeMember and senderTypeNewMemberCommit
400 }
401
402 func (content *framedContentTBS) marshal(b *cryptobyte.Builder) {
403 b.AddUint16(uint16(content.version))
404 content.wireFormat.marshal(b)
405 content.content.marshal(b)
406 switch content.content.sender.senderType {
407 case senderTypeMember, senderTypeNewMemberCommit:
408 content.context.marshal(b)
409 }
410 }
411
412 type publicMessage struct {
413 content framedContent
414 auth framedContentAuthData
415 membershipTag []byte // for senderTypeMember
416 }
417
418 func signPublicMessage(cs CipherSuite, signKey signaturePrivateKey, content *framedContent, ctx *groupContext) (*publicMessage, error) {
419 authContent, err := signAuthenticatedContent(cs, signKey, wireFormatMLSPublicMessage, content, ctx)
420 if err != nil {
421 return nil, err
422 }
423 return &publicMessage{
424 content: authContent.content,
425 auth: authContent.auth,
426 }, nil
427 }
428
429 func (msg *publicMessage) unmarshal(s *cryptobyte.String) error {
430 *msg = publicMessage{}
431
432 if err := msg.content.unmarshal(s); err != nil {
433 return err
434 }
435 if err := msg.auth.unmarshal(s, msg.content.contentType); err != nil {
436 return err
437 }
438
439 if msg.content.sender.senderType == senderTypeMember {
440 if !readOpaqueVec(s, &msg.membershipTag) {
441 return io.ErrUnexpectedEOF
442 }
443 }
444
445 return nil
446 }
447
448 func (msg *publicMessage) marshal(b *cryptobyte.Builder) {
449 msg.content.marshal(b)
450 msg.auth.marshal(b, msg.content.contentType)
451
452 if msg.content.sender.senderType == senderTypeMember {
453 writeOpaqueVec(b, msg.membershipTag)
454 }
455 }
456
457 func (msg *publicMessage) authenticatedContent() *authenticatedContent {
458 return &authenticatedContent{
459 wireFormat: wireFormatMLSPublicMessage,
460 content: msg.content,
461 auth: msg.auth,
462 }
463 }
464
465 func (msg *publicMessage) authenticatedContentTBM(ctx *groupContext) *authenticatedContentTBM {
466 return &authenticatedContentTBM{
467 contentTBS: *msg.authenticatedContent().framedContentTBS(ctx),
468 auth: msg.auth,
469 }
470 }
471
472 func (msg *publicMessage) signMembershipTag(cs CipherSuite, membershipKey []byte, ctx *groupContext) error {
473 if msg.content.sender.senderType != senderTypeMember {
474 return nil
475 }
476 rawAuthContentTBM, err := marshal(msg.authenticatedContentTBM(ctx))
477 if err != nil {
478 return err
479 }
480 msg.membershipTag = cs.signMAC(membershipKey, rawAuthContentTBM)
481 return nil
482 }
483
484 func (msg *publicMessage) verifyMembershipTag(membershipKey []byte, ctx *groupContext) bool {
485 if msg.content.sender.senderType != senderTypeMember {
486 return true // there is no membership tag
487 }
488 rawAuthContentTBM, err := marshal(msg.authenticatedContentTBM(ctx))
489 if err != nil {
490 return false
491 }
492 return ctx.cipherSuite.verifyMAC(membershipKey, rawAuthContentTBM, msg.membershipTag)
493 }
494
495 type authenticatedContentTBM struct {
496 contentTBS framedContentTBS
497 auth framedContentAuthData
498 }
499
500 func (tbm *authenticatedContentTBM) marshal(b *cryptobyte.Builder) {
501 tbm.contentTBS.marshal(b)
502 tbm.auth.marshal(b, tbm.contentTBS.content.contentType)
503 }
504
505 type privateMessage struct {
506 groupID GroupID
507 epoch uint64
508 contentType contentType
509 authenticatedData []byte
510 encryptedSenderData []byte
511 ciphertext []byte
512 }
513
514 func encryptPrivateMessage(cs CipherSuite, secret ratchetSecret, senderDataSecret []byte, content *framedContent, privContent *privateMessageContent, senderData *senderData) (*privateMessage, error) {
515 ciphertext, err := encryptPrivateMessageContent(cs, secret, content, privContent, senderData.reuseGuard)
516 if err != nil {
517 return nil, err
518 }
519 encryptedSenderData, err := encryptSenderData(cs, senderDataSecret, senderData, content, ciphertext)
520 if err != nil {
521 return nil, err
522 }
523 return &privateMessage{
524 groupID: content.groupID,
525 epoch: content.epoch,
526 contentType: content.contentType,
527 authenticatedData: content.authenticatedData,
528 encryptedSenderData: encryptedSenderData,
529 ciphertext: ciphertext,
530 }, nil
531 }
532
533 func (msg *privateMessage) unmarshal(s *cryptobyte.String) error {
534 *msg = privateMessage{}
535 ok := readOpaqueVec(s, (*[]byte)(&msg.groupID)) &&
536 s.ReadUint64(&msg.epoch)
537 if !ok {
538 return io.ErrUnexpectedEOF
539 }
540 if err := msg.contentType.unmarshal(s); err != nil {
541 return err
542 }
543 ok = readOpaqueVec(s, &msg.authenticatedData) &&
544 readOpaqueVec(s, &msg.encryptedSenderData) &&
545 readOpaqueVec(s, &msg.ciphertext)
546 if !ok {
547 return io.ErrUnexpectedEOF
548 }
549 return nil
550 }
551
552 func (msg *privateMessage) marshal(b *cryptobyte.Builder) {
553 writeOpaqueVec(b, []byte(msg.groupID))
554 b.AddUint64(msg.epoch)
555 msg.contentType.marshal(b)
556 writeOpaqueVec(b, msg.authenticatedData)
557 writeOpaqueVec(b, msg.encryptedSenderData)
558 writeOpaqueVec(b, msg.ciphertext)
559 }
560
561 func (msg *privateMessage) decryptSenderData(cs CipherSuite, senderDataSecret []byte) (*senderData, error) {
562 key, err := expandSenderDataKey(cs, senderDataSecret, msg.ciphertext)
563 if err != nil {
564 return nil, err
565 }
566 nonce, err := expandSenderDataNonce(cs, senderDataSecret, msg.ciphertext)
567 if err != nil {
568 return nil, err
569 }
570
571 aad := senderDataAAD{
572 groupID: msg.groupID,
573 epoch: msg.epoch,
574 contentType: msg.contentType,
575 }
576 rawAAD, err := marshal(&aad)
577 if err != nil {
578 return nil, err
579 }
580
581 _, _, aead := cs.hpke().Params()
582 cipher, err := aead.New(key)
583 if err != nil {
584 return nil, err
585 }
586
587 rawSenderData, err := cipher.Open(nil, nonce, msg.encryptedSenderData, rawAAD)
588 if err != nil {
589 return nil, err
590 }
591
592 var senderData senderData
593 if err := unmarshal(rawSenderData, &senderData); err != nil {
594 return nil, err
595 }
596
597 return &senderData, nil
598 }
599
600 func (msg *privateMessage) decryptContent(cs CipherSuite, secret ratchetSecret, reuseGuard [4]byte) (*privateMessageContent, error) {
601 key, nonce, err := derivePrivateMessageKeyAndNonce(cs, secret, reuseGuard)
602 if err != nil {
603 return nil, err
604 }
605
606 aad := privateContentAAD{
607 groupID: msg.groupID,
608 epoch: msg.epoch,
609 contentType: msg.contentType,
610 authenticatedData: msg.authenticatedData,
611 }
612 rawAAD, err := marshal(&aad)
613 if err != nil {
614 return nil, err
615 }
616
617 _, _, aead := cs.hpke().Params()
618 cipher, err := aead.New(key)
619 if err != nil {
620 return nil, err
621 }
622
623 rawContent, err := cipher.Open(nil, nonce, msg.ciphertext, rawAAD)
624 if err != nil {
625 return nil, err
626 }
627
628 s := cryptobyte.String(rawContent)
629 var content privateMessageContent
630 if err := content.unmarshal(&s, msg.contentType); err != nil {
631 return nil, err
632 }
633
634 for _, v := range s {
635 if v != 0 {
636 return nil, fmt.Errorf("mls: padding contains non-zero bytes")
637 }
638 }
639
640 return &content, nil
641 }
642
643 func derivePrivateMessageKeyAndNonce(cs CipherSuite, secret ratchetSecret, reuseGuard [4]byte) (key, nonce []byte, err error) {
644 key, err = secret.deriveKey(cs)
645 if err != nil {
646 return nil, nil, err
647 }
648 nonce, err = secret.deriveNonce(cs)
649 if err != nil {
650 return nil, nil, err
651 }
652
653 for i := range reuseGuard {
654 nonce[i] = nonce[i] ^ reuseGuard[i]
655 }
656
657 return key, nonce, nil
658 }
659
660 func (msg *privateMessage) authenticatedContent(senderData *senderData, content *privateMessageContent) *authenticatedContent {
661 return content.authenticatedContent(&framedContent{
662 groupID: msg.groupID,
663 epoch: msg.epoch,
664 sender: sender{
665 senderType: senderTypeMember,
666 leafIndex: senderData.leafIndex,
667 },
668 authenticatedData: msg.authenticatedData,
669 contentType: msg.contentType,
670 applicationData: content.applicationData,
671 proposal: content.proposal,
672 commit: content.commit,
673 })
674 }
675
676 type senderDataAAD struct {
677 groupID GroupID
678 epoch uint64
679 contentType contentType
680 }
681
682 func (aad *senderDataAAD) marshal(b *cryptobyte.Builder) {
683 writeOpaqueVec(b, []byte(aad.groupID))
684 b.AddUint64(aad.epoch)
685 aad.contentType.marshal(b)
686 }
687
688 type privateContentAAD struct {
689 groupID GroupID
690 epoch uint64
691 contentType contentType
692 authenticatedData []byte
693 }
694
695 func (aad *privateContentAAD) marshal(b *cryptobyte.Builder) {
696 writeOpaqueVec(b, []byte(aad.groupID))
697 b.AddUint64(aad.epoch)
698 aad.contentType.marshal(b)
699 writeOpaqueVec(b, aad.authenticatedData)
700 }
701
702 type privateMessageContent struct {
703 applicationData []byte // for contentTypeApplication
704 proposal *proposal // for contentTypeProposal
705 commit *commit // for contentTypeCommit
706
707 auth framedContentAuthData
708 }
709
710 func (content *privateMessageContent) unmarshal(s *cryptobyte.String, ct contentType) error {
711 *content = privateMessageContent{}
712
713 var err error
714 switch ct {
715 case contentTypeApplication:
716 if !readOpaqueVec(s, &content.applicationData) {
717 err = io.ErrUnexpectedEOF
718 }
719 case contentTypeProposal:
720 content.proposal = new(proposal)
721 err = content.proposal.unmarshal(s)
722 case contentTypeCommit:
723 content.commit = new(commit)
724 err = content.commit.unmarshal(s)
725 default:
726 panic("unreachable")
727 }
728 if err != nil {
729 return err
730 }
731
732 return content.auth.unmarshal(s, ct)
733 }
734
735 func (content *privateMessageContent) marshal(b *cryptobyte.Builder, ct contentType) {
736 switch ct {
737 case contentTypeApplication:
738 writeOpaqueVec(b, content.applicationData)
739 case contentTypeProposal:
740 content.proposal.marshal(b)
741 case contentTypeCommit:
742 content.commit.marshal(b)
743 default:
744 panic("unreachable")
745 }
746 content.auth.marshal(b, ct)
747 }
748
749 func (content *privateMessageContent) authenticatedContent(framedContent *framedContent) *authenticatedContent {
750 return &authenticatedContent{
751 wireFormat: wireFormatMLSPrivateMessage,
752 content: *framedContent,
753 auth: content.auth,
754 }
755 }
756
757 func signPrivateMessageContent(cs CipherSuite, signKey signaturePrivateKey, content *framedContent, ctx *groupContext) (*privateMessageContent, error) {
758 authContent, err := signAuthenticatedContent(cs, signKey, wireFormatMLSPrivateMessage, content, ctx)
759 if err != nil {
760 return nil, err
761 }
762
763 return &privateMessageContent{
764 applicationData: content.applicationData,
765 proposal: content.proposal,
766 commit: content.commit,
767 auth: authContent.auth,
768 }, nil
769 }
770
771 func encryptPrivateMessageContent(cs CipherSuite, secret ratchetSecret, content *framedContent, privContent *privateMessageContent, reuseGuard [4]byte) ([]byte, error) {
772 var b cryptobyte.Builder
773 privContent.marshal(&b, content.contentType)
774 plaintext, err := b.Bytes()
775 if err != nil {
776 return nil, err
777 }
778
779 key, nonce, err := derivePrivateMessageKeyAndNonce(cs, secret, reuseGuard)
780 if err != nil {
781 return nil, err
782 }
783
784 aad := privateContentAAD{
785 groupID: content.groupID,
786 epoch: content.epoch,
787 contentType: content.contentType,
788 authenticatedData: content.authenticatedData,
789 }
790 rawAAD, err := marshal(&aad)
791 if err != nil {
792 return nil, err
793 }
794
795 _, _, aead := cs.hpke().Params()
796 cipher, err := aead.New(key)
797 if err != nil {
798 return nil, err
799 }
800
801 return cipher.Seal(nil, nonce, plaintext, rawAAD), nil
802 }
803
804 func encryptSenderData(cs CipherSuite, senderDataSecret []byte, senderData *senderData, content *framedContent, ciphertext []byte) ([]byte, error) {
805 key, err := expandSenderDataKey(cs, senderDataSecret, ciphertext)
806 if err != nil {
807 return nil, err
808 }
809 nonce, err := expandSenderDataNonce(cs, senderDataSecret, ciphertext)
810 if err != nil {
811 return nil, err
812 }
813
814 aad := senderDataAAD{
815 groupID: content.groupID,
816 epoch: content.epoch,
817 contentType: content.contentType,
818 }
819 rawAAD, err := marshal(&aad)
820 if err != nil {
821 return nil, err
822 }
823
824 _, _, aead := cs.hpke().Params()
825 cipher, err := aead.New(key)
826 if err != nil {
827 return nil, err
828 }
829
830 rawSenderData, err := marshal(senderData)
831 if err != nil {
832 return nil, err
833 }
834
835 return cipher.Seal(nil, nonce, rawSenderData, rawAAD), nil
836 }
837
838 type senderData struct {
839 leafIndex leafIndex
840 generation uint32
841 reuseGuard [4]byte
842 }
843
844 func newSenderData(leafIndex leafIndex, generation uint32) (*senderData, error) {
845 data := senderData{
846 leafIndex: leafIndex,
847 generation: generation,
848 }
849 if _, err := rand.Read(data.reuseGuard[:]); err != nil {
850 return nil, err
851 }
852 return &data, nil
853 }
854
855 func (data *senderData) unmarshal(s *cryptobyte.String) error {
856 if !s.ReadUint32((*uint32)(&data.leafIndex)) || !s.ReadUint32(&data.generation) || !s.CopyBytes(data.reuseGuard[:]) {
857 return io.ErrUnexpectedEOF
858 }
859 return nil
860 }
861
862 func (data *senderData) marshal(b *cryptobyte.Builder) {
863 b.AddUint32(uint32(data.leafIndex))
864 b.AddUint32(data.generation)
865 b.AddBytes(data.reuseGuard[:])
866 }
867
868 func expandSenderDataKey(cs CipherSuite, senderDataSecret, ciphertext []byte) ([]byte, error) {
869 _, _, aead := cs.hpke().Params()
870 ciphertextSample := sampleCiphertext(cs, ciphertext)
871 return cs.expandWithLabel(senderDataSecret, []byte("key"), ciphertextSample, uint16(aead.KeySize()))
872 }
873
874 func expandSenderDataNonce(cs CipherSuite, senderDataSecret, ciphertext []byte) ([]byte, error) {
875 _, _, aead := cs.hpke().Params()
876 ciphertextSample := sampleCiphertext(cs, ciphertext)
877 return cs.expandWithLabel(senderDataSecret, []byte("nonce"), ciphertextSample, uint16(aead.NonceSize()))
878 }
879
880 func sampleCiphertext(cs CipherSuite, ciphertext []byte) []byte {
881 _, kdf, _ := cs.hpke().Params()
882 n := kdf.ExtractSize()
883 if len(ciphertext) < n {
884 return ciphertext
885 }
886 return ciphertext[:n]
887 }
888