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