psk.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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/iputil"
  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. // The minimum length that we accept for a user defined psk, the choice is arbitrary
  15. const MinPskLength = 8
  16. type PskMode int
  17. func (p PskMode) String() string {
  18. switch p {
  19. case PskNone:
  20. return "none"
  21. case PskTransitional:
  22. return "transitional"
  23. case PskEnforced:
  24. return "enforced"
  25. }
  26. return "unknown"
  27. }
  28. func NewPskMode(m string) (PskMode, error) {
  29. switch m {
  30. case "none":
  31. return PskNone, nil
  32. case "transitional":
  33. return PskTransitional, nil
  34. case "enforced":
  35. return PskEnforced, nil
  36. }
  37. return PskNone, ErrNotAPskMode
  38. }
  39. const (
  40. PskNone PskMode = 0
  41. PskTransitional PskMode = 1
  42. PskEnforced PskMode = 2
  43. )
  44. type Psk struct {
  45. // pskMode sets how psk works, ignored, allowed for incoming, or enforced for all
  46. mode PskMode
  47. // Cache holds all pre-computed psk hkdfs
  48. // Handshakes iterate this directly
  49. Cache [][]byte
  50. // The key has already been extracted and is ready to be expanded for use
  51. // MakeFor does the final expand step mixing in the intended recipients vpn ip
  52. key []byte
  53. }
  54. // NewPskFromConfig is a helper for initial boot and config reloading.
  55. func NewPskFromConfig(c *config.C, myVpnIp iputil.VpnIp) (*Psk, error) {
  56. sMode := c.GetString("handshakes.psk.mode", "none")
  57. mode, err := NewPskMode(sMode)
  58. if err != nil {
  59. return nil, NewContextualError("Could not parse handshakes.psk.mode", m{"mode": mode}, err)
  60. }
  61. return NewPsk(
  62. mode,
  63. c.GetStringSlice("handshakes.psk.keys", nil),
  64. myVpnIp,
  65. )
  66. }
  67. // NewPsk creates a new Psk object and handles the caching of all accepted keys and preparation of the primary key
  68. func NewPsk(mode PskMode, keys []string, myVpnIp iputil.VpnIp) (*Psk, error) {
  69. psk := &Psk{
  70. mode: mode,
  71. }
  72. err := psk.preparePrimaryKey(keys)
  73. if err != nil {
  74. return nil, err
  75. }
  76. err = psk.cachePsks(myVpnIp, keys)
  77. if err != nil {
  78. return nil, err
  79. }
  80. return psk, nil
  81. }
  82. // MakeFor if we are in enforced mode, the final hkdf expand stage is done on the pre extracted primary key,
  83. // mixing in the intended recipients vpn ip and the result is returned.
  84. // If we are transitional or not using psks, an empty byte slice is returned
  85. func (p *Psk) MakeFor(vpnIp iputil.VpnIp) ([]byte, error) {
  86. if p.mode != PskEnforced {
  87. return []byte{}, nil
  88. }
  89. hmacKey := make([]byte, sha256.Size)
  90. _, err := io.ReadFull(hkdf.Expand(sha256.New, p.key, vpnIp.ToIP()), hmacKey)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return hmacKey, nil
  95. }
  96. // cachePsks generates all psks we accept and caches them to speed up handshaking
  97. func (p *Psk) cachePsks(myVpnIp iputil.VpnIp, keys []string) error {
  98. // If PskNone is set then we are using the nil byte array for a psk, we can return
  99. if p.mode == PskNone {
  100. p.Cache = [][]byte{nil}
  101. return nil
  102. }
  103. if len(keys) < 1 {
  104. return ErrNotEnoughPskKeys
  105. }
  106. p.Cache = [][]byte{}
  107. if p.mode == PskTransitional {
  108. // We are transitional, we accept empty psks
  109. p.Cache = append(p.Cache, nil)
  110. }
  111. // We are either PskAuto or PskTransitional, build all possibilities
  112. for i, rk := range keys {
  113. k, err := sha256KdfFromString(rk, myVpnIp)
  114. if err != nil {
  115. return fmt.Errorf("failed to generate key for position %v: %w", i, err)
  116. }
  117. p.Cache = append(p.Cache, k)
  118. }
  119. return nil
  120. }
  121. // preparePrimaryKey if we are in enforced mode, will do an hkdf extract on the first key to benefit
  122. // outgoing handshake performance, MakeFor does the final expand step
  123. func (p *Psk) preparePrimaryKey(keys []string) error {
  124. if p.mode != PskEnforced {
  125. // If we aren't enforcing then there is nothing to prepare
  126. return nil
  127. }
  128. if len(keys) < 1 {
  129. return ErrNotEnoughPskKeys
  130. }
  131. p.key = hkdf.Extract(sha256.New, []byte(keys[0]), nil)
  132. return nil
  133. }
  134. // sha256KdfFromString generates a full hkdf
  135. func sha256KdfFromString(secret string, vpnIp iputil.VpnIp) ([]byte, error) {
  136. if len(secret) < MinPskLength {
  137. return nil, ErrKeyTooShort
  138. }
  139. hmacKey := make([]byte, sha256.Size)
  140. _, err := io.ReadFull(hkdf.New(sha256.New, []byte(secret), nil, vpnIp.ToIP()), hmacKey)
  141. if err != nil {
  142. return nil, err
  143. }
  144. return hmacKey, nil
  145. }