handshake.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright (c) 2021 Tulir Asokan
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package whatsmeow
  7. import (
  8. "bytes"
  9. "context"
  10. "fmt"
  11. "time"
  12. "go.mau.fi/libsignal/ecc"
  13. "google.golang.org/protobuf/proto"
  14. "go.mau.fi/whatsmeow/proto/waCert"
  15. "go.mau.fi/whatsmeow/proto/waWa6"
  16. "go.mau.fi/whatsmeow/socket"
  17. "go.mau.fi/whatsmeow/util/keys"
  18. )
  19. const NoiseHandshakeResponseTimeout = 20 * time.Second
  20. const WACertIssuerSerial = 0
  21. var WACertPubKey = [...]byte{0x14, 0x23, 0x75, 0x57, 0x4d, 0xa, 0x58, 0x71, 0x66, 0xaa, 0xe7, 0x1e, 0xbe, 0x51, 0x64, 0x37, 0xc4, 0xa2, 0x8b, 0x73, 0xe3, 0x69, 0x5c, 0x6c, 0xe1, 0xf7, 0xf9, 0x54, 0x5d, 0xa8, 0xee, 0x6b}
  22. // doHandshake implements the Noise_XX_25519_AESGCM_SHA256 handshake for the WhatsApp web API.
  23. func (cli *Client) doHandshake(ctx context.Context, fs *socket.FrameSocket, ephemeralKP keys.KeyPair) error {
  24. nh := socket.NewNoiseHandshake()
  25. nh.Start(socket.NoiseStartPattern, fs.Header)
  26. nh.Authenticate(ephemeralKP.Pub[:])
  27. data, err := proto.Marshal(&waWa6.HandshakeMessage{
  28. ClientHello: &waWa6.HandshakeMessage_ClientHello{
  29. Ephemeral: ephemeralKP.Pub[:],
  30. },
  31. })
  32. if err != nil {
  33. return fmt.Errorf("failed to marshal handshake message: %w", err)
  34. }
  35. err = fs.SendFrame(data)
  36. if err != nil {
  37. return fmt.Errorf("failed to send handshake message: %w", err)
  38. }
  39. var resp []byte
  40. select {
  41. case resp = <-fs.Frames:
  42. case <-time.After(NoiseHandshakeResponseTimeout):
  43. return fmt.Errorf("timed out waiting for handshake response")
  44. }
  45. var handshakeResponse waWa6.HandshakeMessage
  46. err = proto.Unmarshal(resp, &handshakeResponse)
  47. if err != nil {
  48. return fmt.Errorf("failed to unmarshal handshake response: %w", err)
  49. }
  50. serverEphemeral := handshakeResponse.GetServerHello().GetEphemeral()
  51. serverStaticCiphertext := handshakeResponse.GetServerHello().GetStatic()
  52. certificateCiphertext := handshakeResponse.GetServerHello().GetPayload()
  53. if len(serverEphemeral) != 32 || serverStaticCiphertext == nil || certificateCiphertext == nil {
  54. return fmt.Errorf("missing parts of handshake response")
  55. }
  56. serverEphemeralArr := *(*[32]byte)(serverEphemeral)
  57. nh.Authenticate(serverEphemeral)
  58. err = nh.MixSharedSecretIntoKey(*ephemeralKP.Priv, serverEphemeralArr)
  59. if err != nil {
  60. return fmt.Errorf("failed to mix server ephemeral key in: %w", err)
  61. }
  62. staticDecrypted, err := nh.Decrypt(serverStaticCiphertext)
  63. if err != nil {
  64. return fmt.Errorf("failed to decrypt server static ciphertext: %w", err)
  65. } else if len(staticDecrypted) != 32 {
  66. return fmt.Errorf("unexpected length of server static plaintext %d (expected 32)", len(staticDecrypted))
  67. }
  68. err = nh.MixSharedSecretIntoKey(*ephemeralKP.Priv, *(*[32]byte)(staticDecrypted))
  69. if err != nil {
  70. return fmt.Errorf("failed to mix server static key in: %w", err)
  71. }
  72. certDecrypted, err := nh.Decrypt(certificateCiphertext)
  73. if err != nil {
  74. return fmt.Errorf("failed to decrypt noise certificate ciphertext: %w", err)
  75. } else if err = verifyServerCert(certDecrypted, staticDecrypted); err != nil {
  76. return fmt.Errorf("failed to verify server cert: %w", err)
  77. }
  78. encryptedPubkey := nh.Encrypt(cli.Store.NoiseKey.Pub[:])
  79. err = nh.MixSharedSecretIntoKey(*cli.Store.NoiseKey.Priv, serverEphemeralArr)
  80. if err != nil {
  81. return fmt.Errorf("failed to mix noise private key in: %w", err)
  82. }
  83. var clientPayload *waWa6.ClientPayload
  84. if cli.GetClientPayload != nil {
  85. clientPayload = cli.GetClientPayload()
  86. } else {
  87. clientPayload = cli.Store.GetClientPayload()
  88. }
  89. clientFinishPayloadBytes, err := proto.Marshal(clientPayload)
  90. if err != nil {
  91. return fmt.Errorf("failed to marshal client finish payload: %w", err)
  92. }
  93. encryptedClientFinishPayload := nh.Encrypt(clientFinishPayloadBytes)
  94. data, err = proto.Marshal(&waWa6.HandshakeMessage{
  95. ClientFinish: &waWa6.HandshakeMessage_ClientFinish{
  96. Static: encryptedPubkey,
  97. Payload: encryptedClientFinishPayload,
  98. },
  99. })
  100. if err != nil {
  101. return fmt.Errorf("failed to marshal handshake finish message: %w", err)
  102. }
  103. err = fs.SendFrame(data)
  104. if err != nil {
  105. return fmt.Errorf("failed to send handshake finish message: %w", err)
  106. }
  107. ns, err := nh.Finish(ctx, fs, cli.handleFrame, cli.onDisconnect)
  108. if err != nil {
  109. return fmt.Errorf("failed to create noise socket: %w", err)
  110. }
  111. cli.socket = ns
  112. return nil
  113. }
  114. func verifyServerCert(certDecrypted, staticDecrypted []byte) error {
  115. var certChain waCert.CertChain
  116. err := proto.Unmarshal(certDecrypted, &certChain)
  117. if err != nil {
  118. return fmt.Errorf("failed to unmarshal noise certificate: %w", err)
  119. }
  120. var intermediateCertDetails, leafCertDetails waCert.CertChain_NoiseCertificate_Details
  121. intermediateCertDetailsRaw := certChain.GetIntermediate().GetDetails()
  122. intermediateCertSignature := certChain.GetIntermediate().GetSignature()
  123. leafCertDetailsRaw := certChain.GetLeaf().GetDetails()
  124. leafCertSignature := certChain.GetLeaf().GetSignature()
  125. if intermediateCertDetailsRaw == nil || intermediateCertSignature == nil || leafCertDetailsRaw == nil || leafCertSignature == nil {
  126. return fmt.Errorf("missing parts of noise certificate")
  127. } else if len(intermediateCertSignature) != 64 {
  128. return fmt.Errorf("unexpected length of intermediate cert signature %d (expected 64)", len(intermediateCertSignature))
  129. } else if len(leafCertSignature) != 64 {
  130. return fmt.Errorf("unexpected length of leaf cert signature %d (expected 64)", len(leafCertSignature))
  131. } else if !ecc.VerifySignature(ecc.NewDjbECPublicKey(WACertPubKey), intermediateCertDetailsRaw, [64]byte(intermediateCertSignature)) {
  132. return fmt.Errorf("failed to verify intermediate cert signature")
  133. } else if err = proto.Unmarshal(intermediateCertDetailsRaw, &intermediateCertDetails); err != nil {
  134. return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
  135. } else if intermediateCertDetails.GetIssuerSerial() != WACertIssuerSerial {
  136. return fmt.Errorf("unexpected intermediate issuer serial %d (expected %d)", intermediateCertDetails.GetIssuerSerial(), WACertIssuerSerial)
  137. } else if len(intermediateCertDetails.GetKey()) != 32 {
  138. return fmt.Errorf("unexpected length of intermediate cert key %d (expected 32)", len(intermediateCertDetails.GetKey()))
  139. } else if !ecc.VerifySignature(ecc.NewDjbECPublicKey([32]byte(intermediateCertDetails.GetKey())), leafCertDetailsRaw, [64]byte(leafCertSignature)) {
  140. return fmt.Errorf("failed to verify intermediate cert signature")
  141. } else if err = proto.Unmarshal(leafCertDetailsRaw, &leafCertDetails); err != nil {
  142. return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
  143. } else if leafCertDetails.GetIssuerSerial() != intermediateCertDetails.GetSerial() {
  144. return fmt.Errorf("unexpected leaf issuer serial %d (expected %d)", leafCertDetails.GetIssuerSerial(), intermediateCertDetails.GetSerial())
  145. } else if !bytes.Equal(leafCertDetails.GetKey(), staticDecrypted) {
  146. return fmt.Errorf("cert key doesn't match decrypted static")
  147. }
  148. return nil
  149. }