Skip to content

Commit c21ba09

Browse files
committed
crypto/tls: implement TLS 1.3 server handshake (base)
Implement a basic TLS 1.3 server handshake, only enabled if explicitly requested with MaxVersion. This CL intentionally leaves for future CLs: - PSK modes and resumption - client authentication - compatibility mode ChangeCipherSpecs - early data skipping - post-handshake messages - downgrade protection - KeyLogWriter support - TLS_FALLBACK_SCSV processing It also leaves a few areas up for a wider refactor (maybe in Go 1.13): - the certificate selection logic can be significantly improved, including supporting and surfacing signature_algorithms_cert, but this isn't new in TLS 1.3 (see comment in processClientHello) - handshake_server_tls13.go can be dried up and broken into more meaningful, smaller functions, but it felt premature to do before PSK and client auth support - the monstrous ClientHello equality check in doHelloRetryRequest can get both cleaner and more complete with collaboration from the parsing layer, which can come at the same time as extension duplicates detection Updates #9671 Change-Id: Id9db2b6ecc2eea21bf9b59b6d1d9c84a7435151c Reviewed-on: https://go-review.googlesource.com/c/147017 Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Adam Langley <[email protected]>
1 parent 4caa127 commit c21ba09

19 files changed

+1787
-76
lines changed

src/crypto/tls/auth.go

+33
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package tls
77
import (
88
"crypto"
99
"crypto/ecdsa"
10+
"crypto/elliptic"
1011
"crypto/rsa"
1112
"encoding/asn1"
1213
"errors"
@@ -131,3 +132,35 @@ func writeSignedMessage(sigHash io.Writer, context string, transcript hash.Hash)
131132
io.WriteString(sigHash, context)
132133
sigHash.Write(transcript.Sum(nil))
133134
}
135+
136+
// signatureSchemesForCertificate returns the list of supported SignatureSchemes
137+
// for a given certificate, based on the public key.
138+
func signatureSchemesForCertificate(cert *Certificate) []SignatureScheme {
139+
priv, ok := cert.PrivateKey.(crypto.Signer)
140+
if !ok {
141+
return nil
142+
}
143+
144+
switch priv := priv.Public().(type) {
145+
case *ecdsa.PublicKey:
146+
switch priv.Curve {
147+
case elliptic.P256():
148+
return []SignatureScheme{ECDSAWithP256AndSHA256}
149+
case elliptic.P384():
150+
return []SignatureScheme{ECDSAWithP384AndSHA384}
151+
case elliptic.P521():
152+
return []SignatureScheme{ECDSAWithP521AndSHA512}
153+
default:
154+
return nil
155+
}
156+
case *rsa.PublicKey:
157+
// RSA keys with RSA-PSS OID are not supported by crypto/x509.
158+
return []SignatureScheme{
159+
PSSWithSHA256,
160+
PSSWithSHA384,
161+
PSSWithSHA512,
162+
}
163+
default:
164+
return nil
165+
}
166+
}

src/crypto/tls/common.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ func (c *Config) supportedVersions(isClient bool) []uint16 {
740740
continue
741741
}
742742
// TLS 1.3 is only supported if explicitly requested while in development.
743-
if v == VersionTLS13 && (!isClient || c == nil || c.MaxVersion != VersionTLS13) {
743+
if v == VersionTLS13 && (c == nil || c.MaxVersion != VersionTLS13) {
744744
continue
745745
}
746746
versions = append(versions, v)

src/crypto/tls/handshake_messages.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func (m *clientHelloMsg) marshal() []byte {
131131
})
132132
}
133133
if len(m.supportedCurves) > 0 {
134-
// RFC 4492, Section 5.1.1 and RFC 8446, Section 4.2.7
134+
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
135135
b.AddUint16(extensionSupportedCurves)
136136
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
137137
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
@@ -379,7 +379,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
379379
}
380380
m.ocspStapling = statusType == statusTypeOCSP
381381
case extensionSupportedCurves:
382-
// RFC 4492, Section 5.1.1 and RFC 8446, Section 4.2.7
382+
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
383383
var curves cryptobyte.String
384384
if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() {
385385
return false

src/crypto/tls/handshake_server.go

+87-65
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,19 @@ import (
1919
// serverHandshakeState contains details of a server handshake in progress.
2020
// It's discarded once the handshake has completed.
2121
type serverHandshakeState struct {
22-
c *Conn
23-
clientHello *clientHelloMsg
24-
hello *serverHelloMsg
25-
suite *cipherSuite
26-
ellipticOk bool
27-
ecdsaOk bool
28-
rsaDecryptOk bool
29-
rsaSignOk bool
30-
sessionState *sessionState
31-
finishedHash finishedHash
32-
masterSecret []byte
33-
certsFromClient [][]byte
34-
cert *Certificate
35-
cachedClientHelloInfo *ClientHelloInfo
22+
c *Conn
23+
clientHello *clientHelloMsg
24+
hello *serverHelloMsg
25+
suite *cipherSuite
26+
ellipticOk bool
27+
ecdsaOk bool
28+
rsaDecryptOk bool
29+
rsaSignOk bool
30+
sessionState *sessionState
31+
finishedHash finishedHash
32+
masterSecret []byte
33+
certsFromClient [][]byte
34+
cert *Certificate
3635
}
3736

3837
// serverHandshake performs a TLS handshake as a server.
@@ -41,17 +40,36 @@ func (c *Conn) serverHandshake() error {
4140
// encrypt the tickets with.
4241
c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
4342

43+
clientHello, err := c.readClientHello()
44+
if err != nil {
45+
return err
46+
}
47+
48+
if c.vers == VersionTLS13 {
49+
hs := serverHandshakeStateTLS13{
50+
c: c,
51+
clientHello: clientHello,
52+
}
53+
return hs.handshake()
54+
}
55+
4456
hs := serverHandshakeState{
45-
c: c,
57+
c: c,
58+
clientHello: clientHello,
4659
}
47-
isResume, err := hs.readClientHello()
48-
if err != nil {
60+
return hs.handshake()
61+
}
62+
63+
func (hs *serverHandshakeState) handshake() error {
64+
c := hs.c
65+
66+
if err := hs.processClientHello(); err != nil {
4967
return err
5068
}
5169

5270
// For an overview of TLS handshaking, see RFC 5246, Section 7.3.
5371
c.buffering = true
54-
if isResume {
72+
if hs.checkForResumption() {
5573
// The client has included a session ticket and so we do an abbreviated handshake.
5674
if err := hs.doResumeHandshake(); err != nil {
5775
return err
@@ -81,6 +99,9 @@ func (c *Conn) serverHandshake() error {
8199
} else {
82100
// The client didn't include a session ticket, or it wasn't
83101
// valid so we do a full handshake.
102+
if err := hs.pickCipherSuite(); err != nil {
103+
return err
104+
}
84105
if err := hs.doFullHandshake(); err != nil {
85106
return err
86107
}
@@ -109,42 +130,47 @@ func (c *Conn) serverHandshake() error {
109130
return nil
110131
}
111132

112-
// readClientHello reads a ClientHello message from the client and decides
113-
// whether we will perform session resumption.
114-
func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
115-
c := hs.c
116-
133+
// readClientHello reads a ClientHello message and selects the protocol version.
134+
func (c *Conn) readClientHello() (*clientHelloMsg, error) {
117135
msg, err := c.readHandshake()
118136
if err != nil {
119-
return false, err
137+
return nil, err
120138
}
121-
var ok bool
122-
hs.clientHello, ok = msg.(*clientHelloMsg)
139+
clientHello, ok := msg.(*clientHelloMsg)
123140
if !ok {
124141
c.sendAlert(alertUnexpectedMessage)
125-
return false, unexpectedMessageError(hs.clientHello, msg)
142+
return nil, unexpectedMessageError(clientHello, msg)
126143
}
127144

128145
if c.config.GetConfigForClient != nil {
129-
if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
146+
chi := clientHelloInfo(c, clientHello)
147+
if newConfig, err := c.config.GetConfigForClient(chi); err != nil {
130148
c.sendAlert(alertInternalError)
131-
return false, err
149+
return nil, err
132150
} else if newConfig != nil {
133151
newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
134152
c.config = newConfig
135153
}
136154
}
137155

138-
clientVersions := hs.clientHello.supportedVersions
139-
if len(hs.clientHello.supportedVersions) == 0 {
140-
clientVersions = supportedVersionsFromMax(hs.clientHello.vers)
156+
clientVersions := clientHello.supportedVersions
157+
if len(clientHello.supportedVersions) == 0 {
158+
clientVersions = supportedVersionsFromMax(clientHello.vers)
141159
}
142160
c.vers, ok = c.config.mutualVersion(false, clientVersions)
143161
if !ok {
144162
c.sendAlert(alertProtocolVersion)
145-
return false, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
163+
return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
146164
}
147165
c.haveVers = true
166+
c.in.version = c.vers
167+
c.out.version = c.vers
168+
169+
return clientHello, nil
170+
}
171+
172+
func (hs *serverHandshakeState) processClientHello() error {
173+
c := hs.c
148174

149175
hs.hello = new(serverHelloMsg)
150176
hs.hello.vers = c.vers
@@ -181,19 +207,19 @@ Curves:
181207

182208
if !foundCompression {
183209
c.sendAlert(alertHandshakeFailure)
184-
return false, errors.New("tls: client does not support uncompressed connections")
210+
return errors.New("tls: client does not support uncompressed connections")
185211
}
186212

187213
hs.hello.random = make([]byte, 32)
188-
_, err = io.ReadFull(c.config.rand(), hs.hello.random)
214+
_, err := io.ReadFull(c.config.rand(), hs.hello.random)
189215
if err != nil {
190216
c.sendAlert(alertInternalError)
191-
return false, err
217+
return err
192218
}
193219

194220
if len(hs.clientHello.secureRenegotiation) != 0 {
195221
c.sendAlert(alertHandshakeFailure)
196-
return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
222+
return errors.New("tls: initial handshake had non-empty renegotiation extension")
197223
}
198224

199225
hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
@@ -218,10 +244,10 @@ Curves:
218244
}
219245
}
220246

221-
hs.cert, err = c.config.getCertificate(hs.clientHelloInfo())
247+
hs.cert, err = c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
222248
if err != nil {
223249
c.sendAlert(alertInternalError)
224-
return false, err
250+
return err
225251
}
226252
if hs.clientHello.scts {
227253
hs.hello.scts = hs.cert.SignedCertificateTimestamps
@@ -235,7 +261,7 @@ Curves:
235261
hs.rsaSignOk = true
236262
default:
237263
c.sendAlert(alertInternalError)
238-
return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
264+
return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
239265
}
240266
}
241267
if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
@@ -244,13 +270,15 @@ Curves:
244270
hs.rsaDecryptOk = true
245271
default:
246272
c.sendAlert(alertInternalError)
247-
return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
273+
return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
248274
}
249275
}
250276

251-
if hs.checkForResumption() {
252-
return true, nil
253-
}
277+
return nil
278+
}
279+
280+
func (hs *serverHandshakeState) pickCipherSuite() error {
281+
c := hs.c
254282

255283
var preferenceList, supportedList []uint16
256284
if c.config.PreferServerCipherSuites {
@@ -269,7 +297,7 @@ Curves:
269297

270298
if hs.suite == nil {
271299
c.sendAlert(alertHandshakeFailure)
272-
return false, errors.New("tls: no cipher suite supported by both client and server")
300+
return errors.New("tls: no cipher suite supported by both client and server")
273301
}
274302

275303
// See RFC 7507.
@@ -278,13 +306,13 @@ Curves:
278306
// The client is doing a fallback connection.
279307
if hs.clientHello.vers < c.config.supportedVersions(false)[0] {
280308
c.sendAlert(alertInappropriateFallback)
281-
return false, errors.New("tls: client using inappropriate protocol fallback")
309+
return errors.New("tls: client using inappropriate protocol fallback")
282310
}
283311
break
284312
}
285313
}
286314

287-
return false, nil
315+
return nil
288316
}
289317

290318
// checkForResumption reports whether we should perform resumption on this connection.
@@ -766,26 +794,20 @@ func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites
766794
return false
767795
}
768796

769-
func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
770-
if hs.cachedClientHelloInfo != nil {
771-
return hs.cachedClientHelloInfo
772-
}
773-
774-
supportedVersions := hs.clientHello.supportedVersions
775-
if len(hs.clientHello.supportedVersions) == 0 {
776-
supportedVersions = supportedVersionsFromMax(hs.clientHello.vers)
797+
func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
798+
supportedVersions := clientHello.supportedVersions
799+
if len(clientHello.supportedVersions) == 0 {
800+
supportedVersions = supportedVersionsFromMax(clientHello.vers)
777801
}
778802

779-
hs.cachedClientHelloInfo = &ClientHelloInfo{
780-
CipherSuites: hs.clientHello.cipherSuites,
781-
ServerName: hs.clientHello.serverName,
782-
SupportedCurves: hs.clientHello.supportedCurves,
783-
SupportedPoints: hs.clientHello.supportedPoints,
784-
SignatureSchemes: hs.clientHello.supportedSignatureAlgorithms,
785-
SupportedProtos: hs.clientHello.alpnProtocols,
803+
return &ClientHelloInfo{
804+
CipherSuites: clientHello.cipherSuites,
805+
ServerName: clientHello.serverName,
806+
SupportedCurves: clientHello.supportedCurves,
807+
SupportedPoints: clientHello.supportedPoints,
808+
SignatureSchemes: clientHello.supportedSignatureAlgorithms,
809+
SupportedProtos: clientHello.alpnProtocols,
786810
SupportedVersions: supportedVersions,
787-
Conn: hs.c.conn,
811+
Conn: c.conn,
788812
}
789-
790-
return hs.cachedClientHelloInfo
791813
}

0 commit comments

Comments
 (0)