<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">The ngx_ssl_get_certificate() changes “\n” to “\n\t” in the returned PEM string in an effort to make</div><div class="">the string usable as an HTTP header value with $ssl_client_cert. However, bare ‘\n’ (without a preceding ‘\r’) is passed</div><div class="">along as “\n\t". This causes some HTTP servers (including node/express) to hang up. This changeset</div><div class="">fixes the problem by replacing occurrences of ‘\n’ that have no preceding ‘\r’ with "\r\n\t".</div><div class=""><br class=""></div><div class=""><div class="">Tested with node.js/express and nginx-tests.</div></div><div class=""><br class=""></div><div class="">I should note that a similar solution was proposed at <a href="https://forum.nginx.org/read.php?29,249804,249833" class="">https://forum.nginx.org/read.php?29,249804,249833</a>, but the thread never went anywhere.</div><div class="">This solution is slightly more paranoid with edge cases and does not insert extra ‘\r’ characters if they are already present.</div><div class=""><br class=""></div><div class="">Thank you,</div><div class="">Sam McKelvie</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""># HG changeset patch</div><div class=""># User Sam McKelvie <<a href="mailto:sam@surround.io" class="">sam@surround.io</a>></div><div class=""># Date 1454541255 28800</div><div class=""># Wed Feb 03 15:14:15 2016 -0800</div><div class=""># Node ID d70dae44196b5625f10080b4b869f33adbb83f54</div><div class=""># Parent 0e0e2e522fa2cb439b636a2c19aca5bdfbe8704f</div><div class="">Fix ngx_ssl_get_certificate to properly format for HTTP header value.</div><div class=""><br class=""></div><div class="">Previously, the value could contain lines ending in '\n' rather than</div><div class="">'\r\n'. This caused some HTTP servers, including node/express, to</div><div class="">reject the request entirely.</div><div class=""><br class=""></div><div class="">Now, instances of bare '\n' are replaced with "\r\n\t". Instances of</div><div class="">"\r\n" are still replaced with "\r\n\t".</div><div class=""><br class=""></div><div class="">Tested with node.js/express and nginx-tests.</div><div class=""><br class=""></div><div class="">diff -r 0e0e2e522fa2 -r d70dae44196b src/event/ngx_event_openssl.c</div><div class="">--- a/src/event/ngx_event_openssl.c<span class="Apple-tab-span" style="white-space:pre"> </span>Tue Feb 02 16:33:55 2016 +0300</div><div class="">+++ b/src/event/ngx_event_openssl.c<span class="Apple-tab-span" style="white-space:pre"> </span>Wed Feb 03 15:14:15 2016 -0800</div><div class="">@@ -3212,7 +3212,10 @@</div><div class=""> goto failed;</div><div class=""> }</div><div class=""> </div><div class="">- BIO_read(bio, s->data, len);</div><div class="">+ if (BIO_read(bio, s->data, len) != (int)len) {</div><div class="">+ ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_read() failed");</div><div class="">+ goto failed;</div><div class="">+ }</div><div class=""> </div><div class=""> BIO_free(bio);</div><div class=""> X509_free(cert);</div><div class="">@@ -3235,22 +3238,41 @@</div><div class=""> size_t len;</div><div class=""> ngx_uint_t i;</div><div class=""> ngx_str_t cert;</div><div class="">+ int prev_cr;</div><div class=""> </div><div class=""> if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) {</div><div class=""> return NGX_ERROR;</div><div class=""> }</div><div class=""> </div><div class="">+ /* Strip off trailing whitespace (last newline) from the cert */</div><div class="">+ while (cert.len > 0 && (</div><div class="">+ cert.data[cert.len-1] == CR ||</div><div class="">+ cert.data[cert.len-1] == LF ||</div><div class="">+ cert.data[cert.len-1] == ' ')) {</div><div class="">+ --cert.len;</div><div class="">+ }</div><div class="">+</div><div class=""> if (cert.len == 0) {</div><div class=""> s->len = 0;</div><div class=""> return NGX_OK;</div><div class=""> }</div><div class=""> </div><div class="">- len = cert.len - 1;</div><div class="">-</div><div class="">- for (i = 0; i < cert.len - 1; i++) {</div><div class="">+ /* </div><div class="">+ * To make PEM text compatible as an HTTP header value, convert</div><div class="">+ * "\r\n" to "\r\n\t", and convert "\n" to "\r\n\t". Bare '\n'</div><div class="">+ * is rejected by some HTTP servers including node/express. </div><div class="">+ */ </div><div class="">+ prev_cr = 0;</div><div class="">+ len = 0;</div><div class="">+ for (i = 0; i < cert.len; i++) {</div><div class=""> if (cert.data[i] == LF) {</div><div class="">- len++;</div><div class="">+ if (!prev_cr) {</div><div class="">+ len++; /* Insert CR before LF*/</div><div class="">+ }</div><div class="">+ len++; /* Insert '\t' after LF */</div><div class=""> }</div><div class="">+ len++;</div><div class="">+ prev_cr = (cert.data[i] == CR);</div><div class=""> }</div><div class=""> </div><div class=""> s->len = len;</div><div class="">@@ -3261,11 +3283,18 @@</div><div class=""> </div><div class=""> p = s->data;</div><div class=""> </div><div class="">- for (i = 0; i < cert.len - 1; i++) {</div><div class="">+ prev_cr = 0;</div><div class="">+ for (i = 0; i < cert.len; i++) {</div><div class="">+ if (cert.data[i] == LF) {</div><div class="">+ if (!prev_cr) {</div><div class="">+ *p++ = CR;</div><div class="">+ }</div><div class="">+ *p++ = LF;</div><div class="">+ *p++ = '\t';</div><div class="">+ } else {</div><div class=""> *p++ = cert.data[i];</div><div class="">- if (cert.data[i] == LF) {</div><div class="">- *p++ = '\t';</div><div class="">- }</div><div class="">+ }</div><div class="">+ prev_cr = (cert.data[i] == CR);</div><div class=""> }</div><div class=""> </div><div class=""> return NGX_OK;</div><div class=""><br class=""></div><div class=""><br class=""></div></body></html>