From ea5c40d2273a1379bf42ac8d702ff97ca50c734c Mon Sep 17 00:00:00 2001
From: Joe Orton
Date: Fri, 9 Mar 2018 07:55:27 +0000
Subject: [PATCH] Merge r1811976 from trunk:
Add optional _RAW suffix to SSL_*_DN_xx attribute names, allowing
users to convert an attribute value without conversion to UTF-8. (A
public CA has issued certs with attributes tagged as the wrong ASN.1
string types.)
* modules/ssl/ssl_util_ssl.c (asn1_string_convert): Rename from
asn1_string_to_utf8; add raw argument. Reimplement _to_utf8 as
macro.
(modssl_X509_NAME_ENTRY_to_string): Add raw argument.
* modules/ssl/ssl_engine_vars.c (ssl_var_lookup_ssl_cert_dn): Use raw
string conversion if _RAW suffix is present in DN component.
Submitted by: jorton
Reviewed by: jorton, jim, ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1826300 13f79535-47bb-0310-9956-ffa450edef68
---
CHANGES | 3 +++
docs/manual/mod/mod_ssl.xml | 8 +++++++-
modules/ssl/ssl_engine_vars.c | 22 +++++++++++++++-------
modules/ssl/ssl_util_ssl.c | 22 ++++++++++++++--------
modules/ssl/ssl_util_ssl.h | 3 ++-
5 files changed, 41 insertions(+), 17 deletions(-)
diff --git a/CHANGES b/CHANGES
index 88f7db9e3b..f056fa3a9d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.4.32
+ *) mod_ssl: Support SSL DN raw variable extraction without conversion
+ to UTF-8, using _RAW suffix on variable names. [Joe Orton]
+
*) ab: Fix send length calculation for the non-blocking connect case
introduced in 2.4.30. [Joe Orton]
diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml
index 86287a4df9..a2a41042b7 100644
--- a/docs/manual/mod/mod_ssl.xml
+++ b/docs/manual/mod/mod_ssl.xml
@@ -109,7 +109,7 @@ compatibility variables.
x509 specifies a component of an X.509 DN; one of
-C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email
. In Apache 2.1 and
+C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email
. In httpd 2.2.0 and
later, x509 may also include a numeric _n
suffix. If the DN in question contains multiple attributes of the
same name, this suffix is used as a zero-based index to select a
@@ -125,6 +125,12 @@ the SSLOptions directive, the
first (or only) attribute of any DN is added only under a non-suffixed
name; i.e. no _0
suffixed entries are added.
+In httpd 2.4.32 and later, an optional _RAW suffix may be
+added to x509 in a DN component, to suppress conversion of
+the attribute value to UTF-8. This must be placed after the index
+suffix (if any). For example, SSL_SERVER_S_DN_OU_RAW
or
+SSL_SERVER_S_DN_OU_0_RAW
could be used.
+
The format of the *_DN variables has changed in Apache HTTPD
2.3.11. See the LegacyDNStringFormat
option for
SSLOptions for details.
diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c
index 8ce40efac9..a28d4dd751 100644
--- a/modules/ssl/ssl_engine_vars.c
+++ b/modules/ssl/ssl_engine_vars.c
@@ -41,7 +41,7 @@
static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, 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_dn(apr_pool_t *p, X509_NAME *xsname, const char *var);
static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var);
static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm);
static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm);
@@ -588,15 +588,23 @@ static const struct {
{ NULL, 0, 0 }
};
-static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var)
+static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname,
+ const char *var)
{
- char *result, *ptr;
+ const char *ptr;
+ char *result;
X509_NAME_ENTRY *xsne;
- int i, j, n, idx = 0;
+ int i, j, n, idx = 0, raw = 0;
apr_size_t varlen;
+ ptr = ap_strrchr_c(var, '_');
+ if (ptr && ptr > var && strcmp(ptr + 1, "RAW") == 0) {
+ var = apr_pstrmemdup(p, var, ptr - var);
+ raw = 1;
+ }
+
/* if an _N suffix is used, find the Nth attribute of given name */
- ptr = strchr(var, '_');
+ ptr = ap_strchr_c(var, '_');
if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) {
idx = atoi(ptr + 1);
varlen = ptr - var;
@@ -615,7 +623,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) {
- result = modssl_X509_NAME_ENTRY_to_string(p, xsne);
+ result = modssl_X509_NAME_ENTRY_to_string(p, xsne, raw);
break;
}
}
@@ -947,7 +955,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);
}
- value = modssl_X509_NAME_ENTRY_to_string(p, xsne);
+ value = modssl_X509_NAME_ENTRY_to_string(p, xsne, 0);
apr_table_setn(t, key, value);
}
}
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c
index e22dd7d694..b7f0eca173 100644
--- a/modules/ssl/ssl_util_ssl.c
+++ b/modules/ssl/ssl_util_ssl.c
@@ -217,18 +217,21 @@ BOOL modssl_X509_getBC(X509 *cert, int *ca, int *pathlen)
return TRUE;
}
-/* convert an ASN.1 string to a UTF-8 string (escaping control characters) */
-static char *asn1_string_to_utf8(apr_pool_t *p, ASN1_STRING *asn1str)
+/* Convert ASN.1 string to a pool-allocated char * string, escaping
+ * control characters. If raw is zero, convert to UTF-8, otherwise
+ * unchanged from the character set. */
+static char *asn1_string_convert(apr_pool_t *p, ASN1_STRING *asn1str, int raw)
{
char *result = NULL;
BIO *bio;
- int len;
+ int len, flags = ASN1_STRFLGS_ESC_CTRL;
if ((bio = BIO_new(BIO_s_mem())) == NULL)
return NULL;
- ASN1_STRING_print_ex(bio, asn1str, ASN1_STRFLGS_ESC_CTRL|
- ASN1_STRFLGS_UTF8_CONVERT);
+ if (!raw) flags |= ASN1_STRFLGS_UTF8_CONVERT;
+
+ ASN1_STRING_print_ex(bio, asn1str, flags);
len = BIO_pending(bio);
if (len > 0) {
result = apr_palloc(p, len+1);
@@ -239,10 +242,13 @@ static char *asn1_string_to_utf8(apr_pool_t *p, ASN1_STRING *asn1str)
return result;
}
+#define asn1_string_to_utf8(p, a) asn1_string_convert(p, a, 0)
+
/* convert a NAME_ENTRY to UTF8 string */
-char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne)
+char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne,
+ int raw)
{
- char *result = asn1_string_to_utf8(p, X509_NAME_ENTRY_get_data(xsne));
+ char *result = asn1_string_convert(p, X509_NAME_ENTRY_get_data(xsne), raw);
ap_xlate_proto_from_ascii(result, len);
return result;
}
@@ -395,7 +401,7 @@ static BOOL getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids)
subj = X509_get_subject_name(x509);
while ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) != -1) {
APR_ARRAY_PUSH(*ids, const char *) =
- modssl_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i));
+ modssl_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i), 0);
}
return apr_is_empty_array(*ids) ? FALSE : TRUE;
diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h
index 5c6c8b6853..c67dacff3d 100644
--- a/modules/ssl/ssl_util_ssl.h
+++ b/modules/ssl/ssl_util_ssl.h
@@ -68,7 +68,8 @@ EVP_PKEY *modssl_read_privatekey(const char *, EVP_PKEY **, pem_password_cb *,
EVP_PKEY *modssl_read_encrypted_pkey(const char *, EVP_PKEY **, const char *, apr_size_t);
int modssl_smart_shutdown(SSL *ssl);
BOOL modssl_X509_getBC(X509 *, int *, int *);
-char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne);
+char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne,
+ int raw);
char *modssl_X509_NAME_to_string(apr_pool_t *, X509_NAME *, int);
BOOL modssl_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr_array_header_t **);
BOOL modssl_X509_match_name(apr_pool_t *, X509 *, const char *, BOOL, server_rec *);
--
2.40.0