Blame modules/ssl/ssl_engine_vars.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/*                      _             _
Packit 90a5c9
 *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
Packit 90a5c9
 * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
Packit 90a5c9
 * | | | | | | (_) | (_| |   \__ \__ \ |
Packit 90a5c9
 * |_| |_| |_|\___/ \__,_|___|___/___/_|
Packit 90a5c9
 *                      |_____|
Packit 90a5c9
 *  ssl_engine_vars.c
Packit 90a5c9
 *  Variable Lookup Facility
Packit 90a5c9
 */
Packit 90a5c9
                             /* ``Those of you who think they
Packit 90a5c9
                                  know everything are very annoying
Packit 90a5c9
                                  to those of us who do.''
Packit 90a5c9
                                                  -- Unknown       */
Packit 90a5c9
#include "ssl_private.h"
Packit 90a5c9
#include "mod_ssl.h"
Packit 90a5c9
#include "ap_expr.h"
Packit 90a5c9
Packit 90a5c9
#include "apr_time.h"
Packit 90a5c9
Packit 90a5c9
/*  _________________________________________________________________
Packit 90a5c9
**
Packit 90a5c9
**  Variable Lookup
Packit 90a5c9
**  _________________________________________________________________
Packit 90a5c9
*/
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, request_rec *r, char *var);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, SSLConnRec *sslconn);
Packit 90a5c9
static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char *var);
Packit 90a5c9
static void  ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize);
Packit 90a5c9
static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var);
Packit 90a5c9
static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl);
Packit 90a5c9
Packit 90a5c9
static SSLConnRec *ssl_get_effective_config(conn_rec *c)
Packit 90a5c9
{
Packit 90a5c9
    SSLConnRec *sslconn = myConnConfig(c);
Packit 90a5c9
    if (!(sslconn && sslconn->ssl) && c->master) {
Packit 90a5c9
        /* use master connection if no SSL defined here */
Packit 90a5c9
        sslconn = myConnConfig(c->master);
Packit 90a5c9
    }
Packit 90a5c9
    return sslconn;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int ssl_is_https(conn_rec *c)
Packit 90a5c9
{
Packit 90a5c9
    SSLConnRec *sslconn = ssl_get_effective_config(c);
Packit 90a5c9
    return sslconn && sslconn->ssl;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION;
Packit 90a5c9
static char var_library_interface[] = MODSSL_LIBRARY_TEXT;
Packit 90a5c9
static char *var_library = NULL;
Packit 90a5c9
Packit 90a5c9
static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                                 const void *dummy,
Packit 90a5c9
                                                 const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return ssl_ext_list(ctx->p, ctx->c, 1, arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
Packit 90a5c9
{
Packit 90a5c9
    char *var = (char *)data;
Packit 90a5c9
    SSLConnRec *sslconn = ssl_get_effective_config(ctx->c);
Packit 90a5c9
Packit 90a5c9
    return sslconn ? ssl_var_lookup_ssl(ctx->p, sslconn, ctx->r, var) : NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                                const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    char *var = (char *)arg;
Packit 90a5c9
Packit 90a5c9
    return var ? ssl_var_lookup(ctx->p, ctx->s, ctx->c, ctx->r, var) : NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
Packit 90a5c9
{
Packit 90a5c9
    switch (parms->type) {
Packit 90a5c9
    case AP_EXPR_FUNC_VAR:
Packit 90a5c9
        /* for now, we just handle everything that starts with SSL_, but
Packit 90a5c9
         * register our hook as APR_HOOK_LAST
Packit 90a5c9
         * XXX: This can be optimized
Packit 90a5c9
         */
Packit 90a5c9
        if (strcEQn(parms->name, "SSL_", 4)) {
Packit 90a5c9
            *parms->func = expr_var_fn;
Packit 90a5c9
            *parms->data = parms->name + 4;
Packit 90a5c9
            return OK;
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_STRING:
Packit 90a5c9
        /* Function SSL() is implemented by us.
Packit 90a5c9
         */
Packit 90a5c9
        if (strcEQ(parms->name, "SSL")) {
Packit 90a5c9
            *parms->func = expr_func_fn;
Packit 90a5c9
            *parms->data = NULL;
Packit 90a5c9
            return OK;
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_LIST:
Packit 90a5c9
        if (strcEQ(parms->name, "PeerExtList")) {
Packit 90a5c9
            *parms->func = expr_peer_ext_list_fn;
Packit 90a5c9
            *parms->data = "PeerExtList";
Packit 90a5c9
            return OK;
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
    return DECLINED;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
void ssl_var_register(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    char *cp, *cp2;
Packit 90a5c9
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ssl_is_https);
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ssl_ext_list);
Packit 90a5c9
Packit 90a5c9
    /* Perform once-per-process library version determination: */
Packit 90a5c9
    var_library = apr_pstrdup(p, MODSSL_LIBRARY_DYNTEXT);
Packit 90a5c9
Packit 90a5c9
    if ((cp = strchr(var_library, ' ')) != NULL) {
Packit 90a5c9
        *cp = '/';
Packit 90a5c9
        if ((cp2 = strchr(cp, ' ')) != NULL)
Packit 90a5c9
            *cp2 = NUL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if ((cp = strchr(var_library_interface, ' ')) != NULL) {
Packit 90a5c9
        *cp = '/';
Packit 90a5c9
        if ((cp2 = strchr(cp, ' ')) != NULL)
Packit 90a5c9
            *cp2 = NUL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ap_hook_expr_lookup(ssl_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* This function must remain safe to use for a non-SSL connection. */
Packit 90a5c9
char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
Packit 90a5c9
{
Packit 90a5c9
    SSLModConfigRec *mc = myModConfig(s);
Packit 90a5c9
    const char *result;
Packit 90a5c9
    BOOL resdup;
Packit 90a5c9
    apr_time_exp_t tm;
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
    resdup = TRUE;
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * When no pool is given try to find one
Packit 90a5c9
     */
Packit 90a5c9
    if (p == NULL) {
Packit 90a5c9
        if (r != NULL)
Packit 90a5c9
            p = r->pool;
Packit 90a5c9
        else if (c != NULL)
Packit 90a5c9
            p = c->pool;
Packit 90a5c9
        else
Packit 90a5c9
            p = mc->pPool;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * Request dependent stuff
Packit 90a5c9
     */
Packit 90a5c9
    if (r != NULL) {
Packit 90a5c9
        switch (var[0]) {
Packit 90a5c9
        case 'H':
Packit 90a5c9
        case 'h':
Packit 90a5c9
            if (strcEQ(var, "HTTP_USER_AGENT"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "User-Agent");
Packit 90a5c9
            else if (strcEQ(var, "HTTP_REFERER"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "Referer");
Packit 90a5c9
            else if (strcEQ(var, "HTTP_COOKIE"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "Cookie");
Packit 90a5c9
            else if (strcEQ(var, "HTTP_FORWARDED"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "Forwarded");
Packit 90a5c9
            else if (strcEQ(var, "HTTP_HOST"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "Host");
Packit 90a5c9
            else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "Proxy-Connection");
Packit 90a5c9
            else if (strcEQ(var, "HTTP_ACCEPT"))
Packit 90a5c9
                result = apr_table_get(r->headers_in, "Accept");
Packit 90a5c9
            else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
Packit 90a5c9
                /* all other headers from which we are still not know about */
Packit 90a5c9
                result = apr_table_get(r->headers_in, var+5);
Packit 90a5c9
            break;
Packit 90a5c9
Packit 90a5c9
        case 'R':
Packit 90a5c9
        case 'r':
Packit 90a5c9
            if (strcEQ(var, "REQUEST_METHOD"))
Packit 90a5c9
                result = r->method;
Packit 90a5c9
            else if (strcEQ(var, "REQUEST_SCHEME"))
Packit 90a5c9
                result = ap_http_scheme(r);
Packit 90a5c9
            else if (strcEQ(var, "REQUEST_URI"))
Packit 90a5c9
                result = r->uri;
Packit 90a5c9
            else if (strcEQ(var, "REQUEST_FILENAME"))
Packit 90a5c9
                result = r->filename;
Packit 90a5c9
            else if (strcEQ(var, "REMOTE_ADDR"))
Packit 90a5c9
                result = r->useragent_ip;
Packit 90a5c9
            else if (strcEQ(var, "REMOTE_HOST"))
Packit 90a5c9
                result = ap_get_useragent_host(r, REMOTE_NAME, NULL);
Packit 90a5c9
            else if (strcEQ(var, "REMOTE_IDENT"))
Packit 90a5c9
                result = ap_get_remote_logname(r);
Packit 90a5c9
            else if (strcEQ(var, "REMOTE_USER"))
Packit 90a5c9
                result = r->user;
Packit 90a5c9
            break;
Packit 90a5c9
Packit 90a5c9
        case 'S':
Packit 90a5c9
        case 's':
Packit 90a5c9
            if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
Packit 90a5c9
Packit 90a5c9
            if (strcEQ(var, "SERVER_ADMIN"))
Packit 90a5c9
                result = r->server->server_admin;
Packit 90a5c9
            else if (strcEQ(var, "SERVER_NAME"))
Packit 90a5c9
                result = ap_get_server_name_for_url(r);
Packit 90a5c9
            else if (strcEQ(var, "SERVER_PORT"))
Packit 90a5c9
                result = apr_psprintf(p, "%u", ap_get_server_port(r));
Packit 90a5c9
            else if (strcEQ(var, "SERVER_PROTOCOL"))
Packit 90a5c9
                result = r->protocol;
Packit 90a5c9
            else if (strcEQ(var, "SCRIPT_FILENAME"))
Packit 90a5c9
                result = r->filename;
Packit 90a5c9
            break;
Packit 90a5c9
Packit 90a5c9
        default:
Packit 90a5c9
            if (strcEQ(var, "PATH_INFO"))
Packit 90a5c9
                result = r->path_info;
Packit 90a5c9
            else if (strcEQ(var, "QUERY_STRING"))
Packit 90a5c9
                result = r->args;
Packit 90a5c9
            else if (strcEQ(var, "IS_SUBREQ"))
Packit 90a5c9
                result = (r->main != NULL ? "true" : "false");
Packit 90a5c9
            else if (strcEQ(var, "DOCUMENT_ROOT"))
Packit 90a5c9
                result = ap_document_root(r);
Packit 90a5c9
            else if (strcEQ(var, "AUTH_TYPE"))
Packit 90a5c9
                result = r->ap_auth_type;
Packit 90a5c9
            else if (strcEQ(var, "THE_REQUEST"))
Packit 90a5c9
                result = r->the_request;
Packit 90a5c9
            else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
Packit 90a5c9
                result = apr_table_get(r->notes, var+4);
Packit 90a5c9
                if (result == NULL)
Packit 90a5c9
                    result = apr_table_get(r->subprocess_env, var+4);
Packit 90a5c9
            }
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * Connection stuff
Packit 90a5c9
     */
Packit 90a5c9
    if (result == NULL && c != NULL) {
Packit 90a5c9
        SSLConnRec *sslconn = ssl_get_effective_config(c);
Packit 90a5c9
        if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)
Packit 90a5c9
            && sslconn && sslconn->ssl)
Packit 90a5c9
            result = ssl_var_lookup_ssl(p, sslconn, r, var+4);
Packit 90a5c9
        else if (strcEQ(var, "HTTPS")) {
Packit 90a5c9
            if (sslconn && sslconn->ssl)
Packit 90a5c9
                result = "on";
Packit 90a5c9
            else
Packit 90a5c9
                result = "off";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * Totally independent stuff
Packit 90a5c9
     */
Packit 90a5c9
    if (result == NULL) {
Packit 90a5c9
        if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
Packit 90a5c9
            result = ssl_var_lookup_ssl_version(p, var+12);
Packit 90a5c9
        else if (strcEQ(var, "SERVER_SOFTWARE"))
Packit 90a5c9
            result = ap_get_server_banner();
Packit 90a5c9
        else if (strcEQ(var, "API_VERSION")) {
Packit 90a5c9
            result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR);
Packit 90a5c9
            resdup = FALSE;
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME_YEAR")) {
Packit 90a5c9
            apr_time_exp_lt(&tm, apr_time_now());
Packit 90a5c9
            result = apr_psprintf(p, "%02d%02d",
Packit 90a5c9
                                 (tm.tm_year / 100) + 19, tm.tm_year % 100);
Packit 90a5c9
            resdup = FALSE;
Packit 90a5c9
        }
Packit 90a5c9
#define MKTIMESTR(format, tmfield) \
Packit 90a5c9
            apr_time_exp_lt(&tm, apr_time_now()); \
Packit 90a5c9
            result = apr_psprintf(p, format, tm.tmfield); \
Packit 90a5c9
            resdup = FALSE;
Packit 90a5c9
        else if (strcEQ(var, "TIME_MON")) {
Packit 90a5c9
            MKTIMESTR("%02d", tm_mon+1)
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME_DAY")) {
Packit 90a5c9
            MKTIMESTR("%02d", tm_mday)
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME_HOUR")) {
Packit 90a5c9
            MKTIMESTR("%02d", tm_hour)
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME_MIN")) {
Packit 90a5c9
            MKTIMESTR("%02d", tm_min)
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME_SEC")) {
Packit 90a5c9
            MKTIMESTR("%02d", tm_sec)
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME_WDAY")) {
Packit 90a5c9
            MKTIMESTR("%d", tm_wday)
Packit 90a5c9
        }
Packit 90a5c9
        else if (strcEQ(var, "TIME")) {
Packit 90a5c9
            apr_time_exp_lt(&tm, apr_time_now());
Packit 90a5c9
            result = apr_psprintf(p,
Packit 90a5c9
                        "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19,
Packit 90a5c9
                        (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday,
Packit 90a5c9
                        tm.tm_hour, tm.tm_min, tm.tm_sec);
Packit 90a5c9
            resdup = FALSE;
Packit 90a5c9
        }
Packit 90a5c9
        /* all other env-variables from the parent Apache process */
Packit 90a5c9
        else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
Packit 90a5c9
            result = getenv(var+4);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (result != NULL && resdup)
Packit 90a5c9
        result = apr_pstrdup(p, result);
Packit 90a5c9
    if (result == NULL)
Packit 90a5c9
        result = "";
Packit 90a5c9
    return (char *)result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, 
Packit 90a5c9
                                request_rec *r, char *var)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    X509 *xs;
Packit 90a5c9
    STACK_OF(X509) *sk;
Packit 90a5c9
    SSL *ssl;
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
Packit 90a5c9
    ssl = sslconn->ssl;
Packit 90a5c9
    if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_version(p, var+8);
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
Packit 90a5c9
        result = (char *)SSL_get_version(ssl);
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
Packit 90a5c9
        char buf[MODSSL_SESSION_ID_STRING_LEN];
Packit 90a5c9
        SSL_SESSION *pSession = SSL_get_session(ssl);
Packit 90a5c9
        if (pSession) {
Packit 90a5c9
            IDCONST unsigned char *id;
Packit 90a5c9
            unsigned int idlen;
Packit 90a5c9
Packit 90a5c9
#ifdef OPENSSL_NO_SSL_INTERN
Packit 90a5c9
            id = (unsigned char *)SSL_SESSION_get_id(pSession, &idlen);
Packit 90a5c9
#else
Packit 90a5c9
            id = pSession->session_id;
Packit 90a5c9
            idlen = pSession->session_id_length;
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
            result = apr_pstrdup(p, modssl_SSL_SESSION_id2sz(id, idlen,
Packit 90a5c9
                                                             buf, sizeof(buf)));
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if(ssl != NULL && strcEQ(var, "SESSION_RESUMED")) {
Packit 90a5c9
        if (SSL_session_reused(ssl) == 1)
Packit 90a5c9
            result = "Resumed";
Packit 90a5c9
        else
Packit 90a5c9
            result = "Initial";
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cipher(p, sslconn, var+6);
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) {
Packit 90a5c9
        sk = SSL_get_peer_cert_chain(ssl);
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18);
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_RFC4523_CEA")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_rfc4523_cea(p, ssl);
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_verify(p, sslconn);
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
Packit 90a5c9
        if ((xs = SSL_get_peer_certificate(ssl)) != NULL) {
Packit 90a5c9
            result = ssl_var_lookup_ssl_cert(p, r, xs, var+7);
Packit 90a5c9
            X509_free(xs);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
Packit 90a5c9
        if ((xs = SSL_get_certificate(ssl)) != NULL) {
Packit 90a5c9
            result = ssl_var_lookup_ssl_cert(p, r, xs, var+7);
Packit 90a5c9
            /* SSL_get_certificate is different from SSL_get_peer_certificate.
Packit 90a5c9
             * No need to X509_free(xs).
Packit 90a5c9
             */
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_compress_meth(ssl);
Packit 90a5c9
    }
Packit 90a5c9
#ifdef HAVE_TLSEXT
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "TLS_SNI")) {
Packit 90a5c9
        result = apr_pstrdup(p, SSL_get_servername(ssl,
Packit 90a5c9
                                                   TLSEXT_NAMETYPE_host_name));
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) {
Packit 90a5c9
        int flag = 0;
Packit 90a5c9
#ifdef SSL_get_secure_renegotiation_support
Packit 90a5c9
        flag = SSL_get_secure_renegotiation_support(ssl);
Packit 90a5c9
#endif
Packit 90a5c9
        result = apr_pstrdup(p, flag ? "true" : "false");
Packit 90a5c9
    }
Packit 90a5c9
#ifdef HAVE_SRP
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "SRP_USER")) {
Packit 90a5c9
        if ((result = SSL_get_srp_username(ssl)) != NULL) {
Packit 90a5c9
            result = apr_pstrdup(p, result);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) {
Packit 90a5c9
        if ((result = SSL_get_srp_userinfo(ssl)) != NULL) {
Packit 90a5c9
            result = apr_pstrdup(p, result);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_dn_oneline(apr_pool_t *p, request_rec *r,
Packit 90a5c9
                                                X509_NAME *xsname)
Packit 90a5c9
{
Packit 90a5c9
    char *result = NULL;
Packit 90a5c9
    SSLDirConfigRec *dc;
Packit 90a5c9
    int legacy_format = 0;
Packit 90a5c9
    if (r) {
Packit 90a5c9
        dc = myDirConfig(r);
Packit 90a5c9
        legacy_format = dc->nOptions & SSL_OPT_LEGACYDNFORMAT;
Packit 90a5c9
    }
Packit 90a5c9
    if (legacy_format) {
Packit 90a5c9
        char *cp = X509_NAME_oneline(xsname, NULL, 0);
Packit 90a5c9
        result = apr_pstrdup(p, cp);
Packit 90a5c9
        OPENSSL_free(cp);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        BIO* bio;
Packit 90a5c9
        int n;
Packit 90a5c9
        unsigned long flags = XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB;
Packit 90a5c9
        if ((bio = BIO_new(BIO_s_mem())) == NULL)
Packit 90a5c9
            return NULL;
Packit 90a5c9
        X509_NAME_print_ex(bio, xsname, 0, flags);
Packit 90a5c9
        n = BIO_pending(bio);
Packit 90a5c9
        if (n > 0) {
Packit 90a5c9
            result = apr_palloc(p, n+1);
Packit 90a5c9
            n = BIO_read(bio, result, n);
Packit 90a5c9
            result[n] = NUL;
Packit 90a5c9
        }
Packit 90a5c9
        BIO_free(bio);
Packit 90a5c9
    }
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs,
Packit 90a5c9
                                     char *var)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    BOOL resdup;
Packit 90a5c9
    X509_NAME *xsname;
Packit 90a5c9
    int nid;
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
    resdup = TRUE;
Packit 90a5c9
Packit 90a5c9
    if (strcEQ(var, "M_VERSION")) {
Packit 90a5c9
        result = apr_psprintf(p, "%lu", X509_get_version(xs)+1);
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "M_SERIAL")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_serial(p, xs);
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "V_START")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs));
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "V_END")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs));
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "V_REMAIN")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs));
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (*var && strcEQ(var+1, "_DN")) {
Packit 90a5c9
        if (*var == 'S')
Packit 90a5c9
            xsname = X509_get_subject_name(xs);
Packit 90a5c9
        else if (*var == 'I')
Packit 90a5c9
            xsname = X509_get_issuer_name(xs);
Packit 90a5c9
        else
Packit 90a5c9
            return NULL;
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_dn_oneline(p, r, xsname);
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strlen(var) > 5 && strcEQn(var+1, "_DN_", 4)) {
Packit 90a5c9
        if (*var == 'S')
Packit 90a5c9
            xsname = X509_get_subject_name(xs);
Packit 90a5c9
        else if (*var == 'I')
Packit 90a5c9
            xsname = X509_get_issuer_name(xs);
Packit 90a5c9
        else
Packit 90a5c9
            return NULL;
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_san(p, xs, var+4);
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "A_SIG")) {
Packit 90a5c9
#if MODSSL_USE_OPENSSL_PRE_1_1_API
Packit 90a5c9
        nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm));
Packit 90a5c9
#else
Packit 90a5c9
        const ASN1_OBJECT *paobj;
Packit 90a5c9
        X509_ALGOR_get0(&paobj, NULL, NULL, X509_get0_tbs_sigalg(xs));
Packit 90a5c9
        nid = OBJ_obj2nid(paobj);
Packit 90a5c9
#endif
Packit 90a5c9
        result = apr_pstrdup(p,
Packit 90a5c9
                             (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "A_KEY")) {
Packit 90a5c9
#if OPENSSL_VERSION_NUMBER < 0x10100000L
Packit 90a5c9
        nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->key->algor->algorithm));
Packit 90a5c9
#else
Packit 90a5c9
        ASN1_OBJECT *paobj;
Packit 90a5c9
        X509_PUBKEY_get0_param(&paobj, NULL, 0, NULL, X509_get_X509_PUBKEY(xs));
Packit 90a5c9
        nid = OBJ_obj2nid(paobj);
Packit 90a5c9
#endif
Packit 90a5c9
        result = apr_pstrdup(p,
Packit 90a5c9
                             (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "CERT")) {
Packit 90a5c9
        result = ssl_var_lookup_ssl_cert_PEM(p, xs);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (resdup)
Packit 90a5c9
        result = apr_pstrdup(p, result);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* In this table, .extract is non-zero if RDNs using the NID should be
Packit 90a5c9
 * extracted to for the SSL_{CLIENT,SERVER}_{I,S}_DN_* environment
Packit 90a5c9
 * variables. */
Packit 90a5c9
static const struct {
Packit 90a5c9
    char *name;
Packit 90a5c9
    int   nid;
Packit 90a5c9
    int   extract;
Packit 90a5c9
} ssl_var_lookup_ssl_cert_dn_rec[] = {
Packit 90a5c9
    { "C",     NID_countryName,            1 },
Packit 90a5c9
    { "ST",    NID_stateOrProvinceName,    1 }, /* officially    (RFC2156) */
Packit 90a5c9
    { "SP",    NID_stateOrProvinceName,    0 }, /* compatibility (SSLeay)  */
Packit 90a5c9
    { "L",     NID_localityName,           1 },
Packit 90a5c9
    { "O",     NID_organizationName,       1 },
Packit 90a5c9
    { "OU",    NID_organizationalUnitName, 1 },
Packit 90a5c9
    { "CN",    NID_commonName,             1 },
Packit 90a5c9
    { "T",     NID_title,                  1 },
Packit 90a5c9
    { "I",     NID_initials,               1 },
Packit 90a5c9
    { "G",     NID_givenName,              1 },
Packit 90a5c9
    { "S",     NID_surname,                1 },
Packit 90a5c9
    { "D",     NID_description,            1 },
Packit 90a5c9
#ifdef NID_userId
Packit 90a5c9
    { "UID",   NID_userId,                 1 },
Packit 90a5c9
#endif
Packit 90a5c9
    { "Email", NID_pkcs9_emailAddress,     1 },
Packit 90a5c9
    { NULL,    0,                          0 }
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname,
Packit 90a5c9
                                        const char *var)
Packit 90a5c9
{
Packit 90a5c9
    const char *ptr;
Packit 90a5c9
    char *result;
Packit 90a5c9
    X509_NAME_ENTRY *xsne;
Packit 90a5c9
    int i, j, n, idx = 0, raw = 0;
Packit 90a5c9
    apr_size_t varlen;
Packit 90a5c9
Packit 90a5c9
    ptr = ap_strrchr_c(var, '_');
Packit 90a5c9
    if (ptr && ptr > var && strcmp(ptr + 1, "RAW") == 0) {
Packit 90a5c9
        var = apr_pstrmemdup(p, var, ptr - var);
Packit 90a5c9
        raw = 1;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    /* if an _N suffix is used, find the Nth attribute of given name */
Packit 90a5c9
    ptr = ap_strchr_c(var, '_');
Packit 90a5c9
    if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) {
Packit 90a5c9
        idx = atoi(ptr + 1);
Packit 90a5c9
        varlen = ptr - var;
Packit 90a5c9
    } else {
Packit 90a5c9
        varlen = strlen(var);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
Packit 90a5c9
    for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
Packit 90a5c9
        if (strEQn(var, ssl_var_lookup_ssl_cert_dn_rec[i].name, varlen)
Packit 90a5c9
            && strlen(ssl_var_lookup_ssl_cert_dn_rec[i].name) == varlen) {
Packit 90a5c9
            for (j = 0; j < X509_NAME_entry_count(xsname); j++) {
Packit 90a5c9
                xsne = X509_NAME_get_entry(xsname, j);
Packit 90a5c9
Packit 90a5c9
                n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
Packit 90a5c9
Packit 90a5c9
                if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
Packit 90a5c9
                    result = modssl_X509_NAME_ENTRY_to_string(p, xsne, raw);
Packit 90a5c9
                    break;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
Packit 90a5c9
{
Packit 90a5c9
    int type, numlen;
Packit 90a5c9
    const char *onf = NULL;
Packit 90a5c9
    apr_array_header_t *entries;
Packit 90a5c9
Packit 90a5c9
    if (strcEQn(var, "Email_", 6)) {
Packit 90a5c9
        type = GEN_EMAIL;
Packit 90a5c9
        var += 6;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQn(var, "DNS_", 4)) {
Packit 90a5c9
        type = GEN_DNS;
Packit 90a5c9
        var += 4;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQn(var, "OTHER_", 6)) {
Packit 90a5c9
        type = GEN_OTHERNAME;
Packit 90a5c9
        var += 6;
Packit 90a5c9
        if (strEQn(var, "msUPN_", 6)) {
Packit 90a5c9
            var += 6;
Packit 90a5c9
            onf = "msUPN";
Packit 90a5c9
        }
Packit 90a5c9
        else if (strEQn(var, "dnsSRV_", 7)) {
Packit 90a5c9
            var += 7;
Packit 90a5c9
            onf = "id-on-dnsSRV";
Packit 90a5c9
        }
Packit 90a5c9
        else
Packit 90a5c9
           return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    /* sanity check: number must be between 1 and 4 digits */
Packit 90a5c9
    numlen = strspn(var, "0123456789");
Packit 90a5c9
    if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var)))
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    if (modssl_X509_getSAN(p, xs, type, onf, atoi(var), &entries))
Packit 90a5c9
        /* return the first entry from this 1-element array */
Packit 90a5c9
        return APR_ARRAY_IDX(entries, 0, char *);
Packit 90a5c9
    else
Packit 90a5c9
        return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    BIO* bio;
Packit 90a5c9
    int n;
Packit 90a5c9
Packit 90a5c9
    if ((bio = BIO_new(BIO_s_mem())) == NULL)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    ASN1_TIME_print(bio, tm);
Packit 90a5c9
    n = BIO_pending(bio);
Packit 90a5c9
    result = apr_pcalloc(p, n+1);
Packit 90a5c9
    n = BIO_read(bio, result, n);
Packit 90a5c9
    result[n] = NUL;
Packit 90a5c9
    BIO_free(bio);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0')
Packit 90a5c9
Packit 90a5c9
/* Return a string giving the number of days remaining until 'tm', or
Packit 90a5c9
 * "0" if this can't be determined. */
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm)
Packit 90a5c9
{
Packit 90a5c9
    apr_time_t then, now = apr_time_now();
Packit 90a5c9
    apr_time_exp_t exp = {0};
Packit 90a5c9
    long diff;
Packit 90a5c9
    unsigned char *dp;
Packit 90a5c9
Packit 90a5c9
    /* Fail if the time isn't a valid ASN.1 TIME; RFC3280 mandates
Packit 90a5c9
     * that the seconds digits are present even though ASN.1
Packit 90a5c9
     * doesn't. */
Packit 90a5c9
    if ((tm->type == V_ASN1_UTCTIME && tm->length < 11) ||
Packit 90a5c9
        (tm->type == V_ASN1_GENERALIZEDTIME && tm->length < 13) ||
Packit 90a5c9
        !ASN1_TIME_check(tm)) {
Packit 90a5c9
        return apr_pstrdup(p, "0");
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (tm->type == V_ASN1_UTCTIME) {
Packit 90a5c9
        exp.tm_year = DIGIT2NUM(tm->data);
Packit 90a5c9
        if (exp.tm_year <= 50) exp.tm_year += 100;
Packit 90a5c9
        dp = tm->data + 2;
Packit 90a5c9
    } else {
Packit 90a5c9
        exp.tm_year = DIGIT2NUM(tm->data) * 100 + DIGIT2NUM(tm->data + 2) - 1900;
Packit 90a5c9
        dp = tm->data + 4;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    exp.tm_mon = DIGIT2NUM(dp) - 1;
Packit 90a5c9
    exp.tm_mday = DIGIT2NUM(dp + 2) + 1;
Packit 90a5c9
    exp.tm_hour = DIGIT2NUM(dp + 4);
Packit 90a5c9
    exp.tm_min = DIGIT2NUM(dp + 6);
Packit 90a5c9
    exp.tm_sec = DIGIT2NUM(dp + 8);
Packit 90a5c9
Packit 90a5c9
    if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) {
Packit 90a5c9
        return apr_pstrdup(p, "0");
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    diff = (long)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24));
Packit 90a5c9
Packit 90a5c9
    return diff > 0 ? apr_ltoa(p, diff) : apr_pstrdup(p, "0");
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    BIO *bio;
Packit 90a5c9
    int n;
Packit 90a5c9
Packit 90a5c9
    if ((bio = BIO_new(BIO_s_mem())) == NULL)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
Packit 90a5c9
    n = BIO_pending(bio);
Packit 90a5c9
    result = apr_pcalloc(p, n+1);
Packit 90a5c9
    n = BIO_read(bio, result, n);
Packit 90a5c9
    result[n] = NUL;
Packit 90a5c9
    BIO_free(bio);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    X509 *xs;
Packit 90a5c9
    int n;
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
Packit 90a5c9
    if (strspn(var, "0123456789") == strlen(var)) {
Packit 90a5c9
        n = atoi(var);
Packit 90a5c9
        if (n < sk_X509_num(sk)) {
Packit 90a5c9
            xs = sk_X509_value(sk, n);
Packit 90a5c9
            result = ssl_var_lookup_ssl_cert_PEM(p, xs);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    X509 *xs;
Packit 90a5c9
Packit 90a5c9
    ASN1_INTEGER *serialNumber;
Packit 90a5c9
Packit 90a5c9
    if (!(xs = SSL_get_peer_certificate(ssl))) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
Packit 90a5c9
    serialNumber = X509_get_serialNumber(xs);
Packit 90a5c9
    if (serialNumber) {
Packit 90a5c9
        X509_NAME *issuer = X509_get_issuer_name(xs);
Packit 90a5c9
        if (issuer) {
Packit 90a5c9
            BIGNUM *bn = ASN1_INTEGER_to_BN(serialNumber, NULL);
Packit 90a5c9
            char *decimal = BN_bn2dec(bn);
Packit 90a5c9
            result = apr_pstrcat(p, "{ serialNumber ", decimal,
Packit 90a5c9
                    ", issuer rdnSequence:\"",
Packit 90a5c9
                    modssl_X509_NAME_to_string(p, issuer, 0), "\" }", NULL);
Packit 90a5c9
            OPENSSL_free(decimal);
Packit 90a5c9
            BN_free(bn);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    X509_free(xs);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    BIO *bio;
Packit 90a5c9
    int n;
Packit 90a5c9
Packit 90a5c9
    if ((bio = BIO_new(BIO_s_mem())) == NULL)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    PEM_write_bio_X509(bio, xs);
Packit 90a5c9
    n = BIO_pending(bio);
Packit 90a5c9
    result = apr_pcalloc(p, n+1);
Packit 90a5c9
    n = BIO_read(bio, result, n);
Packit 90a5c9
    result[n] = NUL;
Packit 90a5c9
    BIO_free(bio);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, SSLConnRec *sslconn)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    long vrc;
Packit 90a5c9
    const char *verr;
Packit 90a5c9
    const char *vinfo;
Packit 90a5c9
    SSL *ssl;
Packit 90a5c9
    X509 *xs;
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
    ssl   = sslconn->ssl;
Packit 90a5c9
    verr  = sslconn->verify_error;
Packit 90a5c9
    vinfo = sslconn->verify_info;
Packit 90a5c9
    vrc   = SSL_get_verify_result(ssl);
Packit 90a5c9
    xs    = SSL_get_peer_certificate(ssl);
Packit 90a5c9
Packit 90a5c9
    if (vrc == X509_V_OK && verr == NULL && xs == NULL)
Packit 90a5c9
        /* no client verification done at all */
Packit 90a5c9
        result = "NONE";
Packit 90a5c9
    else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
Packit 90a5c9
        /* client verification done successful */
Packit 90a5c9
        result = "SUCCESS";
Packit 90a5c9
    else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
Packit 90a5c9
        /* client verification done in generous way */
Packit 90a5c9
        result = "GENEROUS";
Packit 90a5c9
    else
Packit 90a5c9
        /* client verification failed */
Packit 90a5c9
        result = apr_psprintf(p, "FAILED:%s",
Packit 90a5c9
                              verr ? verr : X509_verify_cert_error_string(vrc));
Packit 90a5c9
Packit 90a5c9
    if (xs)
Packit 90a5c9
        X509_free(xs);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char *var)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    BOOL resdup;
Packit 90a5c9
    int usekeysize, algkeysize;
Packit 90a5c9
    SSL *ssl;
Packit 90a5c9
Packit 90a5c9
    result = NULL;
Packit 90a5c9
    resdup = TRUE;
Packit 90a5c9
Packit 90a5c9
    ssl = sslconn->ssl;
Packit 90a5c9
    ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
Packit 90a5c9
Packit 90a5c9
    if (ssl && strEQ(var, "")) {
Packit 90a5c9
        MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
Packit 90a5c9
        result = (cipher != NULL ? (char *)SSL_CIPHER_get_name(cipher) : NULL);
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "_EXPORT"))
Packit 90a5c9
        result = (usekeysize < 56 ? "true" : "false");
Packit 90a5c9
    else if (strcEQ(var, "_USEKEYSIZE")) {
Packit 90a5c9
        result = apr_itoa(p, usekeysize);
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcEQ(var, "_ALGKEYSIZE")) {
Packit 90a5c9
        result = apr_itoa(p, algkeysize);
Packit 90a5c9
        resdup = FALSE;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (result != NULL && resdup)
Packit 90a5c9
        result = apr_pstrdup(p, result);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
Packit 90a5c9
{
Packit 90a5c9
    MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher;
Packit 90a5c9
Packit 90a5c9
    *usekeysize = 0;
Packit 90a5c9
    *algkeysize = 0;
Packit 90a5c9
    if (ssl != NULL)
Packit 90a5c9
        if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
Packit 90a5c9
            *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize);
Packit 90a5c9
    return;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
Packit 90a5c9
{
Packit 90a5c9
    if (strEQ(var, "INTERFACE")) {
Packit 90a5c9
        return apr_pstrdup(p, var_interface);
Packit 90a5c9
    }
Packit 90a5c9
    else if (strEQ(var, "LIBRARY_INTERFACE")) {
Packit 90a5c9
        return apr_pstrdup(p, var_library_interface);
Packit 90a5c9
    }
Packit 90a5c9
    else if (strEQ(var, "LIBRARY")) {
Packit 90a5c9
        return apr_pstrdup(p, var_library);
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Add each RDN in 'xn' to the table 't' where the NID is present in
Packit 90a5c9
 * 'nids', using key prefix 'pfx'.  */
Packit 90a5c9
static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx,
Packit 90a5c9
                       X509_NAME *xn, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    X509_NAME_ENTRY *xsne;
Packit 90a5c9
    apr_hash_t *count;
Packit 90a5c9
    int i, nid;
Packit 90a5c9
Packit 90a5c9
    /* Hash of (int) NID -> (int *) counter to count each time an RDN
Packit 90a5c9
     * with the given NID has been seen. */
Packit 90a5c9
    count = apr_hash_make(p);
Packit 90a5c9
Packit 90a5c9
    /* For each RDN... */
Packit 90a5c9
    for (i = 0; i < X509_NAME_entry_count(xn); i++) {
Packit 90a5c9
         const char *tag;
Packit 90a5c9
         xsne = X509_NAME_get_entry(xn, i);
Packit 90a5c9
Packit 90a5c9
         /* Retrieve the nid, and check whether this is one of the nids
Packit 90a5c9
          * which are to be extracted. */
Packit 90a5c9
         nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
Packit 90a5c9
Packit 90a5c9
         tag = apr_hash_get(nids, &nid, sizeof nid);
Packit 90a5c9
         if (tag) {
Packit 90a5c9
             const char *key;
Packit 90a5c9
             int *dup;
Packit 90a5c9
             char *value;
Packit 90a5c9
Packit 90a5c9
             /* Check whether a variable with this nid was already
Packit 90a5c9
              * been used; if so, use the foo_N=bar syntax. */
Packit 90a5c9
             dup = apr_hash_get(count, &nid, sizeof nid);
Packit 90a5c9
             if (dup) {
Packit 90a5c9
                 key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup));
Packit 90a5c9
             }
Packit 90a5c9
             else {
Packit 90a5c9
                 /* Otherwise, use the plain foo=bar syntax. */
Packit 90a5c9
                 dup = apr_pcalloc(p, sizeof *dup);
Packit 90a5c9
                 apr_hash_set(count, &nid, sizeof nid, dup);
Packit 90a5c9
                 key = apr_pstrcat(p, pfx, tag, NULL);
Packit 90a5c9
             }
Packit 90a5c9
             value = modssl_X509_NAME_ENTRY_to_string(p, xsne, 0);
Packit 90a5c9
             apr_table_setn(t, key, value);
Packit 90a5c9
         }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    apr_hash_t *nids;
Packit 90a5c9
    unsigned n;
Packit 90a5c9
    X509 *xs;
Packit 90a5c9
Packit 90a5c9
    /* Build up a hash table of (int *)NID->(char *)short-name for all
Packit 90a5c9
     * the tags which are to be extracted: */
Packit 90a5c9
    nids = apr_hash_make(p);
Packit 90a5c9
    for (n = 0; ssl_var_lookup_ssl_cert_dn_rec[n].name; n++) {
Packit 90a5c9
        if (ssl_var_lookup_ssl_cert_dn_rec[n].extract) {
Packit 90a5c9
            apr_hash_set(nids, &ssl_var_lookup_ssl_cert_dn_rec[n].nid,
Packit 90a5c9
                         sizeof(ssl_var_lookup_ssl_cert_dn_rec[0].nid),
Packit 90a5c9
                         ssl_var_lookup_ssl_cert_dn_rec[n].name);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Extract the server cert DNS -- note that the refcount does NOT
Packit 90a5c9
     * increase: */
Packit 90a5c9
    xs = SSL_get_certificate(ssl);
Packit 90a5c9
    if (xs) {
Packit 90a5c9
        extract_dn(t, nids, "SSL_SERVER_S_DN_", X509_get_subject_name(xs), p);
Packit 90a5c9
        extract_dn(t, nids, "SSL_SERVER_I_DN_", X509_get_issuer_name(xs), p);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Extract the client cert DNs -- note that the refcount DOES
Packit 90a5c9
     * increase: */
Packit 90a5c9
    xs = SSL_get_peer_certificate(ssl);
Packit 90a5c9
    if (xs) {
Packit 90a5c9
        extract_dn(t, nids, "SSL_CLIENT_S_DN_", X509_get_subject_name(xs), p);
Packit 90a5c9
        extract_dn(t, nids, "SSL_CLIENT_I_DN_", X509_get_issuer_name(xs), p);
Packit 90a5c9
        X509_free(xs);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void extract_san_array(apr_table_t *t, const char *pfx,
Packit 90a5c9
                              apr_array_header_t *entries, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < entries->nelts; i++) {
Packit 90a5c9
        const char *key = apr_psprintf(p, "%s_%d", pfx, i);
Packit 90a5c9
        apr_table_setn(t, key, APR_ARRAY_IDX(entries, i, const char *));
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    X509 *xs;
Packit 90a5c9
    apr_array_header_t *entries;
Packit 90a5c9
Packit 90a5c9
    /* subjectAltName entries of the server certificate */
Packit 90a5c9
    xs = SSL_get_certificate(ssl);
Packit 90a5c9
    if (xs) {
Packit 90a5c9
        if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
Packit 90a5c9
            extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p);
Packit 90a5c9
        }
Packit 90a5c9
        if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
Packit 90a5c9
            extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p);
Packit 90a5c9
        }
Packit 90a5c9
        if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1,
Packit 90a5c9
                               &entries)) {
Packit 90a5c9
            extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p);
Packit 90a5c9
        }
Packit 90a5c9
        /* no need to free xs (refcount does not increase) */
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* subjectAltName entries of the client certificate */
Packit 90a5c9
    xs = SSL_get_peer_certificate(ssl);
Packit 90a5c9
    if (xs) {
Packit 90a5c9
        if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
Packit 90a5c9
            extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p);
Packit 90a5c9
        }
Packit 90a5c9
        if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
Packit 90a5c9
            extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p);
Packit 90a5c9
        }
Packit 90a5c9
        if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) {
Packit 90a5c9
            extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p);
Packit 90a5c9
        }
Packit 90a5c9
        X509_free(xs);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* For an extension type which OpenSSL does not recognize, attempt to
Packit 90a5c9
 * parse the extension type as a primitive string.  This will fail for
Packit 90a5c9
 * any structured extension type per the docs.  Returns non-zero on
Packit 90a5c9
 * success and writes the string to the given bio. */
Packit 90a5c9
static int dump_extn_value(BIO *bio, ASN1_OCTET_STRING *str)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *pp = str->data;
Packit 90a5c9
    ASN1_STRING *ret = ASN1_STRING_new();
Packit 90a5c9
    int rv = 0;
Packit 90a5c9
Packit 90a5c9
    /* This allows UTF8String, IA5String, VisibleString, or BMPString;
Packit 90a5c9
     * conversion to UTF-8 is forced. */
Packit 90a5c9
    if (d2i_DISPLAYTEXT(&ret, &pp, str->length)) {
Packit 90a5c9
        ASN1_STRING_print_ex(bio, ret, ASN1_STRFLGS_UTF8_CONVERT);
Packit 90a5c9
        rv = 1;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ASN1_STRING_free(ret);
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer,
Packit 90a5c9
                                 const char *extension)
Packit 90a5c9
{
Packit 90a5c9
    SSLConnRec *sslconn = ssl_get_effective_config(c);
Packit 90a5c9
    SSL *ssl = NULL;
Packit 90a5c9
    apr_array_header_t *array = NULL;
Packit 90a5c9
    X509 *xs = NULL;
Packit 90a5c9
    ASN1_OBJECT *oid = NULL;
Packit 90a5c9
    int count = 0, j;
Packit 90a5c9
Packit 90a5c9
    if (!sslconn || !sslconn->ssl || !extension) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    ssl = sslconn->ssl;
Packit 90a5c9
Packit 90a5c9
    /* We accept the "extension" string to be converted as
Packit 90a5c9
     * a long name (nsComment), short name (DN) or
Packit 90a5c9
     * numeric OID (1.2.3.4).
Packit 90a5c9
     */
Packit 90a5c9
    oid = OBJ_txt2obj(extension, 0);
Packit 90a5c9
    if (!oid) {
Packit 90a5c9
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01970)
Packit 90a5c9
                      "could not parse OID '%s'", extension);
Packit 90a5c9
        ERR_clear_error();
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    xs = peer ? SSL_get_peer_certificate(ssl) : SSL_get_certificate(ssl);
Packit 90a5c9
    if (xs == NULL) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    count = X509_get_ext_count(xs);
Packit 90a5c9
    /* Create an array large enough to accommodate every extension. This is
Packit 90a5c9
     * likely overkill, but safe.
Packit 90a5c9
     */
Packit 90a5c9
    array = apr_array_make(p, count, sizeof(char *));
Packit 90a5c9
    for (j = 0; j < count; j++) {
Packit 90a5c9
        X509_EXTENSION *ext = X509_get_ext(xs, j);
Packit 90a5c9
Packit 90a5c9
        if (OBJ_cmp(X509_EXTENSION_get_object(ext), oid) == 0) {
Packit 90a5c9
            BIO *bio = BIO_new(BIO_s_mem());
Packit 90a5c9
Packit 90a5c9
            /* We want to obtain a string representation of the extensions
Packit 90a5c9
             * value and add it to the array we're building.
Packit 90a5c9
             * X509V3_EXT_print() doesn't know about all the possible
Packit 90a5c9
             * data types, but the value is stored as an ASN1_OCTET_STRING
Packit 90a5c9
             * allowing us a fallback in case of X509V3_EXT_print
Packit 90a5c9
             * not knowing how to handle the data.
Packit 90a5c9
             */
Packit 90a5c9
            if (X509V3_EXT_print(bio, ext, 0, 0) == 1 ||
Packit 90a5c9
                dump_extn_value(bio, X509_EXTENSION_get_data(ext)) == 1) {
Packit 90a5c9
                BUF_MEM *buf;
Packit 90a5c9
                char **ptr = apr_array_push(array);
Packit 90a5c9
                BIO_get_mem_ptr(bio, &buf;;
Packit 90a5c9
                *ptr = apr_pstrmemdup(p, buf->data, buf->length);
Packit 90a5c9
            } else {
Packit 90a5c9
                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01971)
Packit 90a5c9
                              "Found an extension '%s', but failed to "
Packit 90a5c9
                              "create a string from it", extension);
Packit 90a5c9
            }
Packit 90a5c9
            BIO_vfree(bio);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (array->nelts == 0)
Packit 90a5c9
        array = NULL;
Packit 90a5c9
Packit 90a5c9
    if (peer) {
Packit 90a5c9
        /* only SSL_get_peer_certificate raises the refcount */
Packit 90a5c9
        X509_free(xs);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ASN1_OBJECT_free(oid);
Packit 90a5c9
    ERR_clear_error();
Packit 90a5c9
    return array;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl)
Packit 90a5c9
{
Packit 90a5c9
    char *result = "NULL";
Packit 90a5c9
#ifndef OPENSSL_NO_COMP
Packit 90a5c9
    SSL_SESSION *pSession = SSL_get_session(ssl);
Packit 90a5c9
Packit 90a5c9
    if (pSession) {
Packit 90a5c9
#ifdef OPENSSL_NO_SSL_INTERN
Packit 90a5c9
        switch (SSL_SESSION_get_compress_id(pSession)) {
Packit 90a5c9
#else
Packit 90a5c9
        switch (pSession->compress_meth) {
Packit 90a5c9
#endif
Packit 90a5c9
        case 0:
Packit 90a5c9
            /* default "NULL" already set */
Packit 90a5c9
            break;
Packit 90a5c9
Packit 90a5c9
            /* Defined by RFC 3749, deflate is coded by "1" */
Packit 90a5c9
        case 1:
Packit 90a5c9
            result = "DEFLATE";
Packit 90a5c9
            break;
Packit 90a5c9
Packit 90a5c9
            /* IANA assigned compression number for LZS */
Packit 90a5c9
        case 0x40:
Packit 90a5c9
            result = "LZS";
Packit 90a5c9
            break;
Packit 90a5c9
Packit 90a5c9
        default:
Packit 90a5c9
            result = "UNKNOWN";
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*  _________________________________________________________________
Packit 90a5c9
**
Packit 90a5c9
**  SSL Extension to mod_log_config
Packit 90a5c9
**  _________________________________________________________________
Packit 90a5c9
*/
Packit 90a5c9
Packit 90a5c9
#include "../../modules/loggers/mod_log_config.h"
Packit 90a5c9
Packit 90a5c9
static const char *ssl_var_log_handler_c(request_rec *r, char *a);
Packit 90a5c9
static const char *ssl_var_log_handler_x(request_rec *r, char *a);
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * register us for the mod_log_config function registering phase
Packit 90a5c9
 * to establish %{...}c and to be able to expand %{...}x variables.
Packit 90a5c9
 */
Packit 90a5c9
void ssl_var_log_config_register(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
Packit 90a5c9
Packit 90a5c9
    log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
Packit 90a5c9
Packit 90a5c9
    if (log_pfn_register) {
Packit 90a5c9
        log_pfn_register(p, "c", ssl_var_log_handler_c, 0);
Packit 90a5c9
        log_pfn_register(p, "x", ssl_var_log_handler_x, 0);
Packit 90a5c9
    }
Packit 90a5c9
    return;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * implement the %{..}c log function
Packit 90a5c9
 * (we are the only function)
Packit 90a5c9
 */
Packit 90a5c9
static const char *ssl_var_log_handler_c(request_rec *r, char *a)
Packit 90a5c9
{
Packit 90a5c9
    SSLConnRec *sslconn = ssl_get_effective_config(r->connection);
Packit 90a5c9
    char *result;
Packit 90a5c9
Packit 90a5c9
    if (sslconn == NULL || sslconn->ssl == NULL)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    result = NULL;
Packit 90a5c9
    if (strEQ(a, "version"))
Packit 90a5c9
        result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL");
Packit 90a5c9
    else if (strEQ(a, "cipher"))
Packit 90a5c9
        result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
Packit 90a5c9
    else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert"))
Packit 90a5c9
        result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
Packit 90a5c9
    else if (strEQ(a, "issuerdn") || strEQ(a, "cacert"))
Packit 90a5c9
        result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
Packit 90a5c9
    else if (strEQ(a, "errcode"))
Packit 90a5c9
        result = "-";
Packit 90a5c9
    else if (strEQ(a, "errstr"))
Packit 90a5c9
        result = (char *)sslconn->verify_error;
Packit 90a5c9
    if (result != NULL && result[0] == NUL)
Packit 90a5c9
        result = NULL;
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * extend the implementation of the %{..}x log function
Packit 90a5c9
 * (there can be more functions)
Packit 90a5c9
 */
Packit 90a5c9
static const char *ssl_var_log_handler_x(request_rec *r, char *a)
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
Packit 90a5c9
    result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
Packit 90a5c9
    if (result != NULL && result[0] == NUL)
Packit 90a5c9
        result = NULL;
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9