Files
quic-go/internal/handshake/client_session_cache.go

84 lines
2.5 KiB
Go

package handshake
import (
"crypto/tls"
"encoding/asn1"
"unsafe"
"github.com/marten-seemann/qtls"
)
type nonceField struct {
Nonce []byte
AppData []byte
}
type clientSessionCache struct {
tls.ClientSessionCache
getAppData func() []byte
setAppData func([]byte)
}
func newClientSessionCache(cache tls.ClientSessionCache, get func() []byte, set func([]byte)) *clientSessionCache {
return &clientSessionCache{
ClientSessionCache: cache,
getAppData: get,
setAppData: set,
}
}
var _ qtls.ClientSessionCache = &clientSessionCache{}
func (c *clientSessionCache) Get(sessionKey string) (*qtls.ClientSessionState, bool) {
sess, ok := c.ClientSessionCache.Get(sessionKey)
if sess == nil {
return nil, ok
}
// qtls.ClientSessionState is identical to the tls.ClientSessionState.
// In order to allow users of quic-go to use a tls.Config,
// we need this workaround to use the ClientSessionCache.
// In unsafe.go we check that the two structs are actually identical.
tlsSessBytes := (*[unsafe.Sizeof(*sess)]byte)(unsafe.Pointer(sess))[:]
var session clientSessionState
sessBytes := (*[unsafe.Sizeof(session)]byte)(unsafe.Pointer(&session))[:]
copy(sessBytes, tlsSessBytes)
var nf nonceField
if _, err := asn1.Unmarshal(session.nonce, &nf); err != nil {
return nil, false
}
c.setAppData(nf.AppData)
session.nonce = nf.Nonce
var qtlsSession qtls.ClientSessionState
qtlsSessBytes := (*[unsafe.Sizeof(qtlsSession)]byte)(unsafe.Pointer(&qtlsSession))[:]
copy(qtlsSessBytes, sessBytes)
return &qtlsSession, ok
}
func (c *clientSessionCache) Put(sessionKey string, cs *qtls.ClientSessionState) {
if cs == nil {
c.ClientSessionCache.Put(sessionKey, nil)
return
}
// qtls.ClientSessionState is identical to the tls.ClientSessionState.
// In order to allow users of quic-go to use a tls.Config,
// we need this workaround to use the ClientSessionCache.
// In unsafe.go we check that the two structs are actually identical.
qtlsSessBytes := (*[unsafe.Sizeof(*cs)]byte)(unsafe.Pointer(cs))[:]
var session clientSessionState
sessBytes := (*[unsafe.Sizeof(session)]byte)(unsafe.Pointer(&session))[:]
copy(sessBytes, qtlsSessBytes)
nonce, err := asn1.Marshal(nonceField{
Nonce: session.nonce,
AppData: c.getAppData(),
})
if err != nil { // marshaling
panic(err)
}
session.nonce = nonce
var tlsSession tls.ClientSessionState
tlsSessBytes := (*[unsafe.Sizeof(tlsSession)]byte)(unsafe.Pointer(&tlsSession))[:]
copy(tlsSessBytes, sessBytes)
c.ClientSessionCache.Put(sessionKey, &tlsSession)
}