diff options
Diffstat (limited to 'libgo/go/crypto/tls/handshake_client.go')
-rw-r--r-- | libgo/go/crypto/tls/handshake_client.go | 83 |
1 files changed, 54 insertions, 29 deletions
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index 73648002bd5..632ceea9c1a 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -5,12 +5,14 @@ package tls import ( + "bytes" "crypto" "crypto/rsa" "crypto/subtle" "crypto/x509" "errors" "io" + "strconv" ) func (c *Conn) clientHandshake() error { @@ -162,10 +164,23 @@ func (c *Conn) clientHandshake() error { } } - transmitCert := false + var certToSend *Certificate certReq, ok := msg.(*certificateRequestMsg) if ok { - // We only accept certificates with RSA keys. + // RFC 4346 on the certificateAuthorities field: + // A list of the distinguished names of acceptable certificate + // authorities. These distinguished names may specify a desired + // distinguished name for a root CA or for a subordinate CA; + // thus, this message can be used to describe both known roots + // and a desired authorization space. If the + // certificate_authorities list is empty then the client MAY + // send any certificate of the appropriate + // ClientCertificateType, unless there is some external + // arrangement to the contrary. + + finishedHash.Write(certReq.marshal()) + + // For now, we only know how to sign challenges with RSA rsaAvail := false for _, certType := range certReq.certificateTypes { if certType == certTypeRSASign { @@ -174,23 +189,41 @@ func (c *Conn) clientHandshake() error { } } - // For now, only send a certificate back if the server gives us an - // empty list of certificateAuthorities. - // - // RFC 4346 on the certificateAuthorities field: - // A list of the distinguished names of acceptable certificate - // authorities. These distinguished names may specify a desired - // distinguished name for a root CA or for a subordinate CA; thus, - // this message can be used to describe both known roots and a - // desired authorization space. If the certificate_authorities - // list is empty then the client MAY send any certificate of the - // appropriate ClientCertificateType, unless there is some - // external arrangement to the contrary. - if rsaAvail && len(certReq.certificateAuthorities) == 0 { - transmitCert = true - } + // We need to search our list of client certs for one + // where SignatureAlgorithm is RSA and the Issuer is in + // certReq.certificateAuthorities + findCert: + for i, cert := range c.config.Certificates { + if !rsaAvail { + continue + } - finishedHash.Write(certReq.marshal()) + leaf := cert.Leaf + if leaf == nil { + if leaf, err = x509.ParseCertificate(cert.Certificate[0]); err != nil { + c.sendAlert(alertInternalError) + return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error()) + } + } + + if leaf.PublicKeyAlgorithm != x509.RSA { + continue + } + + if len(certReq.certificateAuthorities) == 0 { + // they gave us an empty list, so just take the + // first RSA cert from c.config.Certificates + certToSend = &cert + break + } + + for _, ca := range certReq.certificateAuthorities { + if bytes.Equal(leaf.RawIssuer, ca) { + certToSend = &cert + break findCert + } + } + } msg, err = c.readHandshake() if err != nil { @@ -204,17 +237,9 @@ func (c *Conn) clientHandshake() error { } finishedHash.Write(shd.marshal()) - var cert *x509.Certificate - if transmitCert { + if certToSend != nil { certMsg = new(certificateMsg) - if len(c.config.Certificates) > 0 { - cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0]) - if err == nil && cert.PublicKeyAlgorithm == x509.RSA { - certMsg.certificates = c.config.Certificates[0].Certificate - } else { - cert = nil - } - } + certMsg.certificates = certToSend.Certificate finishedHash.Write(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) } @@ -229,7 +254,7 @@ func (c *Conn) clientHandshake() error { c.writeRecord(recordTypeHandshake, ckx.marshal()) } - if cert != nil { + if certToSend != nil { certVerify := new(certificateVerifyMsg) digest := make([]byte, 0, 36) digest = finishedHash.serverMD5.Sum(digest) |