wgengine/magicsock: cache precomputed nacl/box shared keys
Updates #483
This commit is contained in:
parent
a975e86bb8
commit
a83ca9e734
|
@ -95,6 +95,7 @@ type Conn struct {
|
|||
discoOfNode map[tailcfg.NodeKey]tailcfg.DiscoKey
|
||||
|
||||
endpointOfDisco map[tailcfg.DiscoKey]*discoEndpoint
|
||||
sharedDiscoKey map[tailcfg.DiscoKey]*[32]byte // nacl/box precomputed key
|
||||
|
||||
// addrsByUDP is a map of every remote ip:port to a priority
|
||||
// list of endpoint addresses for a peer.
|
||||
|
@ -250,6 +251,7 @@ func newConn() *Conn {
|
|||
derpStarted: make(chan struct{}),
|
||||
peerLastDerp: make(map[key.Public]int),
|
||||
endpointOfDisco: make(map[tailcfg.DiscoKey]*discoEndpoint),
|
||||
sharedDiscoKey: make(map[tailcfg.DiscoKey]*[32]byte),
|
||||
}
|
||||
c.endpointsUpdateWaiter = sync.NewCond(&c.mu)
|
||||
return c
|
||||
|
@ -499,6 +501,11 @@ func (c *Conn) SetNetInfoCallback(fn func(*tailcfg.NetInfo)) {
|
|||
func (c *Conn) SetDiscoPrivateKey(k key.Private) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if !c.discoPrivate.IsZero() && c.discoPrivate != k {
|
||||
// TODO: support changing a key at runtime; need to
|
||||
// clear a bunch of maps at least
|
||||
panic("unsupported")
|
||||
}
|
||||
c.discoPrivate = k
|
||||
c.logf("magicsock: disco key set; public: %x", k.Public())
|
||||
}
|
||||
|
@ -1348,7 +1355,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, addr *net.UDPAddr) bool {
|
|||
var nonce [nonceLen]byte
|
||||
copy(nonce[:], msg[len(magic)+len(key.Public{}):])
|
||||
sealedBox := msg[headerLen:]
|
||||
payload, ok := box.Open(nil, sealedBox, &nonce, key.Public(sender).B32(), c.discoPrivate.B32())
|
||||
payload, ok := box.OpenAfterPrecomputation(nil, sealedBox, &nonce, c.sharedDiscoKeyLocked(sender))
|
||||
if !ok {
|
||||
c.logf("magicsock: failed to open disco message box purportedly from %s (disco key %x)", senderNode.Key.ShortString(), sender[:])
|
||||
return false
|
||||
|
@ -1358,6 +1365,16 @@ func (c *Conn) handleDiscoMessage(msg []byte, addr *net.UDPAddr) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (c *Conn) sharedDiscoKeyLocked(k tailcfg.DiscoKey) *[32]byte {
|
||||
if v, ok := c.sharedDiscoKey[k]; ok {
|
||||
return v
|
||||
}
|
||||
shared := new([32]byte)
|
||||
box.Precompute(shared, key.Public(k).B32(), c.discoPrivate.B32())
|
||||
c.sharedDiscoKey[k] = shared
|
||||
return shared
|
||||
}
|
||||
|
||||
// SetPrivateKey sets the connection's private key.
|
||||
//
|
||||
// This is only used to be able prove our identity when connecting to
|
||||
|
@ -1491,6 +1508,7 @@ func (c *Conn) SetNetworkMap(nm *controlclient.NetworkMap) {
|
|||
if _, ok := c.nodeOfDisco[dk]; !ok {
|
||||
de.cleanup()
|
||||
delete(c.endpointOfDisco, dk)
|
||||
delete(c.sharedDiscoKey, dk)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -841,12 +841,11 @@ func TestDiscoMessage(t *testing.T) {
|
|||
peer1Priv := key.NewPrivate()
|
||||
peer1Pub := peer1Priv.Public()
|
||||
|
||||
c := &Conn{
|
||||
logf: t.Logf,
|
||||
discoPrivate: key.NewPrivate(),
|
||||
nodeOfDisco: map[tailcfg.DiscoKey]*tailcfg.Node{
|
||||
tailcfg.DiscoKey(peer1Pub): &tailcfg.Node{Key: tailcfg.NodeKey{1: 1}},
|
||||
},
|
||||
c := newConn()
|
||||
c.logf = t.Logf
|
||||
c.SetDiscoPrivateKey(key.NewPrivate())
|
||||
c.nodeOfDisco = map[tailcfg.DiscoKey]*tailcfg.Node{
|
||||
tailcfg.DiscoKey(peer1Pub): &tailcfg.Node{Key: tailcfg.NodeKey{1: 1}},
|
||||
}
|
||||
|
||||
const payload = "why hello"
|
||||
|
|
Loading…
Reference in New Issue