connection_state_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package nebula
  2. import (
  3. "net/netip"
  4. "testing"
  5. "time"
  6. "github.com/flynn/noise"
  7. "github.com/slackhq/nebula/cert"
  8. ct "github.com/slackhq/nebula/cert_test"
  9. "github.com/slackhq/nebula/handshake"
  10. "github.com/slackhq/nebula/header"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. )
  14. // runTestHandshake runs a complete IX handshake between two freshly-built
  15. // peers and returns the initiator and responder Results. Used to produce
  16. // real cipher states for tests that need to exercise post-handshake glue.
  17. func runTestHandshake(t *testing.T) (initR, respR *handshake.Result) {
  18. t.Helper()
  19. ca, _, caKey, _ := ct.NewTestCaCert(
  20. cert.Version2, cert.Curve_CURVE25519, time.Time{}, time.Time{}, nil, nil, nil,
  21. )
  22. caPool := ct.NewTestCAPool(ca)
  23. makeCreds := func(name string, networks []netip.Prefix) handshake.GetCredentialFunc {
  24. c, _, rawKey, _ := ct.NewTestCert(
  25. cert.Version2, cert.Curve_CURVE25519, ca, caKey,
  26. name, ca.NotBefore(), ca.NotAfter(), networks, nil, nil,
  27. )
  28. priv, _, _, err := cert.UnmarshalPrivateKeyFromPEM(rawKey)
  29. require.NoError(t, err)
  30. hsBytes, err := c.MarshalForHandshakes()
  31. require.NoError(t, err)
  32. ncs := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256)
  33. cred := handshake.NewCredential(c, hsBytes, priv, ncs)
  34. return func(v cert.Version) *handshake.Credential {
  35. if v == cert.Version2 {
  36. return cred
  37. }
  38. return nil
  39. }
  40. }
  41. verifier := func(c cert.Certificate) (*cert.CachedCertificate, error) {
  42. return caPool.VerifyCertificate(time.Now(), c)
  43. }
  44. initCreds := makeCreds("initiator", []netip.Prefix{netip.MustParsePrefix("10.0.0.1/24")})
  45. respCreds := makeCreds("responder", []netip.Prefix{netip.MustParsePrefix("10.0.0.2/24")})
  46. initM, err := handshake.NewMachine(
  47. cert.Version2, initCreds, verifier,
  48. func() (uint32, error) { return 1000, nil },
  49. true, header.HandshakeIXPSK0,
  50. )
  51. require.NoError(t, err)
  52. respM, err := handshake.NewMachine(
  53. cert.Version2, respCreds, verifier,
  54. func() (uint32, error) { return 2000, nil },
  55. false, header.HandshakeIXPSK0,
  56. )
  57. require.NoError(t, err)
  58. msg1, err := initM.Initiate(nil)
  59. require.NoError(t, err)
  60. resp, respR, err := respM.ProcessPacket(nil, msg1)
  61. require.NoError(t, err)
  62. require.NotNil(t, respR)
  63. _, initR, err = initM.ProcessPacket(nil, resp)
  64. require.NoError(t, err)
  65. require.NotNil(t, initR)
  66. return initR, respR
  67. }
  68. func TestNewConnectionStateFromResult(t *testing.T) {
  69. initR, respR := runTestHandshake(t)
  70. t.Run("initiator", func(t *testing.T) {
  71. ci := newConnectionStateFromResult(initR)
  72. assert.True(t, ci.initiator)
  73. assert.Equal(t, initR.MyCert, ci.myCert)
  74. assert.Equal(t, initR.RemoteCert, ci.peerCert)
  75. assert.NotNil(t, ci.eKey)
  76. assert.NotNil(t, ci.dKey)
  77. // IX has 2 handshake messages; the next data-plane send is counter=3.
  78. assert.Equal(t, uint64(2), ci.messageCounter.Load(),
  79. "messageCounter must equal Result.MessageIndex so the next send is N+1")
  80. // Both handshake counters must be marked seen so they don't appear lost.
  81. // Check returns false if an index has already been recorded.
  82. assert.False(t, ci.window.Check(nil, 1), "counter 1 must already be seen")
  83. assert.False(t, ci.window.Check(nil, 2), "counter 2 must already be seen")
  84. // Counter 3 is the next data-plane message and must NOT be pre-marked.
  85. assert.True(t, ci.window.Check(nil, 3), "counter 3 must not be pre-seeded")
  86. })
  87. t.Run("responder", func(t *testing.T) {
  88. ci := newConnectionStateFromResult(respR)
  89. assert.False(t, ci.initiator)
  90. assert.Equal(t, respR.MyCert, ci.myCert)
  91. assert.Equal(t, respR.RemoteCert, ci.peerCert)
  92. assert.NotNil(t, ci.eKey)
  93. assert.NotNil(t, ci.dKey)
  94. assert.Equal(t, uint64(2), ci.messageCounter.Load())
  95. })
  96. }