Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does caddy support ECDSA+RSA certificates without a manager? #5450

Closed
ryancdotorg opened this issue Mar 21, 2023 · 4 comments
Closed

Does caddy support ECDSA+RSA certificates without a manager? #5450

ryancdotorg opened this issue Mar 21, 2023 · 4 comments
Labels
invalid ❓ This doesn't seem right

Comments

@ryancdotorg
Copy link

This seems to have been brought up in #1575, which was closed, however I don't see any way to actually configure this.

If I specify tls twice, then start caddy 2.6.4 with debug enabled, I can see that it's loading both certificates, but then the first certificate seems to always be chosen, with no cipher suite supported by both client and server being logged if I try to connect with a cipher suite not supporting it.

I have enabled both RSA and ECDSA cipher suites explicitly.

commands to create keys and self-signed certificates

openssl req -x509 -nodes -sha256 -batch -subj '/CN=example.invalid' -newkey rsa:2048 -keyout example.rsa.key -out example.rsa.pem -days 90
openssl req -x509 -nodes -sha256 -batch -subj '/CN=example.invalid' -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout example.ecdsa.key -out example.ecdsa.pem -days 90

Caddyfile

{
        debug
        local_certs
        https_port 8443
        servers :8443 {
                name http
                protocols h2 h1
        }
}

example.invalid {
        tls example.rsa.pem example.rsa.key
        tls example.ecdsa.pem example.ecdsa.key {
                ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_EC
DHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECD
HE_RSA_WITH_AES_256_CBC_SHA
        }
        respond "Hello, HTTP/2!"
}

openssl s_client commands to test connection

openssl s_client -cipher aECDSA -sigalgs ECDSA+SHA256 -tls1_2 -servername example.invalid -alpn h2,http/1.1 -connect 127.0.0.1:8443 < /dev/null
openssl s_client -cipher aRSA -sigalgs RSA+SHA256 -tls1_2 -servername example.invalid -alpn h2,http/1.1 -connect 127.0.0.1:8443 < /dev/null

I see from the code it's using certmagic.DefaultCertificateSelector, which in turn calls ClientHelloInfo.SupportsCertificate, which appears to do the right thing.

Here's the log output from starting caddy, then trying ECDSA (which fails) and RSA (which works) in turn:

2023/03/21 16:51:54.049 INFO    using provided configuration    {"config_file": "Caddyfile2", "config_adapter": ""}
2023/03/21 16:51:54.050 INFO    admin   admin endpoint started  {"address": "localhost:2019", "enforce_origin": false, "origins": ["//[::1]:2019", "//127.0.0.1:2019", "//localhost:2019"]}
2023/03/21 16:51:54.051 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [example.invalid]: no OCSP server specified in certificate"}
2023/03/21 16:51:54.051 DEBUG   events  event   {"name": "cached_unmanaged_cert", "id": "0c4997a7-6fdd-4bb7-b2ca-afe7875ae2f8", "origin": "tls", "data": {"sans":["example.invalid"]}}
2023/03/21 16:51:54.051 DEBUG   tls.cache       added certificate to cache      {"subjects": ["example.invalid"], "expiration": "2023/06/19 16:21:18.000", "managed": false, "issuer_key": "", "hash": "a7
916d4b5a3035a12c278eb0654bef9b6c753774a0e68bf5fe5e54877ece78b0", "cache_size": 1, "cache_capacity": 10000}
2023/03/21 16:51:54.051 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [example.invalid]: no OCSP server specified in certificate"}
2023/03/21 16:51:54.051 DEBUG   events  event   {"name": "cached_unmanaged_cert", "id": "067e20da-e75a-4270-aa2d-ff40102b125d", "origin": "tls", "data": {"sans":["example.invalid"]}}
2023/03/21 16:51:54.051 DEBUG   tls.cache       added certificate to cache      {"subjects": ["example.invalid"], "expiration": "2023/06/19 16:26:41.000", "managed": false, "issuer_key": "", "hash": "65
06fc42a3bfb54c17688f740f897e4415bc2c53203e316a15f9f9001db2fc19", "cache_size": 2, "cache_capacity": 10000}
2023/03/21 16:51:54.051 INFO    http    skipping automatic certificate management because one or more matching certificates are already loaded  {"domain": "example.invalid", "server_name": "http"}
2023/03/21 16:51:54.051 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "http"}
2023/03/21 16:51:54.054 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0xc0000b8310"}
2023/03/21 16:51:54.060 INFO    pki.ca.local    root certificate is already trusted by system   {"path": "storage:pki/authorities/local/root.crt"}
2023/03/21 16:51:54.060 DEBUG   http    starting server loop    {"address": "[::]:8443", "tls": true, "http3": false}
2023/03/21 16:51:54.060 INFO    tls     cleaning storage unit   {"description": "FileStorage:/home/user/.local/share/caddy"}
2023/03/21 16:51:54.060 INFO    http.log        server running  {"name": "http", "protocols": ["h2", "h1"]}
2023/03/21 16:51:54.060 DEBUG   http    starting server loop    {"address": "[::]:80", "tls": false, "http3": false}
2023/03/21 16:51:54.060 INFO    http.log        server running  {"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2023/03/21 16:51:54.060 INFO    autosaved config (load with --resume flag)      {"file": "/home/user/.config/caddy/autosave.json"}
2023/03/21 16:51:54.060 INFO    serving initial configuration
2023/03/21 16:51:54.061 INFO    tls     finished cleaning storage units
2023/03/21 16:51:56.837 DEBUG   events  event   {"name": "tls_get_certificate", "id": "3c81bc25-8b62-4510-91b7-2c6e4629d237", "origin": "tls", "data": {"client_hello":{"CipherSuites":[49196,49327,49325,
49195,49326,49324,49188,49187,49162,49161,255],"ServerName":"example.invalid","SupportedCurves":[29,23,30,25,24],"SupportedPoints":"AAEC","SignatureSchemes":[1027],"SupportedProtos":["h2","http/1.1"],"S
upportedVersions":[771,770,769],"Conn":{}}}}
2023/03/21 16:51:56.837 DEBUG   tls.handshake   choosing certificate    {"identifier": "example.invalid", "num_choices": 2}
2023/03/21 16:51:56.837 DEBUG   tls.handshake   custom certificate selection results    {"identifier": "example.invalid", "subjects": ["example.invalid"], "managed": false, "issuer_key": "", "hash": "a7
916d4b5a3035a12c278eb0654bef9b6c753774a0e68bf5fe5e54877ece78b0"}
2023/03/21 16:51:56.837 DEBUG   tls.handshake   matched certificate in cache    {"remote_ip": "127.0.0.1", "remote_port": "52768", "subjects": ["example.invalid"], "managed": false, "expiration": "2023/
06/19 16:21:18.000", "hash": "a7916d4b5a3035a12c278eb0654bef9b6c753774a0e68bf5fe5e54877ece78b0"}
2023/03/21 16:51:56.837 DEBUG   http.stdlib     http: TLS handshake error from 127.0.0.1:52768: tls: no cipher suite supported by both client and server
2023/03/21 16:51:58.086 DEBUG   events  event   {"name": "tls_get_certificate", "id": "e95576d7-3a75-4cd9-9693-69ced6d015a8", "origin": "tls", "data": {"client_hello":{"CipherSuites":[49200,49199,49192,
49191,49172,49171,157,49313,49309,156,49312,49308,61,60,53,47,255],"ServerName":"example.invalid","SupportedCurves":[29,23,30,25,24],"SupportedPoints":"AAEC","SignatureSchemes":[1025],"SupportedProtos":
["h2","http/1.1"],"SupportedVersions":[771,770,769],"Conn":{}}}}
2023/03/21 16:51:58.086 DEBUG   tls.handshake   choosing certificate    {"identifier": "example.invalid", "num_choices": 2}
2023/03/21 16:51:58.086 DEBUG   tls.handshake   custom certificate selection results    {"identifier": "example.invalid", "subjects": ["example.invalid"], "managed": false, "issuer_key": "", "hash": "a7
916d4b5a3035a12c278eb0654bef9b6c753774a0e68bf5fe5e54877ece78b0"}
2023/03/21 16:51:58.086 DEBUG   tls.handshake   matched certificate in cache    {"remote_ip": "127.0.0.1", "remote_port": "56370", "subjects": ["example.invalid"], "managed": false, "expiration": "2023/
06/19 16:21:18.000", "hash": "a7916d4b5a3035a12c278eb0654bef9b6c753774a0e68bf5fe5e54877ece78b0"}

Am I missing something?

I tried curl as well, but switched to s_client to make sure signature schemes was being set appropriately.

@ryancdotorg
Copy link
Author

ryancdotorg commented Mar 21, 2023

Digging into the golang source, I am checking whether this is because my test certs lack a subject_alternative_name.

@ryancdotorg
Copy link
Author

ryancdotorg commented Mar 21, 2023

Yeah, this is a golang... I'm not even sure if it's fair to call it a bug.

Not Caddy's fault.

If I generate certificates like so:

openssl req -x509 -nodes -batch -subj '/CN=example.invalid' -addext "subjectAltName = DNS:example.invalid" -newkey rsa:2048 -keyout example.rsa.key
 -out example.rsa.pem -days 90
openssl req -x509 -nodes -batch -subj '/CN=example.invalid' -addext "subjectAltName = DNS:example.invalid" -newkey ec -pkeyopt ec_paramgen_curve:pr
ime256v1 -keyout example.ecdsa.key -out example.ecdsa.pem -days 90

It works fine.

@francislavoie
Copy link
Member

Yep - you must use a SAN for Caddy to pick up the cert, because that's what it uses to know what hostnames the certificate supports. The subject field is deprecated in clients, and not used at all in Caddy.

@francislavoie francislavoie added the invalid ❓ This doesn't seem right label Mar 21, 2023
@ryancdotorg
Copy link
Author

The sad thing is I already knew the subject field is deprecated, and even wrote a tool in python for generating certificates acceptable for modern software, but then was lazy and used openssl. 🤦

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid ❓ This doesn't seem right
Projects
None yet
Development

No branches or pull requests

2 participants