<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>