Add new, corporate friendly, SSL client certificate variables.

Dave Bevan dave.bevan at bbc.co.uk
Mon Feb 20 10:20:07 UTC 2017


# HG changeset patch
# User Dave Bevan <dave.bevan at bbc.co.uk>
# Date 1487584846 0
#      Mon Feb 20 10:00:46 2017 +0000
# Node ID 06bd70321e25e01574e406095ff5f21f56b571da
# Parent  87cf6ddb41c216876d13cffa5e637a61b159362c
Add new, corporate friendly, SSL client certificate variables.

Introduce three new SSL variables:

 * ssl_client_ms_upn (extracts Microsoft UserPrincipleName from client cert)
 * ssl_client_email  (extracts email from client cert)
 * ssl_client_s_cn   (extracts Subject Common Name from client cert)

These are particularly useful in corporate environments, and bring some parity
with Apache facilities (particularly ms_upn extract).

diff -r 87cf6ddb41c2 -r 06bd70321e25 src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c	Fri Feb 17 17:01:27 2017 +0300
+++ b/src/event/ngx_event_openssl.c	Mon Feb 20 10:00:46 2017 +0000
@@ -4081,6 +4081,150 @@
 }
 
 
+ngx_int_t
+ngx_ssl_get_client_ms_upn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    int                      i;
+    BIO                     *bio;
+    X509                    *cert;
+    GENERAL_NAME            *altname;
+    STACK_OF(GENERAL_NAME)  *altnames;
+
+    s->len = 0;
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+    if (cert == NULL) {
+        return NGX_OK;
+    }
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        X509_free(cert);
+        return NGX_ERROR;
+    }
+
+    altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+    if (altnames) {
+        for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
+            altname = sk_GENERAL_NAME_value(altnames, i);
+
+            if (altname->type != GEN_OTHERNAME) {
+                continue;
+            }
+
+            if (NID_ms_upn != OBJ_obj2nid(altname->d.otherName->type_id)) {
+                continue;
+            }
+
+            BIO_printf(bio, "%s",
+                (char*)ASN1_STRING_data(altname->d.otherName->value->value.asn1_string));
+        }
+    }
+
+    s->len = BIO_pending(bio);
+    s->data = ngx_pnalloc(pool, s->len);
+
+    BIO_read(bio, s->data, s->len);
+    BIO_free(bio);
+    X509_free(cert);
+    GENERAL_NAMES_free(altnames);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_ssl_get_client_email(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    unsigned int               i;
+    BIO                       *bio;
+    X509                      *cert;
+    STACK_OF(OPENSSL_STRING)  *emails;
+
+    s->len = 0;
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+    if (cert == NULL) {
+        return NGX_OK;
+    }
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        X509_free(cert);
+        return NGX_ERROR;
+    }
+
+    emails = X509_get1_email(cert);
+
+    for (i = 0; i < (unsigned int)sk_OPENSSL_STRING_num(emails); i++) {
+        BIO_printf(bio, "%s",
+            sk_OPENSSL_STRING_value(emails, i));
+        break;
+    }
+
+    s->len = BIO_pending(bio);
+    s->data = ngx_pnalloc(pool, s->len);
+
+    BIO_read(bio, s->data, s->len);
+    BIO_free(bio);
+    X509_free(cert);
+    X509_email_free(emails);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_ssl_get_client_s_cn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    int                        i;
+    BIO                       *bio;
+    X509                      *cert;
+    X509_NAME                 *name;
+    X509_NAME_ENTRY           *cn;
+
+    s->len = 0;
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+    if (cert == NULL) {
+        return NGX_OK;
+    }
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        X509_free(cert);
+        return NGX_ERROR;
+    }
+
+    name = X509_get_subject_name(cert);
+
+    if (name != NULL) {
+        i = -1;
+        for ( ;; ) {
+            i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
+
+            if (i < 0) {
+                break;
+            }
+
+            cn = X509_NAME_get_entry(name, i);
+            BIO_printf(bio, "%s",
+                ASN1_STRING_data(X509_NAME_ENTRY_get_data(cn)));
+        }
+    }
+
+    s->len = BIO_pending(bio);
+    s->data = ngx_pnalloc(pool, s->len);
+
+    BIO_read(bio, s->data, s->len);
+    BIO_free(bio);
+    X509_free(cert);
+
+    return NGX_OK;
+}
+
+
 static time_t
 ngx_ssl_parse_time(
 #if OPENSSL_VERSION_NUMBER > 0x10100000L
diff -r 87cf6ddb41c2 -r 06bd70321e25 src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h	Fri Feb 17 17:01:27 2017 +0300
+++ b/src/event/ngx_event_openssl.h	Mon Feb 20 10:00:46 2017 +0000
@@ -226,6 +226,12 @@
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_client_ms_upn(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
+ngx_int_t ngx_ssl_get_client_email(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
+ngx_int_t ngx_ssl_get_client_s_cn(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 
 
 ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
diff -r 87cf6ddb41c2 -r 06bd70321e25 src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c	Fri Feb 17 17:01:27 2017 +0300
+++ b/src/http/modules/ngx_http_ssl_module.c	Mon Feb 20 10:00:46 2017 +0000
@@ -328,6 +328,15 @@
     { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_client_ms_upn"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_ms_upn, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
+    { ngx_string("ssl_client_email"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_email, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
+    { ngx_string("ssl_client_s_cn"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_s_cn, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
diff -r 87cf6ddb41c2 -r 06bd70321e25 src/stream/ngx_stream_ssl_module.c
--- a/src/stream/ngx_stream_ssl_module.c	Fri Feb 17 17:01:27 2017 +0300
+++ b/src/stream/ngx_stream_ssl_module.c	Mon Feb 20 10:00:46 2017 +0000
@@ -272,6 +272,15 @@
     { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable,
       (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_client_ms_upn"), NULL, ngx_stream_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_ms_upn, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+    { ngx_string("ssl_client_email"), NULL, ngx_stream_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_email, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+    { ngx_string("ssl_client_s_cn"), NULL, ngx_stream_ssl_variable,
+      (uintptr_t) ngx_ssl_get_client_s_cn, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
     { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 


More information about the nginx-devel mailing list