]> granicus.if.org Git - apache/commitdiff
merge r1693792 from trunk
authorKaspar Brand <kbrand@apache.org>
Wed, 30 Sep 2015 11:38:34 +0000 (11:38 +0000)
committerKaspar Brand <kbrand@apache.org>
Wed, 30 Sep 2015 11:38:34 +0000 (11:38 +0000)
Add support for extracting the msUPN and dnsSRV forms
of subjectAltName entries of type "otherName" into
SSL_{CLIENT,SERVER}_SAN_OTHER_{msUPN,dnsSRV}_n environment
variables. Addresses PR 58020.

* docs/manual/mod/mod_ssl.xml: add SSL_*_SAN_OTHER_*_n entries to the
  environment variables table

* modules/ssl/ssl_engine_vars.c: add support for retrieving the
  SSL_{CLIENT,SERVER}_SAN_OTHER_{msUPN,dnsSRV}_n variables

* modules/ssl/ssl_util_ssl.c: add parse_otherName_value, which
  currently recognizes the "msUPN" (1.3.6.1.4.1.311.20.2.3) and
  "id-on-dnsSRV" (1.3.6.1.5.5.7.8.7) otherName forms, and
  adapt modssl_X509_getSAN to take an optional otherName form
  argument for the GEN_OTHERNAME case

* modules/ssl/ssl_util_ssl.h: adapt modssl_X509_getSAN prototype

* modules/ssl/mod_ssl.c: register the id-on-dnsSRV otherName form
  OID (1.3.6.1.5.5.7.8.7) in OpenSSL's objects table

Proposed by: kbrand
Reviewed by: ylavic, jorton

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1706006 13f79535-47bb-0310-9956-ffa450edef68

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

diff --git a/CHANGES b/CHANGES
index 95adda0f6d4616c7390ceff5ca0744940a268c4d..04c7362ba0a25306f0fe32da713c60ccc897289d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,13 @@
                                                          -*- coding: utf-8 -*-
 
 Changes with Apache 2.4.17
+
+  *) mod_ssl: Add support for extracting the msUPN and dnsSRV forms
+     of subjectAltName entries of type "otherName" into
+     SSL_{CLIENT,SERVER}_SAN_OTHER_{msUPN,dnsSRV}_n environment
+     variables. Addresses PR 58020. [Jan Pazdziora <jpazdziora redhat.com>,
+     Kaspar Brand]
+
   *) mod_h2: added donated http/2 implementation to build system. Similar
      configuration options to mod_ssl. [Stefan Eissing]
 
index 076f33653a5afb52df95cecef1f93cd2166791ca..d6ea405a19c95bd3a94df220cc2324766e025e31 100644 (file)
@@ -77,6 +77,7 @@ compatibility variables.</p>
 <tr><td><code>SSL_CLIENT_S_DN_</code><em>x509</em></td> <td>string</td>    <td>Component of client's Subject DN</td></tr>
 <tr><td><code>SSL_CLIENT_SAN_Email_</code><em>n</em></td> <td>string</td>  <td>Client certificate's subjectAltName extension entries of type rfc822Name</td></tr>
 <tr><td><code>SSL_CLIENT_SAN_DNS_</code><em>n</em></td> <td>string</td>    <td>Client certificate's subjectAltName extension entries of type dNSName</td></tr>
+<tr><td><code>SSL_CLIENT_SAN_OTHER_msUPN_</code><em>n</em></td> <td>string</td>    <td>Client certificate's subjectAltName extension entries of type otherName, Microsoft User Principal Name form (OID 1.3.6.1.4.1.311.20.2.3)</td></tr>
 <tr><td><code>SSL_CLIENT_I_DN</code></td>               <td>string</td>    <td>Issuer DN of client's certificate</td></tr>
 <tr><td><code>SSL_CLIENT_I_DN_</code><em>x509</em></td> <td>string</td>    <td>Component of client's Issuer DN</td></tr>
 <tr><td><code>SSL_CLIENT_V_START</code></td>            <td>string</td>    <td>Validity of client's certificate (start time)</td></tr>
@@ -93,6 +94,7 @@ compatibility variables.</p>
 <tr><td><code>SSL_SERVER_S_DN</code></td>               <td>string</td>    <td>Subject DN in server's certificate</td></tr>
 <tr><td><code>SSL_SERVER_SAN_Email_</code><em>n</em></td> <td>string</td>  <td>Server certificate's subjectAltName extension entries of type rfc822Name</td></tr>
 <tr><td><code>SSL_SERVER_SAN_DNS_</code><em>n</em></td> <td>string</td>    <td>Server certificate's subjectAltName extension entries of type dNSName</td></tr>
+<tr><td><code>SSL_SERVER_SAN_OTHER_dnsSRV_</code><em>n</em></td> <td>string</td>    <td>Server certificate's subjectAltName extension entries of type otherName, SRVName form (OID 1.3.6.1.5.5.7.8.7, RFC 4985)</td></tr>
 <tr><td><code>SSL_SERVER_S_DN_</code><em>x509</em></td> <td>string</td>    <td>Component of server's Subject DN</td></tr>
 <tr><td><code>SSL_SERVER_I_DN</code></td>               <td>string</td>    <td>Issuer DN of server's certificate</td></tr>
 <tr><td><code>SSL_SERVER_I_DN_</code><em>x509</em></td> <td>string</td>    <td>Component of server's Issuer DN</td></tr>
index 7d9b8a550cb98d47e7b8076a7727eed8e170235d..567daf0a09aa7b05ac8a96a2a68a634cdc66570e 100644 (file)
@@ -340,6 +340,11 @@ static int ssl_hook_pre_config(apr_pool_t *pconf,
     OpenSSL_add_all_algorithms();
     OPENSSL_load_builtin_modules();
 
+    if (OBJ_txt2nid("id-on-dnsSRV") == NID_undef) {
+        (void)OBJ_create("1.3.6.1.5.5.7.8.7", "id-on-dnsSRV",
+                         "SRVName otherName form");
+    }
+
     /*
      * Let us cleanup the ssl library when the module is unloaded
      */
index 4fce7fc85d7e2afd29a47e069490c6ffbc56d532..0530eea4a3eb6a0f88f9fff933a04a9c14d19de2 100644 (file)
@@ -594,6 +594,7 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *
 static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
 {
     int type, numlen;
+    const char *onf = NULL;
     apr_array_header_t *entries;
 
     if (strcEQn(var, "Email_", 6)) {
@@ -604,6 +605,20 @@ static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
         type = GEN_DNS;
         var += 4;
     }
+    else if (strcEQn(var, "OTHER_", 6)) {
+        type = GEN_OTHERNAME;
+        var += 6;
+        if (strEQn(var, "msUPN_", 6)) {
+            var += 6;
+            onf = "msUPN";
+        }
+        else if (strEQn(var, "dnsSRV_", 7)) {
+            var += 7;
+            onf = "id-on-dnsSRV";
+        }
+        else
+           return NULL;
+    }
     else
         return NULL;
 
@@ -612,11 +627,11 @@ static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
     if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var)))
         return NULL;
 
-    if (modssl_X509_getSAN(p, xs, type, atoi(var), &entries))
-       /* return the first entry from this 1-element array */
-       return APR_ARRAY_IDX(entries, 0, char *);
+    if (modssl_X509_getSAN(p, xs, type, onf, atoi(var), &entries))
+        /* return the first entry from this 1-element array */
+        return APR_ARRAY_IDX(entries, 0, char *);
     else
-       return NULL;
+        return NULL;
 }
 
 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm)
@@ -962,24 +977,31 @@ void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p)
     /* subjectAltName entries of the server certificate */
     xs = SSL_get_certificate(ssl);
     if (xs) {
-        if (modssl_X509_getSAN(p, xs, GEN_EMAIL, -1, &entries)) {
+        if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
             extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p);
         }
-        if (modssl_X509_getSAN(p, xs, GEN_DNS, -1, &entries)) {
+        if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
             extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p);
         }
+        if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1,
+                               &entries)) {
+            extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p);
+        }
         /* no need to free xs (refcount does not increase) */
     }
 
     /* subjectAltName entries of the client certificate */
     xs = SSL_get_peer_certificate(ssl);
     if (xs) {
-        if (modssl_X509_getSAN(p, xs, GEN_EMAIL, -1, &entries)) {
+        if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
             extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p);
         }
-        if (modssl_X509_getSAN(p, xs, GEN_DNS, -1, &entries)) {
+        if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
             extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p);
         }
+        if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) {
+            extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p);
+        }
         X509_free(xs);
     }
 }
index 1acda0d772df61cbceceffc6a2a7ea7302e521a8..a7607c73498ca3cfa4611ff0632fc0a920eaf20f 100644 (file)
@@ -252,19 +252,48 @@ char *modssl_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen)
     return result;
 }
 
+static void parse_otherName_value(apr_pool_t *p, ASN1_TYPE *value,
+                                  const char *onf, apr_array_header_t **entries)
+{
+    const char *str;
+    int nid = onf ? OBJ_txt2nid(onf) : NID_undef;
+
+    if (!value || (nid == NID_undef) || !*entries)
+       return;
+
+    /* 
+     * Currently supported otherName forms (values for "onf"):
+     * "msUPN" (1.3.6.1.4.1.311.20.2.3): Microsoft User Principal Name
+     * "id-on-dnsSRV" (1.3.6.1.5.5.7.8.7): SRVName, as specified in RFC 4985
+     */
+    if ((nid == NID_ms_upn) && (value->type == V_ASN1_UTF8STRING) &&
+        (str = asn1_string_to_utf8(p, value->value.utf8string))) {
+        APR_ARRAY_PUSH(*entries, const char *) = str;
+    } else if (strEQ(onf, "id-on-dnsSRV") &&
+               (value->type == V_ASN1_IA5STRING) &&
+               (str = asn1_string_to_utf8(p, value->value.ia5string))) {
+        APR_ARRAY_PUSH(*entries, const char *) = str;
+    }
+}
+
 /* 
  * Return an array of subjectAltName entries of type "type". If idx is -1,
  * return all entries of the given type, otherwise return an array consisting
  * of the n-th occurrence of that type only. Currently supported types:
  * GEN_EMAIL (rfc822Name)
  * GEN_DNS (dNSName)
+ * GEN_OTHERNAME (requires the otherName form ["onf"] argument to be supplied,
+ *                see parse_otherName_value for the currently supported forms)
  */
-BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, int idx,
-                        apr_array_header_t **entries)
+BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, const char *onf,
+                        int idx, apr_array_header_t **entries)
 {
     STACK_OF(GENERAL_NAME) *names;
+    int nid = onf ? OBJ_txt2nid(onf) : NID_undef;
 
-    if (!x509 || (type < GEN_OTHERNAME) || (type > GEN_RID) || (idx < -1) ||
+    if (!x509 || (type < GEN_OTHERNAME) ||
+        ((type == GEN_OTHERNAME) && (nid == NID_undef)) ||
+        (type > GEN_RID) || (idx < -1) ||
         !(*entries = apr_array_make(p, 0, sizeof(char *)))) {
         *entries = NULL;
         return FALSE;
@@ -277,33 +306,43 @@ BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, int idx,
 
         for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
             name = sk_GENERAL_NAME_value(names, i);
-            if (name->type == type) {
-                if ((idx == -1) || (n == idx)) {
-                    switch (type) {
-                    case GEN_EMAIL:
-                    case GEN_DNS:
-                        utf8str = asn1_string_to_utf8(p, name->d.ia5);
-                        if (utf8str) {
-                            APR_ARRAY_PUSH(*entries, const char *) = utf8str;
-                        }
-                        break;
-                    default:
-                        /*
-                         * Not implemented right now:
-                         * GEN_OTHERNAME (otherName)
-                         * GEN_X400 (x400Address)
-                         * GEN_DIRNAME (directoryName)
-                         * GEN_EDIPARTY (ediPartyName)
-                         * GEN_URI (uniformResourceIdentifier)
-                         * GEN_IPADD (iPAddress)
-                         * GEN_RID (registeredID)
-                         */
-                        break;
+
+            if (name->type != type)
+                continue;
+
+            switch (type) {
+            case GEN_EMAIL:
+            case GEN_DNS:
+                if (((idx == -1) || (n == idx)) &&
+                    (utf8str = asn1_string_to_utf8(p, name->d.ia5))) {
+                    APR_ARRAY_PUSH(*entries, const char *) = utf8str;
+                }
+                n++;
+                break;
+            case GEN_OTHERNAME:
+                if (OBJ_obj2nid(name->d.otherName->type_id) == nid) {
+                    if (((idx == -1) || (n == idx))) {
+                        parse_otherName_value(p, name->d.otherName->value,
+                                              onf, entries);
                     }
+                    n++;
                 }
-                if ((idx != -1) && (n++ > idx))
-                   break;
+                break;
+            default:
+                /*
+                 * Not implemented right now:
+                 * GEN_X400 (x400Address)
+                 * GEN_DIRNAME (directoryName)
+                 * GEN_EDIPARTY (ediPartyName)
+                 * GEN_URI (uniformResourceIdentifier)
+                 * GEN_IPADD (iPAddress)
+                 * GEN_RID (registeredID)
+                 */
+                break;
             }
+
+            if ((idx != -1) && (n > idx))
+               break;
         }
 
         sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
@@ -320,7 +359,7 @@ static BOOL getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids)
 
     /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */
     if (!x509 ||
-        (modssl_X509_getSAN(p, x509, GEN_DNS, -1, ids) == FALSE && !*ids)) {
+        (modssl_X509_getSAN(p, x509, GEN_DNS, NULL, -1, ids) == FALSE && !*ids)) {
         *ids = NULL;
         return FALSE;
     }
index c7c4a916a0a25b3506b92360cf62e937f67fe5f8..5f7483195c830279a462d5fadeab061892e8f16e 100644 (file)
@@ -65,7 +65,7 @@ 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_to_string(apr_pool_t *, X509_NAME *, int);
-BOOL        modssl_X509_getSAN(apr_pool_t *, X509 *, int, int, apr_array_header_t **);
+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 *);
 char       *modssl_SSL_SESSION_id2sz(unsigned char *, int, char *, int);