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  }