Implement client certificates for TLS 1.3 in Go.
Tested by having client and server talk to each other. This adds the certificate_extensions field to CertificateRequest which I'd previously missed. (We completely ignore the field, with the expectation that the C code won't have anything useful to do with it either.) Change-Id: I74f96acd36747d4b6a6f533535e36ea8e94d2be8 Reviewed-on: https://boringssl-review.googlesource.com/8710 Reviewed-by: David Benjamin <davidben@google.com>
This commit is contained in:
parent
615119a9e9
commit
8d343b44bb
@ -510,8 +510,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
||||
}
|
||||
|
||||
var chainToSend *Certificate
|
||||
var certRequested bool
|
||||
var certRequestContext []byte
|
||||
var certReq *certificateRequestMsg
|
||||
if hs.suite.flags&suitePSK != 0 {
|
||||
if encryptedExtensions.extensions.ocspResponse != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
@ -530,11 +529,10 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
||||
return err
|
||||
}
|
||||
|
||||
certReq, ok := msg.(*certificateRequestMsg)
|
||||
var ok bool
|
||||
certReq, ok = msg.(*certificateRequestMsg)
|
||||
if ok {
|
||||
hs.writeServerHash(certReq.marshal())
|
||||
certRequested = true
|
||||
certRequestContext = certReq.requestContext
|
||||
|
||||
chainToSend, err = selectClientCertificate(c, certReq)
|
||||
if err != nil {
|
||||
@ -602,10 +600,42 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
||||
masterSecret := hs.finishedHash.extractKey(handshakeSecret, zeroSecret)
|
||||
trafficSecret := hs.finishedHash.deriveSecret(masterSecret, applicationTrafficLabel)
|
||||
|
||||
if certRequested {
|
||||
_ = chainToSend
|
||||
_ = certRequestContext
|
||||
return errors.New("tls: client auth not implemented.")
|
||||
if certReq != nil {
|
||||
certMsg := &certificateMsg{
|
||||
hasRequestContext: true,
|
||||
requestContext: certReq.requestContext,
|
||||
}
|
||||
if chainToSend != nil {
|
||||
certMsg.certificates = chainToSend.Certificate
|
||||
}
|
||||
hs.writeClientHash(certMsg.marshal())
|
||||
c.writeRecord(recordTypeHandshake, certMsg.marshal())
|
||||
|
||||
if chainToSend != nil {
|
||||
certVerify := &certificateVerifyMsg{
|
||||
hasSignatureAlgorithm: true,
|
||||
}
|
||||
|
||||
// Determine the hash to sign.
|
||||
privKey := chainToSend.PrivateKey
|
||||
|
||||
var err error
|
||||
certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, privKey, c.config, certReq.signatureAlgorithms)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
|
||||
certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
hs.writeClientHash(certVerify.marshal())
|
||||
c.writeRecord(recordTypeHandshake, certVerify.marshal())
|
||||
}
|
||||
}
|
||||
|
||||
// Send a client Finished message.
|
||||
|
@ -1461,6 +1461,11 @@ func (m *certificateRequestMsg) marshal() []byte {
|
||||
caEntry.addBytes(ca)
|
||||
}
|
||||
|
||||
if m.hasRequestContext {
|
||||
// Emit no certificate extensions.
|
||||
body.addU16(0)
|
||||
}
|
||||
|
||||
m.raw = builder.finish()
|
||||
return m.raw
|
||||
}
|
||||
@ -1538,6 +1543,19 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
|
||||
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
|
||||
cas = cas[caLen:]
|
||||
}
|
||||
|
||||
if m.hasRequestContext {
|
||||
// Ignore certificate extensions.
|
||||
if len(data) < 2 {
|
||||
return false
|
||||
}
|
||||
extsLength := int(data[0])<<8 | int(data[1])
|
||||
if len(data) < 2+extsLength {
|
||||
return false
|
||||
}
|
||||
data = data[2+extsLength:]
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -406,8 +406,25 @@ Curves:
|
||||
|
||||
if hs.suite.flags&suitePSK == 0 {
|
||||
if config.ClientAuth >= RequestClientCert {
|
||||
// TODO(davidben): Implement client auth.
|
||||
return errors.New("tls: client auth not implemented")
|
||||
// Request a client certificate
|
||||
certReq := &certificateRequestMsg{
|
||||
hasSignatureAlgorithm: true,
|
||||
hasRequestContext: true,
|
||||
}
|
||||
if !config.Bugs.NoSignatureAlgorithms {
|
||||
certReq.signatureAlgorithms = config.signSignatureAlgorithms()
|
||||
}
|
||||
|
||||
// An empty list of certificateAuthorities signals to
|
||||
// the client that it may send any certificate in response
|
||||
// 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.
|
||||
if config.ClientCAs != nil {
|
||||
certReq.certificateAuthorities = config.ClientCAs.Subjects()
|
||||
}
|
||||
hs.writeServerHash(certReq.marshal())
|
||||
c.writeRecord(recordTypeHandshake, certReq.marshal())
|
||||
}
|
||||
|
||||
certMsg := &certificateMsg{
|
||||
@ -461,7 +478,51 @@ Curves:
|
||||
// If we requested a client certificate, then the client must send a
|
||||
// certificate message, even if it's empty.
|
||||
if config.ClientAuth >= RequestClientCert {
|
||||
return errors.New("tls: client certificates not implemented")
|
||||
msg, err := c.readHandshake()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certMsg, ok := msg.(*certificateMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.writeClientHash(certMsg.marshal())
|
||||
|
||||
if len(certMsg.certificates) == 0 {
|
||||
// The client didn't actually send a certificate
|
||||
switch config.ClientAuth {
|
||||
case RequireAnyClientCert, RequireAndVerifyClientCert:
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: client didn't provide a certificate")
|
||||
}
|
||||
}
|
||||
|
||||
pub, err := hs.processCertsFromClient(certMsg.certificates)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(c.peerCertificates) > 0 {
|
||||
msg, err = c.readHandshake()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certVerify, ok := msg.(*certificateVerifyMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certVerify, msg)
|
||||
}
|
||||
|
||||
input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
|
||||
if err := verifyMessage(c.vers, pub, config, certVerify.signatureAlgorithm, input, certVerify.signature); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return err
|
||||
}
|
||||
hs.writeClientHash(certVerify.marshal())
|
||||
}
|
||||
}
|
||||
|
||||
// Read the client Finished message.
|
||||
|
Loading…
Reference in New Issue
Block a user