Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1487548

Browse files
committedNov 14, 2024·
PSK support for v2
1 parent 5380fef commit 1487548

9 files changed

+451
-33
lines changed
 

‎connection_state.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type ConnectionState struct {
2727
writeLock sync.Mutex
2828
}
2929

30-
func NewConnectionState(l *logrus.Logger, cs *CertState, crt cert.Certificate, initiator bool, pattern noise.HandshakePattern) (*ConnectionState, error) {
30+
func NewConnectionState(l *logrus.Logger, cs *CertState, crt cert.Certificate, initiator bool, pattern noise.HandshakePattern, psk []byte) (*ConnectionState, error) {
3131
var dhFunc noise.DHFunc
3232
switch crt.Curve() {
3333
case cert.Curve_CURVE25519:
@@ -56,13 +56,12 @@ func NewConnectionState(l *logrus.Logger, cs *CertState, crt cert.Certificate, i
5656
b.Update(l, 0)
5757

5858
hs, err := noise.NewHandshakeState(noise.Config{
59-
CipherSuite: ncs,
60-
Random: rand.Reader,
61-
Pattern: pattern,
62-
Initiator: initiator,
63-
StaticKeypair: static,
64-
//NOTE: These should come from CertState (pki.go) when we finally implement it
65-
PresharedKey: []byte{},
59+
CipherSuite: ncs,
60+
Random: rand.Reader,
61+
Pattern: pattern,
62+
Initiator: initiator,
63+
StaticKeypair: static,
64+
PresharedKey: psk,
6665
PresharedKeyPlacement: 0,
6766
})
6867
if err != nil {

‎e2e/handshakes_test.go

+132
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,138 @@ func TestV2NonPrimaryWithLighthouse(t *testing.T) {
11051105
theirControl.Stop()
11061106
}
11071107

1108+
func TestPSK(t *testing.T) {
1109+
tests := []struct {
1110+
name string
1111+
myPskMode nebula.PskMode
1112+
theirPskMode nebula.PskMode
1113+
}{
1114+
// All accepting
1115+
{
1116+
name: "both accepting",
1117+
myPskMode: nebula.PskAccepting,
1118+
theirPskMode: nebula.PskAccepting,
1119+
},
1120+
1121+
// accepting and sending both ways
1122+
{
1123+
name: "accepting to sending",
1124+
myPskMode: nebula.PskAccepting,
1125+
theirPskMode: nebula.PskSending,
1126+
},
1127+
{
1128+
name: "sending to accepting",
1129+
myPskMode: nebula.PskSending,
1130+
theirPskMode: nebula.PskAccepting,
1131+
},
1132+
1133+
// All sending
1134+
{
1135+
name: "sending to sending",
1136+
myPskMode: nebula.PskSending,
1137+
theirPskMode: nebula.PskSending,
1138+
},
1139+
1140+
// enforced and sending both ways
1141+
{
1142+
name: "enforced to sending",
1143+
myPskMode: nebula.PskEnforced,
1144+
theirPskMode: nebula.PskSending,
1145+
},
1146+
{
1147+
name: "sending to enforced",
1148+
myPskMode: nebula.PskSending,
1149+
theirPskMode: nebula.PskEnforced,
1150+
},
1151+
1152+
// All enforced
1153+
{
1154+
name: "both enforced",
1155+
myPskMode: nebula.PskEnforced,
1156+
theirPskMode: nebula.PskEnforced,
1157+
},
1158+
1159+
// Enforced can technically handshake with an accepting node, but it is bad to be in this state
1160+
{
1161+
name: "enforced to accepting",
1162+
myPskMode: nebula.PskEnforced,
1163+
theirPskMode: nebula.PskAccepting,
1164+
},
1165+
}
1166+
1167+
for _, test := range tests {
1168+
t.Run(test.name, func(t *testing.T) {
1169+
var myPskSettings, theirPskSettings m
1170+
1171+
switch test.myPskMode {
1172+
case nebula.PskAccepting:
1173+
myPskSettings = m{"psk": &m{"mode": "accepting", "keys": []string{"garbage0", "this is a key"}}}
1174+
case nebula.PskSending:
1175+
myPskSettings = m{"psk": &m{"mode": "sending", "keys": []string{"this is a key", "garbage1"}}}
1176+
case nebula.PskEnforced:
1177+
myPskSettings = m{"psk": &m{"mode": "enforced", "keys": []string{"this is a key", "garbage2"}}}
1178+
}
1179+
1180+
switch test.theirPskMode {
1181+
case nebula.PskAccepting:
1182+
theirPskSettings = m{"psk": &m{"mode": "accepting", "keys": []string{"garbage3", "this is a key"}}}
1183+
case nebula.PskSending:
1184+
theirPskSettings = m{"psk": &m{"mode": "sending", "keys": []string{"this is a key", "garbage4"}}}
1185+
case nebula.PskEnforced:
1186+
theirPskSettings = m{"psk": &m{"mode": "enforced", "keys": []string{"this is a key", "garbage5"}}}
1187+
}
1188+
1189+
ca, _, caKey, _ := cert_test.NewTestCaCert(cert.Version2, cert.Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
1190+
myControl, myVpnIp, myUdpAddr, _ := newSimpleServer(cert.Version2, ca, caKey, "me", "10.0.0.1/24", myPskSettings)
1191+
theirControl, theirVpnIp, theirUdpAddr, _ := newSimpleServer(cert.Version2, ca, caKey, "them", "10.0.0.2/24", theirPskSettings)
1192+
1193+
myControl.InjectLightHouseAddr(theirVpnIp[0].Addr(), theirUdpAddr)
1194+
r := router.NewR(t, myControl, theirControl)
1195+
1196+
// Start the servers
1197+
myControl.Start()
1198+
theirControl.Start()
1199+
1200+
t.Log("Route until we see our cached packet flow")
1201+
myControl.InjectTunUDPPacket(theirVpnIp[0].Addr(), 80, myVpnIp[0].Addr(), 80, []byte("Hi from me"))
1202+
r.RouteForAllExitFunc(func(p *udp.Packet, c *nebula.Control) router.ExitType {
1203+
h := &header.H{}
1204+
err := h.Parse(p.Data)
1205+
if err != nil {
1206+
panic(err)
1207+
}
1208+
1209+
// If this is the stage 1 handshake packet and I am configured to send with a psk, my cert name should
1210+
// not appear. It would likely be more obvious to unmarshal the payload and check but this works fine for now
1211+
if test.myPskMode == nebula.PskEnforced || test.myPskMode == nebula.PskSending {
1212+
if h.Type == 0 && h.MessageCounter == 1 {
1213+
assert.NotContains(t, string(p.Data), "test me")
1214+
}
1215+
}
1216+
1217+
if p.To == theirUdpAddr && h.Type == 1 {
1218+
return router.RouteAndExit
1219+
}
1220+
1221+
return router.KeepRouting
1222+
})
1223+
1224+
t.Log("My cached packet should be received by them")
1225+
myCachedPacket := theirControl.GetFromTun(true)
1226+
assertUdpPacket(t, []byte("Hi from me"), myCachedPacket, myVpnIp[0].Addr(), theirVpnIp[0].Addr(), 80, 80)
1227+
1228+
t.Log("Test the tunnel with them")
1229+
assertHostInfoPair(t, myUdpAddr, theirUdpAddr, myVpnIp, theirVpnIp, myControl, theirControl)
1230+
assertTunnel(t, myVpnIp[0].Addr(), theirVpnIp[0].Addr(), myControl, theirControl, r)
1231+
1232+
myControl.Stop()
1233+
theirControl.Stop()
1234+
//TODO: assert hostmaps
1235+
})
1236+
}
1237+
1238+
}
1239+
11081240
//TODO: test
11091241
// Race winner renews and handshakes
11101242
// Race loser renews and handshakes

‎e2e/router/router.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,6 @@ type ExitFunc func(packet *udp.Packet, receiver *nebula.Control) ExitType
111111
func NewR(t testing.TB, controls ...*nebula.Control) *R {
112112
ctx, cancel := context.WithCancel(context.Background())
113113

114-
if err := os.MkdirAll("mermaid", 0755); err != nil {
115-
panic(err)
116-
}
117-
118114
r := &R{
119115
controls: make(map[netip.AddrPort]*nebula.Control),
120116
vpnControls: make(map[netip.Addr]*nebula.Control),
@@ -194,6 +190,9 @@ func (r *R) renderFlow() {
194190
return
195191
}
196192

193+
if err := os.MkdirAll(filepath.Dir(r.fn), 0755); err != nil {
194+
panic(err)
195+
}
197196
f, err := os.OpenFile(r.fn, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
198197
if err != nil {
199198
panic(err)

‎examples/config.yml

+32-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,38 @@ pki:
1919
# After all hosts in the mesh are using a v2 certificate then v1 certificates are no longer needed.
2020
# default_version: 1
2121

22+
# psk can be used to mask the contents of handshakes.
23+
psk:
24+
# `mode` defines how the pre shared keys can be used in a handshake.
25+
# `accepting` (the default) will initiate handshakes using an empty key and will try to use any keys provided when
26+
# receiving handshakes, including an empty key.
27+
# `sending` will initiate handshakes with the first key provided and will try to use any keys provided when
28+
# receiving handshakes, including an empty key.
29+
# `enforced` will initiate handshakes with the first psk key provided and will try to use any keys provided when
30+
# responding to handshakes. An empty key will not be allowed.
31+
#
32+
# To change a mesh from not using a psk to enforcing psk:
33+
# 1. Leave `mode` as `accepting` and configure `psk.keys` to match on all nodes in the mesh and reload.
34+
# 2. Change `mode` to `sending` on all nodes in the mesh and reload.
35+
# 3. Change `mode` to `enforced` on all nodes in the mesh and reload.
36+
#mode: accepting
37+
38+
# The keys provided are sent through hkdf to ensure the shared secret used in the noise protocol is the
39+
# correct byte length.
40+
#
41+
# Only the first key is used for outbound handshakes but all keys provided will be tried in the order specified, on
42+
# incoming handshakes. This is to allow for psk rotation.
43+
#
44+
# To rotate a primary key:
45+
# 1. Put the new key in the 2nd slot on every node in the mesh and reload.
46+
# 2. Move the key from the 2nd slot to the 1st slot, the old primary key is now in the 2nd slot, reload.
47+
# 3. Remove the old primary key once it is no longer in use on every node in the mesh and reload.
48+
#keys:
49+
# - shared secret string, this one is used in all outbound handshakes # This is the primary key used when sending handshakes
50+
# - this is a fallback key, received handshakes can use this
51+
# - another fallback, received handshakes can use this one too
52+
# - "\x68\x65\x6c\x6c\x6f\x20\x66\x72\x69\x65\x6e\x64\x73" # for raw bytes if you desire
53+
2254
# The static host map defines a set of hosts with fixed IP addresses on the internet (or any network).
2355
# A host can have multiple fixed IP addresses defined here, and nebula will try each when establishing a tunnel.
2456
# The syntax is:
@@ -309,7 +341,6 @@ logging:
309341
# after receiving the response for lighthouse queries
310342
#trigger_buffer: 64
311343

312-
313344
# Nebula security group configuration
314345
firewall:
315346
# Action to take when a packet is not allowed by the firewall rules.

‎handshake_ix.go

+39-20
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func ixHandshakeStage0(f *Interface, hh *HandshakeHostInfo) bool {
5050
Error("Unable to handshake with host because no certificate handshake bytes is available")
5151
}
5252

53-
ci, err := NewConnectionState(f.l, cs, crt, true, noise.HandshakeIX)
53+
ci, err := NewConnectionState(f.l, cs, crt, true, noise.HandshakeIX, cs.psk.primary)
5454
if err != nil {
5555
f.l.WithError(err).WithField("vpnAddrs", hh.hostinfo.vpnAddrs).
5656
WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).
@@ -104,34 +104,53 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
104104
Error("Unable to handshake with host because no certificate is available")
105105
}
106106

107-
ci, err := NewConnectionState(f.l, cs, crt, false, noise.HandshakeIX)
108-
if err != nil {
109-
f.l.WithError(err).WithField("udpAddr", addr).
110-
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
111-
Error("Failed to create connection state")
112-
return
113-
}
107+
var (
108+
err error
109+
ci *ConnectionState
110+
msg []byte
111+
)
114112

115-
// Mark packet 1 as seen so it doesn't show up as missed
116-
ci.window.Update(f.l, 1)
113+
hs := &NebulaHandshake{}
117114

118-
msg, _, _, err := ci.H.ReadMessage(nil, packet[header.Len:])
119-
if err != nil {
120-
f.l.WithError(err).WithField("udpAddr", addr).
121-
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
122-
Error("Failed to call noise.ReadMessage")
123-
return
115+
for _, psk := range cs.psk.keys {
116+
ci, err = NewConnectionState(f.l, cs, crt, false, noise.HandshakeIX, psk)
117+
if err != nil {
118+
//TODO: should be bother logging this, if we have multiple psks and the error is unrelated it will be verbose.
119+
f.l.WithError(err).WithField("udpAddr", addr).
120+
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
121+
Error("Failed to create connection state")
122+
continue
123+
}
124+
125+
msg, _, _, err = ci.H.ReadMessage(nil, packet[header.Len:])
126+
if err != nil {
127+
// Calls to ReadMessage with an incorrect psk should fail, try the next one if we have one
128+
continue
129+
}
130+
131+
// Sometimes ReadMessage returns fine with a nil psk even if the handshake is using a psk, ensure our protobuf
132+
// comes out clean as well
133+
err = hs.Unmarshal(msg)
134+
if err == nil {
135+
// There was no error, we can continue with this handshake
136+
break
137+
}
138+
139+
// The unmarshal failed, try the next psk if we have one
124140
}
125141

126-
hs := &NebulaHandshake{}
127-
err = hs.Unmarshal(msg)
142+
// We finished with an error, log it and get out
128143
if err != nil || hs.Details == nil {
129-
f.l.WithError(err).WithField("udpAddr", addr).
144+
// We aren't logging the error here because we can't be sure of the failure when using psk
145+
f.l.WithField("udpAddr", addr).
130146
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
131-
Error("Failed unmarshal handshake message")
147+
Error("Was unable to decrypt the handshake")
132148
return
133149
}
134150

151+
// Mark packet 1 as seen so it doesn't show up as missed
152+
ci.window.Update(f.l, 1)
153+
135154
remoteCert, err := cert.RecombineAndValidate(cert.Version(hs.Details.CertVersion), hs.Details.Cert, ci.H.PeerStatic(), ci.Curve(), f.pki.GetCAPool())
136155
if err != nil {
137156
e := f.l.WithError(err).WithField("udpAddr", addr).

‎handshake_manager_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/slackhq/nebula/test"
1111
"github.com/slackhq/nebula/udp"
1212
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
1314
)
1415

1516
func Test_NewHandshakeManagerVpnIp(t *testing.T) {
@@ -23,11 +24,15 @@ func Test_NewHandshakeManagerVpnIp(t *testing.T) {
2324

2425
lh := newTestLighthouse()
2526

27+
psk, err := NewPsk(PskAccepting, nil)
28+
require.NoError(t, err)
29+
2630
cs := &CertState{
2731
defaultVersion: cert.Version1,
2832
privateKey: []byte{},
2933
v1Cert: &dummyCert{version: cert.Version1},
3034
v1HandshakeBytes: []byte{},
35+
psk: psk,
3136
}
3237

3338
blah := NewHandshakeManager(l, mainHM, lh, &udp.NoopConn{}, defaultHandshakeConfig)

‎pki.go

+12
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type CertState struct {
3838
pkcs11Backed bool
3939
cipher string
4040

41+
psk *Psk
42+
4143
myVpnNetworks []netip.Prefix
4244
myVpnNetworksTable *bart.Table[struct{}]
4345
myVpnAddrs []netip.Addr
@@ -181,6 +183,16 @@ func (p *PKI) reloadCerts(c *config.C, initial bool) *util.ContextualError {
181183
}
182184
}
183185

186+
psk, err := NewPskFromConfig(c)
187+
if err != nil {
188+
return util.NewContextualError("Failed to load psk from config", nil, err)
189+
}
190+
if len(psk.keys) > 0 {
191+
p.l.WithField("pskMode", psk.mode).WithField("keysLen", len(psk.keys)).
192+
Info("pre shared keys are in use")
193+
}
194+
newState.psk = psk
195+
184196
p.cs.Store(newState)
185197

186198
//TODO: newState needs a stringer that does json

‎psk.go

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

‎psk_test.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package nebula
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestNewPsk(t *testing.T) {
10+
t.Run("mode accepting", func(t *testing.T) {
11+
p, err := NewPsk(PskAccepting, nil)
12+
assert.NoError(t, err)
13+
assert.Equal(t, PskAccepting, p.mode)
14+
assert.Nil(t, p.keys[0])
15+
assert.Nil(t, p.primary)
16+
17+
p, err = NewPsk(PskAccepting, []string{"1234567"})
18+
assert.Error(t, ErrKeyTooShort)
19+
20+
p, err = NewPsk(PskAccepting, []string{"hi there friends"})
21+
assert.NoError(t, err)
22+
assert.Equal(t, PskAccepting, p.mode)
23+
assert.Nil(t, p.primary)
24+
assert.Len(t, p.keys, 2)
25+
assert.Nil(t, p.keys[1])
26+
27+
expectedCache := []byte{
28+
0xb9, 0x8c, 0xdc, 0xac, 0x77, 0xf4, 0x8c, 0xf8, 0x1d, 0xe7, 0xe7, 0xb, 0x53, 0x25, 0xd3, 0x65,
29+
0xa3, 0x9f, 0x78, 0xb2, 0xc7, 0x2d, 0xa5, 0xd8, 0x84, 0x81, 0x7b, 0xb5, 0xdb, 0xe0, 0x9a, 0xef,
30+
}
31+
assert.Equal(t, expectedCache, p.keys[0])
32+
})
33+
34+
t.Run("mode sending", func(t *testing.T) {
35+
p, err := NewPsk(PskSending, nil)
36+
assert.Error(t, ErrNotEnoughPskKeys, err)
37+
38+
p, err = NewPsk(PskSending, []string{"1234567"})
39+
assert.Error(t, ErrKeyTooShort)
40+
41+
p, err = NewPsk(PskSending, []string{"hi there friends"})
42+
assert.NoError(t, err)
43+
assert.Equal(t, PskSending, p.mode)
44+
assert.Len(t, p.keys, 2)
45+
assert.Nil(t, p.keys[1])
46+
47+
expectedCache := []byte{
48+
0xb9, 0x8c, 0xdc, 0xac, 0x77, 0xf4, 0x8c, 0xf8, 0x1d, 0xe7, 0xe7, 0xb, 0x53, 0x25, 0xd3, 0x65,
49+
0xa3, 0x9f, 0x78, 0xb2, 0xc7, 0x2d, 0xa5, 0xd8, 0x84, 0x81, 0x7b, 0xb5, 0xdb, 0xe0, 0x9a, 0xef,
50+
}
51+
assert.Equal(t, expectedCache, p.keys[0])
52+
assert.Equal(t, p.keys[0], p.primary)
53+
})
54+
55+
t.Run("mode enforced", func(t *testing.T) {
56+
p, err := NewPsk(PskEnforced, nil)
57+
assert.Error(t, ErrNotEnoughPskKeys, err)
58+
59+
p, err = NewPsk(PskEnforced, []string{"hi there friends"})
60+
assert.NoError(t, err)
61+
assert.Equal(t, PskEnforced, p.mode)
62+
assert.Len(t, p.keys, 1)
63+
64+
expectedCache := []byte{
65+
0xb9, 0x8c, 0xdc, 0xac, 0x77, 0xf4, 0x8c, 0xf8, 0x1d, 0xe7, 0xe7, 0xb, 0x53, 0x25, 0xd3, 0x65,
66+
0xa3, 0x9f, 0x78, 0xb2, 0xc7, 0x2d, 0xa5, 0xd8, 0x84, 0x81, 0x7b, 0xb5, 0xdb, 0xe0, 0x9a, 0xef,
67+
}
68+
assert.Equal(t, expectedCache, p.keys[0])
69+
assert.Equal(t, p.keys[0], p.primary)
70+
})
71+
}

0 commit comments

Comments
 (0)
Please sign in to comment.