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>
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 />
** _________________________________________________________________
*/
-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);
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)
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")) {
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;
}
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);
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;
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;
}
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;
}
}
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;
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);
}
}
#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) *)
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;
}
}