[PATCH] Add provision to fetch certificate chain from Nginx

CHHABRA Mandeep Singh mandeep-singh.chhabra at thalesgroup.com
Tue Dec 28 11:56:50 UTC 2021


# HG changeset patch
# User Mandeep Singh Chhabra <mandeep-singh.chhabra at thalesgroup.com>
# Date 1640691269 -19800
#      Tue Dec 28 17:04:29 2021 +0530
# Node ID 9baaef976ac80f05107b60801ebe6559cdb2cbc6
# Parent  b002ad258f1d70924dc13d8f4bc0cc44362f0d0a
Add provision to fetch certificate chain from Nginx

The change adds a new variable ('ssl_client_cert_chain') to the
existing set of variables. It is being part of the http's SSL
module. With this, the middleware can fetch the certificate chain
from Nginx using the variable mentioned. The variable returns
a verified chain of certificates.
If the trust anchor is a root certificate (self signed) which has
issued an intermediate certificate and the client certificate is
issued by the intermediate certificate. The variable ('ssl_client_cert_chain')
will return three certificates (rootCert -> intermediateCert -> clientCert)

diff -r b002ad258f1d -r 9baaef976ac8 src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c         Mon Dec 27 19:49:26 2021 +0300
+++ b/src/event/ngx_event_openssl.c      Tue Dec 28 17:04:29 2021 +0530
@@ -5048,6 +5048,99 @@
     return NGX_ERROR;
}
+ngx_int_t
+ngx_ssl_get_verified_certificate_chain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    size_t   len;
+    BIO     *bio;
+    X509    *cert;
+    STACK_OF(X509)    *certs;
+
+    s->len = 0;
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed");
+        return NGX_ERROR;
+    }
+
+    certs = SSL_get0_verified_chain(c->ssl->connection);
+    if (certs == NULL) {
+        ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_get0_verified_chain failed");
+        goto failed;
+    } else {
+        for (int i = 0; i < sk_X509_num(certs); i++) {
+            cert = sk_X509_value(certs, i);
+
+            if (PEM_write_bio_X509(bio, cert) == 0) {
+                ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "PEM_write_bio_X509() failed");
+                goto failed;
+            }
+        }
+    }
+
+    len = BIO_pending(bio);
+    s->len = len;
+
+    s->data = ngx_pnalloc(pool, len);
+    if (s->data == NULL) {
+        goto failed;
+    }
+
+    BIO_read(bio, s->data, len);
+    BIO_free(bio);
+
+    return NGX_OK;
+
+failed:
+    BIO_free(bio);
+
+    return NGX_ERROR;
+}
+
+ngx_int_t
+ngx_ssl_get_client_certificate_chain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    u_char      *p;
+    size_t       len;
+    ngx_uint_t   i;
+    ngx_str_t    cert_chain;
+
+    if (ngx_ssl_get_verified_certificate_chain(c, pool, &cert_chain) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    if (cert_chain.len == 0) {
+        s->len = 0;
+        return NGX_OK;
+    }
+
+    len = cert_chain.len - 1;
+
+    for (i = 0; i < cert_chain.len - 1; i++) {
+        if (cert_chain.data[i] == LF) {
+            len++;
+        }
+    }
+
+    s->len = len;
+    s->data = ngx_pnalloc(pool, len);
+    if (s->data == NULL) {
+        ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "ngx_pnalloc failed");
+        return NGX_ERROR;
+    }
+
+    p = s->data;
+
+    for (i = 0; i < cert_chain.len - 1; i++) {
+        *p++ = cert_chain.data[i];
+        if (cert_chain.data[i] == LF) {
+            *p++ = '\t';
+        }
+    }
+
+    return NGX_OK;
+}
 ngx_int_t
ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
diff -r b002ad258f1d -r 9baaef976ac8 src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h        Mon Dec 27 19:49:26 2021 +0300
+++ b/src/event/ngx_event_openssl.h     Tue Dec 28 17:04:29 2021 +0530
@@ -276,6 +276,8 @@
     ngx_str_t *s);
ngx_int_t ngx_ssl_get_escaped_certificate(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_client_certificate_chain(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool,
diff -r b002ad258f1d -r 9baaef976ac8 src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c    Mon Dec 27 19:49:26 2021 +0300
+++ b/src/http/modules/ngx_http_ssl_module.c                Tue Dec 28 17:04:29 2021 +0530
@@ -370,6 +370,10 @@
     { ngx_string("ssl_client_raw_cert"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_raw_certificate,
       NGX_HTTP_VAR_CHANGEABLE, 0 },
+
+    { ngx_string("ssl_client_cert_chain"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_certificate_chain,
+      NGX_HTTP_VAR_CHANGEABLE, 0 },
     { ngx_string("ssl_client_escaped_cert"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_escaped_certificate,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20211228/c87cd12c/attachment-0001.htm>


More information about the nginx-devel mailing list