mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/tls: Improve TLS Client Authentication
Fix incorrect marshal/unmarshal of certificateRequest. Add support for configuring client-auth on the server side. Fix the certificate selection in the client side. Update generate_cert.go to new time package Fixes #2521. R=krautz, agl, bradfitz CC=golang-dev, mikkel https://golang.org/cl/5448093
This commit is contained in:
parent
8f1cb093ff
commit
c581ec4918
7 changed files with 937 additions and 150 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue