node.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. // MarshalText implements encoding.TextMarshaler.
  92. func (k NodePrivate) MarshalText() ([]byte, error) {
  93. return toHex(k.k[:], nodePrivateHexPrefix), nil
  94. }
  95. // MarshalText implements encoding.TextUnmarshaler.
  96. func (k *NodePrivate) UnmarshalText(b []byte) error {
  97. return parseHex(k.k[:], mem.B(b), mem.S(nodePrivateHexPrefix))
  98. }
  99. // SealTo wraps cleartext into a NaCl box (see
  100. // golang.org/x/crypto/nacl) to p, authenticated from k, using a
  101. // random nonce.
  102. //
  103. // The returned ciphertext is a 24-byte nonce concatenated with the
  104. // box value.
  105. func (k NodePrivate) SealTo(p NodePublic, cleartext []byte) (ciphertext []byte) {
  106. if k.IsZero() || p.IsZero() {
  107. panic("can't seal with zero keys")
  108. }
  109. var nonce [24]byte
  110. rand(nonce[:])
  111. return box.Seal(nonce[:], cleartext, &nonce, &p.k, &k.k)
  112. }
  113. // OpenFrom opens the NaCl box ciphertext, which must be a value
  114. // created by SealTo, and returns the inner cleartext if ciphertext is
  115. // a valid box from p to k.
  116. func (k NodePrivate) OpenFrom(p NodePublic, ciphertext []byte) (cleartext []byte, ok bool) {
  117. if k.IsZero() || p.IsZero() {
  118. panic("can't open with zero keys")
  119. }
  120. if len(ciphertext) < 24 {
  121. return nil, false
  122. }
  123. nonce := (*[24]byte)(ciphertext)
  124. return box.Open(nil, ciphertext[len(nonce):], nonce, &p.k, &k.k)
  125. }
  126. func (k NodePrivate) UntypedHexString() string {
  127. return hex.EncodeToString(k.k[:])
  128. }
  129. // NodePublic is the public portion of a NodePrivate.
  130. type NodePublic struct {
  131. k [32]byte
  132. }
  133. // Shard returns a uint8 number from a public key with
  134. // mostly-uniform distribution, suitable for sharding.
  135. func (p NodePublic) Shard() uint8 {
  136. // A 25519 public key isn't uniformly random, as it ultimately
  137. // corresponds to a point on the curve.
  138. // But we don't need perfectly uniformly-random, we need
  139. // good-enough-for-sharding random, so we haphazardly
  140. // combine raw values of the key to give us something sufficient.
  141. s := uint8(p.k[31]) + uint8(p.k[30]) + uint8(p.k[20])
  142. return s ^ uint8(p.k[2]+p.k[12])
  143. }
  144. // ParseNodePublicUntyped parses an untyped 64-character hex value
  145. // as a NodePublic.
  146. //
  147. // Deprecated: this function is risky to use, because it cannot verify
  148. // that the hex string was intended to be a NodePublic. This can
  149. // lead to accidentally decoding one type of key as another. For new
  150. // uses that don't require backwards compatibility with the untyped
  151. // string format, please use MarshalText/UnmarshalText.
  152. func ParseNodePublicUntyped(raw mem.RO) (NodePublic, error) {
  153. var ret NodePublic
  154. if err := parseHex(ret.k[:], raw, mem.B(nil)); err != nil {
  155. return NodePublic{}, err
  156. }
  157. return ret, nil
  158. }
  159. // NodePublicFromRaw32 parses a 32-byte raw value as a NodePublic.
  160. //
  161. // This should be used only when deserializing a NodePublic from a
  162. // binary protocol.
  163. func NodePublicFromRaw32(raw mem.RO) NodePublic {
  164. if raw.Len() != 32 {
  165. panic("input has wrong size")
  166. }
  167. var ret NodePublic
  168. raw.Copy(ret.k[:])
  169. return ret
  170. }
  171. // badOldPrefix is a nodekey/discokey prefix that, when base64'd, serializes
  172. // with a "bad01" ("bad ol'", ~"bad old") prefix. It's used for expired node
  173. // keys so when we debug a customer issue, the "bad01" can jump out to us. See:
  174. //
  175. // https://github.com/tailscale/tailscale/issues/6932
  176. var badOldPrefix = []byte{109, 167, 116, 213, 215, 116}
  177. // NodePublicWithBadOldPrefix returns a copy of k with its leading public key
  178. // bytes mutated such that it base64's to a ShortString of [bad01] ("bad ol'"
  179. // [expired node key]).
  180. func NodePublicWithBadOldPrefix(k NodePublic) NodePublic {
  181. var buf [32]byte
  182. k.AppendTo(buf[:0])
  183. copy(buf[:], badOldPrefix)
  184. return NodePublicFromRaw32(mem.B(buf[:]))
  185. }
  186. // IsZero reports whether k is the zero value.
  187. func (k NodePublic) IsZero() bool {
  188. return k == NodePublic{}
  189. }
  190. // ShortString returns the Tailscale conventional debug representation
  191. // of a public key: the first five base64 digits of the key, in square
  192. // brackets.
  193. func (k NodePublic) ShortString() string {
  194. return debug32(k.k)
  195. }
  196. // AppendTo appends k, serialized as a 32-byte binary value, to
  197. // buf. Returns the new slice.
  198. func (k NodePublic) AppendTo(buf []byte) []byte {
  199. return append(buf, k.k[:]...)
  200. }
  201. // ReadRawWithoutAllocating initializes k with bytes read from br.
  202. // The reading is done ~4x slower than io.ReadFull, but in exchange is
  203. // allocation-free.
  204. func (k *NodePublic) ReadRawWithoutAllocating(br *bufio.Reader) error {
  205. var z NodePublic
  206. if *k != z {
  207. return errors.New("refusing to read into non-zero NodePublic")
  208. }
  209. // This is ~4x slower than io.ReadFull, but using io.ReadFull
  210. // causes one extra alloc, which is significant for the DERP
  211. // server that consumes this method. So, process stuff slower but
  212. // without allocation.
  213. //
  214. // Dear future: if io.ReadFull stops causing stuff to escape, you
  215. // should switch back to that.
  216. for i := range k.k {
  217. b, err := br.ReadByte()
  218. if err != nil {
  219. return err
  220. }
  221. k.k[i] = b
  222. }
  223. return nil
  224. }
  225. // WriteRawWithoutAllocating writes out k as 32 bytes to bw.
  226. // The writing is done ~3x slower than bw.Write, but in exchange is
  227. // allocation-free.
  228. func (k NodePublic) WriteRawWithoutAllocating(bw *bufio.Writer) error {
  229. // Equivalent to bw.Write(k.k[:]), but without causing an
  230. // escape-related alloc.
  231. //
  232. // Dear future: if bw.Write(k.k[:]) stops causing stuff to escape,
  233. // you should switch back to that.
  234. for _, b := range k.k {
  235. err := bw.WriteByte(b)
  236. if err != nil {
  237. return err
  238. }
  239. }
  240. return nil
  241. }
  242. // Raw32 returns k encoded as 32 raw bytes.
  243. //
  244. // Deprecated: only needed for a single legacy use in the control
  245. // server, don't add more uses.
  246. func (k NodePublic) Raw32() [32]byte {
  247. var ret [32]byte
  248. copy(ret[:], k.k[:])
  249. return ret
  250. }
  251. // Less reports whether k orders before other, using an undocumented
  252. // deterministic ordering.
  253. func (k NodePublic) Less(other NodePublic) bool {
  254. return bytes.Compare(k.k[:], other.k[:]) < 0
  255. }
  256. // UntypedHexString returns k, encoded as an untyped 64-character hex
  257. // string.
  258. //
  259. // Deprecated: this function is risky to use, because it produces
  260. // serialized values that do not identify themselves as a
  261. // NodePublic, allowing other code to potentially parse it back in
  262. // as the wrong key type. For new uses that don't require backwards
  263. // compatibility with the untyped string format, please use
  264. // MarshalText/UnmarshalText.
  265. func (k NodePublic) UntypedHexString() string {
  266. return hex.EncodeToString(k.k[:])
  267. }
  268. // String returns the output of MarshalText as a string.
  269. func (k NodePublic) String() string {
  270. bs, err := k.MarshalText()
  271. if err != nil {
  272. panic(err)
  273. }
  274. return string(bs)
  275. }
  276. // MarshalText implements encoding.TextMarshaler.
  277. func (k NodePublic) MarshalText() ([]byte, error) {
  278. return toHex(k.k[:], nodePublicHexPrefix), nil
  279. }
  280. // MarshalText implements encoding.TextUnmarshaler.
  281. func (k *NodePublic) UnmarshalText(b []byte) error {
  282. return parseHex(k.k[:], mem.B(b), mem.S(nodePublicHexPrefix))
  283. }
  284. // MarshalBinary implements encoding.BinaryMarshaler.
  285. func (k NodePublic) MarshalBinary() (data []byte, err error) {
  286. b := make([]byte, len(nodePublicBinaryPrefix)+NodePublicRawLen)
  287. copy(b[:len(nodePublicBinaryPrefix)], nodePublicBinaryPrefix)
  288. copy(b[len(nodePublicBinaryPrefix):], k.k[:])
  289. return b, nil
  290. }
  291. // UnmarshalBinary implements encoding.BinaryUnmarshaler.
  292. func (k *NodePublic) UnmarshalBinary(in []byte) error {
  293. data := mem.B(in)
  294. if !mem.HasPrefix(data, mem.S(nodePublicBinaryPrefix)) {
  295. return fmt.Errorf("missing/incorrect type prefix %s", nodePublicBinaryPrefix)
  296. }
  297. if want, got := len(nodePublicBinaryPrefix)+NodePublicRawLen, data.Len(); want != got {
  298. return fmt.Errorf("incorrect len for NodePublic (%d != %d)", got, want)
  299. }
  300. data.SliceFrom(len(nodePublicBinaryPrefix)).Copy(k.k[:])
  301. return nil
  302. }
  303. // WireGuardGoString prints k in the same format used by wireguard-go.
  304. func (k NodePublic) WireGuardGoString() string {
  305. // This implementation deliberately matches the overly complicated
  306. // implementation in wireguard-go.
  307. b64 := func(input byte) byte {
  308. 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)
  309. }
  310. b := []byte("peer(____…____)")
  311. const first = len("peer(")
  312. const second = len("peer(____…")
  313. b[first+0] = b64((k.k[0] >> 2) & 63)
  314. b[first+1] = b64(((k.k[0] << 4) | (k.k[1] >> 4)) & 63)
  315. b[first+2] = b64(((k.k[1] << 2) | (k.k[2] >> 6)) & 63)
  316. b[first+3] = b64(k.k[2] & 63)
  317. b[second+0] = b64(k.k[29] & 63)
  318. b[second+1] = b64((k.k[30] >> 2) & 63)
  319. b[second+2] = b64(((k.k[30] << 4) | (k.k[31] >> 4)) & 63)
  320. b[second+3] = b64((k.k[31] << 2) & 63)
  321. return string(b)
  322. }