crypto/tls: expand ClientHelloInfo

Fixes #17430

Change-Id: Ia1c25363d64e3091455ce00644438715aff30a0d
Reviewed-on: https://go-review.googlesource.com/31391
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Filippo Valsorda <hi@filippo.io>
This commit is contained in:
Filippo Valsorda 2016-10-19 15:21:54 +02:00 committed by Adam Langley
parent 5dbe3480aa
commit b189f06b5c
2 changed files with 77 additions and 22 deletions

View File

@ -14,6 +14,7 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"net"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -238,6 +239,32 @@ type ClientHelloInfo struct {
// is being used (see // is being used (see
// http://tools.ietf.org/html/rfc4492#section-5.1.2). // http://tools.ietf.org/html/rfc4492#section-5.1.2).
SupportedPoints []uint8 SupportedPoints []uint8
// SignatureSchemes lists the signature and hash schemes that the client
// is willing to verify. SignatureSchemes is set only if the Signature
// Algorithms Extension is being used (see
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1).
SignatureSchemes []uint16
// SupportedProtos lists the application protocols supported by the client.
// SupportedProtos is set only if the Application-Layer Protocol
// Negotiation Extension is being used (see
// https://tools.ietf.org/html/rfc7301#section-3.1).
//
// Servers can select a protocol by setting Config.NextProtos in a
// GetConfigForClient return value.
SupportedProtos []string
// SupportedVersions lists the TLS versions supported by the client.
// For TLS versions less than 1.3, this is extrapolated from the max
// version advertised by the client, so values other than the greatest
// might be rejected if used.
SupportedVersions []uint16
// Conn is the underlying net.Conn for the connection. Do not read
// from, or write to, this connection; that will cause the TLS
// connection to fail.
Conn net.Conn
} }
// RenegotiationSupport enumerates the different levels of support for TLS // RenegotiationSupport enumerates the different levels of support for TLS

View File

@ -19,19 +19,20 @@ import (
// serverHandshakeState contains details of a server handshake in progress. // serverHandshakeState contains details of a server handshake in progress.
// It's discarded once the handshake has completed. // It's discarded once the handshake has completed.
type serverHandshakeState struct { type serverHandshakeState struct {
c *Conn c *Conn
clientHello *clientHelloMsg clientHello *clientHelloMsg
hello *serverHelloMsg hello *serverHelloMsg
suite *cipherSuite suite *cipherSuite
ellipticOk bool ellipticOk bool
ecdsaOk bool ecdsaOk bool
rsaDecryptOk bool rsaDecryptOk bool
rsaSignOk bool rsaSignOk bool
sessionState *sessionState sessionState *sessionState
finishedHash finishedHash finishedHash finishedHash
masterSecret []byte masterSecret []byte
certsFromClient [][]byte certsFromClient [][]byte
cert *Certificate cert *Certificate
cachedClientHelloInfo *ClientHelloInfo
} }
// serverHandshake performs a TLS handshake as a server. // serverHandshake performs a TLS handshake as a server.
@ -123,15 +124,8 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
return false, unexpectedMessageError(hs.clientHello, msg) return false, unexpectedMessageError(hs.clientHello, msg)
} }
clientHelloInfo := &ClientHelloInfo{
CipherSuites: hs.clientHello.cipherSuites,
ServerName: hs.clientHello.serverName,
SupportedCurves: hs.clientHello.supportedCurves,
SupportedPoints: hs.clientHello.supportedPoints,
}
if c.config.GetConfigForClient != nil { if c.config.GetConfigForClient != nil {
if newConfig, err := c.config.GetConfigForClient(clientHelloInfo); err != nil { if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
c.sendAlert(alertInternalError) c.sendAlert(alertInternalError)
return false, err return false, err
} else if newConfig != nil { } else if newConfig != nil {
@ -223,7 +217,7 @@ Curves:
} }
} }
hs.cert, err = c.config.getCertificate(clientHelloInfo) hs.cert, err = c.config.getCertificate(hs.clientHelloInfo())
if err != nil { if err != nil {
c.sendAlert(alertInternalError) c.sendAlert(alertInternalError)
return false, err return false, err
@ -812,3 +806,37 @@ func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites
} }
return false return false
} }
// suppVersArray is the backing array of ClientHelloInfo.SupportedVersions
var suppVersArray = [...]uint16{VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
if hs.cachedClientHelloInfo != nil {
return hs.cachedClientHelloInfo
}
var supportedVersions []uint16
if hs.clientHello.vers > VersionTLS12 {
supportedVersions = suppVersArray[:]
} else if hs.clientHello.vers >= VersionSSL30 {
supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:]
}
signatureSchemes := make([]uint16, 0, len(hs.clientHello.signatureAndHashes))
for _, sah := range hs.clientHello.signatureAndHashes {
signatureSchemes = append(signatureSchemes, uint16(sah.hash)<<8+uint16(sah.signature))
}
hs.cachedClientHelloInfo = &ClientHelloInfo{
CipherSuites: hs.clientHello.cipherSuites,
ServerName: hs.clientHello.serverName,
SupportedCurves: hs.clientHello.supportedCurves,
SupportedPoints: hs.clientHello.supportedPoints,
SignatureSchemes: signatureSchemes,
SupportedProtos: hs.clientHello.alpnProtocols,
SupportedVersions: supportedVersions,
Conn: hs.c.conn,
}
return hs.cachedClientHelloInfo
}