node.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package key
  5. import (
  6. "bufio"
  7. "bytes"
  8. "crypto/subtle"
  9. "encoding/hex"
  10. "errors"
  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. // NodePublicRawLen is the length in bytes of a NodePublic, when
  32. // serialized with AppendTo, Raw32 or WriteRawWithoutAllocating.
  33. NodePublicRawLen = 32
  34. )
  35. // NodePrivate is a node key, used for WireGuard tunnels and
  36. // communication with DERP servers.
  37. type NodePrivate struct {
  38. _ structs.Incomparable // because == isn't constant-time
  39. k [32]byte
  40. }
  41. // NewNode creates and returns a new node private key.
  42. func NewNode() NodePrivate {
  43. var ret NodePrivate
  44. rand(ret.k[:])
  45. // WireGuard does its own clamping, so this would be unnecessary -
  46. // but we also use this key for DERP comms, which does require
  47. // clamping.
  48. clamp25519Private(ret.k[:])
  49. return ret
  50. }
  51. // NodePrivateFromRaw32 parses a 32-byte raw value as a NodePrivate.
  52. //
  53. // Deprecated: only needed to cast from legacy node private key types,
  54. // do not add more uses unrelated to #3206.
  55. func NodePrivateFromRaw32(raw mem.RO) NodePrivate {
  56. if raw.Len() != 32 {
  57. panic("input has wrong size")
  58. }
  59. var ret NodePrivate
  60. raw.Copy(ret.k[:])
  61. return ret
  62. }
  63. func ParseNodePrivateUntyped(raw mem.RO) (NodePrivate, error) {
  64. var ret NodePrivate
  65. if err := parseHex(ret.k[:], raw, mem.B(nil)); err != nil {
  66. return NodePrivate{}, err
  67. }
  68. return ret, nil
  69. }
  70. // IsZero reports whether k is the zero value.
  71. func (k NodePrivate) IsZero() bool {
  72. return k.Equal(NodePrivate{})
  73. }
  74. // Equal reports whether k and other are the same key.
  75. func (k NodePrivate) Equal(other NodePrivate) bool {
  76. return subtle.ConstantTimeCompare(k.k[:], other.k[:]) == 1
  77. }
  78. // Public returns the NodePublic for k.
  79. // Panics if NodePrivate is zero.
  80. func (k NodePrivate) Public() NodePublic {
  81. if k.IsZero() {
  82. panic("can't take the public key of a zero NodePrivate")
  83. }
  84. var ret NodePublic
  85. curve25519.ScalarBaseMult(&ret.k, &k.k)
  86. return ret
  87. }
  88. // MarshalText implements encoding.TextMarshaler.
  89. func (k NodePrivate) MarshalText() ([]byte, error) {
  90. return toHex(k.k[:], nodePrivateHexPrefix), nil
  91. }
  92. // MarshalText implements encoding.TextUnmarshaler.
  93. func (k *NodePrivate) UnmarshalText(b []byte) error {
  94. return parseHex(k.k[:], mem.B(b), mem.S(nodePrivateHexPrefix))
  95. }
  96. // SealTo wraps cleartext into a NaCl box (see
  97. // golang.org/x/crypto/nacl) to p, authenticated from k, using a
  98. // random nonce.
  99. //
  100. // The returned ciphertext is a 24-byte nonce concatenated with the
  101. // box value.
  102. func (k NodePrivate) SealTo(p NodePublic, cleartext []byte) (ciphertext []byte) {
  103. if k.IsZero() || p.IsZero() {
  104. panic("can't seal with zero keys")
  105. }
  106. var nonce [24]byte
  107. rand(nonce[:])
  108. return box.Seal(nonce[:], cleartext, &nonce, &p.k, &k.k)
  109. }
  110. // OpenFrom opens the NaCl box ciphertext, which must be a value
  111. // created by SealTo, and returns the inner cleartext if ciphertext is
  112. // a valid box from p to k.
  113. func (k NodePrivate) OpenFrom(p NodePublic, ciphertext []byte) (cleartext []byte, ok bool) {
  114. if k.IsZero() || p.IsZero() {
  115. panic("can't open with zero keys")
  116. }
  117. if len(ciphertext) < 24 {
  118. return nil, false
  119. }
  120. nonce := (*[24]byte)(ciphertext)
  121. return box.Open(nil, ciphertext[len(nonce):], nonce, &p.k, &k.k)
  122. }
  123. func (k NodePrivate) UntypedHexString() string {
  124. return hex.EncodeToString(k.k[:])
  125. }
  126. // NodePublic is the public portion of a NodePrivate.
  127. type NodePublic struct {
  128. k [32]byte
  129. }
  130. // ParseNodePublicUntyped parses an untyped 64-character hex value
  131. // as a NodePublic.
  132. //
  133. // Deprecated: this function is risky to use, because it cannot verify
  134. // that the hex string was intended to be a NodePublic. This can
  135. // lead to accidentally decoding one type of key as another. For new
  136. // uses that don't require backwards compatibility with the untyped
  137. // string format, please use MarshalText/UnmarshalText.
  138. func ParseNodePublicUntyped(raw mem.RO) (NodePublic, error) {
  139. var ret NodePublic
  140. if err := parseHex(ret.k[:], raw, mem.B(nil)); err != nil {
  141. return NodePublic{}, err
  142. }
  143. return ret, nil
  144. }
  145. // NodePublicFromRaw32 parses a 32-byte raw value as a NodePublic.
  146. //
  147. // This should be used only when deserializing a NodePublic from a
  148. // binary protocol.
  149. func NodePublicFromRaw32(raw mem.RO) NodePublic {
  150. if raw.Len() != 32 {
  151. panic("input has wrong size")
  152. }
  153. var ret NodePublic
  154. raw.Copy(ret.k[:])
  155. return ret
  156. }
  157. // IsZero reports whether k is the zero value.
  158. func (k NodePublic) IsZero() bool {
  159. return k == NodePublic{}
  160. }
  161. // ShortString returns the Tailscale conventional debug representation
  162. // of a public key: the first five base64 digits of the key, in square
  163. // brackets.
  164. func (k NodePublic) ShortString() string {
  165. return debug32(k.k)
  166. }
  167. // AppendTo appends k, serialized as a 32-byte binary value, to
  168. // buf. Returns the new slice.
  169. func (k NodePublic) AppendTo(buf []byte) []byte {
  170. return append(buf, k.k[:]...)
  171. }
  172. // ReadRawWithoutAllocating initializes k with bytes read from br.
  173. // The reading is done ~4x slower than io.ReadFull, but in exchange is
  174. // allocation-free.
  175. func (k *NodePublic) ReadRawWithoutAllocating(br *bufio.Reader) error {
  176. var z NodePublic
  177. if *k != z {
  178. return errors.New("refusing to read into non-zero NodePublic")
  179. }
  180. // This is ~4x slower than io.ReadFull, but using io.ReadFull
  181. // causes one extra alloc, which is significant for the DERP
  182. // server that consumes this method. So, process stuff slower but
  183. // without allocation.
  184. //
  185. // Dear future: if io.ReadFull stops causing stuff to escape, you
  186. // should switch back to that.
  187. for i := range k.k {
  188. b, err := br.ReadByte()
  189. if err != nil {
  190. return err
  191. }
  192. k.k[i] = b
  193. }
  194. return nil
  195. }
  196. // WriteRawWithoutAllocating writes out k as 32 bytes to bw.
  197. // The writing is done ~3x slower than bw.Write, but in exchange is
  198. // allocation-free.
  199. func (k NodePublic) WriteRawWithoutAllocating(bw *bufio.Writer) error {
  200. // Equivalent to bw.Write(k.k[:]), but without causing an
  201. // escape-related alloc.
  202. //
  203. // Dear future: if bw.Write(k.k[:]) stops causing stuff to escape,
  204. // you should switch back to that.
  205. for _, b := range k.k {
  206. err := bw.WriteByte(b)
  207. if err != nil {
  208. return err
  209. }
  210. }
  211. return nil
  212. }
  213. // Raw32 returns k encoded as 32 raw bytes.
  214. //
  215. // Deprecated: only needed for a single legacy use in the control
  216. // server, don't add more uses.
  217. func (k NodePublic) Raw32() [32]byte {
  218. var ret [32]byte
  219. copy(ret[:], k.k[:])
  220. return ret
  221. }
  222. // Less reports whether k orders before other, using an undocumented
  223. // deterministic ordering.
  224. func (k NodePublic) Less(other NodePublic) bool {
  225. return bytes.Compare(k.k[:], other.k[:]) < 0
  226. }
  227. // UntypedHexString returns k, encoded as an untyped 64-character hex
  228. // string.
  229. //
  230. // Deprecated: this function is risky to use, because it produces
  231. // serialized values that do not identify themselves as a
  232. // NodePublic, allowing other code to potentially parse it back in
  233. // as the wrong key type. For new uses that don't require backwards
  234. // compatibility with the untyped string format, please use
  235. // MarshalText/UnmarshalText.
  236. func (k NodePublic) UntypedHexString() string {
  237. return hex.EncodeToString(k.k[:])
  238. }
  239. // String returns the output of MarshalText as a string.
  240. func (k NodePublic) String() string {
  241. bs, err := k.MarshalText()
  242. if err != nil {
  243. panic(err)
  244. }
  245. return string(bs)
  246. }
  247. // MarshalText implements encoding.TextMarshaler.
  248. func (k NodePublic) MarshalText() ([]byte, error) {
  249. return toHex(k.k[:], nodePublicHexPrefix), nil
  250. }
  251. // MarshalText implements encoding.TextUnmarshaler.
  252. func (k *NodePublic) UnmarshalText(b []byte) error {
  253. return parseHex(k.k[:], mem.B(b), mem.S(nodePublicHexPrefix))
  254. }
  255. // WireGuardGoString prints k in the same format used by wireguard-go.
  256. func (k NodePublic) WireGuardGoString() string {
  257. // This implementation deliberately matches the overly complicated
  258. // implementation in wireguard-go.
  259. b64 := func(input byte) byte {
  260. 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)
  261. }
  262. b := []byte("peer(____…____)")
  263. const first = len("peer(")
  264. const second = len("peer(____…")
  265. b[first+0] = b64((k.k[0] >> 2) & 63)
  266. b[first+1] = b64(((k.k[0] << 4) | (k.k[1] >> 4)) & 63)
  267. b[first+2] = b64(((k.k[1] << 2) | (k.k[2] >> 6)) & 63)
  268. b[first+3] = b64(k.k[2] & 63)
  269. b[second+0] = b64(k.k[29] & 63)
  270. b[second+1] = b64((k.k[30] >> 2) & 63)
  271. b[second+2] = b64(((k.k[30] << 4) | (k.k[31] >> 4)) & 63)
  272. b[second+3] = b64((k.k[31] << 2) & 63)
  273. return string(b)
  274. }