certificate.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package dtls
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "crypto/x509"
  6. "fmt"
  7. "strings"
  8. )
  9. // ClientHelloInfo contains information from a ClientHello message in order to
  10. // guide application logic in the GetCertificate.
  11. type ClientHelloInfo struct {
  12. // ServerName indicates the name of the server requested by the client
  13. // in order to support virtual hosting. ServerName is only set if the
  14. // client is using SNI (see RFC 4366, Section 3.1).
  15. ServerName string
  16. // CipherSuites lists the CipherSuites supported by the client (e.g.
  17. // TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
  18. CipherSuites []CipherSuiteID
  19. }
  20. // CertificateRequestInfo contains information from a server's
  21. // CertificateRequest message, which is used to demand a certificate and proof
  22. // of control from a client.
  23. type CertificateRequestInfo struct {
  24. // AcceptableCAs contains zero or more, DER-encoded, X.501
  25. // Distinguished Names. These are the names of root or intermediate CAs
  26. // that the server wishes the returned certificate to be signed by. An
  27. // empty slice indicates that the server has no preference.
  28. AcceptableCAs [][]byte
  29. }
  30. // SupportsCertificate returns nil if the provided certificate is supported by
  31. // the server that sent the CertificateRequest. Otherwise, it returns an error
  32. // describing the reason for the incompatibility.
  33. // NOTE: original src: https://github.com/golang/go/blob/29b9a328d268d53833d2cc063d1d8b4bf6852675/src/crypto/tls/common.go#L1273
  34. func (cri *CertificateRequestInfo) SupportsCertificate(c *tls.Certificate) error {
  35. if len(cri.AcceptableCAs) == 0 {
  36. return nil
  37. }
  38. for j, cert := range c.Certificate {
  39. x509Cert := c.Leaf
  40. // Parse the certificate if this isn't the leaf node, or if
  41. // chain.Leaf was nil.
  42. if j != 0 || x509Cert == nil {
  43. var err error
  44. if x509Cert, err = x509.ParseCertificate(cert); err != nil {
  45. return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err)
  46. }
  47. }
  48. for _, ca := range cri.AcceptableCAs {
  49. if bytes.Equal(x509Cert.RawIssuer, ca) {
  50. return nil
  51. }
  52. }
  53. }
  54. return errNotAcceptableCertificateChain
  55. }
  56. func (c *handshakeConfig) setNameToCertificateLocked() {
  57. nameToCertificate := make(map[string]*tls.Certificate)
  58. for i := range c.localCertificates {
  59. cert := &c.localCertificates[i]
  60. x509Cert := cert.Leaf
  61. if x509Cert == nil {
  62. var parseErr error
  63. x509Cert, parseErr = x509.ParseCertificate(cert.Certificate[0])
  64. if parseErr != nil {
  65. continue
  66. }
  67. }
  68. if len(x509Cert.Subject.CommonName) > 0 {
  69. nameToCertificate[strings.ToLower(x509Cert.Subject.CommonName)] = cert
  70. }
  71. for _, san := range x509Cert.DNSNames {
  72. nameToCertificate[strings.ToLower(san)] = cert
  73. }
  74. }
  75. c.nameToCertificate = nameToCertificate
  76. }
  77. func (c *handshakeConfig) getCertificate(clientHelloInfo *ClientHelloInfo) (*tls.Certificate, error) {
  78. c.mu.Lock()
  79. defer c.mu.Unlock()
  80. if c.localGetCertificate != nil &&
  81. (len(c.localCertificates) == 0 || len(clientHelloInfo.ServerName) > 0) {
  82. cert, err := c.localGetCertificate(clientHelloInfo)
  83. if cert != nil || err != nil {
  84. return cert, err
  85. }
  86. }
  87. if c.nameToCertificate == nil {
  88. c.setNameToCertificateLocked()
  89. }
  90. if len(c.localCertificates) == 0 {
  91. return nil, errNoCertificates
  92. }
  93. if len(c.localCertificates) == 1 {
  94. // There's only one choice, so no point doing any work.
  95. return &c.localCertificates[0], nil
  96. }
  97. if len(clientHelloInfo.ServerName) == 0 {
  98. return &c.localCertificates[0], nil
  99. }
  100. name := strings.TrimRight(strings.ToLower(clientHelloInfo.ServerName), ".")
  101. if cert, ok := c.nameToCertificate[name]; ok {
  102. return cert, nil
  103. }
  104. // try replacing labels in the name with wildcards until we get a
  105. // match.
  106. labels := strings.Split(name, ".")
  107. for i := range labels {
  108. labels[i] = "*"
  109. candidate := strings.Join(labels, ".")
  110. if cert, ok := c.nameToCertificate[candidate]; ok {
  111. return cert, nil
  112. }
  113. }
  114. // If nothing matches, return the first certificate.
  115. return &c.localCertificates[0], nil
  116. }
  117. // NOTE: original src: https://github.com/golang/go/blob/29b9a328d268d53833d2cc063d1d8b4bf6852675/src/crypto/tls/handshake_client.go#L974
  118. func (c *handshakeConfig) getClientCertificate(cri *CertificateRequestInfo) (*tls.Certificate, error) {
  119. c.mu.Lock()
  120. defer c.mu.Unlock()
  121. if c.localGetClientCertificate != nil {
  122. return c.localGetClientCertificate(cri)
  123. }
  124. for i := range c.localCertificates {
  125. chain := c.localCertificates[i]
  126. if err := cri.SupportsCertificate(&chain); err != nil {
  127. continue
  128. }
  129. return &chain, nil
  130. }
  131. // No acceptable certificate found. Don't send a certificate.
  132. return new(tls.Certificate), nil
  133. }