ClientSideTLSConfig constructs a tls.Config to be used in a client-side handshake based on the contents of the HandshakeInfo. hostname is passed as a parameter here instead of being part of the HandshakeInfo because HandshakeInfo contains cluster-level security configuration that applies to all end
(ctx context.Context, hostname string)
| 158 | // specific to each endpoint. This allows sharing a single HandshakeInfo |
| 159 | // instance across multiple endpoints in the same cluster. |
| 160 | func (hi *HandshakeInfo) ClientSideTLSConfig(ctx context.Context, hostname string) (*tls.Config, error) { |
| 161 | // On the client side, rootProvider is mandatory. IdentityProvider is |
| 162 | // optional based on whether the client is doing TLS or mTLS. |
| 163 | if hi.rootProvider == nil { |
| 164 | return nil, errors.New("xds: CertificateProvider to fetch trusted roots is missing, cannot perform TLS handshake. Please check configuration on the management server") |
| 165 | } |
| 166 | // Since the call to KeyMaterial() can block, we read the providers under |
| 167 | // the lock but call the actual function after releasing the lock. |
| 168 | rootProv, idProv := hi.rootProvider, hi.identityProvider |
| 169 | |
| 170 | // InsecureSkipVerify needs to be set to true because we need to perform |
| 171 | // custom verification to check the SAN on the received certificate. |
| 172 | // Currently the Go stdlib does complete verification of the cert (which |
| 173 | // includes hostname verification) or none. We are forced to go with the |
| 174 | // latter and perform the normal cert validation ourselves. |
| 175 | cfg := &tls.Config{ |
| 176 | InsecureSkipVerify: true, |
| 177 | NextProtos: []string{"h2"}, |
| 178 | } |
| 179 | |
| 180 | km, err := rootProv.KeyMaterial(ctx) |
| 181 | if err != nil { |
| 182 | return nil, fmt.Errorf("xds: fetching trusted roots from CertificateProvider failed: %v", err) |
| 183 | } |
| 184 | cfg.RootCAs = km.Roots |
| 185 | |
| 186 | // If AutoHostSNI is true, and the endpoint hostname is present, we use the |
| 187 | // endpoint hostname as the SNI value and also for SAN validation. |
| 188 | // Otherwise, we use the SNI value from HandshakeInfo (which is configured |
| 189 | // by the control plane) and validating SANs based on that. |
| 190 | sni := hi.sni |
| 191 | if hi.useAutoHostSNI && hostname != "" { |
| 192 | sni = hostname |
| 193 | } |
| 194 | |
| 195 | cfg.VerifyPeerCertificate = hi.buildVerifyFunc(km, true, sni) |
| 196 | |
| 197 | if idProv != nil { |
| 198 | km, err := idProv.KeyMaterial(ctx) |
| 199 | if err != nil { |
| 200 | return nil, fmt.Errorf("xds: fetching identity certificates from CertificateProvider failed: %v", err) |
| 201 | } |
| 202 | cfg.Certificates = km.Certs |
| 203 | } |
| 204 | |
| 205 | if envconfig.XDSSNIEnabled && sni != "" { |
| 206 | cfg.ServerName = sni |
| 207 | } |
| 208 | return cfg, nil |
| 209 | } |
| 210 | |
| 211 | func (hi *HandshakeInfo) buildVerifyFunc(km *certprovider.KeyMaterial, isClient bool, sni string) func(rawCerts [][]byte, _ [][]*x509.Certificate) error { |
| 212 | return func(rawCerts [][]byte, _ [][]*x509.Certificate) error { |