uquic/internal/handshake/qtls.go
2020-01-30 09:12:31 +07:00

123 lines
4 KiB
Go

package handshake
import (
"crypto/tls"
"net"
"time"
"github.com/marten-seemann/qtls"
)
type conn struct {
remoteAddr net.Addr
}
func newConn(remote net.Addr) net.Conn {
return &conn{remoteAddr: remote}
}
var _ net.Conn = &conn{}
func (c *conn) Read([]byte) (int, error) { return 0, nil }
func (c *conn) Write([]byte) (int, error) { return 0, nil }
func (c *conn) Close() error { return nil }
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
func (c *conn) LocalAddr() net.Addr { return nil }
func (c *conn) SetReadDeadline(time.Time) error { return nil }
func (c *conn) SetWriteDeadline(time.Time) error { return nil }
func (c *conn) SetDeadline(time.Time) error { return nil }
func tlsConfigToQtlsConfig(
c *tls.Config,
recordLayer qtls.RecordLayer,
extHandler tlsExtensionHandler,
getDataForSessionState func() []byte,
setDataFromSessionState func([]byte),
accept0RTT func([]byte) bool,
rejected0RTT func(),
enable0RTT bool,
) *qtls.Config {
if c == nil {
c = &tls.Config{}
}
// Clone the config first. This executes the tls.Config.serverInit().
// This sets the SessionTicketKey, if the user didn't supply one.
c = c.Clone()
// QUIC requires TLS 1.3 or newer
minVersion := c.MinVersion
if minVersion < qtls.VersionTLS13 {
minVersion = qtls.VersionTLS13
}
maxVersion := c.MaxVersion
if maxVersion < qtls.VersionTLS13 {
maxVersion = qtls.VersionTLS13
}
var getConfigForClient func(ch *tls.ClientHelloInfo) (*qtls.Config, error)
if c.GetConfigForClient != nil {
getConfigForClient = func(ch *tls.ClientHelloInfo) (*qtls.Config, error) {
tlsConf, err := c.GetConfigForClient(ch)
if err != nil {
return nil, err
}
if tlsConf == nil {
return nil, nil
}
return tlsConfigToQtlsConfig(tlsConf, recordLayer, extHandler, getDataForSessionState, setDataFromSessionState, accept0RTT, rejected0RTT, enable0RTT), nil
}
}
var csc qtls.ClientSessionCache
if c.ClientSessionCache != nil {
csc = newClientSessionCache(c.ClientSessionCache, getDataForSessionState, setDataFromSessionState)
}
conf := &qtls.Config{
Rand: c.Rand,
Time: c.Time,
Certificates: c.Certificates,
NameToCertificate: c.NameToCertificate,
GetCertificate: c.GetCertificate,
GetClientCertificate: c.GetClientCertificate,
GetConfigForClient: getConfigForClient,
VerifyPeerCertificate: c.VerifyPeerCertificate,
RootCAs: c.RootCAs,
NextProtos: c.NextProtos,
EnforceNextProtoSelection: true,
ServerName: c.ServerName,
ClientAuth: c.ClientAuth,
ClientCAs: c.ClientCAs,
InsecureSkipVerify: c.InsecureSkipVerify,
CipherSuites: c.CipherSuites,
PreferServerCipherSuites: c.PreferServerCipherSuites,
SessionTicketsDisabled: c.SessionTicketsDisabled,
SessionTicketKey: c.SessionTicketKey,
ClientSessionCache: csc,
MinVersion: minVersion,
MaxVersion: maxVersion,
CurvePreferences: c.CurvePreferences,
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
// no need to copy Renegotiation, it's not supported by TLS 1.3
KeyLogWriter: c.KeyLogWriter,
AlternativeRecordLayer: recordLayer,
GetExtensions: extHandler.GetExtensions,
ReceivedExtensions: extHandler.ReceivedExtensions,
Accept0RTT: accept0RTT,
Rejected0RTT: rejected0RTT,
}
if enable0RTT {
conf.Enable0RTT = true
conf.MaxEarlyData = 0xffffffff
}
return conf
}
func cipherSuiteName(id uint16) string {
switch id {
case qtls.TLS_AES_128_GCM_SHA256:
return "TLS_AES_128_GCM_SHA256"
case qtls.TLS_CHACHA20_POLY1305_SHA256:
return "TLS_CHACHA20_POLY1305_SHA256"
case qtls.TLS_AES_256_GCM_SHA384:
return "TLS_AES_256_GCM_SHA384"
default:
return "unknown cipher suite"
}
}