connection_state.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package nebula
  2. import (
  3. "encoding/json"
  4. "log/slog"
  5. "sync"
  6. "sync/atomic"
  7. "github.com/slackhq/nebula/cert"
  8. "github.com/slackhq/nebula/handshake"
  9. "github.com/slackhq/nebula/header"
  10. "github.com/slackhq/nebula/noiseutil"
  11. )
  12. const ReplayWindow = 1024
  13. type ConnectionState struct {
  14. eKey noiseutil.CipherState
  15. dKey noiseutil.CipherState
  16. myCert cert.Certificate
  17. peerCert *cert.CachedCertificate
  18. initiator bool
  19. messageCounter atomic.Uint64
  20. window *Bits
  21. decryptLock sync.Mutex
  22. writeLock sync.Mutex
  23. }
  24. // newConnectionStateFromResult builds a fully-populated ConnectionState from a
  25. // completed handshake.Result. It seeds messageCounter and the replay window so
  26. // that the post-handshake message indices already used on the wire don't count
  27. // as missed traffic in the data plane.
  28. func newConnectionStateFromResult(r *handshake.Result) *ConnectionState {
  29. ci := &ConnectionState{
  30. myCert: r.MyCert,
  31. initiator: r.Initiator,
  32. peerCert: r.RemoteCert,
  33. eKey: noiseutil.NewCipherState(r.EKey, r.Cipher),
  34. dKey: noiseutil.NewCipherState(r.DKey, r.Cipher),
  35. window: NewBits(ReplayWindow),
  36. }
  37. ci.messageCounter.Add(r.MessageIndex)
  38. for i := uint64(1); i <= r.MessageIndex; i++ {
  39. ci.window.Update(nil, i)
  40. }
  41. return ci
  42. }
  43. func (cs *ConnectionState) MarshalJSON() ([]byte, error) {
  44. return json.Marshal(m{
  45. "certificate": cs.peerCert,
  46. "initiator": cs.initiator,
  47. "message_counter": cs.messageCounter.Load(),
  48. })
  49. }
  50. func (cs *ConnectionState) Curve() cert.Curve {
  51. return cs.myCert.Curve()
  52. }
  53. func (cs *ConnectionState) Decrypt(l *slog.Logger, messageCounter uint64, out []byte, packet []byte, nb []byte) ([]byte, error) {
  54. var err error
  55. cs.decryptLock.Lock()
  56. result := cs.window.Check(l, messageCounter)
  57. cs.decryptLock.Unlock()
  58. if !result {
  59. return nil, ErrAlreadySeen
  60. }
  61. out, err = cs.dKey.DecryptDanger(out, packet[:header.Len], packet[header.Len:], messageCounter, nb)
  62. if err != nil {
  63. return nil, err
  64. }
  65. cs.decryptLock.Lock()
  66. result = cs.window.Update(l, messageCounter)
  67. cs.decryptLock.Unlock()
  68. if !result {
  69. return nil, ErrAlreadySeen
  70. }
  71. return out, nil
  72. }
  73. // VerifyRelay verifies AEAD protected (but not encrypted) relay frames. packet must be length-checked by the caller.
  74. func (cs *ConnectionState) VerifyRelay(l *slog.Logger, messageCounter uint64, packet []byte, nb []byte) error {
  75. cs.decryptLock.Lock()
  76. result := cs.window.Check(l, messageCounter)
  77. cs.decryptLock.Unlock()
  78. if !result {
  79. return ErrAlreadySeen
  80. }
  81. signedPayload := packet[:len(packet)-cs.dKey.Overhead()]
  82. signatureValue := packet[len(packet)-cs.dKey.Overhead():]
  83. _, err := cs.dKey.DecryptDanger(nil, signedPayload, signatureValue, messageCounter, nb)
  84. if err != nil {
  85. return err
  86. }
  87. cs.decryptLock.Lock()
  88. result = cs.window.Update(l, messageCounter)
  89. cs.decryptLock.Unlock()
  90. if !result {
  91. return ErrAlreadySeen
  92. }
  93. return nil
  94. }