2018-11-02 00:57:30 -04:00
|
|
|
// Copyright 2018 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package tls
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"crypto"
|
|
|
|
|
"crypto/hmac"
|
|
|
|
|
"crypto/rsa"
|
|
|
|
|
"errors"
|
|
|
|
|
"hash"
|
|
|
|
|
"io"
|
|
|
|
|
"sync/atomic"
|
2018-11-05 15:59:08 -05:00
|
|
|
"time"
|
2018-11-02 00:57:30 -04:00
|
|
|
)
|
|
|
|
|
|
2018-11-05 15:59:08 -05:00
|
|
|
// maxClientPSKIdentities is the number of client PSK identities the server will
|
|
|
|
|
// attempt to validate. It will ignore the rest not to let cheap ClientHello
|
|
|
|
|
// messages cause too much work in session ticket decryption attempts.
|
|
|
|
|
const maxClientPSKIdentities = 5
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
type serverHandshakeStateTLS13 struct {
|
|
|
|
|
c *Conn
|
|
|
|
|
clientHello *clientHelloMsg
|
|
|
|
|
hello *serverHelloMsg
|
2018-11-03 20:04:44 -04:00
|
|
|
sentDummyCCS bool
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
usingPSK bool
|
2018-11-02 00:57:30 -04:00
|
|
|
suite *cipherSuiteTLS13
|
|
|
|
|
cert *Certificate
|
|
|
|
|
sigAlg SignatureScheme
|
2018-11-05 15:59:08 -05:00
|
|
|
earlySecret []byte
|
|
|
|
|
sharedKey []byte
|
2018-11-02 00:57:30 -04:00
|
|
|
handshakeSecret []byte
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
masterSecret []byte
|
2018-11-02 00:57:30 -04:00
|
|
|
trafficSecret []byte // client_application_traffic_secret_0
|
|
|
|
|
transcript hash.Hash
|
2018-11-05 15:59:08 -05:00
|
|
|
clientFinished []byte
|
2018-11-02 00:57:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) handshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
2018-11-14 12:34:38 -05:00
|
|
|
if needFIPS() {
|
|
|
|
|
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
// For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
|
|
|
|
|
if err := hs.processClientHello(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if err := hs.checkForResumption(); err != nil {
|
2018-11-05 15:59:08 -05:00
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if err := hs.pickCertificate(); err != nil {
|
|
|
|
|
return err
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
2018-11-02 00:57:30 -04:00
|
|
|
c.buffering = true
|
|
|
|
|
if err := hs.sendServerParameters(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if err := hs.sendServerCertificate(); err != nil {
|
|
|
|
|
return err
|
2018-11-02 00:57:30 -04:00
|
|
|
}
|
|
|
|
|
if err := hs.sendServerFinished(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-05 15:59:08 -05:00
|
|
|
// Note that at this point we could start sending application data without
|
|
|
|
|
// waiting for the client's second flight, but the application might not
|
|
|
|
|
// expect the lack of replay protection of the ClientHello parameters.
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if _, err := c.flush(); err != nil {
|
2018-11-05 15:59:08 -05:00
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if err := hs.readClientCertificate(); err != nil {
|
2018-11-02 00:57:30 -04:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := hs.readClientFinished(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
atomic.StoreUint32(&c.handshakeStatus, 1)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) processClientHello() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
hs.hello = new(serverHelloMsg)
|
|
|
|
|
|
|
|
|
|
// TLS 1.3 froze the ServerHello.legacy_version field, and uses
|
|
|
|
|
// supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1.
|
|
|
|
|
hs.hello.vers = VersionTLS12
|
|
|
|
|
hs.hello.supportedVersion = c.vers
|
|
|
|
|
|
|
|
|
|
if len(hs.clientHello.supportedVersions) == 0 {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: client used the legacy version field to negotiate TLS 1.3")
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 20:39:45 -05:00
|
|
|
// Abort if the client is doing a fallback and landing lower than what we
|
|
|
|
|
// support. See RFC 7507, which however does not specify the interaction
|
|
|
|
|
// with supported_versions. The only difference is that with
|
|
|
|
|
// supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4]
|
|
|
|
|
// handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case,
|
|
|
|
|
// it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to
|
|
|
|
|
// TLS 1.2, because a TLS 1.3 server would abort here. The situation before
|
|
|
|
|
// supported_versions was not better because there was just no way to do a
|
|
|
|
|
// TLS 1.4 handshake without risking the server selecting TLS 1.3.
|
|
|
|
|
for _, id := range hs.clientHello.cipherSuites {
|
|
|
|
|
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(false) {
|
|
|
|
|
c.sendAlert(alertInappropriateFallback)
|
|
|
|
|
return errors.New("tls: client using inappropriate protocol fallback")
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
if len(hs.clientHello.compressionMethods) != 1 ||
|
|
|
|
|
hs.clientHello.compressionMethods[0] != compressionNone {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: TLS 1.3 client supports illegal compression methods")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.hello.random = make([]byte, 32)
|
|
|
|
|
if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(hs.clientHello.secureRenegotiation) != 0 {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: initial handshake had non-empty renegotiation extension")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hs.clientHello.earlyData {
|
crypto/tls: enable TLS 1.3 and update tests
To disable TLS 1.3, simply remove VersionTLS13 from supportedVersions,
as tested by TestEscapeRoute, and amend documentation. To make it
opt-in, revert the change to (*Config).supportedVersions from this CL.
I did not have the heart to implement the early data skipping feature
when I realized that it did not offer a choice between two
abstraction-breaking options, but demanded them both (look for handshake
type in case of HelloRetryRequest, trial decryption otherwise). It's a
lot of complexity for an apparently small gain, but if anyone has strong
opinions about it let me know.
Note that in TLS 1.3 alerts are encrypted, so the close_notify peeking
to return (n > 0, io.EOF) from Read doesn't work. If we are lucky, those
servers that unexpectedly close connections after serving a single
request will have stopped (maybe thanks to H/2) before they got updated
to TLS 1.3.
Relatedly, session tickets are now provisioned on the client first Read
instead of at Handshake time, because they are, well, post-handshake
messages. If this proves to be a problem we might try to peek at them.
Doubled the tests that cover logic that's different in TLS 1.3.
The benchmarks for TLS 1.2 compared to be0f3c286b5 (before TLS 1.3 and
its refactors, after CL 142817 changed them to use real connections)
show little movement.
name old time/op new time/op delta
HandshakeServer/RSA-8 795µs ± 1% 798µs ± 1% ~ (p=0.057 n=10+18)
HandshakeServer/ECDHE-P256-RSA-8 903µs ± 0% 909µs ± 1% +0.68% (p=0.000 n=8+17)
HandshakeServer/ECDHE-P256-ECDSA-P256-8 198µs ± 0% 204µs ± 1% +3.24% (p=0.000 n=9+18)
HandshakeServer/ECDHE-X25519-ECDSA-P256-8 202µs ± 3% 208µs ± 1% +2.98% (p=0.000 n=9+20)
HandshakeServer/ECDHE-P521-ECDSA-P521-8 15.5ms ± 1% 15.9ms ± 2% +2.49% (p=0.000 n=10+20)
Throughput/MaxPacket/1MB-8 5.81ms ±23% 6.14ms ±44% ~ (p=0.605 n=8+18)
Throughput/MaxPacket/2MB-8 8.91ms ±22% 8.74ms ±33% ~ (p=0.498 n=9+19)
Throughput/MaxPacket/4MB-8 12.8ms ± 3% 14.0ms ±10% +9.74% (p=0.000 n=10+17)
Throughput/MaxPacket/8MB-8 25.1ms ± 7% 24.6ms ±16% ~ (p=0.129 n=9+19)
Throughput/MaxPacket/16MB-8 46.3ms ± 4% 45.9ms ±12% ~ (p=0.340 n=9+20)
Throughput/MaxPacket/32MB-8 88.5ms ± 4% 86.0ms ± 4% -2.82% (p=0.004 n=10+20)
Throughput/MaxPacket/64MB-8 173ms ± 2% 167ms ± 7% -3.42% (p=0.001 n=10+19)
Throughput/DynamicPacket/1MB-8 5.88ms ± 4% 6.59ms ±64% ~ (p=0.232 n=9+18)
Throughput/DynamicPacket/2MB-8 9.08ms ±12% 8.73ms ±21% ~ (p=0.408 n=10+18)
Throughput/DynamicPacket/4MB-8 14.2ms ± 5% 14.0ms ±11% ~ (p=0.188 n=9+19)
Throughput/DynamicPacket/8MB-8 25.1ms ± 6% 24.0ms ± 7% -4.39% (p=0.000 n=10+18)
Throughput/DynamicPacket/16MB-8 45.6ms ± 3% 43.3ms ± 1% -5.22% (p=0.000 n=10+8)
Throughput/DynamicPacket/32MB-8 88.4ms ± 3% 84.8ms ± 2% -4.06% (p=0.000 n=10+10)
Throughput/DynamicPacket/64MB-8 175ms ± 3% 167ms ± 2% -4.63% (p=0.000 n=10+10)
Latency/MaxPacket/200kbps-8 694ms ± 0% 694ms ± 0% -0.02% (p=0.000 n=9+9)
Latency/MaxPacket/500kbps-8 279ms ± 0% 279ms ± 0% -0.09% (p=0.000 n=10+10)
Latency/MaxPacket/1000kbps-8 140ms ± 0% 140ms ± 0% -0.15% (p=0.000 n=10+9)
Latency/MaxPacket/2000kbps-8 71.1ms ± 0% 71.0ms ± 0% -0.09% (p=0.001 n=8+9)
Latency/MaxPacket/5000kbps-8 30.5ms ± 6% 30.1ms ± 6% ~ (p=0.905 n=10+9)
Latency/DynamicPacket/200kbps-8 134ms ± 0% 134ms ± 0% ~ (p=0.796 n=9+9)
Latency/DynamicPacket/500kbps-8 54.8ms ± 0% 54.7ms ± 0% -0.18% (p=0.000 n=8+10)
Latency/DynamicPacket/1000kbps-8 28.5ms ± 0% 29.1ms ± 8% ~ (p=0.173 n=8+10)
Latency/DynamicPacket/2000kbps-8 15.3ms ± 6% 15.9ms ±10% ~ (p=0.905 n=9+10)
Latency/DynamicPacket/5000kbps-8 9.14ms ±21% 9.65ms ±82% ~ (p=0.529 n=10+10)
name old speed new speed delta
Throughput/MaxPacket/1MB-8 175MB/s ±13% 167MB/s ±64% ~ (p=0.646 n=7+20)
Throughput/MaxPacket/2MB-8 241MB/s ±25% 241MB/s ±40% ~ (p=0.660 n=9+20)
Throughput/MaxPacket/4MB-8 328MB/s ± 3% 300MB/s ± 9% -8.70% (p=0.000 n=10+17)
Throughput/MaxPacket/8MB-8 335MB/s ± 7% 340MB/s ±17% ~ (p=0.212 n=9+20)
Throughput/MaxPacket/16MB-8 363MB/s ± 4% 367MB/s ±11% ~ (p=0.340 n=9+20)
Throughput/MaxPacket/32MB-8 379MB/s ± 4% 390MB/s ± 4% +2.93% (p=0.004 n=10+20)
Throughput/MaxPacket/64MB-8 388MB/s ± 2% 401MB/s ± 7% +3.25% (p=0.004 n=10+20)
Throughput/DynamicPacket/1MB-8 178MB/s ± 4% 157MB/s ±73% ~ (p=0.127 n=9+20)
Throughput/DynamicPacket/2MB-8 232MB/s ±11% 243MB/s ±18% ~ (p=0.415 n=10+18)
Throughput/DynamicPacket/4MB-8 296MB/s ± 5% 299MB/s ±15% ~ (p=0.295 n=9+20)
Throughput/DynamicPacket/8MB-8 334MB/s ± 6% 350MB/s ± 7% +4.58% (p=0.000 n=10+18)
Throughput/DynamicPacket/16MB-8 368MB/s ± 3% 388MB/s ± 1% +5.48% (p=0.000 n=10+8)
Throughput/DynamicPacket/32MB-8 380MB/s ± 3% 396MB/s ± 2% +4.20% (p=0.000 n=10+10)
Throughput/DynamicPacket/64MB-8 384MB/s ± 3% 403MB/s ± 2% +4.83% (p=0.000 n=10+10)
Comparing TLS 1.2 and TLS 1.3 at tip shows a slight (~5-10%) slowdown of
handshakes, which might be worth looking at next cycle, but the latency
improvements are expected to overshadow that.
name old time/op new time/op delta
HandshakeServer/ECDHE-P256-RSA-8 909µs ± 1% 963µs ± 0% +5.87% (p=0.000 n=17+18)
HandshakeServer/ECDHE-P256-ECDSA-P256-8 204µs ± 1% 225µs ± 2% +10.20% (p=0.000 n=18+20)
HandshakeServer/ECDHE-X25519-ECDSA-P256-8 208µs ± 1% 230µs ± 2% +10.35% (p=0.000 n=20+18)
HandshakeServer/ECDHE-P521-ECDSA-P521-8 15.9ms ± 2% 15.9ms ± 1% ~ (p=0.444 n=20+19)
Throughput/MaxPacket/1MB-8 6.14ms ±44% 7.07ms ±46% ~ (p=0.057 n=18+19)
Throughput/MaxPacket/2MB-8 8.74ms ±33% 8.61ms ± 9% ~ (p=0.552 n=19+17)
Throughput/MaxPacket/4MB-8 14.0ms ±10% 14.1ms ±12% ~ (p=0.707 n=17+20)
Throughput/MaxPacket/8MB-8 24.6ms ±16% 25.6ms ±14% ~ (p=0.107 n=19+20)
Throughput/MaxPacket/16MB-8 45.9ms ±12% 44.7ms ± 6% ~ (p=0.607 n=20+19)
Throughput/MaxPacket/32MB-8 86.0ms ± 4% 87.9ms ± 8% ~ (p=0.113 n=20+19)
Throughput/MaxPacket/64MB-8 167ms ± 7% 169ms ± 2% +1.26% (p=0.011 n=19+19)
Throughput/DynamicPacket/1MB-8 6.59ms ±64% 6.79ms ±43% ~ (p=0.480 n=18+19)
Throughput/DynamicPacket/2MB-8 8.73ms ±21% 9.58ms ±13% +9.71% (p=0.006 n=18+20)
Throughput/DynamicPacket/4MB-8 14.0ms ±11% 13.9ms ±10% ~ (p=0.687 n=19+20)
Throughput/DynamicPacket/8MB-8 24.0ms ± 7% 24.6ms ± 8% +2.36% (p=0.045 n=18+17)
Throughput/DynamicPacket/16MB-8 43.3ms ± 1% 44.3ms ± 2% +2.48% (p=0.001 n=8+9)
Throughput/DynamicPacket/32MB-8 84.8ms ± 2% 86.7ms ± 2% +2.27% (p=0.000 n=10+10)
Throughput/DynamicPacket/64MB-8 167ms ± 2% 170ms ± 3% +1.89% (p=0.005 n=10+10)
Latency/MaxPacket/200kbps-8 694ms ± 0% 699ms ± 0% +0.65% (p=0.000 n=9+10)
Latency/MaxPacket/500kbps-8 279ms ± 0% 280ms ± 0% +0.68% (p=0.000 n=10+10)
Latency/MaxPacket/1000kbps-8 140ms ± 0% 141ms ± 0% +0.59% (p=0.000 n=9+9)
Latency/MaxPacket/2000kbps-8 71.0ms ± 0% 71.3ms ± 0% +0.42% (p=0.000 n=9+9)
Latency/MaxPacket/5000kbps-8 30.1ms ± 6% 30.7ms ±10% +1.93% (p=0.019 n=9+9)
Latency/DynamicPacket/200kbps-8 134ms ± 0% 138ms ± 0% +3.22% (p=0.000 n=9+10)
Latency/DynamicPacket/500kbps-8 54.7ms ± 0% 56.3ms ± 0% +3.03% (p=0.000 n=10+8)
Latency/DynamicPacket/1000kbps-8 29.1ms ± 8% 29.1ms ± 0% ~ (p=0.173 n=10+8)
Latency/DynamicPacket/2000kbps-8 15.9ms ±10% 16.4ms ±36% ~ (p=0.633 n=10+8)
Latency/DynamicPacket/5000kbps-8 9.65ms ±82% 8.32ms ± 8% ~ (p=0.573 n=10+8)
name old speed new speed delta
Throughput/MaxPacket/1MB-8 167MB/s ±64% 155MB/s ±55% ~ (p=0.224 n=20+19)
Throughput/MaxPacket/2MB-8 241MB/s ±40% 244MB/s ± 9% ~ (p=0.407 n=20+17)
Throughput/MaxPacket/4MB-8 300MB/s ± 9% 298MB/s ±11% ~ (p=0.707 n=17+20)
Throughput/MaxPacket/8MB-8 340MB/s ±17% 330MB/s ±13% ~ (p=0.201 n=20+20)
Throughput/MaxPacket/16MB-8 367MB/s ±11% 375MB/s ± 5% ~ (p=0.607 n=20+19)
Throughput/MaxPacket/32MB-8 390MB/s ± 4% 382MB/s ± 8% ~ (p=0.113 n=20+19)
Throughput/MaxPacket/64MB-8 401MB/s ± 7% 397MB/s ± 2% -0.96% (p=0.030 n=20+19)
Throughput/DynamicPacket/1MB-8 157MB/s ±73% 156MB/s ±39% ~ (p=0.738 n=20+20)
Throughput/DynamicPacket/2MB-8 243MB/s ±18% 220MB/s ±14% -9.65% (p=0.006 n=18+20)
Throughput/DynamicPacket/4MB-8 299MB/s ±15% 303MB/s ± 9% ~ (p=0.512 n=20+20)
Throughput/DynamicPacket/8MB-8 350MB/s ± 7% 342MB/s ± 8% -2.27% (p=0.045 n=18+17)
Throughput/DynamicPacket/16MB-8 388MB/s ± 1% 378MB/s ± 2% -2.41% (p=0.001 n=8+9)
Throughput/DynamicPacket/32MB-8 396MB/s ± 2% 387MB/s ± 2% -2.21% (p=0.000 n=10+10)
Throughput/DynamicPacket/64MB-8 403MB/s ± 2% 396MB/s ± 3% -1.84% (p=0.005 n=10+10)
Fixes #9671
Change-Id: Ieb57c5140eb2c083b8be0d42b240cd2eeec0dcf6
Reviewed-on: https://go-review.googlesource.com/c/147638
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 22:52:51 -05:00
|
|
|
// See RFC 8446, Section 4.2.10 for the complicated behavior required
|
|
|
|
|
// here. The scenario is that a different server at our address offered
|
|
|
|
|
// to accept early data in the past, which we can't handle. For now, all
|
|
|
|
|
// 0-RTT enabled session tickets need to expire before a Go server can
|
|
|
|
|
// replace a server or join a pool. That's the same requirement that
|
|
|
|
|
// applies to mixing or replacing with any TLS 1.2 server.
|
|
|
|
|
c.sendAlert(alertUnsupportedExtension)
|
|
|
|
|
return errors.New("tls: client sent unexpected early data")
|
2018-11-02 00:57:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.hello.sessionId = hs.clientHello.sessionId
|
|
|
|
|
hs.hello.compressionMethod = compressionNone
|
|
|
|
|
|
|
|
|
|
var preferenceList, supportedList []uint16
|
|
|
|
|
if c.config.PreferServerCipherSuites {
|
|
|
|
|
preferenceList = defaultCipherSuitesTLS13()
|
|
|
|
|
supportedList = hs.clientHello.cipherSuites
|
|
|
|
|
} else {
|
|
|
|
|
preferenceList = hs.clientHello.cipherSuites
|
|
|
|
|
supportedList = defaultCipherSuitesTLS13()
|
|
|
|
|
}
|
|
|
|
|
for _, suiteID := range preferenceList {
|
|
|
|
|
hs.suite = mutualCipherSuiteTLS13(supportedList, suiteID)
|
|
|
|
|
if hs.suite != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if hs.suite == nil {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: no cipher suite supported by both client and server")
|
|
|
|
|
}
|
|
|
|
|
c.cipherSuite = hs.suite.id
|
|
|
|
|
hs.hello.cipherSuite = hs.suite.id
|
|
|
|
|
hs.transcript = hs.suite.hash.New()
|
|
|
|
|
|
|
|
|
|
// Pick the ECDHE group in server preference order, but give priority to
|
|
|
|
|
// groups with a key share, to avoid a HelloRetryRequest round-trip.
|
|
|
|
|
var selectedGroup CurveID
|
|
|
|
|
var clientKeyShare *keyShare
|
|
|
|
|
GroupSelection:
|
|
|
|
|
for _, preferredGroup := range c.config.curvePreferences() {
|
|
|
|
|
for _, ks := range hs.clientHello.keyShares {
|
|
|
|
|
if ks.group == preferredGroup {
|
|
|
|
|
selectedGroup = ks.group
|
|
|
|
|
clientKeyShare = &ks
|
|
|
|
|
break GroupSelection
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if selectedGroup != 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for _, group := range hs.clientHello.supportedCurves {
|
|
|
|
|
if group == preferredGroup {
|
|
|
|
|
selectedGroup = group
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if selectedGroup == 0 {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: no ECDHE curve supported by both client and server")
|
|
|
|
|
}
|
|
|
|
|
if clientKeyShare == nil {
|
|
|
|
|
if err := hs.doHelloRetryRequest(selectedGroup); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
clientKeyShare = &hs.clientHello.keyShares[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, ok := curveForCurveID(selectedGroup); selectedGroup != X25519 && !ok {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return errors.New("tls: CurvePreferences includes unsupported curve")
|
|
|
|
|
}
|
|
|
|
|
params, err := generateECDHEParameters(c.config.rand(), selectedGroup)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
hs.hello.serverShare = keyShare{group: selectedGroup, data: params.PublicKey()}
|
2018-11-05 15:59:08 -05:00
|
|
|
hs.sharedKey = params.SharedKey(clientKeyShare.data)
|
|
|
|
|
if hs.sharedKey == nil {
|
2018-11-02 00:57:30 -04:00
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: invalid client key share")
|
|
|
|
|
}
|
2018-11-05 15:59:08 -05:00
|
|
|
|
2018-11-09 22:04:58 -05:00
|
|
|
c.serverName = hs.clientHello.serverName
|
2018-11-05 15:59:08 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
func (hs *serverHandshakeStateTLS13) checkForResumption() error {
|
2018-11-05 15:59:08 -05:00
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
if c.config.SessionTicketsDisabled {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return nil
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
modeOK := false
|
|
|
|
|
for _, mode := range hs.clientHello.pskModes {
|
|
|
|
|
if mode == pskModeDHE {
|
|
|
|
|
modeOK = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !modeOK {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return nil
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return errors.New("tls: invalid or missing PSK binders")
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
if len(hs.clientHello.pskIdentities) == 0 {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return nil
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, identity := range hs.clientHello.pskIdentities {
|
|
|
|
|
if i >= maxClientPSKIdentities {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plaintext, _ := c.decryptTicket(identity.label)
|
|
|
|
|
if plaintext == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
sessionState := new(sessionStateTLS13)
|
|
|
|
|
if ok := sessionState.unmarshal(plaintext); !ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createdAt := time.Unix(int64(sessionState.createdAt), 0)
|
|
|
|
|
if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We don't check the obfuscated ticket age because it's affected by
|
|
|
|
|
// clock skew and it's only a freshness signal useful for shrinking the
|
|
|
|
|
// window for replay attacks, which don't affect us as we don't do 0-RTT.
|
|
|
|
|
|
|
|
|
|
pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite)
|
|
|
|
|
if pskSuite == nil || pskSuite.hash != hs.suite.hash {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PSK connections don't re-establish client certificates, but carry
|
|
|
|
|
// them over in the session ticket. Ensure the presence of client certs
|
|
|
|
|
// in the ticket is consistent with the configured requirements.
|
|
|
|
|
sessionHasClientCerts := len(sessionState.certificate.Certificate) != 0
|
|
|
|
|
needClientCerts := requiresClientCert(c.config.ClientAuth)
|
|
|
|
|
if needClientCerts && !sessionHasClientCerts {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
psk := hs.suite.expandLabel(sessionState.resumptionSecret, "resumption",
|
|
|
|
|
nil, hs.suite.hash.Size())
|
|
|
|
|
hs.earlySecret = hs.suite.extract(psk, nil)
|
|
|
|
|
binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil)
|
|
|
|
|
// Clone the transcript in case a HelloRetryRequest was recorded.
|
|
|
|
|
transcript := cloneHash(hs.transcript, hs.suite.hash)
|
|
|
|
|
if transcript == nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return errors.New("tls: internal error: failed to clone hash")
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
transcript.Write(hs.clientHello.marshalWithoutBinders())
|
|
|
|
|
pskBinder := hs.suite.finishedHash(binderKey, transcript)
|
|
|
|
|
if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
|
|
|
|
|
c.sendAlert(alertDecryptError)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return errors.New("tls: invalid PSK binder")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.processCertsFromClient(sessionState.certificate); err != nil {
|
|
|
|
|
return err
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.hello.selectedIdentityPresent = true
|
|
|
|
|
hs.hello.selectedIdentity = uint16(i)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
hs.usingPSK = true
|
2018-11-05 15:59:08 -05:00
|
|
|
c.didResume = true
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return nil
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
return nil
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
|
|
|
|
|
// interfaces implemented by standard library hashes to clone the state of in
|
|
|
|
|
// to a new instance of h. It returns nil if the operation fails.
|
|
|
|
|
func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash {
|
|
|
|
|
// Recreate the interface to avoid importing encoding.
|
|
|
|
|
type binaryMarshaler interface {
|
|
|
|
|
MarshalBinary() (data []byte, err error)
|
|
|
|
|
UnmarshalBinary(data []byte) error
|
|
|
|
|
}
|
|
|
|
|
marshaler, ok := in.(binaryMarshaler)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
state, err := marshaler.MarshalBinary()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
out := h.New()
|
|
|
|
|
unmarshaler, ok := out.(binaryMarshaler)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if err := unmarshaler.UnmarshalBinary(state); err != nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) pickCertificate() error {
|
|
|
|
|
c := hs.c
|
2018-11-02 00:57:30 -04:00
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// Only one of PSK and certificates are used at a time.
|
|
|
|
|
if hs.usingPSK {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
// This implements a very simplistic certificate selection strategy for now:
|
|
|
|
|
// getCertificate delegates to the application Config.GetCertificate, or
|
|
|
|
|
// selects based on the server_name only. If the selected certificate's
|
|
|
|
|
// public key does not match the client signature_algorithms, the handshake
|
|
|
|
|
// is aborted. No attention is given to signature_algorithms_cert, and it is
|
|
|
|
|
// not passed to the application Config.GetCertificate. This will need to
|
|
|
|
|
// improve according to RFC 8446, sections 4.4.2.2 and 4.2.3.
|
|
|
|
|
certificate, err := c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-29 01:38:07 -05:00
|
|
|
supportedAlgs := signatureSchemesForCertificate(c.vers, certificate)
|
2018-11-02 00:57:30 -04:00
|
|
|
if supportedAlgs == nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
2018-11-29 02:30:26 -05:00
|
|
|
return unsupportedCertificateError(certificate)
|
2018-11-02 00:57:30 -04:00
|
|
|
}
|
|
|
|
|
// Pick signature scheme in client preference order, as the server
|
|
|
|
|
// preference order is not configurable.
|
|
|
|
|
for _, preferredAlg := range hs.clientHello.supportedSignatureAlgorithms {
|
|
|
|
|
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
|
|
|
|
|
hs.sigAlg = preferredAlg
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if hs.sigAlg == 0 {
|
2018-11-29 01:38:07 -05:00
|
|
|
// getCertificate returned a certificate incompatible with the
|
|
|
|
|
// ClientHello supported signature algorithms.
|
2018-11-02 00:57:30 -04:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: client doesn't support selected certificate")
|
|
|
|
|
}
|
|
|
|
|
hs.cert = certificate
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-03 20:04:44 -04:00
|
|
|
// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
|
|
|
|
|
// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
|
|
|
|
if hs.sentDummyCCS {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
hs.sentDummyCCS = true
|
|
|
|
|
|
|
|
|
|
_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
// The first ClientHello gets double-hashed into the transcript upon a
|
|
|
|
|
// HelloRetryRequest. See RFC 8446, Section 4.4.1.
|
|
|
|
|
hs.transcript.Write(hs.clientHello.marshal())
|
|
|
|
|
chHash := hs.transcript.Sum(nil)
|
|
|
|
|
hs.transcript.Reset()
|
|
|
|
|
hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
|
|
|
|
hs.transcript.Write(chHash)
|
|
|
|
|
|
|
|
|
|
helloRetryRequest := &serverHelloMsg{
|
|
|
|
|
vers: hs.hello.vers,
|
|
|
|
|
random: helloRetryRequestRandom,
|
|
|
|
|
sessionId: hs.hello.sessionId,
|
|
|
|
|
cipherSuite: hs.hello.cipherSuite,
|
|
|
|
|
compressionMethod: hs.hello.compressionMethod,
|
|
|
|
|
supportedVersion: hs.hello.supportedVersion,
|
|
|
|
|
selectedGroup: selectedGroup,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(helloRetryRequest.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-03 20:04:44 -04:00
|
|
|
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
msg, err := c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clientHello, ok := msg.(*clientHelloMsg)
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(clientHello, msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: client sent invalid key share in second ClientHello")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if clientHello.earlyData {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: client indicated early data in second ClientHello")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if illegalClientHelloChange(clientHello, hs.clientHello) {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: client illegally modified second ClientHello")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.clientHello = clientHello
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 11:46:44 +01:00
|
|
|
// illegalClientHelloChange reports whether the two ClientHello messages are
|
2018-11-02 00:57:30 -04:00
|
|
|
// different, with the exception of the changes allowed before and after a
|
|
|
|
|
// HelloRetryRequest. See RFC 8446, Section 4.1.2.
|
|
|
|
|
func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
|
|
|
|
|
if len(ch.supportedVersions) != len(ch1.supportedVersions) ||
|
|
|
|
|
len(ch.cipherSuites) != len(ch1.cipherSuites) ||
|
|
|
|
|
len(ch.supportedCurves) != len(ch1.supportedCurves) ||
|
|
|
|
|
len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) ||
|
|
|
|
|
len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) ||
|
|
|
|
|
len(ch.alpnProtocols) != len(ch1.alpnProtocols) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
for i := range ch.supportedVersions {
|
|
|
|
|
if ch.supportedVersions[i] != ch1.supportedVersions[i] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i := range ch.cipherSuites {
|
|
|
|
|
if ch.cipherSuites[i] != ch1.cipherSuites[i] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i := range ch.supportedCurves {
|
|
|
|
|
if ch.supportedCurves[i] != ch1.supportedCurves[i] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i := range ch.supportedSignatureAlgorithms {
|
|
|
|
|
if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i := range ch.supportedSignatureAlgorithmsCert {
|
|
|
|
|
if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i := range ch.alpnProtocols {
|
|
|
|
|
if ch.alpnProtocols[i] != ch1.alpnProtocols[i] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ch.vers != ch1.vers ||
|
|
|
|
|
!bytes.Equal(ch.random, ch1.random) ||
|
|
|
|
|
!bytes.Equal(ch.sessionId, ch1.sessionId) ||
|
|
|
|
|
!bytes.Equal(ch.compressionMethods, ch1.compressionMethods) ||
|
|
|
|
|
ch.nextProtoNeg != ch1.nextProtoNeg ||
|
|
|
|
|
ch.serverName != ch1.serverName ||
|
|
|
|
|
ch.ocspStapling != ch1.ocspStapling ||
|
|
|
|
|
!bytes.Equal(ch.supportedPoints, ch1.supportedPoints) ||
|
|
|
|
|
ch.ticketSupported != ch1.ticketSupported ||
|
|
|
|
|
!bytes.Equal(ch.sessionTicket, ch1.sessionTicket) ||
|
|
|
|
|
ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported ||
|
|
|
|
|
!bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) ||
|
|
|
|
|
ch.scts != ch1.scts ||
|
|
|
|
|
!bytes.Equal(ch.cookie, ch1.cookie) ||
|
|
|
|
|
!bytes.Equal(ch.pskModes, ch1.pskModes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(hs.clientHello.marshal())
|
|
|
|
|
hs.transcript.Write(hs.hello.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-03 20:04:44 -04:00
|
|
|
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 15:59:08 -05:00
|
|
|
earlySecret := hs.earlySecret
|
|
|
|
|
if earlySecret == nil {
|
|
|
|
|
earlySecret = hs.suite.extract(nil, nil)
|
|
|
|
|
}
|
|
|
|
|
hs.handshakeSecret = hs.suite.extract(hs.sharedKey,
|
|
|
|
|
hs.suite.deriveSecret(earlySecret, "derived", nil))
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
|
|
|
|
|
clientHandshakeTrafficLabel, hs.transcript)
|
|
|
|
|
c.in.setTrafficSecret(hs.suite, clientSecret)
|
|
|
|
|
serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
|
|
|
|
|
serverHandshakeTrafficLabel, hs.transcript)
|
|
|
|
|
c.out.setTrafficSecret(hs.suite, serverSecret)
|
|
|
|
|
|
2018-11-03 18:13:05 -04:00
|
|
|
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
encryptedExtensions := new(encryptedExtensionsMsg)
|
|
|
|
|
|
|
|
|
|
if len(hs.clientHello.alpnProtocols) > 0 {
|
|
|
|
|
if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
|
|
|
|
|
encryptedExtensions.alpnProtocol = selectedProto
|
|
|
|
|
c.clientProtocol = selectedProto
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(encryptedExtensions.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
func (hs *serverHandshakeStateTLS13) requestClientCert() bool {
|
|
|
|
|
return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// Only one of PSK and certificates are used at a time.
|
|
|
|
|
if hs.usingPSK {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hs.requestClientCert() {
|
|
|
|
|
// Request a client certificate
|
|
|
|
|
certReq := new(certificateRequestMsgTLS13)
|
|
|
|
|
certReq.ocspStapling = true
|
|
|
|
|
certReq.scts = true
|
2019-02-08 15:36:33 -05:00
|
|
|
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms(VersionTLS13)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
if c.config.ClientCAs != nil {
|
|
|
|
|
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(certReq.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
certMsg := new(certificateMsgTLS13)
|
|
|
|
|
|
|
|
|
|
certMsg.certificate = *hs.cert
|
|
|
|
|
certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
|
|
|
|
|
certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(certMsg.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
certVerifyMsg := new(certificateVerifyMsg)
|
|
|
|
|
certVerifyMsg.hasSignatureAlgorithm = true
|
|
|
|
|
certVerifyMsg.signatureAlgorithm = hs.sigAlg
|
|
|
|
|
|
|
|
|
|
sigType := signatureFromSignatureScheme(hs.sigAlg)
|
|
|
|
|
sigHash, err := hashFromSignatureScheme(hs.sigAlg)
|
|
|
|
|
if sigType == 0 || err != nil {
|
2018-11-29 01:38:07 -05:00
|
|
|
return c.sendAlert(alertInternalError)
|
2018-11-02 00:57:30 -04:00
|
|
|
}
|
|
|
|
|
h := sigHash.New()
|
|
|
|
|
writeSignedMessage(h, serverSignatureContext, hs.transcript)
|
|
|
|
|
|
|
|
|
|
signOpts := crypto.SignerOpts(sigHash)
|
|
|
|
|
if sigType == signatureRSAPSS {
|
|
|
|
|
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
|
|
|
|
}
|
|
|
|
|
sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), h.Sum(nil), signOpts)
|
|
|
|
|
if err != nil {
|
2019-01-18 17:33:49 -05:00
|
|
|
public := hs.cert.PrivateKey.(crypto.Signer).Public()
|
|
|
|
|
if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS &&
|
|
|
|
|
rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
} else {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
}
|
2018-11-02 00:57:30 -04:00
|
|
|
return errors.New("tls: failed to sign handshake: " + err.Error())
|
|
|
|
|
}
|
|
|
|
|
certVerifyMsg.signature = sig
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(certVerifyMsg.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
finished := &finishedMsg{
|
2018-11-04 18:41:37 -05:00
|
|
|
verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
|
2018-11-02 00:57:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(finished.marshal())
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Derive secrets that take context through the server Finished.
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
hs.masterSecret = hs.suite.extract(nil,
|
2018-11-02 00:57:30 -04:00
|
|
|
hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil))
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
|
2018-11-02 00:57:30 -04:00
|
|
|
clientApplicationTrafficLabel, hs.transcript)
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
serverSecret := hs.suite.deriveSecret(hs.masterSecret,
|
2018-11-02 00:57:30 -04:00
|
|
|
serverApplicationTrafficLabel, hs.transcript)
|
|
|
|
|
c.out.setTrafficSecret(hs.suite, serverSecret)
|
|
|
|
|
|
2018-11-03 18:13:05 -04:00
|
|
|
err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
|
2018-11-02 00:57:30 -04:00
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
// If we did not request client certificates, at this point we can
|
|
|
|
|
// precompute the client finished and roll the transcript forward to send
|
|
|
|
|
// session tickets in our first flight.
|
|
|
|
|
if !hs.requestClientCert() {
|
|
|
|
|
if err := hs.sendSessionTickets(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool {
|
|
|
|
|
if hs.c.config.SessionTicketsDisabled {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9.
|
|
|
|
|
for _, pskMode := range hs.clientHello.pskModes {
|
|
|
|
|
if pskMode == pskModeDHE {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
|
|
|
|
|
finishedMsg := &finishedMsg{
|
|
|
|
|
verifyData: hs.clientFinished,
|
|
|
|
|
}
|
|
|
|
|
hs.transcript.Write(finishedMsg.marshal())
|
|
|
|
|
|
2018-11-05 15:59:08 -05:00
|
|
|
if !hs.shouldSendSessionTickets() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
resumptionSecret := hs.suite.deriveSecret(hs.masterSecret,
|
|
|
|
|
resumptionLabel, hs.transcript)
|
|
|
|
|
|
2018-11-05 15:59:08 -05:00
|
|
|
m := new(newSessionTicketMsgTLS13)
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
var certsFromClient [][]byte
|
|
|
|
|
for _, cert := range c.peerCertificates {
|
|
|
|
|
certsFromClient = append(certsFromClient, cert.Raw)
|
|
|
|
|
}
|
2018-11-05 15:59:08 -05:00
|
|
|
state := sessionStateTLS13{
|
|
|
|
|
cipherSuite: hs.suite.id,
|
|
|
|
|
createdAt: uint64(c.config.time().Unix()),
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
resumptionSecret: resumptionSecret,
|
|
|
|
|
certificate: Certificate{
|
|
|
|
|
Certificate: certsFromClient,
|
|
|
|
|
OCSPStaple: c.ocspResponse,
|
|
|
|
|
SignedCertificateTimestamps: c.scts,
|
|
|
|
|
},
|
2018-11-05 15:59:08 -05:00
|
|
|
}
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
var err error
|
2018-11-05 15:59:08 -05:00
|
|
|
m.label, err = c.encryptTicket(state.marshal())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
|
|
|
|
|
|
|
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
if !hs.requestClientCert() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we requested a client certificate, then the client must send a
|
|
|
|
|
// certificate message. If it's empty, no CertificateVerify is sent.
|
|
|
|
|
|
|
|
|
|
msg, err := c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
certMsg, ok := msg.(*certificateMsgTLS13)
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(certMsg, msg)
|
|
|
|
|
}
|
|
|
|
|
hs.transcript.Write(certMsg.marshal())
|
|
|
|
|
|
|
|
|
|
if err := c.processCertsFromClient(certMsg.certificate); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(certMsg.certificate.Certificate) != 0 {
|
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
certVerify, ok := msg.(*certificateVerifyMsg)
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(certVerify, msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// See RFC 8446, Section 4.4.3.
|
2019-02-08 15:36:33 -05:00
|
|
|
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms(VersionTLS13)) {
|
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2
are now filtered by the requested certificate type. This feels like an
improvement anyway, and the full list can be surfaced as well when
support for signature_algorithms_cert is added, which actually matches
the semantics of the CertificateRequest signature_algorithms in TLS 1.2.
Also, note a subtle behavior change in server side resumption: if a
certificate is requested but not required, and the resumed session did
not include one, it used not to invoke VerifyPeerCertificate. However,
if the resumed session did include a certificate, it would. (If a
certificate was required but not in the session, the session is rejected
in checkForResumption.) This inconsistency could be unexpected, even
dangerous, so now VerifyPeerCertificate is always invoked. Still not
consistent with the client behavior, which does not ever invoke
VerifyPeerCertificate on resumption, but it felt too surprising to
entirely change either.
Updates #9671
Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf
Reviewed-on: https://go-review.googlesource.com/c/147599
Reviewed-by: Adam Langley <agl@golang.org>
2018-11-05 19:23:25 -05:00
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: invalid certificate signature algorithm")
|
|
|
|
|
}
|
|
|
|
|
sigType := signatureFromSignatureScheme(certVerify.signatureAlgorithm)
|
|
|
|
|
sigHash, err := hashFromSignatureScheme(certVerify.signatureAlgorithm)
|
|
|
|
|
if sigType == 0 || err != nil {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: invalid certificate signature algorithm")
|
|
|
|
|
}
|
|
|
|
|
h := sigHash.New()
|
|
|
|
|
writeSignedMessage(h, clientSignatureContext, hs.transcript)
|
|
|
|
|
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
|
|
|
|
|
sigHash, h.Sum(nil), certVerify.signature); err != nil {
|
|
|
|
|
c.sendAlert(alertDecryptError)
|
|
|
|
|
return errors.New("tls: invalid certificate signature")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.transcript.Write(certVerify.marshal())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we waited until the client certificates to send session tickets, we
|
|
|
|
|
// are ready to do it now.
|
|
|
|
|
if err := hs.sendSessionTickets(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
func (hs *serverHandshakeStateTLS13) readClientFinished() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
msg, err := c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
finished, ok := msg.(*finishedMsg)
|
|
|
|
|
if !ok {
|
|
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(finished, msg)
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 15:59:08 -05:00
|
|
|
if !hmac.Equal(hs.clientFinished, finished.verifyData) {
|
2018-11-02 00:57:30 -04:00
|
|
|
c.sendAlert(alertDecryptError)
|
|
|
|
|
return errors.New("tls: invalid client finished hash")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.in.setTrafficSecret(hs.suite, hs.trafficSecret)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|