package tls
import (
+ "bytes"
"container/list"
"crypto"
"crypto/ecdsa"
// SignatureSchemes lists the signature schemes that the server is
// willing to verify.
SignatureSchemes []SignatureScheme
+
+ // Version is the TLS version that was negotiated for this connection.
+ Version uint16
}
// RenegotiationSupport enumerates the different levels of support for TLS
return nil
}
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the server that sent the CertificateRequest. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error {
+ if _, err := selectSignatureScheme(cri.Version, c, cri.SignatureSchemes); err != nil {
+ return err
+ }
+
+ if len(cri.AcceptableCAs) == 0 {
+ return nil
+ }
+
+ for j, cert := range c.Certificate {
+ x509Cert := c.Leaf
+ // Parse the certificate if this isn't the leaf node, or if
+ // chain.Leaf was nil.
+ if j != 0 || x509Cert == nil {
+ var err error
+ if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+ return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err)
+ }
+ }
+
+ for _, ca := range cri.AcceptableCAs {
+ if bytes.Equal(x509Cert.RawIssuer, ca) {
+ return nil
+ }
+ }
+ }
+ return errors.New("chain is not signed by an acceptable CA")
+}
+
// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
// from the CommonName and SubjectAlternateName fields of each of the leaf
// certificates.
"fmt"
"io"
"net"
- "strconv"
"strings"
"sync/atomic"
"time"
certRequested = true
hs.finishedHash.Write(certReq.marshal())
- cri := certificateRequestInfoFromMsg(certReq)
+ cri := certificateRequestInfoFromMsg(c.vers, certReq)
if chainToSend, err = c.getClientCertificate(cri); err != nil {
c.sendAlert(alertInternalError)
return err
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
-func certificateRequestInfoFromMsg(certReq *certificateRequestMsg) *CertificateRequestInfo {
+func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
+ cri := &CertificateRequestInfo{
+ AcceptableCAs: certReq.certificateAuthorities,
+ Version: vers,
+ }
+
var rsaAvail, ecAvail bool
for _, certType := range certReq.certificateTypes {
switch certType {
}
}
- cri := &CertificateRequestInfo{
- AcceptableCAs: certReq.certificateAuthorities,
- }
-
if !certReq.hasSignatureAlgorithm {
// Prior to TLS 1.2, the signature schemes were not
// included in the certificate request message. In this
return c.config.GetClientCertificate(cri)
}
- // We need to search our list of client certs for one
- // where SignatureAlgorithm is acceptable to the server and the
- // Issuer is in AcceptableCAs.
- for i, chain := range c.config.Certificates {
- sigOK := false
- for _, alg := range signatureSchemesForCertificate(c.vers, &chain) {
- if isSupportedSignatureAlgorithm(alg, cri.SignatureSchemes) {
- sigOK = true
- break
- }
- }
- if !sigOK {
+ for _, chain := range c.config.Certificates {
+ if err := cri.SupportsCertificate(&chain); err != nil {
continue
}
-
- if len(cri.AcceptableCAs) == 0 {
- return &chain, nil
- }
-
- for j, cert := range chain.Certificate {
- x509Cert := chain.Leaf
- // Parse the certificate if this isn't the leaf node, or if
- // chain.Leaf was nil.
- if j != 0 || x509Cert == nil {
- var err error
- if x509Cert, err = x509.ParseCertificate(cert); err != nil {
- c.sendAlert(alertInternalError)
- return nil, errors.New("tls: failed to parse configured certificate chain #" + strconv.Itoa(i) + ": " + err.Error())
- }
- }
-
- for _, ca := range cri.AcceptableCAs {
- if bytes.Equal(x509Cert.RawIssuer, ca) {
- return &chain, nil
- }
- }
- }
+ return &chain, nil
}
// No acceptable certificate found. Don't send a certificate.