network-lock.go 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build !ts_omit_tailnetlock
  4. package ipnlocal
  5. import (
  6. "bytes"
  7. "context"
  8. "crypto/ed25519"
  9. "crypto/rand"
  10. "encoding/base64"
  11. "encoding/binary"
  12. "encoding/json"
  13. "errors"
  14. "fmt"
  15. "io"
  16. "net/http"
  17. "net/netip"
  18. "os"
  19. "path/filepath"
  20. "slices"
  21. "time"
  22. "tailscale.com/health"
  23. "tailscale.com/health/healthmsg"
  24. "tailscale.com/ipn"
  25. "tailscale.com/ipn/ipnstate"
  26. "tailscale.com/net/tsaddr"
  27. "tailscale.com/tailcfg"
  28. "tailscale.com/tka"
  29. "tailscale.com/tsconst"
  30. "tailscale.com/types/key"
  31. "tailscale.com/types/logger"
  32. "tailscale.com/types/netmap"
  33. "tailscale.com/types/persist"
  34. "tailscale.com/types/tkatype"
  35. "tailscale.com/util/mak"
  36. "tailscale.com/util/set"
  37. )
  38. // TODO(tom): RPC retry/backoff was broken and has been removed. Fix?
  39. var (
  40. errMissingNetmap = errors.New("missing netmap: verify that you are logged in")
  41. errNetworkLockNotActive = errors.New("network-lock is not active")
  42. tkaCompactionDefaults = tka.CompactionOptions{
  43. MinChain: 24, // Keep at minimum 24 AUMs since head.
  44. MinAge: 14 * 24 * time.Hour, // Keep 2 weeks of AUMs.
  45. }
  46. )
  47. type tkaState struct {
  48. profile ipn.ProfileID
  49. authority *tka.Authority
  50. storage tka.CompactableChonk
  51. filtered []ipnstate.TKAPeer
  52. }
  53. func (b *LocalBackend) initTKALocked() error {
  54. cp := b.pm.CurrentProfile()
  55. if cp.ID() == "" {
  56. b.tka = nil
  57. return nil
  58. }
  59. if b.tka != nil {
  60. if b.tka.profile == cp.ID() {
  61. // Already initialized.
  62. return nil
  63. }
  64. // As we're switching profiles, we need to reset the TKA to nil.
  65. b.tka = nil
  66. }
  67. root := b.TailscaleVarRoot()
  68. if root == "" {
  69. b.tka = nil
  70. b.logf("cannot fetch existing TKA state; no state directory for network-lock")
  71. return nil
  72. }
  73. chonkDir := b.chonkPathLocked()
  74. if _, err := os.Stat(chonkDir); err == nil {
  75. // The directory exists, which means network-lock has been initialized.
  76. storage, err := tka.ChonkDir(chonkDir)
  77. if err != nil {
  78. return fmt.Errorf("opening tailchonk: %v", err)
  79. }
  80. authority, err := tka.Open(storage)
  81. if err != nil {
  82. return fmt.Errorf("initializing tka: %v", err)
  83. }
  84. if err := authority.Compact(storage, tkaCompactionDefaults); err != nil {
  85. b.logf("tka compaction failed: %v", err)
  86. }
  87. b.tka = &tkaState{
  88. profile: cp.ID(),
  89. authority: authority,
  90. storage: storage,
  91. }
  92. b.logf("tka initialized at head %x", authority.Head())
  93. }
  94. return nil
  95. }
  96. // noNetworkLockStateDirWarnable is a Warnable to warn the user that Tailnet Lock data
  97. // (in particular, the list of AUMs in the TKA state) is being stored in memory and will
  98. // be lost when tailscaled restarts.
  99. var noNetworkLockStateDirWarnable = health.Register(&health.Warnable{
  100. Code: "no-tailnet-lock-state-dir",
  101. Title: "No statedir for Tailnet Lock",
  102. Severity: health.SeverityMedium,
  103. Text: health.StaticMessage(healthmsg.InMemoryTailnetLockState),
  104. })
  105. // tkaFilterNetmapLocked checks the signatures on each node key, dropping
  106. // nodes from the netmap whose signature does not verify.
  107. //
  108. // b.mu must be held.
  109. func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) {
  110. if b.tka == nil && !b.capTailnetLock {
  111. b.health.SetTKAHealth(nil)
  112. return
  113. }
  114. if b.tka == nil {
  115. b.health.SetTKAHealth(nil)
  116. return // TKA not enabled.
  117. }
  118. tracker := rotationTracker{logf: b.logf}
  119. var toDelete map[int]bool // peer index => true
  120. for i, p := range nm.Peers {
  121. if p.UnsignedPeerAPIOnly() {
  122. // Not subject to tailnet lock.
  123. continue
  124. }
  125. if p.KeySignature().Len() == 0 {
  126. b.logf("Network lock is dropping peer %v(%v) due to missing signature", p.ID(), p.StableID())
  127. mak.Set(&toDelete, i, true)
  128. } else {
  129. details, err := b.tka.authority.NodeKeyAuthorizedWithDetails(p.Key(), p.KeySignature().AsSlice())
  130. if err != nil {
  131. b.logf("Network lock is dropping peer %v(%v) due to failed signature check: %v", p.ID(), p.StableID(), err)
  132. mak.Set(&toDelete, i, true)
  133. continue
  134. }
  135. if details != nil {
  136. // Rotation details are returned when the node key is signed by a valid SigRotation signature.
  137. tracker.addRotationDetails(p.Key(), details)
  138. }
  139. }
  140. }
  141. obsoleteByRotation := tracker.obsoleteKeys()
  142. // nm.Peers is ordered, so deletion must be order-preserving.
  143. if len(toDelete) > 0 || len(obsoleteByRotation) > 0 {
  144. peers := make([]tailcfg.NodeView, 0, len(nm.Peers))
  145. filtered := make([]ipnstate.TKAPeer, 0, len(toDelete)+len(obsoleteByRotation))
  146. for i, p := range nm.Peers {
  147. if !toDelete[i] && !obsoleteByRotation.Contains(p.Key()) {
  148. peers = append(peers, p)
  149. } else {
  150. if obsoleteByRotation.Contains(p.Key()) {
  151. b.logf("Network lock is dropping peer %v(%v) due to key rotation", p.ID(), p.StableID())
  152. }
  153. // Record information about the node we filtered out.
  154. filtered = append(filtered, tkaStateFromPeer(p))
  155. }
  156. }
  157. nm.Peers = peers
  158. b.tka.filtered = filtered
  159. } else {
  160. b.tka.filtered = nil
  161. }
  162. // Check that we ourselves are not locked out, report a health issue if so.
  163. if nm.SelfNode.Valid() && b.tka.authority.NodeKeyAuthorized(nm.SelfNode.Key(), nm.SelfNode.KeySignature().AsSlice()) != nil {
  164. b.health.SetTKAHealth(errors.New(healthmsg.LockedOut))
  165. } else {
  166. b.health.SetTKAHealth(nil)
  167. }
  168. }
  169. // rotationTracker determines the set of node keys that are made obsolete by key
  170. // rotation.
  171. // - for each SigRotation signature, all previous node keys referenced by the
  172. // nested signatures are marked as obsolete.
  173. // - if there are multiple SigRotation signatures tracing back to the same
  174. // wrapping pubkey of the initial SigDirect signature (e.g. if a node is
  175. // cloned with all its keys), we keep just one of them, marking the others as
  176. // obsolete.
  177. type rotationTracker struct {
  178. // obsolete is the set of node keys that are obsolete due to key rotation.
  179. // users of rotationTracker should use the obsoleteKeys method for complete results.
  180. obsolete set.Set[key.NodePublic]
  181. // byWrappingKey keeps track of rotation details per wrapping pubkey.
  182. byWrappingKey map[string][]sigRotationDetails
  183. logf logger.Logf
  184. }
  185. // sigRotationDetails holds information about a node key signed by a SigRotation.
  186. type sigRotationDetails struct {
  187. np key.NodePublic
  188. numPrevKeys int
  189. }
  190. // addRotationDetails records the rotation signature details for a node key.
  191. func (r *rotationTracker) addRotationDetails(np key.NodePublic, d *tka.RotationDetails) {
  192. r.obsolete.Make()
  193. r.obsolete.AddSlice(d.PrevNodeKeys)
  194. if d.InitialSig.SigKind != tka.SigDirect {
  195. // Only enforce uniqueness of chains originating from a SigDirect
  196. // signature. Chains that begin with a SigCredential can legitimately
  197. // start from the same wrapping pubkey when multiple nodes join the
  198. // network using the same reusable auth key.
  199. return
  200. }
  201. rd := sigRotationDetails{
  202. np: np,
  203. numPrevKeys: len(d.PrevNodeKeys),
  204. }
  205. if r.byWrappingKey == nil {
  206. r.byWrappingKey = make(map[string][]sigRotationDetails)
  207. }
  208. wp := string(d.InitialSig.WrappingPubkey)
  209. r.byWrappingKey[wp] = append(r.byWrappingKey[wp], rd)
  210. }
  211. // obsoleteKeys returns the set of node keys that are obsolete due to key rotation.
  212. func (r *rotationTracker) obsoleteKeys() set.Set[key.NodePublic] {
  213. for _, v := range r.byWrappingKey {
  214. // Do not consider signatures for keys that have been marked as obsolete
  215. // by another signature.
  216. v = slices.DeleteFunc(v, func(rd sigRotationDetails) bool {
  217. return r.obsolete.Contains(rd.np)
  218. })
  219. if len(v) == 0 {
  220. continue
  221. }
  222. // If there are multiple rotation signatures with the same wrapping
  223. // pubkey, we need to decide which one is the "latest", and keep it.
  224. // The signature with the largest number of previous keys is likely to
  225. // be the latest.
  226. slices.SortStableFunc(v, func(a, b sigRotationDetails) int {
  227. // Sort by decreasing number of previous keys.
  228. return b.numPrevKeys - a.numPrevKeys
  229. })
  230. // If there are several signatures with the same number of previous
  231. // keys, we cannot determine which one is the latest, so all of them are
  232. // rejected for safety.
  233. if len(v) >= 2 && v[0].numPrevKeys == v[1].numPrevKeys {
  234. r.logf("at least two nodes (%s and %s) have equally valid rotation signatures with the same wrapping pubkey, rejecting", v[0].np, v[1].np)
  235. for _, rd := range v {
  236. r.obsolete.Add(rd.np)
  237. }
  238. } else {
  239. // The first key in v is the one with the longest chain of previous
  240. // keys, so it must be the newest one. Mark all older keys as obsolete.
  241. for _, rd := range v[1:] {
  242. r.obsolete.Add(rd.np)
  243. }
  244. }
  245. }
  246. return r.obsolete
  247. }
  248. // tkaSyncIfNeeded examines TKA info reported from the control plane,
  249. // performing the steps necessary to synchronize local tka state.
  250. //
  251. // There are 4 scenarios handled here:
  252. // - Enablement: nm.TKAEnabled but b.tka == nil
  253. // ∴ reach out to /machine/tka/bootstrap to get the genesis AUM, then
  254. // initialize TKA.
  255. // - Disablement: !nm.TKAEnabled but b.tka != nil
  256. // ∴ reach out to /machine/tka/bootstrap to read the disablement secret,
  257. // then verify and clear tka local state.
  258. // - Sync needed: b.tka.Head != nm.TKAHead
  259. // ∴ complete multi-step synchronization flow.
  260. // - Everything up to date: All other cases.
  261. // ∴ no action necessary.
  262. //
  263. // tkaSyncIfNeeded immediately takes b.takeSyncLock which is held throughout,
  264. // and may take b.mu as required.
  265. func (b *LocalBackend) tkaSyncIfNeeded(nm *netmap.NetworkMap, prefs ipn.PrefsView) error {
  266. b.tkaSyncLock.Lock() // take tkaSyncLock to make this function an exclusive section.
  267. defer b.tkaSyncLock.Unlock()
  268. b.mu.Lock() // take mu to protect access to synchronized fields.
  269. defer b.mu.Unlock()
  270. if b.tka == nil && !b.capTailnetLock {
  271. return nil
  272. }
  273. isEnabled := b.tka != nil
  274. wantEnabled := nm.TKAEnabled
  275. if isEnabled || wantEnabled {
  276. b.logf("tkaSyncIfNeeded: isEnabled=%t, wantEnabled=%t, head=%v", isEnabled, wantEnabled, nm.TKAHead)
  277. }
  278. ourNodeKey, ok := prefs.Persist().PublicNodeKeyOK()
  279. if !ok {
  280. return errors.New("tkaSyncIfNeeded: no node key in prefs")
  281. }
  282. didJustEnable := false
  283. if isEnabled != wantEnabled {
  284. var ourHead tka.AUMHash
  285. if b.tka != nil {
  286. ourHead = b.tka.authority.Head()
  287. }
  288. // Regardless of whether we are moving to disabled or enabled, we
  289. // need information from the tka bootstrap endpoint.
  290. b.mu.Unlock()
  291. bs, err := b.tkaFetchBootstrap(ourNodeKey, ourHead)
  292. b.mu.Lock()
  293. if err != nil {
  294. return fmt.Errorf("fetching bootstrap: %w", err)
  295. }
  296. if wantEnabled && !isEnabled {
  297. if err := b.tkaBootstrapFromGenesisLocked(bs.GenesisAUM, prefs.Persist()); err != nil {
  298. return fmt.Errorf("bootstrap: %w", err)
  299. }
  300. isEnabled = true
  301. didJustEnable = true
  302. } else if !wantEnabled && isEnabled {
  303. if err := b.tkaApplyDisablementLocked(bs.DisablementSecret); err != nil {
  304. // We log here instead of returning an error (which itself would be
  305. // logged), so that sync will continue even if control gives us an
  306. // incorrect disablement secret.
  307. b.logf("Disablement failed, leaving TKA enabled. Error: %v", err)
  308. } else {
  309. isEnabled = false
  310. b.health.SetTKAHealth(nil)
  311. }
  312. } else {
  313. return fmt.Errorf("[bug] unreachable invariant of wantEnabled w/ isEnabled")
  314. }
  315. }
  316. // We always transmit the sync RPCs if TKA was just enabled.
  317. // This informs the control plane that our TKA state is now
  318. // initialized to the transmitted TKA head hash.
  319. if isEnabled && (b.tka.authority.Head() != nm.TKAHead || didJustEnable) {
  320. if err := b.tkaSyncLocked(ourNodeKey); err != nil {
  321. return fmt.Errorf("tka sync: %w", err)
  322. }
  323. // Try to compact the TKA state, to avoid unbounded storage on nodes.
  324. //
  325. // We run this on every sync so that clients compact consistently. In many
  326. // cases this will be a no-op.
  327. if err := b.tka.authority.Compact(b.tka.storage, tkaCompactionDefaults); err != nil {
  328. return fmt.Errorf("tka compact: %w", err)
  329. }
  330. }
  331. return nil
  332. }
  333. // tkaSyncLocked synchronizes TKA state with control. b.mu must be held
  334. // and tka must be initialized. b.mu will be stepped out of (and back into)
  335. // during network RPCs.
  336. //
  337. // b.mu must be held.
  338. func (b *LocalBackend) tkaSyncLocked(ourNodeKey key.NodePublic) error {
  339. offer, err := b.tka.authority.SyncOffer(b.tka.storage)
  340. if err != nil {
  341. return fmt.Errorf("offer: %w", err)
  342. }
  343. b.mu.Unlock()
  344. offerResp, err := b.tkaDoSyncOffer(ourNodeKey, offer)
  345. b.mu.Lock()
  346. if err != nil {
  347. return fmt.Errorf("offer RPC: %w", err)
  348. }
  349. controlOffer, err := tka.ToSyncOffer(offerResp.Head, offerResp.Ancestors)
  350. if err != nil {
  351. return fmt.Errorf("control offer: %v", err)
  352. }
  353. if controlOffer.Head == offer.Head {
  354. // We are up to date.
  355. return nil
  356. }
  357. // Compute missing AUMs before we apply any AUMs from the control-plane,
  358. // so we still submit AUMs to control even if they are not part of the
  359. // active chain.
  360. toSendAUMs, err := b.tka.authority.MissingAUMs(b.tka.storage, controlOffer)
  361. if err != nil {
  362. return fmt.Errorf("computing missing AUMs: %w", err)
  363. }
  364. // If we got this far, then we are not up to date. Either the control-plane
  365. // has updates for us, or we have updates for the control plane.
  366. //
  367. // TODO(tom): Do we want to keep processing even if the Inform fails? Need
  368. // to think through if theres holdback concerns here or not.
  369. if len(offerResp.MissingAUMs) > 0 {
  370. aums := make([]tka.AUM, len(offerResp.MissingAUMs))
  371. for i, a := range offerResp.MissingAUMs {
  372. if err := aums[i].Unserialize(a); err != nil {
  373. return fmt.Errorf("MissingAUMs[%d]: %v", i, err)
  374. }
  375. }
  376. if err := b.tka.authority.Inform(b.tka.storage, aums); err != nil {
  377. return fmt.Errorf("inform failed: %v", err)
  378. }
  379. }
  380. // NOTE(tom): We always send this RPC so control knows what TKA
  381. // head we landed at.
  382. head := b.tka.authority.Head()
  383. b.mu.Unlock()
  384. sendResp, err := b.tkaDoSyncSend(ourNodeKey, head, toSendAUMs, false)
  385. b.mu.Lock()
  386. if err != nil {
  387. return fmt.Errorf("send RPC: %v", err)
  388. }
  389. var remoteHead tka.AUMHash
  390. if err := remoteHead.UnmarshalText([]byte(sendResp.Head)); err != nil {
  391. return fmt.Errorf("head unmarshal: %v", err)
  392. }
  393. if remoteHead != b.tka.authority.Head() {
  394. b.logf("TKA desync: expected consensus after sync but our head is %v and the control plane's is %v", b.tka.authority.Head(), remoteHead)
  395. }
  396. return nil
  397. }
  398. // tkaApplyDisablementLocked checks a disablement secret and locally disables
  399. // TKA (if correct). An error is returned if disablement failed.
  400. //
  401. // b.mu must be held & TKA must be initialized.
  402. func (b *LocalBackend) tkaApplyDisablementLocked(secret []byte) error {
  403. if b.tka.authority.ValidDisablement(secret) {
  404. if err := b.tka.storage.RemoveAll(); err != nil {
  405. return err
  406. }
  407. b.tka = nil
  408. return nil
  409. }
  410. return errors.New("incorrect disablement secret")
  411. }
  412. // chonkPathLocked returns the absolute path to the directory in which TKA
  413. // state (the 'tailchonk') is stored.
  414. //
  415. // b.mu must be held.
  416. func (b *LocalBackend) chonkPathLocked() string {
  417. return filepath.Join(b.TailscaleVarRoot(), "tka-profiles", string(b.pm.CurrentProfile().ID()))
  418. }
  419. // tkaBootstrapFromGenesisLocked initializes the local (on-disk) state of the
  420. // tailnet key authority, based on the given genesis AUM.
  421. //
  422. // b.mu must be held.
  423. func (b *LocalBackend) tkaBootstrapFromGenesisLocked(g tkatype.MarshaledAUM, persist persist.PersistView) error {
  424. var genesis tka.AUM
  425. if err := genesis.Unserialize(g); err != nil {
  426. return fmt.Errorf("reading genesis: %v", err)
  427. }
  428. if persist.Valid() && persist.DisallowedTKAStateIDs().Len() > 0 {
  429. if genesis.State == nil {
  430. return errors.New("invalid genesis: missing State")
  431. }
  432. bootstrapStateID := fmt.Sprintf("%d:%d", genesis.State.StateID1, genesis.State.StateID2)
  433. for _, stateID := range persist.DisallowedTKAStateIDs().All() {
  434. if stateID == bootstrapStateID {
  435. return fmt.Errorf("TKA with stateID of %q is disallowed on this node", stateID)
  436. }
  437. }
  438. }
  439. root := b.TailscaleVarRoot()
  440. var storage tka.CompactableChonk
  441. if root == "" {
  442. b.health.SetUnhealthy(noNetworkLockStateDirWarnable, nil)
  443. b.logf("network-lock using in-memory storage; no state directory")
  444. storage = tka.ChonkMem()
  445. } else {
  446. chonkDir := b.chonkPathLocked()
  447. chonk, err := tka.ChonkDir(chonkDir)
  448. if err != nil {
  449. return fmt.Errorf("chonk: %v", err)
  450. }
  451. storage = chonk
  452. }
  453. authority, err := tka.Bootstrap(storage, genesis)
  454. if err != nil {
  455. return fmt.Errorf("tka bootstrap: %v", err)
  456. }
  457. b.tka = &tkaState{
  458. profile: b.pm.CurrentProfile().ID(),
  459. authority: authority,
  460. storage: storage,
  461. }
  462. return nil
  463. }
  464. // NetworkLockStatus returns a structure describing the state of the
  465. // tailnet key authority, if any.
  466. func (b *LocalBackend) NetworkLockStatus() *ipnstate.NetworkLockStatus {
  467. b.mu.Lock()
  468. defer b.mu.Unlock()
  469. var (
  470. nodeKey *key.NodePublic
  471. nlPriv key.NLPrivate
  472. )
  473. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() && !p.Persist().PrivateNodeKey().IsZero() {
  474. nkp := p.Persist().PublicNodeKey()
  475. nodeKey = &nkp
  476. nlPriv = p.Persist().NetworkLockKey()
  477. }
  478. if nlPriv.IsZero() {
  479. return &ipnstate.NetworkLockStatus{
  480. Enabled: false,
  481. NodeKey: nodeKey,
  482. }
  483. }
  484. if b.tka == nil {
  485. return &ipnstate.NetworkLockStatus{
  486. Enabled: false,
  487. NodeKey: nodeKey,
  488. PublicKey: nlPriv.Public(),
  489. }
  490. }
  491. var head [32]byte
  492. h := b.tka.authority.Head()
  493. copy(head[:], h[:])
  494. var selfAuthorized bool
  495. nodeKeySignature := &tka.NodeKeySignature{}
  496. nm := b.currentNode().NetMap()
  497. if nm != nil {
  498. selfAuthorized = b.tka.authority.NodeKeyAuthorized(nm.SelfNode.Key(), nm.SelfNode.KeySignature().AsSlice()) == nil
  499. if err := nodeKeySignature.Unserialize(nm.SelfNode.KeySignature().AsSlice()); err != nil {
  500. b.logf("failed to decode self node key signature: %v", err)
  501. }
  502. }
  503. keys := b.tka.authority.Keys()
  504. outKeys := make([]ipnstate.TKAKey, len(keys))
  505. for i, k := range keys {
  506. outKeys[i] = ipnstate.TKAKey{
  507. Kind: k.Kind.String(),
  508. Key: key.NLPublicFromEd25519Unsafe(k.Public),
  509. Metadata: k.Meta,
  510. Votes: k.Votes,
  511. }
  512. }
  513. filtered := make([]*ipnstate.TKAPeer, len(b.tka.filtered))
  514. for i := range len(filtered) {
  515. filtered[i] = b.tka.filtered[i].Clone()
  516. }
  517. var visible []*ipnstate.TKAPeer
  518. if nm != nil {
  519. visible = make([]*ipnstate.TKAPeer, len(nm.Peers))
  520. for i, p := range nm.Peers {
  521. s := tkaStateFromPeer(p)
  522. visible[i] = &s
  523. }
  524. }
  525. stateID1, _ := b.tka.authority.StateIDs()
  526. return &ipnstate.NetworkLockStatus{
  527. Enabled: true,
  528. Head: &head,
  529. PublicKey: nlPriv.Public(),
  530. NodeKey: nodeKey,
  531. NodeKeySigned: selfAuthorized,
  532. NodeKeySignature: nodeKeySignature,
  533. TrustedKeys: outKeys,
  534. FilteredPeers: filtered,
  535. VisiblePeers: visible,
  536. StateID: stateID1,
  537. }
  538. }
  539. func tkaStateFromPeer(p tailcfg.NodeView) ipnstate.TKAPeer {
  540. fp := ipnstate.TKAPeer{
  541. Name: p.Name(),
  542. ID: p.ID(),
  543. StableID: p.StableID(),
  544. TailscaleIPs: make([]netip.Addr, 0, p.Addresses().Len()),
  545. NodeKey: p.Key(),
  546. }
  547. for _, addr := range p.Addresses().All() {
  548. if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
  549. fp.TailscaleIPs = append(fp.TailscaleIPs, addr.Addr())
  550. }
  551. }
  552. var decoded tka.NodeKeySignature
  553. if err := decoded.Unserialize(p.KeySignature().AsSlice()); err == nil {
  554. fp.NodeKeySignature = decoded
  555. }
  556. return fp
  557. }
  558. // NetworkLockInit enables network-lock for the tailnet, with the tailnets'
  559. // key authority initialized to trust the provided keys.
  560. //
  561. // Initialization involves two RPCs with control, termed 'begin' and 'finish'.
  562. // The Begin RPC transmits the genesis Authority Update Message, which
  563. // encodes the initial state of the authority, and the list of all nodes
  564. // needing signatures is returned as a response.
  565. // The Finish RPC submits signatures for all these nodes, at which point
  566. // Control has everything it needs to atomically enable network lock.
  567. func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byte, supportDisablement []byte) error {
  568. var ourNodeKey key.NodePublic
  569. var nlPriv key.NLPrivate
  570. b.mu.Lock()
  571. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() && !p.Persist().PrivateNodeKey().IsZero() {
  572. ourNodeKey = p.Persist().PublicNodeKey()
  573. nlPriv = p.Persist().NetworkLockKey()
  574. }
  575. b.mu.Unlock()
  576. if ourNodeKey.IsZero() || nlPriv.IsZero() {
  577. return errors.New("no node-key: is tailscale logged in?")
  578. }
  579. var entropy [16]byte
  580. if _, err := rand.Read(entropy[:]); err != nil {
  581. return err
  582. }
  583. // Generates a genesis AUM representing trust in the provided keys.
  584. // We use an in-memory tailchonk because we don't want to commit to
  585. // the filesystem until we've finished the initialization sequence,
  586. // just in case something goes wrong.
  587. _, genesisAUM, err := tka.Create(tka.ChonkMem(), tka.State{
  588. Keys: keys,
  589. // TODO(tom): s/tka.State.DisablementSecrets/tka.State.DisablementValues
  590. // This will center on consistent nomenclature:
  591. // - DisablementSecret: value needed to disable.
  592. // - DisablementValue: the KDF of the disablement secret, a public value.
  593. DisablementSecrets: disablementValues,
  594. StateID1: binary.LittleEndian.Uint64(entropy[:8]),
  595. StateID2: binary.LittleEndian.Uint64(entropy[8:]),
  596. }, nlPriv)
  597. if err != nil {
  598. return fmt.Errorf("tka.Create: %v", err)
  599. }
  600. b.logf("Generated genesis AUM to initialize network lock, trusting the following keys:")
  601. for i, k := range genesisAUM.State.Keys {
  602. b.logf(" - key[%d] = tlpub:%x with %d votes", i, k.Public, k.Votes)
  603. }
  604. // Phase 1/2 of initialization: Transmit the genesis AUM to Control.
  605. initResp, err := b.tkaInitBegin(ourNodeKey, genesisAUM)
  606. if err != nil {
  607. return fmt.Errorf("tka init-begin RPC: %w", err)
  608. }
  609. // Our genesis AUM was accepted but before Control turns on enforcement of
  610. // node-key signatures, we need to sign keys for all the existing nodes.
  611. // If we don't get these signatures ahead of time, everyone will lose
  612. // connectivity because control won't have any signatures to send which
  613. // satisfy network-lock checks.
  614. sigs := make(map[tailcfg.NodeID]tkatype.MarshaledSignature, len(initResp.NeedSignatures))
  615. for _, nodeInfo := range initResp.NeedSignatures {
  616. nks, err := signNodeKey(nodeInfo, nlPriv)
  617. if err != nil {
  618. return fmt.Errorf("generating signature: %v", err)
  619. }
  620. sigs[nodeInfo.NodeID] = nks.Serialize()
  621. }
  622. // Finalize enablement by transmitting signature for all nodes to Control.
  623. _, err = b.tkaInitFinish(ourNodeKey, sigs, supportDisablement)
  624. return err
  625. }
  626. // NetworkLockAllowed reports whether the node is allowed to use Tailnet Lock.
  627. func (b *LocalBackend) NetworkLockAllowed() bool {
  628. b.mu.Lock()
  629. defer b.mu.Unlock()
  630. return b.capTailnetLock
  631. }
  632. // Only use is in tests.
  633. func (b *LocalBackend) NetworkLockVerifySignatureForTest(nks tkatype.MarshaledSignature, nodeKey key.NodePublic) error {
  634. b.mu.Lock()
  635. defer b.mu.Unlock()
  636. if b.tka == nil {
  637. return errNetworkLockNotActive
  638. }
  639. return b.tka.authority.NodeKeyAuthorized(nodeKey, nks)
  640. }
  641. // Only use is in tests.
  642. func (b *LocalBackend) NetworkLockKeyTrustedForTest(keyID tkatype.KeyID) bool {
  643. b.mu.Lock()
  644. defer b.mu.Unlock()
  645. if b.tka == nil {
  646. panic("network lock not initialized")
  647. }
  648. return b.tka.authority.KeyTrusted(keyID)
  649. }
  650. // NetworkLockForceLocalDisable shuts down TKA locally, and denylists the current
  651. // TKA from being initialized locally in future.
  652. func (b *LocalBackend) NetworkLockForceLocalDisable() error {
  653. b.mu.Lock()
  654. defer b.mu.Unlock()
  655. if b.tka == nil {
  656. return errNetworkLockNotActive
  657. }
  658. id1, id2 := b.tka.authority.StateIDs()
  659. stateID := fmt.Sprintf("%d:%d", id1, id2)
  660. cn := b.currentNode()
  661. newPrefs := b.pm.CurrentPrefs().AsStruct().Clone() // .Persist should always be initialized here.
  662. newPrefs.Persist.DisallowedTKAStateIDs = append(newPrefs.Persist.DisallowedTKAStateIDs, stateID)
  663. if err := b.pm.SetPrefs(newPrefs.View(), cn.NetworkProfile()); err != nil {
  664. return fmt.Errorf("saving prefs: %w", err)
  665. }
  666. if err := b.tka.storage.RemoveAll(); err != nil {
  667. return fmt.Errorf("deleting TKA state: %w", err)
  668. }
  669. b.tka = nil
  670. return nil
  671. }
  672. // NetworkLockSign signs the given node-key and submits it to the control plane.
  673. // rotationPublic, if specified, must be an ed25519 public key.
  674. func (b *LocalBackend) NetworkLockSign(nodeKey key.NodePublic, rotationPublic []byte) error {
  675. ourNodeKey, sig, err := func(nodeKey key.NodePublic, rotationPublic []byte) (key.NodePublic, tka.NodeKeySignature, error) {
  676. b.mu.Lock()
  677. defer b.mu.Unlock()
  678. var nlPriv key.NLPrivate
  679. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() {
  680. nlPriv = p.Persist().NetworkLockKey()
  681. }
  682. if nlPriv.IsZero() {
  683. return key.NodePublic{}, tka.NodeKeySignature{}, errMissingNetmap
  684. }
  685. if b.tka == nil {
  686. return key.NodePublic{}, tka.NodeKeySignature{}, errNetworkLockNotActive
  687. }
  688. if !b.tka.authority.KeyTrusted(nlPriv.KeyID()) {
  689. return key.NodePublic{}, tka.NodeKeySignature{}, errors.New(tsconst.TailnetLockNotTrustedMsg)
  690. }
  691. p, err := nodeKey.MarshalBinary()
  692. if err != nil {
  693. return key.NodePublic{}, tka.NodeKeySignature{}, err
  694. }
  695. sig := tka.NodeKeySignature{
  696. SigKind: tka.SigDirect,
  697. KeyID: nlPriv.KeyID(),
  698. Pubkey: p,
  699. WrappingPubkey: rotationPublic,
  700. }
  701. sig.Signature, err = nlPriv.SignNKS(sig.SigHash())
  702. if err != nil {
  703. return key.NodePublic{}, tka.NodeKeySignature{}, fmt.Errorf("signature failed: %w", err)
  704. }
  705. return b.pm.CurrentPrefs().Persist().PublicNodeKey(), sig, nil
  706. }(nodeKey, rotationPublic)
  707. if err != nil {
  708. return err
  709. }
  710. b.logf("Generated network-lock signature for %v, submitting to control plane", nodeKey)
  711. if _, err := b.tkaSubmitSignature(ourNodeKey, sig.Serialize()); err != nil {
  712. return err
  713. }
  714. return nil
  715. }
  716. // NetworkLockModify adds and/or removes keys in the tailnet's key authority.
  717. func (b *LocalBackend) NetworkLockModify(addKeys, removeKeys []tka.Key) (err error) {
  718. defer func() {
  719. if err != nil {
  720. err = fmt.Errorf("modify network-lock keys: %w", err)
  721. }
  722. }()
  723. b.mu.Lock()
  724. defer b.mu.Unlock()
  725. var ourNodeKey key.NodePublic
  726. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() && !p.Persist().PrivateNodeKey().IsZero() {
  727. ourNodeKey = p.Persist().PublicNodeKey()
  728. }
  729. if ourNodeKey.IsZero() {
  730. return errors.New("no node-key: is tailscale logged in?")
  731. }
  732. var nlPriv key.NLPrivate
  733. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() {
  734. nlPriv = p.Persist().NetworkLockKey()
  735. }
  736. if nlPriv.IsZero() {
  737. return errMissingNetmap
  738. }
  739. if b.tka == nil {
  740. return errNetworkLockNotActive
  741. }
  742. if !b.tka.authority.KeyTrusted(nlPriv.KeyID()) {
  743. return errors.New("this node does not have a trusted tailnet lock key")
  744. }
  745. updater := b.tka.authority.NewUpdater(nlPriv)
  746. for _, addKey := range addKeys {
  747. if err := updater.AddKey(addKey); err != nil {
  748. return err
  749. }
  750. }
  751. for _, removeKey := range removeKeys {
  752. keyID, err := removeKey.ID()
  753. if err != nil {
  754. return err
  755. }
  756. if err := updater.RemoveKey(keyID); err != nil {
  757. return err
  758. }
  759. }
  760. aums, err := updater.Finalize(b.tka.storage)
  761. if err != nil {
  762. return err
  763. }
  764. if len(aums) == 0 {
  765. return nil
  766. }
  767. head := b.tka.authority.Head()
  768. b.mu.Unlock()
  769. resp, err := b.tkaDoSyncSend(ourNodeKey, head, aums, true)
  770. b.mu.Lock()
  771. if err != nil {
  772. return err
  773. }
  774. var controlHead tka.AUMHash
  775. if err := controlHead.UnmarshalText([]byte(resp.Head)); err != nil {
  776. return err
  777. }
  778. lastHead := aums[len(aums)-1].Hash()
  779. if controlHead != lastHead {
  780. return errors.New("central tka head differs from submitted AUM, try again")
  781. }
  782. return nil
  783. }
  784. // NetworkLockDisable disables network-lock using the provided disablement secret.
  785. func (b *LocalBackend) NetworkLockDisable(secret []byte) error {
  786. var (
  787. ourNodeKey key.NodePublic
  788. head tka.AUMHash
  789. err error
  790. )
  791. b.mu.Lock()
  792. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() && !p.Persist().PrivateNodeKey().IsZero() {
  793. ourNodeKey = p.Persist().PublicNodeKey()
  794. }
  795. if b.tka == nil {
  796. err = errNetworkLockNotActive
  797. } else {
  798. head = b.tka.authority.Head()
  799. if !b.tka.authority.ValidDisablement(secret) {
  800. err = errors.New("incorrect disablement secret")
  801. }
  802. }
  803. b.mu.Unlock()
  804. if err != nil {
  805. return err
  806. }
  807. if ourNodeKey.IsZero() {
  808. return errors.New("no node-key: is tailscale logged in?")
  809. }
  810. _, err = b.tkaDoDisablement(ourNodeKey, head, secret)
  811. return err
  812. }
  813. // NetworkLockLog returns the changelog of TKA state up to maxEntries in size.
  814. func (b *LocalBackend) NetworkLockLog(maxEntries int) ([]ipnstate.NetworkLockUpdate, error) {
  815. b.mu.Lock()
  816. defer b.mu.Unlock()
  817. if b.tka == nil {
  818. return nil, errNetworkLockNotActive
  819. }
  820. var out []ipnstate.NetworkLockUpdate
  821. cursor := b.tka.authority.Head()
  822. for range maxEntries {
  823. aum, err := b.tka.storage.AUM(cursor)
  824. if err != nil {
  825. if err == os.ErrNotExist {
  826. break
  827. }
  828. return out, fmt.Errorf("reading AUM (%v): %w", cursor, err)
  829. }
  830. update := ipnstate.NetworkLockUpdate{
  831. Hash: cursor,
  832. Change: aum.MessageKind.String(),
  833. Raw: aum.Serialize(),
  834. }
  835. out = append(out, update)
  836. parent, hasParent := aum.Parent()
  837. if !hasParent {
  838. break
  839. }
  840. cursor = parent
  841. }
  842. return out, nil
  843. }
  844. // NetworkLockAffectedSigs returns the signatures which would be invalidated
  845. // by removing trust in the specified KeyID.
  846. func (b *LocalBackend) NetworkLockAffectedSigs(keyID tkatype.KeyID) ([]tkatype.MarshaledSignature, error) {
  847. var (
  848. ourNodeKey key.NodePublic
  849. err error
  850. )
  851. b.mu.Lock()
  852. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() && !p.Persist().PrivateNodeKey().IsZero() {
  853. ourNodeKey = p.Persist().PublicNodeKey()
  854. }
  855. if b.tka == nil {
  856. err = errNetworkLockNotActive
  857. }
  858. b.mu.Unlock()
  859. if err != nil {
  860. return nil, err
  861. }
  862. resp, err := b.tkaReadAffectedSigs(ourNodeKey, keyID)
  863. if err != nil {
  864. return nil, err
  865. }
  866. b.mu.Lock()
  867. defer b.mu.Unlock()
  868. if b.tka == nil {
  869. return nil, errNetworkLockNotActive
  870. }
  871. // Confirm for ourselves tha the signatures would actually be invalidated
  872. // by removal of trusted in the specified key.
  873. for i, sigBytes := range resp.Signatures {
  874. var sig tka.NodeKeySignature
  875. if err := sig.Unserialize(sigBytes); err != nil {
  876. return nil, fmt.Errorf("failed decoding signature %d: %w", i, err)
  877. }
  878. sigKeyID, err := sig.UnverifiedAuthorizingKeyID()
  879. if err != nil {
  880. return nil, fmt.Errorf("extracting SigID from signature %d: %w", i, err)
  881. }
  882. if !bytes.Equal(keyID, sigKeyID) {
  883. return nil, fmt.Errorf("got signature with keyID %X from request for %X", sigKeyID, keyID)
  884. }
  885. var nodeKey key.NodePublic
  886. if err := nodeKey.UnmarshalBinary(sig.Pubkey); err != nil {
  887. return nil, fmt.Errorf("failed decoding pubkey for signature %d: %w", i, err)
  888. }
  889. if err := b.tka.authority.NodeKeyAuthorized(nodeKey, sigBytes); err != nil {
  890. return nil, fmt.Errorf("signature %d is not valid: %w", i, err)
  891. }
  892. }
  893. return resp.Signatures, nil
  894. }
  895. // NetworkLockGenerateRecoveryAUM generates an AUM which retroactively removes trust in the
  896. // specified keys. This AUM is signed by the current node and returned.
  897. //
  898. // If forkFrom is specified, it is used as the parent AUM to fork from. If the zero value,
  899. // the parent AUM is determined automatically.
  900. func (b *LocalBackend) NetworkLockGenerateRecoveryAUM(removeKeys []tkatype.KeyID, forkFrom tka.AUMHash) (*tka.AUM, error) {
  901. b.mu.Lock()
  902. defer b.mu.Unlock()
  903. if b.tka == nil {
  904. return nil, errNetworkLockNotActive
  905. }
  906. var nlPriv key.NLPrivate
  907. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() {
  908. nlPriv = p.Persist().NetworkLockKey()
  909. }
  910. if nlPriv.IsZero() {
  911. return nil, errMissingNetmap
  912. }
  913. aum, err := b.tka.authority.MakeRetroactiveRevocation(b.tka.storage, removeKeys, nlPriv.KeyID(), forkFrom)
  914. if err != nil {
  915. return nil, err
  916. }
  917. // Sign it ourselves.
  918. aum.Signatures, err = nlPriv.SignAUM(aum.SigHash())
  919. if err != nil {
  920. return nil, fmt.Errorf("signing failed: %w", err)
  921. }
  922. return aum, nil
  923. }
  924. // NetworkLockCosignRecoveryAUM co-signs the provided recovery AUM and returns
  925. // the updated structure.
  926. //
  927. // The recovery AUM provided should be the output from a previous call to
  928. // NetworkLockGenerateRecoveryAUM or NetworkLockCosignRecoveryAUM.
  929. func (b *LocalBackend) NetworkLockCosignRecoveryAUM(aum *tka.AUM) (*tka.AUM, error) {
  930. b.mu.Lock()
  931. defer b.mu.Unlock()
  932. if b.tka == nil {
  933. return nil, errNetworkLockNotActive
  934. }
  935. var nlPriv key.NLPrivate
  936. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() {
  937. nlPriv = p.Persist().NetworkLockKey()
  938. }
  939. if nlPriv.IsZero() {
  940. return nil, errMissingNetmap
  941. }
  942. for _, sig := range aum.Signatures {
  943. if bytes.Equal(sig.KeyID, nlPriv.KeyID()) {
  944. return nil, errors.New("this node has already signed this recovery AUM")
  945. }
  946. }
  947. // Sign it ourselves.
  948. sigs, err := nlPriv.SignAUM(aum.SigHash())
  949. if err != nil {
  950. return nil, fmt.Errorf("signing failed: %w", err)
  951. }
  952. aum.Signatures = append(aum.Signatures, sigs...)
  953. return aum, nil
  954. }
  955. func (b *LocalBackend) NetworkLockSubmitRecoveryAUM(aum *tka.AUM) error {
  956. b.mu.Lock()
  957. defer b.mu.Unlock()
  958. if b.tka == nil {
  959. return errNetworkLockNotActive
  960. }
  961. var ourNodeKey key.NodePublic
  962. if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist().Valid() && !p.Persist().PrivateNodeKey().IsZero() {
  963. ourNodeKey = p.Persist().PublicNodeKey()
  964. }
  965. if ourNodeKey.IsZero() {
  966. return errors.New("no node-key: is tailscale logged in?")
  967. }
  968. b.mu.Unlock()
  969. _, err := b.tkaDoSyncSend(ourNodeKey, aum.Hash(), []tka.AUM{*aum}, false)
  970. b.mu.Lock()
  971. return err
  972. }
  973. var tkaSuffixEncoder = base64.RawStdEncoding
  974. // NetworkLockWrapPreauthKey wraps a pre-auth key with information to
  975. // enable unattended bringup in the locked tailnet.
  976. //
  977. // The provided trusted tailnet-lock key is used to sign
  978. // a SigCredential structure, which is encoded along with the
  979. // private key and appended to the pre-auth key.
  980. func (b *LocalBackend) NetworkLockWrapPreauthKey(preauthKey string, tkaKey key.NLPrivate) (string, error) {
  981. b.mu.Lock()
  982. defer b.mu.Unlock()
  983. if b.tka == nil {
  984. return "", errNetworkLockNotActive
  985. }
  986. pub, priv, err := ed25519.GenerateKey(nil) // nil == crypto/rand
  987. if err != nil {
  988. return "", err
  989. }
  990. sig := tka.NodeKeySignature{
  991. SigKind: tka.SigCredential,
  992. KeyID: tkaKey.KeyID(),
  993. WrappingPubkey: pub,
  994. }
  995. sig.Signature, err = tkaKey.SignNKS(sig.SigHash())
  996. if err != nil {
  997. return "", fmt.Errorf("signing failed: %w", err)
  998. }
  999. b.logf("Generated network-lock credential signature using %s", tkaKey.Public().CLIString())
  1000. return fmt.Sprintf("%s--TL%s-%s", preauthKey, tkaSuffixEncoder.EncodeToString(sig.Serialize()), tkaSuffixEncoder.EncodeToString(priv)), nil
  1001. }
  1002. // NetworkLockVerifySigningDeeplink asks the authority to verify the given deeplink
  1003. // URL. See the comment for ValidateDeeplink for details.
  1004. func (b *LocalBackend) NetworkLockVerifySigningDeeplink(url string) tka.DeeplinkValidationResult {
  1005. b.mu.Lock()
  1006. defer b.mu.Unlock()
  1007. if b.tka == nil {
  1008. return tka.DeeplinkValidationResult{IsValid: false, Error: errNetworkLockNotActive.Error()}
  1009. }
  1010. return b.tka.authority.ValidateDeeplink(url)
  1011. }
  1012. func signNodeKey(nodeInfo tailcfg.TKASignInfo, signer key.NLPrivate) (*tka.NodeKeySignature, error) {
  1013. p, err := nodeInfo.NodePublic.MarshalBinary()
  1014. if err != nil {
  1015. return nil, err
  1016. }
  1017. sig := tka.NodeKeySignature{
  1018. SigKind: tka.SigDirect,
  1019. KeyID: signer.KeyID(),
  1020. Pubkey: p,
  1021. WrappingPubkey: nodeInfo.RotationPubkey,
  1022. }
  1023. sig.Signature, err = signer.SignNKS(sig.SigHash())
  1024. if err != nil {
  1025. return nil, fmt.Errorf("signature failed: %w", err)
  1026. }
  1027. return &sig, nil
  1028. }
  1029. func (b *LocalBackend) tkaInitBegin(ourNodeKey key.NodePublic, aum tka.AUM) (*tailcfg.TKAInitBeginResponse, error) {
  1030. var req bytes.Buffer
  1031. if err := json.NewEncoder(&req).Encode(tailcfg.TKAInitBeginRequest{
  1032. Version: tailcfg.CurrentCapabilityVersion,
  1033. NodeKey: ourNodeKey,
  1034. GenesisAUM: aum.Serialize(),
  1035. }); err != nil {
  1036. return nil, fmt.Errorf("encoding request: %v", err)
  1037. }
  1038. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1039. defer cancel()
  1040. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/init/begin", &req)
  1041. if err != nil {
  1042. return nil, fmt.Errorf("req: %w", err)
  1043. }
  1044. res, err := b.DoNoiseRequest(req2)
  1045. if err != nil {
  1046. return nil, fmt.Errorf("resp: %w", err)
  1047. }
  1048. if res.StatusCode != 200 {
  1049. body, _ := io.ReadAll(res.Body)
  1050. res.Body.Close()
  1051. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1052. }
  1053. a := new(tailcfg.TKAInitBeginResponse)
  1054. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 10 * 1024 * 1024}).Decode(a)
  1055. res.Body.Close()
  1056. if err != nil {
  1057. return nil, fmt.Errorf("decoding JSON: %w", err)
  1058. }
  1059. return a, nil
  1060. }
  1061. func (b *LocalBackend) tkaInitFinish(ourNodeKey key.NodePublic, nks map[tailcfg.NodeID]tkatype.MarshaledSignature, supportDisablement []byte) (*tailcfg.TKAInitFinishResponse, error) {
  1062. var req bytes.Buffer
  1063. if err := json.NewEncoder(&req).Encode(tailcfg.TKAInitFinishRequest{
  1064. Version: tailcfg.CurrentCapabilityVersion,
  1065. NodeKey: ourNodeKey,
  1066. Signatures: nks,
  1067. SupportDisablement: supportDisablement,
  1068. }); err != nil {
  1069. return nil, fmt.Errorf("encoding request: %v", err)
  1070. }
  1071. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1072. defer cancel()
  1073. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/init/finish", &req)
  1074. if err != nil {
  1075. return nil, fmt.Errorf("req: %w", err)
  1076. }
  1077. res, err := b.DoNoiseRequest(req2)
  1078. if err != nil {
  1079. return nil, fmt.Errorf("resp: %w", err)
  1080. }
  1081. if res.StatusCode != 200 {
  1082. body, _ := io.ReadAll(res.Body)
  1083. res.Body.Close()
  1084. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1085. }
  1086. a := new(tailcfg.TKAInitFinishResponse)
  1087. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 1024 * 1024}).Decode(a)
  1088. res.Body.Close()
  1089. if err != nil {
  1090. return nil, fmt.Errorf("decoding JSON: %w", err)
  1091. }
  1092. return a, nil
  1093. }
  1094. // tkaFetchBootstrap sends a /machine/tka/bootstrap RPC to the control plane
  1095. // over noise. This is used to get values necessary to enable or disable TKA.
  1096. func (b *LocalBackend) tkaFetchBootstrap(ourNodeKey key.NodePublic, head tka.AUMHash) (*tailcfg.TKABootstrapResponse, error) {
  1097. bootstrapReq := tailcfg.TKABootstrapRequest{
  1098. Version: tailcfg.CurrentCapabilityVersion,
  1099. NodeKey: ourNodeKey,
  1100. }
  1101. if !head.IsZero() {
  1102. head, err := head.MarshalText()
  1103. if err != nil {
  1104. return nil, fmt.Errorf("head.MarshalText failed: %v", err)
  1105. }
  1106. bootstrapReq.Head = string(head)
  1107. }
  1108. var req bytes.Buffer
  1109. if err := json.NewEncoder(&req).Encode(bootstrapReq); err != nil {
  1110. return nil, fmt.Errorf("encoding request: %v", err)
  1111. }
  1112. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1113. defer cancel()
  1114. if err := ctx.Err(); err != nil {
  1115. return nil, fmt.Errorf("ctx: %w", err)
  1116. }
  1117. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/bootstrap", &req)
  1118. if err != nil {
  1119. return nil, fmt.Errorf("req: %w", err)
  1120. }
  1121. res, err := b.DoNoiseRequest(req2)
  1122. if err != nil {
  1123. return nil, fmt.Errorf("resp: %w", err)
  1124. }
  1125. if res.StatusCode != 200 {
  1126. body, _ := io.ReadAll(res.Body)
  1127. res.Body.Close()
  1128. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1129. }
  1130. a := new(tailcfg.TKABootstrapResponse)
  1131. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 1024 * 1024}).Decode(a)
  1132. res.Body.Close()
  1133. if err != nil {
  1134. return nil, fmt.Errorf("decoding JSON: %w", err)
  1135. }
  1136. return a, nil
  1137. }
  1138. // tkaDoSyncOffer sends a /machine/tka/sync/offer RPC to the control plane
  1139. // over noise. This is the first of two RPCs implementing tka synchronization.
  1140. func (b *LocalBackend) tkaDoSyncOffer(ourNodeKey key.NodePublic, offer tka.SyncOffer) (*tailcfg.TKASyncOfferResponse, error) {
  1141. head, ancestors, err := tka.FromSyncOffer(offer)
  1142. if err != nil {
  1143. return nil, fmt.Errorf("encoding offer: %v", err)
  1144. }
  1145. syncReq := tailcfg.TKASyncOfferRequest{
  1146. Version: tailcfg.CurrentCapabilityVersion,
  1147. NodeKey: ourNodeKey,
  1148. Head: head,
  1149. Ancestors: ancestors,
  1150. }
  1151. var req bytes.Buffer
  1152. if err := json.NewEncoder(&req).Encode(syncReq); err != nil {
  1153. return nil, fmt.Errorf("encoding request: %v", err)
  1154. }
  1155. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1156. defer cancel()
  1157. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/sync/offer", &req)
  1158. if err != nil {
  1159. return nil, fmt.Errorf("req: %w", err)
  1160. }
  1161. res, err := b.DoNoiseRequest(req2)
  1162. if err != nil {
  1163. return nil, fmt.Errorf("resp: %w", err)
  1164. }
  1165. if res.StatusCode != 200 {
  1166. body, _ := io.ReadAll(res.Body)
  1167. res.Body.Close()
  1168. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1169. }
  1170. a := new(tailcfg.TKASyncOfferResponse)
  1171. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 10 * 1024 * 1024}).Decode(a)
  1172. res.Body.Close()
  1173. if err != nil {
  1174. return nil, fmt.Errorf("decoding JSON: %w", err)
  1175. }
  1176. return a, nil
  1177. }
  1178. // tkaDoSyncSend sends a /machine/tka/sync/send RPC to the control plane
  1179. // over noise. This is the second of two RPCs implementing tka synchronization.
  1180. func (b *LocalBackend) tkaDoSyncSend(ourNodeKey key.NodePublic, head tka.AUMHash, aums []tka.AUM, interactive bool) (*tailcfg.TKASyncSendResponse, error) {
  1181. headBytes, err := head.MarshalText()
  1182. if err != nil {
  1183. return nil, fmt.Errorf("head.MarshalText: %w", err)
  1184. }
  1185. sendReq := tailcfg.TKASyncSendRequest{
  1186. Version: tailcfg.CurrentCapabilityVersion,
  1187. NodeKey: ourNodeKey,
  1188. Head: string(headBytes),
  1189. MissingAUMs: make([]tkatype.MarshaledAUM, len(aums)),
  1190. Interactive: interactive,
  1191. }
  1192. for i, a := range aums {
  1193. sendReq.MissingAUMs[i] = a.Serialize()
  1194. }
  1195. var req bytes.Buffer
  1196. if err := json.NewEncoder(&req).Encode(sendReq); err != nil {
  1197. return nil, fmt.Errorf("encoding request: %v", err)
  1198. }
  1199. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1200. defer cancel()
  1201. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/sync/send", &req)
  1202. if err != nil {
  1203. return nil, fmt.Errorf("req: %w", err)
  1204. }
  1205. res, err := b.DoNoiseRequest(req2)
  1206. if err != nil {
  1207. return nil, fmt.Errorf("resp: %w", err)
  1208. }
  1209. if res.StatusCode != 200 {
  1210. body, _ := io.ReadAll(res.Body)
  1211. res.Body.Close()
  1212. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1213. }
  1214. a := new(tailcfg.TKASyncSendResponse)
  1215. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 10 * 1024 * 1024}).Decode(a)
  1216. res.Body.Close()
  1217. if err != nil {
  1218. return nil, fmt.Errorf("decoding JSON: %w", err)
  1219. }
  1220. return a, nil
  1221. }
  1222. func (b *LocalBackend) tkaDoDisablement(ourNodeKey key.NodePublic, head tka.AUMHash, secret []byte) (*tailcfg.TKADisableResponse, error) {
  1223. headBytes, err := head.MarshalText()
  1224. if err != nil {
  1225. return nil, fmt.Errorf("head.MarshalText: %w", err)
  1226. }
  1227. var req bytes.Buffer
  1228. if err := json.NewEncoder(&req).Encode(tailcfg.TKADisableRequest{
  1229. Version: tailcfg.CurrentCapabilityVersion,
  1230. NodeKey: ourNodeKey,
  1231. Head: string(headBytes),
  1232. DisablementSecret: secret,
  1233. }); err != nil {
  1234. return nil, fmt.Errorf("encoding request: %v", err)
  1235. }
  1236. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1237. defer cancel()
  1238. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/disable", &req)
  1239. if err != nil {
  1240. return nil, fmt.Errorf("req: %w", err)
  1241. }
  1242. res, err := b.DoNoiseRequest(req2)
  1243. if err != nil {
  1244. return nil, fmt.Errorf("resp: %w", err)
  1245. }
  1246. if res.StatusCode != 200 {
  1247. body, _ := io.ReadAll(res.Body)
  1248. res.Body.Close()
  1249. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1250. }
  1251. a := new(tailcfg.TKADisableResponse)
  1252. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 1024 * 1024}).Decode(a)
  1253. res.Body.Close()
  1254. if err != nil {
  1255. return nil, fmt.Errorf("decoding JSON: %w", err)
  1256. }
  1257. return a, nil
  1258. }
  1259. func (b *LocalBackend) tkaSubmitSignature(ourNodeKey key.NodePublic, sig tkatype.MarshaledSignature) (*tailcfg.TKASubmitSignatureResponse, error) {
  1260. var req bytes.Buffer
  1261. if err := json.NewEncoder(&req).Encode(tailcfg.TKASubmitSignatureRequest{
  1262. Version: tailcfg.CurrentCapabilityVersion,
  1263. NodeKey: ourNodeKey,
  1264. Signature: sig,
  1265. }); err != nil {
  1266. return nil, fmt.Errorf("encoding request: %v", err)
  1267. }
  1268. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1269. defer cancel()
  1270. req2, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/sign", &req)
  1271. if err != nil {
  1272. return nil, fmt.Errorf("req: %w", err)
  1273. }
  1274. res, err := b.DoNoiseRequest(req2)
  1275. if err != nil {
  1276. return nil, fmt.Errorf("resp: %w", err)
  1277. }
  1278. if res.StatusCode != 200 {
  1279. body, _ := io.ReadAll(res.Body)
  1280. res.Body.Close()
  1281. return nil, fmt.Errorf("request returned (%d): %s", res.StatusCode, string(body))
  1282. }
  1283. a := new(tailcfg.TKASubmitSignatureResponse)
  1284. err = json.NewDecoder(&io.LimitedReader{R: res.Body, N: 1024 * 1024}).Decode(a)
  1285. res.Body.Close()
  1286. if err != nil {
  1287. return nil, fmt.Errorf("decoding JSON: %w", err)
  1288. }
  1289. return a, nil
  1290. }
  1291. func (b *LocalBackend) tkaReadAffectedSigs(ourNodeKey key.NodePublic, key tkatype.KeyID) (*tailcfg.TKASignaturesUsingKeyResponse, error) {
  1292. var encodedReq bytes.Buffer
  1293. if err := json.NewEncoder(&encodedReq).Encode(tailcfg.TKASignaturesUsingKeyRequest{
  1294. Version: tailcfg.CurrentCapabilityVersion,
  1295. NodeKey: ourNodeKey,
  1296. KeyID: key,
  1297. }); err != nil {
  1298. return nil, fmt.Errorf("encoding request: %v", err)
  1299. }
  1300. ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1301. defer cancel()
  1302. req, err := http.NewRequestWithContext(ctx, "GET", "https://unused/machine/tka/affected-sigs", &encodedReq)
  1303. if err != nil {
  1304. return nil, fmt.Errorf("req: %w", err)
  1305. }
  1306. resp, err := b.DoNoiseRequest(req)
  1307. if err != nil {
  1308. return nil, fmt.Errorf("resp: %w", err)
  1309. }
  1310. if resp.StatusCode != 200 {
  1311. body, _ := io.ReadAll(resp.Body)
  1312. resp.Body.Close()
  1313. return nil, fmt.Errorf("request returned (%d): %s", resp.StatusCode, string(body))
  1314. }
  1315. a := new(tailcfg.TKASignaturesUsingKeyResponse)
  1316. err = json.NewDecoder(&io.LimitedReader{R: resp.Body, N: 1024 * 1024}).Decode(a)
  1317. resp.Body.Close()
  1318. if err != nil {
  1319. return nil, fmt.Errorf("decoding JSON: %w", err)
  1320. }
  1321. return a, nil
  1322. }