wgkey: new package

This is a replacement for the key-related parts
of the wireguard-go wgcfg package.

This is almost a straight copy/paste from the wgcfg package.
I have slightly changed some of the exported functions and types
to avoid stutter, added and tweaked some comments,
and removed some now-unused code.

To avoid having wireguard-go depend on this new package,
wgcfg will keep its key types.

We translate into and out of those types at the last minute.
These few remaining uses will be eliminated alongside
the rest of the wgcfg package.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
bradfitz/grafana_auth_proxy
Josh Bleecher Snyder 3 years ago committed by Josh Bleecher Snyder
parent 13b554fed9
commit 56a7652dc9

@ -25,7 +25,6 @@ import (
"strings"
"time"
"github.com/tailscale/wireguard-go/wgcfg"
"golang.org/x/crypto/acme/autocert"
"tailscale.com/atomicfile"
"tailscale.com/derp"
@ -35,6 +34,7 @@ import (
"tailscale.com/net/stun"
"tailscale.com/tsweb"
"tailscale.com/types/key"
"tailscale.com/types/wgkey"
"tailscale.com/version"
)
@ -51,7 +51,7 @@ var (
)
type config struct {
PrivateKey wgcfg.PrivateKey
PrivateKey wgkey.Private
}
func loadConfig() config {
@ -77,8 +77,8 @@ func loadConfig() config {
}
}
func mustNewKey() wgcfg.PrivateKey {
key, err := wgcfg.NewPrivateKey()
func mustNewKey() wgkey.Private {
key, err := wgkey.NewPrivate()
if err != nil {
log.Fatal(err)
}

@ -73,6 +73,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/types/opt from tailscale.com/control/controlclient+
tailscale.com/types/strbuilder from tailscale.com/net/packet
tailscale.com/types/structs from tailscale.com/control/controlclient+
tailscale.com/types/wgkey from tailscale.com/control/controlclient+
LW tailscale.com/util/endian from tailscale.com/net/netns+
tailscale.com/util/lineread from tailscale.com/control/controlclient+
tailscale.com/util/systemd from tailscale.com/control/controlclient+

@ -81,6 +81,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/types/opt from tailscale.com/control/controlclient+
tailscale.com/types/strbuilder from tailscale.com/net/packet
tailscale.com/types/structs from tailscale.com/control/controlclient+
tailscale.com/types/wgkey from tailscale.com/control/controlclient+
LW tailscale.com/util/endian from tailscale.com/net/netns+
tailscale.com/util/lineread from tailscale.com/control/controlclient+
tailscale.com/util/pidowner from tailscale.com/ipn/ipnserver

@ -17,13 +17,13 @@ import (
"sync"
"time"
"github.com/tailscale/wireguard-go/wgcfg"
"golang.org/x/oauth2"
"tailscale.com/logtail/backoff"
"tailscale.com/tailcfg"
"tailscale.com/types/empty"
"tailscale.com/types/logger"
"tailscale.com/types/structs"
"tailscale.com/types/wgkey"
)
// State is the high-level state of the client. It is used only in
@ -665,7 +665,7 @@ func (c *Client) Shutdown() {
// NodePublicKey returns the node public key currently in use. This is
// used exclusively in tests.
func (c *Client) TestOnlyNodePublicKey() wgcfg.Key {
func (c *Client) TestOnlyNodePublicKey() wgkey.Key {
priv := c.direct.GetPersist()
return priv.PrivateNodeKey.Public()
}

@ -31,7 +31,6 @@ import (
"sync/atomic"
"time"
"github.com/tailscale/wireguard-go/wgcfg"
"golang.org/x/crypto/nacl/box"
"golang.org/x/oauth2"
"inet.af/netaddr"
@ -44,6 +43,7 @@ import (
"tailscale.com/types/logger"
"tailscale.com/types/opt"
"tailscale.com/types/structs"
"tailscale.com/types/wgkey"
"tailscale.com/util/systemd"
"tailscale.com/version"
"tailscale.com/wgengine/filter"
@ -61,10 +61,10 @@ type Persist struct {
// needed. This field should be considered read-only from GUI
// frontends. The real value should not be written back in
// this field, lest the frontend persist it to disk.
LegacyFrontendPrivateMachineKey wgcfg.PrivateKey `json:"PrivateMachineKey"`
LegacyFrontendPrivateMachineKey wgkey.Private `json:"PrivateMachineKey"`
PrivateNodeKey wgcfg.PrivateKey
OldPrivateNodeKey wgcfg.PrivateKey // needed to request key rotation
PrivateNodeKey wgkey.Private
OldPrivateNodeKey wgkey.Private // needed to request key rotation
Provider string
LoginName string
}
@ -85,7 +85,7 @@ func (p *Persist) Equals(p2 *Persist) bool {
}
func (p *Persist) Pretty() string {
var mk, ok, nk wgcfg.Key
var mk, ok, nk wgkey.Key
if !p.LegacyFrontendPrivateMachineKey.IsZero() {
mk = p.LegacyFrontendPrivateMachineKey.Public()
}
@ -95,7 +95,7 @@ func (p *Persist) Pretty() string {
if !p.PrivateNodeKey.IsZero() {
nk = p.PrivateNodeKey.Public()
}
ss := func(k wgcfg.Key) string {
ss := func(k wgkey.Key) string {
if k.IsZero() {
return ""
}
@ -115,14 +115,14 @@ type Direct struct {
keepAlive bool
logf logger.Logf
discoPubKey tailcfg.DiscoKey
machinePrivKey wgcfg.PrivateKey
machinePrivKey wgkey.Private
debugFlags []string
mu sync.Mutex // mutex guards the following fields
serverKey wgcfg.Key
serverKey wgkey.Key
persist Persist
authKey string
tryingNewKey wgcfg.PrivateKey
tryingNewKey wgkey.Private
expiry *time.Time
// hostinfo is mutated in-place while mu is held.
hostinfo *tailcfg.Hostinfo // always non-nil
@ -133,7 +133,7 @@ type Direct struct {
type Options struct {
Persist Persist // initial persistent data
MachinePrivateKey wgcfg.PrivateKey // the machine key to use
MachinePrivateKey wgkey.Private // the machine key to use
ServerURL string // URL of the tailcontrol server
AuthKey string // optional node auth key for auto registration
TimeNow func() time.Time // time.Now implementation used by Client
@ -340,7 +340,7 @@ func (c *Direct) doLogin(ctx context.Context, t *oauth2.Token, flags LoginFlags,
}
c.logf("doLogin(regen=%v, hasUrl=%v)", regen, url != "")
if serverKey == (wgcfg.Key{}) {
if serverKey.IsZero() {
var err error
serverKey, err = loadServerKey(ctx, c.httpc, c.serverURL)
if err != nil {
@ -352,12 +352,12 @@ func (c *Direct) doLogin(ctx context.Context, t *oauth2.Token, flags LoginFlags,
c.mu.Unlock()
}
var oldNodeKey wgcfg.Key
var oldNodeKey wgkey.Key
if url != "" {
} else if regen || persist.PrivateNodeKey.IsZero() {
c.logf("Generating a new nodekey.")
persist.OldPrivateNodeKey = persist.PrivateNodeKey
key, err := wgcfg.NewPrivateKey()
key, err := wgkey.NewPrivate()
if err != nil {
c.logf("login keygen: %v", err)
return regen, url, err
@ -793,7 +793,7 @@ func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(*NetworkM
return nil
}
func decode(res *http.Response, v interface{}, serverKey *wgcfg.Key, mkey *wgcfg.PrivateKey) error {
func decode(res *http.Response, v interface{}, serverKey *wgkey.Key, mkey *wgkey.Private) error {
defer res.Body.Close()
msg, err := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20))
if err != nil {
@ -848,7 +848,7 @@ func (c *Direct) decodeMsg(msg []byte, v interface{}) error {
}
func decodeMsg(msg []byte, v interface{}, serverKey *wgcfg.Key, mkey *wgcfg.PrivateKey) error {
func decodeMsg(msg []byte, v interface{}, serverKey *wgkey.Key, mkey *wgkey.Private) error {
decrypted, err := decryptMsg(msg, serverKey, mkey)
if err != nil {
return err
@ -862,7 +862,7 @@ func decodeMsg(msg []byte, v interface{}, serverKey *wgcfg.Key, mkey *wgcfg.Priv
return nil
}
func decryptMsg(msg []byte, serverKey *wgcfg.Key, mkey *wgcfg.PrivateKey) ([]byte, error) {
func decryptMsg(msg []byte, serverKey *wgkey.Key, mkey *wgkey.Private) ([]byte, error) {
var nonce [24]byte
if len(msg) < len(nonce)+1 {
return nil, fmt.Errorf("response missing nonce, len=%d", len(msg))
@ -878,7 +878,7 @@ func decryptMsg(msg []byte, serverKey *wgcfg.Key, mkey *wgcfg.PrivateKey) ([]byt
return decrypted, nil
}
func encode(v interface{}, serverKey *wgcfg.Key, mkey *wgcfg.PrivateKey) ([]byte, error) {
func encode(v interface{}, serverKey *wgkey.Key, mkey *wgkey.Private) ([]byte, error) {
b, err := json.Marshal(v)
if err != nil {
return nil, err
@ -897,27 +897,27 @@ func encode(v interface{}, serverKey *wgcfg.Key, mkey *wgcfg.PrivateKey) ([]byte
return msg, nil
}
func loadServerKey(ctx context.Context, httpc *http.Client, serverURL string) (wgcfg.Key, error) {
func loadServerKey(ctx context.Context, httpc *http.Client, serverURL string) (wgkey.Key, error) {
req, err := http.NewRequest("GET", serverURL+"/key", nil)
if err != nil {
return wgcfg.Key{}, fmt.Errorf("create control key request: %v", err)
return wgkey.Key{}, fmt.Errorf("create control key request: %v", err)
}
req = req.WithContext(ctx)
res, err := httpc.Do(req)
if err != nil {
return wgcfg.Key{}, fmt.Errorf("fetch control key: %v", err)
return wgkey.Key{}, fmt.Errorf("fetch control key: %v", err)
}
defer res.Body.Close()
b, err := ioutil.ReadAll(io.LimitReader(res.Body, 1<<16))
if err != nil {
return wgcfg.Key{}, fmt.Errorf("fetch control key response: %v", err)
return wgkey.Key{}, fmt.Errorf("fetch control key response: %v", err)
}
if res.StatusCode != 200 {
return wgcfg.Key{}, fmt.Errorf("fetch control key: %d: %s", res.StatusCode, string(b))
return wgkey.Key{}, fmt.Errorf("fetch control key: %d: %s", res.StatusCode, string(b))
}
key, err := wgcfg.ParseHexKey(string(b))
key, err := wgkey.ParseHex(string(b))
if err != nil {
return wgcfg.Key{}, fmt.Errorf("fetch control key: %v", err)
return wgkey.Key{}, fmt.Errorf("fetch control key: %v", err)
}
return key, nil
}

@ -17,6 +17,7 @@ import (
"inet.af/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/types/wgkey"
"tailscale.com/wgengine/filter"
)
@ -24,7 +25,7 @@ type NetworkMap struct {
// Core networking
NodeKey tailcfg.NodeKey
PrivateKey wgcfg.PrivateKey
PrivateKey wgkey.Private
Expiry time.Time
// Name is the DNS name assigned to this node.
Name string
@ -241,7 +242,7 @@ const EndpointDiscoSuffix = ".disco.tailscale:12345"
func (nm *NetworkMap) WGCfg(logf logger.Logf, flags WGConfigFlags) (*wgcfg.Config, error) {
cfg := &wgcfg.Config{
Name: "tailscale",
PrivateKey: nm.PrivateKey,
PrivateKey: wgcfg.PrivateKey(nm.PrivateKey),
Addresses: nm.Addresses,
ListenPort: nm.LocalPort,
Peers: make([]wgcfg.Peer, 0, len(nm.Peers)),

@ -8,7 +8,7 @@ import (
"reflect"
"testing"
"github.com/tailscale/wireguard-go/wgcfg"
"tailscale.com/types/wgkey"
)
func TestPersistEqual(t *testing.T) {
@ -18,8 +18,8 @@ func TestPersistEqual(t *testing.T) {
have, persistHandles)
}
newPrivate := func() wgcfg.PrivateKey {
k, err := wgcfg.NewPrivateKey()
newPrivate := func() wgkey.Private {
k, err := wgkey.NewPrivate()
if err != nil {
panic(err)
}

@ -68,7 +68,9 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
github.com/lxn/walk v0.0.0-20201110160827-18ea5e372cdb/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA=
github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/mattn/go-zglob v0.0.1 h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY=
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
@ -104,6 +106,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tailscale/depaware v0.0.0-20201003033024-5d95aab075be/go.mod h1:jissDaJNHiyV2tFdr3QyNEfsZrax/i2yQiSO+CljThI=
github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027 h1:lK99QQdH3yBWY6aGilF+IRlQIdmhzLrsEmF6JgN+Ryw=
github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
github.com/tailscale/wireguard-go v0.0.0-20201220011020-db78fad0bebf h1:HuBwLWbDNIh/G72KSImSEx+dnd7FPGFI1e60LMJtLjU=
@ -124,6 +127,7 @@ go4.org/intern v0.0.0-20201223054237-ef8cbcb8edd7 h1:yeDrXaQ3VRXbTN7lHj70DxW4LdP
go4.org/intern v0.0.0-20201223054237-ef8cbcb8edd7/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc=
go4.org/intern v0.0.0-20201223061701-969c7e87e7cb h1:yuqO0E4bHRsTPUocDpRKXfLE40lwWplVxENQ2WOV7Gc=
go4.org/intern v0.0.0-20201223061701-969c7e87e7cb/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc=
go4.org/mem v0.0.0-20200706164138-185c595c3ecc/go.mod h1:NEYvpHWemiG/E5UWfaN5QAIGZeT1sa0Z2UNk6oeMb/k=
go4.org/mem v0.0.0-20201119185036-c04c5a6ff174 h1:vSug/WNOi2+4jrKdivxayTN/zd8EA1UrStjpWvvo1jk=
go4.org/mem v0.0.0-20201119185036-c04c5a6ff174/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e h1:ExUmGi0ZsQmiVo9giDQqXkr7vreeXPMkOGIusfsfbzI=
@ -131,13 +135,17 @@ go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 h1:1tk03FUNpulq2cuWpXZWj649rwJpk0d20rxWiopKRmc=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 h1:xYJJ3S178yv++9zXV/hnr29plCAGO9vAFG9dorqaFQc=
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -153,6 +161,9 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@ -165,6 +176,7 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -173,10 +185,15 @@ golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -192,6 +209,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20201207232118-ee85cb95a76b h1:a0ErnNnPKmhDyIXQvdZr+Lq8dc8xpMeqkF8y5PgQU4Q=
golang.org/x/term v0.0.0-20201207232118-ee85cb95a76b/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -199,8 +217,11 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqG
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201001230009-b5b87423c93b/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag=
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -208,7 +229,11 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.20200321-0.20200715051853-507f148e1c42/go.mod h1:GJvYs5O24/ASlwPiRklVnjMx2xQzrOic0DuU6GvYJL4=
golang.zx2c4.com/wireguard v0.0.20200321-0.20201111175144-60b3766b89b9 h1:qowcZ56hhpeoESmWzI4Exhx4Y78TpCyXUJur4/c0CoE=
golang.zx2c4.com/wireguard v0.0.20200321-0.20201111175144-60b3766b89b9/go.mod h1:LMeNfjlcPZTrBC1juwgbQyA4Zy2XVcsrdO/fIJxwyuA=
golang.zx2c4.com/wireguard/windows v0.1.2-0.20201004085714-dd60d0447f81/go.mod h1:GaK5zcgr5XE98WaRzIDilumDBp5/yP8j2kG/LCDnvAM=
golang.zx2c4.com/wireguard/windows v0.1.2-0.20201113162609-9b85be97fdf8 h1:nlXPqGA98n+qcq1pwZ28KjM5EsFQvamKS00A+VUeVjs=
golang.zx2c4.com/wireguard/windows v0.1.2-0.20201113162609-9b85be97fdf8/go.mod h1:psva4yDnAHLuh7lUzOK7J7bLYxNFfo0iKWz+mi9gzkA=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -219,8 +244,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.0 h1:AWNL1W1i7f0wNZ8VwOKNJ0sliKvOF/adn0EHenfUh+c=
honnef.co/go/tools v0.1.0/go.mod h1:XtegFAyX/PfluP4921rXU5IkjkqBCDnUq4W8VCIoKvM=
inet.af/netaddr v0.0.0-20200810144936-56928fe48a98/go.mod h1:qqYzz/2whtrbWJvt+DNWQyvekNN4ePQZcg2xc2/Yjww=
inet.af/netaddr v0.0.0-20201218162718-658fec415e52/go.mod h1:qqYzz/2whtrbWJvt+DNWQyvekNN4ePQZcg2xc2/Yjww=
inet.af/netaddr v0.0.0-20201223185330-97d366981fac h1:aqMW8vft7VmOIhtQhsTWhAuZzOBGYBv+Otyvwj+VGSU=
inet.af/netaddr v0.0.0-20201223185330-97d366981fac/go.mod h1:9NdhtHLglxJliAZB6aC5ws3mfnUArdAzHG/iJq7cB/o=
@ -232,3 +259,4 @@ inet.af/netaddr v0.0.0-20201228234250-33d0a924ebbf h1:0eHZ8v6j5wIiOVyoYPd70ueZ/R
inet.af/netaddr v0.0.0-20201228234250-33d0a924ebbf/go.mod h1:9NdhtHLglxJliAZB6aC5ws3mfnUArdAzHG/iJq7cB/o=
rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w=
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
tailscale.com v1.2.10/go.mod h1:JEJiCce3MHtPCTdX2ahLc4tcnxZ7b5etish1Yt0B6+w=

@ -29,6 +29,7 @@ import (
"tailscale.com/types/empty"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/wgkey"
"tailscale.com/util/systemd"
"tailscale.com/version"
"tailscale.com/wgengine"
@ -83,7 +84,7 @@ type LocalBackend struct {
userID string // current controlling user ID (for Windows, primarily)
prefs *Prefs
inServerMode bool
machinePrivKey wgcfg.PrivateKey
machinePrivKey wgkey.Private
state State
// hostinfo is mutated in-place while mu is held.
hostinfo *tailcfg.Hostinfo
@ -737,7 +738,7 @@ func (b *LocalBackend) initMachineKeyLocked() (err error) {
return nil
}
var legacyMachineKey wgcfg.PrivateKey
var legacyMachineKey wgkey.Private
if b.prefs.Persist != nil {
legacyMachineKey = b.prefs.Persist.LegacyFrontendPrivateMachineKey
}
@ -772,7 +773,7 @@ func (b *LocalBackend) initMachineKeyLocked() (err error) {
} else {
b.logf("generating new machine key")
var err error
b.machinePrivKey, err = wgcfg.NewPrivateKey()
b.machinePrivKey, err = wgkey.NewPrivate()
if err != nil {
return fmt.Errorf("initializing new machine key: %w", err)
}

@ -13,10 +13,10 @@ import (
"testing"
"time"
"github.com/tailscale/wireguard-go/wgcfg"
"inet.af/netaddr"
"tailscale.com/control/controlclient"
"tailscale.com/tstest"
"tailscale.com/types/wgkey"
"tailscale.com/wgengine/router"
)
@ -348,7 +348,7 @@ func TestPrefsPretty(t *testing.T) {
{
Prefs{
Persist: &controlclient.Persist{
PrivateNodeKey: wgcfg.PrivateKey{1: 1},
PrivateNodeKey: wgkey.Private{1: 1},
},
},
"linux",

@ -24,7 +24,7 @@ var ErrStateNotExist = errors.New("no state with given ID")
const (
// MachineKeyStateKey is the key under which we store the machine key,
// in its wgcfg.PrivateKey.MarshalText representation.
// in its wgkey.Private.MarshalText representation.
MachineKeyStateKey = StateKey("_machinekey")
// GlobalDaemonStateKey is the ipn.StateKey that tailscaled

@ -11,8 +11,8 @@ import (
"testing"
"time"
"github.com/tailscale/wireguard-go/wgcfg"
"inet.af/netaddr"
"tailscale.com/types/wgkey"
)
func fieldsOf(t reflect.Type) (fields []string) {
@ -194,9 +194,9 @@ func TestNodeEqual(t *testing.T) {
have, nodeHandles)
}
newPublicKey := func(t *testing.T) wgcfg.Key {
newPublicKey := func(t *testing.T) wgkey.Key {
t.Helper()
k, err := wgcfg.NewPrivateKey()
k, err := wgkey.NewPrivate()
if err != nil {
t.Fatal(err)
}

@ -7,7 +7,7 @@ package key
import (
"testing"
"github.com/tailscale/wireguard-go/wgcfg"
"tailscale.com/types/wgkey"
)
func TestTextUnmarshal(t *testing.T) {
@ -28,10 +28,10 @@ func TestTextUnmarshal(t *testing.T) {
func TestClamping(t *testing.T) {
t.Run("NewPrivate", func(t *testing.T) { testClamping(t, NewPrivate) })
// Also test the wgcfg package, as their behavior should match.
t.Run("wgcfg", func(t *testing.T) {
// Also test the wgkey package, as their behavior should match.
t.Run("wgkey", func(t *testing.T) {
testClamping(t, func() Private {
k, err := wgcfg.NewPrivateKey()
k, err := wgkey.NewPrivate()
if err != nil {
t.Fatal(err)
}

@ -0,0 +1,241 @@
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package wgkey contains types and helpers for WireGuard keys.
// It is very similar to package tailscale.com/types/key,
// which is also used for curve25519 keys.
// These keys are used for WireGuard clients;
// those keys are used in other curve25519 clients.
package wgkey
import (
"bytes"
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"strings"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
)
// Size is the number of bytes in a curve25519 key.
const Size = 32
// A Key is a curve25519 key.
// It is used by WireGuard to represent public keys.
type Key [Size]byte
// NewPreshared generates a new random Key.
func NewPreshared() (*Key, error) {
var k [Size]byte
_, err := rand.Read(k[:])
if err != nil {
return nil, err
}
return (*Key)(&k), nil
}
func Parse(b64 string) (*Key, error) { return parseBase64(base64.StdEncoding, b64) }
func ParseHex(s string) (Key, error) {
b, err := hex.DecodeString(s)
if err != nil {
return Key{}, fmt.Errorf("invalid hex key (%q): %w", s, err)
}
if len(b) != Size {
return Key{}, fmt.Errorf("invalid hex key (%q): length=%d, want %d", s, len(b), Size)
}
var key Key
copy(key[:], b)
return key, nil
}
func ParsePrivateHex(v string) (Private, error) {
k, err := ParseHex(v)
if err != nil {
return Private{}, err
}
pk := Private(k)
if pk.IsZero() {
// Do not clamp a zero key, pass the zero through
// (much like NaN propagation) so that IsZero reports
// a useful result.
return pk, nil
}
pk.clamp()
return pk, nil
}
func (k Key) Base64() string { return base64.StdEncoding.EncodeToString(k[:]) }
func (k Key) String() string { return k.ShortString() }
func (k Key) HexString() string { return hex.EncodeToString(k[:]) }
func (k Key) Equal(k2 Key) bool { return subtle.ConstantTimeCompare(k[:], k2[:]) == 1 }
func (k *Key) ShortString() string {
long := k.Base64()
return "[" + long[0:5] + "]"
}
func (k *Key) IsZero() bool {
if k == nil {
return true
}
var zeros Key
return subtle.ConstantTimeCompare(zeros[:], k[:]) == 1
}
func (k *Key) MarshalJSON() ([]byte, error) {
if k == nil {
return []byte("null"), nil
}
// TODO(josharian): use encoding/hex instead?
buf := new(bytes.Buffer)
fmt.Fprintf(buf, `"%x"`, k[:])
return buf.Bytes(), nil
}
func (k *Key) UnmarshalJSON(b []byte) error {
if k == nil {
return errors.New("wgkey.Key: UnmarshalJSON on nil pointer")
}
if len(b) < 3 || b[0] != '"' || b[len(b)-1] != '"' {
return errors.New("wgkey.Key: UnmarshalJSON not given a string")
}
b = b[1 : len(b)-1]
key, err := ParseHex(string(b))
if err != nil {
return fmt.Errorf("wgkey.Key: UnmarshalJSON: %v", err)
}
copy(k[:], key[:])
return nil
}
func (a *Key) LessThan(b *Key) bool {
for i := range a {
if a[i] < b[i] {
return true
} else if a[i] > b[i] {
return false
}
}
return false
}
// A Private is a curve25519 key.
// It is used by WireGuard to represent private keys.
type Private [Size]byte
// NewPrivate generates a new curve25519 secret key.
// It conforms to the format described on https://cr.yp.to/ecdh.html.
func NewPrivate() (Private, error) {
k, err := NewPreshared()
if err != nil {
return Private{}, err
}
k[0] &= 248
k[31] = (k[31] & 127) | 64
return (Private)(*k), nil
}
func ParsePrivate(b64 string) (*Private, error) {
k, err := parseBase64(base64.StdEncoding, b64)
return (*Private)(k), err
}
func (k *Private) String() string { return base64.StdEncoding.EncodeToString(k[:]) }
func (k *Private) HexString() string { return hex.EncodeToString(k[:]) }
func (k *Private) Equal(k2 Private) bool { return subtle.ConstantTimeCompare(k[:], k2[:]) == 1 }
func (k *Private) IsZero() bool {
pk := Key(*k)
return pk.IsZero()
}
func (k *Private) clamp() {
k[0] &= 248
k[31] = (k[31] & 127) | 64
}
// Public computes the public key matching this curve25519 secret key.
func (k *Private) Public() Key {
pk := Key(*k)
if pk.IsZero() {
panic("Tried to generate emptyPrivate.Public()")
}
var p [Size]byte
curve25519.ScalarBaseMult(&p, (*[Size]byte)(k))
return (Key)(p)
}
func (k Private) MarshalText() ([]byte, error) {
// TODO(josharian): use encoding/hex instead?
buf := new(bytes.Buffer)
fmt.Fprintf(buf, `privkey:%x`, k[:])
return buf.Bytes(), nil
}
func (k *Private) UnmarshalText(b []byte) error {
s := string(b)
if !strings.HasPrefix(s, `privkey:`) {
return errors.New("wgkey.Private: UnmarshalText not given a private-key string")
}
s = strings.TrimPrefix(s, `privkey:`)
key, err := ParseHex(s)
if err != nil {
return fmt.Errorf("wgkey.Private: UnmarshalText: %v", err)
}
copy(k[:], key[:])
return nil
}
func parseBase64(enc *base64.Encoding, s string) (*Key, error) {
k, err := enc.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("invalid key (%q): %w", s, err)
}
if len(k) != Size {
return nil, fmt.Errorf("invalid key (%q): length=%d, want %d", s, len(k), Size)
}
var key Key
copy(key[:], k)
return &key, nil
}
func ParseSymmetric(b64 string) (Symmetric, error) {
k, err := parseBase64(base64.StdEncoding, b64)
if err != nil {
return Symmetric{}, err
}
return Symmetric(*k), nil
}
func ParseSymmetricHex(s string) (Symmetric, error) {
b, err := hex.DecodeString(s)
if err != nil {
return Symmetric{}, fmt.Errorf("invalid symmetric hex key (%q): %w", s, err)
}
if len(b) != chacha20poly1305.KeySize {
return Symmetric{}, fmt.Errorf("invalid symmetric hex key length (%q): length=%d, want %d", s, len(b), chacha20poly1305.KeySize)
}
var key Symmetric
copy(key[:], b)
return key, nil
}
// Symmetric is a chacha20poly1305 key.
// It is used by WireGuard to represent pre-shared symmetric keys.
type Symmetric [chacha20poly1305.KeySize]byte
func (k Symmetric) Base64() string { return base64.StdEncoding.EncodeToString(k[:]) }
func (k Symmetric) String() string { return "sym:" + k.Base64()[:8] }
func (k Symmetric) HexString() string { return hex.EncodeToString(k[:]) }
func (k Symmetric) IsZero() bool { return k.Equal(Symmetric{}) }
func (k Symmetric) Equal(k2 Symmetric) bool {
return subtle.ConstantTimeCompare(k[:], k2[:]) == 1
}

@ -0,0 +1,111 @@
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wgkey
import (
"bytes"
"testing"
)
func TestKeyBasics(t *testing.T) {
k1, err := NewPreshared()
if err != nil {
t.Fatal(err)
}
b, err := k1.MarshalJSON()
if err != nil {
t.Fatal(err)
}
t.Run("JSON round-trip", func(t *testing.T) {
// should preserve the keys
k2 := new(Key)
if err := k2.UnmarshalJSON(b); err != nil {
t.Fatal(err)
}
if !bytes.Equal(k1[:], k2[:]) {
t.Fatalf("k1 %v != k2 %v", k1[:], k2[:])
}
if b1, b2 := k1.String(), k2.String(); b1 != b2 {
t.Fatalf("base64-encoded keys do not match: %s, %s", b1, b2)
}
})
t.Run("JSON incompatible with PrivateKey", func(t *testing.T) {
k2 := new(Private)
if err := k2.UnmarshalText(b); err == nil {
t.Fatalf("successfully decoded key as private key")
}
})
t.Run("second key", func(t *testing.T) {
// A second call to NewPreshared should make a new key.
k3, err := NewPreshared()
if err != nil {
t.Fatal(err)
}
if bytes.Equal(k1[:], k3[:]) {
t.Fatalf("k1 %v == k3 %v", k1[:], k3[:])
}
// Check for obvious comparables to make sure we are not generating bad strings somewhere.
if b1, b2 := k1.String(), k3.String(); b1 == b2 {
t.Fatalf("base64-encoded keys match: %s, %s", b1, b2)
}
})
}
func TestPrivateKeyBasics(t *testing.T) {
pri, err := NewPrivate()
if err != nil {
t.Fatal(err)
}
b, err := pri.MarshalText()
if err != nil {
t.Fatal(err)
}
t.Run("JSON round-trip", func(t *testing.T) {
// should preserve the keys
pri2 := new(Private)
if err := pri2.UnmarshalText(b); err != nil {
t.Fatal(err)
}
if !bytes.Equal(pri[:], pri2[:]) {
t.Fatalf("pri %v != pri2 %v", pri[:], pri2[:])
}
if b1, b2 := pri.String(), pri2.String(); b1 != b2 {
t.Fatalf("base64-encoded keys do not match: %s, %s", b1, b2)
}
if pub1, pub2 := pri.Public().String(), pri2.Public().String(); pub1 != pub2 {
t.Fatalf("base64-encoded public keys do not match: %s, %s", pub1, pub2)
}
})
t.Run("JSON incompatible with Key", func(t *testing.T) {
k2 := new(Key)
if err := k2.UnmarshalJSON(b); err == nil {
t.Fatalf("successfully decoded private key as key")
}
})
t.Run("second key", func(t *testing.T) {
// A second call to New should make a new key.
pri3, err := NewPrivate()
if err != nil {
t.Fatal(err)
}
if bytes.Equal(pri[:], pri3[:]) {
t.Fatalf("pri %v == pri3 %v", pri[:], pri3[:])
}
// Check for obvious comparables to make sure we are not generating bad strings somewhere.
if b1, b2 := pri.String(), pri3.String(); b1 == b2 {
t.Fatalf("base64-encoded keys match: %s, %s", b1, b2)
}
if pub1, pub2 := pri.Public().String(), pri3.Public().String(); pub1 == pub2 {
t.Fatalf("base64-encoded public keys match: %s, %s", pub1, pub2)
}
})
}

@ -20,6 +20,7 @@ import (
"tailscale.com/ipn/ipnstate"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/wgkey"
)
var errNoDestinations = errors.New("magicsock: no destinations")
@ -387,7 +388,7 @@ func (a *addrSet) UpdateDst(new *net.UDPAddr) error {
}
}
publicKey := wgcfg.Key(a.publicKey)
publicKey := wgkey.Key(a.publicKey)
pk := publicKey.ShortString()
old := "<none>"
if a.curAddr >= 0 {

@ -52,6 +52,7 @@ import (
"tailscale.com/types/nettype"
"tailscale.com/types/opt"
"tailscale.com/types/structs"
"tailscale.com/types/wgkey"
"tailscale.com/version"
)
@ -1562,7 +1563,7 @@ Top:
} else if asEp != nil {
ep = asEp
} else {
key := wgcfg.Key(dm.src)
key := wgkey.Key(dm.src)
c.logf("magicsock: DERP packet from unknown key: %s", key.ShortString())
// TODO(danderson): after we fail to find a DERP endpoint, we
// seem to be falling through to passing the packet to
@ -1952,7 +1953,7 @@ func (c *Conn) SetNetworkUp(up bool) {
//
// If the private key changes, any DERP connections are torn down &
// recreated when needed.
func (c *Conn) SetPrivateKey(privateKey wgcfg.PrivateKey) error {
func (c *Conn) SetPrivateKey(privateKey wgkey.Private) error {
c.mu.Lock()
defer c.mu.Unlock()
@ -2660,7 +2661,7 @@ func simpleDur(d time.Duration) time.Duration {
}
func peerShort(k key.Public) string {
k2 := wgcfg.Key(k)
k2 := wgkey.Key(k)
return k2.ShortString()
}

@ -42,6 +42,7 @@ import (
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/nettype"
"tailscale.com/types/wgkey"
"tailscale.com/wgengine/filter"
"tailscale.com/wgengine/tstun"
)
@ -119,7 +120,7 @@ func runDERPAndStun(t *testing.T, logf logger.Logf, l nettype.PacketListener, st
// necessary to send and receive packets to test e2e wireguard
// happiness.
type magicStack struct {
privateKey wgcfg.PrivateKey
privateKey wgkey.Private
epCh chan []string // endpoint updates produced by this peer
conn *Conn // the magicsock itself
tun *tuntest.ChannelTUN // TUN device to send/receive packets
@ -133,7 +134,7 @@ type magicStack struct {
func newMagicStack(t testing.TB, logf logger.Logf, l nettype.PacketListener, derpMap *tailcfg.DERPMap) *magicStack {
t.Helper()
privateKey, err := wgcfg.NewPrivateKey()
privateKey, err := wgkey.NewPrivate()
if err != nil {
t.Fatalf("generating private key: %v", err)
}
@ -347,7 +348,7 @@ func TestNewConn(t *testing.T) {
}
defer conn.Close()
conn.SetDERPMap(stuntest.DERPMapOf(stunAddr.String()))
conn.SetPrivateKey(wgcfg.PrivateKey(key.NewPrivate()))
conn.SetPrivateKey(wgkey.Private(key.NewPrivate()))
conn.Start()
go func() {
@ -457,11 +458,11 @@ func makeConfigs(t *testing.T, addrs []netaddr.IPPort) []wgcfg.Config {
var addresses [][]netaddr.IPPrefix
for i := range addrs {
privKey, err := wgcfg.NewPrivateKey()
privKey, err := wgkey.NewPrivate()
if err != nil {
t.Fatal(err)
}
privKeys = append(privKeys, privKey)
privKeys = append(privKeys, wgcfg.PrivateKey(privKey))
addresses = append(addresses, []netaddr.IPPrefix{
parseCIDR(t, fmt.Sprintf("1.0.0.%d/32", i+1)),

@ -37,6 +37,7 @@ import (
"tailscale.com/tailcfg"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/wgkey"
"tailscale.com/version"
"tailscale.com/version/distro"
"tailscale.com/wgengine/filter"
@ -113,9 +114,9 @@ type userspaceEngine struct {
closing bool // Close was called (even if we're still closing)
statusCallback StatusCallback
linkChangeCallback func(major bool, newState *interfaces.State)
peerSequence []wgcfg.Key
peerSequence []wgkey.Key
endpoints []string
pingers map[wgcfg.Key]*pinger // legacy pingers for pre-discovery peers
pingers map[wgkey.Key]*pinger // legacy pingers for pre-discovery peers
linkState *interfaces.State
// Lock ordering: magicsock.Conn.mu, wgLock, then mu.
@ -202,7 +203,7 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
waitCh: make(chan struct{}),
tundev: tstun.WrapTUN(logf, conf.TUN),
resolver: tsdns.NewResolver(rconf),
pingers: make(map[wgcfg.Key]*pinger),
pingers: make(map[wgkey.Key]*pinger),
}
e.localAddrs.Store(map[netaddr.IP]bool{})
e.linkState, _ = getLinkState()
@ -290,7 +291,7 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
}
}
if len(ips) > 0 {
go e.pinger(peerKey, ips)
go e.pinger(wgkey.Key(peerKey), ips)
} else {
logf("[unexpected] peer %s has no single-IP routes: %v", peerKey.ShortString(), allowedIPs)
}
@ -487,7 +488,7 @@ func (p *pinger) close() {
<-p.done
}
func (p *pinger) run(ctx context.Context, peerKey wgcfg.Key, ips []netaddr.IP, srcIP netaddr.IP) {
func (p *pinger) run(ctx context.Context, peerKey wgkey.Key, ips []netaddr.IP, srcIP netaddr.IP) {
defer func() {
p.e.mu.Lock()
if p.e.pingers[peerKey] == p {
@ -556,7 +557,7 @@ func (p *pinger) run(ctx context.Context, peerKey wgcfg.Key, ips []netaddr.IP, s
//
// This is only used with legacy peers (before 0.100.0) that don't
// have advertised discovery keys.
func (e *userspaceEngine) pinger(peerKey wgcfg.Key, ips []netaddr.IP) {
func (e *userspaceEngine) pinger(peerKey wgkey.Key, ips []netaddr.IP) {
e.logf("[v1] generating initial ping traffic to %s (%v)", peerKey.ShortString(), ips)
var srcIP netaddr.IP
@ -890,7 +891,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config)
e.mu.Lock()
e.peerSequence = e.peerSequence[:0]
for _, p := range cfg.Peers {
e.peerSequence = append(e.peerSequence, p.PublicKey)
e.peerSequence = append(e.peerSequence, wgkey.Key(p.PublicKey))
peerSet[key.Public(p.PublicKey)] = struct{}{}
}
e.mu.Unlock()
@ -932,7 +933,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config)
// (which is needed by DERP) before wgdev gets it, as wgdev
// will start trying to handshake, which we want to be able to
// go over DERP.
if err := e.magicConn.SetPrivateKey(cfg.PrivateKey); err != nil {
if err := e.magicConn.SetPrivateKey(wgkey.Private(cfg.PrivateKey)); err != nil {
e.logf("wgengine: Reconfig: SetPrivateKey: %v", err)
}
e.magicConn.UpdatePeers(peerSet)
@ -1039,7 +1040,7 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
errc <- bw.Flush()
}()
pp := make(map[wgcfg.Key]*PeerStatus)
pp := make(map[wgkey.Key]*PeerStatus)
p := &PeerStatus{}
var hst1, hst2, n int64
@ -1062,7 +1063,7 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
log.Fatalf("IpcGetOperation: invalid key %#v", v)
}
p = &PeerStatus{}
pp[wgcfg.Key(pk)] = p
pp[wgkey.Key(pk)] = p
key := tailcfg.NodeKey(pk)
p.NodeKey = key

Loading…
Cancel
Save