psk.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package nebula
  2. import (
  3. "crypto/sha256"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "github.com/slackhq/nebula/config"
  8. "github.com/slackhq/nebula/util"
  9. "golang.org/x/crypto/hkdf"
  10. )
  11. var ErrNotAPskMode = errors.New("not a psk mode")
  12. var ErrKeyTooShort = errors.New("key is too short")
  13. var ErrNotEnoughPskKeys = errors.New("at least 1 key is required")
  14. // MinPskLength is the minimum bytes that we accept for a user defined psk, the choice is arbitrary
  15. const MinPskLength = 8
  16. type PskMode int
  17. const (
  18. PskAccepting PskMode = 0
  19. PskSending PskMode = 1
  20. PskEnforced PskMode = 2
  21. )
  22. func NewPskMode(m string) (PskMode, error) {
  23. switch m {
  24. case "accepting":
  25. return PskAccepting, nil
  26. case "sending":
  27. return PskSending, nil
  28. case "enforced":
  29. return PskEnforced, nil
  30. }
  31. return PskAccepting, ErrNotAPskMode
  32. }
  33. func (p PskMode) String() string {
  34. switch p {
  35. case PskAccepting:
  36. return "accepting"
  37. case PskSending:
  38. return "sending"
  39. case PskEnforced:
  40. return "enforced"
  41. }
  42. return "unknown"
  43. }
  44. func (p PskMode) IsValid() bool {
  45. switch p {
  46. case PskAccepting, PskSending, PskEnforced:
  47. return true
  48. default:
  49. return false
  50. }
  51. }
  52. type Psk struct {
  53. // pskMode sets how psk works, ignored, allowed for incoming, or enforced for all
  54. mode PskMode
  55. // primary is the key to use when sending, it may be nil
  56. primary []byte
  57. // keys holds all pre-computed psk hkdfs
  58. // Handshakes iterate this directly
  59. keys [][]byte
  60. }
  61. // NewPskFromConfig is a helper for initial boot and config reloading.
  62. func NewPskFromConfig(c *config.C) (*Psk, error) {
  63. sMode := c.GetString("psk.mode", "accepting")
  64. mode, err := NewPskMode(sMode)
  65. if err != nil {
  66. return nil, util.NewContextualError("Could not parse psk.mode", m{"mode": mode}, err)
  67. }
  68. return NewPsk(
  69. mode,
  70. c.GetStringSlice("psk.keys", nil),
  71. )
  72. }
  73. // NewPsk creates a new Psk object and handles the caching of all accepted keys
  74. func NewPsk(mode PskMode, keys []string) (*Psk, error) {
  75. if !mode.IsValid() {
  76. return nil, ErrNotAPskMode
  77. }
  78. psk := &Psk{
  79. mode: mode,
  80. }
  81. err := psk.cachePsks(keys)
  82. if err != nil {
  83. return nil, err
  84. }
  85. return psk, nil
  86. }
  87. // cachePsks generates all psks we accept and caches them to speed up handshaking
  88. func (p *Psk) cachePsks(keys []string) error {
  89. if p.mode != PskAccepting && len(keys) < 1 {
  90. return ErrNotEnoughPskKeys
  91. }
  92. p.keys = [][]byte{}
  93. for i, rk := range keys {
  94. k, err := sha256KdfFromString(rk)
  95. if err != nil {
  96. return fmt.Errorf("failed to generate key for position %v: %w", i, err)
  97. }
  98. p.keys = append(p.keys, k)
  99. }
  100. if p.mode != PskAccepting {
  101. // We are either sending or enforcing, the primary key must the first slot
  102. p.primary = p.keys[0]
  103. }
  104. if p.mode != PskEnforced {
  105. // If we are not enforcing psk use then a nil psk is allowed
  106. p.keys = append(p.keys, nil)
  107. }
  108. return nil
  109. }
  110. // sha256KdfFromString generates a useful key to use from a provided secret
  111. func sha256KdfFromString(secret string) ([]byte, error) {
  112. if len(secret) < MinPskLength {
  113. return nil, ErrKeyTooShort
  114. }
  115. hmacKey := make([]byte, sha256.Size)
  116. _, err := io.ReadFull(hkdf.New(sha256.New, []byte(secret), nil, nil), hmacKey)
  117. if err != nil {
  118. return nil, err
  119. }
  120. return hmacKey, nil
  121. }