]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
* mod_ssl: Improve environment variable extraction to be more
authorJim Jagielski <jim@apache.org>
Mon, 15 Feb 2010 19:50:59 +0000 (19:50 +0000)
committerJim Jagielski <jim@apache.org>
Mon, 15 Feb 2010 19:50:59 +0000 (19:50 +0000)
  efficient and to correctly handle DNs with duplicate tags.
  PR 45875.
  Trunk Patch: http://svn.apache.org/viewvc?view=rev&revision=724717
               http://svn.apache.org/viewvc?view=rev&revision=813165
               http://svn.apache.org/viewvc?view=rev&revision=820401
  2.2.x Patch: http://people.apache.org/~minfrin/ssl-env2.diff
  +1: minfrin, fuankg, jim

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@910319 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_engine_vars.c
modules/ssl/ssl_private.h

diff --git a/CHANGES b/CHANGES
index 9840e916a566be58788b5b154c8d8889ae43ade2..98b2c176010e1d1fbbca5aa0b234bf3819ee603a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,10 @@ Changes with Apache 2.2.15
      access control is still vulnerable, unless using OpenSSL >= 0.9.8l.
      [Joe Orton, Ruediger Pluem, Hartmut Keil <Hartmut.Keil adnovum.ch>]
 
+  *) mod_ssl: Reintroduce SSL_CLIENT_S_DN, SSL_CLIENT_I_DN, SSL_SERVER_S_DN,
+     SSL_SERVER_I_DN back to the environment variables to be set by mod_ssl.
+     [Peter Sylvester <peter.sylvester edelweb.fr>]
+
   *) mod_authnz_ldap: Failures to map a username to a DN, or to check a user
      password now result in an informational level log entry instead of 
      warning level.  [Eric Covener]
diff --git a/STATUS b/STATUS
index 23c1b4b00c3913587c260c9fe5b88d70f7215125..0311d44756f6a55b94064676f34f42c35ed029d5 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -87,15 +87,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
- * mod_ssl: Improve environment variable extraction to be more
-   efficient and to correctly handle DNs with duplicate tags.
-   PR 45975.
-   Trunk Patch: http://svn.apache.org/viewvc?view=rev&revision=724717
-                http://svn.apache.org/viewvc?view=rev&revision=813165
-                http://svn.apache.org/viewvc?view=rev&revision=820401
-   2.2.x Patch: http://people.apache.org/~minfrin/ssl-env2.diff
-   +1: minfrin, fuankg, jim
-
   * worker: Don't log MaxClients until we actually hit it.  Warn when within
     MinSpareThreads of MaxClients.
     Trunk patch: http://svn.apache.org/viewvc?rev=906535&view=rev
index f0e051d0964e60c674ed10ee9dd0513a2bf30a1c..05ace714b792ac32bfcaf1efb57e151c27232382 100644 (file)
@@ -1079,33 +1079,7 @@ static const char *ssl_hook_Fixup_vars[] = {
     "SSL_CLIENT_V_END",
     "SSL_CLIENT_V_REMAIN",
     "SSL_CLIENT_S_DN",
-    "SSL_CLIENT_S_DN_C",
-    "SSL_CLIENT_S_DN_ST",
-    "SSL_CLIENT_S_DN_L",
-    "SSL_CLIENT_S_DN_O",
-    "SSL_CLIENT_S_DN_OU",
-    "SSL_CLIENT_S_DN_CN",
-    "SSL_CLIENT_S_DN_T",
-    "SSL_CLIENT_S_DN_I",
-    "SSL_CLIENT_S_DN_G",
-    "SSL_CLIENT_S_DN_S",
-    "SSL_CLIENT_S_DN_D",
-    "SSL_CLIENT_S_DN_UID",
-    "SSL_CLIENT_S_DN_Email",
     "SSL_CLIENT_I_DN",
-    "SSL_CLIENT_I_DN_C",
-    "SSL_CLIENT_I_DN_ST",
-    "SSL_CLIENT_I_DN_L",
-    "SSL_CLIENT_I_DN_O",
-    "SSL_CLIENT_I_DN_OU",
-    "SSL_CLIENT_I_DN_CN",
-    "SSL_CLIENT_I_DN_T",
-    "SSL_CLIENT_I_DN_I",
-    "SSL_CLIENT_I_DN_G",
-    "SSL_CLIENT_I_DN_S",
-    "SSL_CLIENT_I_DN_D",
-    "SSL_CLIENT_I_DN_UID",
-    "SSL_CLIENT_I_DN_Email",
     "SSL_CLIENT_A_KEY",
     "SSL_CLIENT_A_SIG",
     "SSL_SERVER_M_VERSION",
@@ -1113,33 +1087,7 @@ static const char *ssl_hook_Fixup_vars[] = {
     "SSL_SERVER_V_START",
     "SSL_SERVER_V_END",
     "SSL_SERVER_S_DN",
-    "SSL_SERVER_S_DN_C",
-    "SSL_SERVER_S_DN_ST",
-    "SSL_SERVER_S_DN_L",
-    "SSL_SERVER_S_DN_O",
-    "SSL_SERVER_S_DN_OU",
-    "SSL_SERVER_S_DN_CN",
-    "SSL_SERVER_S_DN_T",
-    "SSL_SERVER_S_DN_I",
-    "SSL_SERVER_S_DN_G",
-    "SSL_SERVER_S_DN_S",
-    "SSL_SERVER_S_DN_D",
-    "SSL_SERVER_S_DN_UID",
-    "SSL_SERVER_S_DN_Email",
     "SSL_SERVER_I_DN",
-    "SSL_SERVER_I_DN_C",
-    "SSL_SERVER_I_DN_ST",
-    "SSL_SERVER_I_DN_L",
-    "SSL_SERVER_I_DN_O",
-    "SSL_SERVER_I_DN_OU",
-    "SSL_SERVER_I_DN_CN",
-    "SSL_SERVER_I_DN_T",
-    "SSL_SERVER_I_DN_I",
-    "SSL_SERVER_I_DN_G",
-    "SSL_SERVER_I_DN_S",
-    "SSL_SERVER_I_DN_D",
-    "SSL_SERVER_I_DN_UID",
-    "SSL_SERVER_I_DN_Email",
     "SSL_SERVER_A_KEY",
     "SSL_SERVER_A_SIG",
     "SSL_SESSION_ID",
@@ -1186,6 +1134,8 @@ int ssl_hook_Fixup(request_rec *r)
 
     /* standard SSL environment variables */
     if (dc->nOptions & SSL_OPT_STDENVVARS) {
+        modssl_var_extract_dns(env, sslconn->ssl, r->pool);
+
         for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
             var = (char *)ssl_hook_Fixup_vars[i];
             val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
index eb136077a1213bb98206fda9fac47728637577b2..dd235a809fe51347ce2c60a5538a8694917d678b 100644 (file)
@@ -402,27 +402,31 @@ static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var)
     return result;
 }
 
+/* In this table, .extract is non-zero if RDNs using the NID should be
+ * extracted to for the SSL_{CLIENT,SERVER}_{I,S}_DN_* environment
+ * variables. */
 static const struct {
     char *name;
     int   nid;
+    int   extract;
 } ssl_var_lookup_ssl_cert_dn_rec[] = {
-    { "C",     NID_countryName            },
-    { "ST",    NID_stateOrProvinceName    }, /* officially    (RFC2156) */
-    { "SP",    NID_stateOrProvinceName    }, /* compatibility (SSLeay)  */
-    { "L",     NID_localityName           },
-    { "O",     NID_organizationName       },
-    { "OU",    NID_organizationalUnitName },
-    { "CN",    NID_commonName             },
-    { "T",     NID_title                  },
-    { "I",     NID_initials               },
-    { "G",     NID_givenName              },
-    { "S",     NID_surname                },
-    { "D",     NID_description            },
+    { "C",     NID_countryName,            1 },
+    { "ST",    NID_stateOrProvinceName,    1 }, /* officially    (RFC2156) */
+    { "SP",    NID_stateOrProvinceName,    0 }, /* compatibility (SSLeay)  */
+    { "L",     NID_localityName,           1 },
+    { "O",     NID_organizationName,       1 },
+    { "OU",    NID_organizationalUnitName, 1 },
+    { "CN",    NID_commonName,             1 },
+    { "T",     NID_title,                  1 },
+    { "I",     NID_initials,               1 },
+    { "G",     NID_givenName,              1 },
+    { "S",     NID_surname,                1 },
+    { "D",     NID_description,            1 },
 #ifdef NID_userId
-    { "UID",   NID_userId                 },
+    { "UID",   NID_x500UniqueIdentifier,   1 },
 #endif
-    { "Email", NID_pkcs9_emailAddress     },
-    { NULL,    0                          }
+    { "Email", NID_pkcs9_emailAddress,     1 },
+    { NULL,    0,                          0 }
 };
 
 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var)
@@ -671,6 +675,96 @@ static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
     return NULL;
 }
 
+/* Add each RDN in 'xn' to the table 't' where the NID is present in
+ * 'nids', using key prefix 'pfx'.  */
+static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, 
+                       X509_NAME *xn, apr_pool_t *p)
+{
+    STACK_OF(X509_NAME_ENTRY) *ents = X509_NAME_get_entries(xn);
+    X509_NAME_ENTRY *xsne;
+    apr_hash_t *count;
+    int i, nid;
+  
+    /* Hash of (int) NID -> (int *) counter to count each time an RDN
+     * with the given NID has been seen. */
+    count = apr_hash_make(p);
+
+    /* For each RDN... */
+    for (i = 0; i < sk_X509_NAME_ENTRY_num(ents); i++) {
+         const char *tag;
+
+         xsne = sk_X509_NAME_ENTRY_value(ents, i);
+
+         /* Retrieve the nid, and check whether this is one of the nids
+          * which are to be extracted. */
+         nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
+
+         tag = apr_hash_get(nids, &nid, sizeof nid);
+         if (tag) {
+             unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne);
+             const char *key;
+             int *dup;
+             char *value;
+
+             /* Check whether a variable with this nid was already
+              * been used; if so, use the foo_N=bar syntax. */
+             dup = apr_hash_get(count, &nid, sizeof nid);
+             if (dup) {
+                 key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup));
+             }
+             else {
+                 /* Otherwise, use the plain foo=bar syntax. */
+                 dup = apr_pcalloc(p, sizeof *dup);
+                 apr_hash_set(count, &nid, sizeof nid, dup);
+                 key = apr_pstrcat(p, pfx, tag, NULL);
+             }
+             
+             /* cast needed from 'unsigned char *' to 'char *' */
+             value = apr_pstrmemdup(p, (char *)data,
+                                    X509_NAME_ENTRY_get_data_len(xsne));
+#if APR_CHARSET_EBCDIC
+             ap_xlate_proto_from_ascii(value, X509_NAME_ENTRY_get_data_len(xsne));
+#endif /* APR_CHARSET_EBCDIC */
+             apr_table_setn(t, key, value);
+         }
+    }
+}
+
+void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p)
+{
+    apr_hash_t *nids;
+    unsigned n;
+    X509 *xs;
+
+    /* Build up a hash table of (int *)NID->(char *)short-name for all
+     * the tags which are to be extracted: */
+    nids = apr_hash_make(p);
+    for (n = 0; ssl_var_lookup_ssl_cert_dn_rec[n].name; n++) {
+        if (ssl_var_lookup_ssl_cert_dn_rec[n].extract) {
+            apr_hash_set(nids, &ssl_var_lookup_ssl_cert_dn_rec[n].nid,
+                         sizeof(ssl_var_lookup_ssl_cert_dn_rec[0].nid),
+                         ssl_var_lookup_ssl_cert_dn_rec[n].name);
+        }
+    }
+    
+    /* Extract the server cert DNS -- note that the refcount does NOT
+     * increase: */
+    xs = SSL_get_certificate(ssl);
+    if (xs) {
+        extract_dn(t, nids, "SSL_SERVER_S_DN_", X509_get_subject_name(xs), p);
+        extract_dn(t, nids, "SSL_SERVER_I_DN_", X509_get_issuer_name(xs), p);
+    }
+    
+    /* Extract the client cert DNs -- note that the refcount DOES
+     * increase: */
+    xs = SSL_get_peer_certificate(ssl);
+    if (xs) {
+        extract_dn(t, nids, "SSL_CLIENT_S_DN_", X509_get_subject_name(xs), p);
+        extract_dn(t, nids, "SSL_CLIENT_I_DN_", X509_get_issuer_name(xs), p);
+        X509_free(xs);
+    }
+}
+
 const char *ssl_ext_lookup(apr_pool_t *p, conn_rec *c, int peer,
                            const char *oidnum)
 {
index 9a6915f1497ddfa33dc20972db8796dbc3884190..f6f488099f456e66b9357107e8d8d4dfd7d795d1 100644 (file)
@@ -695,6 +695,10 @@ extern apr_array_header_t *ssl_extlist_by_oid(request_rec *r, const char *oidstr
 
 void         ssl_var_log_config_register(apr_pool_t *p);
 
+/* Extract SSL_*_DN_* variables into table 't' from SSL object 'ssl',
+ * allocating from 'p': */
+void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p);
+
 #define APR_SHM_MAXSIZE (64 * 1024 * 1024)
 
 #endif /* SSL_PRIVATE_H */