2009-11-05 15:44:32 -08:00
|
|
|
// Copyright 2009 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 (
|
2013-07-17 12:33:16 -04:00
|
|
|
"crypto"
|
|
|
|
|
"crypto/ecdsa"
|
2019-05-16 19:13:29 -04:00
|
|
|
"crypto/ed25519"
|
2009-12-15 15:33:31 -08:00
|
|
|
"crypto/rsa"
|
|
|
|
|
"crypto/subtle"
|
2010-08-16 11:22:22 -04:00
|
|
|
"crypto/x509"
|
2011-11-01 22:04:37 -04:00
|
|
|
"errors"
|
2014-02-12 11:20:01 -05:00
|
|
|
"fmt"
|
2009-12-15 15:33:31 -08:00
|
|
|
"io"
|
2018-01-26 09:17:46 +00:00
|
|
|
"sync/atomic"
|
2009-11-05 15:44:32 -08:00
|
|
|
)
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
// serverHandshakeState contains details of a server handshake in progress.
|
|
|
|
|
// It's discarded once the handshake has completed.
|
|
|
|
|
type serverHandshakeState struct {
|
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 *Conn
|
|
|
|
|
clientHello *clientHelloMsg
|
|
|
|
|
hello *serverHelloMsg
|
|
|
|
|
suite *cipherSuite
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
ecdheOk bool
|
2019-05-16 19:13:29 -04:00
|
|
|
ecSignOk 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
|
|
|
rsaDecryptOk bool
|
|
|
|
|
rsaSignOk bool
|
|
|
|
|
sessionState *sessionState
|
|
|
|
|
finishedHash finishedHash
|
|
|
|
|
masterSecret []byte
|
|
|
|
|
cert *Certificate
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// serverHandshake performs a TLS handshake as a server.
|
2011-11-01 22:04:37 -04:00
|
|
|
func (c *Conn) serverHandshake() error {
|
2012-09-24 16:52:43 -04:00
|
|
|
// If this is the first server handshake, we generate a random key to
|
|
|
|
|
// encrypt the tickets with.
|
2017-04-28 13:37:52 -07:00
|
|
|
c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
|
2012-09-24 16:52:43 -04:00
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
clientHello, err := c.readClientHello()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c.vers == VersionTLS13 {
|
|
|
|
|
hs := serverHandshakeStateTLS13{
|
|
|
|
|
c: c,
|
|
|
|
|
clientHello: clientHello,
|
|
|
|
|
}
|
|
|
|
|
return hs.handshake()
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
hs := serverHandshakeState{
|
2018-11-02 00:57:30 -04:00
|
|
|
c: c,
|
|
|
|
|
clientHello: clientHello,
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
2018-11-02 00:57:30 -04:00
|
|
|
return hs.handshake()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) handshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
if err := hs.processClientHello(); err != nil {
|
2010-04-26 22:19:04 -07:00
|
|
|
return err
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
|
2018-10-12 17:07:04 -04:00
|
|
|
// For an overview of TLS handshaking, see RFC 5246, Section 7.3.
|
2016-06-01 14:41:09 -07:00
|
|
|
c.buffering = true
|
2018-11-02 00:57:30 -04:00
|
|
|
if hs.checkForResumption() {
|
2012-09-24 16:52:43 -04:00
|
|
|
// The client has included a session ticket and so we do an abbreviated handshake.
|
|
|
|
|
if err := hs.doResumeHandshake(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := hs.establishKeys(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2015-04-17 21:32:11 -04:00
|
|
|
// ticketSupported is set in a resumption handshake if the
|
|
|
|
|
// ticket from the client was encrypted with an old session
|
|
|
|
|
// ticket key and thus a refreshed ticket should be sent.
|
|
|
|
|
if hs.hello.ticketSupported {
|
|
|
|
|
if err := hs.sendSessionTicket(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
return err
|
|
|
|
|
}
|
2016-06-01 14:41:09 -07:00
|
|
|
if _, err := c.flush(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
c.clientFinishedIsFirst = false
|
2014-08-11 16:40:42 -07:00
|
|
|
if err := hs.readFinished(nil); err != nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
c.didResume = true
|
|
|
|
|
} else {
|
|
|
|
|
// The client didn't include a session ticket, or it wasn't
|
|
|
|
|
// valid so we do a full handshake.
|
2018-11-02 00:57:30 -04:00
|
|
|
if err := hs.pickCipherSuite(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
if err := hs.doFullHandshake(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := hs.establishKeys(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
if err := hs.readFinished(c.clientFinished[:]); err != nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
return err
|
|
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
c.clientFinishedIsFirst = true
|
2016-06-01 14:41:09 -07:00
|
|
|
c.buffering = true
|
2012-09-24 16:52:43 -04:00
|
|
|
if err := hs.sendSessionTicket(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2014-08-11 16:40:42 -07:00
|
|
|
if err := hs.sendFinished(nil); err != nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
return err
|
|
|
|
|
}
|
2016-06-01 14:41:09 -07:00
|
|
|
if _, err := c.flush(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
2017-12-20 19:47:49 -08:00
|
|
|
|
|
|
|
|
c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
|
2018-01-26 09:17:46 +00:00
|
|
|
atomic.StoreUint32(&c.handshakeStatus, 1)
|
2012-09-24 16:52:43 -04:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
// readClientHello reads a ClientHello message and selects the protocol version.
|
|
|
|
|
func (c *Conn) readClientHello() (*clientHelloMsg, error) {
|
2012-09-24 16:52:43 -04:00
|
|
|
msg, err := c.readHandshake()
|
|
|
|
|
if err != nil {
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil, err
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
2018-11-02 00:57:30 -04:00
|
|
|
clientHello, ok := msg.(*clientHelloMsg)
|
2009-11-05 15:44:32 -08:00
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil, unexpectedMessageError(clientHello, msg)
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
2016-10-10 15:27:34 -07:00
|
|
|
|
|
|
|
|
if c.config.GetConfigForClient != nil {
|
2018-11-02 00:57:30 -04:00
|
|
|
chi := clientHelloInfo(c, clientHello)
|
|
|
|
|
if newConfig, err := c.config.GetConfigForClient(chi); err != nil {
|
2016-10-10 15:27:34 -07:00
|
|
|
c.sendAlert(alertInternalError)
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil, err
|
2016-10-10 15:27:34 -07:00
|
|
|
} else if newConfig != nil {
|
2017-04-28 13:37:52 -07:00
|
|
|
newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
|
2016-10-10 15:27:34 -07:00
|
|
|
c.config = newConfig
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
clientVersions := clientHello.supportedVersions
|
|
|
|
|
if len(clientHello.supportedVersions) == 0 {
|
|
|
|
|
clientVersions = supportedVersionsFromMax(clientHello.vers)
|
2018-10-31 09:34:10 -04:00
|
|
|
}
|
2019-08-27 17:27:45 -04:00
|
|
|
c.vers, ok = c.config.mutualVersion(clientVersions)
|
2009-11-05 15:44:32 -08:00
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertProtocolVersion)
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
2010-04-26 22:19:04 -07:00
|
|
|
c.haveVers = true
|
2018-11-02 00:57:30 -04:00
|
|
|
c.in.version = c.vers
|
|
|
|
|
c.out.version = c.vers
|
|
|
|
|
|
|
|
|
|
return clientHello, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) processClientHello() error {
|
|
|
|
|
c := hs.c
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.hello = new(serverHelloMsg)
|
2018-10-31 09:34:10 -04:00
|
|
|
hs.hello.vers = c.vers
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
foundCompression := false
|
2009-11-05 15:44:32 -08:00
|
|
|
// We only support null compression, so check that the client offered it.
|
2012-09-24 16:52:43 -04:00
|
|
|
for _, compression := range hs.clientHello.compressionMethods {
|
2009-11-05 15:44:32 -08:00
|
|
|
if compression == compressionNone {
|
2009-12-15 15:33:31 -08:00
|
|
|
foundCompression = true
|
|
|
|
|
break
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
if !foundCompression {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
2018-11-02 00:57:30 -04:00
|
|
|
return errors.New("tls: client does not support uncompressed connections")
|
2009-12-15 15:33:31 -08:00
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.hello.random = make([]byte, 32)
|
2018-11-05 20:39:45 -05:00
|
|
|
serverRandom := hs.hello.random
|
|
|
|
|
// Downgrade protection canaries. See RFC 8446, Section 4.1.3.
|
2019-08-27 17:27:45 -04:00
|
|
|
maxVers := c.config.maxSupportedVersion()
|
2018-11-05 20:39:45 -05:00
|
|
|
if maxVers >= VersionTLS12 && c.vers < maxVers {
|
|
|
|
|
if c.vers == VersionTLS12 {
|
|
|
|
|
copy(serverRandom[24:], downgradeCanaryTLS12)
|
|
|
|
|
} else {
|
|
|
|
|
copy(serverRandom[24:], downgradeCanaryTLS11)
|
|
|
|
|
}
|
|
|
|
|
serverRandom = serverRandom[:24]
|
|
|
|
|
}
|
|
|
|
|
_, err := io.ReadFull(c.config.rand(), serverRandom)
|
2009-11-05 15:44:32 -08:00
|
|
|
if err != nil {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertInternalError)
|
2018-11-02 00:57:30 -04:00
|
|
|
return err
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
2016-04-26 10:45:35 -07:00
|
|
|
|
|
|
|
|
if len(hs.clientHello.secureRenegotiation) != 0 {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
2018-11-02 00:57:30 -04:00
|
|
|
return errors.New("tls: initial handshake had non-empty renegotiation extension")
|
2016-04-26 10:45:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.hello.compressionMethod = compressionNone
|
|
|
|
|
if len(hs.clientHello.serverName) > 0 {
|
|
|
|
|
c.serverName = hs.clientHello.serverName
|
|
|
|
|
}
|
2014-08-05 11:36:20 -07:00
|
|
|
|
|
|
|
|
if len(hs.clientHello.alpnProtocols) > 0 {
|
|
|
|
|
if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
|
|
|
|
|
hs.hello.alpnProtocol = selectedProto
|
|
|
|
|
c.clientProtocol = selectedProto
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
hs.cert, err = c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
|
2016-03-14 03:35:13 -06:00
|
|
|
if err != nil {
|
crypto/tls: select only compatible chains from Certificates
Now that we have a full implementation of the logic to check certificate
compatibility, we can let applications just list multiple chains in
Certificates (for example, an RSA and an ECDSA one) and choose the most
appropriate automatically.
NameToCertificate only maps each name to one chain, so simply deprecate
it, and while at it simplify its implementation by not stripping
trailing dots from the SNI (which is specified not to have any, see RFC
6066, Section 3) and by not supporting multi-level wildcards, which are
not a thing in the WebPKI (and in crypto/x509).
The performance of SupportsCertificate without Leaf is poor, but doesn't
affect current users. For now document that, and address it properly in
the next cycle. See #35504.
While cleaning up the Certificates/GetCertificate/GetConfigForClient
behavior, also support leaving Certificates/GetCertificate nil if
GetConfigForClient is set, and send unrecognized_name when there are no
available certificates.
Fixes #29139
Fixes #18377
Change-Id: I26604db48806fe4d608388e55da52f34b7ca4566
Reviewed-on: https://go-review.googlesource.com/c/go/+/205059
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-02 14:43:34 -04:00
|
|
|
if err == errNoCertificates {
|
|
|
|
|
c.sendAlert(alertUnrecognizedName)
|
|
|
|
|
} else {
|
|
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
}
|
2018-11-02 00:57:30 -04:00
|
|
|
return err
|
2013-09-17 13:30:36 -04:00
|
|
|
}
|
2015-04-16 14:59:22 -04:00
|
|
|
if hs.clientHello.scts {
|
|
|
|
|
hs.hello.scts = hs.cert.SignedCertificateTimestamps
|
|
|
|
|
}
|
2013-09-17 13:30:36 -04:00
|
|
|
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints)
|
|
|
|
|
|
|
|
|
|
if hs.ecdheOk {
|
|
|
|
|
// Although omiting the ec_point_formats extension is permitted, some
|
|
|
|
|
// old OpenSSL version will refuse to handshake if not present.
|
|
|
|
|
//
|
|
|
|
|
// Per RFC 4492, section 5.1.2, implementations MUST support the
|
|
|
|
|
// uncompressed point format. See golang.org/issue/31943.
|
|
|
|
|
hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 04:01:57 -07:00
|
|
|
if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
|
|
|
|
|
switch priv.Public().(type) {
|
|
|
|
|
case *ecdsa.PublicKey:
|
2019-05-16 19:13:29 -04:00
|
|
|
hs.ecSignOk = true
|
|
|
|
|
case ed25519.PublicKey:
|
|
|
|
|
hs.ecSignOk = true
|
2015-03-19 04:01:57 -07:00
|
|
|
case *rsa.PublicKey:
|
2015-04-02 16:19:46 -07:00
|
|
|
hs.rsaSignOk = true
|
2015-03-19 04:01:57 -07:00
|
|
|
default:
|
|
|
|
|
c.sendAlert(alertInternalError)
|
2018-11-02 00:57:30 -04:00
|
|
|
return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
|
2015-03-19 04:01:57 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
|
|
|
|
|
switch priv.Public().(type) {
|
|
|
|
|
case *rsa.PublicKey:
|
2015-04-02 16:19:46 -07:00
|
|
|
hs.rsaDecryptOk = true
|
2015-03-19 04:01:57 -07:00
|
|
|
default:
|
|
|
|
|
c.sendAlert(alertInternalError)
|
2018-11-02 00:57:30 -04:00
|
|
|
return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
|
2015-03-19 04:01:57 -07:00
|
|
|
}
|
|
|
|
|
}
|
2013-09-17 13:30:36 -04:00
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
// supportsECDHE returns whether ECDHE key exchanges can be used with this
|
|
|
|
|
// pre-TLS 1.3 client.
|
|
|
|
|
func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool {
|
|
|
|
|
supportsCurve := false
|
|
|
|
|
for _, curve := range supportedCurves {
|
|
|
|
|
if c.supportsCurve(curve) {
|
|
|
|
|
supportsCurve = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
supportsPointFormat := false
|
|
|
|
|
for _, pointFormat := range supportedPoints {
|
|
|
|
|
if pointFormat == pointFormatUncompressed {
|
|
|
|
|
supportsPointFormat = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return supportsCurve && supportsPointFormat
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
func (hs *serverHandshakeState) pickCipherSuite() error {
|
|
|
|
|
c := hs.c
|
2012-09-24 16:52:43 -04:00
|
|
|
|
2013-01-22 10:10:38 -05:00
|
|
|
var preferenceList, supportedList []uint16
|
|
|
|
|
if c.config.PreferServerCipherSuites {
|
|
|
|
|
preferenceList = c.config.cipherSuites()
|
|
|
|
|
supportedList = hs.clientHello.cipherSuites
|
|
|
|
|
} else {
|
|
|
|
|
preferenceList = hs.clientHello.cipherSuites
|
|
|
|
|
supportedList = c.config.cipherSuites()
|
|
|
|
|
}
|
|
|
|
|
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
hs.suite = selectCipherSuite(preferenceList, supportedList, hs.cipherSuiteOk)
|
2012-09-24 16:52:43 -04:00
|
|
|
if hs.suite == nil {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
2018-11-02 00:57:30 -04:00
|
|
|
return errors.New("tls: no cipher suite supported by both client and server")
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
2014-10-15 17:54:04 -07:00
|
|
|
for _, id := range hs.clientHello.cipherSuites {
|
|
|
|
|
if id == TLS_FALLBACK_SCSV {
|
2018-11-05 20:39:45 -05:00
|
|
|
// The client is doing a fallback connection. See RFC 7507.
|
2019-08-27 17:27:45 -04:00
|
|
|
if hs.clientHello.vers < c.config.maxSupportedVersion() {
|
2014-10-15 17:54:04 -07:00
|
|
|
c.sendAlert(alertInappropriateFallback)
|
2018-11-02 00:57:30 -04:00
|
|
|
return errors.New("tls: client using inappropriate protocol fallback")
|
2014-10-15 17:54:04 -07:00
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
return nil
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool {
|
|
|
|
|
if c.flags&suiteECDHE != 0 {
|
|
|
|
|
if !hs.ecdheOk {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if c.flags&suiteECSign != 0 {
|
|
|
|
|
if !hs.ecSignOk {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
} else if !hs.rsaSignOk {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
} else if !hs.rsaDecryptOk {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 15:44:42 -08:00
|
|
|
// checkForResumption reports whether we should perform resumption on this connection.
|
2012-09-24 16:52:43 -04:00
|
|
|
func (hs *serverHandshakeState) checkForResumption() bool {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
2014-09-26 11:02:09 +10:00
|
|
|
if c.config.SessionTicketsDisabled {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 15:59:08 -05:00
|
|
|
plaintext, usedOldKey := c.decryptTicket(hs.clientHello.sessionTicket)
|
|
|
|
|
if plaintext == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
hs.sessionState = &sessionState{usedOldKey: usedOldKey}
|
|
|
|
|
ok := hs.sessionState.unmarshal(plaintext)
|
|
|
|
|
if !ok {
|
2012-09-24 16:52:43 -04:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-15 11:41:40 -05:00
|
|
|
// Never resume a session for a different TLS version.
|
|
|
|
|
if c.vers != hs.sessionState.vers {
|
2012-09-24 16:52:43 -04:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cipherSuiteOk := false
|
|
|
|
|
// Check that the client is still offering the ciphersuite in the session.
|
|
|
|
|
for _, id := range hs.clientHello.cipherSuites {
|
|
|
|
|
if id == hs.sessionState.cipherSuite {
|
|
|
|
|
cipherSuiteOk = true
|
|
|
|
|
break
|
|
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
if !cipherSuiteOk {
|
|
|
|
|
return false
|
2009-12-23 11:13:09 -08:00
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
// Check that we also support the ciphersuite from the session.
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
hs.suite = selectCipherSuite([]uint16{hs.sessionState.cipherSuite},
|
|
|
|
|
c.config.cipherSuites(), hs.cipherSuiteOk)
|
|
|
|
|
if hs.suite == nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sessionHasClientCerts := len(hs.sessionState.certificates) != 0
|
2018-11-05 15:59:08 -05:00
|
|
|
needClientCerts := requiresClientCert(c.config.ClientAuth)
|
2012-09-24 16:52:43 -04:00
|
|
|
if needClientCerts && !sessionHasClientCerts {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) doResumeHandshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
|
|
|
|
hs.hello.cipherSuite = hs.suite.id
|
|
|
|
|
// We echo the client's session ID in the ServerHello to let it know
|
|
|
|
|
// that we're doing a resumption.
|
|
|
|
|
hs.hello.sessionId = hs.clientHello.sessionId
|
2015-04-17 21:32:11 -04:00
|
|
|
hs.hello.ticketSupported = hs.sessionState.usedOldKey
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
|
|
|
|
|
hs.finishedHash.discardHandshakeBuffer()
|
|
|
|
|
hs.finishedHash.Write(hs.clientHello.marshal())
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(hs.hello.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2012-09-24 16:52:43 -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 err := c.processCertsFromClient(Certificate{
|
|
|
|
|
Certificate: hs.sessionState.certificates,
|
|
|
|
|
}); err != nil {
|
|
|
|
|
return err
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.masterSecret = hs.sessionState.masterSecret
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) doFullHandshake() error {
|
|
|
|
|
c := hs.c
|
|
|
|
|
|
2013-09-17 13:30:36 -04:00
|
|
|
if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.hello.ocspStapling = true
|
2012-04-12 12:35:21 -04:00
|
|
|
}
|
|
|
|
|
|
2016-10-10 15:27:34 -07:00
|
|
|
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.hello.cipherSuite = hs.suite.id
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
|
|
|
|
|
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
|
2016-10-10 15:27:34 -07:00
|
|
|
if c.config.ClientAuth == NoClientCert {
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
// No need to keep a full record of the handshake if client
|
|
|
|
|
// certificates won't be used.
|
|
|
|
|
hs.finishedHash.discardHandshakeBuffer()
|
|
|
|
|
}
|
|
|
|
|
hs.finishedHash.Write(hs.clientHello.marshal())
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(hs.hello.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2012-04-12 12:35:21 -04:00
|
|
|
|
|
|
|
|
certMsg := new(certificateMsg)
|
2013-09-17 13:30:36 -04:00
|
|
|
certMsg.certificates = hs.cert.Certificate
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(certMsg.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
if hs.hello.ocspStapling {
|
2011-04-14 14:47:28 -04:00
|
|
|
certStatus := new(certificateStatusMsg)
|
2013-09-17 13:30:36 -04:00
|
|
|
certStatus.response = hs.cert.OCSPStaple
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(certStatus.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2011-04-14 14:47:28 -04:00
|
|
|
}
|
|
|
|
|
|
2013-07-02 19:58:56 -04:00
|
|
|
keyAgreement := hs.suite.ka(c.vers)
|
2016-10-10 15:27:34 -07:00
|
|
|
skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
|
2010-12-16 17:10:50 -05:00
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if skx != nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(skx.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2010-12-16 17:10:50 -05:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: disable RSA-PSS in TLS 1.2 again
Signing with RSA-PSS can uncover faulty crypto.Signer implementations,
and it can fail for (broken) small keys. We'll have to take that
breakage eventually, but it would be nice for it to be opt-out at first.
TLS 1.3 requires RSA-PSS and is opt-out in Go 1.13. Instead of making a
TLS 1.3 opt-out influence a TLS 1.2 behavior, let's wait to add RSA-PSS
to TLS 1.2 until TLS 1.3 is on without opt-out.
Note that since the Client Hello is sent before a protocol version is
selected, we have to advertise RSA-PSS there to support TLS 1.3.
That means that we still support RSA-PSS on the client in TLS 1.2 for
verifying server certificates, which is fine, as all issues arise on the
signing side. We have to be careful not to pick (or consider available)
RSA-PSS on the client for client certificates, though.
We'd expect tests to change only in TLS 1.2:
* the server won't pick PSS to sign the key exchange
(Server-TLSv12-* w/ RSA, TestHandshakeServerRSAPSS);
* the server won't advertise PSS in CertificateRequest
(Server-TLSv12-ClientAuthRequested*, TestClientAuth);
* and the client won't pick PSS for its CertificateVerify
(Client-TLSv12-ClientCert-RSA-*, TestHandshakeClientCertRSAPSS,
Client-TLSv12-Renegotiate* because "R" requests a client cert).
Client-TLSv13-ClientCert-RSA-RSAPSS was updated because of a fix in the test.
This effectively reverts 88343530720a52c96b21f2bd5488c8fb607605d7.
Testing was made more complex by the undocumented semantics of OpenSSL's
-[client_]sigalgs (see openssl/openssl#9172).
Updates #32425
Change-Id: Iaddeb2df1f5c75cd090cc8321df2ac8e8e7db349
Reviewed-on: https://go-review.googlesource.com/c/go/+/182339
Reviewed-by: Adam Langley <agl@golang.org>
2019-06-13 18:33:33 -04:00
|
|
|
var certReq *certificateRequestMsg
|
2016-10-10 15:27:34 -07:00
|
|
|
if c.config.ClientAuth >= RequestClientCert {
|
2010-08-16 11:22:22 -04:00
|
|
|
// Request a client certificate
|
crypto/tls: disable RSA-PSS in TLS 1.2 again
Signing with RSA-PSS can uncover faulty crypto.Signer implementations,
and it can fail for (broken) small keys. We'll have to take that
breakage eventually, but it would be nice for it to be opt-out at first.
TLS 1.3 requires RSA-PSS and is opt-out in Go 1.13. Instead of making a
TLS 1.3 opt-out influence a TLS 1.2 behavior, let's wait to add RSA-PSS
to TLS 1.2 until TLS 1.3 is on without opt-out.
Note that since the Client Hello is sent before a protocol version is
selected, we have to advertise RSA-PSS there to support TLS 1.3.
That means that we still support RSA-PSS on the client in TLS 1.2 for
verifying server certificates, which is fine, as all issues arise on the
signing side. We have to be careful not to pick (or consider available)
RSA-PSS on the client for client certificates, though.
We'd expect tests to change only in TLS 1.2:
* the server won't pick PSS to sign the key exchange
(Server-TLSv12-* w/ RSA, TestHandshakeServerRSAPSS);
* the server won't advertise PSS in CertificateRequest
(Server-TLSv12-ClientAuthRequested*, TestClientAuth);
* and the client won't pick PSS for its CertificateVerify
(Client-TLSv12-ClientCert-RSA-*, TestHandshakeClientCertRSAPSS,
Client-TLSv12-Renegotiate* because "R" requests a client cert).
Client-TLSv13-ClientCert-RSA-RSAPSS was updated because of a fix in the test.
This effectively reverts 88343530720a52c96b21f2bd5488c8fb607605d7.
Testing was made more complex by the undocumented semantics of OpenSSL's
-[client_]sigalgs (see openssl/openssl#9172).
Updates #32425
Change-Id: Iaddeb2df1f5c75cd090cc8321df2ac8e8e7db349
Reviewed-on: https://go-review.googlesource.com/c/go/+/182339
Reviewed-by: Adam Langley <agl@golang.org>
2019-06-13 18:33:33 -04:00
|
|
|
certReq = new(certificateRequestMsg)
|
2013-07-17 12:33:16 -04:00
|
|
|
certReq.certificateTypes = []byte{
|
|
|
|
|
byte(certTypeRSASign),
|
|
|
|
|
byte(certTypeECDSASign),
|
|
|
|
|
}
|
2013-07-02 19:58:56 -04:00
|
|
|
if c.vers >= VersionTLS12 {
|
2018-10-24 21:22:00 -04:00
|
|
|
certReq.hasSignatureAlgorithm = true
|
2019-11-03 21:28:47 -05:00
|
|
|
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
|
2013-07-02 19:58:56 -04:00
|
|
|
}
|
2012-01-05 12:05:38 -05:00
|
|
|
|
2010-08-16 11:22:22 -04:00
|
|
|
// An empty list of certificateAuthorities signals to
|
|
|
|
|
// the client that it may send any certificate in response
|
2012-01-05 12:05:38 -05:00
|
|
|
// to our request. When we know the CAs we trust, then
|
|
|
|
|
// we can send them down, so that the client can choose
|
|
|
|
|
// an appropriate certificate to give to us.
|
2016-10-10 15:27:34 -07:00
|
|
|
if c.config.ClientCAs != nil {
|
|
|
|
|
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
|
2012-01-05 12:05:38 -05:00
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(certReq.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
helloDone := new(serverHelloDoneMsg)
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(helloDone.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2016-06-01 14:41:09 -07:00
|
|
|
if _, err := c.flush(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-17 12:33:16 -04:00
|
|
|
var pub crypto.PublicKey // public key for client auth, if any
|
2012-01-05 12:05:38 -05:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
msg, err := c.readHandshake()
|
2012-01-05 12:05:38 -05:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we requested a client certificate, then the client must send a
|
|
|
|
|
// certificate message, even if it's empty.
|
2016-10-10 15:27:34 -07:00
|
|
|
if c.config.ClientAuth >= RequestClientCert {
|
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
|
|
|
certMsg, ok := msg.(*certificateMsg)
|
|
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(certMsg, msg)
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(certMsg.marshal())
|
2010-08-16 11:22:22 -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 err := c.processCertsFromClient(Certificate{
|
|
|
|
|
Certificate: certMsg.certificates,
|
|
|
|
|
}); err != nil {
|
2012-09-24 16:52:43 -04:00
|
|
|
return err
|
2010-08-16 11:22:22 -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 len(certMsg.certificates) != 0 {
|
|
|
|
|
pub = c.peerCertificates[0].PublicKey
|
|
|
|
|
}
|
2012-01-05 12:05:38 -05:00
|
|
|
|
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get client key exchange
|
2010-04-26 22:19:04 -07:00
|
|
|
ckx, ok := msg.(*clientKeyExchangeMsg)
|
2009-11-05 15:44:32 -08:00
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(ckx, msg)
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(ckx.marshal())
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2016-10-10 15:27:34 -07:00
|
|
|
preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
|
2018-11-03 18:13:05 -04:00
|
|
|
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
|
2016-08-20 14:41:42 +03:00
|
|
|
c.sendAlert(alertInternalError)
|
|
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
|
2010-08-16 11:22:22 -04:00
|
|
|
// If we received a client cert in response to our certificate request message,
|
|
|
|
|
// the client will send us a certificateVerifyMsg immediately after the
|
2016-03-01 23:21:55 +00:00
|
|
|
// clientKeyExchangeMsg. This message is a digest of all preceding
|
2010-08-16 11:22:22 -04:00
|
|
|
// handshake-layer messages that is signed using the private key corresponding
|
|
|
|
|
// to the client's certificate. This allows us to verify that the client is in
|
2011-05-18 13:14:56 -04:00
|
|
|
// possession of the private key of the certificate.
|
2010-08-16 11:22:22 -04:00
|
|
|
if len(c.peerCertificates) > 0 {
|
|
|
|
|
msg, err = c.readHandshake()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
certVerify, ok := msg.(*certificateVerifyMsg)
|
|
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(certVerify, msg)
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
var sigType uint8
|
|
|
|
|
var sigHash crypto.Hash
|
|
|
|
|
if c.vers >= VersionTLS12 {
|
|
|
|
|
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return errors.New("tls: client certificate used with invalid signature algorithm")
|
|
|
|
|
}
|
|
|
|
|
sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return c.sendAlert(alertInternalError)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertIllegalParameter)
|
|
|
|
|
return err
|
|
|
|
|
}
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
}
|
|
|
|
|
|
crypto/tls: refactor certificate and signature algorithm logic
This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.
In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.
Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.
On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.
On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.
There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.
The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.
Updates #32426
Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
2019-11-01 19:00:33 -04:00
|
|
|
signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret)
|
|
|
|
|
if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
|
2019-10-29 16:46:26 -04:00
|
|
|
c.sendAlert(alertDecryptError)
|
|
|
|
|
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(certVerify.marshal())
|
2010-08-16 11:22:22 -04:00
|
|
|
}
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
|
|
|
|
|
hs.finishedHash.discardHandshakeBuffer()
|
2012-09-24 16:52:43 -04:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) establishKeys() error {
|
|
|
|
|
c := hs.c
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
crypto/tls: decouple handshake signatures from the handshake hash.
Prior to TLS 1.2, the handshake had a pleasing property that one could
incrementally hash it and, from that, get the needed hashes for both
the CertificateVerify and Finished messages.
TLS 1.2 introduced negotiation for the signature and hash and it became
possible for the handshake hash to be, say, SHA-384, but for the
CertificateVerify to sign the handshake with SHA-1. The problem is that
one doesn't know in advance which hashes will be needed and thus the
handshake needs to be buffered.
Go ignored this, always kept a single handshake hash, and any signatures
over the handshake had to use that hash.
However, there are a set of servers that inspect the client's offered
signature hash functions and will abort the handshake if one of the
server's certificates is signed with a hash function outside of that
set. https://robertsspaceindustries.com/ is an example of such a server.
Clearly not a lot of thought happened when that server code was written,
but its out there and we have to deal with it.
This change decouples the handshake hash from the CertificateVerify
hash. This lays the groundwork for advertising support for SHA-384 but
doesn't actually make that change in the interests of reviewability.
Updating the advertised hash functions will cause changes in many of the
testdata/ files and some errors might get lost in the noise. This change
only needs to update four testdata/ files: one because a SHA-384-based
handshake is now being signed with SHA-256 and the others because the
TLS 1.2 CertificateRequest message now includes SHA-1.
This change also has the effect of adding support for
client-certificates in SSLv3 servers. However, SSLv3 is now disabled by
default so this should be moot.
It would be possible to avoid much of this change and just support
SHA-384 for the ServerKeyExchange as the SKX only signs over the nonces
and SKX params (a design mistake in TLS). However, that would leave Go
in the odd situation where it advertised support for SHA-384, but would
only use the handshake hash when signing client certificates. I fear
that'll just cause problems in the future.
Much of this code was written by davidben@ for the purposes of testing
BoringSSL.
Partly addresses #9757
Change-Id: I5137a472b6076812af387a5a69fc62c7373cd485
Reviewed-on: https://go-review.googlesource.com/9415
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
2015-04-28 09:13:38 -07:00
|
|
|
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2013-08-29 17:18:59 -04:00
|
|
|
var clientCipher, serverCipher interface{}
|
|
|
|
|
var clientHash, serverHash macFunction
|
|
|
|
|
|
|
|
|
|
if hs.suite.aead == nil {
|
|
|
|
|
clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
|
|
|
|
|
clientHash = hs.suite.mac(c.vers, clientMAC)
|
|
|
|
|
serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
|
|
|
|
|
serverHash = hs.suite.mac(c.vers, serverMAC)
|
|
|
|
|
} else {
|
|
|
|
|
clientCipher = hs.suite.aead(clientKey, clientIV)
|
|
|
|
|
serverCipher = hs.suite.aead(serverKey, serverIV)
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
|
2013-08-29 17:18:59 -04:00
|
|
|
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
|
2012-09-24 16:52:43 -04:00
|
|
|
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-11 16:40:42 -07:00
|
|
|
func (hs *serverHandshakeState) readFinished(out []byte) error {
|
2012-09-24 16:52:43 -04:00
|
|
|
c := hs.c
|
|
|
|
|
|
2018-11-03 18:29:09 -04:00
|
|
|
if err := c.readChangeCipherSpec(); err != nil {
|
|
|
|
|
return err
|
2010-04-26 22:19:04 -07:00
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
msg, err := c.readHandshake()
|
2010-04-26 22:19:04 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
clientFinished, ok := msg.(*finishedMsg)
|
2009-11-05 15:44:32 -08:00
|
|
|
if !ok {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
|
|
|
return unexpectedMessageError(clientFinished, msg)
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
verify := hs.finishedHash.clientSum(hs.masterSecret)
|
2009-11-05 15:44:32 -08:00
|
|
|
if len(verify) != len(clientFinished.verifyData) ||
|
|
|
|
|
subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
|
2014-02-12 11:20:01 -05:00
|
|
|
c.sendAlert(alertHandshakeFailure)
|
|
|
|
|
return errors.New("tls: client's Finished message is incorrect")
|
2009-11-05 15:44:32 -08:00
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
hs.finishedHash.Write(clientFinished.marshal())
|
2014-08-11 16:40:42 -07:00
|
|
|
copy(out, verify)
|
2012-09-24 16:52:43 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (hs *serverHandshakeState) sendSessionTicket() error {
|
|
|
|
|
if !hs.hello.ticketSupported {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c := hs.c
|
|
|
|
|
m := new(newSessionTicketMsg)
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
state := sessionState{
|
|
|
|
|
vers: c.vers,
|
|
|
|
|
cipherSuite: hs.suite.id,
|
|
|
|
|
masterSecret: hs.masterSecret,
|
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
|
|
|
certificates: certsFromClient,
|
2012-09-24 16:52:43 -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
|
|
|
var err error
|
2018-11-05 15:59:08 -05:00
|
|
|
m.ticket, err = c.encryptTicket(state.marshal())
|
2012-09-24 16:52:43 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hs.finishedHash.Write(m.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2012-09-24 16:52:43 -04:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-11 16:40:42 -07:00
|
|
|
func (hs *serverHandshakeState) sendFinished(out []byte) error {
|
2012-09-24 16:52:43 -04:00
|
|
|
c := hs.c
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
finished := new(finishedMsg)
|
2012-09-24 16:52:43 -04:00
|
|
|
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
|
|
|
|
|
hs.finishedHash.Write(finished.marshal())
|
2016-02-26 14:17:29 -05:00
|
|
|
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2009-11-05 15:44:32 -08:00
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
c.cipherSuite = hs.suite.id
|
2014-08-11 16:40:42 -07:00
|
|
|
copy(out, finished.verifyData)
|
2012-09-24 16:52:43 -04:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// processCertsFromClient takes a chain of client certificates either from a
|
|
|
|
|
// Certificates message or from a sessionState and verifies them. It returns
|
|
|
|
|
// the public key of the leaf certificate.
|
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 (c *Conn) processCertsFromClient(certificate Certificate) error {
|
|
|
|
|
certificates := certificate.Certificate
|
2012-09-24 16:52:43 -04:00
|
|
|
certs := make([]*x509.Certificate, len(certificates))
|
|
|
|
|
var err error
|
|
|
|
|
for i, asn1Data := range certificates {
|
|
|
|
|
if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
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: failed to parse client certificate: " + err.Error())
|
2012-09-24 16:52:43 -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 len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
|
|
|
|
return errors.New("tls: client didn't provide a certificate")
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-24 16:52:43 -04:00
|
|
|
if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
|
|
|
|
|
opts := x509.VerifyOptions{
|
|
|
|
|
Roots: c.config.ClientCAs,
|
|
|
|
|
CurrentTime: c.config.time(),
|
|
|
|
|
Intermediates: x509.NewCertPool(),
|
|
|
|
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, cert := range certs[1:] {
|
|
|
|
|
opts.Intermediates.AddCert(cert)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chains, err := certs[0].Verify(opts)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
2019-10-29 16:46:26 -04:00
|
|
|
return errors.New("tls: failed to verify client certificate: " + err.Error())
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.verifiedChains = chains
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-13 16:22:28 -06:00
|
|
|
if c.config.VerifyPeerCertificate != nil {
|
|
|
|
|
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
|
|
|
|
|
c.sendAlert(alertBadCertificate)
|
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 err
|
2016-07-13 16:22:28 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 03:35:13 -06:00
|
|
|
if len(certs) == 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
|
2012-09-24 16:52:43 -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
|
|
|
switch certs[0].PublicKey.(type) {
|
2019-05-16 19:13:29 -04:00
|
|
|
case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
|
2016-03-14 03:35:13 -06:00
|
|
|
default:
|
|
|
|
|
c.sendAlert(alertUnsupportedCertificate)
|
2019-10-29 16:46:26 -04:00
|
|
|
return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
|
2016-03-14 03:35:13 -06: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
|
|
|
|
2016-03-14 03:35:13 -06:00
|
|
|
c.peerCertificates = certs
|
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.ocspResponse = certificate.OCSPStaple
|
|
|
|
|
c.scts = certificate.SignedCertificateTimestamps
|
|
|
|
|
return nil
|
2012-09-24 16:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
|
|
|
|
|
supportedVersions := clientHello.supportedVersions
|
|
|
|
|
if len(clientHello.supportedVersions) == 0 {
|
|
|
|
|
supportedVersions = supportedVersionsFromMax(clientHello.vers)
|
2016-10-19 15:21:54 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-02 00:57:30 -04:00
|
|
|
return &ClientHelloInfo{
|
|
|
|
|
CipherSuites: clientHello.cipherSuites,
|
|
|
|
|
ServerName: clientHello.serverName,
|
|
|
|
|
SupportedCurves: clientHello.supportedCurves,
|
|
|
|
|
SupportedPoints: clientHello.supportedPoints,
|
|
|
|
|
SignatureSchemes: clientHello.supportedSignatureAlgorithms,
|
|
|
|
|
SupportedProtos: clientHello.alpnProtocols,
|
2016-10-19 15:21:54 +02:00
|
|
|
SupportedVersions: supportedVersions,
|
2018-11-02 00:57:30 -04:00
|
|
|
Conn: c.conn,
|
2019-11-01 19:00:33 -04:00
|
|
|
config: c.config,
|
2016-10-19 15:21:54 +02:00
|
|
|
}
|
|
|
|
|
}
|