caddy: "invalid header field value" when including http.request.tls.client.certificate_pem placeholder in a header
Caddy version: v2.2.0 h1:sMUFqTbVIRlmA8NkFnNt9l7s0e+0gw+7GPIrhty905A=
I am trying to pass pem-encoded client certificate to proxied service via a X-SSL-Cert header, like so:
sub.example.com {
reverse_proxy 127.0.0.1:8000 {
header_up X-SSL-Cert {http.request.tls.client.certificate_pem}
}
tls {
client_auth {
mode require
}
}
}
I am trying to use recently added client.certificate_pem placeholder (https://github.com/caddyserver/caddy/pull/3662/commits/497c3f785772b0017c525ef6de587eeba4aec4dc#diff-18e521e381018c19bda45164dcad2b9cR347 ) which, if I understand correctly, is synonymous to apache’s SSL_CLIENT_CERT (i.e. in an apache config one would write RequestHeader set X-SSL-Cert "%{SSL_CLIENT_CERT}s").
But for the given Caddyfile I get a 502 Bad Gateway with the following error in the logs:
Sep 30 19:11:55 example.guest caddy[9838]:
{
"level": "error",
"ts": 1601493115.886311,
"logger": "http.log.error",
"msg": "net/http: invalid header field value \"-----BEGIN CERTIFICATE-----\\nMIIG... certificate content...-----END CERTIFICATE-----\\n\" for key X-Ssl-Cert",
"duration": 0.000691328,
"status": 502,
"err_id": "gys3swkea",
"err_trace": "reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:440)"
}
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 36 (25 by maintainers)
Only when used in a header, which it may not necessarily be. Placeholders can be used almost anywhere in the config.
My understanding is that it fails because
\nis a control character andhttpguts.ValidHeaderFieldValue(h)rejects control characters.The problem is there’s no standard for how header values should be encoded if they have invalid characters. The typical ways are either URL encode or base64 encode, but it depends on the applications which one makes the most sense. If there’s evidence that some apps specifically support URL encoded PEM, then I don’t have a problem adding a placeholder for that.
Did you also see the solution that Martin posted here https://github.com/mcebular/caddy/commit/df63c2d78fc3c2d6daf5ccf8c42a4dc4cc1f4572?
Keycloak supports Nginx, Apache and HAProxy, which can all pass PEM certificates in HTTP headers without failing, unlike Caddy. My ask of Keycloak will essentially boil down to having them patch a solution to support DER. It should be doable but there is no reason why the Keycloak team will need to support this, as a PEM file is well understood.
For now I’ll keep using Martin’s solution and will read through Keycloak’s contribution guidelines tomorrow and make the ask.
@mholt the ask is that the PEM is URL-encoded, i.e. URL-encoding the
\ncharacters, not URL-encoded raw bytes.You could try this maybe, if it requires the ASCII armor to exist
This is the same text as a PEM, but without newlines. That might be fine depending on how Keycloak parses it.
Anyway, I suggest you reach out to Keycloak as well, they should probably be able to support der-base64 as well.
@anestos
Maybe. Depends on the results of the test and the general utility/usefulness of the feature.\
Yeah… we maintainers feel this.
@Ramzec @mc0239 please take a look at PR, we can merge it, but you need to check it first and make sure that it solves the problem
I don’t see the harm in URL encoding it personally. It’ll be more compatible with existing applications written to support the approach Apache and Nginx take with passing through certificates via headers.
If we do the DER approach then it should be called
certificate_der, but I don’t see the harm in addingcertificate_pem_escapedfor those that want it that way.Looks like it hits this check: https://godoc.org/golang.org/x/net/http/httpguts#ValidHeaderFieldValue
in https://golang.org/src/net/http/transport.go
I’m not certain how to decipher that 🤔
Edit: Yeah
isCTL()rejects\nas it’s ASCII value is 10 (it rejects 0-31 and 127)Edit2: Looks like HTTP headers use
\r\n(CRLF) for newlines.