]> granicus.if.org Git - apache/commitdiff
Change the format of the SSL_{CLIENT,SERVER}_{I,S}_DN variables
authorStefan Fritsch <sf@apache.org>
Sat, 1 Jan 2011 23:56:24 +0000 (23:56 +0000)
committerStefan Fritsch <sf@apache.org>
Sat, 1 Jan 2011 23:56:24 +0000 (23:56 +0000)
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

CHANGES
docs/manual/mod/mod_ssl.xml
docs/manual/upgrading.xml
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_vars.c
modules/ssl/ssl_private.h
modules/ssl/ssl_util_ssl.c
modules/ssl/ssl_util_ssl.h

diff --git a/CHANGES b/CHANGES
index c6821771094a1f414462b61cfa21a88c9a3553cd..8d25db4e6d09c111d834bac51000e0acf0bf5c27 100644 (file)
--- 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]
 
index 13f0a969ea79640fc39304109fcec6620db1a3d2..4cbb1ba266392c5fcf11871daa6472a3116c5b7a 100644 (file)
@@ -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 />
index a5f385da7ed10c85b5504470a545c4e3f9a28767..e2ce3f773976520e3386d53349563ebd34d87f00 100644 (file)
       <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>
 
index 4bccfe72d6b97311d6cb65b1a4af31c78d231bfb..029d3d77c5346d4b6d3d5aeeaed05716a2709451 100644 (file)
@@ -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, "'",
index d5cf63ba32a05df30d767c1dd71adc0e3c45430f..a8c0aef41f09dac2ee2450a9c5549504bac3e4dd 100644 (file)
@@ -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);
          }
     }
index ae344a141d150c0522aa0f13bb07959fb948cad2..d8d0cd27b7871326603d714a2252d0772b88d96b 100644 (file)
@@ -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;
 
 /**
index f44c707fa31d60887d416192be691ccd1df8ca92..722ab01f6ca963dba2df8f211854824a49326ce6 100644 (file)
@@ -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;
         }
     }
index 04bcbdc27876a83c0427649f262d86a0f85423fd..cabfb27c918046ca28821824179aa27b55d50807 100644 (file)
@@ -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 *);