Proposed changeset to fix client cert from ngx_ssl_get_certificate passed as HTTP header value

Maxim Dounin mdounin at mdounin.ru
Thu Feb 4 18:29:28 UTC 2016


Hello!

On Thu, Feb 04, 2016 at 09:17:31AM -0800, Sam McKelvie wrote:

> > Hello!
> >
> > On Wed, Feb 03, 2016 at 03:38:13PM -0800, Sam McKelvie wrote:
> >
> >> The ngx_ssl_get_certificate() changes ?\n? to ?\n\t? in the returned PEM string in an effort to make
> >> the string usable as an HTTP header value with $ssl_client_cert. However, bare ?\n? (without a preceding ?\r?) is passed
> >> along as ?\n\t". This causes some HTTP servers (including node/express) to hang up. This changeset
> >> fixes the problem by replacing occurrences of ?\n? that have no preceding ?\r? with "\r\n\t".
> >>
> >> Tested with node.js/express and nginx-tests.
> >>
> >> I should note that a similar solution was proposed at https://forum.nginx.org/read.php?29,249804,249833 <https://forum.nginx.org/read.php?29,249804,249833>, but the thread never went anywhere.
> >> This solution is slightly more paranoid with edge cases and does not insert extra ?\r? characters if they are already present.
> >
> > IMHO, header line folding is wrong enough to don't bother with
> > trying to fix this.  It doesn't work in way too many cases
> > including with nginx itself, and it is deprecated by RFC7230.
> >
> > Much better approach would be to switch to something different -
> > may be just properly urlencoded $ssl_client_raw_cert, or plain
> > base64 without any newlines, or whatever.
> >
> I tend to agree. However, nix_ssl_get_certificate() is already folding
> the certificate for HTTP headers by inserting '\t' at the beginning of
> each line, so that seems to be its primary purpose. I can’t change
> that function to return anything that is not itself a valid PEM
> certificate, or it would certainly break any existing applications
> that parse the results. So unless you think it is OK to tweak it to
> insert '\r' as well,  I think you are saying this function is just
> permanently unusable for the purposes of passing a certificate in a
> header.

Current implementation is usable where it is currently used.  Most 
servers happen to parse "\n" without "\r" just fine.  RFC2616 
explicitly recommends applications to accept bare LF,
http://tools.ietf.org/html/rfc2616#section-19.3:

   The line terminator for message-header fields is the sequence CRLF.
   However, we recommend that applications, when parsing such headers,
   recognize a single LF as a line terminator and ignore the leading CR.

On the other hand, any changes, even minor ones like adding "\r", 
may break existing applications who use $ssl_client_cert.  And if 
we are goint to introduce changes - it's better to change it 
something more useable than header folding.

> Would you be more amenable to defining a new "$ssl_base64_client_cert"
> or “$ssl_escaped_client_cert” variable that is a properly encoded PEM
> string? Would you prefer base64 (which would greatly increase the
> size) or a quoted-string for with backslashes to escape control
> characters? I would be willing to submit such a changeset…

For sure base64-encoded PEM is not something we want, that would 
be double base64 encoding and makes no sense.  Base64-encoded DER 
(== PEM without header/footer/newlines) may be an option.

I tend to think that we want to use URI escaping here.  We already 
do this in mail for Auth-SSL-Cert header, with minimal escaping.  
As we don't know context for the variable - it probably would be a 
better option to escape it as an URI component.

Tricky part here is to understand what we are going to do with the 
$ssl_client_cert variable.  I don't like the idea of preserving it 
in "PEM with tab added for header folding" forever.

-- 
Maxim Dounin
http://nginx.org/



More information about the nginx-devel mailing list