mirror of
https://github.com/XTLS/REALITY.git
synced 2026-10-06 13:58:02 +03:00
crypto/tls: clamp effective minimum version to TLS 1.3 when using QUIC
Change-Id: Ieec72362bacf1956a2bd5e0b2eb8dad88e624bd1 Reviewed-on: https://go-review.googlesource.com/c/go/+/745980 Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
@@ -495,6 +495,9 @@ type ClientHelloInfo struct {
|
||||
// for use with SupportsCertificate.
|
||||
config *Config
|
||||
|
||||
// isQUIC indicates whether the connection is a QUIC connection.
|
||||
isQUIC bool
|
||||
|
||||
// ctx is the context of the handshake that is in progress.
|
||||
ctx context.Context
|
||||
}
|
||||
@@ -1257,7 +1260,7 @@ const roleServer = false
|
||||
|
||||
// supportedVersions returns the list of supported TLS versions, sorted from
|
||||
// highest to lowest (and hence also in preference order).
|
||||
func (c *Config) supportedVersions(isClient bool) []uint16 {
|
||||
func (c *Config) supportedVersions(isClient, isQUIC bool) []uint16 {
|
||||
versions := make([]uint16, 0, len(supportedVersions))
|
||||
for _, v := range supportedVersions {
|
||||
if fips140tls.Required() && !slices.Contains(allowedSupportedVersionsFIPS, v) {
|
||||
@@ -1275,13 +1278,16 @@ func (c *Config) supportedVersions(isClient bool) []uint16 {
|
||||
if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
|
||||
continue
|
||||
}
|
||||
if isQUIC && v < VersionTLS13 {
|
||||
continue
|
||||
}
|
||||
versions = append(versions, v)
|
||||
}
|
||||
return versions
|
||||
}
|
||||
|
||||
func (c *Config) maxSupportedVersion(isClient bool) uint16 {
|
||||
supportedVersions := c.supportedVersions(isClient)
|
||||
func (c *Config) maxSupportedVersion(isClient, isQUIC bool) uint16 {
|
||||
supportedVersions := c.supportedVersions(isClient, isQUIC)
|
||||
if len(supportedVersions) == 0 {
|
||||
return 0
|
||||
}
|
||||
@@ -1333,8 +1339,8 @@ func (c *Config) supportsCurve(version uint16, x CurveID) bool {
|
||||
|
||||
// mutualVersion returns the protocol version to use given the advertised
|
||||
// versions of the peer. The highest supported version is preferred.
|
||||
func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) {
|
||||
supportedVersions := c.supportedVersions(isClient)
|
||||
func (c *Config) mutualVersion(isClient, isQUIC bool, peerVersions []uint16) (uint16, bool) {
|
||||
supportedVersions := c.supportedVersions(isClient, isQUIC)
|
||||
for _, v := range supportedVersions {
|
||||
if slices.Contains(peerVersions, v) {
|
||||
return v, true
|
||||
@@ -1420,7 +1426,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
vers, ok := config.mutualVersion(roleServer, chi.SupportedVersions)
|
||||
vers, ok := config.mutualVersion(roleServer, chi.isQUIC, chi.SupportedVersions)
|
||||
if !ok {
|
||||
return errors.New("no mutually supported protocol versions")
|
||||
}
|
||||
|
||||
+3
-3
@@ -58,7 +58,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
||||
return nil, nil, nil, errors.New("tls: NextProtos values too large")
|
||||
}
|
||||
|
||||
supportedVersions := config.supportedVersions(roleClient)
|
||||
supportedVersions := config.supportedVersions(roleClient, c.quic != nil)
|
||||
if len(supportedVersions) == 0 {
|
||||
return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
// If we are negotiating a protocol version that's lower than what we
|
||||
// support, check for the server downgrade canaries.
|
||||
// See RFC 8446, Section 4.1.3.
|
||||
maxVers := c.config.maxSupportedVersion(roleClient)
|
||||
maxVers := c.config.maxSupportedVersion(roleClient, c.quic != nil)
|
||||
tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
|
||||
tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
|
||||
if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
|
||||
@@ -510,7 +510,7 @@ func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
|
||||
peerVersion = serverHello.supportedVersion
|
||||
}
|
||||
|
||||
vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion})
|
||||
vers, ok := c.config.mutualVersion(roleClient, c.quic != nil, []uint16{peerVersion})
|
||||
if !ok {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion)
|
||||
|
||||
+4
-3
@@ -189,7 +189,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, *echServer
|
||||
} else if len(clientVersions) == 0 {
|
||||
clientVersions = supportedVersionsFromMax(clientHello.vers)
|
||||
}
|
||||
c.vers, ok = c.config.mutualVersion(roleServer, clientVersions)
|
||||
c.vers, ok = c.config.mutualVersion(roleServer, c.quic != nil, clientVersions)
|
||||
if !ok {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return nil, nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
|
||||
@@ -236,7 +236,7 @@ func (hs *serverHandshakeState) processClientHello() error {
|
||||
hs.hello.random = make([]byte, 32)
|
||||
serverRandom := hs.hello.random
|
||||
// Downgrade protection canaries. See RFC 8446, Section 4.1.3.
|
||||
maxVers := c.config.maxSupportedVersion(roleServer)
|
||||
maxVers := c.config.maxSupportedVersion(roleServer, c.quic != nil)
|
||||
if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
|
||||
if c.vers == VersionTLS12 {
|
||||
copy(serverRandom[24:], downgradeCanaryTLS12)
|
||||
@@ -411,7 +411,7 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
|
||||
for _, id := range hs.clientHello.cipherSuites {
|
||||
if id == TLS_FALLBACK_SCSV {
|
||||
// The client is doing a fallback connection. See RFC 7507.
|
||||
if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) {
|
||||
if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer, c.quic != nil) {
|
||||
c.sendAlert(alertInappropriateFallback)
|
||||
return errors.New("tls: client using inappropriate protocol fallback")
|
||||
}
|
||||
@@ -1034,6 +1034,7 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
|
||||
Conn: conn,
|
||||
HelloRetryRequest: c.didHRR,
|
||||
config: c.config,
|
||||
isQUIC: c.quic != nil,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
|
||||
if id == TLS_FALLBACK_SCSV {
|
||||
// Use c.vers instead of max(supported_versions) because an attacker
|
||||
// could defeat this by adding an arbitrary high version otherwise.
|
||||
if c.vers < c.config.maxSupportedVersion(roleServer) {
|
||||
if c.vers < c.config.maxSupportedVersion(roleServer, c.quic != nil) {
|
||||
c.sendAlert(alertInappropriateFallback)
|
||||
return errors.New("tls: client using inappropriate protocol fallback")
|
||||
}
|
||||
|
||||
@@ -185,16 +185,12 @@ type quicState struct {
|
||||
|
||||
// QUICClient returns a new TLS client side connection using QUICTransport as the
|
||||
// underlying transport. The config cannot be nil.
|
||||
//
|
||||
// The config's MinVersion must be at least TLS 1.3.
|
||||
func QUICClient(config *QUICConfig) *QUICConn {
|
||||
return newQUICConn(Client(nil, config.TLSConfig), config)
|
||||
}
|
||||
|
||||
// QUICServer returns a new TLS server side connection using QUICTransport as the
|
||||
// underlying transport. The config cannot be nil.
|
||||
//
|
||||
// The config's MinVersion must be at least TLS 1.3.
|
||||
func QUICServer(config *QUICConfig) *QUICConn {
|
||||
c, _ := Server(context.Background(), nil, config.TLSConfig)
|
||||
return newQUICConn(c, config)
|
||||
@@ -222,9 +218,6 @@ func (q *QUICConn) Start(ctx context.Context) error {
|
||||
return quicError(errors.New("tls: Start called more than once"))
|
||||
}
|
||||
q.conn.quic.started = true
|
||||
if q.conn.config.MinVersion < VersionTLS13 {
|
||||
return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.3"))
|
||||
}
|
||||
go q.conn.HandshakeContext(ctx)
|
||||
if _, ok := <-q.conn.quic.blockedc; !ok {
|
||||
return q.conn.handshakeErr
|
||||
|
||||
Reference in New Issue
Block a user