Changeset 70c2d86 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Jan 11, 2013, 12:55:20 AM (8 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, upstream
Children:
3f5c713, ec06980
Parents:
3e94bd3
Message:

Imported Upstream version 0.3.4

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r3e94bd3 r70c2d86  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
     3 *  Copyright 2007 Nikos Mavrogiannopoulos
    34 *
    45 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1819#include "mod_gnutls.h"
    1920#include "http_vhost.h"
     21#include "ap_mpm.h"
    2022
    2123#if !USING_2_1_RECENT
     
    2830
    2931#if MOD_GNUTLS_DEBUG
    30 static apr_file_t* debug_log_fp;
    31 #endif
     32static apr_file_t *debug_log_fp;
     33#endif
     34
     35static int mpm_is_threaded;
     36
     37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
     38/* use side==0 for server and side==1 for client */
     39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert,
     40                                     int side, int export_certificates_enabled);
    3241
    3342static apr_status_t mgs_cleanup_pre_config(void *data)
     
    3847
    3948#if MOD_GNUTLS_DEBUG
    40 static void gnutls_debug_log_all( int level, const char* str)
     49static void gnutls_debug_log_all(int level, const char *str)
    4150{
    4251    apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
     
    4453#endif
    4554
    46 int mgs_hook_pre_config(apr_pool_t * pconf,
    47                         apr_pool_t * plog, apr_pool_t * ptemp)
     55int
     56mgs_hook_pre_config(apr_pool_t * pconf,
     57                    apr_pool_t * plog, apr_pool_t * ptemp)
    4858{
    4959
    5060#if APR_HAS_THREADS
    51     /* TODO: Check MPM Type here */
    52     gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
     61    ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
     62    if (mpm_is_threaded) {
     63        gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
     64    }
     65#else
     66    mpm_is_threaded = 0;
    5367#endif
    5468
     
    5670
    5771    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
    58                               apr_pool_cleanup_null);
     72                              apr_pool_cleanup_null);
    5973
    6074#if MOD_GNUTLS_DEBUG
    6175    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
    62                   APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf);
     76                  APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
     77                  pconf);
    6378
    6479    gnutls_global_set_log_level(9);
     
    7085
    7186
    72 static gnutls_datum load_params(const char* file, server_rec* s,
    73                                 apr_pool_t* pool)
     87static gnutls_datum
     88load_params(const char *file, server_rec * s, apr_pool_t * pool)
    7489{
    7590    gnutls_datum ret = { NULL, 0 };
    76     apr_file_t* fp;
     91    apr_file_t *fp;
    7792    apr_finfo_t finfo;
    7893    apr_status_t rv;
    7994    apr_size_t br = 0;
    8095
    81     rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT,
    82                        pool);
     96    rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, APR_OS_DEFAULT,
     97                       pool);
    8398    if (rv != APR_SUCCESS) {
    84         ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    85                      "GnuTLS failed to load params file at: %s", file);
    86         return ret;
     99        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     100                     "GnuTLS failed to load params file at: %s. Will use internal params.", file);
     101        return ret;
    87102    }
    88103
     
    90105
    91106    if (rv != APR_SUCCESS) {
    92         ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    93                      "GnuTLS failed to stat params file at: %s", file);
    94         return ret;
    95     }
    96 
    97     ret.data = apr_palloc(pool, finfo.size+1);
     107        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     108                     "GnuTLS failed to stat params file at: %s", file);
     109        return ret;
     110    }
     111
     112    ret.data = apr_palloc(pool, finfo.size + 1);
    98113    rv = apr_file_read_full(fp, ret.data, finfo.size, &br);
    99114
    100115    if (rv != APR_SUCCESS) {
    101         ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    102                      "GnuTLS failed to read params file at: %s", file);
    103         return ret;
     116        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     117                     "GnuTLS failed to read params file at: %s", file);
     118        return ret;
    104119    }
    105120    apr_file_close(fp);
     
    110125}
    111126
    112 int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
    113                                        apr_pool_t * ptemp,
    114                                        server_rec * base_server)
     127static int mgs_select_virtual_server_cb( gnutls_session_t session)
     128{
     129    mgs_handle_t *ctxt;
     130    mgs_srvconf_rec *tsc;
     131
     132    ctxt = gnutls_transport_get_ptr(session);
     133
     134    /* find the virtual server */
     135    tsc = mgs_find_sni_server(session);
     136
     137    if (tsc != NULL)
     138        ctxt->sc = tsc;
     139
     140    gnutls_certificate_server_set_request(session,
     141       ctxt->sc->client_verify_mode);
     142
     143    /* set the new server credentials
     144     */
     145
     146    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
     147      ctxt->sc->certs);
     148
     149    gnutls_credentials_set(session, GNUTLS_CRD_ANON,
     150      ctxt->sc->anon_creds);
     151
     152    if ( ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
     153       gnutls_credentials_set(session, GNUTLS_CRD_SRP,
     154         ctxt->sc->srp_creds);
     155    }
     156
     157    /* enable the default priorities and override them later on
     158     */
     159    gnutls_set_default_priority( session);
     160
     161    /* update the priorities - to avoid negotiating a ciphersuite that is not
     162     * enabled on this virtual server
     163     */
     164    if (ctxt->sc->ciphers[0] != 0)
     165      gnutls_cipher_set_priority(session, ctxt->sc->ciphers);
     166    if (ctxt->sc->compression[0] != 0)
     167      gnutls_compression_set_priority(session, ctxt->sc->compression);
     168    if (ctxt->sc->key_exchange[0] != 0)
     169      gnutls_kx_set_priority(session, ctxt->sc->key_exchange);
     170    if (ctxt->sc->macs[0] != 0)
     171      gnutls_mac_set_priority(session, ctxt->sc->macs);
     172    if (ctxt->sc->cert_types[0] != 0)
     173      gnutls_certificate_type_set_priority(session, ctxt->sc->cert_types);
     174
     175    /* allow separate caches per virtual host. Actually allowing the same is not
     176     * a good idea, especially if they have different security requirements.
     177     */
     178    mgs_cache_session_init(ctxt);
     179
     180    return 0;
     181}
     182
     183static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
     184{
     185    mgs_handle_t *ctxt;
     186
     187    ctxt = gnutls_transport_get_ptr(session);
     188
     189    ret->type = GNUTLS_CRT_X509;
     190    ret->ncerts = 1;
     191    ret->deinit_all = 0;
     192
     193    ret->cert.x509 = &ctxt->sc->cert_x509;
     194    ret->key.x509 = ctxt->sc->privkey_x509;
     195    return 0;
     196}
     197
     198const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
     199"MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
     200"gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
     201"KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
     202"dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
     203"YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
     204"Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
     205"-----END DH PARAMETERS-----\n";
     206
     207int
     208mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
     209                     apr_pool_t * ptemp, server_rec * base_server)
    115210{
    116211    int rv;
    117     int data_len;
     212    size_t data_len;
    118213    server_rec *s;
    119214    gnutls_dh_params_t dh_params;
     
    124219    int first_run = 0;
    125220    const char *userdata_key = "mgs_init";
    126          
     221
    127222    apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
    128223    if (data == NULL) {
    129         first_run = 1;
    130         apr_pool_userdata_set((const void *)1, userdata_key,
    131                               apr_pool_cleanup_null,
    132                               base_server->process->pool);
     224        first_run = 1;
     225        apr_pool_userdata_set((const void *) 1, userdata_key,
     226                              apr_pool_cleanup_null,
     227                              base_server->process->pool);
    133228    }
    134229
    135230
    136231    {
    137         gnutls_datum pdata;
    138         apr_pool_t* tpool;
    139         s = base_server;
    140         sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    141                                                              &gnutls_module);
    142 
    143         apr_pool_create(&tpool, p);
    144 
    145         gnutls_dh_params_init(&dh_params);
    146 
    147         pdata = load_params(sc_base->dh_params_file, s, tpool);
    148 
    149         if (pdata.size != 0) {
    150             rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
    151                                                GNUTLS_X509_FMT_PEM);
    152             if (rv != 0) {
    153                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    154                              "GnuTLS: Unable to load DH Params: (%d) %s",
    155                              rv, gnutls_strerror(rv));
    156                 exit(rv);
     232        gnutls_datum pdata;
     233        apr_pool_t *tpool;
     234        s = base_server;
     235        sc_base =
     236            (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     237                                                     &gnutls_module);
     238
     239        apr_pool_create(&tpool, p);
     240
     241        gnutls_dh_params_init(&dh_params);
     242
     243        pdata = load_params(sc_base->dh_params_file, s, tpool);
     244
     245        if (pdata.size != 0) {
     246            rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
     247                                               GNUTLS_X509_FMT_PEM);
     248            if (rv != 0) {
     249                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     250                             "GnuTLS: Unable to load DH Params: (%d) %s",
     251                             rv, gnutls_strerror(rv));
     252                exit(rv);
     253            }
     254        } else {
     255            /* If the file does not exist use internal parameters
     256             */
     257            pdata.data = (void*)static_dh_params;
     258            pdata.size = sizeof( static_dh_params);
     259            rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
     260                                               GNUTLS_X509_FMT_PEM);
     261
     262            if (rv < 0) {
     263              ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     264                         "GnuTLS: Unable to load internal DH Params."
     265                         " Shutting down.");
     266              exit(-1);
    157267            }
    158         }
    159         else {
    160             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    161                          "GnuTLS: Unable to load DH Params."
    162                          " Shutting Down.");
    163             exit(-1);
    164         }
    165         apr_pool_clear(tpool);
    166 
    167         gnutls_rsa_params_init(&rsa_params);
    168 
    169         pdata = load_params(sc_base->rsa_params_file, s, tpool);
    170 
    171         if (pdata.size != 0) {
    172             rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata,
    173                                                 GNUTLS_X509_FMT_PEM);
    174             if (rv != 0) {
    175                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    176                              "GnuTLS: Unable to load RSA Params: (%d) %s",
    177                              rv, gnutls_strerror(rv));
    178                 exit(rv);
    179             }
    180         }
    181         else {
    182             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    183                          "GnuTLS: Unable to load RSA Params."
    184                          " Shutting Down.");
    185             exit(-1);
    186         }
    187 
    188         apr_pool_destroy(tpool);
    189         rv = mgs_cache_post_config(p, s, sc_base);
    190         if (rv != 0) {
    191             ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    192                          "GnuTLS: Post Config for GnuTLSCache Failed."
    193                          " Shutting Down.");
    194             exit(-1);
    195         }
    196          
    197         for (s = base_server; s; s = s->next) {
    198             sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    199                                                                  &gnutls_module);
    200             sc->cache_type = sc_base->cache_type;
    201             sc->cache_config = sc_base->cache_config;
    202 
    203             gnutls_certificate_set_rsa_export_params(sc->certs,
    204                                                      rsa_params);
    205             gnutls_certificate_set_dh_params(sc->certs, dh_params);
    206 
    207             if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    208                 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
    209                              "[GnuTLS] - Host '%s:%d' is missing a "
    210                              "Certificate File!",
    211                          s->server_hostname, s->port);
    212                 exit(-1);
     268        }
     269        apr_pool_clear(tpool);
     270
     271        rsa_params = NULL;
     272       
     273        pdata = load_params(sc_base->rsa_params_file, s, tpool);
     274
     275        if (pdata.size != 0) {
     276            gnutls_rsa_params_init(&rsa_params);
     277            rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata,
     278                                                GNUTLS_X509_FMT_PEM);
     279            if (rv != 0) {
     280                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     281                             "GnuTLS: Unable to load RSA Params: (%d) %s",
     282                             rv, gnutls_strerror(rv));
     283                exit(rv);
     284            }
     285        }
     286        /* not an error but RSA-EXPORT ciphersuites are not available
     287         */
     288
     289        apr_pool_destroy(tpool);
     290        rv = mgs_cache_post_config(p, s, sc_base);
     291        if (rv != 0) {
     292            ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     293                         "GnuTLS: Post Config for GnuTLSCache Failed."
     294                         " Shutting Down.");
     295            exit(-1);
     296        }
     297
     298        for (s = base_server; s; s = s->next) {
     299            sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     300                                                          &gnutls_module);
     301            sc->cache_type = sc_base->cache_type;
     302            sc->cache_config = sc_base->cache_config;
     303
     304            if (rsa_params != NULL)
     305              gnutls_certificate_set_rsa_export_params(sc->certs,
     306                                                     rsa_params);
     307            gnutls_certificate_set_dh_params(sc->certs, dh_params);
     308
     309            gnutls_anon_set_server_dh_params( sc->anon_creds, dh_params);
     310           
     311            gnutls_certificate_server_set_retrieve_function(sc->certs,
     312                                                    cert_retrieve_fn);
     313
     314            if ( sc->srp_tpasswd_conf_file != NULL && sc->srp_tpasswd_file != NULL) {
     315                gnutls_srp_set_server_credentials_file( sc->srp_creds,
     316                    sc->srp_tpasswd_file, sc->srp_tpasswd_conf_file);
    213317            }
    214318           
    215             if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    216                 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
    217                              "[GnuTLS] - Host '%s:%d' is missing a "
    218                              "Private Key File!",
    219                              s->server_hostname, s->port);
    220                 exit(-1);
     319            if (sc->cert_x509 == NULL
     320                && sc->enabled == GNUTLS_ENABLED_TRUE) {
     321                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
     322                             "[GnuTLS] - Host '%s:%d' is missing a "
     323                             "Certificate File!", s->server_hostname,
     324                             s->port);
     325                exit(-1);
     326            }
     327
     328            if (sc->privkey_x509 == NULL
     329                && sc->enabled == GNUTLS_ENABLED_TRUE) {
     330                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
     331                             "[GnuTLS] - Host '%s:%d' is missing a "
     332                             "Private Key File!",
     333                             s->server_hostname, s->port);
     334                exit(-1);
     335            }
     336
     337            if (sc->enabled == GNUTLS_ENABLED_TRUE) {
     338            rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
     339                                               GNUTLS_OID_X520_COMMON_NAME,
     340                                               0, 0, NULL, &data_len);
     341
     342            if (data_len < 1) {
     343                sc->enabled = GNUTLS_ENABLED_FALSE;
     344                sc->cert_cn = NULL;
     345                continue;
     346            }
     347
     348            sc->cert_cn = apr_palloc(p, data_len);
     349            rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
     350                                               GNUTLS_OID_X520_COMMON_NAME,
     351                                               0, 0, sc->cert_cn,
     352                                               &data_len);
    221353            }
    222            
    223             rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
    224                                                GNUTLS_OID_X520_COMMON_NAME, 0, 0,
    225                                                NULL, &data_len);
    226            
    227             if (data_len < 1) {
    228                 sc->enabled = GNUTLS_ENABLED_FALSE;
    229                 sc->cert_cn = NULL;
    230                 continue;
    231             }
    232            
    233             sc->cert_cn = apr_palloc(p, data_len);
    234             rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
    235                                                GNUTLS_OID_X520_COMMON_NAME, 0, 0,
    236                                                sc->cert_cn, &data_len);
    237             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    238                          s,
    239                          "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", sc->cert_cn, rv,
    240                          gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)),
    241                          (unsigned int)s, (unsigned int)sc);
    242         }
     354        }
    243355    }
    244356
     
    248360}
    249361
    250 void mgs_hook_child_init(apr_pool_t *p, server_rec *s)
     362void mgs_hook_child_init(apr_pool_t * p, server_rec * s)
    251363{
    252364    apr_status_t rv = APR_SUCCESS;
    253365    mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
    254                                                       &gnutls_module);
     366                                               &gnutls_module);
    255367
    256368    if (sc->cache_type != mgs_cache_none) {
    257         rv = mgs_cache_child_init(p, s, sc);
    258         if(rv != APR_SUCCESS) {
    259             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    260                              "[GnuTLS] - Failed to run Cache Init");
    261         }
    262     }
    263     else {
    264         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
    265                      "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
     369        rv = mgs_cache_child_init(p, s, sc);
     370        if (rv != APR_SUCCESS) {
     371            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     372                         "[GnuTLS] - Failed to run Cache Init");
     373        }
     374    } else {
     375        ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
     376                     "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
    266377    }
    267378}
     
    270381{
    271382    mgs_srvconf_rec *sc =
    272         (mgs_srvconf_rec *) ap_get_module_config(r->server->
    273                                                         module_config,
    274                                                         &gnutls_module);
     383        (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
     384                                                 &gnutls_module);
    275385
    276386    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    277         return NULL;
     387        return NULL;
    278388    }
    279389
     
    284394{
    285395    mgs_srvconf_rec *sc =
    286         (mgs_srvconf_rec *) ap_get_module_config(r->server->
    287                                                         module_config,
    288                                                         &gnutls_module);
     396        (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
     397                                                 &gnutls_module);
    289398
    290399    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    291         return 0;
     400        return 0;
    292401    }
    293402
     
    298407
    299408#if USING_2_1_RECENT
    300 typedef struct
    301 {
     409typedef struct {
    302410    mgs_handle_t *ctxt;
    303411    mgs_srvconf_rec *sc;
    304     const char* sni_name;
     412    const char *sni_name;
    305413} vhost_cb_rec;
    306414
    307 static int vhost_cb (void* baton, conn_rec* conn, server_rec* s)
     415static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
    308416{
    309417    mgs_srvconf_rec *tsc;
    310     vhost_cb_rec* x = baton;
     418    vhost_cb_rec *x = baton;
    311419
    312420    tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    313                                                           &gnutls_module);
    314    
     421                                                   &gnutls_module);
     422
    315423    if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
    316         return 0;
    317     }
    318    
     424        return 0;
     425    }
     426
    319427    /* The CN can contain a * -- this will match those too. */
    320428    if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
    321         /* found a match */
     429        /* found a match */
    322430#if MOD_GNUTLS_DEBUG
    323         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    324                      x->ctxt->c->base_server,
    325                      "GnuTLS: Virtual Host CB: "
    326                      "'%s' == '%s'", tsc->cert_cn, x->sni_name);
    327 #endif
    328         /* Because we actually change the server used here, we need to reset
    329         * things like ClientVerify.
    330         */
    331         x->sc = tsc;
    332         /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
    333         * certificate structure *should* change when the server changes.
    334         * acccckkkkkk.
    335         */
    336         return 1;
     431        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     432                     x->ctxt->c->base_server,
     433                     "GnuTLS: Virtual Host CB: "
     434                     "'%s' == '%s'", tsc->cert_cn, x->sni_name);
     435#endif
     436        /* Because we actually change the server used here, we need to reset
     437        * things like ClientVerify.
     438        */
     439        x->sc = tsc;
     440        /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
     441        * certificate structure *should* change when the server changes.
     442        * acccckkkkkk.
     443        */
     444        return 1;
    337445    }
    338446    return 0;
     
    340448#endif
    341449
    342 mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session)
     450mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
    343451{
    344452    int rv;
    345     int sni_type;
    346     int data_len = MAX_HOST_LEN;
     453    unsigned int sni_type;
     454    size_t data_len = MAX_HOST_LEN;
    347455    char sni_name[MAX_HOST_LEN];
    348456    mgs_handle_t *ctxt;
     
    350458    vhost_cb_rec cbx;
    351459#else
    352     server_rec* s;
    353     mgs_srvconf_rec *tsc;   
    354 #endif
    355    
     460    server_rec *s;
     461    mgs_srvconf_rec *tsc;
     462#endif
     463
    356464    ctxt = gnutls_transport_get_ptr(session);
    357    
     465
    358466    sni_type = gnutls_certificate_type_get(session);
    359467    if (sni_type != GNUTLS_CRT_X509) {
    360         /* In theory, we could support OpenPGP Certificates. Theory != code. */
    361         ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
    362                      ctxt->c->base_server,
    363                      "GnuTLS: Only x509 Certificates are currently supported.");
    364         return NULL;
    365     }
    366    
    367     rv = gnutls_server_name_get(ctxt->session, sni_name, 
    368                                 &data_len, &sni_type, 0);
    369    
     468        /* In theory, we could support OpenPGP Certificates. Theory != code. */
     469        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     470                     ctxt->c->base_server,
     471                     "GnuTLS: Only x509 Certificates are currently supported.");
     472        return NULL;
     473    }
     474
     475    rv = gnutls_server_name_get(ctxt->session, sni_name,
     476                                &data_len, &sni_type, 0);
     477
    370478    if (rv != 0) {
    371         return NULL;
    372     }
    373    
     479        return NULL;
     480    }
     481
    374482    if (sni_type != GNUTLS_NAME_DNS) {
    375         ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
    376                      ctxt->c->base_server,
    377                      "GnuTLS: Unknown type '%d' for SNI: "
    378                      "'%s'", sni_type, sni_name);
    379         return NULL;
    380     }
    381    
     483        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     484                     ctxt->c->base_server,
     485                     "GnuTLS: Unknown type '%d' for SNI: "
     486                     "'%s'", sni_type, sni_name);
     487        return NULL;
     488    }
     489
    382490    /**
    383491     * Code in the Core already sets up the c->base_server as the base
     
    388496    cbx.sc = NULL;
    389497    cbx.sni_name = sni_name;
    390    
     498
    391499    rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    392500    if (rv == 1) {
    393         return cbx.sc;
     501        return cbx.sc;
    394502    }
    395503#else
    396504    for (s = ap_server_conf; s; s = s->next) {
    397        
    398         tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    399                                                        &gnutls_module);
    400         if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
    401             continue;
    402         }
     505
     506        tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     507                                                       &gnutls_module);
     508        if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
     509            continue;
     510        }
    403511#if MOD_GNUTLS_DEBUG
    404         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    405                      ctxt->c->base_server,
    406                      "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X", tsc->cert_cn, rv,
    407                      gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)),
    408                      (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc);
    409 #endif           
    410         /* The CN can contain a * -- this will match those too. */
    411         if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
     512        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     513                     ctxt->c->base_server,
     514                     "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
     515                     tsc->cert_cn, rv,
     516                     gnutls_pk_algorithm_get_name
     517                     (gnutls_x509_privkey_get_pk_algorithm
     518                      (ctxt->sc->privkey_x509)), (unsigned int) s,
     519                     (unsigned int) s->next, (unsigned int) tsc);
     520#endif
     521        /* The CN can contain a * -- this will match those too. */
     522        if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
    412523#if MOD_GNUTLS_DEBUG
    413             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    414                         ctxt->c->base_server,
    415                         "GnuTLS: Virtual Host: "
    416                         "'%s' == '%s'", tsc->cert_cn, sni_name);
    417 #endif
    418             return tsc;
    419         }
     524            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     525                        ctxt->c->base_server,
     526                        "GnuTLS: Virtual Host: "
     527                        "'%s' == '%s'", tsc->cert_cn, sni_name);
     528#endif
     529            return tsc;
     530        }
    420531    }
    421532#endif
     
    424535
    425536
    426 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret)
    427 {
    428     mgs_handle_t *ctxt;
    429     mgs_srvconf_rec *tsc;
    430    
    431     ctxt = gnutls_transport_get_ptr(session);
    432 
    433     ret->type = GNUTLS_CRT_X509;
    434     ret->ncerts = 1;
    435     ret->deinit_all = 0;
    436 
    437     tsc = mgs_find_sni_server(session);
    438    
    439     if (tsc != NULL) {
    440         ctxt->sc = tsc;
    441         gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
    442     }
    443    
    444     ret->cert.x509 = &ctxt->sc->cert_x509;
    445     ret->key.x509 = ctxt->sc->privkey_x509;
    446     return 0;
    447 }
    448 
    449 static mgs_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
     537
     538
     539static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
    450540{
    451541    mgs_handle_t *ctxt;
    452542    mgs_srvconf_rec *sc =
    453         (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
    454                                                         module_config,
    455                                                         &gnutls_module);
     543        (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
     544                                                module_config,
     545                                                &gnutls_module);
    456546
    457547    ctxt = apr_pcalloc(pool, sizeof(*ctxt));
     
    470560
    471561    gnutls_init(&ctxt->session, GNUTLS_SERVER);
     562   
     563    /* This is not very good as it trades security for compatibility,
     564     * but it is the only way to be ultra-portable.
     565     */
     566    gnutls_session_enable_compatibility_mode( ctxt->session);
    472567
    473568    gnutls_protocol_set_priority(ctxt->session, sc->protocol);
    474     gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
    475     gnutls_compression_set_priority(ctxt->session, sc->compression);
    476     gnutls_kx_set_priority(ctxt->session, sc->key_exchange);
    477     gnutls_mac_set_priority(ctxt->session, sc->macs);
    478     gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types);
    479 
    480     mgs_cache_session_init(ctxt);
    481    
    482     gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    483 
    484     gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn);
    485     gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
     569
     570    gnutls_handshake_set_post_client_hello_function( ctxt->session, mgs_select_virtual_server_cb);
     571
    486572    return ctxt;
    487573}
     
    491577    mgs_handle_t *ctxt;
    492578    mgs_srvconf_rec *sc =
    493         (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
    494                                                         module_config,
    495                                                         &gnutls_module);
     579        (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
     580                                                module_config,
     581                                                &gnutls_module);
    496582
    497583    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
    498         return DECLINED;
     584        return DECLINED;
    499585    }
    500586
     
    503589    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
    504590
    505     gnutls_transport_set_pull_function(ctxt->session,
    506                                        mgs_transport_read);
    507     gnutls_transport_set_push_function(ctxt->session,
    508                                        mgs_transport_write);
     591    gnutls_transport_set_pull_function(ctxt->session, mgs_transport_read);
     592    gnutls_transport_set_push_function(ctxt->session, mgs_transport_write);
    509593    gnutls_transport_set_ptr(ctxt->session, ctxt);
    510    
    511     ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt,
    512                                             NULL, c);
    513     ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt,
    514                                               NULL, c);
     594
     595    ctxt->input_filter =
     596        ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
     597    ctxt->output_filter =
     598        ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
    515599
    516600    return OK;
    517601}
    518602
    519 int mgs_hook_fixups(request_rec *r)
     603int mgs_hook_fixups(request_rec * r)
    520604{
    521605    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
    522606    char buf[AP_IOBUFSIZE];
    523     const char* tmp;
    524     int len;
     607    const char *tmp;
     608    size_t len;
    525609    mgs_handle_t *ctxt;
    526610    int rv = OK;
    527    
     611
    528612    apr_table_t *env = r->subprocess_env;
    529613
    530     ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
    531 
    532     if(!ctxt) {
    533         return DECLINED;
     614    ctxt =
     615        ap_get_module_config(r->connection->conn_config, &gnutls_module);
     616
     617    if (!ctxt) {
     618        return DECLINED;
    534619    }
    535620
    536621    apr_table_setn(env, "HTTPS", "on");
    537622
    538     apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION);
    539     apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION);
     623    apr_table_setn(env, "SSL_VERSION_LIBRARY", "GnuTLS/"LIBGNUTLS_VERSION);
     624    apr_table_setn(env, "SSL_VERSION_INTERFACE", "mod_gnutls/"MOD_GNUTLS_VERSION);
    540625
    541626    apr_table_setn(env, "SSL_PROTOCOL",
    542                    gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
    543 
     627                   gnutls_protocol_get_name(gnutls_protocol_get_version
     628                                            (ctxt->session)));
     629
     630    /* should have been called SSL_CIPHERSUITE instead */                                         
    544631    apr_table_setn(env, "SSL_CIPHER",
    545                    gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session)));
    546 
    547     apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
    548 
    549     tmp = apr_psprintf(r->pool, "%d",
    550               8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)));
     632          gnutls_cipher_suite_get_name(
     633            gnutls_kx_get(ctxt->session), gnutls_cipher_get(ctxt->session),
     634                    gnutls_mac_get(ctxt->session)));
     635
     636    apr_table_setn(env, "SSL_COMPRESS_METHOD",
     637                   gnutls_compression_get_name(gnutls_compression_get
     638                                          (ctxt->session)));
     639
     640    apr_table_setn(env, "SSL_SRP_USER",
     641                   gnutls_srp_server_get_username( ctxt->session));
     642
     643    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
     644        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
     645
     646    unsigned int key_size =
     647        8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
     648    tmp = apr_psprintf(r->pool, "%u", key_size);
    551649
    552650    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
    553651
    554652    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
     653
     654    apr_table_setn(env, "SSL_CIPHER_EXPORT",
     655                   (key_size <= 40) ? "true" : "false");
    555656
    556657    len = sizeof(sbuf);
     
    559660    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
    560661
    561     /* TODO: There are many other env vars that we need to add */
    562     {
    563         len = sizeof(buf);
    564         gnutls_x509_crt_get_dn(ctxt->sc->cert_x509, buf, &len);
    565         apr_table_setn(env, "SSL_SERVER_S_DN", apr_pstrmemdup(r->pool, buf, len));
    566            
    567         len = sizeof(buf);
    568         gnutls_x509_crt_get_issuer_dn(ctxt->sc->cert_x509, buf, &len);
    569         apr_table_setn(env, "SSL_SERVER_I_DN", apr_pstrmemdup(r->pool, buf, len));
    570     }
    571    
     662    mgs_add_common_cert_vars(r, ctxt->sc->cert_x509, 0, ctxt->sc->export_certificates_enabled);
     663
    572664    return rv;
    573665}
    574666
    575 int mgs_hook_authz(request_rec *r)
     667int mgs_hook_authz(request_rec * r)
    576668{
    577669    int rv;
    578     int status;
    579670    mgs_handle_t *ctxt;
    580671    mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
    581                                                       &gnutls_module);
    582    
    583     ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
    584    
     672                                               &gnutls_module);
     673
     674    ctxt =
     675        ap_get_module_config(r->connection->conn_config, &gnutls_module);
     676
    585677    if (!ctxt) {
    586         return DECLINED;
    587     }
    588    
    589     if (!dc) {
    590         dc = mgs_config_dir_create(r->pool, NULL);
     678        return DECLINED;
    591679    }
    592680
    593681    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
    594         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    595                       "GnuTLS: Directory set to Ignore Client Certificate!");
    596         return DECLINED;
    597     }
    598 
    599     if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
    600         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    601                      "GnuTLS: Attempting to rehandshake with peer. %d %d",
    602                       ctxt->sc->client_verify_mode, dc->client_verify_mode);
    603        
    604         gnutls_certificate_server_set_request(ctxt->session,
    605                                               dc->client_verify_mode);
    606    
    607         if (mgs_rehandshake(ctxt) != 0) {
    608             return HTTP_FORBIDDEN;
    609         }
    610     }
    611     else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
     682        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     683                      "GnuTLS: Directory set to Ignore Client Certificate!");
     684    } else {
     685        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
     686            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     687                          "GnuTLS: Attempting to rehandshake with peer. %d %d",
     688                          ctxt->sc->client_verify_mode,
     689                          dc->client_verify_mode);
     690
     691            gnutls_certificate_server_set_request(ctxt->session,
     692                                                  dc->client_verify_mode);
     693
     694            if (mgs_rehandshake(ctxt) != 0) {
     695                return HTTP_FORBIDDEN;
     696            }
     697        } else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
    612698#if MOD_GNUTLS_DEBUG
    613         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    614                       "GnuTLS: Peer is set to IGNORE");
    615 #endif
    616         return DECLINED;
    617     }
    618    
    619     rv = gnutls_certificate_verify_peers2(ctxt->session, &status);
    620 
     699            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     700                          "GnuTLS: Peer is set to IGNORE");
     701#endif
     702        } else {
     703            rv = mgs_cert_verify(r, ctxt);
     704            if (rv != DECLINED) {
     705                return rv;
     706            }
     707        }
     708    }
     709
     710    return DECLINED;
     711}
     712
     713/* variables that are not sent by default:
     714 *
     715 * SSL_CLIENT_CERT      string  PEM-encoded client certificate
     716 * SSL_SERVER_CERT      string  PEM-encoded client certificate
     717 */
     718
     719/* side is either 0 for SERVER or 1 for CLIENT
     720 */
     721#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
     722static void
     723mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, int export_certificates_enabled)
     724{
     725    unsigned char sbuf[64];     /* buffer to hold serials */
     726    char buf[AP_IOBUFSIZE];
     727    const char *tmp;
     728    size_t len;
     729    int alg;
     730
     731    apr_table_t *env = r->subprocess_env;
     732
     733    if (export_certificates_enabled != 0) {
     734      char cert_buf[10*1024];
     735      len = sizeof(cert_buf);
     736
     737      if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
     738        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
     739                   apr_pstrmemdup(r->pool, cert_buf, len));
     740     
     741    }
     742
     743    len = sizeof(buf);
     744    gnutls_x509_crt_get_dn(cert, buf, &len);
     745    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
     746                   apr_pstrmemdup(r->pool, buf, len));
     747
     748    len = sizeof(buf);
     749    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
     750    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
     751                   apr_pstrmemdup(r->pool, buf, len));
     752
     753    len = sizeof(sbuf);
     754    gnutls_x509_crt_get_serial(cert, sbuf, &len);
     755    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
     756    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
     757                   apr_pstrdup(r->pool, tmp));
     758
     759    tmp =
     760        mgs_time2sz(gnutls_x509_crt_get_expiration_time
     761                    (cert), buf, sizeof(buf));
     762    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     763                   apr_pstrdup(r->pool, tmp));
     764
     765    tmp =
     766        mgs_time2sz(gnutls_x509_crt_get_activation_time
     767                    (cert), buf, sizeof(buf));
     768    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     769                   apr_pstrdup(r->pool, tmp));
     770
     771    alg = gnutls_x509_crt_get_signature_algorithm( cert);
     772    if (alg >= 0) {
     773      apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", NULL),
     774          gnutls_sign_algorithm_get_name( alg));
     775    }
     776
     777    alg = gnutls_x509_crt_get_pk_algorithm( cert, NULL);
     778    if (alg >= 0) {
     779      apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
     780          gnutls_pk_algorithm_get_name( alg));
     781    }
     782
     783
     784}
     785
     786
     787static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
     788{
     789    const gnutls_datum_t *cert_list;
     790    unsigned int cert_list_size, status, expired;
     791    int rv, ret;
     792    gnutls_x509_crt_t cert;
     793    apr_time_t activation_time, expiration_time, cur_time;
     794
     795    cert_list =
     796        gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
     797
     798    if (cert_list == NULL || cert_list_size == 0) {
     799        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
     800         */
     801        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     802            return OK;
     803
     804        /* no certificate provided by the client, but one was required. */
     805        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     806                      "GnuTLS: Failed to Verify Peer: "
     807                      "Client did not submit a certificate");
     808        return HTTP_FORBIDDEN;
     809    }
     810
     811    if (cert_list_size > 1) {
     812        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     813                      "GnuTLS: Failed to Verify Peer: "
     814                      "Chained Client Certificates are not supported.");
     815        return HTTP_FORBIDDEN;
     816    }
     817
     818    gnutls_x509_crt_init(&cert);
     819    rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
    621820    if (rv < 0) {
    622         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    623                      "GnuTLS: Failed to Verify Peer: (%d) %s",
    624                      rv, gnutls_strerror(rv));
    625         return HTTP_FORBIDDEN;
    626     }
    627    
    628     if (status < 0) {
    629         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    630                      "GnuTLS: Peer Status is invalid.");
    631         return HTTP_FORBIDDEN;
    632     }
    633    
     821        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     822                      "GnuTLS: Failed to Verify Peer: "
     823                      "Failed to import peer certificates.");
     824        ret = HTTP_FORBIDDEN;
     825        goto exit;
     826    }
     827
     828    apr_time_ansi_put(&expiration_time,
     829                      gnutls_x509_crt_get_expiration_time(cert));
     830    apr_time_ansi_put(&activation_time,
     831                      gnutls_x509_crt_get_activation_time(cert));
     832
     833    rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list,
     834                                ctxt->sc->ca_list_size, 0, &status);
     835
     836    if (rv < 0) {
     837        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     838                      "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
     839                      rv, gnutls_strerror(rv));
     840        ret = HTTP_FORBIDDEN;
     841        goto exit;
     842    }
     843
     844    expired = 0;
     845    cur_time = apr_time_now();
     846    if (activation_time > cur_time) {
     847        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     848                      "GnuTLS: Failed to Verify Peer: "
     849                      "Peer Certificate is not yet activated.");
     850        expired = 1;
     851    }
     852
     853    if (expiration_time < cur_time) {
     854        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     855                      "GnuTLS: Failed to Verify Peer: "
     856                      "Peer Certificate is expired.");
     857        expired = 1;
     858    }
     859
    634860    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
    635         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    636                      "GnuTLS: Could not find Signer for Peer Certificate");
    637     }
    638    
     861        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     862                      "GnuTLS: Could not find Signer for Peer Certificate");
     863    }
     864
    639865    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
    640         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    641                      "GnuTLS: Could not find CA for Peer Certificate");
    642     }
    643    
     866        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     867                      "GnuTLS: Peer's Certificate signer is not a CA");
     868    }
     869
    644870    if (status & GNUTLS_CERT_INVALID) {
    645         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    646                      "GnuTLS: Peer Certificate is invalid.");
    647         return HTTP_FORBIDDEN;
    648     }
    649     else if (status & GNUTLS_CERT_REVOKED) {
    650         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    651                      "GnuTLS: Peer Certificate is revoked.");
    652         return HTTP_FORBIDDEN;
    653     }
    654    
    655     /* TODO: OpenPGP Certificates */
    656     if (gnutls_certificate_type_get(ctxt->session) != GNUTLS_CRT_X509) {
    657         ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
    658                      "GnuTLS: Only x509 is supported for client certificates");         
    659         return HTTP_FORBIDDEN;
    660     }
     871        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     872                      "GnuTLS: Peer Certificate is invalid.");
     873    } else if (status & GNUTLS_CERT_REVOKED) {
     874        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     875                      "GnuTLS: Peer Certificate is revoked.");
     876    }
     877
    661878    /* TODO: Further Verification. */
    662     ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
    663                  "GnuTLS: Verified Peer.");             
    664     return OK;
    665 }
    666 
     879    /* Revocation is X.509 non workable paradigm, I really doubt implementation
     880     * is worth doing --nmav
     881     */
     882/// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size);
     883
     884//    mgs_hook_fixups(r);
     885//    rv = mgs_authz_lua(r);
     886
     887    mgs_add_common_cert_vars(r, cert, 1, ctxt->sc->export_certificates_enabled);
     888
     889    {
     890      /* days remaining */
     891      unsigned long remain = (apr_time_sec(expiration_time) - apr_time_sec(cur_time))/86400;
     892      apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
     893          apr_psprintf(r->pool, "%lu", remain));
     894    }
     895
     896    if (status == 0 && expired == 0) {
     897        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "SUCCESS");
     898        ret = OK;
     899    } else {
     900        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "FAILED");
     901        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     902            ret = OK;
     903        else
     904            ret = HTTP_FORBIDDEN;
     905    }
     906
     907  exit:
     908    gnutls_x509_crt_deinit(cert);
     909    return ret;
     910
     911
     912}
Note: See TracChangeset for help on using the changeset viewer.