Changeset ae29683 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Feb 21, 2014, 12:15:56 AM (6 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, upstream
Children:
4addf74, 62f781c
Parents:
180e49f (diff), 1a99240 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Imported Upstream version 0.6

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r180e49f rae29683  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2007 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2021#include "http_vhost.h"
    2122#include "ap_mpm.h"
    22 
    23 #if APR_HAS_THREADS
    24 # if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11
    25 #include <gcrypt.h>
    26 GCRY_THREAD_OPTION_PTHREAD_IMPL;
    27 # endif
     23#include "mod_status.h"
     24
     25#ifdef ENABLE_MSVA
     26#include <msv/msv.h>
    2827#endif
    2928
     
    3635#endif
    3736
    38 static int mpm_is_threaded;
    39 static gnutls_datum session_ticket_key = { NULL, 0 };
     37static gnutls_datum_t session_ticket_key = {NULL, 0};
    4038
    4139static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    4240/* use side==0 for server and side==1 for client */
    43 static void mgs_add_common_cert_vars(request_rec * r,
    44                                      gnutls_x509_crt_t cert, int side,
    45                                      int export_certificates_enabled);
    46 static void mgs_add_common_pgpcert_vars(request_rec * r,
    47                                         gnutls_openpgp_crt_t cert,
    48                                         int side,
    49                                         int export_certificates_enabled);
    50 
    51 static apr_status_t mgs_cleanup_pre_config(void *data)
    52 {
    53         gnutls_free(session_ticket_key.data);
    54         session_ticket_key.data = NULL;
    55         session_ticket_key.size = 0;
    56         gnutls_global_deinit();
    57         return APR_SUCCESS;
    58 }
    59 
     41static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert);
     42static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert);
     43static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
     44static int mgs_status_hook(request_rec *r, int flags);
     45
     46/* Pool Cleanup Function */
     47apr_status_t mgs_cleanup_pre_config(void *data) {
     48        /* Free all session data */
     49    gnutls_free(session_ticket_key.data);
     50    session_ticket_key.data = NULL;
     51    session_ticket_key.size = 0;
     52        /* Deinitialize GnuTLS Library */
     53    gnutls_global_deinit();
     54    return APR_SUCCESS;
     55}
     56
     57/* Logging Function for Maintainers */
    6058#if MOD_GNUTLS_DEBUG
    61 static void gnutls_debug_log_all(int level, const char *str)
    62 {
    63         apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
    64 }
    65 
     59static void gnutls_debug_log_all(int level, const char *str) {
     60    apr_file_printf(debug_log_fp, "<%d> %s", level, str);
     61}
    6662#define _gnutls_log apr_file_printf
    6763#else
    68 # define _gnutls_log(...)
     64#define _gnutls_log(...)
    6965#endif
    7066
    71 int
    72 mgs_hook_pre_config(apr_pool_t * pconf,
    73                     apr_pool_t * plog, apr_pool_t * ptemp)
    74 {
    75         int ret;
    76 
     67static const char* mgs_readable_cvm(mgs_client_verification_method_e m) {
     68    switch(m) {
     69    case mgs_cvm_unset:
     70        return "unset";
     71    case mgs_cvm_cartel:
     72        return "cartel";
     73    case mgs_cvm_msva:
     74        return "msva";
     75    }
     76    return "unknown";
     77}
     78
     79/* Pre-Configuration HOOK: Runs First */
     80int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp) {
     81
     82/* Maintainer Logging */
    7783#if MOD_GNUTLS_DEBUG
    78         apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
    79                       APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
    80                       pconf);
     84    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pconf);
     85    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     86    gnutls_global_set_log_level(9);
     87    gnutls_global_set_log_function(gnutls_debug_log_all);
     88    _gnutls_log(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
     89#endif
     90
     91    int ret;
     92
     93        /* Check for required GnuTLS Library Version */
     94    if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
     95                ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_check_version() failed. Required: "
     96                                        "gnutls-%s Found: gnutls-%s", LIBGNUTLS_VERSION, gnutls_check_version(NULL));
     97        return DONE;
     98    }
     99
     100        /* Initialize GnuTLS Library */
     101    ret = gnutls_global_init();
     102    if (ret < 0) {
     103                ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_global_init: %s", gnutls_strerror(ret));
     104                return DONE;
     105    }
     106
     107        /* Generate a Session Key */
     108    ret = gnutls_session_ticket_key_generate(&session_ticket_key);
     109    if (ret < 0) {
     110                ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_session_ticket_key_generate: %s", gnutls_strerror(ret));
     111                return DONE;
     112    }
     113
     114    AP_OPTIONAL_HOOK(status_hook, mgs_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
     115
     116        /* Register a pool clean-up function */
     117    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, apr_pool_cleanup_null);
     118
     119    return OK;
     120}
     121
     122static int mgs_select_virtual_server_cb(gnutls_session_t session) {
     123
     124    mgs_handle_t *ctxt = NULL;
     125    mgs_srvconf_rec *tsc = NULL;
     126    int ret = 0;
     127
     128    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     129
     130    ctxt = gnutls_transport_get_ptr(session);
     131
     132    /* find the virtual server */
     133    tsc = mgs_find_sni_server(session);
     134
     135    if (tsc != NULL) {
     136        // Found a TLS vhost based on the SNI from the client; use it instead.
     137        ctxt->sc = tsc;
     138        }
     139
     140    gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
     141
     142    /* Set Anon credentials */
     143    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
     144        /* Set x509 credentials */
     145    gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
     146
     147#ifdef ENABLE_SRP
     148        /* Set SRP credentials */
     149    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
     150        gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
     151    }
     152#endif
     153
     154    /* update the priorities - to avoid negotiating a ciphersuite that is not
     155     * enabled on this virtual server. Note that here we ignore the version
     156     * negotiation.
     157     */
     158
     159    ret = gnutls_priority_set(session, ctxt->sc->priorities);
     160    /* actually it shouldn't fail since we have checked at startup */
     161    return ret;
     162
     163}
     164
     165static int cert_retrieve_fn(gnutls_session_t session,
     166                                                        const gnutls_datum_t * req_ca_rdn, int nreqs,
     167                                                        const gnutls_pk_algorithm_t * pk_algos, int pk_algos_length,
     168                                                        gnutls_retr2_st *ret) {
     169
    81170
    82171        _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    83172
    84         gnutls_global_set_log_level(9);
    85         gnutls_global_set_log_function(gnutls_debug_log_all);
    86         _gnutls_log(debug_log_fp, "gnutls: %s\n",
    87                     gnutls_check_version(NULL));
    88 #endif
    89 
    90 #if APR_HAS_THREADS
    91         ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
    92 #if (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 11) || GNUTLS_VERSION_MAJOR < 2
    93         if (mpm_is_threaded) {
    94                 gcry_control(GCRYCTL_SET_THREAD_CBS,
    95                              &gcry_threads_pthread);
     173        mgs_handle_t *ctxt;
     174
     175    if (session == NULL) {
     176                // ERROR INVALID SESSION
     177                ret->ncerts = 0;
     178                ret->deinit_all = 1;
     179        return -1;
    96180        }
    97 #endif
    98 #else
    99         mpm_is_threaded = 0;
    100 #endif
    101 
    102 
    103         if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
    104                 _gnutls_log(debug_log_fp,
    105                             "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
    106                             LIBGNUTLS_VERSION, gnutls_check_version(NULL));
    107                 return -3;
     181    ctxt = gnutls_transport_get_ptr(session);
     182
     183    if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
     184                // X509 CERTIFICATE
     185                ret->cert_type = GNUTLS_CRT_X509;
     186                ret->key_type = GNUTLS_PRIVKEY_X509;
     187        ret->ncerts = ctxt->sc->certs_x509_chain_num;
     188        ret->deinit_all = 0;
     189        ret->cert.x509 = ctxt->sc->certs_x509_chain;
     190        ret->key.x509 = ctxt->sc->privkey_x509;
     191        return 0;
     192    } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) {
     193                // OPENPGP CERTIFICATE
     194                ret->cert_type = GNUTLS_CRT_OPENPGP;
     195                ret->key_type = GNUTLS_PRIVKEY_OPENPGP;
     196        ret->ncerts = 1;
     197        ret->deinit_all = 0;
     198        ret->cert.pgp = ctxt->sc->cert_pgp;
     199        ret->key.pgp = ctxt->sc->privkey_pgp;
     200        return 0;
     201    } else {
     202                // UNKNOWN CERTIFICATE
     203                ret->ncerts = 0;
     204                ret->deinit_all = 1;
     205            return -1;
    108206        }
    109 
    110         ret = gnutls_global_init();
    111         if (ret < 0) {
    112                 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n",
    113                             gnutls_strerror(ret));
    114                 return -3;
    115         }
    116 
    117         ret = gnutls_session_ticket_key_generate(&session_ticket_key);
    118         if (ret < 0) {
    119                 _gnutls_log(debug_log_fp,
    120                             "gnutls_session_ticket_key_generate: %s\n",
    121                             gnutls_strerror(ret));
    122         }
    123 
    124         apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
    125                                   apr_pool_cleanup_null);
    126 
    127 
    128         return OK;
    129 }
    130 
    131 static int mgs_select_virtual_server_cb(gnutls_session_t session)
    132 {
    133         mgs_handle_t *ctxt;
    134         mgs_srvconf_rec *tsc;
    135         int ret;
    136         int cprio[2];
    137 
    138         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    139 
    140         ctxt = gnutls_transport_get_ptr(session);
    141 
    142         /* find the virtual server */
    143         tsc = mgs_find_sni_server(session);
    144 
    145         if (tsc != NULL)
    146                 ctxt->sc = tsc;
    147 
    148         gnutls_certificate_server_set_request(session,
    149                                               ctxt->
    150                                               sc->client_verify_mode);
    151 
    152         /* set the new server credentials
    153          */
    154 
    155         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
    156                                ctxt->sc->certs);
    157 
    158         gnutls_credentials_set(session, GNUTLS_CRD_ANON,
    159                                ctxt->sc->anon_creds);
    160 
    161 #ifdef ENABLE_SRP
    162         if (ctxt->sc->srp_tpasswd_conf_file != NULL
    163             && ctxt->sc->srp_tpasswd_file != NULL) {
    164                 gnutls_credentials_set(session, GNUTLS_CRD_SRP,
    165                                        ctxt->sc->srp_creds);
    166         }
    167 #endif
    168 
    169         /* update the priorities - to avoid negotiating a ciphersuite that is not
    170          * enabled on this virtual server. Note that here we ignore the version
    171          * negotiation.
    172          */
    173         ret = gnutls_priority_set(session, ctxt->sc->priorities);
    174         /* actually it shouldn't fail since we have checked at startup */
    175         if (ret < 0)
    176                 return ret;
    177 
    178         /* If both certificate types are not present disallow them from
    179          * being negotiated.
    180          */
    181         if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
    182                 cprio[0] = GNUTLS_CRT_X509;
    183                 cprio[1] = 0;
    184                 gnutls_certificate_type_set_priority(session, cprio);
    185         } else if (ctxt->sc->cert_pgp != NULL
    186                    && ctxt->sc->certs_x509[0] == NULL) {
    187                 cprio[0] = GNUTLS_CRT_OPENPGP;
    188                 cprio[1] = 0;
    189                 gnutls_certificate_type_set_priority(session, cprio);
    190         }
    191 
    192         return 0;
    193 }
    194 
    195 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
    196 {
    197         mgs_handle_t *ctxt;
    198 
    199         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    200         ctxt = gnutls_transport_get_ptr(session);
    201 
    202         if (ctxt == NULL)
    203                 return GNUTLS_E_INTERNAL_ERROR;
    204 
    205         if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
    206                 ret->type = GNUTLS_CRT_X509;
    207                 ret->ncerts = ctxt->sc->certs_x509_num;
    208                 ret->deinit_all = 0;
    209 
    210                 ret->cert.x509 = ctxt->sc->certs_x509;
    211                 ret->key.x509 = ctxt->sc->privkey_x509;
    212 
    213                 return 0;
    214         } else if (gnutls_certificate_type_get(session) ==
    215                    GNUTLS_CRT_OPENPGP) {
    216                 ret->type = GNUTLS_CRT_OPENPGP;
    217                 ret->ncerts = 1;
    218                 ret->deinit_all = 0;
    219 
    220                 ret->cert.pgp = ctxt->sc->cert_pgp;
    221                 ret->key.pgp = ctxt->sc->privkey_pgp;
    222 
    223                 return 0;
    224 
    225         }
    226 
    227         return GNUTLS_E_INTERNAL_ERROR;
    228207}
    229208
    230209/* 2048-bit group parameters from SRP specification */
    231210const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
    232     "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
    233     "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
    234     "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
    235     "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
    236     "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
    237     "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
    238     "-----END DH PARAMETERS-----\n";
     211        "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
     212        "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
     213        "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
     214        "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
     215        "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
     216        "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
     217        "-----END DH PARAMETERS-----\n";
    239218
    240219/* Read the common name or the alternative name of the certificate.
     
    243222 * Returns negative on error.
    244223 */
    245 static int read_crt_cn(server_rec * s, apr_pool_t * p,
    246                        gnutls_x509_crt_t cert, char **cert_cn)
    247 {
    248         int rv = 0, i;
    249         size_t data_len;
    250 
    251 
    252         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    253         *cert_cn = NULL;
    254 
    255         data_len = 0;
    256         rv = gnutls_x509_crt_get_dn_by_oid(cert,
    257                                            GNUTLS_OID_X520_COMMON_NAME,
    258                                            0, 0, NULL, &data_len);
    259 
    260         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    261                 *cert_cn = apr_palloc(p, data_len);
    262                 rv = gnutls_x509_crt_get_dn_by_oid(cert,
    263                                                    GNUTLS_OID_X520_COMMON_NAME,
    264                                                    0, 0, *cert_cn,
    265                                                    &data_len);
    266         } else {                /* No CN return subject alternative name */
    267                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    268                              "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    269                              s->server_hostname, s->port);
    270                 rv = 0;
    271                 /* read subject alternative name */
    272                 for (i = 0; !(rv < 0); i++) {
    273                         data_len = 0;
    274                         rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
    275                                                                   NULL,
    276                                                                   &data_len,
    277                                                                   NULL);
    278 
    279                         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
    280                             && data_len > 1) {
    281                                 /* FIXME: not very efficient. What if we have several alt names
    282                                  * before DNSName?
    283                                  */
    284                                 *cert_cn = apr_palloc(p, data_len + 1);
    285 
    286                                 rv = gnutls_x509_crt_get_subject_alt_name
    287                                     (cert, i, *cert_cn, &data_len, NULL);
    288                                 (*cert_cn)[data_len] = 0;
    289 
    290                                 if (rv == GNUTLS_SAN_DNSNAME)
    291                                         break;
     224static int read_crt_cn(server_rec * s, apr_pool_t * p, gnutls_x509_crt_t cert, char **cert_cn) {
     225
     226    int rv = 0, i;
     227    size_t data_len;
     228
     229
     230    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     231    *cert_cn = NULL;
     232
     233    data_len = 0;
     234    rv = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &data_len);
     235
     236    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     237        *cert_cn = apr_palloc(p, data_len);
     238        rv = gnutls_x509_crt_get_dn_by_oid(cert,
     239                GNUTLS_OID_X520_COMMON_NAME,
     240                0, 0, *cert_cn,
     241                &data_len);
     242    } else { /* No CN return subject alternative name */
     243        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     244                "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
     245                s->server_hostname, s->port);
     246        rv = 0;
     247        /* read subject alternative name */
     248        for (i = 0; !(rv < 0); i++) {
     249            data_len = 0;
     250            rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
     251                    NULL,
     252                    &data_len,
     253                    NULL);
     254
     255            if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
     256                    && data_len > 1) {
     257                /* FIXME: not very efficient. What if we have several alt names
     258                 * before DNSName?
     259                 */
     260                *cert_cn = apr_palloc(p, data_len + 1);
     261
     262                rv = gnutls_x509_crt_get_subject_alt_name
     263                        (cert, i, *cert_cn, &data_len, NULL);
     264                (*cert_cn)[data_len] = 0;
     265
     266                if (rv == GNUTLS_SAN_DNSNAME)
     267                    break;
     268            }
     269        }
     270    }
     271
     272    return rv;
     273}
     274
     275static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
     276        gnutls_openpgp_crt_t cert, char **cert_cn) {
     277    int rv = 0;
     278    size_t data_len;
     279
     280
     281    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     282    *cert_cn = NULL;
     283
     284    data_len = 0;
     285    rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
     286
     287    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     288        *cert_cn = apr_palloc(p, data_len);
     289        rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
     290                &data_len);
     291    } else { /* No CN return subject alternative name */
     292        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     293                "No name found in PGP certificate for '%s:%d'.",
     294                s->server_hostname, s->port);
     295    }
     296
     297    return rv;
     298}
     299
     300int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * base_server) {
     301
     302    int rv;
     303    server_rec *s;
     304    gnutls_dh_params_t dh_params = NULL;
     305    mgs_srvconf_rec *sc;
     306    mgs_srvconf_rec *sc_base;
     307    void *data = NULL;
     308    const char *userdata_key = "mgs_init";
     309
     310    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     311
     312    apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
     313    if (data == NULL) {
     314        apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, base_server->process->pool);
     315    }
     316
     317
     318    s = base_server;
     319    sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
     320
     321    gnutls_dh_params_init(&dh_params);
     322
     323    if (sc_base->dh_params == NULL) {
     324        gnutls_datum_t pdata = {
     325            (void *) static_dh_params,
     326            sizeof(static_dh_params)
     327        };
     328        rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, GNUTLS_X509_FMT_PEM);
     329        /* Generate DH Params
     330        int dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
     331                GNUTLS_SEC_PARAM_NORMAL);
     332        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     333            "GnuTLS: Generating DH Params of %i bits.  "
     334            "To avoid this use GnuTLSDHFile to specify DH Params for this host",
     335            dh_bits);
     336#if MOD_GNUTLS_DEBUG
     337            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     338                    "GnuTLS: Generated DH Params of %i bits",dh_bits);
     339#endif
     340        rv = gnutls_dh_params_generate2 (dh_params,dh_bits);
     341        */
     342        if (rv < 0) {
     343            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     344                    "GnuTLS: Unable to generate or load DH Params: (%d) %s",
     345                    rv, gnutls_strerror(rv));
     346            exit(rv);
     347        }
     348    } else {
     349        dh_params = sc_base->dh_params;
     350    }
     351
     352    rv = mgs_cache_post_config(p, s, sc_base);
     353    if (rv != 0) {
     354        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     355                "GnuTLS: Post Config for GnuTLSCache Failed."
     356                " Shutting Down.");
     357        exit(-1);
     358    }
     359
     360    for (s = base_server; s; s = s->next) {
     361        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
     362        sc->cache_type = sc_base->cache_type;
     363        sc->cache_config = sc_base->cache_config;
     364        sc->cache_timeout = sc_base->cache_timeout;
     365
     366        /* defaults for unset values: */
     367        if (sc->enabled == GNUTLS_ENABLED_UNSET)
     368            sc->enabled = GNUTLS_ENABLED_FALSE;
     369        if (sc->tickets == GNUTLS_ENABLED_UNSET)
     370            sc->tickets = GNUTLS_ENABLED_TRUE;
     371        if (sc->export_certificates_enabled == GNUTLS_ENABLED_UNSET)
     372            sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
     373        if (sc->client_verify_mode ==  -1)
     374            sc->client_verify_mode = GNUTLS_CERT_IGNORE;
     375        if (sc->client_verify_method ==  mgs_cvm_unset)
     376            sc->client_verify_method = mgs_cvm_cartel;
     377
     378
     379        /* Check if the priorities have been set */
     380        if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     381            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     382                    "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
     383                    s->server_hostname, s->port);
     384            exit(-1);
     385        }
     386
     387        /* Check if DH params have been set per host */
     388        if (sc->dh_params != NULL) {
     389            gnutls_certificate_set_dh_params(sc->certs, sc->dh_params);
     390            gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params);
     391        } else if (dh_params) {
     392            gnutls_certificate_set_dh_params(sc->certs, dh_params);
     393            gnutls_anon_set_server_dh_params(sc->anon_creds, dh_params);
     394        }
     395
     396        gnutls_certificate_set_retrieve_function(sc->certs, cert_retrieve_fn);
     397
     398#ifdef ENABLE_SRP
     399        if (sc->srp_tpasswd_conf_file != NULL
     400                && sc->srp_tpasswd_file != NULL) {
     401            rv = gnutls_srp_set_server_credentials_file
     402                    (sc->srp_creds, sc->srp_tpasswd_file,
     403                    sc->srp_tpasswd_conf_file);
     404
     405            if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
     406                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
     407                        s,
     408                        "[GnuTLS] - Host '%s:%d' is missing a "
     409                        "SRP password or conf File!",
     410                        s->server_hostname, s->port);
     411                exit(-1);
     412            }
     413        }
     414#endif
     415
     416        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
     417            sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     418                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     419                                                "[GnuTLS] - Host '%s:%d' is missing a Certificate File!",
     420                                                s->server_hostname, s->port);
     421            exit(-1);
     422        }
     423
     424        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
     425            ((sc->certs_x509_chain != NULL && sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
     426             (sc->cert_pgp != NULL && sc->privkey_pgp == NULL))) {
     427                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     428                                                "[GnuTLS] - Host '%s:%d' is missing a Private Key File!",
     429                                                s->server_hostname, s->port);
     430            exit(-1);
     431        }
     432
     433        if (sc->enabled == GNUTLS_ENABLED_TRUE) {
     434            rv = -1;
     435            if (sc->certs_x509_chain_num > 0) {
     436                rv = read_crt_cn(s, p, sc->certs_x509_chain[0], &sc->cert_cn);
     437            }
     438            if (rv < 0 && sc->cert_pgp != NULL) {
     439                rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
     440                        }
     441
     442            if (rv < 0) {
     443                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     444                                                        "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
     445                                                        s->server_hostname, s->port);
     446                sc->cert_cn = NULL;
     447                continue;
     448            }
     449        }
     450    }
     451
     452
     453    ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
     454
     455    {
     456        const char* libvers = gnutls_check_version(NULL);
     457        char* gnutls_version = NULL;
     458        if(libvers && (gnutls_version = apr_psprintf(p, "GnuTLS/%s", libvers))) {
     459            ap_add_version_component(p, gnutls_version);
     460        } else {
     461            // In case we could not create the above string go for the static version instead
     462            ap_add_version_component(p, "GnuTLS/" GNUTLS_VERSION "-static");
     463        }
     464    }
     465
     466    return OK;
     467}
     468
     469void mgs_hook_child_init(apr_pool_t * p, server_rec * s) {
     470    apr_status_t rv = APR_SUCCESS;
     471    mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
     472            &gnutls_module);
     473
     474    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     475    if (sc->cache_type != mgs_cache_none) {
     476        rv = mgs_cache_child_init(p, s, sc);
     477        if (rv != APR_SUCCESS) {
     478            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     479                    "[GnuTLS] - Failed to run Cache Init");
     480        }
     481    }
     482    /* Block SIGPIPE Signals */
     483    rv = apr_signal_block(SIGPIPE);
     484    if(rv != APR_SUCCESS) {
     485        /* error sending output */
     486        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     487                "GnuTLS: Error Blocking SIGPIPE Signal!");
     488    }
     489}
     490
     491const char *mgs_hook_http_scheme(const request_rec * r) {
     492    mgs_srvconf_rec *sc;
     493
     494    if (r == NULL)
     495        return NULL;
     496
     497    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
     498            server->module_config,
     499            &gnutls_module);
     500
     501    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     502    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
     503        return NULL;
     504    }
     505
     506    return "https";
     507}
     508
     509apr_port_t mgs_hook_default_port(const request_rec * r) {
     510    mgs_srvconf_rec *sc;
     511
     512    if (r == NULL)
     513        return 0;
     514
     515    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
     516            server->module_config,
     517            &gnutls_module);
     518
     519    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     520    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
     521        return 0;
     522    }
     523
     524    return 443;
     525}
     526
     527#define MAX_HOST_LEN 255
     528
     529#if USING_2_1_RECENT
     530
     531typedef struct {
     532    mgs_handle_t *ctxt;
     533    mgs_srvconf_rec *sc;
     534    const char *sni_name;
     535} vhost_cb_rec;
     536
     537/**
     538 * Matches the current vhost's ServerAlias directives
     539 *
     540 * @param x vhost callback record
     541 * @param s server record
     542 * @return true if a match, false otherwise
     543 *
     544 */
     545int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc) {
     546        apr_array_header_t *names;
     547        int i,rv = 0;
     548        char ** name;
     549
     550        /* Check ServerName First! */
     551        if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) {
     552                // We have a match, save this server configuration
     553                x->sc = tsc;
     554                rv = 1;
     555        /* Check any ServerAlias directives */
     556        } else if(s->names->nelts) {
     557                names = s->names;
     558                name = (char **)names->elts;
     559                for (i = 0; i < names->nelts; ++i) {
     560                        if (!name[i]) { continue; }
     561                                if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) {
     562                                        // We have a match, save this server configuration
     563                                        x->sc = tsc;
     564                                        rv = 1;
     565                        }
     566                }
     567        /* Wild any ServerAlias Directives */
     568        } else if(s->wild_names->nelts) {
     569                names = s->wild_names;
     570        name = (char **)names->elts;
     571                for (i = 0; i < names->nelts; ++i) {
     572                        if (!name[i]) { continue; }
     573                                if(apr_fnmatch(name[i], x->sni_name ,
     574                                                                APR_FNM_CASE_BLIND|
     575                                                                APR_FNM_PERIOD|
     576                                                                APR_FNM_PATHNAME|
     577                                                                APR_FNM_NOESCAPE) == APR_SUCCESS) {
     578                                x->sc = tsc;
     579                                rv = 1;
    292580                        }
    293581                }
    294582        }
    295 
    296583        return rv;
    297584}
    298585
    299 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
    300                           gnutls_openpgp_crt_t cert, char **cert_cn)
    301 {
    302         int rv = 0;
    303         size_t data_len;
    304 
    305 
    306         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    307         *cert_cn = NULL;
    308 
    309         data_len = 0;
    310         rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
    311 
    312         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    313                 *cert_cn = apr_palloc(p, data_len);
    314                 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
    315                                                  &data_len);
    316         } else {                /* No CN return subject alternative name */
    317                 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    318                              "No name found in PGP certificate for '%s:%d'.",
    319                              s->server_hostname, s->port);
    320         }
    321 
    322         return rv;
    323 }
    324 
    325 
    326 int
    327 mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
    328                      apr_pool_t * ptemp, server_rec * base_server)
    329 {
    330         int rv;
    331         server_rec *s;
    332         gnutls_dh_params_t dh_params = NULL;
    333         gnutls_rsa_params_t rsa_params = NULL;
    334         mgs_srvconf_rec *sc;
    335         mgs_srvconf_rec *sc_base;
    336         void *data = NULL;
    337         int first_run = 0;
    338         const char *userdata_key = "mgs_init";
    339 
    340         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    341         apr_pool_userdata_get(&data, userdata_key,
    342                               base_server->process->pool);
    343         if (data == NULL) {
    344                 first_run = 1;
    345                 apr_pool_userdata_set((const void *) 1, userdata_key,
    346                                       apr_pool_cleanup_null,
    347                                       base_server->process->pool);
    348         }
    349 
    350 
    351         s = base_server;
    352         sc_base =
    353             (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    354                                                      &gnutls_module);
    355 
    356         gnutls_dh_params_init(&dh_params);
    357 
    358         if (sc_base->dh_params == NULL) {
    359                 gnutls_datum pdata = {
    360                         (void *) static_dh_params,
    361                         sizeof(static_dh_params)
    362                 };
    363                 /* loading defaults */
    364                 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
    365                                                    GNUTLS_X509_FMT_PEM);
    366 
    367                 if (rv < 0) {
    368                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    369                                      "GnuTLS: Unable to load DH Params: (%d) %s",
    370                                      rv, gnutls_strerror(rv));
    371                         exit(rv);
    372                 }
    373         } else
    374                 dh_params = sc_base->dh_params;
    375 
    376         if (sc_base->rsa_params != NULL)
    377                 rsa_params = sc_base->rsa_params;
    378 
    379         /* else not an error but RSA-EXPORT ciphersuites are not available
    380          */
    381 
    382         rv = mgs_cache_post_config(p, s, sc_base);
    383         if (rv != 0) {
    384                 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    385                              "GnuTLS: Post Config for GnuTLSCache Failed."
    386                              " Shutting Down.");
    387                 exit(-1);
    388         }
    389 
    390         for (s = base_server; s; s = s->next) {
    391                 void *load = NULL;
    392                 sc = (mgs_srvconf_rec *)
    393                     ap_get_module_config(s->module_config, &gnutls_module);
    394                 sc->cache_type = sc_base->cache_type;
    395                 sc->cache_config = sc_base->cache_config;
    396 
    397                 /* Check if the priorities have been set */
    398                 if (sc->priorities == NULL
    399                     && sc->enabled == GNUTLS_ENABLED_TRUE) {
    400                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    401                                      "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
    402                                      s->server_hostname, s->port);
    403                         exit(-1);
    404                 }
    405 
    406                 /* Check if DH or RSA params have been set per host */
    407                 if (sc->rsa_params != NULL)
    408                         load = sc->rsa_params;
    409                 else if (rsa_params)
    410                         load = rsa_params;
    411 
    412                 if (load != NULL)
    413                         gnutls_certificate_set_rsa_export_params(sc->certs,
    414                                                                  load);
    415 
    416 
    417                 load = NULL;
    418                 if (sc->dh_params != NULL)
    419                         load = sc->dh_params;
    420                 else if (dh_params)
    421                         load = dh_params;
    422 
    423                 if (load != NULL) {     /* not needed but anyway */
    424                         gnutls_certificate_set_dh_params(sc->certs, load);
    425                         gnutls_anon_set_server_dh_params(sc->anon_creds,
    426                                                          load);
    427                 }
    428 
    429                 gnutls_certificate_server_set_retrieve_function(sc->certs,
    430                                                                 cert_retrieve_fn);
    431 
    432 #ifdef ENABLE_SRP
    433                 if (sc->srp_tpasswd_conf_file != NULL
    434                     && sc->srp_tpasswd_file != NULL) {
    435                         rv = gnutls_srp_set_server_credentials_file
    436                             (sc->srp_creds, sc->srp_tpasswd_file,
    437                              sc->srp_tpasswd_conf_file);
    438 
    439                         if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
    440                                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
    441                                              s,
    442                                              "[GnuTLS] - Host '%s:%d' is missing a "
    443                                              "SRP password or conf File!",
    444                                              s->server_hostname, s->port);
    445                                 exit(-1);
    446                         }
    447                 }
     586static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) {
     587    mgs_srvconf_rec *tsc;
     588    vhost_cb_rec *x = baton;
     589    int ret;
     590
     591    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     592    tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     593            &gnutls_module);
     594
     595    if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
     596        return 0;
     597    }
     598
     599    if (tsc->certs_x509_chain_num > 0) {
     600        /* why are we doing this check? */
     601        ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_chain[0], s->server_hostname);
     602        if (0 == ret)
     603            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     604                         "GnuTLS: Error checking certificate for hostname "
     605                         "'%s'", s->server_hostname);
     606    } else {
     607        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     608                     "GnuTLS: SNI request for '%s' but no X.509 certs available at all",
     609                     s->server_hostname);
     610    }
     611        return check_server_aliases(x, s, tsc);
     612}
    448613#endif
    449614
    450                 if (sc->certs_x509[0] == NULL &&
    451                     sc->cert_pgp == NULL &&
    452                     sc->enabled == GNUTLS_ENABLED_TRUE) {
    453                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    454                                      "[GnuTLS] - Host '%s:%d' is missing a "
    455                                      "Certificate File!",
    456                                      s->server_hostname, s->port);
    457                         exit(-1);
    458                 }
    459 
    460                 if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    461                     ((sc->certs_x509[0] != NULL
    462                       && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL
    463                                                        && sc->privkey_pgp
    464                                                        == NULL))) {
    465                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    466                                      "[GnuTLS] - Host '%s:%d' is missing a "
    467                                      "Private Key File!",
    468                                      s->server_hostname, s->port);
    469                         exit(-1);
    470                 }
    471 
    472                 if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    473                         rv = read_crt_cn(s, p, sc->certs_x509[0],
    474                                          &sc->cert_cn);
    475                         if (rv < 0 && sc->cert_pgp != NULL)     /* try openpgp certificate */
    476                                 rv = read_pgpcrt_cn(s, p, sc->cert_pgp,
    477                                                     &sc->cert_cn);
    478 
    479                         if (rv < 0) {
    480                                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
    481                                              s,
    482                                              "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
    483                                              s->server_hostname, s->port);
    484                                 sc->cert_cn = NULL;
    485                                 continue;
    486                         }
    487                 }
    488         }
    489 
    490 
    491         ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
    492 
    493         return OK;
    494 }
    495 
    496 void mgs_hook_child_init(apr_pool_t * p, server_rec * s)
    497 {
    498         apr_status_t rv = APR_SUCCESS;
    499         mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
    500                                                    &gnutls_module);
    501 
    502         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    503         if (sc->cache_type != mgs_cache_none) {
    504                 rv = mgs_cache_child_init(p, s, sc);
    505                 if (rv != APR_SUCCESS) {
    506                         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    507                                      "[GnuTLS] - Failed to run Cache Init");
    508                 }
    509         }
    510 }
    511 
    512 const char *mgs_hook_http_scheme(const request_rec * r)
    513 {
    514         mgs_srvconf_rec *sc;
    515 
    516         if (r == NULL)
    517                 return NULL;
    518 
    519         sc = (mgs_srvconf_rec *) ap_get_module_config(r->
    520                                                       server->module_config,
    521                                                       &gnutls_module);
    522 
    523         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    524         if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    525                 return NULL;
    526         }
    527 
    528         return "https";
    529 }
    530 
    531 apr_port_t mgs_hook_default_port(const request_rec * r)
    532 {
    533         mgs_srvconf_rec *sc;
    534 
    535         if (r == NULL)
    536                 return 0;
    537 
    538         sc = (mgs_srvconf_rec *) ap_get_module_config(r->
    539                                                       server->module_config,
    540                                                       &gnutls_module);
    541 
    542         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    543         if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    544                 return 0;
    545         }
    546 
    547         return 443;
    548 }
    549 
    550 #define MAX_HOST_LEN 255
    551 
     615mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) {
     616    int rv;
     617    unsigned int sni_type;
     618    size_t data_len = MAX_HOST_LEN;
     619    char sni_name[MAX_HOST_LEN];
     620    mgs_handle_t *ctxt;
    552621#if USING_2_1_RECENT
    553 typedef struct {
    554         mgs_handle_t *ctxt;
    555         mgs_srvconf_rec *sc;
    556         const char *sni_name;
    557 } vhost_cb_rec;
    558 
    559 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
    560 {
    561         mgs_srvconf_rec *tsc;
    562         vhost_cb_rec *x = baton;
    563 
    564         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    565         tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    566                                                        &gnutls_module);
    567 
    568         if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
    569                 return 0;
    570         }
    571 
    572         /* The CN can contain a * -- this will match those too. */
    573         if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
    574                 /* found a match */
    575 #if MOD_GNUTLS_DEBUG
    576                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    577                              x->ctxt->c->base_server,
    578                              "GnuTLS: Virtual Host CB: "
    579                              "'%s' == '%s'", tsc->cert_cn, x->sni_name);
     622    vhost_cb_rec cbx;
     623#else
     624    server_rec *s;
     625    mgs_srvconf_rec *tsc;
    580626#endif
    581                 /* Because we actually change the server used here, we need to reset
    582                  * things like ClientVerify.
    583                  */
    584                 x->sc = tsc;
    585                 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
    586                  * certificate structure *should* change when the server changes.
    587                  * acccckkkkkk.
    588                  */
    589                 return 1;
    590         } else {
    591 #if MOD_GNUTLS_DEBUG
    592                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    593                              x->ctxt->c->base_server,
    594                              "GnuTLS: Virtual Host CB: "
    595                              "'%s' != '%s'", tsc->cert_cn, x->sni_name);
    596 #endif
    597 
    598         }
    599         return 0;
    600 }
    601 #endif
    602 
    603 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
    604 {
    605         int rv;
    606         unsigned int sni_type;
    607         size_t data_len = MAX_HOST_LEN;
    608         char sni_name[MAX_HOST_LEN];
    609         mgs_handle_t *ctxt;
    610 #if USING_2_1_RECENT
    611         vhost_cb_rec cbx;
    612 #else
    613         server_rec *s;
    614         mgs_srvconf_rec *tsc;
    615 #endif
    616 
    617         if (session == NULL)
    618                 return NULL;
    619 
    620         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    621         ctxt = gnutls_transport_get_ptr(session);
    622 
    623         rv = gnutls_server_name_get(ctxt->session, sni_name,
    624                                     &data_len, &sni_type, 0);
    625 
    626         if (rv != 0) {
    627                 return NULL;
    628         }
    629 
    630         if (sni_type != GNUTLS_NAME_DNS) {
    631                 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
    632                              ctxt->c->base_server,
    633                              "GnuTLS: Unknown type '%d' for SNI: "
    634                              "'%s'", sni_type, sni_name);
    635                 return NULL;
    636         }
     627
     628    if (session == NULL)
     629        return NULL;
     630
     631    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     632    ctxt = gnutls_transport_get_ptr(session);
     633
     634    rv = gnutls_server_name_get(ctxt->session, sni_name,
     635            &data_len, &sni_type, 0);
     636
     637    if (rv != 0) {
     638        return NULL;
     639    }
     640
     641    if (sni_type != GNUTLS_NAME_DNS) {
     642        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     643                ctxt->c->base_server,
     644                "GnuTLS: Unknown type '%d' for SNI: "
     645                "'%s'", sni_type, sni_name);
     646        return NULL;
     647    }
    637648
    638649    /**
     
    641652     */
    642653#if USING_2_1_RECENT
    643         cbx.ctxt = ctxt;
    644         cbx.sc = NULL;
    645         cbx.sni_name = sni_name;
    646 
    647         rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    648         if (rv == 1) {
    649                 return cbx.sc;
     654    cbx.ctxt = ctxt;
     655    cbx.sc = NULL;
     656    cbx.sni_name = sni_name;
     657
     658    rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     659    if (rv == 1) {
     660        return cbx.sc;
     661    }
     662#else
     663    for (s = ap_server_conf; s; s = s->next) {
     664
     665        tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     666                &gnutls_module);
     667
     668        if (tsc->enabled != GNUTLS_ENABLED_TRUE) { continue; }
     669
     670                                if(check_server_aliases(x, s, tsc)) {
     671                                        return tsc;
     672                                }
     673#endif
     674    return NULL;
     675}
     676
     677static void create_gnutls_handle(conn_rec * c) {
     678    mgs_handle_t *ctxt;
     679    /* Get mod_gnutls Configuration Record */
     680    mgs_srvconf_rec *sc =(mgs_srvconf_rec *)
     681            ap_get_module_config(c->base_server->module_config,&gnutls_module);
     682
     683    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     684    ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
     685    ctxt->c = c;
     686    ctxt->sc = sc;
     687    ctxt->status = 0;
     688    ctxt->input_rc = APR_SUCCESS;
     689    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
     690    ctxt->input_cbuf.length = 0;
     691    ctxt->output_rc = APR_SUCCESS;
     692    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
     693    ctxt->output_blen = 0;
     694    ctxt->output_length = 0;
     695    /* Initialize GnuTLS Library */
     696    gnutls_init(&ctxt->session, GNUTLS_SERVER);
     697    /* Initialize Session Tickets */
     698    if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) {
     699        gnutls_session_ticket_enable_server(ctxt->session,&session_ticket_key);
     700    }
     701
     702    /* Set Default Priority */
     703        gnutls_priority_set_direct (ctxt->session, "NORMAL", NULL);
     704    /* Set Handshake function */
     705    gnutls_handshake_set_post_client_hello_function(ctxt->session,
     706            mgs_select_virtual_server_cb);
     707    /* Initialize Session Cache */
     708    mgs_cache_session_init(ctxt);
     709
     710    /* Set this config for this connection */
     711    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
     712    /* Set pull, push & ptr functions */
     713    gnutls_transport_set_pull_function(ctxt->session,
     714            mgs_transport_read);
     715    gnutls_transport_set_push_function(ctxt->session,
     716            mgs_transport_write);
     717    gnutls_transport_set_ptr(ctxt->session, ctxt);
     718    /* Add IO filters */
     719    ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME,
     720            ctxt, NULL, c);
     721    ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
     722            ctxt, NULL, c);
     723}
     724
     725int mgs_hook_pre_connection(conn_rec * c, void *csd) {
     726    mgs_srvconf_rec *sc;
     727
     728    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     729
     730    sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->module_config,
     731            &gnutls_module);
     732
     733    if (sc && (!sc->enabled || sc->proxy_enabled == GNUTLS_ENABLED_TRUE)) {
     734        return DECLINED;
     735    }
     736
     737    create_gnutls_handle(c);
     738    return OK;
     739}
     740
     741int mgs_hook_fixups(request_rec * r) {
     742    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
     743    char buf[AP_IOBUFSIZE];
     744    const char *tmp;
     745    size_t len;
     746    mgs_handle_t *ctxt;
     747    int rv = OK;
     748
     749    if (r == NULL)
     750        return DECLINED;
     751
     752    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     753    apr_table_t *env = r->subprocess_env;
     754
     755    ctxt =
     756            ap_get_module_config(r->connection->conn_config,
     757            &gnutls_module);
     758
     759    if (!ctxt || ctxt->session == NULL) {
     760        return DECLINED;
     761    }
     762
     763    apr_table_setn(env, "HTTPS", "on");
     764
     765    apr_table_setn(env, "SSL_VERSION_LIBRARY",
     766            "GnuTLS/" LIBGNUTLS_VERSION);
     767    apr_table_setn(env, "SSL_VERSION_INTERFACE",
     768            "mod_gnutls/" MOD_GNUTLS_VERSION);
     769
     770    apr_table_setn(env, "SSL_PROTOCOL",
     771            gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
     772
     773    /* should have been called SSL_CIPHERSUITE instead */
     774    apr_table_setn(env, "SSL_CIPHER",
     775            gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session),
     776                                         gnutls_cipher_get(ctxt->session),
     777                                         gnutls_mac_get(ctxt->session)));
     778
     779    apr_table_setn(env, "SSL_COMPRESS_METHOD",
     780            gnutls_compression_get_name(gnutls_compression_get(ctxt->session)));
     781
     782#ifdef ENABLE_SRP
     783    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
     784        tmp = gnutls_srp_server_get_username(ctxt->session);
     785        apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
     786    } else {
     787        apr_table_unset(env, "SSL_SRP_USER");
     788    }
     789#endif
     790
     791    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
     792        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
     793
     794    unsigned int key_size = 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
     795    tmp = apr_psprintf(r->pool, "%u", key_size);
     796
     797    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
     798
     799    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
     800
     801    apr_table_setn(env, "SSL_CIPHER_EXPORT",
     802            (key_size <= 40) ? "true" : "false");
     803
     804    int dhsize = gnutls_dh_get_prime_bits(ctxt->session);
     805    if (dhsize > 0) {
     806        tmp = apr_psprintf(r->pool, "%d", dhsize);
     807        apr_table_setn(env, "SSL_DH_PRIME_BITS", tmp);
     808    }
     809
     810    len = sizeof (sbuf);
     811    gnutls_session_get_id(ctxt->session, sbuf, &len);
     812    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     813    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
     814
     815    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     816                mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_chain[0], 0, ctxt->sc->export_certificates_enabled);
     817        } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
     818        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, ctxt->sc->export_certificates_enabled);
    650819        }
    651 #else
    652         for (s = ap_server_conf; s; s = s->next) {
    653 
    654                 tsc =
    655                     (mgs_srvconf_rec *)
    656                     ap_get_module_config(s->module_config, &gnutls_module);
    657                 if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
    658                         continue;
    659                 }
     820
     821    return rv;
     822}
     823
     824int mgs_hook_authz(request_rec * r) {
     825    int rv;
     826    mgs_handle_t *ctxt;
     827    mgs_dirconf_rec *dc;
     828
     829    if (r == NULL)
     830        return DECLINED;
     831
     832    dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
     833
     834    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     835    ctxt =
     836            ap_get_module_config(r->connection->conn_config,
     837            &gnutls_module);
     838
     839    if (!ctxt || ctxt->session == NULL) {
     840        return DECLINED;
     841    }
     842
     843    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
     844        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     845                "GnuTLS: Directory set to Ignore Client Certificate!");
     846    } else {
     847        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
     848            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     849                    "GnuTLS: Attempting to rehandshake with peer. %d %d",
     850                    ctxt->sc->client_verify_mode,
     851                    dc->client_verify_mode);
     852
     853            /* If we already have a client certificate, there's no point in
     854             * re-handshaking... */
     855            rv = mgs_cert_verify(r, ctxt);
     856            if (rv != DECLINED && rv != HTTP_FORBIDDEN)
     857                return rv;
     858
     859            gnutls_certificate_server_set_request
     860                    (ctxt->session, dc->client_verify_mode);
     861
     862            if (mgs_rehandshake(ctxt) != 0) {
     863                return HTTP_FORBIDDEN;
     864            }
     865        } else if (ctxt->sc->client_verify_mode ==
     866                GNUTLS_CERT_IGNORE) {
    660867#if MOD_GNUTLS_DEBUG
    661                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    662                              ctxt->c->base_server,
    663                              "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
    664                              tsc->cert_cn, rv,
    665                              gnutls_pk_algorithm_get_name
    666                              (gnutls_x509_privkey_get_pk_algorithm
    667                               (ctxt->sc->privkey_x509)), (unsigned int) s,
    668                              (unsigned int) s->next, (unsigned int) tsc);
     868            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     869                    "GnuTLS: Peer is set to IGNORE");
    669870#endif
    670                 /* The CN can contain a * -- this will match those too. */
    671                 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
    672 #if MOD_GNUTLS_DEBUG
    673                         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    674                                      ctxt->c->base_server,
    675                                      "GnuTLS: Virtual Host: "
    676                                      "'%s' == '%s'", tsc->cert_cn,
    677                                      sni_name);
    678 #endif
    679                         return tsc;
    680                 }
    681         }
    682 #endif
    683         return NULL;
    684 }
    685 
    686 
    687 static const int protocol_priority[] = {
    688         GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
    689 };
    690 
    691 
    692 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
    693 {
    694         mgs_handle_t *ctxt;
    695         mgs_srvconf_rec *sc =
    696             (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
    697                                                      module_config,
    698                                                      &gnutls_module);
    699 
    700         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    701         ctxt = apr_pcalloc(pool, sizeof(*ctxt));
    702         ctxt->c = c;
    703         ctxt->sc = sc;
    704         ctxt->status = 0;
    705 
    706         ctxt->input_rc = APR_SUCCESS;
    707         ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
    708         ctxt->input_cbuf.length = 0;
    709 
    710         ctxt->output_rc = APR_SUCCESS;
    711         ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
    712         ctxt->output_blen = 0;
    713         ctxt->output_length = 0;
    714 
    715         gnutls_init(&ctxt->session, GNUTLS_SERVER);
    716         if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
    717                 gnutls_session_ticket_enable_server(ctxt->session,
    718                                                     &session_ticket_key);
    719 
    720         /* because we don't set any default priorities here (we set later at
    721          * the user hello callback) we need to at least set this in order for
    722          * gnutls to be able to read packets.
    723          */
    724         gnutls_protocol_set_priority(ctxt->session, protocol_priority);
    725 
    726         gnutls_handshake_set_post_client_hello_function(ctxt->session,
    727                                                         mgs_select_virtual_server_cb);
    728 
    729         mgs_cache_session_init(ctxt);
    730 
    731         return ctxt;
    732 }
    733 
    734 int mgs_hook_pre_connection(conn_rec * c, void *csd)
    735 {
    736         mgs_handle_t *ctxt;
    737         mgs_srvconf_rec *sc;
    738 
    739         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    740 
    741         if (c == NULL) {
    742                 return DECLINED;
    743         }
    744 
    745         sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
    746                                                       module_config,
    747                                                       &gnutls_module);
    748 
    749         if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
    750                 return DECLINED;
    751         }
    752 
    753         if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip,c->local_ip) == 0) {
    754         /* Connection initiated by Apache (mod_proxy) => ignore */
    755                 return OK;
    756         }
    757                
    758         ctxt = create_gnutls_handle(c->pool, c);
    759 
    760         ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
    761 
    762         gnutls_transport_set_pull_function(ctxt->session,
    763                                            mgs_transport_read);
    764         gnutls_transport_set_push_function(ctxt->session,
    765                                            mgs_transport_write);
    766         gnutls_transport_set_ptr(ctxt->session, ctxt);
    767 
    768         ctxt->input_filter =
    769             ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
    770         ctxt->output_filter =
    771             ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
    772 
    773         return OK;
    774 }
    775 
    776 int mgs_hook_fixups(request_rec * r)
    777 {
    778         unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
    779         char buf[AP_IOBUFSIZE];
    780         const char *tmp;
    781         size_t len;
    782         mgs_handle_t *ctxt;
    783         int rv = OK;
    784 
    785         if (r == NULL)
    786                 return DECLINED;
    787 
    788         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    789         apr_table_t *env = r->subprocess_env;
    790 
    791         ctxt =
    792             ap_get_module_config(r->connection->conn_config,
    793                                  &gnutls_module);
    794 
    795         if (!ctxt || ctxt->session == NULL) {
    796                 return DECLINED;
    797         }
    798 
    799         apr_table_setn(env, "HTTPS", "on");
    800 
    801         apr_table_setn(env, "SSL_VERSION_LIBRARY",
    802                        "GnuTLS/" LIBGNUTLS_VERSION);
    803         apr_table_setn(env, "SSL_VERSION_INTERFACE",
    804                        "mod_gnutls/" MOD_GNUTLS_VERSION);
    805 
    806         apr_table_setn(env, "SSL_PROTOCOL",
    807                        gnutls_protocol_get_name(gnutls_protocol_get_version
    808                                                 (ctxt->session)));
    809 
    810         /* should have been called SSL_CIPHERSUITE instead */
    811         apr_table_setn(env, "SSL_CIPHER",
    812                        gnutls_cipher_suite_get_name(gnutls_kx_get
    813                                                     (ctxt->session),
    814                                                     gnutls_cipher_get
    815                                                     (ctxt->session),
    816                                                     gnutls_mac_get
    817                                                     (ctxt->session)));
    818 
    819         apr_table_setn(env, "SSL_COMPRESS_METHOD",
    820                        gnutls_compression_get_name(gnutls_compression_get
    821                                                    (ctxt->session)));
    822 
    823 #ifdef ENABLE_SRP
    824         tmp = gnutls_srp_server_get_username(ctxt->session);
    825         apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
    826 #endif
    827 
    828         if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
    829                 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
    830 
    831         unsigned int key_size =
    832             8 *
    833             gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
    834         tmp = apr_psprintf(r->pool, "%u", key_size);
    835 
    836         apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
    837 
    838         apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
    839 
    840         apr_table_setn(env, "SSL_CIPHER_EXPORT",
    841                        (key_size <= 40) ? "true" : "false");
    842 
    843         len = sizeof(sbuf);
    844         gnutls_session_get_id(ctxt->session, sbuf, &len);
    845         tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
    846         apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
    847 
    848         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    849                 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
    850                                          ctxt->
    851                                          sc->export_certificates_enabled);
    852         else if (gnutls_certificate_type_get(ctxt->session) ==
    853                  GNUTLS_CRT_OPENPGP)
    854                 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
    855                                             ctxt->
    856                                             sc->export_certificates_enabled);
    857 
    858         return rv;
    859 }
    860 
    861 int mgs_hook_authz(request_rec * r)
    862 {
    863         int rv;
    864         mgs_handle_t *ctxt;
    865         mgs_dirconf_rec *dc;
    866 
    867         if (r == NULL)
    868                 return DECLINED;
    869 
    870         dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
    871 
    872         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    873         ctxt =
    874             ap_get_module_config(r->connection->conn_config,
    875                                  &gnutls_module);
    876 
    877         if (!ctxt || ctxt->session == NULL) {
    878                 return DECLINED;
    879         }
    880 
    881         if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
    882                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    883                               "GnuTLS: Directory set to Ignore Client Certificate!");
    884         } else {
    885                 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
    886                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    887                                       "GnuTLS: Attempting to rehandshake with peer. %d %d",
    888                                       ctxt->sc->client_verify_mode,
    889                                       dc->client_verify_mode);
    890 
    891                         /* If we already have a client certificate, there's no point in
    892                          * re-handshaking... */
    893                         rv = mgs_cert_verify(r, ctxt);
    894                         if (rv != DECLINED && rv != HTTP_FORBIDDEN)
    895                                 return rv;
    896 
    897                         gnutls_certificate_server_set_request
    898                             (ctxt->session, dc->client_verify_mode);
    899 
    900                         if (mgs_rehandshake(ctxt) != 0) {
    901                                 return HTTP_FORBIDDEN;
    902                         }
    903                 } else if (ctxt->sc->client_verify_mode ==
    904                            GNUTLS_CERT_IGNORE) {
    905 #if MOD_GNUTLS_DEBUG
    906                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    907                                       "GnuTLS: Peer is set to IGNORE");
    908 #endif
    909                         return DECLINED;
    910                 }
    911                 rv = mgs_cert_verify(r, ctxt);
    912                 if (rv != DECLINED &&
    913                     (rv != HTTP_FORBIDDEN ||
    914                      dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
    915                         return rv;
    916                 }
    917         }
    918 
    919         return DECLINED;
     871            return DECLINED;
     872        }
     873        rv = mgs_cert_verify(r, ctxt);
     874        if (rv != DECLINED &&
     875                (rv != HTTP_FORBIDDEN ||
     876                dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
     877            return rv;
     878        }
     879    }
     880
     881    return DECLINED;
    920882}
    921883
     
    926888 */
    927889
    928 /* side is either 0 for SERVER or 1 for CLIENT
     890/* @param side is either 0 for SERVER or 1 for CLIENT
     891 *
     892 * @param export_full_cert (boolean) export the PEM-encoded
     893 * certificate in full as an environment variable.
    929894 */
    930895#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
    931 static void
    932 mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
    933                          int export_certificates_enabled)
     896
     897static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert) {
     898    unsigned char sbuf[64]; /* buffer to hold serials */
     899    char buf[AP_IOBUFSIZE];
     900    const char *tmp;
     901    char *tmp2;
     902    size_t len;
     903    int ret, i;
     904
     905    if (r == NULL)
     906        return;
     907
     908    apr_table_t *env = r->subprocess_env;
     909
     910    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     911    if (export_full_cert != 0) {
     912        char cert_buf[10 * 1024];
     913        len = sizeof (cert_buf);
     914
     915        if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
     916            apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
     917                           apr_pstrmemdup(r->pool, cert_buf, len));
     918        else
     919            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     920                          "GnuTLS: Failed to export X.509 certificate to environment");
     921    }
     922
     923    len = sizeof (buf);
     924    gnutls_x509_crt_get_dn(cert, buf, &len);
     925    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
     926            apr_pstrmemdup(r->pool, buf, len));
     927
     928    len = sizeof (buf);
     929    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
     930    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
     931            apr_pstrmemdup(r->pool, buf, len));
     932
     933    len = sizeof (sbuf);
     934    gnutls_x509_crt_get_serial(cert, sbuf, &len);
     935    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     936    apr_table_setn(env,
     937            apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
     938            apr_pstrdup(r->pool, tmp));
     939
     940    ret = gnutls_x509_crt_get_version(cert);
     941    if (ret > 0)
     942        apr_table_setn(env,
     943            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     944            NULL), apr_psprintf(r->pool,
     945            "%u", ret));
     946
     947    apr_table_setn(env,
     948            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     949            "X.509");
     950
     951    tmp =
     952            mgs_time2sz(gnutls_x509_crt_get_expiration_time
     953            (cert), buf, sizeof (buf));
     954    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     955            apr_pstrdup(r->pool, tmp));
     956
     957    tmp =
     958            mgs_time2sz(gnutls_x509_crt_get_activation_time
     959            (cert), buf, sizeof (buf));
     960    apr_table_setn(env,
     961            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     962            apr_pstrdup(r->pool, tmp));
     963
     964    ret = gnutls_x509_crt_get_signature_algorithm(cert);
     965    if (ret >= 0) {
     966        apr_table_setn(env,
     967                apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
     968                NULL),
     969                gnutls_sign_algorithm_get_name(ret));
     970    }
     971
     972    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
     973    if (ret >= 0) {
     974        apr_table_setn(env,
     975                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     976                NULL),
     977                gnutls_pk_algorithm_get_name(ret));
     978    }
     979
     980    /* export all the alternative names (DNS, RFC822 and URI) */
     981    for (i = 0; !(ret < 0); i++) {
     982        len = 0;
     983        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
     984                NULL, &len,
     985                NULL);
     986
     987        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
     988            tmp2 = apr_palloc(r->pool, len + 1);
     989
     990            ret =
     991                    gnutls_x509_crt_get_subject_alt_name(cert, i,
     992                    tmp2,
     993                    &len,
     994                    NULL);
     995            tmp2[len] = 0;
     996
     997            if (ret == GNUTLS_SAN_DNSNAME) {
     998                apr_table_setn(env,
     999                        apr_psprintf(r->pool,
     1000                        "%s_S_AN%u",
     1001                        MGS_SIDE, i),
     1002                        apr_psprintf(r->pool,
     1003                        "DNSNAME:%s",
     1004                        tmp2));
     1005            } else if (ret == GNUTLS_SAN_RFC822NAME) {
     1006                apr_table_setn(env,
     1007                        apr_psprintf(r->pool,
     1008                        "%s_S_AN%u",
     1009                        MGS_SIDE, i),
     1010                        apr_psprintf(r->pool,
     1011                        "RFC822NAME:%s",
     1012                        tmp2));
     1013            } else if (ret == GNUTLS_SAN_URI) {
     1014                apr_table_setn(env,
     1015                        apr_psprintf(r->pool,
     1016                        "%s_S_AN%u",
     1017                        MGS_SIDE, i),
     1018                        apr_psprintf(r->pool,
     1019                        "URI:%s",
     1020                        tmp2));
     1021            } else {
     1022                apr_table_setn(env,
     1023                        apr_psprintf(r->pool,
     1024                        "%s_S_AN%u",
     1025                        MGS_SIDE, i),
     1026                        "UNSUPPORTED");
     1027            }
     1028        }
     1029    }
     1030}
     1031
     1032
     1033/* @param side 0: server, 1: client
     1034 *
     1035 * @param export_full_cert (boolean) export the PEM-encoded
     1036 * certificate in full as an environment variable.
     1037 */
     1038static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert) {
     1039
     1040        unsigned char sbuf[64]; /* buffer to hold serials */
     1041    char buf[AP_IOBUFSIZE];
     1042    const char *tmp;
     1043    size_t len;
     1044    int ret;
     1045
     1046    if (r == NULL)
     1047        return;
     1048
     1049    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1050    apr_table_t *env = r->subprocess_env;
     1051
     1052    if (export_full_cert != 0) {
     1053        char cert_buf[10 * 1024];
     1054        len = sizeof (cert_buf);
     1055
     1056        if (gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
     1057            apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
     1058                           apr_pstrmemdup(r->pool, cert_buf, len));
     1059        else
     1060            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1061                          "GnuTLS: Failed to export OpenPGP certificate to environment");
     1062    }
     1063
     1064    len = sizeof (buf);
     1065    gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
     1066    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
     1067            apr_pstrmemdup(r->pool, buf, len));
     1068
     1069    len = sizeof (sbuf);
     1070    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
     1071    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     1072    apr_table_setn(env,
     1073            apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
     1074            NULL), apr_pstrdup(r->pool, tmp));
     1075
     1076    ret = gnutls_openpgp_crt_get_version(cert);
     1077    if (ret > 0)
     1078        apr_table_setn(env,
     1079            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     1080            NULL), apr_psprintf(r->pool,
     1081            "%u", ret));
     1082
     1083    apr_table_setn(env,
     1084            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     1085            "OPENPGP");
     1086
     1087    tmp =
     1088            mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
     1089            (cert), buf, sizeof (buf));
     1090    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     1091            apr_pstrdup(r->pool, tmp));
     1092
     1093    tmp =
     1094            mgs_time2sz(gnutls_openpgp_crt_get_creation_time
     1095            (cert), buf, sizeof (buf));
     1096    apr_table_setn(env,
     1097            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     1098            apr_pstrdup(r->pool, tmp));
     1099
     1100    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
     1101    if (ret >= 0) {
     1102        apr_table_setn(env,
     1103                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     1104                NULL),
     1105                gnutls_pk_algorithm_get_name(ret));
     1106    }
     1107
     1108}
     1109
     1110/* TODO: Allow client sending a X.509 certificate chain */
     1111static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) {
     1112    const gnutls_datum_t *cert_list;
     1113    unsigned int cert_list_size, status;
     1114    int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
     1115    unsigned int ch_size = 0;
     1116
     1117    union {
     1118        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
     1119        gnutls_openpgp_crt_t pgp;
     1120    } cert;
     1121    apr_time_t expiration_time, cur_time;
     1122
     1123    if (r == NULL || ctxt == NULL || ctxt->session == NULL)
     1124        return HTTP_FORBIDDEN;
     1125
     1126    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1127    cert_list =
     1128            gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
     1129
     1130    if (cert_list == NULL || cert_list_size == 0) {
     1131        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
     1132         */
     1133        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1134            return OK;
     1135
     1136        /* no certificate provided by the client, but one was required. */
     1137        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1138                "GnuTLS: Failed to Verify Peer: "
     1139                "Client did not submit a certificate");
     1140        return HTTP_FORBIDDEN;
     1141    }
     1142
     1143    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1144        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1145                "GnuTLS: A Chain of %d certificate(s) was provided for validation",
     1146                cert_list_size);
     1147
     1148        for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
     1149            gnutls_x509_crt_init(&cert.x509[ch_size]);
     1150            rv = gnutls_x509_crt_import(cert.x509[ch_size],
     1151                    &cert_list[ch_size],
     1152                    GNUTLS_X509_FMT_DER);
     1153            // When failure to import, leave the loop
     1154            if (rv != GNUTLS_E_SUCCESS) {
     1155                if (ch_size < 1) {
     1156                    ap_log_rerror(APLOG_MARK,
     1157                            APLOG_INFO, 0, r,
     1158                            "GnuTLS: Failed to Verify Peer: "
     1159                            "Failed to import peer certificates.");
     1160                    ret = HTTP_FORBIDDEN;
     1161                    goto exit;
     1162                }
     1163                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1164                        "GnuTLS: Failed to import some peer certificates. Using %d certificates",
     1165                        ch_size);
     1166                rv = GNUTLS_E_SUCCESS;
     1167                break;
     1168            }
     1169        }
     1170    } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
     1171        if (cert_list_size > 1) {
     1172            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1173                    "GnuTLS: Failed to Verify Peer: "
     1174                    "Chained Client Certificates are not supported.");
     1175            return HTTP_FORBIDDEN;
     1176        }
     1177
     1178        gnutls_openpgp_crt_init(&cert.pgp);
     1179        rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
     1180                GNUTLS_OPENPGP_FMT_RAW);
     1181
     1182    } else
     1183        return HTTP_FORBIDDEN;
     1184
     1185    if (rv < 0) {
     1186        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1187                "GnuTLS: Failed to Verify Peer: "
     1188                "Failed to import peer certificates.");
     1189        ret = HTTP_FORBIDDEN;
     1190        goto exit;
     1191    }
     1192
     1193    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1194        apr_time_ansi_put(&expiration_time,
     1195                gnutls_x509_crt_get_expiration_time
     1196                (cert.x509[0]));
     1197
     1198        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1199                      "GnuTLS: Verifying list of %d certificate(s) via method '%s'",
     1200                      ch_size, mgs_readable_cvm(ctxt->sc->client_verify_method));
     1201        switch(ctxt->sc->client_verify_method) {
     1202        case mgs_cvm_cartel:
     1203            rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
     1204                                             ctxt->sc->ca_list,
     1205                                             ctxt->sc->ca_list_size,
     1206                                             NULL, 0, 0, &status);
     1207            break;
     1208#ifdef ENABLE_MSVA
     1209        case mgs_cvm_msva:
     1210        {
     1211            struct msv_response* resp = NULL;
     1212            struct msv_query q = { .context="https", .peertype="client", .pkctype="x509pem" };
     1213            msv_ctxt_t ctx = msv_ctxt_init(NULL);
     1214            char cert_pem_buf[10 * 1024];
     1215            size_t len = sizeof (cert_pem_buf);
     1216
     1217            rv = 0;
     1218            if (gnutls_x509_crt_export(cert.x509[0], GNUTLS_X509_FMT_PEM, cert_pem_buf, &len) >= 0) {
     1219                /* FIXME : put together a name from the cert we received, instead of hard-coding this value: */
     1220                q.peername = mgs_x509_construct_uid(r, cert.x509[0]);
     1221                q.pkcdata = cert_pem_buf;
     1222                rv = msv_query_agent(ctx, q, &resp);
     1223                if (rv == LIBMSV_ERROR_SUCCESS) {
     1224                    status = 0;
     1225                } else if (rv == LIBMSV_ERROR_INVALID) {
     1226                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1227                                  "GnuTLS: Monkeysphere validation failed: (message: %s)", resp->message);
     1228                    status = GNUTLS_CERT_INVALID;
     1229                } else {
     1230                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1231                                  "GnuTLS: Error communicating with the Monkeysphere Validation Agent: (%d) %s", rv, msv_strerror(ctx, rv));
     1232                    status = GNUTLS_CERT_INVALID;
     1233                    rv = -1;
     1234                }
     1235            } else {
     1236                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1237                              "GnuTLS: Could not convert the client certificate to PEM format");
     1238                status = GNUTLS_CERT_INVALID;
     1239                rv = GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
     1240            }
     1241            msv_response_destroy(resp);
     1242            msv_ctxt_destroy(ctx);
     1243        }
     1244            break;
     1245#endif
     1246        default:
     1247            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1248                          "GnuTLS: Failed to Verify X.509 Peer: method '%s' is not supported",
     1249                          mgs_readable_cvm(ctxt->sc->client_verify_method));
     1250        }
     1251
     1252    } else {
     1253        apr_time_ansi_put(&expiration_time,
     1254                gnutls_openpgp_crt_get_expiration_time
     1255                (cert.pgp));
     1256
     1257        switch(ctxt->sc->client_verify_method) {
     1258        case mgs_cvm_cartel:
     1259            rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
     1260                                                ctxt->sc->pgp_list, 0,
     1261                                                &status);
     1262            break;
     1263#ifdef ENABLE_MSVA
     1264        case mgs_cvm_msva:
     1265            /* need to set status and rv */
     1266            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1267                          "GnuTLS:  OpenPGP verification via MSVA is not yet implemented");
     1268            rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
     1269            break;
     1270#endif
     1271        default:
     1272            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1273                          "GnuTLS: Failed to Verify OpenPGP Peer: method '%s' is not supported",
     1274                          mgs_readable_cvm(ctxt->sc->client_verify_method));
     1275        }
     1276    }
     1277
     1278    if (rv < 0) {
     1279        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1280                "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
     1281                rv, gnutls_strerror(rv));
     1282        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
     1283            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
     1284                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
     1285        ret = HTTP_FORBIDDEN;
     1286        goto exit;
     1287    }
     1288
     1289    /* TODO: X509 CRL Verification. */
     1290    /* May add later if anyone needs it.
     1291     */
     1292    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
     1293
     1294    cur_time = apr_time_now();
     1295
     1296    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
     1297        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1298                "GnuTLS: Could not find Signer for Peer Certificate");
     1299    }
     1300
     1301    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
     1302        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1303                "GnuTLS: Peer's Certificate signer is not a CA");
     1304    }
     1305
     1306    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
     1307        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1308                "GnuTLS: Peer's Certificate is using insecure algorithms");
     1309    }
     1310
     1311    if (status & GNUTLS_CERT_EXPIRED
     1312            || status & GNUTLS_CERT_NOT_ACTIVATED) {
     1313        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1314                "GnuTLS: Peer's Certificate signer is expired or not yet activated");
     1315    }
     1316
     1317    if (status & GNUTLS_CERT_INVALID) {
     1318        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1319                "GnuTLS: Peer Certificate is invalid.");
     1320    } else if (status & GNUTLS_CERT_REVOKED) {
     1321        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1322                "GnuTLS: Peer Certificate is revoked.");
     1323    }
     1324
     1325    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
     1326        mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_enabled);
     1327    else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP)
     1328        mgs_add_common_pgpcert_vars(r, cert.pgp, 1, ctxt->sc->export_certificates_enabled);
     1329
     1330    {
     1331        /* days remaining */
     1332        unsigned long remain =
     1333                (apr_time_sec(expiration_time) -
     1334                apr_time_sec(cur_time)) / 86400;
     1335        apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
     1336                apr_psprintf(r->pool, "%lu", remain));
     1337    }
     1338
     1339    if (status == 0) {
     1340        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
     1341                "SUCCESS");
     1342        ret = OK;
     1343    } else {
     1344        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
     1345                "FAILED");
     1346        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1347            ret = OK;
     1348        else
     1349            ret = HTTP_FORBIDDEN;
     1350    }
     1351
     1352exit:
     1353    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1354        int i;
     1355        for (i = 0; i < ch_size; i++) {
     1356            gnutls_x509_crt_deinit(cert.x509[i]);
     1357        }
     1358    } else if (gnutls_certificate_type_get(ctxt->session) ==
     1359            GNUTLS_CRT_OPENPGP)
     1360        gnutls_openpgp_crt_deinit(cert.pgp);
     1361    return ret;
     1362
     1363
     1364}
     1365
     1366static const char* mgs_x509_leaf_oid_from_dn(apr_pool_t *pool, const char* oid, gnutls_x509_crt_t cert) {
     1367    int rv=GNUTLS_E_SUCCESS, i;
     1368    size_t sz=0, lastsz=0;
     1369    char* data=NULL;
     1370
     1371    i = -1;
     1372    while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
     1373        i++;
     1374        lastsz=sz;
     1375        sz=0;
     1376        rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i, 0, NULL, &sz);
     1377    }
     1378    if (i > 0) {
     1379        data = apr_palloc(pool, lastsz);
     1380        sz=lastsz;
     1381        rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i-1, 0, data, &sz);
     1382        if (rv == GNUTLS_E_SUCCESS)
     1383            return data;
     1384    }
     1385    return NULL;
     1386}
     1387
     1388static const char* mgs_x509_first_type_from_san(apr_pool_t *pool, gnutls_x509_subject_alt_name_t target, gnutls_x509_crt_t cert) {
     1389    int rv=GNUTLS_E_SUCCESS;
     1390    size_t sz;
     1391    char* data=NULL;
     1392    unsigned int i;
     1393    gnutls_x509_subject_alt_name_t thistype;
     1394
     1395    i = 0;
     1396    while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
     1397        sz = 0;
     1398        rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, NULL, &sz, &thistype, NULL);
     1399        if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && thistype == target) {
     1400            data = apr_palloc(pool, sz);
     1401            rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, data, &sz, &thistype, NULL);
     1402            if (rv == target)
     1403                return data;
     1404        }
     1405        i++;
     1406    }
     1407    return NULL;
     1408}
     1409
     1410/* Create a string representing a candidate User ID from an X.509
     1411 * certificate
     1412
     1413 * We need this for client certification because a client gives us a
     1414 * certificate, but doesn't tell us (in any other way) who they are
     1415 * trying to authenticate as.
     1416
     1417 * TODO: we might need another parallel for OpenPGP, but for that it's
     1418 * much simpler: we can just assume that the first User ID marked as
     1419 * "primary" (or the first User ID, period) is the identity the user
     1420 * is trying to present as.
     1421
     1422 * one complaint might be "but the user wanted to be another identity,
     1423 * which is also in the certificate (e.g. in a SubjectAltName)"
     1424 * However, given that any user can regenerate their own X.509
     1425 * certificate with their own public key content, they should just do
     1426 * so, and not expect us to guess at their identity :)
     1427
     1428 * This function allocates it's response from the pool given it.  When
     1429 * that pool is reclaimed, the response will also be deallocated.
     1430
     1431 * FIXME: what about extracting a server-style cert
     1432 *        (e.g. https://imposter.example) from the DN or any sAN?
     1433
     1434 * FIXME: what if we want to call this outside the context of a
     1435 *        request?  That complicates the logging.
     1436 */
     1437static const char* mgs_x509_construct_uid(request_rec *r, gnutls_x509_crt_t cert) {
     1438    /* basic strategy, assuming humans are the users: we are going to
     1439     * try to reconstruct a "conventional" User ID by pulling in a
     1440     * name, comment, and e-mail address.
     1441     */
     1442    apr_pool_t *pool = r->pool;
     1443    const char *name=NULL, *comment=NULL, *email=NULL;
     1444    const char *ret=NULL;
     1445    /* subpool for temporary allocation: */
     1446    apr_pool_t *sp=NULL;
     1447
     1448    if (APR_SUCCESS != apr_pool_create(&sp, pool))
     1449        return NULL; /* i'm assuming that libapr would log this kind
     1450                      * of error on its own */
     1451
     1452     /* Name
     1453
     1454     the name comes from the leaf commonName of the cert's Subject.
     1455
     1456     (MAYBE: should we look at trying to assemble a candidate from
     1457             givenName, surName, suffix, etc?  the "name" field
     1458             appears to be case-insensitive, which seems problematic
     1459             from what we expect; see:
     1460             http://www.itu.int/rec/T-REC-X.520-200102-s/e )
     1461
     1462     (MAYBE: should we try pulling a commonName or otherName or
     1463             something from subjectAltName? see:
     1464             https://tools.ietf.org/html/rfc5280#section-4.2.1.6
     1465             GnuTLS does not support looking for Common Names in the
     1466             SAN yet)
     1467     */
     1468    name = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_COMMON_NAME, cert);
     1469
     1470    /* Comment
     1471
     1472       I am inclined to punt on this for now, as Comment has been so
     1473       atrociously misused in OpenPGP.  Perhaps if there is a
     1474       pseudonym (OID 2.5.4.65, aka GNUTLS_OID_X520_PSEUDONYM) field
     1475       in the subject or sAN?
     1476    */
     1477    comment = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_PSEUDONYM, cert);
     1478
     1479    /* E-mail
     1480
     1481       This should be the the first rfc822Name from the sAN.
     1482
     1483       failing that, we'll take the leaf email in the certificate's
     1484       subject; this is a deprecated use though.
     1485     */
     1486    email = mgs_x509_first_type_from_san(sp, GNUTLS_SAN_RFC822NAME, cert);
     1487    if (email == NULL)
     1488        email = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_PKCS9_EMAIL, cert);
     1489
     1490    /* assemble all the parts: */
     1491
     1492    /* must have at least a name or an e-mail. */
     1493    if (name == NULL && email == NULL) {
     1494        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1495                "GnuTLS: Need either a name or an e-mail address to get a User ID from an X.509 certificate.");
     1496        goto end;
     1497    }
     1498    if (name) {
     1499        if (comment) {
     1500            if (email) {
     1501                ret = apr_psprintf(pool, "%s (%s) <%s>", name, comment, email);
     1502            } else {
     1503                ret = apr_psprintf(pool, "%s (%s)", name, comment);
     1504            }
     1505        } else {
     1506            if (email) {
     1507                ret = apr_psprintf(pool, "%s <%s>", name, email);
     1508            } else {
     1509                ret = apr_pstrdup(pool, name);
     1510            }
     1511        }
     1512    } else {
     1513        if (comment) {
     1514            ret = apr_psprintf(pool, "(%s) <%s>", comment, email);
     1515        } else {
     1516            ret = apr_psprintf(pool, "<%s>", email);
     1517        }
     1518    }
     1519
     1520end:
     1521    apr_pool_destroy(sp);
     1522    return ret;
     1523}
     1524
     1525static int mgs_status_hook(request_rec *r, int flags)
    9341526{
    935         unsigned char sbuf[64]; /* buffer to hold serials */
    936         char buf[AP_IOBUFSIZE];
    937         const char *tmp;
    938         char *tmp2;
    939         size_t len;
    940         int ret, i;
    941 
    942         if (r == NULL)
    943                 return;
    944 
    945         apr_table_t *env = r->subprocess_env;
    946 
    947         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    948         if (export_certificates_enabled != 0) {
    949                 char cert_buf[10 * 1024];
    950                 len = sizeof(cert_buf);
    951 
    952                 if (gnutls_x509_crt_export
    953                     (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
    954                         apr_table_setn(env,
    955                                        apr_pstrcat(r->pool, MGS_SIDE,
    956                                                    "_CERT", NULL),
    957                                        apr_pstrmemdup(r->pool, cert_buf,
    958                                                       len));
    959 
    960         }
    961 
    962         len = sizeof(buf);
    963         gnutls_x509_crt_get_dn(cert, buf, &len);
    964         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
    965                        apr_pstrmemdup(r->pool, buf, len));
    966 
    967         len = sizeof(buf);
    968         gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
    969         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
    970                        apr_pstrmemdup(r->pool, buf, len));
    971 
    972         len = sizeof(sbuf);
    973         gnutls_x509_crt_get_serial(cert, sbuf, &len);
    974         tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
    975         apr_table_setn(env,
    976                        apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
    977                        apr_pstrdup(r->pool, tmp));
    978 
    979         ret = gnutls_x509_crt_get_version(cert);
    980         if (ret > 0)
    981                 apr_table_setn(env,
    982                                apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
    983                                            NULL), apr_psprintf(r->pool,
    984                                                                "%u", ret));
    985 
    986         apr_table_setn(env,
    987                        apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
    988                        "X.509");
    989 
    990         tmp =
    991             mgs_time2sz(gnutls_x509_crt_get_expiration_time
    992                         (cert), buf, sizeof(buf));
    993         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    994                        apr_pstrdup(r->pool, tmp));
    995 
    996         tmp =
    997             mgs_time2sz(gnutls_x509_crt_get_activation_time
    998                         (cert), buf, sizeof(buf));
    999         apr_table_setn(env,
    1000                        apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
    1001                        apr_pstrdup(r->pool, tmp));
    1002 
    1003         ret = gnutls_x509_crt_get_signature_algorithm(cert);
    1004         if (ret >= 0) {
    1005                 apr_table_setn(env,
    1006                                apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
    1007                                            NULL),
    1008                                gnutls_sign_algorithm_get_name(ret));
    1009         }
    1010 
    1011         ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
    1012         if (ret >= 0) {
    1013                 apr_table_setn(env,
    1014                                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    1015                                            NULL),
    1016                                gnutls_pk_algorithm_get_name(ret));
    1017         }
    1018 
    1019         /* export all the alternative names (DNS, RFC822 and URI) */
    1020         for (i = 0; !(ret < 0); i++) {
    1021                 len = 0;
    1022                 ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
    1023                                                            NULL, &len,
    1024                                                            NULL);
    1025 
    1026                 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
    1027                         tmp2 = apr_palloc(r->pool, len + 1);
    1028 
    1029                         ret =
    1030                             gnutls_x509_crt_get_subject_alt_name(cert, i,
    1031                                                                  tmp2,
    1032                                                                  &len,
    1033                                                                  NULL);
    1034                         tmp2[len] = 0;
    1035 
    1036                         if (ret == GNUTLS_SAN_DNSNAME) {
    1037                                 apr_table_setn(env,
    1038                                                apr_psprintf(r->pool,
    1039                                                             "%s_S_AN%u",
    1040                                                             MGS_SIDE, i),
    1041                                                apr_psprintf(r->pool,
    1042                                                             "DNSNAME:%s",
    1043                                                             tmp2));
    1044                         } else if (ret == GNUTLS_SAN_RFC822NAME) {
    1045                                 apr_table_setn(env,
    1046                                                apr_psprintf(r->pool,
    1047                                                             "%s_S_AN%u",
    1048                                                             MGS_SIDE, i),
    1049                                                apr_psprintf(r->pool,
    1050                                                             "RFC822NAME:%s",
    1051                                                             tmp2));
    1052                         } else if (ret == GNUTLS_SAN_URI) {
    1053                                 apr_table_setn(env,
    1054                                                apr_psprintf(r->pool,
    1055                                                             "%s_S_AN%u",
    1056                                                             MGS_SIDE, i),
    1057                                                apr_psprintf(r->pool,
    1058                                                             "URI:%s",
    1059                                                             tmp2));
    1060                         } else {
    1061                                 apr_table_setn(env,
    1062                                                apr_psprintf(r->pool,
    1063                                                             "%s_S_AN%u",
    1064                                                             MGS_SIDE, i),
    1065                                                "UNSUPPORTED");
    1066                         }
    1067                 }
    1068         }
    1069 }
    1070 
    1071 static void
    1072 mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
    1073                             int side, int export_certificates_enabled)
    1074 {
    1075         unsigned char sbuf[64]; /* buffer to hold serials */
    1076         char buf[AP_IOBUFSIZE];
    1077         const char *tmp;
    1078         size_t len;
    1079         int ret;
    1080 
    1081         if (r == NULL)
    1082                 return;
    1083 
    1084         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1085         apr_table_t *env = r->subprocess_env;
    1086 
    1087         if (export_certificates_enabled != 0) {
    1088                 char cert_buf[10 * 1024];
    1089                 len = sizeof(cert_buf);
    1090 
    1091                 if (gnutls_openpgp_crt_export
    1092                     (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
    1093                         apr_table_setn(env,
    1094                                        apr_pstrcat(r->pool, MGS_SIDE,
    1095                                                    "_CERT", NULL),
    1096                                        apr_pstrmemdup(r->pool, cert_buf,
    1097                                                       len));
    1098 
    1099         }
    1100 
    1101         len = sizeof(buf);
    1102         gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
    1103         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
    1104                        apr_pstrmemdup(r->pool, buf, len));
    1105 
    1106         len = sizeof(sbuf);
    1107         gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
    1108         tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
    1109         apr_table_setn(env,
    1110                        apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
    1111                                    NULL), apr_pstrdup(r->pool, tmp));
    1112 
    1113         ret = gnutls_openpgp_crt_get_version(cert);
    1114         if (ret > 0)
    1115                 apr_table_setn(env,
    1116                                apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
    1117                                            NULL), apr_psprintf(r->pool,
    1118                                                                "%u", ret));
    1119 
    1120         apr_table_setn(env,
    1121                        apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
    1122                        "OPENPGP");
    1123 
    1124         tmp =
    1125             mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
    1126                         (cert), buf, sizeof(buf));
    1127         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    1128                        apr_pstrdup(r->pool, tmp));
    1129 
    1130         tmp =
    1131             mgs_time2sz(gnutls_openpgp_crt_get_creation_time
    1132                         (cert), buf, sizeof(buf));
    1133         apr_table_setn(env,
    1134                        apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
    1135                        apr_pstrdup(r->pool, tmp));
    1136 
    1137         ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
    1138         if (ret >= 0) {
    1139                 apr_table_setn(env,
    1140                                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    1141                                            NULL),
    1142                                gnutls_pk_algorithm_get_name(ret));
    1143         }
    1144 
    1145 }
    1146 
    1147 /* TODO: Allow client sending a X.509 certificate chain */
    1148 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
    1149 {
    1150         const gnutls_datum_t *cert_list;
    1151         unsigned int cert_list_size, status;
    1152         int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
    1153         unsigned int ch_size = 0;
    1154         union {
    1155                 gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
    1156                 gnutls_openpgp_crt_t pgp;
    1157         } cert;
    1158         apr_time_t expiration_time, cur_time;
    1159 
    1160         if (r == NULL || ctxt == NULL || ctxt->session == NULL)
    1161                 return HTTP_FORBIDDEN;
    1162 
    1163         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1164         cert_list =
    1165             gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
    1166 
    1167         if (cert_list == NULL || cert_list_size == 0) {
    1168                 /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
    1169                  */
    1170                 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
    1171                         return OK;
    1172 
    1173                 /* no certificate provided by the client, but one was required. */
    1174                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1175                               "GnuTLS: Failed to Verify Peer: "
    1176                               "Client did not submit a certificate");
    1177                 return HTTP_FORBIDDEN;
    1178         }
    1179 
    1180         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1181                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1182                               "GnuTLS: A Chain of %d certificate(s) was provided for validation",
    1183                               cert_list_size);
    1184 
    1185                 for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
    1186                         gnutls_x509_crt_init(&cert.x509[ch_size]);
    1187                         rv = gnutls_x509_crt_import(cert.x509[ch_size],
    1188                                                     &cert_list[ch_size],
    1189                                                     GNUTLS_X509_FMT_DER);
    1190                         // When failure to import, leave the loop
    1191                         if (rv != GNUTLS_E_SUCCESS) {
    1192                                 if (ch_size < 1) {
    1193                                         ap_log_rerror(APLOG_MARK,
    1194                                                       APLOG_INFO, 0, r,
    1195                                                       "GnuTLS: Failed to Verify Peer: "
    1196                                                       "Failed to import peer certificates.");
    1197                                         ret = HTTP_FORBIDDEN;
    1198                                         goto exit;
    1199                                 }
    1200                                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1201                                               "GnuTLS: Failed to import some peer certificates. Using %d certificates",
    1202                                               ch_size);
    1203                                 rv = GNUTLS_E_SUCCESS;
    1204                                 break;
    1205                         }
    1206                 }
    1207         } else if (gnutls_certificate_type_get(ctxt->session) ==
    1208                    GNUTLS_CRT_OPENPGP) {
    1209                 if (cert_list_size > 1) {
    1210                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1211                                       "GnuTLS: Failed to Verify Peer: "
    1212                                       "Chained Client Certificates are not supported.");
    1213                         return HTTP_FORBIDDEN;
    1214                 }
    1215 
    1216                 gnutls_openpgp_crt_init(&cert.pgp);
    1217                 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
    1218                                                GNUTLS_OPENPGP_FMT_RAW);
    1219 
    1220         } else
    1221                 return HTTP_FORBIDDEN;
    1222 
    1223         if (rv < 0) {
    1224                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1225                               "GnuTLS: Failed to Verify Peer: "
    1226                               "Failed to import peer certificates.");
    1227                 ret = HTTP_FORBIDDEN;
    1228                 goto exit;
    1229         }
    1230 
    1231         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1232                 apr_time_ansi_put(&expiration_time,
    1233                                   gnutls_x509_crt_get_expiration_time
    1234                                   (cert.x509[0]));
    1235 
    1236                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1237                               "GnuTLS: Verifying list of  %d certificate(s)",
    1238                               ch_size);
    1239                 rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
    1240                                                  ctxt->sc->ca_list,
    1241                                                  ctxt->sc->ca_list_size,
    1242                                                  NULL, 0, 0, &status);
    1243         } else {
    1244                 apr_time_ansi_put(&expiration_time,
    1245                                   gnutls_openpgp_crt_get_expiration_time
    1246                                   (cert.pgp));
    1247 
    1248                 rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
    1249                                                     ctxt->sc->pgp_list, 0,
    1250                                                     &status);
    1251         }
    1252 
    1253         if (rv < 0) {
    1254                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1255                               "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
    1256                               rv, gnutls_strerror(rv));
    1257                 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
    1258                         ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
    1259                                       "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
    1260                 ret = HTTP_FORBIDDEN;
    1261                 goto exit;
    1262         }
    1263 
    1264         /* TODO: X509 CRL Verification. */
    1265         /* May add later if anyone needs it.
    1266          */
    1267         /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
    1268 
    1269         cur_time = apr_time_now();
    1270 
    1271         if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
    1272                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1273                               "GnuTLS: Could not find Signer for Peer Certificate");
    1274         }
    1275 
    1276         if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
    1277                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1278                               "GnuTLS: Peer's Certificate signer is not a CA");
    1279         }
    1280 
    1281         if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
    1282                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1283                               "GnuTLS: Peer's Certificate is using insecure algorithms");
    1284         }
    1285 
    1286         if (status & GNUTLS_CERT_EXPIRED
    1287             || status & GNUTLS_CERT_NOT_ACTIVATED) {
    1288                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1289                               "GnuTLS: Peer's Certificate signer is expired or not yet activated");
    1290         }
    1291 
    1292         if (status & GNUTLS_CERT_INVALID) {
    1293                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1294                               "GnuTLS: Peer Certificate is invalid.");
    1295         } else if (status & GNUTLS_CERT_REVOKED) {
    1296                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1297                               "GnuTLS: Peer Certificate is revoked.");
    1298         }
    1299 
    1300         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    1301                 mgs_add_common_cert_vars(r, cert.x509[0], 1,
    1302                                          ctxt->
    1303                                          sc->export_certificates_enabled);
    1304         else if (gnutls_certificate_type_get(ctxt->session) ==
    1305                  GNUTLS_CRT_OPENPGP)
    1306                 mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
    1307                                             ctxt->
    1308                                             sc->export_certificates_enabled);
    1309 
    1310         {
    1311                 /* days remaining */
    1312                 unsigned long remain =
    1313                     (apr_time_sec(expiration_time) -
    1314                      apr_time_sec(cur_time)) / 86400;
    1315                 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
    1316                                apr_psprintf(r->pool, "%lu", remain));
    1317         }
    1318 
    1319         if (status == 0) {
    1320                 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
    1321                                "SUCCESS");
    1322                 ret = OK;
    1323         } else {
    1324                 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
    1325                                "FAILED");
    1326                 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
    1327                         ret = OK;
    1328                 else
    1329                         ret = HTTP_FORBIDDEN;
    1330         }
    1331 
    1332       exit:
    1333         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1334                 int i;
    1335                 for (i = 0; i < ch_size; i++) {
    1336                         gnutls_x509_crt_deinit(cert.x509[i]);
    1337                 }
    1338         } else if (gnutls_certificate_type_get(ctxt->session) ==
    1339                    GNUTLS_CRT_OPENPGP)
    1340                 gnutls_openpgp_crt_deinit(cert.pgp);
    1341         return ret;
    1342 
    1343 
    1344 }
     1527    mgs_srvconf_rec *sc;
     1528
     1529    if (r == NULL)
     1530        return OK;
     1531
     1532    sc = (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config, &gnutls_module);
     1533
     1534    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1535
     1536    ap_rputs("<hr>\n", r);
     1537    ap_rputs("<h2>GnuTLS Information:</h2>\n<dl>\n", r);
     1538
     1539    ap_rprintf(r, "<dt>GnuTLS version:</dt><dd>%s</dd>\n", gnutls_check_version(NULL));
     1540    ap_rputs("<dt>Built against:</dt><dd>" GNUTLS_VERSION "</dd>\n", r);
     1541    ap_rprintf(r, "<dt>using TLS:</dt><dd>%s</dd>\n", (sc->enabled == GNUTLS_ENABLED_FALSE ? "no" : "yes"));
     1542    if (sc->enabled != GNUTLS_ENABLED_FALSE) {
     1543        mgs_handle_t* ctxt;
     1544        ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
     1545        if (ctxt && ctxt->session != NULL) {
     1546#if GNUTLS_VERSION_MAJOR < 3
     1547            ap_rprintf(r, "<dt>This TLS Session:</dt><dd>%s</dd>\n",
     1548                gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session),
     1549                gnutls_cipher_get(ctxt->session),
     1550                gnutls_mac_get(ctxt->session)));
     1551#else
     1552            char* z = NULL;
     1553            z = gnutls_session_get_desc(ctxt->session);
     1554            if (z) {
     1555                ap_rprintf(r, "<dt>This TLS Session:</dt><dd>%s</dd>\n", z);
     1556                gnutls_free(z);
     1557            }
     1558#endif
     1559        }
     1560    }
     1561
     1562    ap_rputs("</dl>\n", r);
     1563    return OK;
     1564}
     1565
Note: See TracChangeset for help on using the changeset viewer.