Server Name Indication

1. Caddy version (caddy version):

2.4.5

2. How I run Caddy:

I run it in a container mapping volumes to the host

a. System environment:

Docker

b. Command:

caddy run --config /Caddyfile

c. Service/unit/compose file:

Paste full file contents here.
Make sure backticks stay on their own lines,
and the post looks nice in the preview pane.

d. My complete Caddyfile or JSON config:

{
	http_port 8786
	auto_https off
}
:443 {

	tls /data/cert.pem /data/cert.key {
             client_auth {
                 mode require_and_verify
                 trusted_ca_cert_file /data/ca_cert.pem
        }

	reverse_proxy {
		to http://localhost:3000
	}

    root * /caddyroot
	file_server
	
	handle_errors {
		@502 {
			expression {http.error.status_code} == 502
		}
		rewrite @502 /502.html
		file_server

	}
}

3. The problem I’m having:

Trying to enable client authentication with tls directive. The website is on the localhost and the authentication works if I use “localhost” in the browser URL (https://localhost:443). If I try to use the IP address (https://192.168.1.23:443) the certificate verifies but no web page presents. The output of caddy explains that “strict host matching: TLS ServerName() and HTTP Host (192.168.1.23) values differ” How do I get the TLS Server Name to match or how do I disable strict host matching with client authentication?

4. Error messages and/or full log output:

“strict host matching: TLS ServerName() and HTTP Host (192.168.1.23) values differ”

5. What I already tried:

changing localhost to the IP address in reverse_proxy directive. Same result

6. Links to relevant resources:

When you enable client auth, it implicitly enables strict SNI host matching. A comment in the code explains why:

So your request needs to exactly match the name in the server certificate. If your certificate is for localhost but you make a request with an IP address, that won’t work.

Also, it looks like you’re missing a closing } for the tls directive.

1 Like

Sir–thank you for the response. I knew that Strict SNI was enabled by following the go code as well as forum discussions. But I figured I could map/rewrite/force the Host name or the TLS ServerName to be equal to each other through some caddyfile directive.

Or, for now, since I am generating self signed certificates for the server it would be fine to know what openssl generation setting I’d need to set to make the TLS ServerName equal to the host IP address entered into the browser if that is possible. Changing the cert CN didn’t seem to change anything so I am not sure what caddy is expecting to match against when I enter the IP address as the URL in the browser and how I can make that work through some technique

Thank you again

The CN field on certs is deprecated for TLS, it’s the SAN field that’s looked at.

Thank you for the response. Yes, I was thinking so but I was having trouble adding a SAN extension to the certificate with openssl. I also wonder if SAN can be an IP address or does it have to be a domain or name. I will give it another look. Thanks again.

I have verified that my server certificate has the IP address as an alternative name but I still get the same error when I use the IP address as the URL:
“strict host matching: TLS ServerName() and HTTP Host (172.16.10.37) values differ”

But the server certificate used by caddy now has this output when I issue this command:

openssl x509 -noout -text -in server.pem | grep -A 1 “Subject Alternative Name”

X509v3 Subject Alternative Name:
IP Address:172.16.10.37

So I believe that the Server Name should be known by it’s IP address but Caddy still cannot find it. What server cert attribute should I be using to inform caddy that the server IP address is the TLS ServerName too?

I suppose the overarching question, given my reverse proxy setup, how might I do client authentication when the server I access is specified by an IP address which is a common situation for what I am addressing.

Thanks again.

Apparently SNI doesn’t support anything other than DNS names, as per the RFC, so browsers don’t set the IP address in that field:

Currently, the only server names supported are DNS hostnames

Literal IPv4 and IPv6 addresses are not permitted in “HostName”.

So you would have to turn off strict SNI to do what you want, (but that has other implications, as the comment in the code I linked above outlines).

The Caddyfile adapter also doesn’t let you explicitly turn off strict_sni_host, it only lets you explicitly turn it on. But I just opened a pull request to fix this httpcaddyfile: Support explicitly turning off `strict_sni_host` by francislavoie · Pull Request #4592 · caddyserver/caddy · GitHub

Another workaround is you can set the default_sni global option to set a default SNI if it was empty: Global options (Caddyfile) — Caddy Documentation

But I’d suggest you reconsider if you really need to use direct IP addresses for this, or whether you can just use a proper DNS hostname all the time, which wouldn’t have this problem.

Thank you again. I was afraid of that. It seems the default_sni only works if the browser doesn’t provide anything in the client hello which most seem to do these days.

I will examine the RFC closely but I did find here Steps to generate CSR for SAN certificate with openssl | GoLinuxCloud a way to provide IP addresses as alternative names in certificates and used the sample config file tailored to my needs. At least when reading the cert back it seemed to report the IP address as an alternative Name. Here is the relevant part of the config file:

[req]
req_extensions = req_ext
[req_ext]
subjectAltName = @alt_names
[alt_names]
IP.1 = 10.10.10.13
IP.2 = 10.10.10.14
IP.3 = 10.10.10.17
DNS.1 = centos8-2.example.com
DNS.2 = centos8-3.example.com

For the particular needs I am faced with there is some requirement to authenticate clients in a closed network often without DNS service. The servers are identified with IP address only. If I could override strict SNI I would do so but Caddy enforces it if client authentication is being used. Is there a config way of turning it off?

Thanks for your help. It’s been exasperating but maybe it’s just not possible to do and knowing that at least I can stop banging my head against a wall

Yes, like I wrote above, only in JSON currently but it will be possible in Caddyfile with the PR I just opened.

Excellent–thank you very much. I may try to synthesize a “hostname” and see if I can at least prove this out (i.e., document the mechanics of creating the certs according to the requirements of client authentication). I read the RFC 6066 and it repeats the same restrictions on hostname above.

Thanks again!

P.S. No matter what I did the TLS ServerName reported in the error message was always (). Is there a way to force this to be the IP address for testing purposes?

That’s what default_sni is for.

But you can’t force browsers to set it.

This topic was automatically closed after 30 days. New replies are no longer allowed.