golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/stateless_reset.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import ( 10 "crypto/hmac" 11 "crypto/rand" 12 "crypto/sha256" 13 "hash" 14 "sync" 15 ) 16 17 const statelessResetTokenLen = 128 / 8 18 19 // A statelessResetToken is a stateless reset token. 20 // https://www.rfc-editor.org/rfc/rfc9000#section-10.3 21 type statelessResetToken [statelessResetTokenLen]byte 22 23 type statelessResetTokenGenerator struct { 24 canReset bool 25 26 // The hash.Hash interface is not concurrency safe, 27 // so we need a mutex here. 28 // 29 // There shouldn't be much contention on stateless reset token generation. 30 // If this proves to be a problem, we could avoid the mutex by using a separate 31 // generator per Conn, or by using a concurrency-safe generator. 32 mu sync.Mutex 33 mac hash.Hash 34 } 35 36 func (g *statelessResetTokenGenerator) init(secret [32]byte) { 37 zero := true 38 for _, b := range secret { 39 if b != 0 { 40 zero = false 41 break 42 } 43 } 44 if zero { 45 // Generate tokens using a random secret, but don't send stateless resets. 46 rand.Read(secret[:]) 47 g.canReset = false 48 } else { 49 g.canReset = true 50 } 51 g.mac = hmac.New(sha256.New, secret[:]) 52 } 53 54 func (g *statelessResetTokenGenerator) tokenForConnID(cid []byte) (token statelessResetToken) { 55 g.mu.Lock() 56 defer g.mu.Unlock() 57 defer g.mac.Reset() 58 g.mac.Write(cid) 59 copy(token[:], g.mac.Sum(nil)) 60 return token 61 }