TLSConfig creates a tls.Config which sets the GetCertificate field to a certificate store which uses the given source to update the the certificates on-demand. It also sets the ClientCAs field if src.LoadClientCAs returns a non-nil value and sets ClientAuth to RequireAndVerifyClientCert.
(src Source, strictMatch bool, minVersion, maxVersion uint16, cipherSuites []uint16)
| 93 | // It also sets the ClientCAs field if src.LoadClientCAs returns a non-nil |
| 94 | // value and sets ClientAuth to RequireAndVerifyClientCert. |
| 95 | func TLSConfig(src Source, strictMatch bool, minVersion, maxVersion uint16, cipherSuites []uint16) (*tls.Config, error) { |
| 96 | clientCAs, err := src.LoadClientCAs() |
| 97 | if err != nil { |
| 98 | return nil, err |
| 99 | } |
| 100 | |
| 101 | sf := &singleflight.Group{} |
| 102 | store := NewStore() |
| 103 | x := &tls.Config{ |
| 104 | MinVersion: minVersion, |
| 105 | MaxVersion: maxVersion, |
| 106 | CipherSuites: cipherSuites, |
| 107 | NextProtos: []string{"h2", "http/1.1"}, |
| 108 | GetCertificate: func(clientHello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) { |
| 109 | cert, err = getCertificate(store.certstore(), clientHello, strictMatch) |
| 110 | if cert != nil { |
| 111 | return |
| 112 | } |
| 113 | |
| 114 | switch err { |
| 115 | case nil, ErrNoCertsStored: |
| 116 | // Store doesn't contain a suitable cert. Perhaps the source can issue one? |
| 117 | default: |
| 118 | // an unrecoverable error |
| 119 | return |
| 120 | } |
| 121 | |
| 122 | ca, ok := src.(Issuer) |
| 123 | if !ok { |
| 124 | return |
| 125 | } |
| 126 | |
| 127 | serverName := clientHello.ServerName |
| 128 | x, err, _ := sf.Do(serverName, func() (any, error) { |
| 129 | return ca.Issue(serverName) |
| 130 | }) |
| 131 | if err != nil { |
| 132 | return cert, err |
| 133 | } |
| 134 | |
| 135 | return x.(*tls.Certificate), nil |
| 136 | }, |
| 137 | } |
| 138 | |
| 139 | if clientCAs != nil { |
| 140 | x.ClientCAs = clientCAs |
| 141 | x.ClientAuth = tls.RequireAndVerifyClientCert |
| 142 | } |
| 143 | |
| 144 | go func() { |
| 145 | for certs := range src.Certificates() { |
| 146 | store.SetCertificates(certs) |
| 147 | } |
| 148 | }() |
| 149 | |
| 150 | return x, nil |
| 151 | } |