mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
Improve mod_ssl's environment variable extraction to correctly handle
DNs with duplicate tags: * modules/ssl/ssl_engine_vars.c: Augment the ssl_var_lookup_ssl_cert_dn_rec table with a flag to indicate whether RDNs of the given NID should be extracted to the environment. (extract_dn, modssl_var_extract_dns): New functions. * modules/ssl/ssl_private.h (modssl_var_extract_dns): Add prototype. * modules/ssl/ssl_engine_kernel.c: Remove SSL_*_DN_ from the list of variables to insert into the environment. (ssl_hook_Fixup): Use modssl_var_extract_dns to insert the SSL_*_DN_ variables efficiently and accurately, handling certs with duplicate RDN tags correctly. PR: 45875 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@724717 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
4
CHANGES
4
CHANGES
@@ -2,6 +2,10 @@
|
||||
Changes with Apache 2.3.1
|
||||
[ When backported to 2.2.x, remove entry from this file ]
|
||||
|
||||
*) mod_ssl: Improve environment variable extraction to be more
|
||||
efficient and to correctly handle DNs with duplicate tags.
|
||||
PR 45975. [Joe Orton]
|
||||
|
||||
*) Remove the obsolete serial attribute from the RPM spec file. Compile
|
||||
against the external pcre. Add missing binaries fcgistarter, and
|
||||
mod_socache* and mod_session*. [Graham Leggett]
|
||||
|
@@ -1012,68 +1012,12 @@ static const char *ssl_hook_Fixup_vars[] = {
|
||||
"SSL_CLIENT_V_START",
|
||||
"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",
|
||||
"SSL_SERVER_M_SERIAL",
|
||||
"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",
|
||||
@@ -1125,6 +1069,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);
|
||||
|
@@ -402,28 +402,32 @@ 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_x500UniqueIdentifier /* new name as of Openssl 0.9.7 */
|
||||
{ "UID", NID_x500UniqueIdentifier },
|
||||
{ "UID", NID_x500UniqueIdentifier, 1 },
|
||||
#else /* old name, OpenSSL < 0.9.7 */
|
||||
{ "UID", NID_uniqueIdentifier },
|
||||
{ "UID", NID_uniqueIdentifier, 1 },
|
||||
#endif
|
||||
{ "Email", NID_pkcs9_emailAddress },
|
||||
{ "Email", NID_pkcs9_emailAddress, 1 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -673,6 +677,95 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer,
|
||||
const char *extension)
|
||||
|
@@ -647,6 +647,10 @@ apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, const cha
|
||||
|
||||
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);
|
||||
|
||||
#ifdef HAVE_OCSP
|
||||
/* Perform OCSP validation of the current cert in the given context.
|
||||
* Returns non-zero on success or zero on failure. On failure, the
|
||||
|
Reference in New Issue
Block a user