Commit 8a1c04de authored by Kaspar Brand's avatar Kaspar Brand
Browse files

Merge r1650047 from trunk:

Add support for extracting subjectAltName entries of type
rfc822Name and dNSName into SSL_{CLIENT,SERVER}_SAN_{Email,DNS}_n
variables.

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

* modules/ssl/ssl_engine_kernel.c: in ssl_hook_Fixup, add extraction
  of subjectAltName entries for the "StdEnvVars" case

* modules/ssl/ssl_engine_vars.c: add support for retrieving the
  SSL_{CLIENT,SERVER}_SAN_{Email,DNS}_n variables, either with
  individual on-demand lookup (ssl_var_lookup_ssl_cert_san),
  or with full-list extraction to the environment ("StdEnvVars")

* modules/ssl/ssl_private.h: add modssl_var_extract_san_entries prototype

* modules/ssl/ssl_util_ssl.c: implement SSL_X509_getSAN and
  SSL_ASN1_STRING_to_utf8 helper functions, with factoring out common
  code from SSL_X509_getIDs and SSL_X509_NAME_ENTRY_to_string where
  suitable. Limit SSL_X509_getSAN to the two most common subjectAltName
  entry types appearing in user or server certificates (i.e., rfc822Name
  and dNSName), for the time being.

* modules/ssl/ssl_util_ssl.h: add SSL_ASN1_STRING_to_utf8
  and SSL_X509_getSAN prototypes


Proposed by: kbrand
Reviewed by: ylavic, druggeri


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1676087 13f79535-47bb-0310-9956-ffa450edef68
parent ded38ffa
Loading
Loading
Loading
Loading
+4 −0
Changes for CHANGES: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -12,6 +12,10 @@ Changes with Apache 2.4.13
     calls r:wsupgrade() can cause a child process crash. 
     [Edward Lu <Chaosed0 gmail.com>]

  *) mod_ssl: Add support for extracting subjectAltName entries of type
     rfc822Name and dNSName into SSL_{CLIENT,SERVER}_SAN_{Email,DNS}_n
     environment variables. Also addresses PR 57207. [Kaspar Brand]

  *) mpm_event: Allow for timer events duplicates. [Jim Jagielski, Yann Ylavic]

  *) mod_proxy, mod_ssl, mod_cache_socache, mod_socache_*: Support machine
+0 −6
Changes for STATUS: 0 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -105,12 +105,6 @@ RELEASE SHOWSTOPPERS:
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
  [ start all new proposals below, under PATCHES PROPOSED. ]

   * mod_ssl: Add support for extracting subjectAltName entries of type
     rfc822Name and dNSName into SSL_{CLIENT,SERVER}_SAN_{Email,DNS}_n
     variables. (also covers PR57207)
     trunk patch: https://svn.apache.org/r1650047
     2.4.x patch: trunk patch works (modulo CHANGES)
     +1: kbrand, ylavic, druggeri


PATCHES PROPOSED TO BACKPORT FROM TRUNK:
+4 −0
Changes for docs/manual/mod/mod_ssl.xml: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@ compatibility variables.</p>
<tr><td><code>SSL_CLIENT_M_SERIAL</code></td>           <td>string</td>    <td>The serial of the client certificate</td></tr>
<tr><td><code>SSL_CLIENT_S_DN</code></td>               <td>string</td>    <td>Subject DN in client's certificate</td></tr>
<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_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>
@@ -89,6 +91,8 @@ compatibility variables.</p>
<tr><td><code>SSL_SERVER_M_VERSION</code></td>          <td>string</td>    <td>The version of the server certificate</td></tr>
<tr><td><code>SSL_SERVER_M_SERIAL</code></td>           <td>string</td>    <td>The serial of the server certificate</td></tr>
<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_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>
+1 −0
Changes for modules/ssl/ssl_engine_kernel.c: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -1187,6 +1187,7 @@ int ssl_hook_Fixup(request_rec *r)
    /* standard SSL environment variables */
    if (dc->nOptions & SSL_OPT_STDENVVARS) {
        modssl_var_extract_dns(env, sslconn->ssl, r->pool);
        modssl_var_extract_san_entries(env, sslconn->ssl, r->pool);

        for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
            var = (char *)ssl_hook_Fixup_vars[i];
+74 −0
Changes for modules/ssl/ssl_engine_vars.c: 74 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
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_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);
static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs);
@@ -498,6 +499,10 @@ static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs,
        result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
        resdup = FALSE;
    }
    else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) {
        result = ssl_var_lookup_ssl_cert_san(p, xs, var+4);
        resdup = FALSE;
    }
    else if (strcEQ(var, "A_SIG")) {
        nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm));
        result = apr_pstrdup(p,
@@ -586,6 +591,34 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *
    return result;
}

static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
{
    int type, numlen;
    apr_array_header_t *entries;

    if (strcEQn(var, "Email_", 6)) {
        type = GEN_EMAIL;
        var += 6;
    }
    else if (strcEQn(var, "DNS_", 4)) {
        type = GEN_DNS;
        var += 4;
    }
    else
        return NULL;

    /* sanity check: number must be between 1 and 4 digits */
    numlen = strspn(var, "0123456789");
    if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var)))
        return NULL;

    if (SSL_X509_getSAN(p, xs, type, atoi(var), &entries))
       /* return the first entry from this 1-element array */
       return APR_ARRAY_IDX(entries, 0, char *);
    else
       return NULL;
}

static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm)
{
    char *result;
@@ -910,6 +943,47 @@ void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p)
    }
}

static void extract_san_array(apr_table_t *t, const char *pfx,
                              apr_array_header_t *entries, apr_pool_t *p)
{
    int i;

    for (i = 0; i < entries->nelts; i++) {
        const char *key = apr_psprintf(p, "%s_%d", pfx, i);
        apr_table_setn(t, key, APR_ARRAY_IDX(entries, i, const char *));
    }
}

void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p)
{
    X509 *xs;
    apr_array_header_t *entries;

    /* subjectAltName entries of the server certificate */
    xs = SSL_get_certificate(ssl);
    if (xs) {
        if (SSL_X509_getSAN(p, xs, GEN_EMAIL, -1, &entries)) {
            extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p);
        }
        if (SSL_X509_getSAN(p, xs, GEN_DNS, -1, &entries)) {
            extract_san_array(t, "SSL_SERVER_SAN_DNS", 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 (SSL_X509_getSAN(p, xs, GEN_EMAIL, -1, &entries)) {
            extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p);
        }
        if (SSL_X509_getSAN(p, xs, GEN_DNS, -1, &entries)) {
            extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p);
        }
        X509_free(xs);
    }
}

/* For an extension type which OpenSSL does not recognize, attempt to
 * parse the extension type as a primitive string.  This will fail for
 * any structured extension type per the docs.  Returns non-zero on
Loading