1// Copyright 2016 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package chat
5
6import (
7	"bytes"
8	"crypto/hmac"
9	"crypto/rand"
10	"crypto/sha256"
11	"encoding/binary"
12	"encoding/hex"
13	"errors"
14	"flag"
15	"fmt"
16	"sort"
17	"sync"
18	"time"
19
20	"golang.org/x/crypto/nacl/box"
21	"golang.org/x/crypto/nacl/secretbox"
22	"golang.org/x/net/context"
23	"golang.org/x/sync/errgroup"
24
25	"github.com/keybase/client/go/chat/globals"
26	"github.com/keybase/client/go/chat/signencrypt"
27	"github.com/keybase/client/go/chat/storage"
28	"github.com/keybase/client/go/chat/types"
29	"github.com/keybase/client/go/chat/utils"
30	"github.com/keybase/client/go/ephemeral"
31	"github.com/keybase/client/go/kbcrypto"
32	"github.com/keybase/client/go/libkb"
33	"github.com/keybase/client/go/logger"
34	"github.com/keybase/client/go/protocol/chat1"
35	"github.com/keybase/client/go/protocol/gregor1"
36	"github.com/keybase/client/go/protocol/keybase1"
37	"github.com/keybase/client/go/teambot"
38	"github.com/keybase/client/go/teams"
39	"github.com/keybase/clockwork"
40	"github.com/keybase/go-codec/codec"
41	"github.com/keybase/go-crypto/ed25519"
42)
43
44const CurrentMessageBoxedVersion = chat1.MessageBoxedVersion_V2
45
46var publicCryptKey keybase1.CryptKey
47
48func init() {
49	// publicCryptKey is a zero key used for public chat messages.
50	var zero [libkb.NaclDHKeySecretSize]byte
51	publicCryptKey = keybase1.CryptKey{
52		KeyGeneration: 1,
53		Key:           keybase1.Bytes32(zero),
54	}
55}
56
57type Boxer struct {
58	utils.DebugLabeler
59	globals.Contextified
60
61	boxVersionForTesting *chat1.MessageBoxedVersion
62
63	// Replaceable for testing.
64	// Normally set to normal implementations.
65	hashV1 func(data []byte) chat1.Hash
66
67	// Slots for replacing with test implementations.
68	// These are normally nil.
69	testingValidSenderKey     func(context.Context, gregor1.UID, []byte, gregor1.Time) (revoked *gregor1.Time, unboxingErr types.UnboxingError)
70	testingGetSenderInfoLocal func(context.Context, gregor1.UID, gregor1.DeviceID) (senderUsername string, senderDeviceName string, senderDeviceType keybase1.DeviceTypeV2)
71	// Post-process signatures and signencrypts
72	testingSignatureMangle func([]byte) []byte
73
74	clock clockwork.Clock
75}
76
77func NewBoxer(g *globals.Context) *Boxer {
78	return &Boxer{
79		DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "Boxer", false),
80		hashV1:       hashSha256V1,
81		Contextified: globals.NewContextified(g),
82		clock:        clockwork.NewRealClock(),
83	}
84}
85
86func (b *Boxer) SetClock(clock clockwork.Clock) {
87	b.clock = clock
88}
89
90func (b *Boxer) log() logger.Logger {
91	return b.G().GetLog()
92}
93
94func (b *Boxer) makeErrorMessageFromPieces(ctx context.Context, err types.UnboxingError,
95	msgID chat1.MessageID, msgType chat1.MessageType, ctime gregor1.Time,
96	sender gregor1.UID, senderDevice gregor1.DeviceID, botUID *gregor1.UID,
97	isEphemeral bool, explodedBy *string, etime gregor1.Time) chat1.MessageUnboxed {
98	e := chat1.MessageUnboxedError{
99		ErrType:        err.ExportType(),
100		ErrMsg:         err.Error(),
101		InternalErrMsg: err.InternalError(),
102		VersionKind:    err.VersionKind(),
103		VersionNumber:  err.VersionNumber(),
104		IsCritical:     err.IsCritical(),
105		MessageID:      msgID,
106		MessageType:    msgType,
107		Ctime:          ctime,
108		IsEphemeral:    isEphemeral,
109		ExplodedBy:     explodedBy,
110		Etime:          etime,
111		BotUsername:    b.getBotInfoLocal(ctx, botUID),
112	}
113	e.SenderUsername, e.SenderDeviceName, e.SenderDeviceType = b.getSenderInfoLocal(ctx,
114		sender, senderDevice)
115	return chat1.NewMessageUnboxedWithError(e)
116}
117
118func (b *Boxer) makeErrorMessage(ctx context.Context, msg chat1.MessageBoxed, err types.UnboxingError) chat1.MessageUnboxed {
119	return b.makeErrorMessageFromPieces(ctx, err, msg.GetMessageID(), msg.GetMessageType(),
120		msg.ServerHeader.Ctime, msg.ClientHeader.Sender, msg.ClientHeader.SenderDevice,
121		msg.ClientHeader.BotUID,
122		msg.IsEphemeral(), msg.ExplodedBy(), msg.Etime())
123}
124
125func (b *Boxer) detectPermanentError(conv types.UnboxConversationInfo, err error, tlfName string) types.UnboxingError {
126	// Check for team not exist error that is in raw form
127	if aerr, ok := err.(libkb.AppStatusError); ok {
128		switch keybase1.StatusCode(aerr.Code) {
129		case keybase1.StatusCode_SCTeamNotFound:
130			return NewPermanentUnboxingError(err)
131		default:
132			// Nothing to do.
133		}
134	}
135
136	if _, ok := IsRekeyError(err); ok && conv.GetFinalizeInfo() != nil {
137		return NewPermanentUnboxingError(err)
138	}
139
140	// Check if we have a permanent or tranisent team read error. Transient
141	// errors, are converted to rekey errors later.
142	if teams.IsTeamReadError(err) {
143		switch err.Error() {
144		case "Root team has been deleted",
145			"Root team has been abandoned: All members have left or reset",
146			"Root team is not active":
147			return NewPermanentUnboxingError(err)
148		default:
149			return NewTransientUnboxingError(err)
150		}
151	}
152	switch err := err.(type) {
153	case libkb.UserDeletedError:
154		if len(err.Msg) == 0 {
155			err.Msg = fmt.Sprintf("user deleted in chat '%v'", tlfName)
156		}
157		return NewPermanentUnboxingError(err)
158	case teams.TeamDoesNotExistError,
159		teams.KBFSKeyGenerationError,
160		libkb.KeyMaskNotFoundError,
161		libkb.AssertionCheckError,
162		DecryptionKeyNotFoundError,
163		NotAuthenticatedForThisDeviceError,
164		InvalidMACError,
165		ImpteamBadteamError,
166		teambot.TeambotPermanentKeyError:
167		return NewPermanentUnboxingError(err)
168	case ephemeral.EphemeralKeyError:
169		// Normalize error message with EphemeralUnboxingError
170		ekErr := NewEphemeralUnboxingError(err)
171		if err.IsPermanent() {
172			return NewPermanentUnboxingError(ekErr)
173		}
174		return NewTransientUnboxingError(ekErr)
175	}
176
177	// Check for no space left on device errors
178	if libkb.IsNoSpaceOnDeviceError(err) {
179		return NewPermanentUnboxingError(err)
180	}
181
182	// transient error. Rekey errors come through here
183	return NewTransientUnboxingError(err)
184}
185
186type basicUnboxConversationInfo struct {
187	convID       chat1.ConversationID
188	membersType  chat1.ConversationMembersType
189	finalizeInfo *chat1.ConversationFinalizeInfo
190	visibility   keybase1.TLFVisibility
191}
192
193var _ types.UnboxConversationInfo = (*basicUnboxConversationInfo)(nil)
194
195func newBasicUnboxConversationInfo(convID chat1.ConversationID,
196	membersType chat1.ConversationMembersType, finalizeInfo *chat1.ConversationFinalizeInfo,
197	visibility keybase1.TLFVisibility) *basicUnboxConversationInfo {
198	return &basicUnboxConversationInfo{
199		convID:       convID,
200		membersType:  membersType,
201		finalizeInfo: finalizeInfo,
202		visibility:   visibility,
203	}
204}
205
206func (b *basicUnboxConversationInfo) GetConvID() chat1.ConversationID {
207	return b.convID
208}
209
210func (b *basicUnboxConversationInfo) GetMembersType() chat1.ConversationMembersType {
211	return b.membersType
212}
213
214func (b *basicUnboxConversationInfo) GetFinalizeInfo() *chat1.ConversationFinalizeInfo {
215	return b.finalizeInfo
216}
217
218func (b *basicUnboxConversationInfo) GetExpunge() *chat1.Expunge {
219	return nil
220}
221
222func (b *basicUnboxConversationInfo) GetMaxDeletedUpTo() chat1.MessageID {
223	return 0
224}
225
226func (b *basicUnboxConversationInfo) IsPublic() bool {
227	return b.visibility == keybase1.TLFVisibility_PUBLIC
228}
229
230func (b *basicUnboxConversationInfo) GetMaxMessage(chat1.MessageType) (chat1.MessageSummary, error) {
231	return chat1.MessageSummary{}, nil
232}
233
234type extraInboxUnboxConversationInfo struct {
235	convID      chat1.ConversationID
236	membersType chat1.ConversationMembersType
237	visibility  keybase1.TLFVisibility
238}
239
240var _ types.UnboxConversationInfo = (*extraInboxUnboxConversationInfo)(nil)
241
242func newExtraInboxUnboxConverstionInfo(convID chat1.ConversationID, membersType chat1.ConversationMembersType,
243	visibility keybase1.TLFVisibility) *extraInboxUnboxConversationInfo {
244	return &extraInboxUnboxConversationInfo{
245		convID:      convID,
246		membersType: membersType,
247		visibility:  visibility,
248	}
249}
250
251func (p *extraInboxUnboxConversationInfo) GetConvID() chat1.ConversationID {
252	return p.convID
253}
254
255func (p *extraInboxUnboxConversationInfo) GetMembersType() chat1.ConversationMembersType {
256	return p.membersType
257}
258
259func (p *extraInboxUnboxConversationInfo) GetFinalizeInfo() *chat1.ConversationFinalizeInfo {
260	return nil
261}
262
263func (p *extraInboxUnboxConversationInfo) GetExpunge() *chat1.Expunge {
264	return nil
265}
266
267func (p *extraInboxUnboxConversationInfo) GetMaxDeletedUpTo() chat1.MessageID {
268	return 0
269}
270
271func (p *extraInboxUnboxConversationInfo) IsPublic() bool {
272	return p.visibility == keybase1.TLFVisibility_PUBLIC
273}
274
275func (p *extraInboxUnboxConversationInfo) GetMaxMessage(chat1.MessageType) (chat1.MessageSummary, error) {
276	return chat1.MessageSummary{}, nil
277}
278
279func (b *Boxer) getEffectiveMembersType(ctx context.Context, boxed chat1.MessageBoxed,
280	convMembersType chat1.ConversationMembersType) chat1.ConversationMembersType {
281	switch convMembersType {
282	case chat1.ConversationMembersType_IMPTEAMUPGRADE:
283		if boxed.KBFSEncrypted() {
284			b.Debug(ctx, "getEffectiveMembersType: overruling %v conv with KBFS keys", convMembersType)
285			return chat1.ConversationMembersType_KBFS
286		}
287	default:
288		// Nothing to do for other conv types.
289	}
290	return convMembersType
291}
292
293var errBoxerUnavailableMessage = NewPermanentUnboxingError(errors.New("message not available"))
294
295func (b *Boxer) castInternalError(ierr types.UnboxingError) error {
296	err, ok := ierr.(error)
297	if ok {
298		return err
299	}
300	return nil
301}
302
303// UnboxMessage unboxes a chat1.MessageBoxed into a chat1.MessageUnboxed. It
304// finds the appropriate keybase1.CryptKey, decrypts the message, and verifies
305// several things:
306//   - The message's signature is valid.
307//   - (TODO) The signing KID was valid when the signature was made.
308//   - (TODO) The signing KID belongs to the sending device.
309//   - (TODO) The sending device belongs to the sender.
310//     [Note that we do currently check the KID -> UID relationship,
311//     independent of the device ID.]
312//   - (TODO) The sender has write permission in the TLF.
313//   - (TODO) The TLF name, public flag, and finalized info resolve to the TLF ID.
314//   - The conversation ID derives from the ConversationIDTriple.
315//   - The body hash is not a replay from another message we know about.
316//   - The prev pointers are consistent with other messages we know about.
317//   - (TODO) The prev pointers are not absurdly ancient.
318//   - The ClientHeader provided with the BoxedMessage matches the one we decrypt.
319//
320// The first return value is unusable if the err != nil. Returns (_, err) for
321// non-permanent errors, and (MessageUnboxedError, nil) for permanent errors.
322// Permanent errors can be cached and must be treated as a value to deal with,
323// whereas temporary errors are transient failures.
324func (b *Boxer) UnboxMessage(ctx context.Context, boxed chat1.MessageBoxed, conv types.UnboxConversationInfo,
325	info *types.BoxerEncryptionInfo) (m chat1.MessageUnboxed, uberr types.UnboxingError) {
326	ctx = libkb.WithLogTag(ctx, "CHTUNBOX")
327	var err error
328	defer b.Trace(ctx, &err, "UnboxMessage(%s, %d)", conv.GetConvID(),
329		boxed.GetMessageID())()
330	defer func() { err = b.castInternalError(uberr) }()
331
332	// Check to see if the context has been cancelled
333	select {
334	case <-ctx.Done():
335		return m, NewTransientUnboxingError(ctx.Err())
336	default:
337	}
338
339	// if the server message doesn't have a TLFID, then it isn't available to us. This is most commonly
340	// used when restricted bots try to read messages not encrypted for them.
341	if boxed.ClientHeader.Conv.Tlfid.IsNil() {
342		return b.makeErrorMessage(ctx, boxed, errBoxerUnavailableMessage), nil
343	}
344
345	// If we don't have an rtime, add one.
346	if boxed.ServerHeader.Rtime == nil {
347		now := gregor1.ToTime(b.clock.Now())
348		boxed.ServerHeader.Rtime = &now
349	}
350	tlfName := boxed.ClientHeader.TLFNameExpanded(conv.GetFinalizeInfo())
351	if conv.IsPublic() != boxed.ClientHeader.TlfPublic {
352		return b.makeErrorMessage(ctx, boxed,
353			NewPermanentUnboxingError(fmt.Errorf("visibility mismatch: %v != %v", conv.IsPublic(),
354				boxed.ClientHeader.TlfPublic))), nil
355	}
356	if info == nil {
357		info = new(types.BoxerEncryptionInfo)
358		keyMembersType := b.getEffectiveMembersType(ctx, boxed, conv.GetMembersType())
359		encryptionKey, err := globals.CtxKeyFinder(ctx, b.G()).FindForDecryption(ctx,
360			tlfName, boxed.ClientHeader.Conv.Tlfid, conv.GetMembersType(),
361			conv.IsPublic(), boxed.KeyGeneration,
362			keyMembersType == chat1.ConversationMembersType_KBFS, boxed.ClientHeader.BotUID)
363		if err != nil {
364			// Post-process error from this
365			uberr = b.detectPermanentError(conv, err, tlfName)
366			if uberr.IsPermanent() {
367				return b.makeErrorMessage(ctx, boxed, uberr), nil
368			}
369			return chat1.MessageUnboxed{}, uberr
370		}
371
372		// If the message is exploding, load the ephemeral key.
373		var ephemeralKey types.EphemeralCryptKey
374		if boxed.IsEphemeral() {
375			ephemeralKey, err = globals.CtxKeyFinder(ctx, b.G()).EphemeralKeyForDecryption(
376				b.G().MetaContext(ctx), tlfName, boxed.ClientHeader.Conv.Tlfid, conv.GetMembersType(),
377				boxed.ClientHeader.TlfPublic, boxed.ClientHeader.BotUID,
378				boxed.EphemeralMetadata().Generation, &boxed.ServerHeader.Ctime)
379			if err != nil {
380				b.Debug(ctx, "failed to get a key for ephemeral message: msgID: %d err: %v", boxed.ServerHeader.MessageID, err)
381				uberr = b.detectPermanentError(conv, err, tlfName)
382				if uberr.IsPermanent() {
383					return b.makeErrorMessage(ctx, boxed, uberr), nil
384				}
385				return chat1.MessageUnboxed{}, uberr
386			}
387		}
388		info.Key = encryptionKey
389		info.EphemeralKey = ephemeralKey
390	}
391
392	unboxed, ierr := b.unbox(ctx, boxed, conv, info.Key, info.EphemeralKey)
393	if ierr == nil {
394		ierr = b.checkInvariants(ctx, conv.GetConvID(), boxed, unboxed)
395	}
396	if ierr != nil {
397		b.Debug(ctx, "failed to unbox message: msgID: %d err: %s", boxed.ServerHeader.MessageID,
398			ierr.Error())
399		if ierr.IsPermanent() {
400			return b.makeErrorMessage(ctx, boxed, ierr), nil
401		}
402		return chat1.MessageUnboxed{}, ierr
403	}
404	return chat1.NewMessageUnboxedWithValid(*unboxed), nil
405}
406
407func (b *Boxer) checkInvariants(ctx context.Context, convID chat1.ConversationID, boxed chat1.MessageBoxed, unboxed *chat1.MessageUnboxedValid) types.UnboxingError {
408	// Check that the ConversationIDTriple in the signed message header matches
409	// the conversation ID we were expecting.
410	if !unboxed.ClientHeader.Conv.Derivable(convID) {
411		err := fmt.Errorf("conversation ID mismatch: header: %x convID: %s",
412			unboxed.ClientHeader.Conv.Hash(), convID)
413		return NewPermanentUnboxingError(err)
414	}
415
416	// Check that message type on the client header matches the body
417	body := unboxed.MessageBody
418	if !body.IsNil() {
419		bodyTyp, err := body.MessageType()
420		if err != nil {
421			return NewPermanentUnboxingError(err)
422		}
423		if unboxed.ClientHeader.MessageType != bodyTyp {
424			err := fmt.Errorf("client header message type does not match body: %v(header) != %v(body)",
425				unboxed.ClientHeader.MessageType, bodyTyp)
426			return NewPermanentUnboxingError(err)
427		}
428	}
429
430	// Make sure the body hash is unique to this message, and then record it.
431	// This detects attempts by the server to replay a message. Right now we
432	// use a "first writer wins" rule here, though we could also consider a
433	// "duplication invalidates both" rule if we wanted to be stricter. Note
434	// that this only prevents replays of messages you *know about*. There's
435	// currently nothing stopping the server from replaying an ancient message
436	// if you're never going to fetch enough history to notice.
437	//
438	// But...wait...why aren't we using the header hash here? It covers more
439	// stuff, and we're using it below, when we check the consistency of
440	// messages and prev pointers...
441	//
442	// The reason we can't use the header hash to prevent replays is that it's
443	// a hash *of* a signature, rather than a hash that's *been signed*.
444	// Unfortunately, most signature schemes are "malleable" in some way,
445	// depending on the implementation. See
446	// http://crypto.stackexchange.com/a/14719/21442. If I have the shared
447	// encryption key (and recall that in public chats, everyone does), I can
448	// decrypt the message, twiddle your signature into another valid signature
449	// over the same plaintext, reencrypt the whole thing, and pass it off as a
450	// new valid message with a seemingly new signature and therefore a unique
451	// header hash. Because the body hash is unique to each message (derived
452	// from a random nonce), and because it's *inside* the signature, we use
453	// that to detect replays instead.
454	replayErr := storage.CheckAndRecordBodyHash(ctx, b.G(), unboxed.BodyHash, boxed.ServerHeader.MessageID, convID)
455	if replayErr != nil {
456		b.Debug(ctx, "UnboxMessage found a replayed body hash: %s", replayErr)
457		return NewPermanentUnboxingError(replayErr)
458	}
459
460	// Make sure the header hash and prev pointers of this message are
461	// consistent with every other message we've seen, and record them.
462	//
463	// The discussion above explains why we have to use the body hash there to
464	// prevent replays. But we need to use the header hash here, because it's
465	// the only thing that covers the entire message. The goal isn't to prevent
466	// the creation of new messages (as it was above), but to prevent an old
467	// message from changing.
468	prevPtrErr := storage.CheckAndRecordPrevPointer(ctx, b.G(), boxed.ServerHeader.MessageID, convID, unboxed.HeaderHash)
469	if prevPtrErr != nil {
470		b.Debug(ctx, "UnboxMessage found an inconsistent header hash: %s", prevPtrErr)
471		return NewPermanentUnboxingError(prevPtrErr)
472	}
473	for _, prevPtr := range unboxed.ClientHeader.Prev {
474		prevPtrErr := storage.CheckAndRecordPrevPointer(ctx, b.G(), prevPtr.Id, convID, prevPtr.Hash)
475		if prevPtrErr != nil {
476			b.Debug(ctx, "UnboxMessage found an inconsistent prev pointer: %s", prevPtrErr)
477			return NewPermanentUnboxingError(prevPtrErr)
478		}
479	}
480
481	return nil
482}
483
484func (b *Boxer) unbox(ctx context.Context, boxed chat1.MessageBoxed,
485	conv types.UnboxConversationInfo, encryptionKey types.CryptKey,
486	ephemeralKey types.EphemeralCryptKey) (*chat1.MessageUnboxedValid, types.UnboxingError) {
487	switch boxed.Version {
488	case chat1.MessageBoxedVersion_VNONE, chat1.MessageBoxedVersion_V1:
489		res, err := b.unboxV1(ctx, boxed, conv, encryptionKey)
490		if err != nil {
491			b.Debug(ctx, "error unboxing message version: %v", boxed.Version)
492		}
493		return res, err
494	// V3 is the same as V2, except that it indicates exploding message support.
495	// V4 is the same as V3, except if pairwise MACs are included, then the sender signing key is a dummy.
496	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
497		res, err := b.unboxV2orV3orV4(ctx, boxed, conv, encryptionKey, ephemeralKey)
498		if err != nil {
499			b.Debug(ctx, "error unboxing message version: %v, %s", boxed.Version, err)
500		}
501		return res, err
502	// NOTE: When adding new versions here, you must also update
503	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
504	// new max version
505	default:
506		return nil,
507			NewPermanentUnboxingError(NewMessageBoxedVersionError(boxed.Version))
508	}
509}
510
511func (b *Boxer) headerUnsupported(ctx context.Context, headerVersion chat1.HeaderPlaintextVersion,
512	header chat1.HeaderPlaintext) chat1.HeaderPlaintextUnsupported {
513	switch headerVersion {
514	case chat1.HeaderPlaintextVersion_V2:
515		return header.V2()
516	case chat1.HeaderPlaintextVersion_V3:
517		return header.V3()
518	case chat1.HeaderPlaintextVersion_V4:
519		return header.V4()
520	case chat1.HeaderPlaintextVersion_V5:
521		return header.V5()
522	case chat1.HeaderPlaintextVersion_V6:
523		return header.V6()
524	case chat1.HeaderPlaintextVersion_V7:
525		return header.V7()
526	case chat1.HeaderPlaintextVersion_V8:
527		return header.V8()
528	case chat1.HeaderPlaintextVersion_V9:
529		return header.V9()
530	case chat1.HeaderPlaintextVersion_V10:
531		return header.V10()
532	default:
533		b.Debug(ctx, "headerUnsupported: unknown version: %v", headerVersion)
534		return chat1.HeaderPlaintextUnsupported{
535			Mi: chat1.HeaderPlaintextMetaInfo{
536				Crit: true,
537			},
538		}
539	}
540}
541
542func (b *Boxer) bodyUnsupported(ctx context.Context, bodyVersion chat1.BodyPlaintextVersion,
543	body chat1.BodyPlaintext) chat1.BodyPlaintextUnsupported {
544	switch bodyVersion {
545	case chat1.BodyPlaintextVersion_V3:
546		return body.V3()
547	case chat1.BodyPlaintextVersion_V4:
548		return body.V4()
549	case chat1.BodyPlaintextVersion_V5:
550		return body.V5()
551	case chat1.BodyPlaintextVersion_V6:
552		return body.V6()
553	case chat1.BodyPlaintextVersion_V7:
554		return body.V7()
555	case chat1.BodyPlaintextVersion_V8:
556		return body.V8()
557	case chat1.BodyPlaintextVersion_V9:
558		return body.V9()
559	case chat1.BodyPlaintextVersion_V10:
560		return body.V10()
561	default:
562		b.Debug(ctx, "bodyUnsupported: unknown version: %v", bodyVersion)
563		return chat1.BodyPlaintextUnsupported{
564			Mi: chat1.BodyPlaintextMetaInfo{
565				Crit: true,
566			},
567		}
568	}
569}
570
571// unboxV1 unboxes a chat1.MessageBoxed into a keybase1.Message given
572// a keybase1.CryptKey.
573func (b *Boxer) unboxV1(ctx context.Context, boxed chat1.MessageBoxed,
574	conv types.UnboxConversationInfo, encryptionKey types.CryptKey) (*chat1.MessageUnboxedValid, types.UnboxingError) {
575	var err error
576	if boxed.ServerHeader == nil {
577		return nil, NewPermanentUnboxingError(errors.New("nil ServerHeader in MessageBoxed"))
578	}
579
580	if len(boxed.VerifyKey) != 0 {
581		return nil, NewPermanentUnboxingError(errors.New("populated VerifyKey in MBV1"))
582	}
583
584	// compute the header hash
585	headerHash := b.hashV1(boxed.HeaderCiphertext.E)
586
587	// Whether the body is missing (deleted)
588	skipBodyVerification := (len(boxed.BodyCiphertext.E) == 0)
589
590	// TODO We should check whether the body is allowed to have been deleted by checking
591	// that there is in fact a message that deleted it.
592	// We should fetch that message and check its signed body.
593	// That involves fetching a message whose ID is not known here.
594
595	// decrypt body
596	// will remain empty if the body was deleted
597	var bodyVersioned chat1.BodyPlaintext
598	if !skipBodyVerification {
599		packedBody, err := b.open(boxed.BodyCiphertext, libkb.NaclSecretBoxKey(encryptionKey.Material()))
600		if err != nil {
601			return nil, NewPermanentUnboxingError(err)
602		}
603		if err := b.unmarshal(packedBody, &bodyVersioned); err != nil {
604			return nil, NewPermanentUnboxingError(err)
605		}
606	}
607
608	// decrypt header
609	packedHeader, err := b.open(boxed.HeaderCiphertext.AsEncrypted(), libkb.NaclSecretBoxKey(encryptionKey.Material()))
610	if err != nil {
611		return nil, NewPermanentUnboxingError(err)
612	}
613	var header chat1.HeaderPlaintext
614	if err := b.unmarshal(packedHeader, &header); err != nil {
615		return nil, NewPermanentUnboxingError(err)
616	}
617
618	// verify the message
619	validity, ierr := b.verifyMessageV1(ctx, header, boxed, skipBodyVerification)
620	if ierr != nil {
621		return nil, ierr
622	}
623
624	// create a chat1.MessageClientHeader from versioned HeaderPlaintext
625	var clientHeader chat1.MessageClientHeaderVerified
626	headerVersion, err := header.Version()
627	if err != nil {
628		return nil, NewPermanentUnboxingError(err)
629	}
630
631	rtime := gregor1.ToTime(b.clock.Now())
632	if boxed.ServerHeader.Rtime != nil {
633		rtime = *boxed.ServerHeader.Rtime
634	}
635	var headerSignature *chat1.SignatureInfo
636	var bodyHash chat1.Hash
637	switch headerVersion {
638	case chat1.HeaderPlaintextVersion_V1:
639		// Verified above in verifyMessageV1
640		headerSignature = header.V1().HeaderSignature
641		hp := header.V1()
642		bodyHash = hp.BodyHash
643		clientHeader = chat1.MessageClientHeaderVerified{
644			Conv:         hp.Conv,
645			TlfName:      hp.TlfName,
646			TlfPublic:    hp.TlfPublic,
647			MessageType:  hp.MessageType,
648			Prev:         hp.Prev,
649			Sender:       hp.Sender,
650			SenderDevice: hp.SenderDevice,
651			// MerkleRoot is not expected to be in any v1 messages. Ignore it.
652			MerkleRoot:        nil,
653			OutboxID:          hp.OutboxID,
654			OutboxInfo:        hp.OutboxInfo,
655			KbfsCryptKeysUsed: hp.KbfsCryptKeysUsed,
656			Rtime:             rtime,
657		}
658	// NOTE: When adding new versions here, you must also update
659	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
660	// new max version
661	default:
662		return nil,
663			NewPermanentUnboxingError(NewHeaderVersionError(headerVersion,
664				b.headerUnsupported(ctx, headerVersion, header)))
665	}
666
667	// Check for sender match on the inner and outer header.
668	if !clientHeader.Sender.Eq(boxed.ClientHeader.Sender) {
669		return nil, NewPermanentUnboxingError(fmt.Errorf("sender does not match"))
670	}
671	if !bytes.Equal(clientHeader.SenderDevice.Bytes(), boxed.ClientHeader.SenderDevice.Bytes()) {
672		return nil, NewPermanentUnboxingError(fmt.Errorf("sender device does not match"))
673	}
674
675	// Any of (senderUsername, senderDeviceName, senderDeviceType) could be empty strings because of non-critical failures.
676	senderUsername, senderDeviceName, senderDeviceType := b.getSenderInfoLocal(
677		ctx, clientHeader.Sender, clientHeader.SenderDevice)
678
679	// create a chat1.MessageBody from versioned chat1.BodyPlaintext
680	// Will remain empty if the body was deleted.
681	var body chat1.MessageBody
682	if !skipBodyVerification {
683		bodyVersion, err := bodyVersioned.Version()
684		if err != nil {
685			return nil, NewPermanentUnboxingError(err)
686		}
687		switch bodyVersion {
688		case chat1.BodyPlaintextVersion_V1:
689			body = bodyVersioned.V1().MessageBody
690		// NOTE: When adding new versions here, you must also update
691		// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
692		// new max version
693		default:
694			return nil,
695				NewPermanentUnboxingError(NewBodyVersionError(bodyVersion,
696					b.bodyUnsupported(ctx, bodyVersion, bodyVersioned)))
697		}
698	}
699
700	// Get at mention usernames
701	atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions :=
702		b.getAtMentionInfo(ctx, clientHeader.Conv.Tlfid, clientHeader.Conv.TopicType, conv, body)
703
704	ierr = b.compareHeadersMBV1(ctx, boxed.ClientHeader, clientHeader)
705	if ierr != nil {
706		return nil, ierr
707	}
708
709	// create an unboxed message
710	return &chat1.MessageUnboxedValid{
711		ClientHeader:          clientHeader,
712		ServerHeader:          *boxed.ServerHeader,
713		MessageBody:           body,
714		SenderUsername:        senderUsername,
715		SenderDeviceName:      senderDeviceName,
716		SenderDeviceType:      senderDeviceType,
717		BodyHash:              bodyHash,
718		HeaderHash:            headerHash,
719		HeaderSignature:       headerSignature,
720		VerificationKey:       &validity.validationKey,
721		SenderDeviceRevokedAt: validity.senderDeviceRevokedAt,
722		AtMentions:            atMentions,
723		AtMentionUsernames:    atMentionUsernames,
724		ChannelMention:        chanMention,
725		ChannelNameMentions:   channelNameMentions,
726		MaybeMentions:         maybeRes,
727		BotUsername:           b.getBotInfoLocal(ctx, clientHeader.BotUID),
728		Emojis:                b.getEmojis(ctx, clientHeader.Conv.TopicType, body),
729	}, nil
730}
731
732func (b *Boxer) memberCtime(mctx libkb.MetaContext, conv types.UnboxConversationInfo, tlfID chat1.TLFID, tlfName string) (*keybase1.Time, error) {
733	team, err := NewTeamLoader(b.G().ExternalG()).loadTeam(mctx.Ctx(), tlfID, tlfName,
734		conv.GetMembersType(), conv.IsPublic(), nil)
735	if err != nil {
736		return nil, err
737	}
738	uv, err := mctx.G().GetMeUV(mctx.Ctx())
739	if err != nil {
740		return nil, err
741	}
742	return team.MemberCtime(mctx.Ctx(), uv), nil
743}
744
745func (b *Boxer) validatePairwiseMAC(ctx context.Context, boxed chat1.MessageBoxed,
746	conv types.UnboxConversationInfo, headerHash chat1.Hash) (senderKey []byte, err error) {
747	defer b.Trace(ctx, &err, "validatePairwiseMAC")()
748
749	// First, find a MAC that matches our receiving device encryption KID.
750	ourDeviceKeyNacl, err := b.G().ActiveDevice.NaclEncryptionKey()
751	if err != nil {
752		return nil, err
753	}
754	messageMAC, found := boxed.ClientHeader.PairwiseMacs[ourDeviceKeyNacl.GetKID()]
755	if !found {
756		// This is an error users will actually see when they've just joined a
757		// team or added a new device.
758		mctx := b.G().MetaContext(ctx)
759		memberCtime, err := b.memberCtime(mctx, conv, boxed.ClientHeader.Conv.Tlfid, boxed.ClientHeader.TlfName)
760		if err != nil {
761			b.Debug(ctx, "Unable to get member ctime: %v", err)
762		}
763		return nil, NewNotAuthenticatedForThisDeviceError(mctx,
764			memberCtime, boxed.ServerHeader.Ctime)
765	}
766
767	// Second, load the device encryption KID for the sender.
768	senderUID, err := keybase1.UIDFromSlice(boxed.ClientHeader.Sender)
769	if err != nil {
770		return nil, err
771	}
772	senderDeviceID, err := keybase1.DeviceIDFromSlice(boxed.ClientHeader.SenderDevice)
773	if err != nil {
774		return nil, err
775	}
776	// Use the loading function that hits the server if-and-only-if we don't
777	// have the given deviceID in cache.
778	senderUPAK, err := b.G().GetUPAKLoader().LoadUPAKWithDeviceID(ctx, senderUID, senderDeviceID)
779	if err != nil {
780		return nil, err
781	}
782	senderEncryptionKID := senderUPAK.Current.FindEncryptionKIDFromDeviceID(senderDeviceID)
783	if senderEncryptionKID.IsNil() {
784		for _, upk := range senderUPAK.PastIncarnations {
785			senderEncryptionKID = upk.FindEncryptionKIDFromDeviceID(senderDeviceID)
786			if !senderEncryptionKID.IsNil() {
787				break
788			}
789		}
790		if senderEncryptionKID.IsNil() {
791			return nil, fmt.Errorf("failed to find encryption key for device %s", senderDeviceID.String())
792		}
793	}
794	senderDeviceDHKeyNacl, err := libkb.ImportDHKeypairFromKID(senderEncryptionKID)
795	if err != nil {
796		return nil, err
797	}
798
799	// Finally, validate the MAC.
800	computedMAC := makeOnePairwiseMAC(*ourDeviceKeyNacl.Private, senderDeviceDHKeyNacl.Public, headerHash)
801	if !hmac.Equal(messageMAC, computedMAC) {
802		return nil, NewInvalidMACError()
803	}
804
805	return senderEncryptionKID.ToBytes(), nil
806}
807
808func (b *Boxer) ResolveSkippedUnboxed(ctx context.Context, msg chat1.MessageUnboxed) (res chat1.MessageUnboxed, modified bool, err types.UnboxingError) {
809	if !msg.IsValid() {
810		return msg, false, nil
811	}
812	if msg.Valid().VerificationKey == nil {
813		return msg, false, nil
814	}
815	// verify sender key
816	revokedAt, ierr := b.ValidSenderKey(ctx, msg.Valid().ClientHeader.Sender, *msg.Valid().VerificationKey,
817		msg.Valid().ServerHeader.Ctime)
818	if ierr != nil {
819		if ierr.IsPermanent() {
820			return b.makeErrorMessageFromPieces(ctx, ierr, msg.GetMessageID(), msg.GetMessageType(),
821				msg.Valid().ServerHeader.Ctime, msg.Valid().ClientHeader.Sender,
822				msg.Valid().ClientHeader.SenderDevice,
823				msg.Valid().ClientHeader.BotUID, msg.Valid().IsEphemeral(),
824				msg.Valid().ExplodedBy(), msg.Valid().Etime()), true, nil
825		}
826		return msg, false, ierr
827	}
828	mvalid := msg.Valid()
829	mvalid.SenderDeviceRevokedAt = revokedAt
830	return chat1.NewMessageUnboxedWithValid(mvalid), revokedAt != nil, nil
831}
832
833func (b *Boxer) ResolveSkippedUnboxeds(ctx context.Context, msgs []chat1.MessageUnboxed) (res []chat1.MessageUnboxed, modifiedMap map[chat1.MessageID]bool, err types.UnboxingError) {
834	modifiedMap = make(map[chat1.MessageID]bool)
835	for _, msg := range msgs {
836		rmsg, modified, err := b.ResolveSkippedUnboxed(ctx, msg)
837		if err != nil {
838			return res, modifiedMap, err
839		}
840		modifiedMap[rmsg.GetMessageID()] = modified
841		res = append(res, rmsg)
842	}
843	return res, modifiedMap, nil
844}
845
846func (b *Boxer) unboxV2orV3orV4(ctx context.Context, boxed chat1.MessageBoxed,
847	conv types.UnboxConversationInfo, baseEncryptionKey types.CryptKey,
848	ephemeralKey types.EphemeralCryptKey) (*chat1.MessageUnboxedValid, types.UnboxingError) {
849	if boxed.ServerHeader == nil {
850		return nil, NewPermanentUnboxingError(errors.New("nil ServerHeader in MessageBoxed"))
851	}
852
853	// Compute the header hash
854	headerHash, ierr := b.makeHeaderHash(boxed.HeaderCiphertext.AsSignEncrypted())
855	if ierr != nil {
856		return nil, ierr
857	}
858
859	// Regular messages use the same encryption key for the header and for the
860	// body. Exploding messages use a derived ephemeral key for the body.
861	headerEncryptionKey, err := libkb.DeriveSymmetricKey(
862		libkb.NaclSecretBoxKey(baseEncryptionKey.Material()), libkb.EncryptionReasonChatMessage)
863	if err != nil {
864		return nil, NewPermanentUnboxingError(err)
865	}
866	bodyEncryptionKey := headerEncryptionKey
867	if boxed.IsEphemeral() {
868		bodyEncryptionKey, err = libkb.DeriveFromSecret(ephemeralKey.Material(), libkb.DeriveReasonTeamEKExplodingChat)
869		if err != nil {
870			return nil, NewPermanentUnboxingError(err)
871		}
872	}
873
874	// Validate verification key against unverified sender id.
875	// Later it is asserted that the claimed and signing sender are the same.
876	// ValidSenderKey uses the server-given ctime, but emits senderDeviceRevokedAt as a workaround.
877	// See ValidSenderKey for details.
878	if boxed.VerifyKey == nil {
879		return nil, NewPermanentUnboxingError(libkb.NoKeyError{Msg: "sender key missing"})
880	}
881
882	// This will be the message's signing key in the normal case, and the
883	// sending device's encryption key in the pairwise MAC case.
884	senderKeyToValidate := boxed.VerifyKey
885
886	// When pairwise MACs are present (in practice only on exploding messages,
887	// but in theory we support them anywhere), we validate the one that's
888	// intended for our device, and error out if it's missing or invalid. If it
889	// is valid, then we *don't* validate the message signing key. That is,
890	// even though signEncryptOpen will check a signature in the end, we no
891	// longer care what signing key it's using.
892	if len(boxed.ClientHeader.PairwiseMacs) > 0 {
893		if boxed.Version != chat1.MessageBoxedVersion_V3 && !bytes.Equal(boxed.VerifyKey, dummySigningKey().GetKID().ToBytes()) {
894			return nil, NewPermanentUnboxingError(fmt.Errorf("expected dummy signing key (%s), got %s", dummySigningKey().GetKID(), hex.EncodeToString(boxed.VerifyKey)))
895		}
896		senderKeyToValidate, err = b.validatePairwiseMAC(ctx, boxed, conv, headerHash)
897		if err != nil {
898			// Return a transient error if possible
899			return nil, b.detectPermanentError(conv, err, boxed.ClientHeader.TlfName)
900		}
901	} else if bytes.Equal(boxed.VerifyKey, dummySigningKey().GetKID().ToBytes()) {
902		// Note that this can happen if the server is stripping MACs for some
903		// reason, for example if you're testing against an out-of-date server
904		// version.
905		return nil, NewPermanentUnboxingError(fmt.Errorf("unexpected dummy signing key with no pairwise MACs present"))
906	}
907
908	// If we validated a pairwise MAC above, then senderKeyToValidate will be
909	// the sender's device encryption key, instead of the VerifyKey from the
910	// message. In this case, ValidSenderKey is just fetching revocation info for us.
911	var senderDeviceRevokedAt *gregor1.Time
912	switch globals.CtxUnboxMode(ctx) {
913	case types.UnboxModeFull:
914		senderDeviceRevokedAt, ierr = b.ValidSenderKey(
915			ctx, boxed.ClientHeader.Sender, senderKeyToValidate, boxed.ServerHeader.Ctime)
916		if ierr != nil {
917			return nil, ierr
918		}
919	case types.UnboxModeQuick:
920		// we skip this check in quick mode, the idea is we will do it later asynchonously so we can
921		// deliver messges quicker to the UI.
922	}
923
924	// Open header and verify against VerifyKey
925	headerPacked, err := b.signEncryptOpen(boxed.HeaderCiphertext.AsSignEncrypted(), headerEncryptionKey,
926		boxed.VerifyKey, kbcrypto.SignaturePrefixChatMBv2)
927	if err != nil {
928		return nil, NewPermanentUnboxingError(err)
929	}
930	var headerVersioned chat1.HeaderPlaintext
931	err = b.unmarshal(headerPacked, &headerVersioned)
932	if err != nil {
933		return nil, NewPermanentUnboxingError(err)
934	}
935
936	// Unversion header
937	// Also check that the HeaderSignature field from MessageBoxed V1 is nil
938	// This object has been signed
939	clientHeader, bodyHashSigned, ierr := b.unversionHeaderMBV2(ctx, boxed.ServerHeader, headerVersioned)
940	if ierr != nil {
941		return nil, ierr
942	}
943
944	// Whether the body is missing (deleted)
945	isBodyDeleted := (len(boxed.BodyCiphertext.E) == 0)
946
947	// TODO We should check whether the body is allowed to have been deleted by checking
948	// that there is in fact a message that deleted it.
949	// We should fetch that message and check its signed body.
950	// That involves fetching a message whose ID is not known here.
951
952	// Verify body hash
953	// The hash of the encrypted body must match that signed into the header.
954	if !isBodyDeleted {
955		ierr = b.verifyBodyHash(ctx, boxed.BodyCiphertext, bodyHashSigned)
956		if ierr != nil {
957			return nil, ierr
958		}
959	}
960
961	// Compare the signed and unsigned header.
962	// Checks that [Sender, SenderDevice] match, and other things.
963	ierr = b.compareHeadersMBV2orV3(ctx, boxed.ClientHeader, clientHeader, boxed.Version)
964	if ierr != nil {
965		return nil, ierr
966	}
967
968	// Decrypt body
969	// If the body is deleted, this is left blank.
970	var body chat1.MessageBody
971	if !isBodyDeleted {
972		bodyPacked, err := b.open(boxed.BodyCiphertext, bodyEncryptionKey)
973		if err != nil {
974			return nil, NewPermanentUnboxingError(err)
975		}
976		var bodyVersioned chat1.BodyPlaintext
977		err = b.unmarshal(bodyPacked, &bodyVersioned)
978		if err != nil {
979			return nil, NewPermanentUnboxingError(err)
980		}
981
982		// Unversion the body
983		body, ierr = b.unversionBody(ctx, bodyVersioned)
984		if ierr != nil {
985			return nil, ierr
986		}
987	}
988
989	// Get sender info
990	// Any of (senderUsername, senderDeviceName, senderDeviceType) could be empty strings because of non-critical failures.
991	senderUsername, senderDeviceName, senderDeviceType := b.getSenderInfoLocal(
992		ctx, clientHeader.Sender, clientHeader.SenderDevice)
993
994	// Get at mention usernames
995	atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions :=
996		b.getAtMentionInfo(ctx, clientHeader.Conv.Tlfid, clientHeader.Conv.TopicType, conv, body)
997
998	clientHeader.HasPairwiseMacs = len(boxed.ClientHeader.PairwiseMacs) > 0
999
1000	// create an unboxed message
1001	return &chat1.MessageUnboxedValid{
1002		ClientHeader:          clientHeader,
1003		ServerHeader:          *boxed.ServerHeader,
1004		MessageBody:           body,
1005		SenderUsername:        senderUsername,
1006		SenderDeviceName:      senderDeviceName,
1007		SenderDeviceType:      senderDeviceType,
1008		BodyHash:              bodyHashSigned,
1009		HeaderHash:            headerHash,
1010		HeaderSignature:       nil,
1011		VerificationKey:       &senderKeyToValidate,
1012		SenderDeviceRevokedAt: senderDeviceRevokedAt,
1013		AtMentions:            atMentions,
1014		AtMentionUsernames:    atMentionUsernames,
1015		ChannelMention:        chanMention,
1016		ChannelNameMentions:   channelNameMentions,
1017		MaybeMentions:         maybeRes,
1018		BotUsername:           b.getBotInfoLocal(ctx, clientHeader.BotUID),
1019		Emojis:                b.getEmojis(ctx, clientHeader.Conv.TopicType, body),
1020	}, nil
1021}
1022
1023// Unversions a header.
1024// Also check that the HeaderSignature field from MessageBoxed V1 is nil.
1025// Therefore only for use with MessageBoxed V2.
1026// Returns (header, bodyHash, err)
1027func (b *Boxer) unversionHeaderMBV2(ctx context.Context, serverHeader *chat1.MessageServerHeader, headerVersioned chat1.HeaderPlaintext) (chat1.MessageClientHeaderVerified, []byte, types.UnboxingError) {
1028	if serverHeader == nil {
1029		return chat1.MessageClientHeaderVerified{}, nil, NewPermanentUnboxingError(errors.New("nil ServerHeader in MessageBoxed"))
1030	}
1031
1032	rtime := gregor1.ToTime(b.clock.Now())
1033	if serverHeader.Rtime != nil {
1034		rtime = *serverHeader.Rtime
1035	}
1036
1037	headerVersion, err := headerVersioned.Version()
1038	if err != nil {
1039		return chat1.MessageClientHeaderVerified{}, nil, NewPermanentUnboxingError(err)
1040	}
1041	switch headerVersion {
1042	case chat1.HeaderPlaintextVersion_V1:
1043		hp := headerVersioned.V1()
1044		if hp.HeaderSignature != nil {
1045			return chat1.MessageClientHeaderVerified{}, nil,
1046				NewPermanentUnboxingError(fmt.Errorf("HeaderSignature non-nil in MBV2"))
1047		}
1048		return chat1.MessageClientHeaderVerified{
1049			Conv:              hp.Conv,
1050			TlfName:           hp.TlfName,
1051			TlfPublic:         hp.TlfPublic,
1052			MessageType:       hp.MessageType,
1053			Prev:              hp.Prev,
1054			Sender:            hp.Sender,
1055			SenderDevice:      hp.SenderDevice,
1056			MerkleRoot:        hp.MerkleRoot,
1057			OutboxID:          hp.OutboxID,
1058			OutboxInfo:        hp.OutboxInfo,
1059			KbfsCryptKeysUsed: hp.KbfsCryptKeysUsed,
1060			EphemeralMetadata: hp.EphemeralMetadata,
1061			BotUID:            hp.BotUID,
1062			Rtime:             rtime,
1063		}, hp.BodyHash, nil
1064	// NOTE: When adding new versions here, you must also update
1065	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
1066	// new max version
1067	default:
1068		return chat1.MessageClientHeaderVerified{}, nil,
1069			NewPermanentUnboxingError(NewHeaderVersionError(headerVersion,
1070				b.headerUnsupported(ctx, headerVersion, headerVersioned)))
1071	}
1072}
1073
1074func (b *Boxer) unversionBody(ctx context.Context, bodyVersioned chat1.BodyPlaintext) (chat1.MessageBody, types.UnboxingError) {
1075	bodyVersion, err := bodyVersioned.Version()
1076	if err != nil {
1077		return chat1.MessageBody{}, NewPermanentUnboxingError(err)
1078	}
1079	switch bodyVersion {
1080	case chat1.BodyPlaintextVersion_V1:
1081		return bodyVersioned.V1().MessageBody, nil
1082	case chat1.BodyPlaintextVersion_V2:
1083		return bodyVersioned.V2().MessageBody, nil
1084	// NOTE: When adding new versions here, you must also update
1085	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
1086	// new max version
1087	default:
1088		return chat1.MessageBody{},
1089			NewPermanentUnboxingError(NewBodyVersionError(bodyVersion,
1090				b.bodyUnsupported(ctx, bodyVersion, bodyVersioned)))
1091	}
1092}
1093
1094func (b *Boxer) verifyBodyHash(ctx context.Context, bodyEncrypted chat1.EncryptedData, bodyHashSigned []byte) types.UnboxingError {
1095	bodyHashObserved, err := b.makeBodyHash(bodyEncrypted)
1096	if err != nil {
1097		return err
1098	}
1099
1100	if len(bodyHashSigned) == 0 {
1101		return NewPermanentUnboxingError(BodyHashInvalid{})
1102	}
1103
1104	if !libkb.SecureByteArrayEq(bodyHashObserved, bodyHashSigned) {
1105		return NewPermanentUnboxingError(BodyHashInvalid{})
1106	}
1107	return nil
1108}
1109
1110// Compare the unsigned and signed header for MessageBoxedVersion_V2.
1111// The V1 and V2 checks are different methods because they are strict on slightly different things.
1112// Confirm that fields in the server-supplied ClientHeader match what
1113// we decrypt. It would be preferable if the server didn't supply this data
1114// at all (so that we didn't have to worry about anyone trusting it
1115// *before* we get to this check, for example), but since we have it we
1116// need to check it.
1117// The most important check here is that the Sender and SenderDevice match.
1118// That is the only thing that gives the verification key used credibility.
1119func (b *Boxer) compareHeadersMBV2orV3(ctx context.Context, hServer chat1.MessageClientHeader, hSigned chat1.MessageClientHeaderVerified, version chat1.MessageBoxedVersion) types.UnboxingError {
1120	// Conv
1121	if !hServer.Conv.Eq(hSigned.Conv) {
1122		return NewPermanentUnboxingError(NewHeaderMismatchError("Conv"))
1123	}
1124
1125	// TlfName
1126	if hServer.TlfName != hSigned.TlfName {
1127		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfName"))
1128	}
1129
1130	// TlfPublic
1131	if hServer.TlfPublic != hSigned.TlfPublic {
1132		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfPublic"))
1133	}
1134
1135	// MessageType
1136	if hServer.MessageType != hSigned.MessageType {
1137		return NewPermanentUnboxingError(NewHeaderMismatchError("MessageType"))
1138	}
1139
1140	// Note: Supersedes and Deletes are not checked because they are not
1141	//       part of MessageClientHeaderVerified.
1142
1143	// Prev
1144	if len(hServer.Prev) != len(hSigned.Prev) {
1145		return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
1146	}
1147	for i, a := range hServer.Prev {
1148		b := hSigned.Prev[i]
1149		if !a.Eq(b) {
1150			return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
1151		}
1152	}
1153
1154	// Sender
1155	// This prevents someone from re-using a header for another sender
1156	if !hServer.Sender.Eq(hSigned.Sender) {
1157		return NewPermanentUnboxingError(NewHeaderMismatchError("Sender"))
1158	}
1159
1160	// SenderDevice
1161	if !bytes.Equal(hServer.SenderDevice.Bytes(), hSigned.SenderDevice.Bytes()) {
1162		return NewPermanentUnboxingError(NewHeaderMismatchError("SenderDevice"))
1163	}
1164
1165	// MerkleRoot
1166	if !hServer.MerkleRoot.Eq(hSigned.MerkleRoot) {
1167		return NewPermanentUnboxingError(NewHeaderMismatchError("MerkleRoot"))
1168	}
1169	if hSigned.MerkleRoot == nil {
1170		return NewPermanentUnboxingError(fmt.Errorf("missing MerkleRoot in chat message"))
1171	}
1172
1173	// OutboxID
1174	if !hServer.OutboxID.Eq(hSigned.OutboxID) {
1175		return NewPermanentUnboxingError(NewHeaderMismatchError("OutboxID"))
1176	}
1177
1178	// OutboxInfo
1179	if !hServer.OutboxInfo.Eq(hSigned.OutboxInfo) {
1180		return NewPermanentUnboxingError(NewHeaderMismatchError("OutboxInfo"))
1181	}
1182
1183	// EphemeralMetadata (only present in V3 and greater)
1184	if version > chat1.MessageBoxedVersion_V2 && !hServer.EphemeralMetadata.Eq(hSigned.EphemeralMetadata) {
1185		return NewPermanentUnboxingError(NewHeaderMismatchError("EphemeralMetadata"))
1186	}
1187
1188	// BotUID (only present in V3 and greater)
1189	if version > chat1.MessageBoxedVersion_V2 && !gregor1.UIDPtrEq(hServer.BotUID, hSigned.BotUID) {
1190		return NewPermanentUnboxingError(NewHeaderMismatchError("BotUID"))
1191	}
1192
1193	return nil
1194}
1195
1196func (b *Boxer) makeHeaderHash(headerSealed chat1.SignEncryptedData) (chat1.Hash, types.UnboxingError) {
1197	buf := bytes.Buffer{}
1198	err := binary.Write(&buf, binary.BigEndian, int32(headerSealed.V))
1199	if err != nil {
1200		return nil, NewPermanentUnboxingError(err)
1201	}
1202	// Only the ciphertext at the end should be of variable length, otherwise
1203	// this hash could be ambiguous.
1204	if len(headerSealed.N) != signencrypt.NonceSize {
1205		return nil, NewPermanentUnboxingError(fmt.Errorf("unexpected nonce size, %d != %d", len(headerSealed.N), signencrypt.NonceSize))
1206	}
1207	_, err = buf.Write(headerSealed.N)
1208	if err != nil {
1209		return nil, NewPermanentUnboxingError(err)
1210	}
1211	_, err = buf.Write(headerSealed.E)
1212	if err != nil {
1213		return nil, NewPermanentUnboxingError(err)
1214	}
1215	return b.hashV1(buf.Bytes()), nil
1216}
1217
1218func (b *Boxer) makeBodyHash(bodyCiphertext chat1.EncryptedData) (chat1.Hash, types.UnboxingError) {
1219	buf := bytes.Buffer{}
1220	err := binary.Write(&buf, binary.BigEndian, int32(bodyCiphertext.V))
1221	if err != nil {
1222		return nil, NewPermanentUnboxingError(err)
1223	}
1224	_, err = buf.Write(bodyCiphertext.N)
1225	if err != nil {
1226		return nil, NewPermanentUnboxingError(err)
1227	}
1228	_, err = buf.Write(bodyCiphertext.E)
1229	if err != nil {
1230		return nil, NewPermanentUnboxingError(err)
1231	}
1232	return b.hashV1(buf.Bytes()), nil
1233}
1234
1235// unboxThread transforms a chat1.ThreadViewBoxed to a keybase1.ThreadView.
1236func (b *Boxer) UnboxThread(ctx context.Context, boxed chat1.ThreadViewBoxed, conv types.UnboxConversationInfo) (thread chat1.ThreadView, err error) {
1237
1238	thread = chat1.ThreadView{
1239		Pagination: boxed.Pagination,
1240	}
1241
1242	if thread.Messages, err = b.UnboxMessages(ctx, boxed.Messages, conv); err != nil {
1243		return chat1.ThreadView{}, err
1244	}
1245
1246	return thread, nil
1247}
1248
1249func (b *Boxer) getUsernameAndDevice(ctx context.Context, uid keybase1.UID, deviceID keybase1.DeviceID) (string, string, keybase1.DeviceTypeV2, error) {
1250	nun, devName, devType, err := globals.CtxUPAKFinder(ctx, b.G()).LookupUsernameAndDevice(ctx, uid, deviceID)
1251	if err != nil {
1252		return "", "", keybase1.DeviceTypeV2_NONE, err
1253	}
1254	return nun.String(), devName, devType, nil
1255}
1256
1257func (b *Boxer) getUsername(ctx context.Context, uid keybase1.UID) (string, error) {
1258	name, err := b.G().GetUPAKLoader().LookupUsername(ctx, uid)
1259	if err != nil {
1260		return "", err
1261	}
1262	return name.String(), nil
1263}
1264
1265// Any of (senderUsername, senderDeviceName, senderDeviceType) could be empty strings because of non-critical failures.
1266// This first tries to username and device info, falling back to just username, falling back to empty strings.
1267// The reason for this soft error handling is that a permanent failure would be inappropriate, a transient
1268// failure could cause an entire thread not to load, and loading the names of revoked devices may not work this way.
1269// This deserves to be reconsidered.
1270func (b *Boxer) getSenderInfoLocal(ctx context.Context, uid1 gregor1.UID, deviceID1 gregor1.DeviceID) (senderUsername string, senderDeviceName string, senderDeviceType keybase1.DeviceTypeV2) {
1271	if uid1.IsNil() {
1272		b.Debug(ctx, "unable to fetch sender and device information: nil UID")
1273		return "", "", ""
1274	}
1275
1276	if b.testingGetSenderInfoLocal != nil {
1277		b.assertInTest()
1278		return b.testingGetSenderInfoLocal(ctx, uid1, deviceID1)
1279	}
1280
1281	uid := keybase1.UID(uid1.String())
1282	did := keybase1.DeviceID(deviceID1.String())
1283
1284	username, deviceName, deviceType, err := b.getUsernameAndDevice(ctx, uid, did)
1285	if err != nil {
1286		b.Debug(ctx, "unable to fetch sender and device information: UID: %s deviceID: %s",
1287			uid1, deviceID1)
1288		// try to just get username
1289		username, err = b.getUsername(ctx, uid)
1290		if err != nil {
1291			b.Debug(ctx, "failed to fetch sender username after initial error: err: %s", err.Error())
1292		}
1293	}
1294	return username, deviceName, deviceType
1295}
1296
1297func (b *Boxer) getBotInfoLocal(ctx context.Context, uid *gregor1.UID) string {
1298	if uid == nil {
1299		return ""
1300	}
1301	kbuid := keybase1.UID(uid.String())
1302	username, err := b.getUsername(ctx, kbuid)
1303	if err != nil {
1304		b.Debug(ctx, "failed to fetch bot username: %v", err)
1305		return ""
1306	}
1307	return username
1308}
1309
1310func (b *Boxer) getEmojis(ctx context.Context, topicType chat1.TopicType, body chat1.MessageBody) (res []chat1.HarvestedEmoji) {
1311	if topicType != chat1.TopicType_CHAT {
1312		return nil
1313	}
1314	emojis := body.GetEmojis()
1315	if emojis == nil {
1316		return nil
1317	}
1318	res = make([]chat1.HarvestedEmoji, 0, len(emojis))
1319	for _, emoji := range emojis {
1320		res = append(res, emoji)
1321	}
1322	return res
1323}
1324
1325func (b *Boxer) getAtMentionInfo(ctx context.Context, tlfID chat1.TLFID, topicType chat1.TopicType,
1326	conv types.UnboxConversationInfo, body chat1.MessageBody) (atMentions []gregor1.UID, atMentionUsernames []string, maybeRes []chat1.MaybeMention, chanMention chat1.ChannelMention, channelNameMentions []chat1.ChannelNameMention) {
1327	if topicType != chat1.TopicType_CHAT {
1328		// only care about chat conversations for these mentions
1329		return atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions
1330	}
1331	chanMention = chat1.ChannelMention_NONE
1332	typ, err := body.MessageType()
1333	if err != nil {
1334		return nil, nil, nil, chanMention, nil
1335	}
1336	uid := gregor1.UID(b.G().GetEnv().GetUID().ToBytes())
1337	tcs := b.G().TeamChannelSource
1338	var userAtMentions []chat1.KnownUserMention
1339	switch typ {
1340	case chat1.MessageType_TEXT:
1341		userAtMentions, maybeRes, chanMention = utils.GetTextAtMentionedItems(ctx, b.G(), uid,
1342			conv.GetConvID(), body.Text(), nil, &b.DebugLabeler)
1343		if conv.GetMembersType() == chat1.ConversationMembersType_TEAM {
1344			channelNameMentions = utils.ParseChannelNameMentions(ctx, body.Text().Body, uid, tlfID, tcs)
1345		}
1346	case chat1.MessageType_ATTACHMENT:
1347		userAtMentions, maybeRes, chanMention = utils.ParseAtMentionedItems(ctx, b.G(),
1348			body.Attachment().GetTitle(), body.Attachment().UserMentions, nil)
1349		if conv.GetMembersType() == chat1.ConversationMembersType_TEAM {
1350			channelNameMentions = utils.ParseChannelNameMentions(ctx, body.Attachment().GetTitle(), uid, tlfID, tcs)
1351		}
1352	case chat1.MessageType_FLIP:
1353		if topicType == chat1.TopicType_CHAT {
1354			userAtMentions, maybeRes, chanMention = utils.ParseAtMentionedItems(ctx, b.G(), body.Flip().Text,
1355				body.Flip().UserMentions, nil)
1356		}
1357	case chat1.MessageType_EDIT:
1358		userAtMentions, maybeRes, chanMention = utils.ParseAtMentionedItems(ctx, b.G(), body.Edit().Body,
1359			body.Edit().UserMentions, nil)
1360		if conv.GetMembersType() == chat1.ConversationMembersType_TEAM {
1361			channelNameMentions = utils.ParseChannelNameMentions(ctx, body.Edit().Body, uid, tlfID, tcs)
1362		}
1363	case chat1.MessageType_SYSTEM:
1364		atMentions, chanMention, channelNameMentions = utils.SystemMessageMentions(ctx, b.G(), uid,
1365			body.System())
1366	case chat1.MessageType_REACTION:
1367		targetUID := body.Reaction().TargetUID
1368		if targetUID != nil {
1369			atMentions = []gregor1.UID{*targetUID}
1370		}
1371	default:
1372		return nil, nil, nil, chanMention, nil
1373	}
1374	for _, uat := range userAtMentions {
1375		atMentions = append(atMentions, uat.Uid)
1376	}
1377	usernames := make(map[string]bool)
1378	for _, uid := range atMentions {
1379		name, err := b.G().GetUPAKLoader().LookupUsername(ctx, keybase1.UID(uid.String()))
1380		if err != nil {
1381			continue
1382		}
1383		usernames[name.String()] = true
1384	}
1385	for u := range usernames {
1386		atMentionUsernames = append(atMentionUsernames, u)
1387	}
1388	return atMentions, atMentionUsernames, maybeRes, chanMention, channelNameMentions
1389}
1390
1391func (b *Boxer) UnboxMessages(ctx context.Context, boxed []chat1.MessageBoxed, conv types.UnboxConversationInfo) (unboxed []chat1.MessageUnboxed, err error) {
1392	defer b.Trace(ctx, &err, "UnboxMessages: %s, boxed: %d", conv.GetConvID(), len(boxed))()
1393
1394	// First stamp all of the messages as received
1395	now := gregor1.ToTime(b.clock.Now())
1396	for i, msg := range boxed {
1397		msg.ServerHeader.Rtime = &now
1398		boxed[i] = msg
1399	}
1400
1401	boxCh := make(chan chat1.MessageBoxed)
1402	eg, ctx := errgroup.WithContext(ctx)
1403	eg.Go(func() error {
1404		defer close(boxCh)
1405		for _, msg := range boxed {
1406			select {
1407			case boxCh <- msg:
1408			case <-ctx.Done():
1409				return ctx.Err()
1410			}
1411		}
1412		return nil
1413	})
1414	var resLock sync.Mutex
1415	numUnboxThreads := 2
1416	for i := 0; i < numUnboxThreads; i++ {
1417		eg.Go(func() error {
1418			for msg := range boxCh {
1419				decmsg, err := b.UnboxMessage(ctx, msg, conv, nil)
1420				if err != nil {
1421					return err
1422				}
1423				resLock.Lock()
1424				unboxed = append(unboxed, decmsg)
1425				resLock.Unlock()
1426			}
1427			return nil
1428		})
1429	}
1430
1431	if err := eg.Wait(); err != nil {
1432		return unboxed, err
1433	}
1434	sort.Sort(utils.ByMsgUnboxedMsgID(unboxed))
1435	return unboxed, nil
1436}
1437
1438// If no error then MerkleRoot is non-nil.
1439func (b *Boxer) latestMerkleRoot(ctx context.Context) (*chat1.MerkleRoot, error) {
1440	merkleClient := b.G().GetMerkleClient()
1441	if merkleClient == nil {
1442		return nil, fmt.Errorf("no MerkleClient available")
1443	}
1444	mr, err := merkleClient.FetchRootFromServer(b.G().MetaContext(ctx), libkb.ChatBoxerMerkleFreshness)
1445	if err != nil {
1446		return nil, err
1447	}
1448	if mr == nil {
1449		return nil, fmt.Errorf("No merkle root available for chat header")
1450	}
1451	merkleRoot := mr.ToInfo()
1452	return &merkleRoot, nil
1453}
1454
1455var dummySigningKeyPtr *libkb.NaclSigningKeyPair
1456var dummySigningKeyOnce sync.Once
1457
1458// We use this constant key when we already have pairwiseMACs providing
1459// authentication. Creating a keypair requires a curve multiply, so we cache it
1460// here, in case someone uses it in a tight loop.
1461func dummySigningKey() libkb.NaclSigningKeyPair {
1462	dummySigningKeyOnce.Do(func() {
1463		var allZeroSecretKey [libkb.NaclSigningKeySecretSize]byte
1464		dummyKeypair, err := libkb.MakeNaclSigningKeyPairFromSecret(allZeroSecretKey)
1465		if err != nil {
1466			panic("errors in key generation should be impossible: " + err.Error())
1467		}
1468		dummySigningKeyPtr = &dummyKeypair
1469	})
1470	return *dummySigningKeyPtr
1471}
1472
1473func (b *Boxer) GetEncryptionInfo(ctx context.Context, msg *chat1.MessagePlaintext,
1474	membersType chat1.ConversationMembersType, signingKeyPair libkb.NaclSigningKeyPair) (res types.BoxerEncryptionInfo, err error) {
1475
1476	tlfName := msg.ClientHeader.TlfName
1477	version, err := b.GetBoxedVersion(*msg)
1478	if err != nil {
1479		return res, err
1480	}
1481	encryptionKey, nameInfo, err := globals.CtxKeyFinder(ctx, b.G()).FindForEncryption(ctx,
1482		tlfName, msg.ClientHeader.Conv.Tlfid, membersType,
1483		msg.ClientHeader.TlfPublic, msg.ClientHeader.BotUID)
1484	if err != nil {
1485		return res, NewBoxingCryptKeysError(err)
1486	}
1487	msg.ClientHeader.TlfName = nameInfo.CanonicalName
1488
1489	// If the message is exploding, load the ephemeral key, and tweak the
1490	// version. Make sure we're not using MessageBoxedVersion_V1, since that
1491	// doesn't support exploding messages.
1492	var ephemeralKey types.EphemeralCryptKey
1493	var pairwiseMACRecipients []keybase1.KID
1494	if msg.IsEphemeral() {
1495		ephemeralKey, err = globals.CtxKeyFinder(ctx, b.G()).EphemeralKeyForEncryption(
1496			b.G().MetaContext(ctx), tlfName, msg.ClientHeader.Conv.Tlfid,
1497			membersType, msg.ClientHeader.TlfPublic, msg.ClientHeader.BotUID)
1498		if err != nil {
1499			return res, NewBoxingCryptKeysError(err)
1500		}
1501		// V3 is "V2 plus support for exploding messages", and V4 is "V3 plus
1502		// support for pairwise MACs". Thus we'll bump all exploding messages
1503		// from V2 to V3, and all MAC'd messages from V3 to V4. Eventually we
1504		// can deprecate the old versions and remove these branches, once
1505		// support is widespread.
1506		if version == chat1.MessageBoxedVersion_V2 {
1507			version = chat1.MessageBoxedVersion_V3
1508		}
1509
1510		// If this is a team conversation, and the team is small enough, load
1511		// the list of pairwise MAC recipients. Note that this is all the
1512		// devices in the team, not just those that can read the current
1513		// teamEK. There are a few reasons for doing it this way:
1514		//   - It's probably better performance. Including all devices
1515		//     makes the message bigger and takes more Curve25519 ops, but
1516		//     it means we only need to reference the UPAK cache. To get
1517		//     the set of devices-that-are-not-stale, we'd need to ask the
1518		//     server and pay the cost of a network round trip. We could
1519		//     introduce yet another caching layer, but EKs change more
1520		//     frequently than devices in general.
1521		//   - It leaves us more flexibility in the future. If say we
1522		//     introduce a best-effort rekey mechanism for ephmeral keys,
1523		//     existing pairwise MACs will Just Work™ after a rekey.
1524		shouldPairwiseMAC, recipients, err := globals.CtxKeyFinder(ctx, b.G()).ShouldPairwiseMAC(
1525			ctx, tlfName, msg.ClientHeader.Conv.Tlfid, membersType, msg.ClientHeader.TlfPublic)
1526		if err != nil {
1527			return res, err
1528		} else if shouldPairwiseMAC {
1529			if len(recipients) == 0 {
1530				return res, fmt.Errorf("unexpected empty pairwise recipients list")
1531			}
1532			pairwiseMACRecipients = recipients
1533			// As noted above, bump the version to V4 when we're MAC'ing.
1534			if version == chat1.MessageBoxedVersion_V3 {
1535				version = chat1.MessageBoxedVersion_V4
1536			}
1537			// Replace the signing key with a dummy. Using the real signing key
1538			// would sabotage the repudiability that pairwise MACs are
1539			// providing. We could avoid signing entirely, but this approach
1540			// keeps the difference between the two modes very small.
1541			signingKeyPair = dummySigningKey()
1542		}
1543	}
1544	return types.BoxerEncryptionInfo{
1545		Key:                   encryptionKey,
1546		EphemeralKey:          ephemeralKey,
1547		PairwiseMACRecipients: pairwiseMACRecipients,
1548		Version:               version,
1549		SigningKeyPair:        signingKeyPair,
1550	}, nil
1551}
1552
1553func (b *Boxer) GetBoxedVersion(msg chat1.MessagePlaintext) (chat1.MessageBoxedVersion, error) {
1554	version := CurrentMessageBoxedVersion
1555	if b.boxVersionForTesting != nil {
1556		version = *b.boxVersionForTesting
1557	}
1558	if msg.IsEphemeral() && version == chat1.MessageBoxedVersion_V1 {
1559		return version, fmt.Errorf("cannot use exploding messages with V1")
1560	}
1561	return version, nil
1562}
1563
1564// BoxMessage encrypts a keybase1.MessagePlaintext into a chat1.MessageBoxed.  It
1565// finds the most recent key for the TLF.
1566func (b *Boxer) BoxMessage(ctx context.Context, msg chat1.MessagePlaintext,
1567	membersType chat1.ConversationMembersType,
1568	signingKeyPair libkb.NaclSigningKeyPair, info *types.BoxerEncryptionInfo) (res chat1.MessageBoxed, err error) {
1569	defer b.Trace(ctx, &err, "BoxMessage")()
1570	tlfName := msg.ClientHeader.TlfName
1571	if len(tlfName) == 0 {
1572		return res, NewBoxingError("blank TLF name given", true)
1573	}
1574	version, err := b.GetBoxedVersion(msg)
1575	if err != nil {
1576		return res, err
1577	}
1578	if err = b.attachMerkleRoot(ctx, &msg, version); err != nil {
1579		return res, err
1580	}
1581	if info == nil {
1582		info = new(types.BoxerEncryptionInfo)
1583		if *info, err = b.GetEncryptionInfo(ctx, &msg, membersType, signingKeyPair); err != nil {
1584			return res, err
1585		}
1586		if len(msg.ClientHeader.TlfName) == 0 {
1587			msg := fmt.Sprintf("blank TLF name received: original: %s canonical: %s", tlfName,
1588				msg.ClientHeader.TlfName)
1589			return res, NewBoxingError(msg, true)
1590		}
1591	}
1592	boxed, err := b.box(ctx, msg, info.Key, info.EphemeralKey, info.SigningKeyPair, info.Version,
1593		info.PairwiseMACRecipients)
1594	if err != nil {
1595		return res, NewBoxingError(err.Error(), true)
1596	}
1597	return boxed, nil
1598}
1599
1600// Attach a merkle root to the message to send.
1601// Modifies msg.
1602// For MessageBoxedV1 makes sure there is no MR.
1603// For MessageBoxedV2 attaches a MR that is no more out of date than ChatBoxerMerkleFreshness.
1604func (b *Boxer) attachMerkleRoot(ctx context.Context, msg *chat1.MessagePlaintext, version chat1.MessageBoxedVersion) error {
1605	switch version {
1606	case chat1.MessageBoxedVersion_V1:
1607		if msg.ClientHeader.MerkleRoot != nil {
1608			return NewBoxingError("cannot send v1 message with merkle root", true)
1609		}
1610	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
1611		merkleRoot, err := b.latestMerkleRoot(ctx)
1612		if err != nil {
1613			return NewBoxingError(err.Error(), false)
1614		}
1615		msg.ClientHeader.MerkleRoot = merkleRoot
1616		if msg.ClientHeader.MerkleRoot == nil {
1617			return NewBoxingError("cannot send message without merkle root", false)
1618		}
1619	default:
1620		return fmt.Errorf("attachMerkleRoot unrecognized version: %s", version)
1621	}
1622	return nil
1623}
1624
1625func (b *Boxer) preBoxCheck(ctx context.Context, messagePlaintext chat1.MessagePlaintext) error {
1626	typ, err := messagePlaintext.MessageBody.MessageType()
1627	if err != nil {
1628		return err
1629	}
1630	e := func(format string, args ...interface{}) error {
1631		return errors.New(fmt.Sprintf("malformed %v message: ", typ) + fmt.Sprintf(format, args...))
1632	}
1633	switch typ {
1634	case chat1.MessageType_DELETEHISTORY:
1635		body := messagePlaintext.MessageBody.Deletehistory()
1636		dhHeader := messagePlaintext.ClientHeader.DeleteHistory
1637		if dhHeader == nil {
1638			return e("missing header")
1639		}
1640		if *dhHeader != body {
1641			return e("header-body mismatch")
1642		}
1643	default:
1644		if messagePlaintext.ClientHeader.DeleteHistory != nil {
1645			return e("cannot have delete-history header")
1646		}
1647	}
1648
1649	return nil
1650}
1651
1652func (b *Boxer) box(ctx context.Context, messagePlaintext chat1.MessagePlaintext, encryptionKey types.CryptKey,
1653	ephemeralKey types.EphemeralCryptKey, signingKeyPair libkb.NaclSigningKeyPair, version chat1.MessageBoxedVersion,
1654	pairwiseMACRecipients []keybase1.KID) (res chat1.MessageBoxed, err error) {
1655	if err = b.preBoxCheck(ctx, messagePlaintext); err != nil {
1656		return res, err
1657	}
1658
1659	switch version {
1660	case chat1.MessageBoxedVersion_V1:
1661		if res, err = b.boxV1(messagePlaintext, encryptionKey, signingKeyPair); err != nil {
1662			b.Debug(ctx, "error boxing message version: %v", version)
1663		}
1664		return res, err
1665	// V3 is the same as V2, except that it indicates exploding message
1666	// support. V4 is the same as V3, except that it signs with the zero key
1667	// when pairwise MACs are included.
1668	case chat1.MessageBoxedVersion_V2, chat1.MessageBoxedVersion_V3, chat1.MessageBoxedVersion_V4:
1669		if res, err = b.boxV2orV3orV4(ctx, messagePlaintext, encryptionKey, ephemeralKey, signingKeyPair,
1670			version, pairwiseMACRecipients); err != nil {
1671			b.Debug(ctx, "error boxing message version: %v", version)
1672		}
1673		return res, err
1674	default:
1675		return res, fmt.Errorf("invalid version for boxing: %v", version)
1676	}
1677}
1678
1679// boxMessageWithKeys encrypts and signs a keybase1.MessagePlaintext into a
1680// chat1.MessageBoxed given a keybase1.CryptKey.
1681func (b *Boxer) boxV1(messagePlaintext chat1.MessagePlaintext, key types.CryptKey,
1682	signingKeyPair libkb.NaclSigningKeyPair) (res chat1.MessageBoxed, err error) {
1683
1684	body := chat1.BodyPlaintextV1{
1685		MessageBody: messagePlaintext.MessageBody,
1686	}
1687	plaintextBody := chat1.NewBodyPlaintextWithV1(body)
1688	encryptedBody, err := b.seal(plaintextBody, libkb.NaclSecretBoxKey(key.Material()))
1689	if err != nil {
1690		return res, err
1691	}
1692
1693	// create the v1 header, adding hash
1694	bodyHash := b.hashV1(encryptedBody.E)
1695	if messagePlaintext.ClientHeader.MerkleRoot != nil {
1696		return res, fmt.Errorf("cannot box v1 message with merkle root")
1697	}
1698	header := chat1.HeaderPlaintextV1{
1699		Conv:              messagePlaintext.ClientHeader.Conv,
1700		TlfName:           messagePlaintext.ClientHeader.TlfName,
1701		TlfPublic:         messagePlaintext.ClientHeader.TlfPublic,
1702		MessageType:       messagePlaintext.ClientHeader.MessageType,
1703		Prev:              messagePlaintext.ClientHeader.Prev,
1704		Sender:            messagePlaintext.ClientHeader.Sender,
1705		SenderDevice:      messagePlaintext.ClientHeader.SenderDevice,
1706		MerkleRoot:        nil, // MerkleRoot cannot be sent in MBv1 messages
1707		BodyHash:          bodyHash[:],
1708		OutboxInfo:        messagePlaintext.ClientHeader.OutboxInfo,
1709		OutboxID:          messagePlaintext.ClientHeader.OutboxID,
1710		KbfsCryptKeysUsed: messagePlaintext.ClientHeader.KbfsCryptKeysUsed,
1711	}
1712
1713	// sign the header and insert the signature
1714	sig, err := b.signMarshal(header, signingKeyPair, kbcrypto.SignaturePrefixChatMBv1)
1715	if err != nil {
1716		return res, err
1717	}
1718	header.HeaderSignature = &sig
1719
1720	// create a plaintext header
1721	plaintextHeader := chat1.NewHeaderPlaintextWithV1(header)
1722	encryptedHeader, err := b.seal(plaintextHeader, libkb.NaclSecretBoxKey(key.Material()))
1723	if err != nil {
1724		return res, err
1725	}
1726	return chat1.MessageBoxed{
1727		Version:          chat1.MessageBoxedVersion_V1,
1728		ClientHeader:     messagePlaintext.ClientHeader,
1729		BodyCiphertext:   *encryptedBody,
1730		HeaderCiphertext: encryptedHeader.AsSealed(),
1731		KeyGeneration:    key.Generation(),
1732	}, nil
1733}
1734
1735func makeOnePairwiseMAC(private libkb.NaclDHKeyPrivate, public libkb.NaclDHKeyPublic, input []byte) []byte {
1736	privKeyBytes := [32]byte(private)
1737	pubKeyBytes := [32]byte(public)
1738	var rawShared [32]byte
1739	box.Precompute(&rawShared, &pubKeyBytes, &privKeyBytes)
1740	derivedShared, err := libkb.DeriveFromSecret(rawShared, libkb.DeriveReasonChatPairwiseMAC)
1741	if err != nil {
1742		panic(err) // key derivation should never fail
1743	}
1744	hmacState := hmac.New(sha256.New, derivedShared[:])
1745	_, _ = hmacState.Write(input)
1746	return hmacState.Sum(nil)
1747}
1748
1749func (b *Boxer) makeAllPairwiseMACs(ctx context.Context, headerSealed chat1.SignEncryptedData, recipients []keybase1.KID) (macs map[keybase1.KID][]byte, err error) {
1750	defer b.G().CTrace(ctx, fmt.Sprintf("makeAllPairwiseMACs with %d recipients", len(recipients)), &err)()
1751
1752	pairwiseMACs := map[keybase1.KID][]byte{}
1753	headerHash, ierr := b.makeHeaderHash(headerSealed)
1754	if ierr != nil {
1755		return nil, ierr
1756	}
1757	deviceKeyNacl, err := b.G().ActiveDevice.NaclEncryptionKey()
1758	if err != nil {
1759		return nil, err
1760	}
1761	for _, recipientKID := range recipients {
1762		recipientKeyNacl, err := libkb.ImportDHKeypairFromKID(recipientKID)
1763		if err != nil {
1764			return nil, err
1765		}
1766		pairwiseMACs[recipientKID] = makeOnePairwiseMAC(*deviceKeyNacl.Private, recipientKeyNacl.Public, headerHash)
1767	}
1768	return pairwiseMACs, nil
1769}
1770
1771func (b *Boxer) versionBody(ctx context.Context, messagePlaintext chat1.MessagePlaintext) chat1.BodyPlaintext {
1772	switch messagePlaintext.ClientHeader.MessageType {
1773	case chat1.MessageType_PIN:
1774		return chat1.NewBodyPlaintextWithV2(chat1.BodyPlaintextV2{
1775			MessageBody: messagePlaintext.MessageBody,
1776		})
1777	default:
1778		return chat1.NewBodyPlaintextWithV1(chat1.BodyPlaintextV1{
1779			MessageBody: messagePlaintext.MessageBody,
1780		})
1781	}
1782}
1783
1784// V3 is just V2 but with exploding messages support. V4 is just V3, but it
1785// signs with the zero key when pairwise MACs are included.
1786func (b *Boxer) boxV2orV3orV4(ctx context.Context, messagePlaintext chat1.MessagePlaintext,
1787	baseEncryptionKey types.CryptKey, ephemeralKey types.EphemeralCryptKey, signingKeyPair libkb.NaclSigningKeyPair,
1788	version chat1.MessageBoxedVersion, pairwiseMACRecipients []keybase1.KID) (res chat1.MessageBoxed, err error) {
1789
1790	if messagePlaintext.ClientHeader.MerkleRoot == nil {
1791		return res, NewBoxingError("cannot send message without merkle root", false)
1792	}
1793	headerEncryptionKey, err := libkb.DeriveSymmetricKey(
1794		libkb.NaclSecretBoxKey(baseEncryptionKey.Material()), libkb.EncryptionReasonChatMessage)
1795	if err != nil {
1796		return res, err
1797	}
1798
1799	// Regular messages use the same encryption key for the header and for the
1800	// body. Exploding messages use a derived ephemeral key for the body.
1801	bodyEncryptionKey := headerEncryptionKey
1802	if messagePlaintext.IsEphemeral() {
1803		bodyEncryptionKey, err = libkb.DeriveFromSecret(ephemeralKey.Material(), libkb.DeriveReasonTeamEKExplodingChat)
1804		if err != nil {
1805			return res, err
1806		}
1807		// The MessagePlaintext supplied by the caller has a Lifetime, but we
1808		// expect the Generation is left uninitialized, and we set it here.
1809		messagePlaintext.ClientHeader.EphemeralMetadata.Generation = ephemeralKey.Generation()
1810	}
1811
1812	bodyVersioned := b.versionBody(ctx, messagePlaintext)
1813	bodyEncrypted, err := b.seal(bodyVersioned, bodyEncryptionKey)
1814	if err != nil {
1815		return res, err
1816	}
1817
1818	bodyHash, err := b.makeBodyHash(*bodyEncrypted)
1819	if err != nil {
1820		return res, err
1821	}
1822
1823	// create the v1 header, adding hash
1824	headerVersioned := chat1.NewHeaderPlaintextWithV1(chat1.HeaderPlaintextV1{
1825		Conv:              messagePlaintext.ClientHeader.Conv,
1826		TlfName:           messagePlaintext.ClientHeader.TlfName,
1827		TlfPublic:         messagePlaintext.ClientHeader.TlfPublic,
1828		MessageType:       messagePlaintext.ClientHeader.MessageType,
1829		Prev:              messagePlaintext.ClientHeader.Prev,
1830		Sender:            messagePlaintext.ClientHeader.Sender,
1831		SenderDevice:      messagePlaintext.ClientHeader.SenderDevice,
1832		BodyHash:          bodyHash,
1833		MerkleRoot:        messagePlaintext.ClientHeader.MerkleRoot,
1834		OutboxInfo:        messagePlaintext.ClientHeader.OutboxInfo,
1835		OutboxID:          messagePlaintext.ClientHeader.OutboxID,
1836		KbfsCryptKeysUsed: messagePlaintext.ClientHeader.KbfsCryptKeysUsed,
1837		EphemeralMetadata: messagePlaintext.ClientHeader.EphemeralMetadata,
1838		BotUID:            messagePlaintext.ClientHeader.BotUID,
1839		// In MessageBoxed.V2 HeaderSignature is nil.
1840		HeaderSignature: nil,
1841	})
1842
1843	// signencrypt the header
1844	headerSealed, err := b.signEncryptMarshal(headerVersioned, headerEncryptionKey,
1845		signingKeyPair, kbcrypto.SignaturePrefixChatMBv2)
1846	if err != nil {
1847		return res, err
1848	}
1849
1850	// Make pairwise MACs if there are any pairwise recipients supplied. Note
1851	// that we still sign+encrypt with a signing key above. If we want
1852	// repudiability, it's the caller's responsibility to provide a zero
1853	// signing key or similar. Signing with a real key and also MAC'ing is
1854	// redundant, but it will let us test the MAC code in prod in a backwards
1855	// compatible way.
1856	if len(pairwiseMACRecipients) > 0 {
1857		pairwiseMACs, err := b.makeAllPairwiseMACs(ctx, headerSealed, pairwiseMACRecipients)
1858		if err != nil {
1859			return res, err
1860		}
1861		messagePlaintext.ClientHeader.PairwiseMacs = pairwiseMACs
1862	}
1863
1864	// verify
1865	verifyKey := signingKeyPair.GetBinaryKID()
1866
1867	return chat1.MessageBoxed{
1868		Version:          version,
1869		ServerHeader:     nil,
1870		ClientHeader:     messagePlaintext.ClientHeader,
1871		HeaderCiphertext: headerSealed.AsSealed(),
1872		BodyCiphertext:   *bodyEncrypted,
1873		VerifyKey:        verifyKey,
1874		KeyGeneration:    baseEncryptionKey.Generation(),
1875	}, nil
1876}
1877
1878// seal encrypts data into chat1.EncryptedData.
1879func (b *Boxer) seal(data interface{}, key libkb.NaclSecretBoxKey) (*chat1.EncryptedData, error) {
1880	s, err := b.marshal(data)
1881	if err != nil {
1882		return nil, err
1883	}
1884
1885	var nonce [libkb.NaclDHNonceSize]byte
1886	if _, err := rand.Read(nonce[:]); err != nil {
1887		return nil, err
1888	}
1889
1890	var encKey [libkb.NaclSecretBoxKeySize]byte = key
1891
1892	sealed := secretbox.Seal(nil, s, &nonce, &encKey)
1893	enc := &chat1.EncryptedData{
1894		V: 1,
1895		E: sealed,
1896		N: nonce[:],
1897	}
1898
1899	return enc, nil
1900}
1901
1902// open decrypts chat1.EncryptedData.
1903func (b *Boxer) open(data chat1.EncryptedData, key libkb.NaclSecretBoxKey) ([]byte, error) {
1904	if len(data.N) != libkb.NaclDHNonceSize {
1905		return nil, libkb.DecryptBadNonceError{}
1906	}
1907	var nonce [libkb.NaclDHNonceSize]byte
1908	copy(nonce[:], data.N)
1909
1910	plain, ok := secretbox.Open(nil, data.E, &nonce, (*[32]byte)(&key))
1911	if !ok {
1912		return nil, libkb.DecryptOpenError{}
1913	}
1914	return plain, nil
1915}
1916
1917// signMarshal signs data with a NaclSigningKeyPair, returning a chat1.SignatureInfo.
1918// It marshals data before signing.
1919func (b *Boxer) signMarshal(data interface{}, kp libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignatureInfo, error) {
1920	encoded, err := b.marshal(data)
1921	if err != nil {
1922		return chat1.SignatureInfo{}, err
1923	}
1924
1925	return b.sign(encoded, kp, prefix)
1926}
1927
1928// signEncryptMarshal signencrypts data given an encryption and signing key, returning a chat1.SignEncryptedData.
1929// It marshals data before signing.
1930func (b *Boxer) signEncryptMarshal(data interface{}, encryptionKey libkb.NaclSecretBoxKey,
1931	signingKeyPair libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignEncryptedData, error) {
1932	encoded, err := b.marshal(data)
1933	if err != nil {
1934		return chat1.SignEncryptedData{}, err
1935	}
1936
1937	return b.signEncrypt(encoded, encryptionKey, signingKeyPair, prefix)
1938}
1939
1940// sign signs msg with a NaclSigningKeyPair, returning a chat1.SignatureInfo.
1941func (b *Boxer) sign(msg []byte, kp libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignatureInfo, error) {
1942	sig, err := kp.SignV2(msg, prefix)
1943	if err != nil {
1944		return chat1.SignatureInfo{}, err
1945	}
1946	sigInfo := chat1.SignatureInfo{
1947		V: sig.Version,
1948		S: sig.Sig[:],
1949		K: sig.Kid,
1950	}
1951
1952	if b.testingSignatureMangle != nil {
1953		b.assertInTest()
1954		sigInfo.S = b.testingSignatureMangle(sigInfo.S)
1955	}
1956
1957	return sigInfo, nil
1958}
1959
1960// signEncrypt signencrypts msg.
1961func (b *Boxer) signEncrypt(msg []byte, encryptionKey libkb.NaclSecretBoxKey,
1962	signingKeyPair libkb.NaclSigningKeyPair, prefix kbcrypto.SignaturePrefix) (chat1.SignEncryptedData, error) {
1963	if signingKeyPair.Private == nil {
1964		return chat1.SignEncryptedData{}, libkb.NoSecretKeyError{}
1965	}
1966
1967	var nonce [signencrypt.NonceSize]byte
1968	if _, err := rand.Read(nonce[:]); err != nil {
1969		return chat1.SignEncryptedData{}, err
1970	}
1971
1972	var encKey [signencrypt.SecretboxKeySize]byte = encryptionKey
1973	var signKey [ed25519.PrivateKeySize]byte = *signingKeyPair.Private
1974
1975	signEncryptedBytes := signencrypt.SealWhole(
1976		msg, &encKey, &signKey, prefix, &nonce)
1977	signEncryptedInfo := chat1.SignEncryptedData{
1978		V: 1,
1979		E: signEncryptedBytes,
1980		N: nonce[:],
1981	}
1982
1983	if b.testingSignatureMangle != nil {
1984		b.assertInTest()
1985		signEncryptedInfo.E = b.testingSignatureMangle(signEncryptedInfo.E)
1986	}
1987
1988	return signEncryptedInfo, nil
1989}
1990
1991// signEncryptOpen opens and verifies chat1.SignEncryptedData.
1992func (b *Boxer) signEncryptOpen(data chat1.SignEncryptedData, encryptionKey libkb.NaclSecretBoxKey,
1993	verifyKID []byte, prefix kbcrypto.SignaturePrefix) ([]byte, error) {
1994	var encKey [signencrypt.SecretboxKeySize]byte = encryptionKey
1995
1996	verifyKey := kbcrypto.KIDToNaclSigningKeyPublic(verifyKID)
1997	if verifyKey == nil {
1998		return nil, kbcrypto.BadKeyError{}
1999	}
2000	var verKey [ed25519.PublicKeySize]byte = *verifyKey
2001
2002	var nonce [signencrypt.NonceSize]byte
2003	if copy(nonce[:], data.N) != signencrypt.NonceSize {
2004		return nil, libkb.DecryptBadNonceError{}
2005	}
2006
2007	plain, err := signencrypt.OpenWhole(data.E, &encKey, &verKey, prefix, &nonce)
2008	if err != nil {
2009		return nil, err
2010	}
2011	return plain, nil
2012}
2013
2014type verifyMessageRes struct {
2015	senderDeviceRevokedAt *gregor1.Time
2016	validationKey         []byte
2017}
2018
2019// verifyMessage checks that a message is valid.
2020// Only works on MessageBoxedVersion_V1
2021func (b *Boxer) verifyMessageV1(ctx context.Context, header chat1.HeaderPlaintext, msg chat1.MessageBoxed, skipBodyVerification bool) (verifyMessageRes, types.UnboxingError) {
2022	headerVersion, err := header.Version()
2023	if err != nil {
2024		return verifyMessageRes{}, NewPermanentUnboxingError(err)
2025	}
2026
2027	switch headerVersion {
2028	case chat1.HeaderPlaintextVersion_V1:
2029		return b.verifyMessageHeaderV1(ctx, header.V1(), msg, skipBodyVerification)
2030	// NOTE: When adding new versions here, you must also update
2031	// chat1/extras.go so MessageUnboxedError.ParseableVersion understands the
2032	// new max version
2033	default:
2034		return verifyMessageRes{},
2035			NewPermanentUnboxingError(NewHeaderVersionError(headerVersion,
2036				b.headerUnsupported(ctx, headerVersion, header)))
2037	}
2038}
2039
2040// verifyMessageHeaderV1 checks the body hash, header signature, and signing key validity.
2041func (b *Boxer) verifyMessageHeaderV1(ctx context.Context, header chat1.HeaderPlaintextV1, msg chat1.MessageBoxed, skipBodyVerification bool) (verifyMessageRes, types.UnboxingError) {
2042	if !skipBodyVerification {
2043		// check body hash
2044		bh := b.hashV1(msg.BodyCiphertext.E)
2045		if !libkb.SecureByteArrayEq(bh[:], header.BodyHash) {
2046			return verifyMessageRes{}, NewPermanentUnboxingError(BodyHashInvalid{})
2047		}
2048	}
2049
2050	// check key validity
2051	// ValidSenderKey uses the server-given ctime, but emits senderDeviceRevokedAt as a workaround.
2052	// See ValidSenderKey for details.
2053	var revoked *gregor1.Time
2054	validationKey := header.HeaderSignature.K
2055	switch globals.CtxUnboxMode(ctx) {
2056	case types.UnboxModeFull:
2057		var ierr types.UnboxingError
2058		revoked, ierr = b.ValidSenderKey(ctx, header.Sender, header.HeaderSignature.K, msg.ServerHeader.Ctime)
2059		if ierr != nil {
2060			return verifyMessageRes{}, ierr
2061		}
2062	default:
2063		// Nothing to do.
2064	}
2065
2066	// check signature
2067	hcopy := header
2068	hcopy.HeaderSignature = nil
2069	hpack, err := b.marshal(hcopy)
2070	if err != nil {
2071		return verifyMessageRes{}, NewPermanentUnboxingError(err)
2072	}
2073	if !b.verify(hpack, *header.HeaderSignature, kbcrypto.SignaturePrefixChatMBv1) {
2074		return verifyMessageRes{}, NewPermanentUnboxingError(libkb.BadSigError{E: "header signature invalid"})
2075	}
2076
2077	return verifyMessageRes{
2078		senderDeviceRevokedAt: revoked,
2079		validationKey:         validationKey,
2080	}, nil
2081}
2082
2083// verify verifies the signature of data using SignatureInfo.
2084func (b *Boxer) verify(data []byte, si chat1.SignatureInfo, prefix kbcrypto.SignaturePrefix) bool {
2085	sigInfo := kbcrypto.NaclSigInfo{
2086		Version: si.V,
2087		Prefix:  prefix,
2088		Kid:     si.K,
2089		Payload: data,
2090	}
2091	copy(sigInfo.Sig[:], si.S)
2092	_, err := sigInfo.Verify()
2093	return (err == nil)
2094}
2095
2096// ValidSenderKey checks that the key was active for sender at ctime.
2097// This trusts the server for ctime, so a colluding server could use a revoked key and this check erroneously pass.
2098// But (revoked != nil) if the key was ever revoked, so that is irrespective of ctime.
2099// Returns (validAtCtime, revoked, err)
2100func (b *Boxer) ValidSenderKey(ctx context.Context, sender gregor1.UID, key []byte, ctime gregor1.Time) (revoked *gregor1.Time, unboxErr types.UnboxingError) {
2101	var found, deleted bool
2102	var revokedAt *keybase1.KeybaseTime
2103	validAtCtime := true
2104	if b.testingValidSenderKey != nil {
2105		b.assertInTest()
2106		return b.testingValidSenderKey(ctx, sender, key, ctime)
2107	}
2108	defer func() {
2109		if unboxErr == nil {
2110			if !found {
2111				unboxErr = NewPermanentUnboxingError(libkb.NoKeyError{Msg: "sender key not found"})
2112			} else if !validAtCtime {
2113				unboxErr = NewPermanentUnboxingError(libkb.NoKeyError{
2114					Msg: "key invalid for sender at message ctime",
2115				})
2116			}
2117		}
2118	}()
2119
2120	kbSender, err := keybase1.UIDFromString(hex.EncodeToString(sender.Bytes()))
2121	if err != nil {
2122		return nil, NewPermanentUnboxingError(err)
2123	}
2124	kid := keybase1.KIDFromSlice(key)
2125	ctime2 := gregor1.FromTime(ctime)
2126
2127	cachedUserLoader := globals.CtxUPAKFinder(ctx, b.G())
2128	if cachedUserLoader == nil {
2129		return nil, NewTransientUnboxingError(fmt.Errorf("no CachedUserLoader available in context"))
2130	}
2131
2132	found, revokedAt, deleted, err = cachedUserLoader.CheckKIDForUID(ctx, kbSender, kid)
2133	if err != nil {
2134		return nil, NewTransientUnboxingError(err)
2135	}
2136	if !found {
2137		return nil, nil
2138	}
2139
2140	if deleted {
2141		b.Debug(ctx, "sender %s key %s was deleted", kbSender, kid)
2142		// Set the key as being revoked since the beginning of time, so all messages will get labeled
2143		// as suspect
2144		zeroTime := gregor1.Time(0)
2145		return &zeroTime, nil
2146	}
2147
2148	if revokedAt != nil {
2149		if revokedAt.Unix.IsZero() {
2150			return nil, NewPermanentUnboxingError(fmt.Errorf("zero clock time on expired key"))
2151		}
2152		t := b.keybase1KeybaseTimeToTime(*revokedAt)
2153		revokedTime := gregor1.ToTime(t)
2154		revoked = &revokedTime
2155		validAtCtime = t.After(ctime2)
2156	}
2157	return revoked, nil
2158}
2159
2160func (b *Boxer) keybase1KeybaseTimeToTime(t1 keybase1.KeybaseTime) time.Time {
2161	// u is in milliseconds
2162	u := int64(t1.Unix)
2163	t2 := time.Unix(u/1e3, (u%1e3)*1e6)
2164	return t2
2165}
2166
2167func (b *Boxer) marshal(v interface{}) ([]byte, error) {
2168	mh := codec.MsgpackHandle{WriteExt: true}
2169	var data []byte
2170	enc := codec.NewEncoderBytes(&data, &mh)
2171	if err := enc.Encode(v); err != nil {
2172		return nil, err
2173	}
2174	return data, nil
2175}
2176
2177func (b *Boxer) unmarshal(data []byte, v interface{}) error {
2178	mh := codec.MsgpackHandle{WriteExt: true}
2179	dec := codec.NewDecoderBytes(data, &mh)
2180	return dec.Decode(&v)
2181}
2182
2183func (b *Boxer) assertInTest() {
2184	b.log().Warning("Using TESTING jig. Not suitable for normal use.")
2185	if flag.Lookup("test.v") == nil {
2186		panic("testing jig installed in normal mode")
2187	}
2188}
2189
2190func hashSha256V1(data []byte) chat1.Hash {
2191	sum := sha256.Sum256(data)
2192	return sum[:]
2193}
2194
2195// See note on compareHeadersMBV2orV3.
2196func (b *Boxer) compareHeadersMBV1(ctx context.Context, hServer chat1.MessageClientHeader, hSigned chat1.MessageClientHeaderVerified) types.UnboxingError {
2197	// Conv
2198	if !hServer.Conv.Eq(hSigned.Conv) {
2199		return NewPermanentUnboxingError(NewHeaderMismatchError("Conv"))
2200	}
2201
2202	// TlfName
2203	if hServer.TlfName != hSigned.TlfName {
2204		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfName"))
2205	}
2206
2207	// TlfPublic
2208	if hServer.TlfPublic != hSigned.TlfPublic {
2209		return NewPermanentUnboxingError(NewHeaderMismatchError("TlfPublic"))
2210	}
2211
2212	// MessageType
2213	if hServer.MessageType != hSigned.MessageType {
2214		return NewPermanentUnboxingError(NewHeaderMismatchError("MessageType"))
2215	}
2216
2217	// Note: Supersedes, Deletes, and some other fields are not checked because they are not
2218	//       part of MessageClientHeaderVerified.
2219
2220	// Prev
2221	if len(hServer.Prev) != len(hSigned.Prev) {
2222		return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
2223	}
2224	for i, a := range hServer.Prev {
2225		b := hSigned.Prev[i]
2226		if !a.Eq(b) {
2227			return NewPermanentUnboxingError(NewHeaderMismatchError("Prev"))
2228		}
2229	}
2230
2231	// Sender
2232	// This prevents someone from re-using a header for another sender
2233	if !hServer.Sender.Eq(hSigned.Sender) {
2234		return NewPermanentUnboxingError(NewHeaderMismatchError("Sender"))
2235	}
2236
2237	// SenderDevice
2238	if !bytes.Equal(hServer.SenderDevice.Bytes(), hSigned.SenderDevice.Bytes()) {
2239		return NewPermanentUnboxingError(NewHeaderMismatchError("SenderDevice"))
2240	}
2241
2242	// _Don't_ check that the MerkleRoot's match.
2243	// The signed MerkleRoot should be nil as it was not part of the protocol
2244	// when clients were writing MBV1. But we just allow anything here.
2245	// There are V1 messages in the wild with hServer.MerkleRoot set but nothing signed.
2246
2247	// OutboxID, OutboxInfo: Left unchecked as I'm not sure whether these hold in V1 messages.
2248
2249	return nil
2250}
2251
2252func (b *Boxer) CompareTlfNames(ctx context.Context, tlfName1, tlfName2 string,
2253	membersType chat1.ConversationMembersType, tlfPublic bool) (bool, error) {
2254	get1 := func(tlfName string, tlfPublic bool) (string, error) {
2255		nameInfo, err := CreateNameInfoSource(ctx, b.G(), membersType).LookupID(ctx, tlfName,
2256			tlfPublic)
2257		if err != nil {
2258			return "", err
2259		}
2260		return nameInfo.CanonicalName, nil
2261	}
2262
2263	c1, err := get1(tlfName1, tlfPublic)
2264	if err != nil {
2265		return false, err
2266	}
2267	c2, err := get1(tlfName2, tlfPublic)
2268	if err != nil {
2269		return false, err
2270	}
2271	return c1 == c2, nil
2272}
2273