From: Jim Jagielski Date: Mon, 15 Feb 2010 19:50:59 +0000 (+0000) Subject: * mod_ssl: Improve environment variable extraction to be more X-Git-Tag: 2.2.15~82 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=84b6cfcb59f616e0e6e85f4f78143c07377ee09c;p=thirdparty%2Fapache%2Fhttpd.git * mod_ssl: Improve environment variable extraction to be more 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 --- diff --git a/CHANGES b/CHANGES index 9840e916a56..98b2c176010 100644 --- 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 ] + *) 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 ] + *) 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 23c1b4b00c3..0311d44756f 100644 --- 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 diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index f0e051d0964..05ace714b79 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -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); diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index eb136077a12..dd235a809fe 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -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) { diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 9a6915f1497..f6f488099f4 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -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 */