handshake_manager_pq.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. package nebula
  2. import (
  3. "context"
  4. "crypto/hmac"
  5. "crypto/rand"
  6. "crypto/sha256"
  7. "encoding/binary"
  8. "errors"
  9. "log/slog"
  10. "net/netip"
  11. "sync"
  12. "time"
  13. "github.com/slackhq/nebula/cert"
  14. "github.com/slackhq/nebula/config"
  15. "github.com/slackhq/nebula/handshake"
  16. "github.com/slackhq/nebula/handshake/fragment"
  17. "github.com/slackhq/nebula/header"
  18. )
  19. const (
  20. // DefaultPQRepairDelay is how long repair fragments trail the data fragments.
  21. DefaultPQRepairDelay = 10 * time.Millisecond
  22. // pqAmplification bounds what a responder sends in reply to an unvalidated
  23. // address, as a multiple of what it received from it.
  24. pqAmplification = 3
  25. )
  26. // pqMaxMsgLen bounds the fragmented handshake messages a node reassembles:
  27. // msg1 in the responder's table and msg2 in an initiator's slots. The largest
  28. // is msg2 at about 9.6KB, which leaves room for certificates carrying many
  29. // names and routes.
  30. const pqMaxMsgLen = 16384
  31. // pqTableConfig bounds the responder's reassembly of msg1 fragments from senders
  32. // that have not authenticated yet.
  33. var pqTableConfig = fragment.TableConfig{
  34. MaxBytes: 4 << 20,
  35. MaxEntries: 1024,
  36. MaxPerSource: 4,
  37. MaxMsgLen: pqMaxMsgLen,
  38. TTL: 3 * time.Second,
  39. }
  40. type pqHandshakeConfig struct {
  41. initiate bool // start PQ handshakes
  42. accept bool // answer PQ handshakes
  43. require bool // only PQ handshakes, in either direction
  44. sticky bool // never fall back to classical for a peer that completed PQ
  45. repairDelay time.Duration // delay between data and repair fragments
  46. }
  47. func pqHandshakeConfigFrom(c *config.C) pqHandshakeConfig {
  48. cfg := pqHandshakeConfig{
  49. initiate: c.GetBool("handshakes.pq.initiate", false),
  50. accept: c.GetBool("handshakes.pq.accept", false),
  51. require: c.GetBool("handshakes.pq.require", false),
  52. sticky: c.GetBool("handshakes.pq.sticky", false),
  53. repairDelay: c.GetDuration("handshakes.pq.repair_delay", DefaultPQRepairDelay),
  54. }
  55. if cfg.require {
  56. cfg.initiate = true
  57. cfg.accept = true
  58. }
  59. return cfg
  60. }
  61. // pqConfig returns the post-quantum settings in effect.
  62. func (hm *HandshakeManager) pqConfig() *pqHandshakeConfig {
  63. return hm.pq.Load()
  64. }
  65. // warnPQWithoutV3 says so when post-quantum settings are on but the node has no
  66. // version 3 certificate: post-quantum handshakes are hybrid only, so they do
  67. // nothing until it has one. require is refused outright when loading pki.
  68. func warnPQWithoutV3(l *slog.Logger, cfg pqHandshakeConfig, cs *CertState) {
  69. if _, ok := cs.hybridSubtype(); ok || !(cfg.initiate || cfg.accept || cfg.sticky) {
  70. return
  71. }
  72. l.Warn("handshakes.pq has no effect without a version 3 certificate in pki.cert",
  73. "initiate", cfg.initiate, "accept", cfg.accept, "sticky", cfg.sticky)
  74. }
  75. // reloadPQ applies changed post-quantum settings. Handshakes already in flight
  76. // keep going; the new settings apply to the next attempt and packet.
  77. func (hm *HandshakeManager) reloadPQ(c *config.C) {
  78. if !c.HasChanged("handshakes.pq") {
  79. return
  80. }
  81. old := hm.pqConfig()
  82. cfg := pqHandshakeConfigFrom(c)
  83. cs := hm.f.pki.getCertState()
  84. if _, ok := cs.hybridSubtype(); cfg.require && !ok {
  85. hm.l.Error("Refusing handshakes.pq.require without a version 3 certificate in pki.cert, keeping the previous settings")
  86. return
  87. }
  88. warnPQWithoutV3(hm.l, cfg, cs)
  89. hm.pq.Store(&cfg)
  90. hm.l.Info("Post-quantum handshake settings changed",
  91. "initiate", cfg.initiate, "oldInitiate", old.initiate,
  92. "accept", cfg.accept, "oldAccept", old.accept,
  93. "require", cfg.require, "oldRequire", old.require,
  94. "sticky", cfg.sticky, "oldSticky", old.sticky,
  95. "repairDelay", cfg.repairDelay, "oldRepairDelay", old.repairDelay,
  96. )
  97. }
  98. // pqMsg2Slots is how many responders' msg2s one attempt reassembles at once.
  99. // Two hosts answer the same msg1 when a stale lighthouse address for the peer
  100. // belongs to another node now. Both answers name this attempt in RemoteIndex
  101. // and differ only in FragID, the responder's own index. A single assembly that
  102. // emptied on a FragID change let the two interleaved bursts wipe each other
  103. // out, and since hearing any msg2 fragment stops the classical turns, the
  104. // retries only repeated it (up to three extra attempts in e2e). One slot per
  105. // FragID lets whichever answer completes first be processed; a wrong host's
  106. // answer then takes the existing block-and-retry path.
  107. const pqMsg2Slots = 2
  108. // msg2Slot reassembles one responder's msg2.
  109. type msg2Slot struct {
  110. fragID uint32
  111. msgLen uint16
  112. a *fragment.Assembly
  113. }
  114. // pqAttempt is the initiator's post-quantum attempt for a pending handshake. It
  115. // lives alongside the classical attempt in HandshakeHostInfo and has its own
  116. // local index, so whichever answer arrives first wins.
  117. type pqAttempt struct {
  118. machine *handshake.Machine
  119. subtype header.MessageSubType
  120. index uint32
  121. sender *fragment.Sender
  122. msg2 [pqMsg2Slots]msg2Slot // an array, not a map: one slot is used nearly always
  123. cookieResendAt time.Time // last resend prompted by a cookie reply
  124. heard bool // a msg2 fragment or cookie reply arrived, so the peer speaks PQ
  125. }
  126. // slotFor returns the assembly collecting msg2 fragments with fh's FragID,
  127. // starting one if there is none. A responder never changes its FragID or
  128. // MsgLen, so a fragment whose MsgLen disagrees with its slot is a stray or a
  129. // forgery and starts that slot over. When every slot is taken the one holding
  130. // the least is replaced: a third responder is vanishingly rare, and a forged
  131. // FragID could already spoil an attempt. It returns nil if no assembly can be
  132. // made for fh.
  133. func (pq *pqAttempt) slotFor(fh fragment.Header) *fragment.Assembly {
  134. victim := -1
  135. for i := range pq.msg2 {
  136. s := &pq.msg2[i]
  137. if s.a != nil && s.fragID == fh.FragID {
  138. if s.msgLen == fh.MsgLen {
  139. return s.a
  140. }
  141. victim = i
  142. break
  143. }
  144. }
  145. if victim < 0 {
  146. for i := range pq.msg2 {
  147. if pq.msg2[i].a == nil {
  148. victim = i
  149. break
  150. }
  151. }
  152. }
  153. if victim < 0 {
  154. victim = 0
  155. for i := 1; i < len(pq.msg2); i++ {
  156. if pq.msg2[i].a.Stored() < pq.msg2[victim].a.Stored() {
  157. victim = i
  158. }
  159. }
  160. }
  161. a, err := fragment.NewAssembly(fh)
  162. if err != nil {
  163. return nil
  164. }
  165. pq.msg2[victim] = msg2Slot{fragID: fh.FragID, msgLen: fh.MsgLen, a: a}
  166. return a
  167. }
  168. // dropSlot releases the slot holding a.
  169. func (pq *pqAttempt) dropSlot(a *fragment.Assembly) {
  170. for i := range pq.msg2 {
  171. if pq.msg2[i].a == a {
  172. pq.msg2[i] = msg2Slot{}
  173. }
  174. }
  175. }
  176. // pqFragKey identifies one msg1 being reassembled.
  177. type pqFragKey struct {
  178. addr netip.AddrPort
  179. relay uint32
  180. fragID uint32
  181. }
  182. // pqFragSource groups msg1 reassemblies for the per-source quota: an IPv4 /32,
  183. // an IPv6 /64, or one relay channel.
  184. type pqFragSource struct {
  185. prefix netip.Prefix
  186. relay uint32
  187. }
  188. func pqFragKeyFor(via ViaSender, fragID uint32) (pqFragKey, pqFragSource) {
  189. if via.IsRelayed {
  190. return pqFragKey{relay: via.relay.LocalIndex, fragID: fragID},
  191. pqFragSource{relay: via.relay.LocalIndex}
  192. }
  193. addr := via.UdpAddr.Addr().Unmap()
  194. bits := 64
  195. if addr.Is4() {
  196. bits = 32
  197. }
  198. prefix, _ := addr.Prefix(bits)
  199. return pqFragKey{addr: via.UdpAddr, fragID: fragID}, pqFragSource{prefix: prefix}
  200. }
  201. // reassembled turns a decoded message into the packet the handshake Machine
  202. // expects, by writing the header of one of its fragments into the header.Len
  203. // bytes left for it in front of the message.
  204. func reassembled(h *header.H, pkt []byte) []byte {
  205. return header.Encode(pkt, header.Version, header.Handshake, h.Subtype, h.RemoteIndex, h.MessageCounter)[:len(pkt)]
  206. }
  207. // usePQ decides whether this outbound attempt is post-quantum. A peer that does
  208. // not speak PQ silently drops it, so timer retries alternate between PQ and
  209. // classical, starting with PQ. An attempt triggered early by a lighthouse reply
  210. // is sending to addresses nothing has been sent to yet, and a new path gets the
  211. // PQ attempt first. With require, or for a peer that completed a PQ handshake
  212. // when sticky is on, every attempt is PQ. Once anything has come back for the PQ
  213. // attempt the peer evidently speaks PQ, and a classical attempt would only race
  214. // it, so classical stops getting turns.
  215. func (hm *HandshakeManager) usePQ(hh *HandshakeHostInfo, vpnIp netip.Addr, triggered bool) bool {
  216. cfg := hm.pqConfig()
  217. if _, ok := hm.f.pki.getCertState().hybridSubtype(); !ok {
  218. return false
  219. }
  220. switch {
  221. case !cfg.initiate, hh.noPQ:
  222. return false
  223. case cfg.require:
  224. return true
  225. case hh.pq != nil && hh.pq.heard:
  226. return true
  227. case cfg.sticky:
  228. if _, ok := hm.pqPeers.Load(vpnIp); ok {
  229. return true
  230. }
  231. }
  232. return hh.counter <= 1 || triggered || !hh.lastPQ
  233. }
  234. // relayEstablished pushes the pending handshake with target through a relay that
  235. // just came up, rather than leaving it for the next retry. Nothing has gone over
  236. // the relay yet, so like any new path it gets the PQ attempt first, which then
  237. // counts as the PQ turn: the next retry is classical, as if it had been sent on
  238. // schedule. Without this, relays coming up while the first attempt is in flight
  239. // handed every relayed handshake to the classical retry.
  240. func (hm *HandshakeManager) relayEstablished(target netip.Addr, relayHI *HostInfo, relay *Relay) {
  241. hh := hm.queryVpnIp(target)
  242. if hh == nil {
  243. return
  244. }
  245. hh.Lock()
  246. defer hh.Unlock()
  247. if hm.queryVpnIp(target) != hh {
  248. return
  249. }
  250. var now, later [][]byte
  251. switch {
  252. case hh.pq != nil:
  253. var err error
  254. now, later, err = hh.pq.sender.Attempt(fragment.DefaultRepair(hh.pq.sender.Layout().K))
  255. if err != nil {
  256. return
  257. }
  258. hh.lastPQ = true
  259. case hh.ready:
  260. now = [][]byte{hh.hostinfo.HandshakePacket[handshakePacketStage0]}
  261. default:
  262. return
  263. }
  264. f := hm.f
  265. hh.hostinfo.logger(hm.l).Info("Send handshake via new relay", "relay", relayHI.vpnAddrs[0])
  266. _ = hm.sendFragmented(now, later, func(p []byte) error {
  267. f.sendHandshakeVia(relayHI, relay, p)
  268. return nil
  269. })
  270. }
  271. // sendHandshakeVia sends a handshake packet through a relay, with buffers sized
  272. // for the packet rather than the mtu: a relayed post-quantum handshake is
  273. // dozens of fragments.
  274. func (f *Interface) sendHandshakeVia(via *HostInfo, relay *Relay, p []byte) {
  275. out := make([]byte, header.Len+len(p)+via.ConnectionState.eKey.Overhead())
  276. f.SendVia(via, relay, p, make([]byte, 12), out, false, 0)
  277. }
  278. // buildPQAttempt creates the initiator's PQ Machine and msg1 sender. A node with
  279. // a v3 certificate speaks the hybrid handshake for its suite's KEM, anyone else
  280. // the ephemeral KEM one.
  281. func (hm *HandshakeManager) buildPQAttempt(hh *HandshakeHostInfo) bool {
  282. cs := hm.f.pki.getCertState()
  283. v := hm.initiatingVersion(hh, cs)
  284. subtype, ok := cs.hybridSubtype()
  285. if !ok {
  286. return false
  287. }
  288. v = cert.Version3
  289. if cs.GetCredential(v) == nil {
  290. hm.f.l.Error("Unable to handshake with host because no certificate is available",
  291. "vpnAddrs", hh.hostinfo.vpnAddrs, "certVersion", v)
  292. return false
  293. }
  294. pq := &pqAttempt{subtype: subtype}
  295. machine, err := handshake.NewMachine(
  296. v, cs.GetCredential,
  297. hm.certVerifier(), func() (uint32, error) { return hm.allocatePQIndex(hh, pq) },
  298. true, subtype,
  299. )
  300. if err != nil {
  301. hm.f.l.Error("Failed to create handshake machine",
  302. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  303. return false
  304. }
  305. msg, err := machine.Initiate(nil)
  306. if err != nil {
  307. hm.f.l.Error("Failed to initiate handshake",
  308. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  309. hm.releasePQIndex(hh, pq)
  310. return false
  311. }
  312. sender, err := fragment.NewSender(msg[header.Len:], subtype, 0, 1, pq.index)
  313. if err != nil {
  314. hm.f.l.Error("Failed to fragment handshake",
  315. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  316. hm.releasePQIndex(hh, pq)
  317. return false
  318. }
  319. pq.machine = machine
  320. pq.sender = sender
  321. hh.pq = pq
  322. return true
  323. }
  324. // allocatePQIndex registers a local index for the PQ attempt. Unlike
  325. // allocateIndex it leaves hostinfo.localIndexId alone; that is settled when one
  326. // of the attempts completes.
  327. func (hm *HandshakeManager) allocatePQIndex(hh *HandshakeHostInfo, pq *pqAttempt) (uint32, error) {
  328. hm.mainHostMap.RLock()
  329. defer hm.mainHostMap.RUnlock()
  330. hm.Lock()
  331. defer hm.Unlock()
  332. for range 32 {
  333. index, err := generateIndex(hm.l)
  334. if err != nil {
  335. return 0, err
  336. }
  337. _, inPending := hm.indexes[index]
  338. _, inMain := hm.mainHostMap.Indexes[index]
  339. if !inMain && !inPending {
  340. pq.index = index
  341. hm.indexes[index] = hh
  342. return index, nil
  343. }
  344. }
  345. return 0, errors.New("failed to generate unique localIndexId")
  346. }
  347. // abandonPQ drops a failed PQ attempt, leaving classical attempts only. The
  348. // caller must hold hh.Lock.
  349. func (hm *HandshakeManager) abandonPQ(hh *HandshakeHostInfo) {
  350. hm.releasePQIndex(hh, hh.pq)
  351. hh.pq = nil
  352. hh.noPQ = true
  353. }
  354. func (hm *HandshakeManager) releasePQIndex(hh *HandshakeHostInfo, pq *pqAttempt) {
  355. hm.Lock()
  356. defer hm.Unlock()
  357. if pq.index != 0 && hm.indexes[pq.index] == hh {
  358. delete(hm.indexes, pq.index)
  359. }
  360. }
  361. // settleIndex makes winner the hostinfo's local index and releases the index of
  362. // the attempt that lost.
  363. func (hm *HandshakeManager) settleIndex(hh *HandshakeHostInfo, winner uint32) {
  364. hm.Lock()
  365. defer hm.Unlock()
  366. for _, idx := range []uint32{hh.hostinfo.localIndexId, hh.pqIndex()} {
  367. if idx != 0 && idx != winner && hm.indexes[idx] == hh {
  368. delete(hm.indexes, idx)
  369. }
  370. }
  371. hh.hostinfo.localIndexId = winner
  372. }
  373. func (hh *HandshakeHostInfo) pqIndex() uint32 {
  374. if hh.pq == nil {
  375. return 0
  376. }
  377. return hh.pq.index
  378. }
  379. // handleFragment routes one fragment of a PQ handshake message.
  380. func (hm *HandshakeManager) handleFragment(via ViaSender, packet []byte, h *header.H) {
  381. if h.MessageCounter == pqCookieCounter {
  382. hm.handleCookie(via, packet, h)
  383. return
  384. }
  385. fh, sym, err := fragment.Parse(packet[header.Len:])
  386. if err != nil {
  387. hm.l.Debug("dropping malformed handshake fragment", "from", via, "error", err)
  388. return
  389. }
  390. switch h.MessageCounter {
  391. case 1:
  392. cfg := hm.pqConfig()
  393. if !cfg.accept {
  394. hm.l.Debug("dropping post-quantum handshake, not accepting them", "from", via)
  395. return
  396. }
  397. mine, hasV3 := hm.f.pki.getCertState().hybridSubtype()
  398. switch {
  399. case !hasV3:
  400. hm.l.Debug("dropping hybrid handshake, no v3 certificate to answer it with", "from", via)
  401. return
  402. case h.Subtype != mine:
  403. // The peer's suite uses another KEM. Like a peer without PQ, it
  404. // falls back to classical unless either side requires PQ.
  405. hm.l.Debug("dropping hybrid handshake, our v3 certificate's suite uses another KEM", "from", via,
  406. "style", header.SubTypeName(header.Handshake, h.Subtype), "ours", header.SubTypeName(header.Handshake, mine))
  407. return
  408. }
  409. if h.RemoteIndex != 0 {
  410. hm.l.Debug("dropping stage-1 handshake with non-zero RemoteIndex",
  411. "from", via, "remoteIndex", h.RemoteIndex)
  412. return
  413. }
  414. now := time.Now()
  415. key, src := pqFragKeyFor(via, fh.FragID)
  416. if hm.pqTable.Load() >= pqCookieLoad && !(fh.HasCookie() && hm.pqCookies.valid(key, fh.Cookie, now)) {
  417. hm.sendCookie(via, h.Subtype, fh, key, len(packet), now)
  418. return
  419. }
  420. res, err := hm.pqTable.Add(key, src, now, fh, sym)
  421. if err != nil {
  422. hm.l.Debug("dropping handshake fragment", "from", via, "error", err)
  423. return
  424. }
  425. if res == nil {
  426. return
  427. }
  428. if existing := hm.pqAnswered.lookup(res.Hash, time.Now()); existing != nil {
  429. // Already answered: resend with fresh symbols on the path this copy came by.
  430. if msg := existing.HandshakePacket[handshakePacketStage2]; msg != nil {
  431. hm.sendHandshakeResponse(via, msg, existing, true, res.Received)
  432. }
  433. hm.pqTable.Answered(key, res, now)
  434. return
  435. }
  436. if res.Repeat {
  437. // Answered once, but long enough ago to be forgotten: start over.
  438. hm.pqTable.Forget(key)
  439. return
  440. }
  441. hm.beginHandshake(via, reassembled(h, res.Packet), h, res.Received)
  442. if hm.pqAnswered.lookup(res.Hash, now) != nil {
  443. hm.pqTable.Answered(key, res, now)
  444. }
  445. case 2:
  446. if hh := hm.queryIndex(h.RemoteIndex); hh != nil {
  447. hm.continuePQ(via, hh, h, fh, sym)
  448. }
  449. case 3:
  450. if handshake.IsHybrid(h.Subtype) {
  451. hm.continueHybridResponder(via, h, fh, sym)
  452. }
  453. }
  454. }
  455. // continuePQ collects msg2 fragments for the initiator's PQ attempt, one slot
  456. // per responder FragID, and processes the first msg2 to complete.
  457. func (hm *HandshakeManager) continuePQ(via ViaSender, hh *HandshakeHostInfo, h *header.H, fh fragment.Header, sym []byte) {
  458. if int(fh.MsgLen) > pqMaxMsgLen {
  459. return
  460. }
  461. hh.Lock()
  462. defer hh.Unlock()
  463. pq := hh.pq
  464. if pq == nil || pq.index != h.RemoteIndex || !hm.stillPending(hh, pq.index) {
  465. return
  466. }
  467. pq.heard = true
  468. a := pq.slotFor(fh)
  469. if a == nil {
  470. return
  471. }
  472. ready, err := a.Add(fh, sym)
  473. if err != nil || !ready {
  474. return
  475. }
  476. pkt, err := a.Decode(make([]byte, header.Len))
  477. pq.dropSlot(a)
  478. if err != nil {
  479. hm.l.Debug("failed to decode handshake fragments", "from", via, "error", err)
  480. return
  481. }
  482. hm.processResponse(via, hh, pq.machine, reassembled(h, pkt))
  483. }
  484. // sendFragmented sends packets to a peer: now immediately and later after the
  485. // repair delay. It returns the first error from the immediate sends; errors from
  486. // delayed sends are only logged.
  487. func (hm *HandshakeManager) sendFragmented(now, later [][]byte, send func([]byte) error) error {
  488. return hm.sendFragmentedAfter(now, later, send, hm.pqConfig().repairDelay)
  489. }
  490. // sendFragmentedAfter is sendFragmented with the given repair delay.
  491. func (hm *HandshakeManager) sendFragmentedAfter(now, later [][]byte, send func([]byte) error, delay time.Duration) error {
  492. var first error
  493. for _, p := range now {
  494. if err := send(p); err != nil && first == nil {
  495. first = err
  496. }
  497. }
  498. sendLater := func() {
  499. for _, p := range later {
  500. if err := send(p); err != nil {
  501. hm.l.Debug("Failed to send handshake repair fragment", "error", err)
  502. }
  503. }
  504. }
  505. switch {
  506. case len(later) == 0:
  507. case delay <= 0:
  508. sendLater()
  509. default:
  510. time.AfterFunc(delay, sendLater)
  511. }
  512. return first
  513. }
  514. // sendFragmentedResponse sends the responder's msg2 as fragments, each send
  515. // offering symbols the hostinfo has not sent before. The clock on resends is
  516. // per path and lives in the fragment table: a copy of msg1 arriving by a second
  517. // path (the other address family, a relay) is answered on that path at once,
  518. // which carries the handshake when the first path only works one way, and a
  519. // retry on a path is reported as a repeat at most once per retry interval.
  520. // received is how many bytes the triggering msg1 took, which bounds what may be
  521. // sent back before the address is validated.
  522. func (hm *HandshakeManager) sendFragmentedResponse(via ViaSender, msg []byte, hostinfo *HostInfo, received int) error {
  523. var h header.H
  524. if err := h.Parse(msg); err != nil {
  525. return err
  526. }
  527. s, err := fragment.NewSender(msg[header.Len:], h.Subtype, h.RemoteIndex, h.MessageCounter, hostinfo.localIndexId)
  528. if err != nil {
  529. return err
  530. }
  531. l := s.Layout()
  532. repair := fragment.DefaultRepair(l.K)
  533. if received > 0 {
  534. pktLen := header.Len + fragment.HeaderLen + l.SymbolSize
  535. budget := pqAmplification * received / pktLen
  536. if budget < l.K {
  537. return errors.New("handshake response exceeds the amplification budget")
  538. }
  539. repair = min(repair, budget-l.K)
  540. }
  541. n := uint32(l.K + repair)
  542. s.SetNext(int(hostinfo.handshakeNextSymbol.Add(n) - n))
  543. pkts, later, err := s.Attempt(repair)
  544. if err != nil {
  545. return err
  546. }
  547. if via.IsRelayed {
  548. if via.relay == nil {
  549. return errors.New("both addr and via.relay are nil")
  550. }
  551. // We received a valid handshake on this relay, so make sure the relay
  552. // state reflects that, in case it had been marked Disestablished.
  553. hostinfo.relayState.InsertRelayTo(via.relayHI.vpnAddrs[0])
  554. via.relayHI.relayState.UpdateRelayForByIdxState(via.relay.LocalIndex, Established)
  555. }
  556. hm.f.messageMetrics.Tx(header.Handshake, h.Subtype, int64(len(pkts)+len(later)))
  557. return hm.sendFragmented(pkts, later, hm.sendTo(via))
  558. }
  559. // notePQPeer remembers peers that completed a PQ handshake, for sticky mode.
  560. func (hm *HandshakeManager) notePQPeer(subtype header.MessageSubType, vpnAddrs []netip.Addr) {
  561. if !hm.pqConfig().sticky || !header.IsFragmented(subtype) {
  562. return
  563. }
  564. for _, a := range vpnAddrs {
  565. hm.pqPeers.Store(a, struct{}{})
  566. }
  567. if hm.l.Enabled(context.Background(), slog.LevelDebug) {
  568. hm.l.Debug("Remembering post-quantum peer", "vpnAddrs", vpnAddrs)
  569. }
  570. }
  571. // pqAnswered remembers the msg1s a responder recently answered, keyed by hash,
  572. // so a repeat is recognised before any noise, KEM or certificate work. Repeats
  573. // are routine: the trailing repair fragments of an attempt rebuild a msg1 that
  574. // its data fragments already completed, and a retrying initiator offers fresh
  575. // symbols for the same msg1. Entries only exist for completed handshakes, which
  576. // need a valid certificate, and live as long as an initiator keeps retrying.
  577. type pqAnswered struct {
  578. sync.Mutex
  579. ttl time.Duration
  580. entries map[[sha256.Size]byte]pqAnsweredEntry
  581. }
  582. type pqAnsweredEntry struct {
  583. hostinfo *HostInfo
  584. at time.Time
  585. }
  586. const pqAnsweredMax = 4096
  587. func newPQAnswered(ttl time.Duration) *pqAnswered {
  588. return &pqAnswered{ttl: ttl, entries: map[[sha256.Size]byte]pqAnsweredEntry{}}
  589. }
  590. func (a *pqAnswered) add(msg1 []byte, hostinfo *HostInfo, now time.Time) {
  591. a.Lock()
  592. defer a.Unlock()
  593. if len(a.entries) >= pqAnsweredMax {
  594. for k := range a.entries {
  595. delete(a.entries, k)
  596. break
  597. }
  598. }
  599. a.entries[sha256.Sum256(msg1)] = pqAnsweredEntry{hostinfo: hostinfo, at: now}
  600. }
  601. // lookup finds the hostinfo that answered the msg1 with this sha256.
  602. func (a *pqAnswered) lookup(hash [sha256.Size]byte, now time.Time) *HostInfo {
  603. a.Lock()
  604. defer a.Unlock()
  605. e, ok := a.entries[hash]
  606. if !ok || now.Sub(e.at) > a.ttl {
  607. return nil
  608. }
  609. return e.hostinfo
  610. }
  611. func (a *pqAnswered) expire(now time.Time) {
  612. a.Lock()
  613. defer a.Unlock()
  614. for k, e := range a.entries {
  615. if now.Sub(e.at) > a.ttl {
  616. delete(a.entries, k)
  617. }
  618. }
  619. }
  620. // A responder whose msg1 table is under load stops keeping state for senders
  621. // that have not shown they receive at their address. It answers a fragment
  622. // without a valid cookie with a cookie reply and keeps nothing; the initiator
  623. // resends with the cookie attached. This is WireGuard's under-load cookie, QUIC's
  624. // Retry and SCTP's state cookie: one extra round trip, only while under attack.
  625. const (
  626. // pqCookieLoad is the table load above which msg1 fragments need a cookie.
  627. pqCookieLoad = 0.5
  628. // pqCookieCounter marks a cookie reply in the header's message counter.
  629. // Handshake messages count from 1.
  630. pqCookieCounter = 0
  631. // pqCookieRotate is how often the cookie secret changes. A cookie stays
  632. // valid for between one and two rotations.
  633. pqCookieRotate = 2 * time.Minute
  634. pqCookieReplyLen = header.Len + fragment.CookieLen
  635. )
  636. // pqCookies mints and checks cookies: an HMAC over the sender's address (or relay
  637. // channel) and FragID under a rotating secret, with the previous secret still
  638. // accepted.
  639. type pqCookies struct {
  640. sync.Mutex
  641. secrets [2][32]byte
  642. rotatedAt time.Time
  643. }
  644. func newPQCookies(now time.Time) *pqCookies {
  645. c := &pqCookies{rotatedAt: now}
  646. _, _ = rand.Read(c.secrets[0][:])
  647. _, _ = rand.Read(c.secrets[1][:])
  648. return c
  649. }
  650. func (c *pqCookies) rotate(now time.Time) {
  651. if now.Sub(c.rotatedAt) < pqCookieRotate {
  652. return
  653. }
  654. c.secrets[1] = c.secrets[0]
  655. _, _ = rand.Read(c.secrets[0][:])
  656. c.rotatedAt = now
  657. }
  658. func cookieMAC(secret []byte, key pqFragKey) fragment.Cookie {
  659. mac := hmac.New(sha256.New, secret)
  660. addr := key.addr.Addr().As16()
  661. mac.Write(addr[:])
  662. var b [10]byte
  663. binary.BigEndian.PutUint16(b[0:], key.addr.Port())
  664. binary.BigEndian.PutUint32(b[2:], key.relay)
  665. binary.BigEndian.PutUint32(b[6:], key.fragID)
  666. mac.Write(b[:])
  667. var c fragment.Cookie
  668. copy(c[:], mac.Sum(nil))
  669. return c
  670. }
  671. func (c *pqCookies) make(key pqFragKey, now time.Time) fragment.Cookie {
  672. c.Lock()
  673. defer c.Unlock()
  674. c.rotate(now)
  675. return cookieMAC(c.secrets[0][:], key)
  676. }
  677. func (c *pqCookies) valid(key pqFragKey, cookie fragment.Cookie, now time.Time) bool {
  678. c.Lock()
  679. defer c.Unlock()
  680. c.rotate(now)
  681. for _, s := range c.secrets {
  682. want := cookieMAC(s[:], key)
  683. if hmac.Equal(want[:], cookie[:]) {
  684. return true
  685. }
  686. }
  687. return false
  688. }
  689. // sendCookie answers a msg1 fragment that arrived without a valid cookie while
  690. // under load. The reply is never larger than what triggered it, and replies are
  691. // rate limited as a whole.
  692. func (hm *HandshakeManager) sendCookie(via ViaSender, subtype header.MessageSubType, fh fragment.Header, key pqFragKey, received int, now time.Time) {
  693. if received < pqCookieReplyLen {
  694. return
  695. }
  696. if _, ok := hm.pqCookieLimiter.Allow(); !ok {
  697. return
  698. }
  699. c := hm.pqCookies.make(key, now)
  700. reply := make([]byte, header.Len, pqCookieReplyLen)
  701. header.Encode(reply, header.Version, header.Handshake, subtype, fh.FragID, pqCookieCounter)
  702. reply = append(reply, c[:]...)
  703. hm.f.messageMetrics.Tx(header.Handshake, subtype, 1)
  704. if err := hm.sendTo(via)(reply); err != nil {
  705. hm.l.Debug("Failed to send handshake cookie", "to", via, "error", err)
  706. }
  707. }
  708. // handleCookie attaches a responder's cookie to the PQ attempt it names and
  709. // resends right away, at most once per retry interval, rather than waiting for
  710. // the next attempt.
  711. func (hm *HandshakeManager) handleCookie(via ViaSender, packet []byte, h *header.H) {
  712. if len(packet) != pqCookieReplyLen {
  713. return
  714. }
  715. hh := hm.queryIndex(h.RemoteIndex)
  716. if hh == nil {
  717. return
  718. }
  719. hh.Lock()
  720. defer hh.Unlock()
  721. pq := hh.pq
  722. if pq == nil || pq.index != h.RemoteIndex || !hm.stillPending(hh, pq.index) {
  723. return
  724. }
  725. var c fragment.Cookie
  726. copy(c[:], packet[header.Len:])
  727. pq.sender.SetCookie(c)
  728. pq.heard = true
  729. now := time.Now()
  730. if now.Sub(pq.cookieResendAt) < hm.config.tryInterval {
  731. return
  732. }
  733. pq.cookieResendAt = now
  734. pkts, later, err := pq.sender.Attempt(fragment.DefaultRepair(pq.sender.Layout().K))
  735. if err != nil {
  736. return
  737. }
  738. hm.messageMetrics.Tx(header.Handshake, pq.subtype, int64(len(pkts)+len(later)))
  739. if err := hm.sendFragmented(pkts, later, hm.sendTo(via)); err != nil {
  740. hm.l.Debug("Failed to resend handshake with cookie", "to", via, "error", err)
  741. }
  742. }
  743. // sendTo returns a function sending a packet back the way via came: directly, or
  744. // through the relay it arrived on.
  745. func (hm *HandshakeManager) sendTo(via ViaSender) func([]byte) error {
  746. f := hm.f
  747. if !via.IsRelayed {
  748. return func(p []byte) error {
  749. return f.outside.WriteTo(p, via.UdpAddr)
  750. }
  751. }
  752. return func(p []byte) error {
  753. if via.relay == nil {
  754. return errors.New("both addr and via.relay are nil")
  755. }
  756. f.sendHandshakeVia(via.relayHI, via.relay, p)
  757. return nil
  758. }
  759. }