patterns.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package handshake
  2. import (
  3. "fmt"
  4. "github.com/flynn/noise"
  5. "github.com/slackhq/nebula/header"
  6. )
  7. // msgFlags tracks what application data a handshake message carries.
  8. type msgFlags struct {
  9. expectsPayload bool // message carries indexes and time
  10. expectsCert bool // message carries the certificate
  11. kemKey bool // payload carries an ML-KEM encapsulation key
  12. kemCiphertext bool // message is prefixed with the ML-KEM ciphertext for the peer's key
  13. }
  14. // subtypeInfo bundles the noise pattern with the per-message flags for a
  15. // given handshake subtype.
  16. type subtypeInfo struct {
  17. pattern noise.HandshakePattern
  18. pskPlacement int // noise psk modifier position, 0 means no psk token
  19. msgs []msgFlags
  20. }
  21. // subtypeInfos defines the noise pattern and message content layout for each
  22. // handshake subtype.
  23. var subtypeInfos = map[header.MessageSubType]subtypeInfo{
  24. // IX: 2 messages, both carry payload and cert
  25. header.HandshakeIXPSK0: {
  26. pattern: noise.HandshakeIX,
  27. msgs: []msgFlags{
  28. {expectsPayload: true, expectsCert: true},
  29. {expectsPayload: true, expectsCert: true},
  30. },
  31. },
  32. // IX with an ephemeral ML-KEM-1024 exchange:
  33. // msg1 (I->R): payload + cert + encapsulation key
  34. // msg2 (R->I): ciphertext || noise(payload + cert)
  35. // The responder encapsulates after reading msg1 and mixes the shared secret in
  36. // through the psk2 token at the end of msg2. The ciphertext travels outside the
  37. // noise message because the initiator needs the secret before it can process
  38. // that token.
  39. header.HandshakeIXPSK2MLKEM1024: {
  40. pattern: noise.HandshakeIX,
  41. pskPlacement: 2,
  42. msgs: []msgFlags{
  43. {expectsPayload: true, expectsCert: true, kemKey: true},
  44. {expectsPayload: true, expectsCert: true, kemCiphertext: true},
  45. },
  46. },
  47. // XX: 3 messages
  48. // msg1 (I->R): payload only
  49. // msg2 (R->I): payload + cert
  50. // msg3 (I->R): cert only
  51. //header.HandshakeXXPSK0: {
  52. // pattern: noise.HandshakeXX,
  53. // msgs: []msgFlags{
  54. // {expectsPayload: true, expectsCert: false},
  55. // {expectsPayload: true, expectsCert: true},
  56. // {expectsPayload: false, expectsCert: true},
  57. // },
  58. //},
  59. }
  60. func subtypeInfoFor(subtype header.MessageSubType) (subtypeInfo, error) {
  61. if info, ok := subtypeInfos[subtype]; ok {
  62. return info, nil
  63. }
  64. return subtypeInfo{}, fmt.Errorf("%w: %d", ErrUnknownSubtype, subtype)
  65. }