summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Fritsch <sf@apache.org>2011-01-01 23:56:24 +0000
committerStefan Fritsch <sf@apache.org>2011-01-01 23:56:24 +0000
commit7403827278ff4dc120b59f83c5237050a922ecd2 (patch)
tree830013733bbb1c49439b4d29d0717660354d97ee
parent01755ffe635ad69bfb74871b4bdc36e228bfeb5a (diff)
downloadhttpd-7403827278ff4dc120b59f83c5237050a922ecd2.tar.gz
Change the format of the SSL_{CLIENT,SERVER}_{I,S}_DN variables
to be RFC 2253 compatible, convert non-ASCII characters to UTF8, and escape other special characters with backslashes. The old format can still be used with the LegacyDNStringFormat argument to SSLOptions. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1054323 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES5
-rw-r--r--docs/manual/mod/mod_ssl.xml19
-rw-r--r--docs/manual/upgrading.xml6
-rw-r--r--modules/ssl/ssl_engine_config.c3
-rw-r--r--modules/ssl/ssl_engine_vars.c107
-rw-r--r--modules/ssl/ssl_private.h2
-rw-r--r--modules/ssl/ssl_util_ssl.c29
-rw-r--r--modules/ssl/ssl_util_ssl.h1
8 files changed, 119 insertions, 53 deletions
diff --git a/CHANGES b/CHANGES
index c682177109..8d25db4e6d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,11 @@
Changes with Apache 2.3.11
+ *) mod_ssl: Change the format of the SSL_{CLIENT,SERVER}_{I,S}_DN variables
+ to be RFC 2253 compatible, convert non-ASCII characters to UTF8, and
+ escape other special characters with backslashes. The old format can
+ still be used with the LegacyDNStringFormat argument to SSLOptions.
+
*) core, mod_rewrite: Make the REQUEST_SCHEME variable available to
scripts and mod_rewrite. [Stefan Fritsch]
diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml
index 13f0a969ea..4cbb1ba266 100644
--- a/docs/manual/mod/mod_ssl.xml
+++ b/docs/manual/mod/mod_ssl.xml
@@ -106,6 +106,10 @@ attribute. For example, where the server certificate subject DN
included two OU fields, <code>SSL_SERVER_S_DN_OU_0</code> and
<code>SSL_SERVER_S_DN_OU_1</code> could be used to reference each.</p>
+<p>The format of the <em>*_DN</em> variables has changed in Apache HTTPD
+2.3.11. See the <code>LegacyDNStringFormat</code> option for
+<directive module="mod_ssl">SSLOptions</directive> for details.</p>
+
<p><code>SSL_CLIENT_V_REMAIN</code> is only available in version 2.1
and later.</p>
@@ -1181,6 +1185,21 @@ The available <em>option</em>s are:</p>
checks sometimes maybe not what the user expects, so enable this on a
per-directory basis only, please.</p>
</li>
+<li><code>LegacyDNStringFormat</code>
+ <p>
+ This option influences how values of the
+ <code>SSL_{CLIENT,SERVER}_{I,S}_DN</code> variables are formatted. Since
+ version 2.3.11, Apache HTTPD uses a RFC 2253 compatible format by
+ default. This uses commas as delimiters between the attributes, allows the
+ use of non-ASCII characters (which are converted to UTF8), escapes
+ various special characters with backslashes, and sorts the attributes
+ with the "C" attribute last.</p>
+
+ <p>If <code>LegacyDNStringFormat</code> is set, the old format will be
+ used which sorts the "C" attribute first, uses slashes as separators, and
+ does not handle non-ASCII and special characters in any consistent way.
+ </p>
+</li>
</ul>
<example><title>Example</title>
SSLOptions +FakeBasicAuth -StrictRequire<br />
diff --git a/docs/manual/upgrading.xml b/docs/manual/upgrading.xml
index a5f385da7e..e2ce3f7739 100644
--- a/docs/manual/upgrading.xml
+++ b/docs/manual/upgrading.xml
@@ -236,6 +236,12 @@
<li><module>mod_auto_index</module>: will now extract titles and
display descriptions for .xhtml files, which were previously
ignored.</li>
+
+ <li><module>mod_ssl</module>: The default format of the <code>*_DN</code>
+ variables has changed. The old format can still be used with the new
+ <code>LegacyDNStringFormat</code> argument to <directive
+ module="mod_ssl">SSLOptions</directive>.</li>
+
<li><program>htpasswd</program> now uses MD5 hash by default on
all platforms.</li>
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index 4bccfe72d6..029d3d77c5 100644
--- a/modules/ssl/ssl_engine_config.c
+++ b/modules/ssl/ssl_engine_config.c
@@ -1107,6 +1107,9 @@ const char *ssl_cmd_SSLOptions(cmd_parms *cmd,
else if (strcEQ(w, "OptRenegotiate")) {
opt = SSL_OPT_OPTRENEGOTIATE;
}
+ else if (strcEQ(w, "LegacyDNStringFormat")) {
+ opt = SSL_OPT_LEGACYDNFORMAT;
+ }
else {
return apr_pstrcat(cmd->pool,
"SSLOptions: Illegal option '", w, "'",
diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c
index d5cf63ba32..a8c0aef41f 100644
--- a/modules/ssl/ssl_engine_vars.c
+++ b/modules/ssl/ssl_engine_vars.c
@@ -39,8 +39,8 @@
** _________________________________________________________________
*/
-static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var);
-static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var);
+static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, char *var);
+static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var);
static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var);
static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm);
static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_UTCTIME *tm);
@@ -73,7 +73,7 @@ static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx_t *ctx,
static const char *expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
{
char *var = (char *)data;
- return ssl_var_lookup_ssl(ctx->p, ctx->c, var);
+ return ssl_var_lookup_ssl(ctx->p, ctx->c, ctx->r, var);
}
static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
@@ -241,7 +241,7 @@ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r,
SSLConnRec *sslconn = myConnConfig(c);
if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)
&& sslconn && sslconn->ssl)
- result = ssl_var_lookup_ssl(p, c, var+4);
+ result = ssl_var_lookup_ssl(p, c, r, var+4);
else if (strcEQ(var, "REMOTE_ADDR"))
result = c->remote_ip;
else if (strcEQ(var, "HTTPS")) {
@@ -313,7 +313,8 @@ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r,
return (char *)result;
}
-static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
+static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r,
+ char *var)
{
SSLConnRec *sslconn = myConnConfig(c);
char *result;
@@ -358,13 +359,17 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
}
else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
if ((xs = SSL_get_peer_certificate(ssl)) != NULL) {
- result = ssl_var_lookup_ssl_cert(p, xs, var+7);
+ result = ssl_var_lookup_ssl_cert(p, r, xs, var+7);
X509_free(xs);
}
}
else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
- if ((xs = SSL_get_certificate(ssl)) != NULL)
- result = ssl_var_lookup_ssl_cert(p, xs, var+7);
+ if ((xs = SSL_get_certificate(ssl)) != NULL) {
+ result = ssl_var_lookup_ssl_cert(p, r, xs, var+7);
+ /* SSL_get_certificate is different from SSL_get_peer_certificate.
+ * No need to X509_free(xs).
+ */
+ }
}
else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
result = ssl_var_lookup_ssl_compress_meth(ssl);
@@ -386,13 +391,44 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
return result;
}
-static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var)
+static char *ssl_var_lookup_ssl_cert_dn_oneline(apr_pool_t *p, request_rec *r,
+ X509_NAME *xsname)
+{
+ char *result;
+ SSLDirConfigRec *dc;
+ int legacy_format = 0;
+ if (r) {
+ dc = myDirConfig(r);
+ legacy_format = dc->nOptions & SSL_OPT_LEGACYDNFORMAT;
+ }
+ if (legacy_format) {
+ char *cp = X509_NAME_oneline(xsname, NULL, 0);
+ result = apr_pstrdup(p, cp);
+ modssl_free(cp);
+ }
+ else {
+ BIO* bio;
+ int n;
+ unsigned long flags = XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB;
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+ X509_NAME_print_ex(bio, xsname, 0, flags);
+ n = BIO_pending(bio);
+ result = apr_palloc(p, n+1);
+ n = BIO_read(bio, result, n);
+ result[n] = NUL;
+ BIO_free(bio);
+ }
+ return result;
+}
+
+static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs,
+ char *var)
{
char *result;
BOOL resdup;
X509_NAME *xsname;
int nid;
- char *cp;
result = NULL;
resdup = TRUE;
@@ -414,27 +450,23 @@ static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var)
result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs));
resdup = FALSE;
}
- else if (strcEQ(var, "S_DN")) {
- xsname = X509_get_subject_name(xs);
- cp = X509_NAME_oneline(xsname, NULL, 0);
- result = apr_pstrdup(p, cp);
- modssl_free(cp);
- resdup = FALSE;
- }
- else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
- xsname = X509_get_subject_name(xs);
- result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
- resdup = FALSE;
- }
- else if (strcEQ(var, "I_DN")) {
- xsname = X509_get_issuer_name(xs);
- cp = X509_NAME_oneline(xsname, NULL, 0);
- result = apr_pstrdup(p, cp);
- modssl_free(cp);
+ else if (*var && strcEQ(var+1, "_DN")) {
+ if (*var == 'S')
+ xsname = X509_get_subject_name(xs);
+ else if (*var == 'I')
+ xsname = X509_get_issuer_name(xs);
+ else
+ return NULL;
+ result = ssl_var_lookup_ssl_cert_dn_oneline(p, r, xsname);
resdup = FALSE;
}
- else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) {
- xsname = X509_get_issuer_name(xs);
+ else if (strlen(var) > 5 && strcEQn(var+1, "_DN_", 4)) {
+ if (*var == 'S')
+ xsname = X509_get_subject_name(xs);
+ else if (*var == 'I')
+ xsname = X509_get_issuer_name(xs);
+ else
+ return NULL;
result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
resdup = FALSE;
}
@@ -516,13 +548,7 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *
n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
- unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne);
- /* cast needed from unsigned char to char */
- result = apr_pstrmemdup(p, (char *)data,
- X509_NAME_ENTRY_get_data_len(xsne));
-#if APR_CHARSET_EBCDIC
- ap_xlate_proto_from_ascii(result, X509_NAME_ENTRY_get_data_len(xsne));
-#endif /* APR_CHARSET_EBCDIC */
+ result = SSL_X509_NAME_ENTRY_to_string(p, xsne);
break;
}
}
@@ -759,7 +785,6 @@ static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx,
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;
@@ -776,13 +801,7 @@ static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx,
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 */
+ value = SSL_X509_NAME_ENTRY_to_string(p, xsne);
apr_table_setn(t, key, value);
}
}
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index ae344a141d..d8d0cd27b7 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -230,7 +230,7 @@ typedef int ssl_algo_t;
#define SSL_OPT_FAKEBASICAUTH (1<<4)
#define SSL_OPT_STRICTREQUIRE (1<<5)
#define SSL_OPT_OPTRENEGOTIATE (1<<6)
-#define SSL_OPT_ALL (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE)
+#define SSL_OPT_LEGACYDNFORMAT (1<<7)
typedef int ssl_opt_t;
/**
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c
index f44c707fa3..722ab01f6c 100644
--- a/modules/ssl/ssl_util_ssl.c
+++ b/modules/ssl/ssl_util_ssl.c
@@ -344,14 +344,32 @@ BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen)
#endif
}
+/* convert a NAME_ENTRY to UTF8 string */
+char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne)
+{
+ char *result = NULL;
+ BIO* bio;
+ int len;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+ ASN1_STRING_print_ex(bio, X509_NAME_ENTRY_get_data(xsne),
+ ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_UTF8_CONVERT);
+ len = BIO_pending(bio);
+ result = apr_palloc(p, len+1);
+ len = BIO_read(bio, result, len);
+ result[len] = NUL;
+ BIO_free(bio);
+ ap_xlate_proto_from_ascii(value, len);
+ return result;
+}
+
/* retrieve subject CommonName of certificate */
BOOL SSL_X509_getCN(apr_pool_t *p, X509 *xs, char **cppCN)
{
X509_NAME *xsn;
X509_NAME_ENTRY *xsne;
int i, nid;
- unsigned char *data_ptr;
- int data_len;
xsn = X509_get_subject_name(xs);
for (i = 0; i < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *)
@@ -360,12 +378,7 @@ BOOL SSL_X509_getCN(apr_pool_t *p, X509 *xs, char **cppCN)
X509_NAME_get_entries(xsn), i);
nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
if (nid == NID_commonName) {
- data_ptr = X509_NAME_ENTRY_get_data_ptr(xsne);
- data_len = X509_NAME_ENTRY_get_data_len(xsne);
- *cppCN = apr_palloc(p, data_len+1);
- apr_cpystrn(*cppCN, (char *)data_ptr, data_len+1);
- (*cppCN)[data_len] = NUL;
- ap_xlate_proto_from_ascii(*cppCN, data_len);
+ *cppCN = SSL_X509_NAME_ENTRY_to_string(p, xsne);
return TRUE;
}
}
diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h
index 04bcbdc278..cabfb27c91 100644
--- a/modules/ssl/ssl_util_ssl.h
+++ b/modules/ssl/ssl_util_ssl.h
@@ -85,6 +85,7 @@ int SSL_X509_STORE_lookup(X509_STORE *, int, X509_NAME *, X509_OBJECT *)
char *SSL_make_ciphersuite(apr_pool_t *, SSL *);
BOOL SSL_X509_isSGC(X509 *);
BOOL SSL_X509_getBC(X509 *, int *, int *);
+char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne);
BOOL SSL_X509_getCN(apr_pool_t *, X509 *, char **);
BOOL SSL_X509_INFO_load_file(apr_pool_t *, STACK_OF(X509_INFO) *, const char *);
BOOL SSL_X509_INFO_load_path(apr_pool_t *, STACK_OF(X509_INFO) *, const char *);