Changeset e183628 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Sep 19, 2011, 11:58:43 PM (8 years ago)
Author:
Dash Shendy <neuromancer@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, master, msva, upstream
Children:
c7c2ad2
Parents:
6223319
Message:

Updated Copyright Headers & Formatting

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r6223319 re183628  
    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");
     
    2223
    2324#if APR_HAS_THREADS
    24 # if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11
     25#if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11
    2526#include <gcrypt.h>
    2627GCRY_THREAD_OPTION_PTHREAD_IMPL;
    27 # endif
     28#endif
    2829#endif
    2930
     
    3738
    3839static int mpm_is_threaded;
    39 static gnutls_datum session_ticket_key = { NULL, 0 };
     40static gnutls_datum session_ticket_key = {NULL, 0};
    4041
    4142static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    4243/* use side==0 for server and side==1 for client */
    4344static void mgs_add_common_cert_vars(request_rec * r,
    44                                      gnutls_x509_crt_t cert, int side,
    45                                      int export_certificates_enabled);
     45        gnutls_x509_crt_t cert, int side,
     46        int export_certificates_enabled);
    4647static 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;
     48        gnutls_openpgp_crt_t cert,
     49        int side,
     50        int export_certificates_enabled);
     51
     52static apr_status_t mgs_cleanup_pre_config(void *data) {
     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;
    5858}
    5959
    6060#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);
     61
     62static void gnutls_debug_log_all(int level, const char *str) {
     63    apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
    6464}
    6565
    6666#define _gnutls_log apr_file_printf
    6767#else
    68 # define _gnutls_log(...)
     68#define _gnutls_log(...)
    6969#endif
    7070
    7171int
    7272mgs_hook_pre_config(apr_pool_t * pconf,
    73                     apr_pool_t * plog, apr_pool_t * ptemp)
    74 {
    75         int ret;
     73        apr_pool_t * plog, apr_pool_t * ptemp) {
     74    int ret;
    7675
    7776#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);
    81 
    82         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    83 
    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));
     77    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
     78            APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
     79            pconf);
     80
     81    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     82
     83    gnutls_global_set_log_level(9);
     84    gnutls_global_set_log_function(gnutls_debug_log_all);
     85    _gnutls_log(debug_log_fp, "gnutls: %s\n",
     86            gnutls_check_version(NULL));
    8887#endif
    8988
    9089#if APR_HAS_THREADS
    91         ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
     90    ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
    9291#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);
    96         }
     92    if (mpm_is_threaded) {
     93        gcry_control(GCRYCTL_SET_THREAD_CBS,
     94                &gcry_threads_pthread);
     95    }
    9796#endif
    9897#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;
    108         }
    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);
     98    mpm_is_threaded = 0;
     99#endif
     100
     101
     102    if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
     103        _gnutls_log(debug_log_fp,
     104                "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
     105                LIBGNUTLS_VERSION, gnutls_check_version(NULL));
     106        return -3;
     107    }
     108
     109    ret = gnutls_global_init();
     110    if (ret < 0) {
     111        _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n",
     112                gnutls_strerror(ret));
     113        return -3;
     114    }
     115
     116    ret = gnutls_session_ticket_key_generate(&session_ticket_key);
     117    if (ret < 0) {
     118        _gnutls_log(debug_log_fp,
     119                "gnutls_session_ticket_key_generate: %s\n",
     120                gnutls_strerror(ret));
     121    }
     122
     123    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
     124            apr_pool_cleanup_null);
     125
     126
     127    return OK;
     128}
     129
     130static int mgs_select_virtual_server_cb(gnutls_session_t session) {
     131    mgs_handle_t *ctxt;
     132    mgs_srvconf_rec *tsc;
     133    int ret;
     134    int cprio[2];
     135
     136    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     137
     138    ctxt = gnutls_transport_get_ptr(session);
     139
     140    /* find the virtual server */
     141    tsc = mgs_find_sni_server(session);
     142
     143    if (tsc != NULL)
     144        ctxt->sc = tsc;
     145
     146    gnutls_certificate_server_set_request(session,
     147            ctxt->
     148            sc->client_verify_mode);
     149
     150    /* set the new server credentials
     151     */
     152
     153    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
     154            ctxt->sc->certs);
     155
     156    gnutls_credentials_set(session, GNUTLS_CRD_ANON,
     157            ctxt->sc->anon_creds);
    160158
    161159#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;
     160    if (ctxt->sc->srp_tpasswd_conf_file != NULL
     161            && ctxt->sc->srp_tpasswd_file != NULL) {
     162        gnutls_credentials_set(session, GNUTLS_CRD_SRP,
     163                ctxt->sc->srp_creds);
     164    }
     165#endif
     166
     167    /* update the priorities - to avoid negotiating a ciphersuite that is not
     168     * enabled on this virtual server. Note that here we ignore the version
     169     * negotiation.
     170     */
     171    ret = gnutls_priority_set(session, ctxt->sc->priorities);
     172    /* actually it shouldn't fail since we have checked at startup */
     173    if (ret < 0)
     174        return ret;
     175
     176    /* If both certificate types are not present disallow them from
     177     * being negotiated.
     178     */
     179    if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
     180        cprio[0] = GNUTLS_CRT_X509;
     181        cprio[1] = 0;
     182        gnutls_certificate_type_set_priority(session, cprio);
     183    } else if (ctxt->sc->cert_pgp != NULL
     184            && ctxt->sc->certs_x509[0] == NULL) {
     185        cprio[0] = GNUTLS_CRT_OPENPGP;
     186        cprio[1] = 0;
     187        gnutls_certificate_type_set_priority(session, cprio);
     188    }
     189
     190    return 0;
     191}
     192
     193static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) {
     194    mgs_handle_t *ctxt;
     195
     196    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     197    ctxt = gnutls_transport_get_ptr(session);
     198
     199    if (ctxt == NULL)
     200        return GNUTLS_E_INTERNAL_ERROR;
     201
     202    if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
     203        ret->type = GNUTLS_CRT_X509;
     204        ret->ncerts = ctxt->sc->certs_x509_num;
     205        ret->deinit_all = 0;
     206
     207        ret->cert.x509 = ctxt->sc->certs_x509;
     208        ret->key.x509 = ctxt->sc->privkey_x509;
     209
     210        return 0;
     211    } else if (gnutls_certificate_type_get(session) ==
     212            GNUTLS_CRT_OPENPGP) {
     213        ret->type = GNUTLS_CRT_OPENPGP;
     214        ret->ncerts = 1;
     215        ret->deinit_all = 0;
     216
     217        ret->cert.pgp = ctxt->sc->cert_pgp;
     218        ret->key.pgp = ctxt->sc->privkey_pgp;
     219
     220        return 0;
     221
     222    }
     223
     224    return GNUTLS_E_INTERNAL_ERROR;
    228225}
    229226
    230227/* 2048-bit group parameters from SRP specification */
    231228const 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";
     229        "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
     230        "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
     231        "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
     232        "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
     233        "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
     234        "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
     235        "-----END DH PARAMETERS-----\n";
    239236
    240237/* Read the common name or the alternative name of the certificate.
     
    244241 */
    245242static 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;
    292                         }
    293                 }
    294         }
    295 
    296         return rv;
     243        gnutls_x509_crt_t cert, char **cert_cn) {
     244    int rv = 0, i;
     245    size_t data_len;
     246
     247
     248    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     249    *cert_cn = NULL;
     250
     251    data_len = 0;
     252    rv = gnutls_x509_crt_get_dn_by_oid(cert,
     253            GNUTLS_OID_X520_COMMON_NAME,
     254            0, 0, NULL, &data_len);
     255
     256    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     257        *cert_cn = apr_palloc(p, data_len);
     258        rv = gnutls_x509_crt_get_dn_by_oid(cert,
     259                GNUTLS_OID_X520_COMMON_NAME,
     260                0, 0, *cert_cn,
     261                &data_len);
     262    } else { /* No CN return subject alternative name */
     263        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     264                "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
     265                s->server_hostname, s->port);
     266        rv = 0;
     267        /* read subject alternative name */
     268        for (i = 0; !(rv < 0); i++) {
     269            data_len = 0;
     270            rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
     271                    NULL,
     272                    &data_len,
     273                    NULL);
     274
     275            if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
     276                    && data_len > 1) {
     277                /* FIXME: not very efficient. What if we have several alt names
     278                 * before DNSName?
     279                 */
     280                *cert_cn = apr_palloc(p, data_len + 1);
     281
     282                rv = gnutls_x509_crt_get_subject_alt_name
     283                        (cert, i, *cert_cn, &data_len, NULL);
     284                (*cert_cn)[data_len] = 0;
     285
     286                if (rv == GNUTLS_SAN_DNSNAME)
     287                    break;
     288            }
     289        }
     290    }
     291
     292    return rv;
    297293}
    298294
    299295static 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 
     296        gnutls_openpgp_crt_t cert, char **cert_cn) {
     297    int rv = 0;
     298    size_t data_len;
     299
     300
     301    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     302    *cert_cn = NULL;
     303
     304    data_len = 0;
     305    rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
     306
     307    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     308        *cert_cn = apr_palloc(p, data_len);
     309        rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
     310                &data_len);
     311    } else { /* No CN return subject alternative name */
     312        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     313                "No name found in PGP certificate for '%s:%d'.",
     314                s->server_hostname, s->port);
     315    }
     316
     317    return rv;
     318}
    325319
    326320int
    327321mgs_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);
     322        apr_pool_t * ptemp, server_rec * base_server) {
     323    int rv;
     324    server_rec *s;
     325    gnutls_dh_params_t dh_params = NULL;
     326    gnutls_rsa_params_t rsa_params = NULL;
     327    mgs_srvconf_rec *sc;
     328    mgs_srvconf_rec *sc_base;
     329    void *data = NULL;
     330    int first_run = 0;
     331    const char *userdata_key = "mgs_init";
     332
     333    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     334    apr_pool_userdata_get(&data, userdata_key,
     335            base_server->process->pool);
     336    if (data == NULL) {
     337        first_run = 1;
     338        apr_pool_userdata_set((const void *) 1, userdata_key,
     339                apr_pool_cleanup_null,
     340                base_server->process->pool);
     341    }
     342
     343
     344    s = base_server;
     345    sc_base =
     346            (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     347            &gnutls_module);
     348
     349    gnutls_dh_params_init(&dh_params);
     350
     351    if (sc_base->dh_params == NULL) {
     352        gnutls_datum pdata = {
     353            (void *) static_dh_params,
     354            sizeof (static_dh_params)
     355        };
     356        /* loading defaults */
     357        rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
     358                GNUTLS_X509_FMT_PEM);
     359
     360        if (rv < 0) {
     361            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     362                    "GnuTLS: Unable to load DH Params: (%d) %s",
     363                    rv, gnutls_strerror(rv));
     364            exit(rv);
     365        }
     366    } else
     367        dh_params = sc_base->dh_params;
     368
     369    if (sc_base->rsa_params != NULL)
     370        rsa_params = sc_base->rsa_params;
     371
     372    /* else not an error but RSA-EXPORT ciphersuites are not available
     373     */
     374
     375    rv = mgs_cache_post_config(p, s, sc_base);
     376    if (rv != 0) {
     377        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     378                "GnuTLS: Post Config for GnuTLSCache Failed."
     379                " Shutting Down.");
     380        exit(-1);
     381    }
     382
     383    for (s = base_server; s; s = s->next) {
     384        void *load = NULL;
     385        sc = (mgs_srvconf_rec *)
     386                ap_get_module_config(s->module_config, &gnutls_module);
     387        sc->cache_type = sc_base->cache_type;
     388        sc->cache_config = sc_base->cache_config;
     389
     390        /* Check if the priorities have been set */
     391        if (sc->priorities == NULL
     392                && sc->enabled == GNUTLS_ENABLED_TRUE) {
     393            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     394                    "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
     395                    s->server_hostname, s->port);
     396            exit(-1);
     397        }
     398
     399        /* Check if DH or RSA params have been set per host */
     400        if (sc->rsa_params != NULL)
     401            load = sc->rsa_params;
     402        else if (rsa_params)
     403            load = rsa_params;
     404
     405        if (load != NULL)
     406            gnutls_certificate_set_rsa_export_params(sc->certs,
     407                load);
     408
     409
     410        load = NULL;
     411        if (sc->dh_params != NULL)
     412            load = sc->dh_params;
     413        else if (dh_params)
     414            load = dh_params;
     415
     416        if (load != NULL) { /* not needed but anyway */
     417            gnutls_certificate_set_dh_params(sc->certs, load);
     418            gnutls_anon_set_server_dh_params(sc->anon_creds,
     419                    load);
     420        }
     421
     422        gnutls_certificate_server_set_retrieve_function(sc->certs,
     423                cert_retrieve_fn);
    431424
    432425#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                 }
    448 #endif
    449 
    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;
     426        if (sc->srp_tpasswd_conf_file != NULL
     427                && sc->srp_tpasswd_file != NULL) {
     428            rv = gnutls_srp_set_server_credentials_file
     429                    (sc->srp_creds, sc->srp_tpasswd_file,
     430                    sc->srp_tpasswd_conf_file);
     431
     432            if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
     433                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
     434                        s,
     435                        "[GnuTLS] - Host '%s:%d' is missing a "
     436                        "SRP password or conf File!",
     437                        s->server_hostname, s->port);
     438                exit(-1);
     439            }
     440        }
     441#endif
     442
     443        if (sc->certs_x509[0] == NULL &&
     444                sc->cert_pgp == NULL &&
     445                sc->enabled == GNUTLS_ENABLED_TRUE) {
     446            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     447                    "[GnuTLS] - Host '%s:%d' is missing a "
     448                    "Certificate File!",
     449                    s->server_hostname, s->port);
     450            exit(-1);
     451        }
     452
     453        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
     454                ((sc->certs_x509[0] != NULL
     455                && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL
     456                && sc->privkey_pgp
     457                == NULL))) {
     458            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     459                    "[GnuTLS] - Host '%s:%d' is missing a "
     460                    "Private Key File!",
     461                    s->server_hostname, s->port);
     462            exit(-1);
     463        }
     464
     465        if (sc->enabled == GNUTLS_ENABLED_TRUE) {
     466            rv = read_crt_cn(s, p, sc->certs_x509[0],
     467                    &sc->cert_cn);
     468            if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */
     469                rv = read_pgpcrt_cn(s, p, sc->cert_pgp,
     470                    &sc->cert_cn);
     471
     472            if (rv < 0) {
     473                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
     474                        s,
     475                        "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
     476                        s->server_hostname, s->port);
     477                sc->cert_cn = NULL;
     478                continue;
     479            }
     480        }
     481    }
     482
     483
     484    ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
     485
     486    return OK;
     487}
     488
     489void mgs_hook_child_init(apr_pool_t * p, server_rec * s) {
     490    apr_status_t rv = APR_SUCCESS;
     491    mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
     492            &gnutls_module);
     493
     494    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     495    if (sc->cache_type != mgs_cache_none) {
     496        rv = mgs_cache_child_init(p, s, sc);
     497        if (rv != APR_SUCCESS) {
     498            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     499                    "[GnuTLS] - Failed to run Cache Init");
     500        }
     501    }
     502}
     503
     504const char *mgs_hook_http_scheme(const request_rec * r) {
     505    mgs_srvconf_rec *sc;
     506
     507    if (r == NULL)
     508        return NULL;
     509
     510    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
     511            server->module_config,
     512            &gnutls_module);
     513
     514    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     515    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
     516        return NULL;
     517    }
     518
     519    return "https";
     520}
     521
     522apr_port_t mgs_hook_default_port(const request_rec * r) {
     523    mgs_srvconf_rec *sc;
     524
     525    if (r == NULL)
     526        return 0;
     527
     528    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
     529            server->module_config,
     530            &gnutls_module);
     531
     532    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     533    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
     534        return 0;
     535    }
     536
     537    return 443;
    548538}
    549539
     
    551541
    552542#if USING_2_1_RECENT
     543
    553544typedef struct {
    554         mgs_handle_t *ctxt;
    555         mgs_srvconf_rec *sc;
    556         const char *sni_name;
     545    mgs_handle_t *ctxt;
     546    mgs_srvconf_rec *sc;
     547    const char *sni_name;
    557548} vhost_cb_rec;
    558549
    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 */
     550static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) {
     551    mgs_srvconf_rec *tsc;
     552    vhost_cb_rec *x = baton;
     553
     554    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     555    tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     556            &gnutls_module);
     557
     558    if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
     559        return 0;
     560    }
     561
     562    /* The CN can contain a * -- this will match those too. */
     563    if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
     564        /* found a match */
    575565#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);
    580 #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 {
     566        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     567                x->ctxt->c->base_server,
     568                "GnuTLS: Virtual Host CB: "
     569                "'%s' == '%s'", tsc->cert_cn, x->sni_name);
     570#endif
     571        /* Because we actually change the server used here, we need to reset
     572        * things like ClientVerify.
     573        */
     574        x->sc = tsc;
     575        /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
     576        * certificate structure *should* change when the server changes.
     577        * acccckkkkkk.
     578        */
     579        return 1;
     580    } else {
    591581#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;
     582        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     583                x->ctxt->c->base_server,
     584                "GnuTLS: Virtual Host CB: "
     585                "'%s' != '%s'", tsc->cert_cn, x->sni_name);
     586#endif
     587
     588    }
     589    return 0;
     590}
     591#endif
     592
     593mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) {
     594    int rv;
     595    unsigned int sni_type;
     596    size_t data_len = MAX_HOST_LEN;
     597    char sni_name[MAX_HOST_LEN];
     598    mgs_handle_t *ctxt;
    610599#if USING_2_1_RECENT
    611         vhost_cb_rec cbx;
     600    vhost_cb_rec cbx;
    612601#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         }
     602    server_rec *s;
     603    mgs_srvconf_rec *tsc;
     604#endif
     605
     606    if (session == NULL)
     607        return NULL;
     608
     609    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     610    ctxt = gnutls_transport_get_ptr(session);
     611
     612    rv = gnutls_server_name_get(ctxt->session, sni_name,
     613            &data_len, &sni_type, 0);
     614
     615    if (rv != 0) {
     616        return NULL;
     617    }
     618
     619    if (sni_type != GNUTLS_NAME_DNS) {
     620        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     621                ctxt->c->base_server,
     622                "GnuTLS: Unknown type '%d' for SNI: "
     623                "'%s'", sni_type, sni_name);
     624        return NULL;
     625    }
    637626
    638627    /**
     
    641630     */
    642631#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;
    650         }
     632    cbx.ctxt = ctxt;
     633    cbx.sc = NULL;
     634    cbx.sni_name = sni_name;
     635
     636    rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     637    if (rv == 1) {
     638        return cbx.sc;
     639    }
    651640#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                 }
     641    for (s = ap_server_conf; s; s = s->next) {
     642
     643        tsc =
     644                (mgs_srvconf_rec *)
     645                ap_get_module_config(s->module_config, &gnutls_module);
     646        if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
     647            continue;
     648        }
    660649#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);
    669 #endif
    670                 /* The CN can contain a * -- this will match those too. */
    671                 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
     650        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     651                ctxt->c->base_server,
     652                "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
     653                tsc->cert_cn, rv,
     654                gnutls_pk_algorithm_get_name
     655                (gnutls_x509_privkey_get_pk_algorithm
     656                (ctxt->sc->privkey_x509)), (unsigned int) s,
     657                (unsigned int) s->next, (unsigned int) tsc);
     658#endif
     659        /* The CN can contain a * -- this will match those too. */
     660        if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
    672661#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;
     662            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     663                    ctxt->c->base_server,
     664                    "GnuTLS: Virtual Host: "
     665                    "'%s' == '%s'", tsc->cert_cn,
     666                    sni_name);
     667#endif
     668            return tsc;
     669        }
     670    }
     671#endif
     672    return NULL;
    684673}
    685674
    686675
    687676static const int protocol_priority[] = {
    688         GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
     677    GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
    689678};
    690679
    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) {
     680static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) {
     681    mgs_handle_t *ctxt;
     682    mgs_srvconf_rec *sc =
     683            (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
     684            module_config,
     685            &gnutls_module);
     686
     687    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     688    ctxt = apr_pcalloc(pool, sizeof (*ctxt));
     689    ctxt->c = c;
     690    ctxt->sc = sc;
     691    ctxt->status = 0;
     692
     693    ctxt->input_rc = APR_SUCCESS;
     694    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
     695    ctxt->input_cbuf.length = 0;
     696
     697    ctxt->output_rc = APR_SUCCESS;
     698    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
     699    ctxt->output_blen = 0;
     700    ctxt->output_length = 0;
     701
     702    gnutls_init(&ctxt->session, GNUTLS_SERVER);
     703    if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
     704        gnutls_session_ticket_enable_server(ctxt->session,
     705            &session_ticket_key);
     706
     707    /* because we don't set any default priorities here (we set later at
     708     * the user hello callback) we need to at least set this in order for
     709     * gnutls to be able to read packets.
     710     */
     711    gnutls_protocol_set_priority(ctxt->session, protocol_priority);
     712
     713    gnutls_handshake_set_post_client_hello_function(ctxt->session,
     714            mgs_select_virtual_server_cb);
     715
     716    mgs_cache_session_init(ctxt);
     717
     718    return ctxt;
     719}
     720
     721int mgs_hook_pre_connection(conn_rec * c, void *csd) {
     722    mgs_handle_t *ctxt;
     723    mgs_srvconf_rec *sc;
     724
     725    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     726
     727    if (c == NULL) {
     728        return DECLINED;
     729    }
     730
     731    sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
     732            module_config,
     733            &gnutls_module);
     734
     735    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
     736        return DECLINED;
     737    }
     738
     739    if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip, c->local_ip) == 0) {
    754740        /* 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)));
     741        return OK;
     742    }
     743
     744    ctxt = create_gnutls_handle(c->pool, c);
     745
     746    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
     747
     748    gnutls_transport_set_pull_function(ctxt->session,
     749            mgs_transport_read);
     750    gnutls_transport_set_push_function(ctxt->session,
     751            mgs_transport_write);
     752    gnutls_transport_set_ptr(ctxt->session, ctxt);
     753
     754    ctxt->input_filter =
     755            ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
     756    ctxt->output_filter =
     757            ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
     758
     759    return OK;
     760}
     761
     762int mgs_hook_fixups(request_rec * r) {
     763    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
     764    char buf[AP_IOBUFSIZE];
     765    const char *tmp;
     766    size_t len;
     767    mgs_handle_t *ctxt;
     768    int rv = OK;
     769
     770    if (r == NULL)
     771        return DECLINED;
     772
     773    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     774    apr_table_t *env = r->subprocess_env;
     775
     776    ctxt =
     777            ap_get_module_config(r->connection->conn_config,
     778            &gnutls_module);
     779
     780    if (!ctxt || ctxt->session == NULL) {
     781        return DECLINED;
     782    }
     783
     784    apr_table_setn(env, "HTTPS", "on");
     785
     786    apr_table_setn(env, "SSL_VERSION_LIBRARY",
     787            "GnuTLS/" LIBGNUTLS_VERSION);
     788    apr_table_setn(env, "SSL_VERSION_INTERFACE",
     789            "mod_gnutls/" MOD_GNUTLS_VERSION);
     790
     791    apr_table_setn(env, "SSL_PROTOCOL",
     792            gnutls_protocol_get_name(gnutls_protocol_get_version
     793            (ctxt->session)));
     794
     795    /* should have been called SSL_CIPHERSUITE instead */
     796    apr_table_setn(env, "SSL_CIPHER",
     797            gnutls_cipher_suite_get_name(gnutls_kx_get
     798            (ctxt->session),
     799            gnutls_cipher_get
     800            (ctxt->session),
     801            gnutls_mac_get
     802            (ctxt->session)));
     803
     804    apr_table_setn(env, "SSL_COMPRESS_METHOD",
     805            gnutls_compression_get_name(gnutls_compression_get
     806            (ctxt->session)));
    822807
    823808#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) {
     809    tmp = gnutls_srp_server_get_username(ctxt->session);
     810    apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
     811#endif
     812
     813    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
     814        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
     815
     816    unsigned int key_size =
     817            8 *
     818            gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
     819    tmp = apr_psprintf(r->pool, "%u", key_size);
     820
     821    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
     822
     823    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
     824
     825    apr_table_setn(env, "SSL_CIPHER_EXPORT",
     826            (key_size <= 40) ? "true" : "false");
     827
     828    len = sizeof (sbuf);
     829    gnutls_session_get_id(ctxt->session, sbuf, &len);
     830    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     831    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
     832
     833    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
     834        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
     835            ctxt->
     836            sc->export_certificates_enabled);
     837    else if (gnutls_certificate_type_get(ctxt->session) ==
     838            GNUTLS_CRT_OPENPGP)
     839        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
     840            ctxt->
     841            sc->export_certificates_enabled);
     842
     843    return rv;
     844}
     845
     846int mgs_hook_authz(request_rec * r) {
     847    int rv;
     848    mgs_handle_t *ctxt;
     849    mgs_dirconf_rec *dc;
     850
     851    if (r == NULL)
     852        return DECLINED;
     853
     854    dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
     855
     856    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     857    ctxt =
     858            ap_get_module_config(r->connection->conn_config,
     859            &gnutls_module);
     860
     861    if (!ctxt || ctxt->session == NULL) {
     862        return DECLINED;
     863    }
     864
     865    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
     866        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     867                "GnuTLS: Directory set to Ignore Client Certificate!");
     868    } else {
     869        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
     870            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     871                    "GnuTLS: Attempting to rehandshake with peer. %d %d",
     872                    ctxt->sc->client_verify_mode,
     873                    dc->client_verify_mode);
     874
     875            /* If we already have a client certificate, there's no point in
     876             * re-handshaking... */
     877            rv = mgs_cert_verify(r, ctxt);
     878            if (rv != DECLINED && rv != HTTP_FORBIDDEN)
     879                return rv;
     880
     881            gnutls_certificate_server_set_request
     882                    (ctxt->session, dc->client_verify_mode);
     883
     884            if (mgs_rehandshake(ctxt) != 0) {
     885                return HTTP_FORBIDDEN;
     886            }
     887        } else if (ctxt->sc->client_verify_mode ==
     888                GNUTLS_CERT_IGNORE) {
    905889#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;
     890            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     891                    "GnuTLS: Peer is set to IGNORE");
     892#endif
     893            return DECLINED;
     894        }
     895        rv = mgs_cert_verify(r, ctxt);
     896        if (rv != DECLINED &&
     897                (rv != HTTP_FORBIDDEN ||
     898                dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
     899            return rv;
     900        }
     901    }
     902
     903    return DECLINED;
    920904}
    921905
     
    929913 */
    930914#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
     915
    931916static void
    932917mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
    933                          int export_certificates_enabled)
    934 {
    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         }
     918        int export_certificates_enabled) {
     919    unsigned char sbuf[64]; /* buffer to hold serials */
     920    char buf[AP_IOBUFSIZE];
     921    const char *tmp;
     922    char *tmp2;
     923    size_t len;
     924    int ret, i;
     925
     926    if (r == NULL)
     927        return;
     928
     929    apr_table_t *env = r->subprocess_env;
     930
     931    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     932    if (export_certificates_enabled != 0) {
     933        char cert_buf[10 * 1024];
     934        len = sizeof (cert_buf);
     935
     936        if (gnutls_x509_crt_export
     937                (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
     938            apr_table_setn(env,
     939                apr_pstrcat(r->pool, MGS_SIDE,
     940                "_CERT", NULL),
     941                apr_pstrmemdup(r->pool, cert_buf,
     942                len));
     943
     944    }
     945
     946    len = sizeof (buf);
     947    gnutls_x509_crt_get_dn(cert, buf, &len);
     948    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
     949            apr_pstrmemdup(r->pool, buf, len));
     950
     951    len = sizeof (buf);
     952    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
     953    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
     954            apr_pstrmemdup(r->pool, buf, len));
     955
     956    len = sizeof (sbuf);
     957    gnutls_x509_crt_get_serial(cert, sbuf, &len);
     958    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     959    apr_table_setn(env,
     960            apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
     961            apr_pstrdup(r->pool, tmp));
     962
     963    ret = gnutls_x509_crt_get_version(cert);
     964    if (ret > 0)
     965        apr_table_setn(env,
     966            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     967            NULL), apr_psprintf(r->pool,
     968            "%u", ret));
     969
     970    apr_table_setn(env,
     971            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     972            "X.509");
     973
     974    tmp =
     975            mgs_time2sz(gnutls_x509_crt_get_expiration_time
     976            (cert), buf, sizeof (buf));
     977    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     978            apr_pstrdup(r->pool, tmp));
     979
     980    tmp =
     981            mgs_time2sz(gnutls_x509_crt_get_activation_time
     982            (cert), buf, sizeof (buf));
     983    apr_table_setn(env,
     984            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     985            apr_pstrdup(r->pool, tmp));
     986
     987    ret = gnutls_x509_crt_get_signature_algorithm(cert);
     988    if (ret >= 0) {
     989        apr_table_setn(env,
     990                apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
     991                NULL),
     992                gnutls_sign_algorithm_get_name(ret));
     993    }
     994
     995    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
     996    if (ret >= 0) {
     997        apr_table_setn(env,
     998                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     999                NULL),
     1000                gnutls_pk_algorithm_get_name(ret));
     1001    }
     1002
     1003    /* export all the alternative names (DNS, RFC822 and URI) */
     1004    for (i = 0; !(ret < 0); i++) {
     1005        len = 0;
     1006        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
     1007                NULL, &len,
     1008                NULL);
     1009
     1010        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
     1011            tmp2 = apr_palloc(r->pool, len + 1);
     1012
     1013            ret =
     1014                    gnutls_x509_crt_get_subject_alt_name(cert, i,
     1015                    tmp2,
     1016                    &len,
     1017                    NULL);
     1018            tmp2[len] = 0;
     1019
     1020            if (ret == GNUTLS_SAN_DNSNAME) {
     1021                apr_table_setn(env,
     1022                        apr_psprintf(r->pool,
     1023                        "%s_S_AN%u",
     1024                        MGS_SIDE, i),
     1025                        apr_psprintf(r->pool,
     1026                        "DNSNAME:%s",
     1027                        tmp2));
     1028            } else if (ret == GNUTLS_SAN_RFC822NAME) {
     1029                apr_table_setn(env,
     1030                        apr_psprintf(r->pool,
     1031                        "%s_S_AN%u",
     1032                        MGS_SIDE, i),
     1033                        apr_psprintf(r->pool,
     1034                        "RFC822NAME:%s",
     1035                        tmp2));
     1036            } else if (ret == GNUTLS_SAN_URI) {
     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                        "URI:%s",
     1043                        tmp2));
     1044            } else {
     1045                apr_table_setn(env,
     1046                        apr_psprintf(r->pool,
     1047                        "%s_S_AN%u",
     1048                        MGS_SIDE, i),
     1049                        "UNSUPPORTED");
     1050            }
     1051        }
     1052    }
    10691053}
    10701054
    10711055static void
    10721056mgs_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         }
     1057        int side, int export_certificates_enabled) {
     1058    unsigned char sbuf[64]; /* buffer to hold serials */
     1059    char buf[AP_IOBUFSIZE];
     1060    const char *tmp;
     1061    size_t len;
     1062    int ret;
     1063
     1064    if (r == NULL)
     1065        return;
     1066
     1067    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1068    apr_table_t *env = r->subprocess_env;
     1069
     1070    if (export_certificates_enabled != 0) {
     1071        char cert_buf[10 * 1024];
     1072        len = sizeof (cert_buf);
     1073
     1074        if (gnutls_openpgp_crt_export
     1075                (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
     1076            apr_table_setn(env,
     1077                apr_pstrcat(r->pool, MGS_SIDE,
     1078                "_CERT", NULL),
     1079                apr_pstrmemdup(r->pool, cert_buf,
     1080                len));
     1081
     1082    }
     1083
     1084    len = sizeof (buf);
     1085    gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
     1086    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
     1087            apr_pstrmemdup(r->pool, buf, len));
     1088
     1089    len = sizeof (sbuf);
     1090    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
     1091    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     1092    apr_table_setn(env,
     1093            apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
     1094            NULL), apr_pstrdup(r->pool, tmp));
     1095
     1096    ret = gnutls_openpgp_crt_get_version(cert);
     1097    if (ret > 0)
     1098        apr_table_setn(env,
     1099            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     1100            NULL), apr_psprintf(r->pool,
     1101            "%u", ret));
     1102
     1103    apr_table_setn(env,
     1104            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     1105            "OPENPGP");
     1106
     1107    tmp =
     1108            mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
     1109            (cert), buf, sizeof (buf));
     1110    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     1111            apr_pstrdup(r->pool, tmp));
     1112
     1113    tmp =
     1114            mgs_time2sz(gnutls_openpgp_crt_get_creation_time
     1115            (cert), buf, sizeof (buf));
     1116    apr_table_setn(env,
     1117            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     1118            apr_pstrdup(r->pool, tmp));
     1119
     1120    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
     1121    if (ret >= 0) {
     1122        apr_table_setn(env,
     1123                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     1124                NULL),
     1125                gnutls_pk_algorithm_get_name(ret));
     1126    }
    11441127
    11451128}
    11461129
    11471130/* 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 }
     1131static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) {
     1132    const gnutls_datum_t *cert_list;
     1133    unsigned int cert_list_size, status;
     1134    int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
     1135    unsigned int ch_size = 0;
     1136
     1137    union {
     1138        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
     1139        gnutls_openpgp_crt_t pgp;
     1140    } cert;
     1141    apr_time_t expiration_time, cur_time;
     1142
     1143    if (r == NULL || ctxt == NULL || ctxt->session == NULL)
     1144        return HTTP_FORBIDDEN;
     1145
     1146    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1147    cert_list =
     1148            gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
     1149
     1150    if (cert_list == NULL || cert_list_size == 0) {
     1151        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
     1152        */
     1153        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1154            return OK;
     1155
     1156        /* no certificate provided by the client, but one was required. */
     1157        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1158                "GnuTLS: Failed to Verify Peer: "
     1159                "Client did not submit a certificate");
     1160        return HTTP_FORBIDDEN;
     1161    }
     1162
     1163    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1164        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1165                "GnuTLS: A Chain of %d certificate(s) was provided for validation",
     1166                cert_list_size);
     1167
     1168        for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
     1169            gnutls_x509_crt_init(&cert.x509[ch_size]);
     1170            rv = gnutls_x509_crt_import(cert.x509[ch_size],
     1171                    &cert_list[ch_size],
     1172                    GNUTLS_X509_FMT_DER);
     1173            // When failure to import, leave the loop
     1174            if (rv != GNUTLS_E_SUCCESS) {
     1175                if (ch_size < 1) {
     1176                    ap_log_rerror(APLOG_MARK,
     1177                            APLOG_INFO, 0, r,
     1178                            "GnuTLS: Failed to Verify Peer: "
     1179                            "Failed to import peer certificates.");
     1180                    ret = HTTP_FORBIDDEN;
     1181                    goto exit;
     1182                }
     1183                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1184                        "GnuTLS: Failed to import some peer certificates. Using %d certificates",
     1185                        ch_size);
     1186                rv = GNUTLS_E_SUCCESS;
     1187                break;
     1188            }
     1189        }
     1190    } else if (gnutls_certificate_type_get(ctxt->session) ==
     1191            GNUTLS_CRT_OPENPGP) {
     1192        if (cert_list_size > 1) {
     1193            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1194                    "GnuTLS: Failed to Verify Peer: "
     1195                    "Chained Client Certificates are not supported.");
     1196            return HTTP_FORBIDDEN;
     1197        }
     1198
     1199        gnutls_openpgp_crt_init(&cert.pgp);
     1200        rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
     1201                GNUTLS_OPENPGP_FMT_RAW);
     1202
     1203    } else
     1204        return HTTP_FORBIDDEN;
     1205
     1206    if (rv < 0) {
     1207        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1208                "GnuTLS: Failed to Verify Peer: "
     1209                "Failed to import peer certificates.");
     1210        ret = HTTP_FORBIDDEN;
     1211        goto exit;
     1212    }
     1213
     1214    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1215        apr_time_ansi_put(&expiration_time,
     1216                gnutls_x509_crt_get_expiration_time
     1217                (cert.x509[0]));
     1218
     1219        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1220                "GnuTLS: Verifying list of  %d certificate(s)",
     1221                ch_size);
     1222        rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
     1223                ctxt->sc->ca_list,
     1224                ctxt->sc->ca_list_size,
     1225                NULL, 0, 0, &status);
     1226    } else {
     1227        apr_time_ansi_put(&expiration_time,
     1228                gnutls_openpgp_crt_get_expiration_time
     1229                (cert.pgp));
     1230
     1231        rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
     1232                ctxt->sc->pgp_list, 0,
     1233                &status);
     1234    }
     1235
     1236    if (rv < 0) {
     1237        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1238                "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
     1239                rv, gnutls_strerror(rv));
     1240        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
     1241            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
     1242                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
     1243        ret = HTTP_FORBIDDEN;
     1244        goto exit;
     1245    }
     1246
     1247    /* TODO: X509 CRL Verification. */
     1248    /* May add later if anyone needs it.
     1249    */
     1250    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
     1251
     1252    cur_time = apr_time_now();
     1253
     1254    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
     1255        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1256                "GnuTLS: Could not find Signer for Peer Certificate");
     1257    }
     1258
     1259    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
     1260        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1261                "GnuTLS: Peer's Certificate signer is not a CA");
     1262    }
     1263
     1264    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
     1265        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1266                "GnuTLS: Peer's Certificate is using insecure algorithms");
     1267    }
     1268
     1269    if (status & GNUTLS_CERT_EXPIRED
     1270            || status & GNUTLS_CERT_NOT_ACTIVATED) {
     1271        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1272                "GnuTLS: Peer's Certificate signer is expired or not yet activated");
     1273    }
     1274
     1275    if (status & GNUTLS_CERT_INVALID) {
     1276        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1277                "GnuTLS: Peer Certificate is invalid.");
     1278    } else if (status & GNUTLS_CERT_REVOKED) {
     1279        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1280                "GnuTLS: Peer Certificate is revoked.");
     1281    }
     1282
     1283    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
     1284        mgs_add_common_cert_vars(r, cert.x509[0], 1,
     1285            ctxt->
     1286            sc->export_certificates_enabled);
     1287    else if (gnutls_certificate_type_get(ctxt->session) ==
     1288            GNUTLS_CRT_OPENPGP)
     1289        mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
     1290            ctxt->
     1291            sc->export_certificates_enabled);
     1292
     1293    {
     1294        /* days remaining */
     1295        unsigned long remain =
     1296                (apr_time_sec(expiration_time) -
     1297                apr_time_sec(cur_time)) / 86400;
     1298        apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
     1299                apr_psprintf(r->pool, "%lu", remain));
     1300    }
     1301
     1302    if (status == 0) {
     1303        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
     1304                "SUCCESS");
     1305        ret = OK;
     1306    } else {
     1307        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
     1308                "FAILED");
     1309        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1310            ret = OK;
     1311        else
     1312            ret = HTTP_FORBIDDEN;
     1313    }
     1314
     1315exit:
     1316    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1317        int i;
     1318        for (i = 0; i < ch_size; i++) {
     1319            gnutls_x509_crt_deinit(cert.x509[i]);
     1320        }
     1321    } else if (gnutls_certificate_type_get(ctxt->session) ==
     1322            GNUTLS_CRT_OPENPGP)
     1323        gnutls_openpgp_crt_deinit(cert.pgp);
     1324    return ret;
     1325
     1326
     1327}
Note: See TracChangeset for help on using the changeset viewer.