handshake_manager_pq.go 21 KB

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