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

An equivalent of Apache's +ExportCertData in Caddy #6713

Open
Marian-Kechlibar opened this issue Nov 27, 2024 · 6 comments
Open

An equivalent of Apache's +ExportCertData in Caddy #6713

Marian-Kechlibar opened this issue Nov 27, 2024 · 6 comments
Labels
feature ⚙️ New feature or request good first issue 🐤 Good for newcomers

Comments

@Marian-Kechlibar
Copy link

Apache Webserver's mod_ssl has an optional configuration flag +ExportCertData, which is turned off by default (for performance reasons), but when turned on, it populates the superglobals with variables containing the current server and client certificate. To cite from the docs:

When this option is enabled, additional CGI/SSI environment variables are created: SSL_SERVER_CERT, SSL_CLIENT_CERT and SSL_CLIENT_CERT_CHAIN_n (with n = 0,1,2,..). These contain the PEM-encoded X.509 Certificates of server and client for the current HTTPS connection and can be used by CGI scripts for deeper Certificate checking. Additionally all other certificates of the client certificate chain are provided, too. This bloats up the environment a little bit which is why you have to use this option to enable it on demand.

This would be useful in Caddy too, as it would make migration of Apache-optimized apps to Caddy more straightforward. We had a debate with @francislavoie about the functionality here and I made case that it makes sense to have access to the server-side cert as well.

https://caddy.community/t/populating-server-server-cert-and-server-client-cert/26521

He recommended me to start an Issue on GitHub, so here I am. I know next to nothing about Caddy code, so I dare not submit a Pull request for that functionality.

@francislavoie francislavoie added feature ⚙️ New feature or request good first issue 🐤 Good for newcomers labels Nov 27, 2024
@mholt
Copy link
Member

mholt commented Dec 4, 2024

Thanks -- to clarify, it looks like, based on the forum topic, the request is actually for placeholders containing server cert info.

@Marian-Kechlibar
Copy link
Author

Marian-Kechlibar commented Dec 4, 2024

Yes. it is.

Meanwhile, I was able to use the placeholder for the client certificate, but with some unexpected behavior, which may warrant its own issue...

Namely, when I enter the following into my Caddyfile:

request_header +X-Tls-Client-Cert-Der-Base64 {http.request.tls.client.certificate_der_base64}

the request header gets added even if there is no client cert provided, and populated with the literal "{http.request.tls.client.certificate_der_base64}"

That is unexpected for me. I would expect the header either to be absent, or empty in that case. (If HTTP allows empty headers; IDK). Should I start another topic over that purpose?

@mholt
Copy link
Member

mholt commented Dec 4, 2024

Ah, that's because in the header directive(s) only known placeholders are replaced. If there is no client certificate, the placeholder is not set.

We can change this in one of two ways:

  • Always replace placeholder-looking substrings, but this is problematic (syntactically) for values that aren't intended to be placeholders (e.g. JSON)
  • Replacers return two values: the value, and whether the key (placeholder name) is known. We are evidently returning false to known, when there is no client cert. It is kind of debatable whether that is correct. We could return true as in, we know this placeholder, but do we really if there is no client auth?

I'm leaning towards the second though, if we do make a change.

@Marian-Kechlibar
Copy link
Author

Ah, that's because in the header directive(s) only known placeholders are replaced. If there is no client certificate, the placeholder is not set.

We can change this in one of two ways:

  • Always replace placeholder-looking substrings, but this is problematic (syntactically) for values that aren't intended to be placeholders (e.g. JSON)
  • Replacers return two values: the value, and whether the key (placeholder name) is known. We are evidently returning false to known, when there is no client cert. It is kind of debatable whether that is correct. We could return true as in, we know this placeholder, but do we really if there is no client auth?

I'm leaning towards the second though, if we do make a change.

The second variant feels more natural to me, too.

@steffenbusch
Copy link
Contributor

Can you try this:

@hasClientCert {
       not vars {http.request.tls.client.certificate_der_base64} ""
}
request_header @hasClientCert +X-Tls-Client-Cert-Der-Base64 {http.request.tls.client.certificate_der_base64}

@mholt
Copy link
Member

mholt commented Dec 10, 2024

Thanks for the workaround @steffenbusch !

I suppose we could still change the placeholders behavior in the case of client auth missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ⚙️ New feature or request good first issue 🐤 Good for newcomers
Projects
None yet
Development

No branches or pull requests

4 participants