From 947eb5f2f5ce0daadadf0eb73dd8eebe46e82732 Mon Sep 17 00:00:00 2001
From: Francesco Giacomini <giaco at cnaf dot infn dot it>
Date: Mon, 25 Jun 2018 17:14:26 +0200
Subject: [PATCH 1/5] tentative support for ssl_client_ee_s_dn

---
 src/ngx_http_voms_module.cpp | 104 +++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

diff --git a/src/ngx_http_voms_module.cpp b/src/ngx_http_voms_module.cpp
index bc3af26..b6811eb 100644
--- a/src/ngx_http_voms_module.cpp
+++ b/src/ngx_http_voms_module.cpp
@@ -67,6 +67,10 @@ static ngx_int_t generic_getter(  //
     ngx_http_request_t* r,
     ngx_http_variable_value_t* v,
     uintptr_t data);
+static ngx_int_t get_ssl_client_ee_s_dn(  //
+    ngx_http_request_t* r,
+    ngx_http_variable_value_t* v,
+    uintptr_t data);
 
 using getter_t = std::string(VomsAc const& voms);
 static getter_t get_voms_user;
@@ -170,9 +174,109 @@ static ngx_http_variable_t variables[] = {
         NGX_HTTP_VAR_NOCACHEABLE,
         0  //
     },
+    {
+        ngx_string("ssl_client_ee_s_dn"),
+        NULL,
+        get_ssl_client_ee_s_dn,
+        0,
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
     ngx_http_null_variable  //
 };
 
+static std::string to_rfc2253(X509_NAME* name)
+{
+  std::string result;
+
+  BioPtr bio(BIO_new(BIO_s_mem()), &BIO_free);
+  if (!bio) {
+    return result;
+  }
+
+  if (X509_NAME_print_ex(bio.get(), name, 0, XN_FLAG_RFC2253) < 0) {
+    return result;
+  }
+
+  auto len = BIO_pending(bio.get());
+  result.resize(len);
+
+  BIO_read(bio.get(), &result[0], result.size());
+
+  return result;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+uint32_t X509_get_extension_flags(X509* x)
+{
+  return x->ex_flags;
+}
+#endif
+
+static bool is_proxy(X509* cert)
+{
+  return X509_get_extension_flags(cert) & EXFLAG_PROXY;
+}
+
+static ngx_int_t get_ssl_client_ee_s_dn(ngx_http_request_t* r,
+                                        ngx_http_variable_value_t* v,
+                                        uintptr_t data)
+{
+  ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __func__);
+
+  v->not_found = 1;
+  v->valid = 0;
+
+  auto chain = SSL_get_peer_cert_chain(r->connection->ssl->connection);
+  if (!chain) {
+    ngx_log_error(
+        NGX_LOG_ERR, r->connection->log, 0, "SSL_get_peer_cert_chain() failed");
+    return NGX_OK;
+  }
+
+  // find first non-proxy
+  X509* ee_cert = nullptr;
+  for (int i = 0; i != sk_X509_num(chain); ++i) {
+    auto cert = sk_X509_value(chain, i);
+    if (cert && !is_proxy(cert)) {
+      ee_cert = cert;
+      break;
+    }
+  }
+
+  if (!ee_cert) {
+    ngx_log_error(NGX_LOG_DEBUG,
+                  r->connection->log,
+                  0,
+                  "cannot identify end-entity certificate");
+    return NGX_OK;
+  }
+
+  auto dn = X509_get_subject_name(ee_cert);
+  if (!dn) {
+    ngx_log_error(NGX_LOG_DEBUG,
+                  r->connection->log,
+                  0,
+                  "cannot get subject dn from certificate");
+    return NGX_OK;
+  }
+  std::string value = to_rfc2253(dn);
+
+  auto buffer = static_cast<u_char*>(ngx_pnalloc(r->pool, value.size()));
+  if (!buffer) {
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
+    return NGX_OK;
+  }
+  ngx_memcpy(buffer, value.c_str(), value.size());
+
+  v->data = buffer;
+  v->len = value.size();
+  v->valid = 1;
+  v->not_found = 0;
+  v->no_cacheable = 0;
+  return NGX_OK;
+}
+
 static ngx_int_t add_variables(ngx_conf_t* cf)
 {
   for (ngx_http_variable_t* v = variables; v->name.len; ++v) {
-- 
GitLab


From ea3e6196cb857d34c1759844df9c76a346121ef8 Mon Sep 17 00:00:00 2001
From: Andrea Ceccanti <andrea.ceccanti@gmail.com>
Date: Mon, 25 Jun 2018 18:09:59 +0200
Subject: [PATCH 2/5] Support for plain X.509 certs + tests

---
 src/ngx_http_voms_module.cpp |  19 +++--
 t/certs/7.cert.pem           |  67 +++++++++++++++++
 t/certs/7.key.pem            |  15 ++++
 t/certs/7.pem                |  82 +++++++++++++++++++++
 t/certs/8.cert.pem           |  88 +++++++++++++++++++++++
 t/certs/8.key.pem            |  15 ++++
 t/certs/8.pem                | 103 ++++++++++++++++++++++++++
 t/certs/README.md            |   4 +-
 t/eec_subject.t              | 136 +++++++++++++++++++++++++++++++++++
 9 files changed, 521 insertions(+), 8 deletions(-)
 create mode 100644 t/certs/7.cert.pem
 create mode 100644 t/certs/7.key.pem
 create mode 100644 t/certs/7.pem
 create mode 100644 t/certs/8.cert.pem
 create mode 100644 t/certs/8.key.pem
 create mode 100644 t/certs/8.pem
 create mode 100644 t/eec_subject.t

diff --git a/src/ngx_http_voms_module.cpp b/src/ngx_http_voms_module.cpp
index b6811eb..f08cf6e 100644
--- a/src/ngx_http_voms_module.cpp
+++ b/src/ngx_http_voms_module.cpp
@@ -233,14 +233,19 @@ static ngx_int_t get_ssl_client_ee_s_dn(ngx_http_request_t* r,
         NGX_LOG_ERR, r->connection->log, 0, "SSL_get_peer_cert_chain() failed");
     return NGX_OK;
   }
-
-  // find first non-proxy
+  
   X509* ee_cert = nullptr;
-  for (int i = 0; i != sk_X509_num(chain); ++i) {
-    auto cert = sk_X509_value(chain, i);
-    if (cert && !is_proxy(cert)) {
-      ee_cert = cert;
-      break;
+
+  if (sk_X509_num(chain) == 0) {
+    ee_cert = SSL_get_peer_certificate(r->connection->ssl->connection);
+  } else {
+    // find first non-proxy
+    for (int i = 0; i != sk_X509_num(chain); ++i) {
+      auto cert = sk_X509_value(chain, i);
+      if (cert && !is_proxy(cert)) {
+        ee_cert = cert;
+        break;
+      }
     }
   }
 
diff --git a/t/certs/7.cert.pem b/t/certs/7.cert.pem
new file mode 100644
index 0000000..f531910
--- /dev/null
+++ b/t/certs/7.cert.pem
@@ -0,0 +1,67 @@
+-----BEGIN CERTIFICATE-----
+MIICZDCCAc+gAwIBAgIECbJ7aTALBgkqhkiG9w0BAQUwVTELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAxEzARBgNVBAMTCjExMjA1NTI3NjcwHhcNMTgwNjI2MTE1OTU0WhcNMjIwOTI0
+MTUzOTM0WjBpMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0
+ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzES
+MBAGA1UEAxMJMTYyNjkxOTQ1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCY
+y5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib5noh3UB5jzT85ZyK
+mEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZLvGNr0BMedleJCe9
+Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQABozEwLzAOBgNVHQ8B
+Af8EBAMCBeAwHQYIKwYBBQUHAQ4BAf8EDjAMMAoGCCsGAQUFBxUBMAsGCSqGSIb3
+DQEBBQOBgQCKUH2ZNCrtUrz9atjgi3FY3pjIKZcCIxDLDz+YJC1CVJaZFQ0KMHkM
+PAuIwxqUdrR1jRG7s1QCZlr7QXySlql0v6icLAlnm1kVZ4MhOxGTLSVdUgqNz3kN
+Jz7cvtRnk4nCeb+4WnmSyfK8o7IPavp4DRs5aeZ9BtvCBzFRWALITg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICOzCCAaagAwIBAgIEQspHPzALBgkqhkiG9w0BAQUwQDELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAwHhcNMTgwNjI2MTE1OTQ0WhcNMjIwOTI0MTUzOTM0WjBVMQswCQYDVQQGEwJJ
+VDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUx
+MTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAkEUmDYhSUD64QKktC0A5d0LvufnAqcQbVktdpi8n14Up/7K2/jGFTVnu
+8NwPcfxog1kH5+ddp1JBI5FSELJkWD5a0oAfjz+6JNVb9sFRH4PuNO8O3ZrzpEDF
+I7rZ1x+vMqH43iYBaO89vafaeVHSEUJQOx3Z/Lv5OTv1r8tUKWECAwEAAaMxMC8w
+DgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEFBQcVATAL
+BgkqhkiG9w0BAQUDgYEAsY5QuVar+9Toz3FEOYjY1PBn5cBg+zBmdLDkMTruS8XS
+JA1WkSUNi5HtU8FuGkvs3Z8Rfw4vhQICl9wZdoPMDNo8rv2ErDgIM1QFqAiYqnz5
+Tt0xeZAJXCoAdoxg8wmeflQymbR2JoP2Q6UjI1LfwoYnaZf3saz5PQi+F4IZkq8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICkjCCAXygAwIBAgIEf5WeODALBgkqhkiG9w0BAQUwKzELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAwHhcNMTgwNjI2MTE1OTE0WhcN
+MjIwOTI0MTUzOTM0WjBAMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYD
+VQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDCBnzANBgkqhkiG9w0BAQEF
+AAOBjQAwgYkCgYEA2pv6lQyWBT3/Yv4IiCkp7UbliS2DvEeZyR5bwoc0/zfRjCfk
+Wt169bDzDlgYqqXp+tO+PNbOovz48zHbhtNHGGT8I5N6wi6PUp7RPPBkHnlC13P5
+AlSQg5E+k+xyEJ6zRLhi2IcO5vd8oXGqGrj1hlli7gtNdtEwEd8pz8OkkB0CAwEA
+AaMxMC8wDgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEF
+BQcVATALBgkqhkiG9w0BAQUDggEBAHs2qi5wGjQ2g7nX2UTNpCzkUxKSjYuf+5gx
+v74JSKUIaRxmtVWoa4UzH3tSYqdjDGFv6XEPScbbMz6HJjEMN1M7Elcsd01mnFCj
+WFHLlMkcBTyfCHMTzDtGhuUL5TdBJs0ha98Q+/hI3Nm+6SoZ2/2flRTdLOh9qQzx
+870bckwo6FHNZ32hdCPGJ4cy0pcV3Hc99K1iiQHTYEDZJoxvlZ/Wn2q+d/DsJycC
+Cdh237RRwWSxAJ3V1XWpXbP+FYFJx1aJEBwEVfXL0dqUrn7BYEOvR7SDPFXHbnFx
+x7Pd9+dwIh9aEdUYqXQWBCIHwFtVMv6P0jG0ochpQjmO3TjIkS4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgIBCTANBgkqhkiG9w0BAQUFADAtMQswCQYDVQQGEwJJVDEM
+MAoGA1UECgwDSUdJMRAwDgYDVQQDDAdUZXN0IENBMB4XDTEyMDkyNjE1MzkzNFoX
+DTIyMDkyNDE1MzkzNFowKzELMAkGA1UEBhMCSVQxDDAKBgNVBAoTA0lHSTEOMAwG
+A1UEAxMFdGVzdDAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKxtrw
+hoZ27SxxISjlRqWmBWB6U+N/xW2kS1uUfrQRav6auVtmtEW45J44VTi3WW6Y113R
+BwmS6oW+3lzyBBZVPqnhV9/VkTxLp83gGVVvHATgGgkjeTxIsOE+TkPKAoZJ/QFc
+CfPh3WdZ3ANI14WYkAM9VXsSbh2okCsWGa4o6pzt3Pt1zKkyO4PW0cBkletDImJK
+2vufuDVNm7Iz/y3/8pY8p3MoiwbF/PdSba7XQAxBWUJMoaleh8xy8HSROn7tF2al
+xoDLH4QWhp6UDn2rvOWseBqUMPXFjsUi1/rkw1oHAjMroTk5lL15GI0LGd5dTVop
+kKXFbTTYxSkPz1MLAgMBAAGjgcowgccwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
+fLdB5+jO9LyWN2/VCNYgMa0jvHEwDgYDVR0PAQH/BAQDAgXgMD4GA1UdJQQ3MDUG
+CCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBBggrBgEF
+BQcDBDAfBgNVHSMEGDAWgBSRdzZ7LrRp8yfqt/YIi0ojohFJxjAnBgNVHREEIDAe
+gRxhbmRyZWEuY2VjY2FudGlAY25hZi5pbmZuLml0MA0GCSqGSIb3DQEBBQUAA4IB
+AQANYtWXetheSeVpCfnId9TkKyKTAp8RahNZl4XFrWWn2S9We7ACK/G7u1DebJYx
+d8POo8ClscoXyTO2BzHHZLxauEKIzUv7g2GehI+SckfZdjFyRXjD0+wMGwzX7MDu
+SL3CG2aWsYpkBnj6BMlr0P3kZEMqV5t2+2Tj0+aXppBPVwzJwRhnrSJiO5WIZAZf
+49YhMn61sQIrepvhrKEUR4XVorH2Bj8ek1/iLlgcmFMBOds+PrehSRR8Gn0IjlEg
+C68EY6KPE+FKySuS7Ur7lTAjNdddfdAgKV6hJyST6/dx8ymIkb8nxCPnxCcT2I2N
+vDxcPMc/wmnMa+smNal0sJ6m
+-----END CERTIFICATE-----
diff --git a/t/certs/7.key.pem b/t/certs/7.key.pem
new file mode 100644
index 0000000..b191807
--- /dev/null
+++ b/t/certs/7.key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCYy5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib
+5noh3UB5jzT85ZyKmEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZ
+LvGNr0BMedleJCe9Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQAB
+AoGAGiw1rr9qvMAQw113o5N4/urblGAkquwY2kRxp50tf9SsBpnkv3+5R/e4RZpM
+P02thOgVQTivw21Ocmhs0w1XjH+LUNo8f9+Aet5F5qTS0p/cvCKeBfb4cVAAJFjM
+T8DxEpN5ZTwQVdb/CeoIr513suW6QuFqrJP2XjuTD37tZSkCQQDKb/AHVb+ajKq4
+mFQE+N3AcSYYqlqBbfdiPegaxUYTe9j0r6Rjzd/GpCtTSmpk+lIC9jWqMFr1OnDc
+3u8I0DVXAkEAwTkphRZeufrHghNFtFRec/+11vluqHEzUgno16bwxIg8ipqs/hjK
+iHKjtD7b3jIdKiISJIleEf2t9E3q05Z/lwJAWs63pzKpzlQHSOLb3ZcdMfQPmMTh
+8Gk5rVIDye5wLtFBUxFu9m4lUV/XJ3ecHkvDehyjmgIy6woaEpnWM+fh5QJAP2K8
+Hx+ehY4iAqbF2AlRTuZUxaffyDwSZNhBXPUzyJUUnzdshpKlZiuNTmTMhdCUxqyU
+nQ2/IVHBzgH9hdm6EwJAXk30m26ayo5awSv7LgtsgFh/1kTCSpzlfycwnO+NEfkV
+co+HkGYnU5lVXGMzAQyJDtiq+8f2A/lxdov6QYy/0w==
+-----END RSA PRIVATE KEY-----
diff --git a/t/certs/7.pem b/t/certs/7.pem
new file mode 100644
index 0000000..4fd0644
--- /dev/null
+++ b/t/certs/7.pem
@@ -0,0 +1,82 @@
+-----BEGIN CERTIFICATE-----
+MIICZDCCAc+gAwIBAgIECbJ7aTALBgkqhkiG9w0BAQUwVTELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAxEzARBgNVBAMTCjExMjA1NTI3NjcwHhcNMTgwNjI2MTE1OTU0WhcNMjIwOTI0
+MTUzOTM0WjBpMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0
+ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzES
+MBAGA1UEAxMJMTYyNjkxOTQ1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCY
+y5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib5noh3UB5jzT85ZyK
+mEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZLvGNr0BMedleJCe9
+Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQABozEwLzAOBgNVHQ8B
+Af8EBAMCBeAwHQYIKwYBBQUHAQ4BAf8EDjAMMAoGCCsGAQUFBxUBMAsGCSqGSIb3
+DQEBBQOBgQCKUH2ZNCrtUrz9atjgi3FY3pjIKZcCIxDLDz+YJC1CVJaZFQ0KMHkM
+PAuIwxqUdrR1jRG7s1QCZlr7QXySlql0v6icLAlnm1kVZ4MhOxGTLSVdUgqNz3kN
+Jz7cvtRnk4nCeb+4WnmSyfK8o7IPavp4DRs5aeZ9BtvCBzFRWALITg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCYy5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib
+5noh3UB5jzT85ZyKmEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZ
+LvGNr0BMedleJCe9Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQAB
+AoGAGiw1rr9qvMAQw113o5N4/urblGAkquwY2kRxp50tf9SsBpnkv3+5R/e4RZpM
+P02thOgVQTivw21Ocmhs0w1XjH+LUNo8f9+Aet5F5qTS0p/cvCKeBfb4cVAAJFjM
+T8DxEpN5ZTwQVdb/CeoIr513suW6QuFqrJP2XjuTD37tZSkCQQDKb/AHVb+ajKq4
+mFQE+N3AcSYYqlqBbfdiPegaxUYTe9j0r6Rjzd/GpCtTSmpk+lIC9jWqMFr1OnDc
+3u8I0DVXAkEAwTkphRZeufrHghNFtFRec/+11vluqHEzUgno16bwxIg8ipqs/hjK
+iHKjtD7b3jIdKiISJIleEf2t9E3q05Z/lwJAWs63pzKpzlQHSOLb3ZcdMfQPmMTh
+8Gk5rVIDye5wLtFBUxFu9m4lUV/XJ3ecHkvDehyjmgIy6woaEpnWM+fh5QJAP2K8
+Hx+ehY4iAqbF2AlRTuZUxaffyDwSZNhBXPUzyJUUnzdshpKlZiuNTmTMhdCUxqyU
+nQ2/IVHBzgH9hdm6EwJAXk30m26ayo5awSv7LgtsgFh/1kTCSpzlfycwnO+NEfkV
+co+HkGYnU5lVXGMzAQyJDtiq+8f2A/lxdov6QYy/0w==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICOzCCAaagAwIBAgIEQspHPzALBgkqhkiG9w0BAQUwQDELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAwHhcNMTgwNjI2MTE1OTQ0WhcNMjIwOTI0MTUzOTM0WjBVMQswCQYDVQQGEwJJ
+VDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUx
+MTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAkEUmDYhSUD64QKktC0A5d0LvufnAqcQbVktdpi8n14Up/7K2/jGFTVnu
+8NwPcfxog1kH5+ddp1JBI5FSELJkWD5a0oAfjz+6JNVb9sFRH4PuNO8O3ZrzpEDF
+I7rZ1x+vMqH43iYBaO89vafaeVHSEUJQOx3Z/Lv5OTv1r8tUKWECAwEAAaMxMC8w
+DgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEFBQcVATAL
+BgkqhkiG9w0BAQUDgYEAsY5QuVar+9Toz3FEOYjY1PBn5cBg+zBmdLDkMTruS8XS
+JA1WkSUNi5HtU8FuGkvs3Z8Rfw4vhQICl9wZdoPMDNo8rv2ErDgIM1QFqAiYqnz5
+Tt0xeZAJXCoAdoxg8wmeflQymbR2JoP2Q6UjI1LfwoYnaZf3saz5PQi+F4IZkq8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICkjCCAXygAwIBAgIEf5WeODALBgkqhkiG9w0BAQUwKzELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAwHhcNMTgwNjI2MTE1OTE0WhcN
+MjIwOTI0MTUzOTM0WjBAMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYD
+VQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDCBnzANBgkqhkiG9w0BAQEF
+AAOBjQAwgYkCgYEA2pv6lQyWBT3/Yv4IiCkp7UbliS2DvEeZyR5bwoc0/zfRjCfk
+Wt169bDzDlgYqqXp+tO+PNbOovz48zHbhtNHGGT8I5N6wi6PUp7RPPBkHnlC13P5
+AlSQg5E+k+xyEJ6zRLhi2IcO5vd8oXGqGrj1hlli7gtNdtEwEd8pz8OkkB0CAwEA
+AaMxMC8wDgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEF
+BQcVATALBgkqhkiG9w0BAQUDggEBAHs2qi5wGjQ2g7nX2UTNpCzkUxKSjYuf+5gx
+v74JSKUIaRxmtVWoa4UzH3tSYqdjDGFv6XEPScbbMz6HJjEMN1M7Elcsd01mnFCj
+WFHLlMkcBTyfCHMTzDtGhuUL5TdBJs0ha98Q+/hI3Nm+6SoZ2/2flRTdLOh9qQzx
+870bckwo6FHNZ32hdCPGJ4cy0pcV3Hc99K1iiQHTYEDZJoxvlZ/Wn2q+d/DsJycC
+Cdh237RRwWSxAJ3V1XWpXbP+FYFJx1aJEBwEVfXL0dqUrn7BYEOvR7SDPFXHbnFx
+x7Pd9+dwIh9aEdUYqXQWBCIHwFtVMv6P0jG0ochpQjmO3TjIkS4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgIBCTANBgkqhkiG9w0BAQUFADAtMQswCQYDVQQGEwJJVDEM
+MAoGA1UECgwDSUdJMRAwDgYDVQQDDAdUZXN0IENBMB4XDTEyMDkyNjE1MzkzNFoX
+DTIyMDkyNDE1MzkzNFowKzELMAkGA1UEBhMCSVQxDDAKBgNVBAoTA0lHSTEOMAwG
+A1UEAxMFdGVzdDAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKxtrw
+hoZ27SxxISjlRqWmBWB6U+N/xW2kS1uUfrQRav6auVtmtEW45J44VTi3WW6Y113R
+BwmS6oW+3lzyBBZVPqnhV9/VkTxLp83gGVVvHATgGgkjeTxIsOE+TkPKAoZJ/QFc
+CfPh3WdZ3ANI14WYkAM9VXsSbh2okCsWGa4o6pzt3Pt1zKkyO4PW0cBkletDImJK
+2vufuDVNm7Iz/y3/8pY8p3MoiwbF/PdSba7XQAxBWUJMoaleh8xy8HSROn7tF2al
+xoDLH4QWhp6UDn2rvOWseBqUMPXFjsUi1/rkw1oHAjMroTk5lL15GI0LGd5dTVop
+kKXFbTTYxSkPz1MLAgMBAAGjgcowgccwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
+fLdB5+jO9LyWN2/VCNYgMa0jvHEwDgYDVR0PAQH/BAQDAgXgMD4GA1UdJQQ3MDUG
+CCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBBggrBgEF
+BQcDBDAfBgNVHSMEGDAWgBSRdzZ7LrRp8yfqt/YIi0ojohFJxjAnBgNVHREEIDAe
+gRxhbmRyZWEuY2VjY2FudGlAY25hZi5pbmZuLml0MA0GCSqGSIb3DQEBBQUAA4IB
+AQANYtWXetheSeVpCfnId9TkKyKTAp8RahNZl4XFrWWn2S9We7ACK/G7u1DebJYx
+d8POo8ClscoXyTO2BzHHZLxauEKIzUv7g2GehI+SckfZdjFyRXjD0+wMGwzX7MDu
+SL3CG2aWsYpkBnj6BMlr0P3kZEMqV5t2+2Tj0+aXppBPVwzJwRhnrSJiO5WIZAZf
+49YhMn61sQIrepvhrKEUR4XVorH2Bj8ek1/iLlgcmFMBOds+PrehSRR8Gn0IjlEg
+C68EY6KPE+FKySuS7Ur7lTAjNdddfdAgKV6hJyST6/dx8ymIkb8nxCPnxCcT2I2N
+vDxcPMc/wmnMa+smNal0sJ6m
+-----END CERTIFICATE-----
diff --git a/t/certs/8.cert.pem b/t/certs/8.cert.pem
new file mode 100644
index 0000000..c0252cf
--- /dev/null
+++ b/t/certs/8.cert.pem
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIICZDCCAc+gAwIBAgIECbJ7aTALBgkqhkiG9w0BAQUwVTELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAxEzARBgNVBAMTCjExMjA1NTI3NjcwHhcNMTgwNjI2MTE1OTU0WhcNMjIwOTI0
+MTUzOTM0WjBpMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0
+ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzES
+MBAGA1UEAxMJMTYyNjkxOTQ1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCY
+y5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib5noh3UB5jzT85ZyK
+mEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZLvGNr0BMedleJCe9
+Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQABozEwLzAOBgNVHQ8B
+Af8EBAMCBeAwHQYIKwYBBQUHAQ4BAf8EDjAMMAoGCCsGAQUFBxUBMAsGCSqGSIb3
+DQEBBQOBgQCKUH2ZNCrtUrz9atjgi3FY3pjIKZcCIxDLDz+YJC1CVJaZFQ0KMHkM
+PAuIwxqUdrR1jRG7s1QCZlr7QXySlql0v6icLAlnm1kVZ4MhOxGTLSVdUgqNz3kN
+Jz7cvtRnk4nCeb+4WnmSyfK8o7IPavp4DRs5aeZ9BtvCBzFRWALITg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICOzCCAaagAwIBAgIEQspHPzALBgkqhkiG9w0BAQUwQDELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAwHhcNMTgwNjI2MTE1OTQ0WhcNMjIwOTI0MTUzOTM0WjBVMQswCQYDVQQGEwJJ
+VDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUx
+MTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAkEUmDYhSUD64QKktC0A5d0LvufnAqcQbVktdpi8n14Up/7K2/jGFTVnu
+8NwPcfxog1kH5+ddp1JBI5FSELJkWD5a0oAfjz+6JNVb9sFRH4PuNO8O3ZrzpEDF
+I7rZ1x+vMqH43iYBaO89vafaeVHSEUJQOx3Z/Lv5OTv1r8tUKWECAwEAAaMxMC8w
+DgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEFBQcVATAL
+BgkqhkiG9w0BAQUDgYEAsY5QuVar+9Toz3FEOYjY1PBn5cBg+zBmdLDkMTruS8XS
+JA1WkSUNi5HtU8FuGkvs3Z8Rfw4vhQICl9wZdoPMDNo8rv2ErDgIM1QFqAiYqnz5
+Tt0xeZAJXCoAdoxg8wmeflQymbR2JoP2Q6UjI1LfwoYnaZf3saz5PQi+F4IZkq8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICkjCCAXygAwIBAgIEf5WeODALBgkqhkiG9w0BAQUwKzELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAwHhcNMTgwNjI2MTE1OTE0WhcN
+MjIwOTI0MTUzOTM0WjBAMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYD
+VQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDCBnzANBgkqhkiG9w0BAQEF
+AAOBjQAwgYkCgYEA2pv6lQyWBT3/Yv4IiCkp7UbliS2DvEeZyR5bwoc0/zfRjCfk
+Wt169bDzDlgYqqXp+tO+PNbOovz48zHbhtNHGGT8I5N6wi6PUp7RPPBkHnlC13P5
+AlSQg5E+k+xyEJ6zRLhi2IcO5vd8oXGqGrj1hlli7gtNdtEwEd8pz8OkkB0CAwEA
+AaMxMC8wDgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEF
+BQcVATALBgkqhkiG9w0BAQUDggEBAHs2qi5wGjQ2g7nX2UTNpCzkUxKSjYuf+5gx
+v74JSKUIaRxmtVWoa4UzH3tSYqdjDGFv6XEPScbbMz6HJjEMN1M7Elcsd01mnFCj
+WFHLlMkcBTyfCHMTzDtGhuUL5TdBJs0ha98Q+/hI3Nm+6SoZ2/2flRTdLOh9qQzx
+870bckwo6FHNZ32hdCPGJ4cy0pcV3Hc99K1iiQHTYEDZJoxvlZ/Wn2q+d/DsJycC
+Cdh237RRwWSxAJ3V1XWpXbP+FYFJx1aJEBwEVfXL0dqUrn7BYEOvR7SDPFXHbnFx
+x7Pd9+dwIh9aEdUYqXQWBCIHwFtVMv6P0jG0ochpQjmO3TjIkS4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgIBCTANBgkqhkiG9w0BAQUFADAtMQswCQYDVQQGEwJJVDEM
+MAoGA1UECgwDSUdJMRAwDgYDVQQDDAdUZXN0IENBMB4XDTEyMDkyNjE1MzkzNFoX
+DTIyMDkyNDE1MzkzNFowKzELMAkGA1UEBhMCSVQxDDAKBgNVBAoTA0lHSTEOMAwG
+A1UEAxMFdGVzdDAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKxtrw
+hoZ27SxxISjlRqWmBWB6U+N/xW2kS1uUfrQRav6auVtmtEW45J44VTi3WW6Y113R
+BwmS6oW+3lzyBBZVPqnhV9/VkTxLp83gGVVvHATgGgkjeTxIsOE+TkPKAoZJ/QFc
+CfPh3WdZ3ANI14WYkAM9VXsSbh2okCsWGa4o6pzt3Pt1zKkyO4PW0cBkletDImJK
+2vufuDVNm7Iz/y3/8pY8p3MoiwbF/PdSba7XQAxBWUJMoaleh8xy8HSROn7tF2al
+xoDLH4QWhp6UDn2rvOWseBqUMPXFjsUi1/rkw1oHAjMroTk5lL15GI0LGd5dTVop
+kKXFbTTYxSkPz1MLAgMBAAGjgcowgccwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
+fLdB5+jO9LyWN2/VCNYgMa0jvHEwDgYDVR0PAQH/BAQDAgXgMD4GA1UdJQQ3MDUG
+CCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBBggrBgEF
+BQcDBDAfBgNVHSMEGDAWgBSRdzZ7LrRp8yfqt/YIi0ojohFJxjAnBgNVHREEIDAe
+gRxhbmRyZWEuY2VjY2FudGlAY25hZi5pbmZuLml0MA0GCSqGSIb3DQEBBQUAA4IB
+AQANYtWXetheSeVpCfnId9TkKyKTAp8RahNZl4XFrWWn2S9We7ACK/G7u1DebJYx
+d8POo8ClscoXyTO2BzHHZLxauEKIzUv7g2GehI+SckfZdjFyRXjD0+wMGwzX7MDu
+SL3CG2aWsYpkBnj6BMlr0P3kZEMqV5t2+2Tj0+aXppBPVwzJwRhnrSJiO5WIZAZf
+49YhMn61sQIrepvhrKEUR4XVorH2Bj8ek1/iLlgcmFMBOds+PrehSRR8Gn0IjlEg
+C68EY6KPE+FKySuS7Ur7lTAjNdddfdAgKV6hJyST6/dx8ymIkb8nxCPnxCcT2I2N
+vDxcPMc/wmnMa+smNal0sJ6m
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgIJAMzDwAv7o5VUMA0GCSqGSIb3DQEBBQUAMC0xCzAJBgNV
+BAYTAklUMQwwCgYDVQQKDANJR0kxEDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMTIwOTI2
+MTUwMDU0WhcNMjIwOTI0MTUwMDU0WjAtMQswCQYDVQQGEwJJVDEMMAoGA1UECgwD
+SUdJMRAwDgYDVQQDDAdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA9u4Fgtj7YpMRql3NAasEUmP6Byv/CH+dPZNzSxfNCMOPqARLBWS/2Ora
+m5cRpoBByT0LpjDCFBJhLrBKvCvmWOTfS1jYsQwSpC/5scButthlcNOhLKQSZblS
+8Pa7HoFS4zQFwCwWOYbOLF+FblYRgSY30WMi361giydeV8iei8KNH2FIoDyo9kjV
+gYQKp76LFv7urGhc5sHA+HWq7+AfyivtZC+a55Rw6EHXOQ+vih5TPXa1t5RL7IkY
+4U7Ld5ExptBIDx0UkSihYexAY4RGXVUaq535dGtJQ8/NYMrJ5NMGt2X0bRszArnE
+EKc/qdAcgcalgoiaZtVkq45eXADXzwIDAQABo4GiMIGfMB0GA1UdDgQWBBSRdzZ7
+LrRp8yfqt/YIi0ojohFJxjBdBgNVHSMEVjBUgBSRdzZ7LrRp8yfqt/YIi0ojohFJ
+xqExpC8wLTELMAkGA1UEBhMCSVQxDDAKBgNVBAoMA0lHSTEQMA4GA1UEAwwHVGVz
+dCBDQYIJAMzDwAv7o5VUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQB379cvZmfCLvGdoGbW+6ppDNy3pT9hqYmZAlfV
+FGZSEaTKjGCbPuErUNC6+7zhij5CmMtMRhccI3JswjPHPQGm12jiEC492J6Avj/x
+PL8vcBRofe4whXefDVgUw8G1nkQYr2BF0jzeiN72ToISGMbt/q94QV70lYCo/Tog
+UQQ6F+XhztffxQyRgsUXhR4qq1D4h7UifqfQGBzknS23RMLQUdKXG4MhTLMVmxJC
+uY9Oi0It3hk9Qtn0nlZ7rvo5weJGxuRBbZ85Nvw2tIhH7G2osc6zqmHTmUAR4FXb
+l8/ElwGVrURMMuJLDbISVXjBNFuVOS2BdlyEe4x5kfQAWITZ
+-----END CERTIFICATE-----
diff --git a/t/certs/8.key.pem b/t/certs/8.key.pem
new file mode 100644
index 0000000..b191807
--- /dev/null
+++ b/t/certs/8.key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCYy5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib
+5noh3UB5jzT85ZyKmEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZ
+LvGNr0BMedleJCe9Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQAB
+AoGAGiw1rr9qvMAQw113o5N4/urblGAkquwY2kRxp50tf9SsBpnkv3+5R/e4RZpM
+P02thOgVQTivw21Ocmhs0w1XjH+LUNo8f9+Aet5F5qTS0p/cvCKeBfb4cVAAJFjM
+T8DxEpN5ZTwQVdb/CeoIr513suW6QuFqrJP2XjuTD37tZSkCQQDKb/AHVb+ajKq4
+mFQE+N3AcSYYqlqBbfdiPegaxUYTe9j0r6Rjzd/GpCtTSmpk+lIC9jWqMFr1OnDc
+3u8I0DVXAkEAwTkphRZeufrHghNFtFRec/+11vluqHEzUgno16bwxIg8ipqs/hjK
+iHKjtD7b3jIdKiISJIleEf2t9E3q05Z/lwJAWs63pzKpzlQHSOLb3ZcdMfQPmMTh
+8Gk5rVIDye5wLtFBUxFu9m4lUV/XJ3ecHkvDehyjmgIy6woaEpnWM+fh5QJAP2K8
+Hx+ehY4iAqbF2AlRTuZUxaffyDwSZNhBXPUzyJUUnzdshpKlZiuNTmTMhdCUxqyU
+nQ2/IVHBzgH9hdm6EwJAXk30m26ayo5awSv7LgtsgFh/1kTCSpzlfycwnO+NEfkV
+co+HkGYnU5lVXGMzAQyJDtiq+8f2A/lxdov6QYy/0w==
+-----END RSA PRIVATE KEY-----
diff --git a/t/certs/8.pem b/t/certs/8.pem
new file mode 100644
index 0000000..910e313
--- /dev/null
+++ b/t/certs/8.pem
@@ -0,0 +1,103 @@
+-----BEGIN CERTIFICATE-----
+MIICZDCCAc+gAwIBAgIECbJ7aTALBgkqhkiG9w0BAQUwVTELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAxEzARBgNVBAMTCjExMjA1NTI3NjcwHhcNMTgwNjI2MTE1OTU0WhcNMjIwOTI0
+MTUzOTM0WjBpMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0
+ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzES
+MBAGA1UEAxMJMTYyNjkxOTQ1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCY
+y5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib5noh3UB5jzT85ZyK
+mEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZLvGNr0BMedleJCe9
+Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQABozEwLzAOBgNVHQ8B
+Af8EBAMCBeAwHQYIKwYBBQUHAQ4BAf8EDjAMMAoGCCsGAQUFBxUBMAsGCSqGSIb3
+DQEBBQOBgQCKUH2ZNCrtUrz9atjgi3FY3pjIKZcCIxDLDz+YJC1CVJaZFQ0KMHkM
+PAuIwxqUdrR1jRG7s1QCZlr7QXySlql0v6icLAlnm1kVZ4MhOxGTLSVdUgqNz3kN
+Jz7cvtRnk4nCeb+4WnmSyfK8o7IPavp4DRs5aeZ9BtvCBzFRWALITg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCYy5e3JJDyhKnsh8yT15qfFCuViyzPzzGhWLTiX57giLsRsbib
+5noh3UB5jzT85ZyKmEpHvZ3acWzcWqbqM/YyU2vPpxamm6+uZ2JUJFUc4zKahNQZ
+LvGNr0BMedleJCe9Ht+cQlSIons2rRvCuzMCnXRsYMyPFT4ZesbZcz+fUQIDAQAB
+AoGAGiw1rr9qvMAQw113o5N4/urblGAkquwY2kRxp50tf9SsBpnkv3+5R/e4RZpM
+P02thOgVQTivw21Ocmhs0w1XjH+LUNo8f9+Aet5F5qTS0p/cvCKeBfb4cVAAJFjM
+T8DxEpN5ZTwQVdb/CeoIr513suW6QuFqrJP2XjuTD37tZSkCQQDKb/AHVb+ajKq4
+mFQE+N3AcSYYqlqBbfdiPegaxUYTe9j0r6Rjzd/GpCtTSmpk+lIC9jWqMFr1OnDc
+3u8I0DVXAkEAwTkphRZeufrHghNFtFRec/+11vluqHEzUgno16bwxIg8ipqs/hjK
+iHKjtD7b3jIdKiISJIleEf2t9E3q05Z/lwJAWs63pzKpzlQHSOLb3ZcdMfQPmMTh
+8Gk5rVIDye5wLtFBUxFu9m4lUV/XJ3ecHkvDehyjmgIy6woaEpnWM+fh5QJAP2K8
+Hx+ehY4iAqbF2AlRTuZUxaffyDwSZNhBXPUzyJUUnzdshpKlZiuNTmTMhdCUxqyU
+nQ2/IVHBzgH9hdm6EwJAXk30m26ayo5awSv7LgtsgFh/1kTCSpzlfycwnO+NEfkV
+co+HkGYnU5lVXGMzAQyJDtiq+8f2A/lxdov6QYy/0w==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICOzCCAaagAwIBAgIEQspHPzALBgkqhkiG9w0BAQUwQDELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAxEzARBgNVBAMTCjIxNDA1MTE4
+MDAwHhcNMTgwNjI2MTE1OTQ0WhcNMjIwOTI0MTUzOTM0WjBVMQswCQYDVQQGEwJJ
+VDEMMAoGA1UEChMDSUdJMQ4wDAYDVQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUx
+MTgwMDETMBEGA1UEAxMKMTEyMDU1Mjc2NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAkEUmDYhSUD64QKktC0A5d0LvufnAqcQbVktdpi8n14Up/7K2/jGFTVnu
+8NwPcfxog1kH5+ddp1JBI5FSELJkWD5a0oAfjz+6JNVb9sFRH4PuNO8O3ZrzpEDF
+I7rZ1x+vMqH43iYBaO89vafaeVHSEUJQOx3Z/Lv5OTv1r8tUKWECAwEAAaMxMC8w
+DgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEFBQcVATAL
+BgkqhkiG9w0BAQUDgYEAsY5QuVar+9Toz3FEOYjY1PBn5cBg+zBmdLDkMTruS8XS
+JA1WkSUNi5HtU8FuGkvs3Z8Rfw4vhQICl9wZdoPMDNo8rv2ErDgIM1QFqAiYqnz5
+Tt0xeZAJXCoAdoxg8wmeflQymbR2JoP2Q6UjI1LfwoYnaZf3saz5PQi+F4IZkq8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICkjCCAXygAwIBAgIEf5WeODALBgkqhkiG9w0BAQUwKzELMAkGA1UEBhMCSVQx
+DDAKBgNVBAoTA0lHSTEOMAwGA1UEAxMFdGVzdDAwHhcNMTgwNjI2MTE1OTE0WhcN
+MjIwOTI0MTUzOTM0WjBAMQswCQYDVQQGEwJJVDEMMAoGA1UEChMDSUdJMQ4wDAYD
+VQQDEwV0ZXN0MDETMBEGA1UEAxMKMjE0MDUxMTgwMDCBnzANBgkqhkiG9w0BAQEF
+AAOBjQAwgYkCgYEA2pv6lQyWBT3/Yv4IiCkp7UbliS2DvEeZyR5bwoc0/zfRjCfk
+Wt169bDzDlgYqqXp+tO+PNbOovz48zHbhtNHGGT8I5N6wi6PUp7RPPBkHnlC13P5
+AlSQg5E+k+xyEJ6zRLhi2IcO5vd8oXGqGrj1hlli7gtNdtEwEd8pz8OkkB0CAwEA
+AaMxMC8wDgYDVR0PAQH/BAQDAgXgMB0GCCsGAQUFBwEOAQH/BA4wDDAKBggrBgEF
+BQcVATALBgkqhkiG9w0BAQUDggEBAHs2qi5wGjQ2g7nX2UTNpCzkUxKSjYuf+5gx
+v74JSKUIaRxmtVWoa4UzH3tSYqdjDGFv6XEPScbbMz6HJjEMN1M7Elcsd01mnFCj
+WFHLlMkcBTyfCHMTzDtGhuUL5TdBJs0ha98Q+/hI3Nm+6SoZ2/2flRTdLOh9qQzx
+870bckwo6FHNZ32hdCPGJ4cy0pcV3Hc99K1iiQHTYEDZJoxvlZ/Wn2q+d/DsJycC
+Cdh237RRwWSxAJ3V1XWpXbP+FYFJx1aJEBwEVfXL0dqUrn7BYEOvR7SDPFXHbnFx
+x7Pd9+dwIh9aEdUYqXQWBCIHwFtVMv6P0jG0ochpQjmO3TjIkS4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgIBCTANBgkqhkiG9w0BAQUFADAtMQswCQYDVQQGEwJJVDEM
+MAoGA1UECgwDSUdJMRAwDgYDVQQDDAdUZXN0IENBMB4XDTEyMDkyNjE1MzkzNFoX
+DTIyMDkyNDE1MzkzNFowKzELMAkGA1UEBhMCSVQxDDAKBgNVBAoTA0lHSTEOMAwG
+A1UEAxMFdGVzdDAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKxtrw
+hoZ27SxxISjlRqWmBWB6U+N/xW2kS1uUfrQRav6auVtmtEW45J44VTi3WW6Y113R
+BwmS6oW+3lzyBBZVPqnhV9/VkTxLp83gGVVvHATgGgkjeTxIsOE+TkPKAoZJ/QFc
+CfPh3WdZ3ANI14WYkAM9VXsSbh2okCsWGa4o6pzt3Pt1zKkyO4PW0cBkletDImJK
+2vufuDVNm7Iz/y3/8pY8p3MoiwbF/PdSba7XQAxBWUJMoaleh8xy8HSROn7tF2al
+xoDLH4QWhp6UDn2rvOWseBqUMPXFjsUi1/rkw1oHAjMroTk5lL15GI0LGd5dTVop
+kKXFbTTYxSkPz1MLAgMBAAGjgcowgccwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
+fLdB5+jO9LyWN2/VCNYgMa0jvHEwDgYDVR0PAQH/BAQDAgXgMD4GA1UdJQQ3MDUG
+CCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBBggrBgEF
+BQcDBDAfBgNVHSMEGDAWgBSRdzZ7LrRp8yfqt/YIi0ojohFJxjAnBgNVHREEIDAe
+gRxhbmRyZWEuY2VjY2FudGlAY25hZi5pbmZuLml0MA0GCSqGSIb3DQEBBQUAA4IB
+AQANYtWXetheSeVpCfnId9TkKyKTAp8RahNZl4XFrWWn2S9We7ACK/G7u1DebJYx
+d8POo8ClscoXyTO2BzHHZLxauEKIzUv7g2GehI+SckfZdjFyRXjD0+wMGwzX7MDu
+SL3CG2aWsYpkBnj6BMlr0P3kZEMqV5t2+2Tj0+aXppBPVwzJwRhnrSJiO5WIZAZf
+49YhMn61sQIrepvhrKEUR4XVorH2Bj8ek1/iLlgcmFMBOds+PrehSRR8Gn0IjlEg
+C68EY6KPE+FKySuS7Ur7lTAjNdddfdAgKV6hJyST6/dx8ymIkb8nxCPnxCcT2I2N
+vDxcPMc/wmnMa+smNal0sJ6m
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgIJAMzDwAv7o5VUMA0GCSqGSIb3DQEBBQUAMC0xCzAJBgNV
+BAYTAklUMQwwCgYDVQQKDANJR0kxEDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMTIwOTI2
+MTUwMDU0WhcNMjIwOTI0MTUwMDU0WjAtMQswCQYDVQQGEwJJVDEMMAoGA1UECgwD
+SUdJMRAwDgYDVQQDDAdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA9u4Fgtj7YpMRql3NAasEUmP6Byv/CH+dPZNzSxfNCMOPqARLBWS/2Ora
+m5cRpoBByT0LpjDCFBJhLrBKvCvmWOTfS1jYsQwSpC/5scButthlcNOhLKQSZblS
+8Pa7HoFS4zQFwCwWOYbOLF+FblYRgSY30WMi361giydeV8iei8KNH2FIoDyo9kjV
+gYQKp76LFv7urGhc5sHA+HWq7+AfyivtZC+a55Rw6EHXOQ+vih5TPXa1t5RL7IkY
+4U7Ld5ExptBIDx0UkSihYexAY4RGXVUaq535dGtJQ8/NYMrJ5NMGt2X0bRszArnE
+EKc/qdAcgcalgoiaZtVkq45eXADXzwIDAQABo4GiMIGfMB0GA1UdDgQWBBSRdzZ7
+LrRp8yfqt/YIi0ojohFJxjBdBgNVHSMEVjBUgBSRdzZ7LrRp8yfqt/YIi0ojohFJ
+xqExpC8wLTELMAkGA1UEBhMCSVQxDDAKBgNVBAoMA0lHSTEQMA4GA1UEAwwHVGVz
+dCBDQYIJAMzDwAv7o5VUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQB379cvZmfCLvGdoGbW+6ppDNy3pT9hqYmZAlfV
+FGZSEaTKjGCbPuErUNC6+7zhij5CmMtMRhccI3JswjPHPQGm12jiEC492J6Avj/x
+PL8vcBRofe4whXefDVgUw8G1nkQYr2BF0jzeiN72ToISGMbt/q94QV70lYCo/Tog
+UQQ6F+XhztffxQyRgsUXhR4qq1D4h7UifqfQGBzknS23RMLQUdKXG4MhTLMVmxJC
+uY9Oi0It3hk9Qtn0nlZ7rvo5weJGxuRBbZ85Nvw2tIhH7G2osc6zqmHTmUAR4FXb
+l8/ElwGVrURMMuJLDbISVXjBNFuVOS2BdlyEe4x5kfQAWITZ
+-----END CERTIFICATE-----
diff --git a/t/certs/README.md b/t/certs/README.md
index 4af2c71..2684175 100644
--- a/t/certs/README.md
+++ b/t/certs/README.md
@@ -10,7 +10,9 @@ Proxy certificates are generated using [VOMS client 3.3.1](http://italiangrid.gi
  * 4.pem: long-lived proxy with VOMS generic attributes containing reserved characters;
  * 5.pem: long-lived proxy with valid VOMS attributes, `*.lsc` file missing in `vomsdir`. 
  * 6.pem: long-lived proxy with valid VOMS attributes, with an old format for fqans. 
-
+ * 7.pem: long-lived proxy (3 delegations), without VOMS attributes;
+ * 8.pem: long-lived proxy (3 delegations), without VOMS attributes, plus CA
+   certificate included in the chain;
 
 To obtain such certificates the following command is used:
 
diff --git a/t/eec_subject.t b/t/eec_subject.t
new file mode 100644
index 0000000..9932f4e
--- /dev/null
+++ b/t/eec_subject.t
@@ -0,0 +1,136 @@
+use Test::Nginx::Socket 'no_plan';
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: rfc proxy certificate, no AC
+--- main_config
+    env OPENSSL_ALLOW_PROXY_CERTS=1;
+    env X509_VOMS_DIR=t/vomsdir;
+    env X509_CERT_DIR=t/trust-anchors;
+--- http_config
+    server {
+        error_log logs/error.log debug;
+        listen 8443 ssl;
+        ssl_certificate ../../certs/nginx_voms_example.cert.pem;
+        ssl_certificate_key ../../certs/nginx_voms_example.key.pem;
+        ssl_client_certificate ../../trust-anchors/igi-test-ca.pem;
+        ssl_verify_depth 10;
+        ssl_verify_client on;
+	location = / {
+            default_type text/plain;
+            echo $ssl_client_ee_s_dn;
+        }
+    }
+--- config
+    location = / {
+        error_log logs/error-proxy.log debug;
+        proxy_pass https://localhost:8443/;
+        proxy_ssl_certificate ../../certs/0.cert.pem;
+        proxy_ssl_certificate_key ../../certs/0.key.pem;
+    }
+--- request
+GET / 
+--- response_body
+CN=test0,O=IGI,C=IT
+--- error_code: 200
+
+=== TEST 2: standard x.509 certificate 
+--- main_config
+    env OPENSSL_ALLOW_PROXY_CERTS=1;
+    env X509_VOMS_DIR=t/vomsdir;
+    env X509_CERT_DIR=t/trust-anchors;
+--- http_config
+    server {
+        error_log logs/error.log debug;
+        listen 8443 ssl;
+        ssl_certificate ../../certs/nginx_voms_example.cert.pem;
+        ssl_certificate_key ../../certs/nginx_voms_example.key.pem;
+        ssl_client_certificate ../../trust-anchors/igi-test-ca.pem;
+        ssl_verify_depth 10;
+        ssl_verify_client on;
+	location = / {
+            default_type text/plain;
+            echo $ssl_client_ee_s_dn;
+            echo $ssl_client_s_dn;
+        }
+    }
+--- config
+    location = / {
+        error_log logs/error-proxy.log debug;
+        proxy_pass https://localhost:8443/;
+        proxy_ssl_certificate ../../certs/nginx_voms_example.cert.pem;
+        proxy_ssl_certificate_key ../../certs/nginx_voms_example.key.pem;
+    }
+--- request
+GET / 
+--- response_body
+CN=nginx-voms.example,O=IGI,C=IT
+CN=nginx-voms.example,O=IGI,C=IT
+--- error_code: 200
+
+=== TEST 3: three delegations proxy
+--- main_config
+    env OPENSSL_ALLOW_PROXY_CERTS=1;
+    env X509_VOMS_DIR=t/vomsdir;
+    env X509_CERT_DIR=t/trust-anchors;
+--- http_config
+    server {
+        error_log logs/error.log debug;
+        listen 8443 ssl;
+        ssl_certificate ../../certs/nginx_voms_example.cert.pem;
+        ssl_certificate_key ../../certs/nginx_voms_example.key.pem;
+        ssl_client_certificate ../../trust-anchors/igi-test-ca.pem;
+        ssl_verify_depth 10;
+        ssl_verify_client on;
+	location = / {
+            default_type text/plain;
+            echo $ssl_client_ee_s_dn;
+        }
+    }
+--- config
+    location = / {
+        error_log logs/error-proxy.log debug;
+        proxy_pass https://localhost:8443/;
+        proxy_ssl_certificate ../../certs/7.cert.pem;
+        proxy_ssl_certificate_key ../../certs/7.key.pem;
+    }
+--- request
+GET / 
+--- response_body
+CN=test0,O=IGI,C=IT
+--- error_code: 200
+
+
+=== TEST 4: three delegations proxy + CA cert
+--- main_config
+    env OPENSSL_ALLOW_PROXY_CERTS=1;
+    env X509_VOMS_DIR=t/vomsdir;
+    env X509_CERT_DIR=t/trust-anchors;
+--- http_config
+    server {
+        error_log logs/error.log debug;
+        listen 8443 ssl;
+        ssl_certificate ../../certs/nginx_voms_example.cert.pem;
+        ssl_certificate_key ../../certs/nginx_voms_example.key.pem;
+        ssl_client_certificate ../../trust-anchors/igi-test-ca.pem;
+        ssl_verify_depth 10;
+        ssl_verify_client on;
+	location = / {
+            default_type text/plain;
+            echo $ssl_client_ee_s_dn;
+        }
+    }
+--- config
+    location = / {
+        error_log logs/error-proxy.log debug;
+        proxy_pass https://localhost:8443/;
+        proxy_ssl_certificate ../../certs/8.cert.pem;
+        proxy_ssl_certificate_key ../../certs/8.key.pem;
+    }
+--- request
+GET / 
+--- response_body
+CN=test0,O=IGI,C=IT
+--- error_code: 200
-- 
GitLab


From a7ad6f58fa374e341a1551456c1536c235cf7516 Mon Sep 17 00:00:00 2001
From: Andrea Ceccanti <andrea.ceccanti@gmail.com>
Date: Tue, 26 Jun 2018 16:14:43 +0200
Subject: [PATCH 3/5] Support for ssl_client_ee_i_dn

---
 src/ngx_http_voms_module.cpp | 92 ++++++++++++++++++++++++++++++++++--
 t/eec_subject.t              | 10 ++++
 2 files changed, 99 insertions(+), 3 deletions(-)

diff --git a/src/ngx_http_voms_module.cpp b/src/ngx_http_voms_module.cpp
index f08cf6e..f16e6fa 100644
--- a/src/ngx_http_voms_module.cpp
+++ b/src/ngx_http_voms_module.cpp
@@ -33,6 +33,11 @@ using X509Ptr = std::unique_ptr<X509, decltype(&X509_free)>;
 using VomsAc = voms;
 using MaybeVomsAc = boost::optional<VomsAc>;
 
+enum EECSubjectOrIssuer {
+  SUBJECT,
+  ISSUER
+};
+
 static ngx_int_t add_variables(ngx_conf_t* cf);
 
 static ngx_http_module_t ctx = {
@@ -67,7 +72,8 @@ static ngx_int_t generic_getter(  //
     ngx_http_request_t* r,
     ngx_http_variable_value_t* v,
     uintptr_t data);
-static ngx_int_t get_ssl_client_ee_s_dn(  //
+
+static ngx_int_t get_ssl_client_ee_dn(  //
     ngx_http_request_t* r,
     ngx_http_variable_value_t* v,
     uintptr_t data);
@@ -177,8 +183,16 @@ static ngx_http_variable_t variables[] = {
     {
         ngx_string("ssl_client_ee_s_dn"),
         NULL,
-        get_ssl_client_ee_s_dn,
-        0,
+        get_ssl_client_ee_dn,
+        SUBJECT,
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("ssl_client_ee_i_dn"),
+        NULL,
+        get_ssl_client_ee_dn,
+        ISSUER,
         NGX_HTTP_VAR_NOCACHEABLE,
         0  //
     },
@@ -218,6 +232,78 @@ static bool is_proxy(X509* cert)
   return X509_get_extension_flags(cert) & EXFLAG_PROXY;
 }
 
+static ngx_int_t get_ssl_client_ee_dn(ngx_http_request_t* r,
+                                        ngx_http_variable_value_t* v,
+                                        uintptr_t data)
+{
+
+  ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __func__);
+
+  v->not_found = 1;
+  v->valid = 0;
+
+  auto chain = SSL_get_peer_cert_chain(r->connection->ssl->connection);
+  if (!chain) {
+    ngx_log_error(
+        NGX_LOG_ERR, r->connection->log, 0, "SSL_get_peer_cert_chain() failed");
+    return NGX_OK;
+  }
+  
+  X509* ee_cert = nullptr;
+
+  if (sk_X509_num(chain) == 0) {
+    ee_cert = SSL_get_peer_certificate(r->connection->ssl->connection);
+  } else {
+    // find first non-proxy
+    for (int i = 0; i != sk_X509_num(chain); ++i) {
+      auto cert = sk_X509_value(chain, i);
+      if (cert && !is_proxy(cert)) {
+        ee_cert = cert;
+        break;
+      }
+    }
+  }
+
+  if (!ee_cert) {
+    ngx_log_error(NGX_LOG_DEBUG,
+                  r->connection->log,
+                  0,
+                  "cannot identify end-entity certificate");
+    return NGX_OK;
+  }
+
+  X509_NAME* dn = nullptr;
+
+  if (data == SUBJECT) {
+    dn = X509_get_subject_name(ee_cert);
+  } else {
+    dn = X509_get_issuer_name(ee_cert);
+  }
+
+  if (!dn) {
+    ngx_log_error(NGX_LOG_DEBUG,
+                  r->connection->log,
+                  0,
+                  "cannot get dn from certificate");
+    return NGX_OK;
+  }
+  std::string value = to_rfc2253(dn);
+
+  auto buffer = static_cast<u_char*>(ngx_pnalloc(r->pool, value.size()));
+  if (!buffer) {
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
+    return NGX_OK;
+  }
+  ngx_memcpy(buffer, value.c_str(), value.size());
+
+  v->data = buffer;
+  v->len = value.size();
+  v->valid = 1;
+  v->not_found = 0;
+  v->no_cacheable = 0;
+  return NGX_OK;
+}
+      
 static ngx_int_t get_ssl_client_ee_s_dn(ngx_http_request_t* r,
                                         ngx_http_variable_value_t* v,
                                         uintptr_t data)
diff --git a/t/eec_subject.t b/t/eec_subject.t
index 9932f4e..a1e316e 100644
--- a/t/eec_subject.t
+++ b/t/eec_subject.t
@@ -21,6 +21,7 @@ __DATA__
 	location = / {
             default_type text/plain;
             echo $ssl_client_ee_s_dn;
+            echo $ssl_client_ee_i_dn;
         }
     }
 --- config
@@ -34,6 +35,7 @@ __DATA__
 GET / 
 --- response_body
 CN=test0,O=IGI,C=IT
+CN=Test CA,O=IGI,C=IT
 --- error_code: 200
 
 === TEST 2: standard x.509 certificate 
@@ -54,6 +56,8 @@ CN=test0,O=IGI,C=IT
             default_type text/plain;
             echo $ssl_client_ee_s_dn;
             echo $ssl_client_s_dn;
+            echo $ssl_client_ee_i_dn;
+            echo $ssl_client_i_dn;
         }
     }
 --- config
@@ -68,6 +72,8 @@ GET /
 --- response_body
 CN=nginx-voms.example,O=IGI,C=IT
 CN=nginx-voms.example,O=IGI,C=IT
+CN=Test CA,O=IGI,C=IT
+CN=Test CA,O=IGI,C=IT
 --- error_code: 200
 
 === TEST 3: three delegations proxy
@@ -87,6 +93,7 @@ CN=nginx-voms.example,O=IGI,C=IT
 	location = / {
             default_type text/plain;
             echo $ssl_client_ee_s_dn;
+            echo $ssl_client_ee_i_dn;
         }
     }
 --- config
@@ -100,6 +107,7 @@ CN=nginx-voms.example,O=IGI,C=IT
 GET / 
 --- response_body
 CN=test0,O=IGI,C=IT
+CN=Test CA,O=IGI,C=IT
 --- error_code: 200
 
 
@@ -120,6 +128,7 @@ CN=test0,O=IGI,C=IT
 	location = / {
             default_type text/plain;
             echo $ssl_client_ee_s_dn;
+            echo $ssl_client_ee_i_dn;
         }
     }
 --- config
@@ -133,4 +142,5 @@ CN=test0,O=IGI,C=IT
 GET / 
 --- response_body
 CN=test0,O=IGI,C=IT
+CN=Test CA,O=IGI,C=IT
 --- error_code: 200
-- 
GitLab


From bdd5f835449ac1ca287c8c74b112a7592d9d613e Mon Sep 17 00:00:00 2001
From: Francesco Giacomini <giaco at cnaf dot infn dot it>
Date: Tue, 26 Jun 2018 17:20:25 +0200
Subject: [PATCH 4/5] fix issue #14

---
 src/ngx_http_voms_module.cpp | 110 +++++++----------------------------
 1 file changed, 20 insertions(+), 90 deletions(-)

diff --git a/src/ngx_http_voms_module.cpp b/src/ngx_http_voms_module.cpp
index f16e6fa..bf64344 100644
--- a/src/ngx_http_voms_module.cpp
+++ b/src/ngx_http_voms_module.cpp
@@ -33,10 +33,7 @@ using X509Ptr = std::unique_ptr<X509, decltype(&X509_free)>;
 using VomsAc = voms;
 using MaybeVomsAc = boost::optional<VomsAc>;
 
-enum EECSubjectOrIssuer {
-  SUBJECT,
-  ISSUER
-};
+enum class EeDn { SUBJECT, ISSUER };
 
 static ngx_int_t add_variables(ngx_conf_t* cf);
 
@@ -184,7 +181,7 @@ static ngx_http_variable_t variables[] = {
         ngx_string("ssl_client_ee_s_dn"),
         NULL,
         get_ssl_client_ee_dn,
-        SUBJECT,
+        static_cast<uintptr_t>(EeDn::SUBJECT),
         NGX_HTTP_VAR_NOCACHEABLE,
         0  //
     },
@@ -192,7 +189,7 @@ static ngx_http_variable_t variables[] = {
         ngx_string("ssl_client_ee_i_dn"),
         NULL,
         get_ssl_client_ee_dn,
-        ISSUER,
+        static_cast<uintptr_t>(EeDn::ISSUER),
         NGX_HTTP_VAR_NOCACHEABLE,
         0  //
     },
@@ -221,7 +218,7 @@ static std::string to_rfc2253(X509_NAME* name)
 }
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
-uint32_t X509_get_extension_flags(X509* x)
+static uint32_t X509_get_extension_flags(X509* x)
 {
   return x->ex_flags;
 }
@@ -233,10 +230,9 @@ static bool is_proxy(X509* cert)
 }
 
 static ngx_int_t get_ssl_client_ee_dn(ngx_http_request_t* r,
-                                        ngx_http_variable_value_t* v,
-                                        uintptr_t data)
+                                      ngx_http_variable_value_t* v,
+                                      uintptr_t data)
 {
-
   ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __func__);
 
   v->not_found = 1;
@@ -248,7 +244,7 @@ static ngx_int_t get_ssl_client_ee_dn(ngx_http_request_t* r,
         NGX_LOG_ERR, r->connection->log, 0, "SSL_get_peer_cert_chain() failed");
     return NGX_OK;
   }
-  
+
   X509* ee_cert = nullptr;
 
   if (sk_X509_num(chain) == 0) {
@@ -272,90 +268,28 @@ static ngx_int_t get_ssl_client_ee_dn(ngx_http_request_t* r,
     return NGX_OK;
   }
 
-  X509_NAME* dn = nullptr;
-
-  if (data == SUBJECT) {
-    dn = X509_get_subject_name(ee_cert);
-  } else {
-    dn = X509_get_issuer_name(ee_cert);
+  X509_NAME* dn;
+
+  switch (static_cast<EeDn>(data)) {
+    case EeDn::SUBJECT:
+      dn = X509_get_subject_name(ee_cert);
+      break;
+    case EeDn::ISSUER:
+      dn = X509_get_issuer_name(ee_cert);
+      break;
+    default:
+      dn = nullptr;
   }
 
   if (!dn) {
-    ngx_log_error(NGX_LOG_DEBUG,
-                  r->connection->log,
-                  0,
-                  "cannot get dn from certificate");
-    return NGX_OK;
-  }
-  std::string value = to_rfc2253(dn);
-
-  auto buffer = static_cast<u_char*>(ngx_pnalloc(r->pool, value.size()));
-  if (!buffer) {
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
-    return NGX_OK;
-  }
-  ngx_memcpy(buffer, value.c_str(), value.size());
-
-  v->data = buffer;
-  v->len = value.size();
-  v->valid = 1;
-  v->not_found = 0;
-  v->no_cacheable = 0;
-  return NGX_OK;
-}
-      
-static ngx_int_t get_ssl_client_ee_s_dn(ngx_http_request_t* r,
-                                        ngx_http_variable_value_t* v,
-                                        uintptr_t data)
-{
-  ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __func__);
-
-  v->not_found = 1;
-  v->valid = 0;
-
-  auto chain = SSL_get_peer_cert_chain(r->connection->ssl->connection);
-  if (!chain) {
     ngx_log_error(
-        NGX_LOG_ERR, r->connection->log, 0, "SSL_get_peer_cert_chain() failed");
-    return NGX_OK;
-  }
-  
-  X509* ee_cert = nullptr;
-
-  if (sk_X509_num(chain) == 0) {
-    ee_cert = SSL_get_peer_certificate(r->connection->ssl->connection);
-  } else {
-    // find first non-proxy
-    for (int i = 0; i != sk_X509_num(chain); ++i) {
-      auto cert = sk_X509_value(chain, i);
-      if (cert && !is_proxy(cert)) {
-        ee_cert = cert;
-        break;
-      }
-    }
-  }
-
-  if (!ee_cert) {
-    ngx_log_error(NGX_LOG_DEBUG,
-                  r->connection->log,
-                  0,
-                  "cannot identify end-entity certificate");
-    return NGX_OK;
-  }
-
-  auto dn = X509_get_subject_name(ee_cert);
-  if (!dn) {
-    ngx_log_error(NGX_LOG_DEBUG,
-                  r->connection->log,
-                  0,
-                  "cannot get subject dn from certificate");
+        NGX_LOG_DEBUG, r->connection->log, 0, "cannot get DN from certificate");
     return NGX_OK;
   }
   std::string value = to_rfc2253(dn);
 
   auto buffer = static_cast<u_char*>(ngx_pnalloc(r->pool, value.size()));
   if (!buffer) {
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
     return NGX_OK;
   }
   ngx_memcpy(buffer, value.c_str(), value.size());
@@ -389,10 +323,7 @@ static MaybeVomsAc retrieve_voms_ac_from_proxy(ngx_http_request_t* r)
   ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __func__);
 
   if (!r->http_connection->ssl) {
-    ngx_log_error(NGX_LOG_ERR,
-                  r->connection->log,
-                  0,
-                  "SSL not enabled");
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "SSL not enabled");
     return boost::none;
   }
 
@@ -497,7 +428,6 @@ static ngx_int_t generic_getter(ngx_http_request_t* r,
 
   auto buffer = static_cast<u_char*>(ngx_pnalloc(r->pool, value.size()));
   if (!buffer) {
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
     return NGX_OK;
   }
   ngx_memcpy(buffer, value.c_str(), value.size());
-- 
GitLab


From d904aca125bb9815359ed8b6ca2a33f0a98ad1a4 Mon Sep 17 00:00:00 2001
From: Francesco Giacomini <giaco at cnaf dot infn dot it>
Date: Tue, 26 Jun 2018 17:33:31 +0200
Subject: [PATCH 5/5] update documentation

---
 README.md | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/README.md b/README.md
index 2106e51..ed301d6 100644
--- a/README.md
+++ b/README.md
@@ -33,12 +33,24 @@ The Subject of the End-Entity certificate, used to sign the proxy.
 
 _Example_: ``/C=IT/O=IGI/CN=test0``
 
+### ssl_client_ee_s_dn
+
+Like `voms_user`, the Subject of the End-Entity certificate. Unlike `voms_user`, it is available even for non-VOMS proxies and is formatted according to RFC 2253.
+
+_Example_: ``CN=test0,O=IGI,C=IT``
+
 ### voms_user_ca
 
 The Issuer (Certificate Authority) of the End-Entity certificate.
 
 _Example_: ``/C=IT/O=IGI/CN=Test CA``
 
+### ssl_client_ee_i_dn
+
+Like `voms_user_ca`, the Issuer of the End-Entity certificate. Unlike `voms_user_ca`, it is available even for non-VOMS proxies and is formatted according to RFC 2253.
+
+_Example_: ``CN=Test CA,O=IGI,C=IT``
+
 ### voms_fqans
 
 A comma-separated list of Fully Qualified Attribute Names. See [The VOMS Attribute Certificate Format](http://ogf.org/documents/GFD.182.pdf) for more details.
-- 
GitLab