From 15376f975b1c6f1211af42861ff1ba13b5f26972 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 28 Oct 2021 14:53:10 -0700 Subject: [PATCH] types/wgkey: delete, no longer used. Updates #3206 Signed-off-by: David Anderson --- cmd/tailscale/depaware.txt | 3 +- cmd/tailscaled/depaware.txt | 1 - types/key/node.go | 19 --- types/wgkey/key.go | 253 ------------------------------------ types/wgkey/key_test.go | 184 -------------------------- 5 files changed, 1 insertion(+), 459 deletions(-) delete mode 100644 types/wgkey/key.go delete mode 100644 types/wgkey/key_test.go diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index 6cc0bb43e..e207669a4 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -72,7 +72,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/types/persist from tailscale.com/ipn tailscale.com/types/preftype from tailscale.com/cmd/tailscale/cli+ tailscale.com/types/structs from tailscale.com/ipn+ - tailscale.com/types/wgkey from tailscale.com/types/key tailscale.com/util/dnsname from tailscale.com/cmd/tailscale/cli+ W tailscale.com/util/endian from tailscale.com/net/netns tailscale.com/util/groupmember from tailscale.com/cmd/tailscale/cli @@ -82,7 +81,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/wgengine/filter from tailscale.com/types/netmap golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box golang.org/x/crypto/chacha20 from golang.org/x/crypto/chacha20poly1305 - golang.org/x/crypto/chacha20poly1305 from crypto/tls+ + golang.org/x/crypto/chacha20poly1305 from crypto/tls golang.org/x/crypto/cryptobyte from crypto/ecdsa+ golang.org/x/crypto/cryptobyte/asn1 from crypto/ecdsa+ golang.org/x/crypto/curve25519 from crypto/tls+ diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 94a3a6bac..8e1fe5154 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -222,7 +222,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/types/persist from tailscale.com/control/controlclient+ tailscale.com/types/preftype from tailscale.com/ipn+ tailscale.com/types/structs from tailscale.com/control/controlclient+ - tailscale.com/types/wgkey from tailscale.com/types/key L tailscale.com/util/cmpver from tailscale.com/net/dns 💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+ tailscale.com/util/dnsname from tailscale.com/hostinfo+ diff --git a/types/key/node.go b/types/key/node.go index 0542c147a..c618939eb 100644 --- a/types/key/node.go +++ b/types/key/node.go @@ -15,7 +15,6 @@ import ( "golang.org/x/crypto/curve25519" "golang.org/x/crypto/nacl/box" "tailscale.com/types/structs" - "tailscale.com/types/wgkey" ) const ( @@ -148,15 +147,6 @@ func (k NodePrivate) AsPrivate() Private { return k.k } -// AsWGPrivate returns k converted to a wgkey.Private. -// -// Deprecated: exists only as a compatibility bridge while -// wgkey.Private gets removed from the codebase. Do not introduce new -// uses that aren't related to #3206. -func (k NodePrivate) AsWGPrivate() wgkey.Private { - return k.k -} - // NodePublic is the public portion of a NodePrivate. type NodePublic struct { k [32]byte @@ -335,12 +325,3 @@ func (k NodePublic) WireGuardGoString() string { func (k NodePublic) AsPublic() Public { return k.k } - -// AsWGKey returns k converted to a wgkey.Key. -// -// Deprecated: exists only as a compatibility bridge while -// wgkey.Key gets removed from the codebase. Do not introduce new -// uses that aren't related to #3206. -func (k NodePublic) AsWGKey() wgkey.Key { - return k.k -} diff --git a/types/wgkey/key.go b/types/wgkey/key.go deleted file mode 100644 index bb9529ec1..000000000 --- a/types/wgkey/key.go +++ /dev/null @@ -1,253 +0,0 @@ -// 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 ( - "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 and preshared 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) AppendTo(b []byte) []byte { return appendKey(b, "", k) } - -func (k *Key) ShortString() string { - // The goal here is to generate "[" + base64.StdEncoding.EncodeToString(k[:])[:5] + "]". - // Since we only care about the first 5 characters, it suffices to encode the first 4 bytes of k. - // Encoding those 4 bytes requires 8 bytes. - // Make dst have size 9, to fit the leading '[' plus those 8 bytes. - // We slice the unused ones away at the end. - dst := make([]byte, 9) - dst[0] = '[' - base64.StdEncoding.Encode(dst[1:], k[:4]) - dst[6] = ']' - return string(dst[:7]) -} - -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) { - buf := make([]byte, 2+len(k)*2) - buf[0] = '"' - hex.Encode(buf[1:], k[:]) - buf[len(buf)-1] = '"' - return buf, 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] - if len(b) != 2*Size { - return fmt.Errorf("wgkey.Key: UnmarshalJSON input wrong size: %d", len(b)) - } - hex.Decode(k[:], b) - 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. -// -// TODO: make this look more like types/key, key generation should not -// return an error. -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 appendKey(base []byte, prefix string, k [32]byte) []byte { - ret := append(base, make([]byte, len(prefix)+64)...) - buf := ret[len(base):] - copy(buf, prefix) - hex.Encode(buf[len(prefix):], k[:]) - return ret -} - -func (k Private) MarshalText() ([]byte, error) { return appendKey(nil, "privkey:", k), nil } -func (k Private) AppendTo(b []byte) []byte { return appendKey(b, "privkey:", k) } - -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 -} diff --git a/types/wgkey/key_test.go b/types/wgkey/key_test.go deleted file mode 100644 index 0859471eb..000000000 --- a/types/wgkey/key_test.go +++ /dev/null @@ -1,184 +0,0 @@ -// 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" - "encoding/json" - "testing" - - "tailscale.com/tstest" -) - -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 (pointer)", 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) - } - }) - - t.Run("JSON round-trip (value)", func(t *testing.T) { - type T struct { - K Key - } - v := T{K: *k1} - b, err := json.Marshal(v) - if err != nil { - t.Fatal(err) - } - var u T - if err := json.Unmarshal(b, &u); err != nil { - t.Fatal(err) - } - if !bytes.Equal(v.K[:], u.K[:]) { - t.Fatalf("v.K %v != u.K %v", v.K[:], u.K[:]) - } - if b1, b2 := v.K.String(), u.K.String(); b1 != b2 { - t.Fatalf("base64-encoded keys do not 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) - } - }) -} - -func TestMarshalJSONAllocs(t *testing.T) { - var k Key - err := tstest.MinAllocsPerRun(t, 1, func() { - k.MarshalJSON() - }) - if err != nil { - t.Fatal(err) - } -} - -var sink []byte - -func BenchmarkMarshalJSON(b *testing.B) { - b.ReportAllocs() - var k Key - for i := 0; i < b.N; i++ { - var err error - sink, err = k.MarshalJSON() - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkUnmarshalJSON(b *testing.B) { - b.ReportAllocs() - var k Key - buf, err := k.MarshalJSON() - if err != nil { - b.Fatal(err) - } - for i := 0; i < b.N; i++ { - err := k.UnmarshalJSON(buf) - if err != nil { - b.Fatal(err) - } - } -} - -var sinkString string - -func BenchmarkShortString(b *testing.B) { - b.ReportAllocs() - var k Key - for i := 0; i < b.N; i++ { - sinkString = k.ShortString() - } -}