ephermal_cache.go 1.29 KB
package handshake

import (
	"sync"
	"time"

	"github.com/lucas-clemente/quic-go/internal/crypto"
	"github.com/lucas-clemente/quic-go/internal/protocol"
)

var (
	kexLifetime    = protocol.EphermalKeyLifetime
	kexCurrent     crypto.KeyExchange
	kexCurrentTime time.Time
	kexMutex       sync.RWMutex
)

// getEphermalKEX returns the currently active KEX, which changes every protocol.EphermalKeyLifetime
// See the explanation from the QUIC crypto doc:
//
// A single connection is the usual scope for forward security, but the security
// difference between an ephemeral key used for a single connection, and one
// used for all connections for 60 seconds is negligible. Thus we can amortise
// the Diffie-Hellman key generation at the server over all the connections in a
// small time span.
func getEphermalKEX() (crypto.KeyExchange, error) {
	kexMutex.RLock()
	res := kexCurrent
	t := kexCurrentTime
	kexMutex.RUnlock()
	if res != nil && time.Since(t) < kexLifetime {
		return res, nil
	}

	kexMutex.Lock()
	defer kexMutex.Unlock()
	// Check if still unfulfilled
	if kexCurrent == nil || time.Since(kexCurrentTime) > kexLifetime {
		kex, err := crypto.NewCurve25519KEX()
		if err != nil {
			return nil, err
		}
		kexCurrent = kex
		kexCurrentTime = time.Now()
		return kexCurrent, nil
	}
	return kexCurrent, nil
}