node.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package key
  4. import (
  5. "bufio"
  6. "bytes"
  7. "crypto/subtle"
  8. "encoding/hex"
  9. "errors"
  10. "fmt"
  11. "go4.org/mem"
  12. "golang.org/x/crypto/curve25519"
  13. "golang.org/x/crypto/nacl/box"
  14. "tailscale.com/types/structs"
  15. )
  16. const (
  17. // nodePrivateHexPrefix is the prefix used to identify a
  18. // hex-encoded node private key.
  19. //
  20. // This prefix name is a little unfortunate, in that it comes from
  21. // WireGuard's own key types, and we've used it for both key types
  22. // we persist to disk (machine and node keys). But we're stuck
  23. // with it for now, barring another round of tricky migration.
  24. nodePrivateHexPrefix = "privkey:"
  25. // nodePublicHexPrefix is the prefix used to identify a
  26. // hex-encoded node public key.
  27. //
  28. // This prefix is used in the control protocol, so cannot be
  29. // changed.
  30. nodePublicHexPrefix = "nodekey:"
  31. // nodePublicBinaryPrefix is the prefix used to identify a
  32. // binary-encoded node public key.
  33. nodePublicBinaryPrefix = "np"
  34. // NodePublicRawLen is the length in bytes of a NodePublic, when
  35. // serialized with AppendTo, Raw32 or WriteRawWithoutAllocating.
  36. NodePublicRawLen = 32
  37. )
  38. // NodePrivate is a node key, used for WireGuard tunnels and
  39. // communication with DERP servers.
  40. type NodePrivate struct {
  41. _ structs.Incomparable // because == isn't constant-time
  42. k [32]byte
  43. }
  44. // NewNode creates and returns a new node private key.
  45. func NewNode() NodePrivate {
  46. var ret NodePrivate
  47. rand(ret.k[:])
  48. // WireGuard does its own clamping, so this would be unnecessary -
  49. // but we also use this key for DERP comms, which does require
  50. // clamping.
  51. clamp25519Private(ret.k[:])
  52. return ret
  53. }
  54. // NodePrivateFromRaw32 parses a 32-byte raw value as a NodePrivate.
  55. //
  56. // Deprecated: only needed to cast from legacy node private key types,
  57. // do not add more uses unrelated to #3206.
  58. func NodePrivateFromRaw32(raw mem.RO) NodePrivate {
  59. if raw.Len() != 32 {
  60. panic("input has wrong size")
  61. }
  62. var ret NodePrivate
  63. raw.Copy(ret.k[:])
  64. return ret
  65. }
  66. func ParseNodePrivateUntyped(raw mem.RO) (NodePrivate, error) {
  67. var ret NodePrivate
  68. if err := parseHex(ret.k[:], raw, mem.B(nil)); err != nil {
  69. return NodePrivate{}, err
  70. }
  71. return ret, nil
  72. }
  73. // IsZero reports whether k is the zero value.
  74. func (k NodePrivate) IsZero() bool {
  75. return k.Equal(NodePrivate{})
  76. }
  77. // Equal reports whether k and other are the same key.
  78. func (k NodePrivate) Equal(other NodePrivate) bool {
  79. return subtle.ConstantTimeCompare(k.k[:], other.k[:]) == 1
  80. }
  81. // Public returns the NodePublic for k.
  82. // Panics if NodePrivate is zero.
  83. func (k NodePrivate) Public() NodePublic {
  84. if k.IsZero() {
  85. panic("can't take the public key of a zero NodePrivate")
  86. }
  87. var ret NodePublic
  88. curve25519.ScalarBaseMult(&ret.k, &k.k)
  89. return ret
  90. }
  91. // AppendText implements encoding.TextAppender.
  92. func (k NodePrivate) AppendText(b []byte) ([]byte, error) {
  93. return appendHexKey(b, nodePrivateHexPrefix, k.k[:]), nil
  94. }
  95. // MarshalText implements encoding.TextMarshaler.
  96. func (k NodePrivate) MarshalText() ([]byte, error) {
  97. return k.AppendText(nil)
  98. }
  99. // MarshalText implements encoding.TextUnmarshaler.
  100. func (k *NodePrivate) UnmarshalText(b []byte) error {
  101. return parseHex(k.k[:], mem.B(b), mem.S(nodePrivateHexPrefix))
  102. }
  103. // SealTo wraps cleartext into a NaCl box (see
  104. // golang.org/x/crypto/nacl) to p, authenticated from k, using a
  105. // random nonce.
  106. //
  107. // The returned ciphertext is a 24-byte nonce concatenated with the
  108. // box value.
  109. func (k NodePrivate) SealTo(p NodePublic, cleartext []byte) (ciphertext []byte) {
  110. if k.IsZero() || p.IsZero() {
  111. panic("can't seal with zero keys")
  112. }
  113. var nonce [24]byte
  114. rand(nonce[:])
  115. return box.Seal(nonce[:], cleartext, &nonce, &p.k, &k.k)
  116. }
  117. // OpenFrom opens the NaCl box ciphertext, which must be a value
  118. // created by SealTo, and returns the inner cleartext if ciphertext is
  119. // a valid box from p to k.
  120. func (k NodePrivate) OpenFrom(p NodePublic, ciphertext []byte) (cleartext []byte, ok bool) {
  121. if k.IsZero() || p.IsZero() {
  122. panic("can't open with zero keys")
  123. }
  124. if len(ciphertext) < 24 {
  125. return nil, false
  126. }
  127. nonce := (*[24]byte)(ciphertext)
  128. return box.Open(nil, ciphertext[len(nonce):], nonce, &p.k, &k.k)
  129. }
  130. func (k NodePrivate) UntypedHexString() string {
  131. return hex.EncodeToString(k.k[:])
  132. }
  133. // NodePublic is the public portion of a NodePrivate.
  134. type NodePublic struct {
  135. k [32]byte
  136. }
  137. // Shard returns a uint8 number from a public key with
  138. // mostly-uniform distribution, suitable for sharding.
  139. func (p NodePublic) Shard() uint8 {
  140. // A 25519 public key isn't uniformly random, as it ultimately
  141. // corresponds to a point on the curve.
  142. // But we don't need perfectly uniformly-random, we need
  143. // good-enough-for-sharding random, so we haphazardly
  144. // combine raw values of the key to give us something sufficient.
  145. s := uint8(p.k[31]) + uint8(p.k[30]) + uint8(p.k[20])
  146. return s ^ uint8(p.k[2]+p.k[12])
  147. }
  148. // Compare returns -1, 0, or 1, depending on whether p orders before p2,
  149. // using bytes.Compare on the bytes of the public key.
  150. func (p NodePublic) Compare(p2 NodePublic) int {
  151. return bytes.Compare(p.k[:], p2.k[:])
  152. }
  153. // ParseNodePublicUntyped parses an untyped 64-character hex value
  154. // as a NodePublic.
  155. //
  156. // Deprecated: this function is risky to use, because it cannot verify
  157. // that the hex string was intended to be a NodePublic. This can
  158. // lead to accidentally decoding one type of key as another. For new
  159. // uses that don't require backwards compatibility with the untyped
  160. // string format, please use MarshalText/UnmarshalText.
  161. func ParseNodePublicUntyped(raw mem.RO) (NodePublic, error) {
  162. var ret NodePublic
  163. if err := parseHex(ret.k[:], raw, mem.B(nil)); err != nil {
  164. return NodePublic{}, err
  165. }
  166. return ret, nil
  167. }
  168. // NodePublicFromRaw32 parses a 32-byte raw value as a NodePublic.
  169. //
  170. // This should be used only when deserializing a NodePublic from a
  171. // binary protocol.
  172. func NodePublicFromRaw32(raw mem.RO) NodePublic {
  173. if raw.Len() != 32 {
  174. panic("input has wrong size")
  175. }
  176. var ret NodePublic
  177. raw.Copy(ret.k[:])
  178. return ret
  179. }
  180. // badOldPrefix is a nodekey/discokey prefix that, when base64'd, serializes
  181. // with a "bad01" ("bad ol'", ~"bad old") prefix. It's used for expired node
  182. // keys so when we debug a customer issue, the "bad01" can jump out to us. See:
  183. //
  184. // https://github.com/tailscale/tailscale/issues/6932
  185. var badOldPrefix = []byte{109, 167, 116, 213, 215, 116}
  186. // NodePublicWithBadOldPrefix returns a copy of k with its leading public key
  187. // bytes mutated such that it base64's to a ShortString of [bad01] ("bad ol'"
  188. // [expired node key]).
  189. func NodePublicWithBadOldPrefix(k NodePublic) NodePublic {
  190. var buf [32]byte
  191. k.AppendTo(buf[:0])
  192. copy(buf[:], badOldPrefix)
  193. return NodePublicFromRaw32(mem.B(buf[:]))
  194. }
  195. // IsZero reports whether k is the zero value.
  196. func (k NodePublic) IsZero() bool {
  197. return k == NodePublic{}
  198. }
  199. // ShortString returns the Tailscale conventional debug representation
  200. // of a public key: the first five base64 digits of the key, in square
  201. // brackets.
  202. func (k NodePublic) ShortString() string {
  203. return debug32(k.k)
  204. }
  205. // AppendTo appends k, serialized as a 32-byte binary value, to
  206. // buf. Returns the new slice.
  207. func (k NodePublic) AppendTo(buf []byte) []byte {
  208. return append(buf, k.k[:]...)
  209. }
  210. // ReadRawWithoutAllocating initializes k with bytes read from br.
  211. // The reading is done ~4x slower than io.ReadFull, but in exchange is
  212. // allocation-free.
  213. func (k *NodePublic) ReadRawWithoutAllocating(br *bufio.Reader) error {
  214. var z NodePublic
  215. if *k != z {
  216. return errors.New("refusing to read into non-zero NodePublic")
  217. }
  218. // This is ~4x slower than io.ReadFull, but using io.ReadFull
  219. // causes one extra alloc, which is significant for the DERP
  220. // server that consumes this method. So, process stuff slower but
  221. // without allocation.
  222. //
  223. // Dear future: if io.ReadFull stops causing stuff to escape, you
  224. // should switch back to that.
  225. for i := range k.k {
  226. b, err := br.ReadByte()
  227. if err != nil {
  228. return err
  229. }
  230. k.k[i] = b
  231. }
  232. return nil
  233. }
  234. // WriteRawWithoutAllocating writes out k as 32 bytes to bw.
  235. // The writing is done ~3x slower than bw.Write, but in exchange is
  236. // allocation-free.
  237. func (k NodePublic) WriteRawWithoutAllocating(bw *bufio.Writer) error {
  238. // Equivalent to bw.Write(k.k[:]), but without causing an
  239. // escape-related alloc.
  240. //
  241. // Dear future: if bw.Write(k.k[:]) stops causing stuff to escape,
  242. // you should switch back to that.
  243. for _, b := range k.k {
  244. err := bw.WriteByte(b)
  245. if err != nil {
  246. return err
  247. }
  248. }
  249. return nil
  250. }
  251. // Raw32 returns k encoded as 32 raw bytes.
  252. //
  253. // Deprecated: only needed for a single legacy use in the control
  254. // server and a few places in the wireguard-go API; don't add
  255. // more uses.
  256. func (k NodePublic) Raw32() [32]byte {
  257. return k.k
  258. }
  259. // Less reports whether k orders before other, using an undocumented
  260. // deterministic ordering.
  261. func (k NodePublic) Less(other NodePublic) bool {
  262. return bytes.Compare(k.k[:], other.k[:]) < 0
  263. }
  264. // UntypedHexString returns k, encoded as an untyped 64-character hex
  265. // string.
  266. //
  267. // Deprecated: this function is risky to use, because it produces
  268. // serialized values that do not identify themselves as a
  269. // NodePublic, allowing other code to potentially parse it back in
  270. // as the wrong key type. For new uses that don't require backwards
  271. // compatibility with the untyped string format, please use
  272. // MarshalText/UnmarshalText.
  273. func (k NodePublic) UntypedHexString() string {
  274. return hex.EncodeToString(k.k[:])
  275. }
  276. // String returns k as a hex-encoded string with a type prefix.
  277. func (k NodePublic) String() string {
  278. bs, err := k.MarshalText()
  279. if err != nil {
  280. panic(err)
  281. }
  282. return string(bs)
  283. }
  284. // AppendText implements encoding.TextAppender. It appends a typed prefix
  285. // followed by hex encoded represtation of k to b.
  286. func (k NodePublic) AppendText(b []byte) ([]byte, error) {
  287. return appendHexKey(b, nodePublicHexPrefix, k.k[:]), nil
  288. }
  289. // MarshalText implements encoding.TextMarshaler. It returns a typed prefix
  290. // followed by a hex encoded representation of k.
  291. func (k NodePublic) MarshalText() ([]byte, error) {
  292. return k.AppendText(nil)
  293. }
  294. // UnmarshalText implements encoding.TextUnmarshaler. It expects a typed prefix
  295. // followed by a hex encoded representation of k.
  296. func (k *NodePublic) UnmarshalText(b []byte) error {
  297. return parseHex(k.k[:], mem.B(b), mem.S(nodePublicHexPrefix))
  298. }
  299. // MarshalBinary implements encoding.BinaryMarshaler.
  300. func (k NodePublic) MarshalBinary() (data []byte, err error) {
  301. b := make([]byte, len(nodePublicBinaryPrefix)+NodePublicRawLen)
  302. copy(b[:len(nodePublicBinaryPrefix)], nodePublicBinaryPrefix)
  303. copy(b[len(nodePublicBinaryPrefix):], k.k[:])
  304. return b, nil
  305. }
  306. // UnmarshalBinary implements encoding.BinaryUnmarshaler.
  307. func (k *NodePublic) UnmarshalBinary(in []byte) error {
  308. data := mem.B(in)
  309. if !mem.HasPrefix(data, mem.S(nodePublicBinaryPrefix)) {
  310. return fmt.Errorf("missing/incorrect type prefix %s", nodePublicBinaryPrefix)
  311. }
  312. if want, got := len(nodePublicBinaryPrefix)+NodePublicRawLen, data.Len(); want != got {
  313. return fmt.Errorf("incorrect len for NodePublic (%d != %d)", got, want)
  314. }
  315. data.SliceFrom(len(nodePublicBinaryPrefix)).Copy(k.k[:])
  316. return nil
  317. }
  318. // WireGuardGoString prints k in the same format used by wireguard-go.
  319. func (k NodePublic) WireGuardGoString() string {
  320. // This implementation deliberately matches the overly complicated
  321. // implementation in wireguard-go.
  322. b64 := func(input byte) byte {
  323. return input + 'A' + byte(((25-int(input))>>8)&6) - byte(((51-int(input))>>8)&75) - byte(((61-int(input))>>8)&15) + byte(((62-int(input))>>8)&3)
  324. }
  325. b := []byte("peer(____…____)")
  326. const first = len("peer(")
  327. const second = len("peer(____…")
  328. b[first+0] = b64((k.k[0] >> 2) & 63)
  329. b[first+1] = b64(((k.k[0] << 4) | (k.k[1] >> 4)) & 63)
  330. b[first+2] = b64(((k.k[1] << 2) | (k.k[2] >> 6)) & 63)
  331. b[first+3] = b64(k.k[2] & 63)
  332. b[second+0] = b64(k.k[29] & 63)
  333. b[second+1] = b64((k.k[30] >> 2) & 63)
  334. b[second+2] = b64(((k.k[30] << 4) | (k.k[31] >> 4)) & 63)
  335. b[second+3] = b64((k.k[31] << 2) & 63)
  336. return string(b)
  337. }