source: mod_gnutls/src/gnutls_hooks.c @ 56f3628

debian/masterdebian/stretch-backportsjessie-backportsmsvaupstream
Last change on this file since 56f3628 was 56f3628, checked in by Nokis Mavrogiannopoulos <nmav@…>, 11 years ago

Added patch to fix issue with mod_proxy. Investigation and patch by Alain Knaff.

It seems that the reason for this behavior is that the mgs_hook_pre_connection is being called both for incoming and outgoing (mod_proxy) connections.

The attached patch (mod_proxy.patch) tries to find out in which case we are, and returns OK without doing anything if it is an outgoing connection.

The method of telling both cases apart (namely, checking whether remote address' hostname is set) may seem somewhat hackish, but it does work, even if
HostnameLookups? is set to On.

If ever there is a problem with this method, we might need to check local port instead (whether it is 443), but that would break if a non-standard https port was used.

  • Property mode set to 100644
File size: 34.1 KB
Line 
1/**
2 *  Copyright 2004-2005 Paul Querna
3 *  Copyright 2007 Nikos Mavrogiannopoulos
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 */
18
19#include "mod_gnutls.h"
20#include "http_vhost.h"
21#include "ap_mpm.h"
22
23#if !USING_2_1_RECENT
24extern server_rec *ap_server_conf;
25#endif
26
27#if APR_HAS_THREADS
28GCRY_THREAD_OPTION_PTHREAD_IMPL;
29#endif
30
31#if MOD_GNUTLS_DEBUG
32static apr_file_t *debug_log_fp;
33#endif
34
35static int mpm_is_threaded;
36
37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
38/* use side==0 for server and side==1 for client */
39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert,
40                                     int side,
41                                     int export_certificates_enabled);
42static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
43                                     int side,
44                                     int export_certificates_enabled);
45
46static apr_status_t mgs_cleanup_pre_config(void *data)
47{
48    gnutls_global_deinit();
49    return APR_SUCCESS;
50}
51
52#if MOD_GNUTLS_DEBUG
53static void gnutls_debug_log_all(int level, const char *str)
54{
55    apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
56}
57#define _gnutls_log apr_file_printf
58#else
59# define _gnutls_log(...)
60#endif
61
62int
63mgs_hook_pre_config(apr_pool_t * pconf,
64                    apr_pool_t * plog, apr_pool_t * ptemp)
65{
66int ret;
67
68#if MOD_GNUTLS_DEBUG
69    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
70                  APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
71                  pconf);
72
73    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
74
75    gnutls_global_set_log_level(9);
76    gnutls_global_set_log_function(gnutls_debug_log_all);
77    _gnutls_log(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
78#endif
79
80#if APR_HAS_THREADS
81    ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
82    if (mpm_is_threaded) {
83        gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
84    }
85#else
86    mpm_is_threaded = 0;
87#endif
88
89    if (gnutls_check_version(LIBGNUTLS_VERSION)==NULL) {
90        _gnutls_log(debug_log_fp, "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", 
91          LIBGNUTLS_VERSION, gnutls_check_version(NULL));
92        return -3;
93    }
94
95    ret = gnutls_global_init();
96    if (ret < 0) {
97        _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n", gnutls_strerror(ret));
98        return -3;
99    }
100
101    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
102                              apr_pool_cleanup_null);
103
104
105    return OK;
106}
107
108static int mgs_select_virtual_server_cb(gnutls_session_t session)
109{
110    mgs_handle_t *ctxt;
111    mgs_srvconf_rec *tsc;
112    int ret;
113    int cprio[2];
114
115    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
116
117    ctxt = gnutls_transport_get_ptr(session);
118
119    /* find the virtual server */
120    tsc = mgs_find_sni_server(session);
121
122    if (tsc != NULL)
123        ctxt->sc = tsc;
124
125    gnutls_certificate_server_set_request(session,
126                                          ctxt->sc->client_verify_mode);
127
128    /* set the new server credentials
129     */
130
131    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
132                           ctxt->sc->certs);
133
134    gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
135
136#ifdef ENABLE_SRP
137    if (ctxt->sc->srp_tpasswd_conf_file != NULL
138        && ctxt->sc->srp_tpasswd_file != NULL) {
139        gnutls_credentials_set(session, GNUTLS_CRD_SRP,
140                               ctxt->sc->srp_creds);
141    }
142#endif
143
144    /* update the priorities - to avoid negotiating a ciphersuite that is not
145     * enabled on this virtual server. Note that here we ignore the version
146     * negotiation.
147     */
148    ret = gnutls_priority_set(session, ctxt->sc->priorities);
149    /* actually it shouldn't fail since we have checked at startup */
150    if (ret < 0)
151        return ret;
152
153    /* If both certificate types are not present disallow them from
154     * being negotiated.
155     */
156    if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
157        cprio[0] = GNUTLS_CRT_X509;
158        cprio[1] = 0;
159        gnutls_certificate_type_set_priority( session, cprio);
160    } else if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0]==NULL) {
161        cprio[0] = GNUTLS_CRT_OPENPGP;
162        cprio[1] = 0;
163        gnutls_certificate_type_set_priority( session, cprio);
164    }
165
166    return 0;
167}
168
169static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
170{
171    mgs_handle_t *ctxt;
172
173    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
174    ctxt = gnutls_transport_get_ptr(session);
175
176    if (ctxt == NULL)
177        return GNUTLS_E_INTERNAL_ERROR;
178
179    if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) {
180        ret->type = GNUTLS_CRT_X509;
181        ret->ncerts = ctxt->sc->certs_x509_num;
182        ret->deinit_all = 0;
183
184        ret->cert.x509 = ctxt->sc->certs_x509;
185        ret->key.x509 = ctxt->sc->privkey_x509;
186       
187        return 0;
188    } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) {
189        ret->type = GNUTLS_CRT_OPENPGP;
190        ret->ncerts = 1;
191        ret->deinit_all = 0;
192
193        ret->cert.pgp = ctxt->sc->cert_pgp;
194        ret->key.pgp = ctxt->sc->privkey_pgp;
195
196        return 0;
197   
198    }
199
200    return GNUTLS_E_INTERNAL_ERROR;
201}
202
203/* 2048-bit group parameters from SRP specification */
204const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
205    "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
206    "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
207    "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
208    "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
209    "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
210    "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
211    "-----END DH PARAMETERS-----\n";
212
213/* Read the common name or the alternative name of the certificate.
214 * We only support a single name per certificate.
215 *
216 * Returns negative on error.
217 */
218static int read_crt_cn(server_rec * s, apr_pool_t * p,
219                       gnutls_x509_crt_t cert, char **cert_cn)
220{
221    int rv = 0, i;
222    size_t data_len;
223
224
225    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
226    *cert_cn = NULL;
227
228    data_len = 0;
229    rv = gnutls_x509_crt_get_dn_by_oid(cert,
230                                       GNUTLS_OID_X520_COMMON_NAME,
231                                       0, 0, NULL, &data_len);
232
233    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
234        *cert_cn = apr_palloc(p, data_len);
235        rv = gnutls_x509_crt_get_dn_by_oid(cert,
236                                           GNUTLS_OID_X520_COMMON_NAME, 0,
237                                           0, *cert_cn, &data_len);
238    } else {                    /* No CN return subject alternative name */
239        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
240                     "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
241                     s->server_hostname, s->port);
242        rv = 0;
243        /* read subject alternative name */
244        for (i = 0; !(rv < 0); i++) {
245            data_len = 0;
246            rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
247                                                      NULL, &data_len,
248                                                      NULL);
249
250            if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
251                /* FIXME: not very efficient. What if we have several alt names
252                 * before DNSName?
253                 */
254                *cert_cn = apr_palloc(p, data_len + 1);
255
256                rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
257                                                          *cert_cn,
258                                                          &data_len, NULL);
259                (*cert_cn)[data_len] = 0;
260
261                if (rv == GNUTLS_SAN_DNSNAME)
262                    break;
263            }
264        }
265    }
266
267    return rv;
268}
269
270static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
271                       gnutls_openpgp_crt_t cert, char **cert_cn)
272{
273    int rv = 0;
274    size_t data_len;
275
276
277    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
278    *cert_cn = NULL;
279
280    data_len = 0;
281    rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
282
283    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
284        *cert_cn = apr_palloc(p, data_len);
285        rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len);
286    } else {                    /* No CN return subject alternative name */
287        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
288                     "No name found in PGP certificate for '%s:%d'.",
289                     s->server_hostname, s->port);
290    }
291
292    return rv;
293}
294
295
296int
297mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
298                     apr_pool_t * ptemp, server_rec * base_server)
299{
300    int rv;
301    server_rec *s;
302    gnutls_dh_params_t dh_params = NULL;
303    gnutls_rsa_params_t rsa_params = NULL;
304    mgs_srvconf_rec *sc;
305    mgs_srvconf_rec *sc_base;
306    void *data = NULL;
307    int first_run = 0;
308    const char *userdata_key = "mgs_init";
309
310    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
311    apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
312    if (data == NULL) {
313        first_run = 1;
314        apr_pool_userdata_set((const void *) 1, userdata_key,
315                              apr_pool_cleanup_null,
316                              base_server->process->pool);
317    }
318
319
320    {
321        s = base_server;
322        sc_base =
323            (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
324                                                     &gnutls_module);
325
326        gnutls_dh_params_init(&dh_params);
327
328        if (sc_base->dh_params == NULL) {
329            gnutls_datum pdata = { (void *) static_dh_params, sizeof(static_dh_params) };
330            /* loading defaults */
331            rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
332                                               GNUTLS_X509_FMT_PEM);
333
334            if (rv < 0) {
335                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
336                     "GnuTLS: Unable to load DH Params: (%d) %s",
337                     rv, gnutls_strerror(rv));
338                exit(rv);
339            }
340        } else dh_params = sc_base->dh_params;
341
342        if (sc_base->rsa_params != NULL) 
343            rsa_params = sc_base->rsa_params;
344
345        /* else not an error but RSA-EXPORT ciphersuites are not available
346         */
347
348        rv = mgs_cache_post_config(p, s, sc_base);
349        if (rv != 0) {
350            ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
351                         "GnuTLS: Post Config for GnuTLSCache Failed."
352                         " Shutting Down.");
353            exit(-1);
354        }
355
356        for (s = base_server; s; s = s->next) {
357            void *load = NULL;
358            sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
359                                                          &gnutls_module);
360            sc->cache_type = sc_base->cache_type;
361            sc->cache_config = sc_base->cache_config;
362
363            /* Check if the priorities have been set */
364            if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
365                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
366                     "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
367                             s->server_hostname, s->port);
368                exit(-1);
369            }
370           
371            /* Check if DH or RSA params have been set per host */
372            if (sc->rsa_params != NULL)
373                load = sc->rsa_params;
374            else if (rsa_params) load = rsa_params;
375           
376            if (load != NULL)
377                gnutls_certificate_set_rsa_export_params(sc->certs, load);
378
379
380            load = NULL;
381            if (sc->dh_params != NULL)
382                load = sc->dh_params;
383            else if (dh_params) load = dh_params;
384           
385            if (load != NULL) { /* not needed but anyway */
386                gnutls_certificate_set_dh_params(sc->certs, load);
387                gnutls_anon_set_server_dh_params(sc->anon_creds, load);
388            }
389
390            gnutls_certificate_server_set_retrieve_function(sc->certs,
391                                                            cert_retrieve_fn);
392
393#ifdef ENABLE_SRP
394            if (sc->srp_tpasswd_conf_file != NULL
395                && sc->srp_tpasswd_file != NULL) {
396                rv = gnutls_srp_set_server_credentials_file(sc->srp_creds,
397                                                            sc->
398                                                            srp_tpasswd_file,
399                                                            sc->
400                                                            srp_tpasswd_conf_file);
401
402                if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
403                    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
404                                 "[GnuTLS] - Host '%s:%d' is missing a "
405                                 "SRP password or conf File!",
406                                 s->server_hostname, s->port);
407                    exit(-1);
408                }
409            }
410#endif
411
412            if (sc->certs_x509[0] == NULL &&
413                sc->cert_pgp == NULL &&
414                sc->enabled == GNUTLS_ENABLED_TRUE) {
415                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
416                             "[GnuTLS] - Host '%s:%d' is missing a "
417                             "Certificate File!", s->server_hostname,
418                             s->port);
419                exit(-1);
420            }
421
422            if (sc->enabled == GNUTLS_ENABLED_TRUE && 
423              ((sc->certs_x509[0] != NULL && sc->privkey_x509 == NULL) ||
424              (sc->cert_pgp != NULL && sc->privkey_pgp == NULL))) {
425                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
426                             "[GnuTLS] - Host '%s:%d' is missing a "
427                             "Private Key File!",
428                             s->server_hostname, s->port);
429                exit(-1);
430            }
431
432            if (sc->enabled == GNUTLS_ENABLED_TRUE) {
433                rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn);
434                if (rv < 0 && sc->cert_pgp != NULL)  /* try openpgp certificate */
435                    rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
436
437                if (rv < 0) {
438                    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
439                                 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
440                                 s->server_hostname, s->port);
441                    sc->cert_cn = NULL;
442                    continue;
443                }
444            }
445        }
446    }
447
448    ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
449
450    return OK;
451}
452
453void mgs_hook_child_init(apr_pool_t * p, server_rec * s)
454{
455    apr_status_t rv = APR_SUCCESS;
456    mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
457                                               &gnutls_module);
458
459    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
460    if (sc->cache_type != mgs_cache_none) {
461        rv = mgs_cache_child_init(p, s, sc);
462        if (rv != APR_SUCCESS) {
463            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
464                         "[GnuTLS] - Failed to run Cache Init");
465        }
466    } else {
467        ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
468                     "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
469    }
470}
471
472const char *mgs_hook_http_scheme(const request_rec * r)
473{
474    mgs_srvconf_rec *sc =
475        (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
476                                                 &gnutls_module);
477
478    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
479    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
480        return NULL;
481    }
482
483    return "https";
484}
485
486apr_port_t mgs_hook_default_port(const request_rec * r)
487{
488    mgs_srvconf_rec *sc =
489        (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
490                                                 &gnutls_module);
491
492    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
493    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
494        return 0;
495    }
496
497    return 443;
498}
499
500#define MAX_HOST_LEN 255
501
502#if USING_2_1_RECENT
503typedef struct {
504    mgs_handle_t *ctxt;
505    mgs_srvconf_rec *sc;
506    const char *sni_name;
507} vhost_cb_rec;
508
509static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
510{
511    mgs_srvconf_rec *tsc;
512    vhost_cb_rec *x = baton;
513
514    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
515    tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
516                                                   &gnutls_module);
517
518    if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
519        return 0;
520    }
521
522    /* The CN can contain a * -- this will match those too. */
523    if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
524        /* found a match */
525#if MOD_GNUTLS_DEBUG
526        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
527                     x->ctxt->c->base_server,
528                     "GnuTLS: Virtual Host CB: "
529                     "'%s' == '%s'", tsc->cert_cn, x->sni_name);
530#endif
531        /* Because we actually change the server used here, we need to reset
532         * things like ClientVerify.
533         */
534        x->sc = tsc;
535        /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
536         * certificate structure *should* change when the server changes.
537         * acccckkkkkk.
538         */
539        return 1;
540    } else {
541#if MOD_GNUTLS_DEBUG
542        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
543                     x->ctxt->c->base_server,
544                     "GnuTLS: Virtual Host CB: "
545                     "'%s' != '%s'", tsc->cert_cn, x->sni_name);
546#endif
547
548    }
549    return 0;
550}
551#endif
552
553mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
554{
555    int rv;
556    unsigned int sni_type;
557    size_t data_len = MAX_HOST_LEN;
558    char sni_name[MAX_HOST_LEN];
559    mgs_handle_t *ctxt;
560#if USING_2_1_RECENT
561    vhost_cb_rec cbx;
562#else
563    server_rec *s;
564    mgs_srvconf_rec *tsc;
565#endif
566
567    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
568    ctxt = gnutls_transport_get_ptr(session);
569
570    rv = gnutls_server_name_get(ctxt->session, sni_name,
571                                &data_len, &sni_type, 0);
572
573    if (rv != 0) {
574        return NULL;
575    }
576
577    if (sni_type != GNUTLS_NAME_DNS) {
578        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
579                     ctxt->c->base_server,
580                     "GnuTLS: Unknown type '%d' for SNI: "
581                     "'%s'", sni_type, sni_name);
582        return NULL;
583    }
584
585    /**
586     * Code in the Core already sets up the c->base_server as the base
587     * for this IP/Port combo.  Trust that the core did the 'right' thing.
588     */
589#if USING_2_1_RECENT
590    cbx.ctxt = ctxt;
591    cbx.sc = NULL;
592    cbx.sni_name = sni_name;
593
594    rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
595    if (rv == 1) {
596        return cbx.sc;
597    }
598#else
599    for (s = ap_server_conf; s; s = s->next) {
600
601        tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
602                                                       &gnutls_module);
603        if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
604            continue;
605        }
606#if MOD_GNUTLS_DEBUG
607        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
608                     ctxt->c->base_server,
609                     "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
610                     tsc->cert_cn, rv,
611                     gnutls_pk_algorithm_get_name
612                     (gnutls_x509_privkey_get_pk_algorithm
613                      (ctxt->sc->privkey_x509)), (unsigned int) s,
614                     (unsigned int) s->next, (unsigned int) tsc);
615#endif
616        /* The CN can contain a * -- this will match those too. */
617        if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
618#if MOD_GNUTLS_DEBUG
619            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
620                         ctxt->c->base_server,
621                         "GnuTLS: Virtual Host: "
622                         "'%s' == '%s'", tsc->cert_cn, sni_name);
623#endif
624            return tsc;
625        }
626    }
627#endif
628    return NULL;
629}
630
631
632static const int protocol_priority[] = {
633    GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
634};
635
636
637static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
638{
639    mgs_handle_t *ctxt;
640    mgs_srvconf_rec *sc =
641        (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
642                                                 module_config,
643                                                 &gnutls_module);
644
645    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
646    ctxt = apr_pcalloc(pool, sizeof(*ctxt));
647    ctxt->c = c;
648    ctxt->sc = sc;
649    ctxt->status = 0;
650
651    ctxt->input_rc = APR_SUCCESS;
652    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
653    ctxt->input_cbuf.length = 0;
654
655    ctxt->output_rc = APR_SUCCESS;
656    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
657    ctxt->output_blen = 0;
658    ctxt->output_length = 0;
659
660    gnutls_init(&ctxt->session, GNUTLS_SERVER);
661
662    /* because we don't set any default priorities here (we set later at
663     * the user hello callback) we need to at least set this in order for
664     * gnutls to be able to read packets.
665     */
666    gnutls_protocol_set_priority(ctxt->session, protocol_priority);
667
668    gnutls_handshake_set_post_client_hello_function(ctxt->session,
669                                                    mgs_select_virtual_server_cb);
670
671    mgs_cache_session_init(ctxt);
672
673    return ctxt;
674}
675
676int mgs_hook_pre_connection(conn_rec * c, void *csd)
677{
678    mgs_handle_t *ctxt;
679    mgs_srvconf_rec *sc =
680        (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
681                                                 module_config,
682                                                 &gnutls_module);
683
684    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
685    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
686        return DECLINED;
687    }
688
689    if(c->remote_addr->hostname)
690      /* Connection initiated by Apache (mod_proxy) => ignore */
691      return OK;
692
693    ctxt = create_gnutls_handle(c->pool, c);
694
695    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
696
697    gnutls_transport_set_pull_function(ctxt->session, mgs_transport_read);
698    gnutls_transport_set_push_function(ctxt->session, mgs_transport_write);
699    gnutls_transport_set_ptr(ctxt->session, ctxt);
700
701    ctxt->input_filter =
702        ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
703    ctxt->output_filter =
704        ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
705
706    return OK;
707}
708
709int mgs_hook_fixups(request_rec * r)
710{
711    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
712    char buf[AP_IOBUFSIZE];
713    const char *tmp;
714    size_t len;
715    mgs_handle_t *ctxt;
716    int rv = OK;
717
718    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
719    apr_table_t *env = r->subprocess_env;
720
721    ctxt =
722        ap_get_module_config(r->connection->conn_config, &gnutls_module);
723
724    if (!ctxt) {
725        return DECLINED;
726    }
727
728    apr_table_setn(env, "HTTPS", "on");
729
730    apr_table_setn(env, "SSL_VERSION_LIBRARY",
731                   "GnuTLS/" LIBGNUTLS_VERSION);
732    apr_table_setn(env, "SSL_VERSION_INTERFACE",
733                   "mod_gnutls/" MOD_GNUTLS_VERSION);
734
735    apr_table_setn(env, "SSL_PROTOCOL",
736                   gnutls_protocol_get_name(gnutls_protocol_get_version
737                                            (ctxt->session)));
738
739    /* should have been called SSL_CIPHERSUITE instead */
740    apr_table_setn(env, "SSL_CIPHER",
741                   gnutls_cipher_suite_get_name(gnutls_kx_get
742                                                (ctxt->session),
743                                                gnutls_cipher_get(ctxt->
744                                                                  session),
745                                                gnutls_mac_get(ctxt->
746                                                               session)));
747
748    apr_table_setn(env, "SSL_COMPRESS_METHOD",
749                   gnutls_compression_get_name(gnutls_compression_get
750                                               (ctxt->session)));
751
752#ifdef ENABLE_SRP
753    apr_table_setn(env, "SSL_SRP_USER",
754                   gnutls_srp_server_get_username(ctxt->session));
755#endif
756
757    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
758        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
759
760    unsigned int key_size =
761        8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
762    tmp = apr_psprintf(r->pool, "%u", key_size);
763
764    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
765
766    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
767
768    apr_table_setn(env, "SSL_CIPHER_EXPORT",
769                   (key_size <= 40) ? "true" : "false");
770
771    len = sizeof(sbuf);
772    gnutls_session_get_id(ctxt->session, sbuf, &len);
773    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
774    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
775
776    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
777        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
778                             ctxt->sc->export_certificates_enabled);
779    else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
780        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
781                             ctxt->sc->export_certificates_enabled);
782
783    return rv;
784}
785
786int mgs_hook_authz(request_rec * r)
787{
788    int rv;
789    mgs_handle_t *ctxt;
790    mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
791                                               &gnutls_module);
792
793    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
794    ctxt =
795        ap_get_module_config(r->connection->conn_config, &gnutls_module);
796
797    if (!ctxt) {
798        return DECLINED;
799    }
800
801    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
802        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
803                      "GnuTLS: Directory set to Ignore Client Certificate!");
804    } else {
805        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
806            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
807                          "GnuTLS: Attempting to rehandshake with peer. %d %d",
808                          ctxt->sc->client_verify_mode,
809                          dc->client_verify_mode);
810
811            gnutls_certificate_server_set_request(ctxt->session,
812                                                  dc->client_verify_mode);
813
814            if (mgs_rehandshake(ctxt) != 0) {
815                return HTTP_FORBIDDEN;
816            }
817        } else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
818#if MOD_GNUTLS_DEBUG
819            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
820                          "GnuTLS: Peer is set to IGNORE");
821#endif
822        } else {
823            rv = mgs_cert_verify(r, ctxt);
824            if (rv != DECLINED) {
825                return rv;
826            }
827        }
828    }
829
830    return DECLINED;
831}
832
833/* variables that are not sent by default:
834 *
835 * SSL_CLIENT_CERT      string  PEM-encoded client certificate
836 * SSL_SERVER_CERT      string  PEM-encoded client certificate
837 */
838
839/* side is either 0 for SERVER or 1 for CLIENT
840 */
841#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
842static void
843mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
844                         int export_certificates_enabled)
845{
846    unsigned char sbuf[64];     /* buffer to hold serials */
847    char buf[AP_IOBUFSIZE];
848    const char *tmp;
849    char *tmp2;
850    size_t len;
851    int ret, i;
852
853    apr_table_t *env = r->subprocess_env;
854
855    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
856    if (export_certificates_enabled != 0) {
857        char cert_buf[10 * 1024];
858        len = sizeof(cert_buf);
859
860        if (gnutls_x509_crt_export
861            (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
862            apr_table_setn(env,
863                           apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
864                           apr_pstrmemdup(r->pool, cert_buf, len));
865
866    }
867
868    len = sizeof(buf);
869    gnutls_x509_crt_get_dn(cert, buf, &len);
870    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
871                   apr_pstrmemdup(r->pool, buf, len));
872
873    len = sizeof(buf);
874    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
875    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
876                   apr_pstrmemdup(r->pool, buf, len));
877
878    len = sizeof(sbuf);
879    gnutls_x509_crt_get_serial(cert, sbuf, &len);
880    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
881    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
882                   apr_pstrdup(r->pool, tmp));
883
884    ret = gnutls_x509_crt_get_version(cert);
885    if (ret > 0)
886        apr_table_setn(env,
887                       apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
888                       apr_psprintf(r->pool, "%u", ret));
889
890    apr_table_setn(env,
891       apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "X.509");
892
893    tmp =
894        mgs_time2sz(gnutls_x509_crt_get_expiration_time
895                    (cert), buf, sizeof(buf));
896    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
897                   apr_pstrdup(r->pool, tmp));
898
899    tmp =
900        mgs_time2sz(gnutls_x509_crt_get_activation_time
901                    (cert), buf, sizeof(buf));
902    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
903                   apr_pstrdup(r->pool, tmp));
904
905    ret = gnutls_x509_crt_get_signature_algorithm(cert);
906    if (ret >= 0) {
907        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", NULL),
908                       gnutls_sign_algorithm_get_name(ret));
909    }
910
911    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
912    if (ret >= 0) {
913        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
914                       gnutls_pk_algorithm_get_name(ret));
915    }
916
917    /* export all the alternative names (DNS, RFC822 and URI) */
918    for (i = 0; !(ret < 0); i++) {
919        len = 0;
920        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
921                                                   NULL, &len, NULL);
922
923        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
924            tmp2 = apr_palloc(r->pool, len + 1);
925
926            ret =
927                gnutls_x509_crt_get_subject_alt_name(cert, i, tmp2, &len,
928                                                     NULL);
929            tmp2[len] = 0;
930
931            if (ret == GNUTLS_SAN_DNSNAME) {
932                apr_table_setn(env,
933                       apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), 
934                       apr_psprintf(r->pool, "DNSNAME:%s", tmp2));
935            } else if (ret == GNUTLS_SAN_RFC822NAME) {
936                apr_table_setn(env,
937                       apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), 
938                       apr_psprintf(r->pool, "RFC822NAME:%s", tmp2));
939            } else if (ret == GNUTLS_SAN_URI) {
940                apr_table_setn(env,
941                       apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), 
942                       apr_psprintf(r->pool, "URI:%s", tmp2));
943            } else {
944                apr_table_setn(env,
945                       apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i), 
946                       "UNSUPPORTED");
947            }
948        }
949    }
950}
951
952static void
953mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side,
954                         int export_certificates_enabled)
955{
956    unsigned char sbuf[64];     /* buffer to hold serials */
957    char buf[AP_IOBUFSIZE];
958    const char *tmp;
959    size_t len;
960    int ret;
961
962    _gnutls_log(debug_log_fp,   "%s: %d\n", __func__, __LINE__);
963    apr_table_t *env = r->subprocess_env;
964
965    if (export_certificates_enabled != 0) {
966        char cert_buf[10 * 1024];
967        len = sizeof(cert_buf);
968
969        if (gnutls_openpgp_crt_export
970            (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
971            apr_table_setn(env,
972                           apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
973                           apr_pstrmemdup(r->pool, cert_buf, len));
974
975    }
976
977    len = sizeof(buf);
978    gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
979    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
980                   apr_pstrmemdup(r->pool, buf, len));
981
982    len = sizeof(sbuf);
983    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
984    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
985    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL),
986                   apr_pstrdup(r->pool, tmp));
987
988    ret = gnutls_openpgp_crt_get_version(cert);
989    if (ret > 0)
990        apr_table_setn(env,
991                       apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
992                       apr_psprintf(r->pool, "%u", ret));
993
994    apr_table_setn(env,
995       apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP");
996
997    tmp =
998        mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
999                    (cert), buf, sizeof(buf));
1000    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
1001                   apr_pstrdup(r->pool, tmp));
1002
1003    tmp =
1004        mgs_time2sz(gnutls_openpgp_crt_get_creation_time
1005                    (cert), buf, sizeof(buf));
1006    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
1007                   apr_pstrdup(r->pool, tmp));
1008
1009    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
1010    if (ret >= 0) {
1011        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
1012                       gnutls_pk_algorithm_get_name(ret));
1013    }
1014
1015}
1016
1017/* TODO: Allow client sending a X.509 certificate chain */
1018static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
1019{
1020    const gnutls_datum_t *cert_list;
1021    unsigned int cert_list_size, status, expired;
1022    int rv, ret;
1023    union {
1024      gnutls_x509_crt_t x509;
1025      gnutls_openpgp_crt_t pgp;
1026    } cert;
1027    apr_time_t activation_time, expiration_time, cur_time;
1028
1029    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1030    cert_list =
1031        gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
1032
1033    if (cert_list == NULL || cert_list_size == 0) {
1034        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
1035         */
1036        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1037            return OK;
1038
1039        /* no certificate provided by the client, but one was required. */
1040        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1041                      "GnuTLS: Failed to Verify Peer: "
1042                      "Client did not submit a certificate");
1043        return HTTP_FORBIDDEN;
1044    }
1045
1046    if (cert_list_size > 1) {
1047        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1048                      "GnuTLS: Failed to Verify Peer: "
1049                      "Chained Client Certificates are not supported.");
1050        return HTTP_FORBIDDEN;
1051    }
1052
1053    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
1054        gnutls_x509_crt_init(&cert.x509);
1055        rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER);
1056    } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) {
1057        gnutls_openpgp_crt_init(&cert.pgp);
1058        rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW);
1059    } else return HTTP_FORBIDDEN;
1060 
1061    if (rv < 0) {
1062       ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1063                      "GnuTLS: Failed to Verify Peer: "
1064                      "Failed to import peer certificates.");
1065       ret = HTTP_FORBIDDEN;
1066       goto exit;
1067    }
1068
1069    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
1070        apr_time_ansi_put(&expiration_time,
1071                      gnutls_x509_crt_get_expiration_time(cert.x509));
1072        apr_time_ansi_put(&activation_time,
1073                      gnutls_x509_crt_get_activation_time(cert.x509));
1074
1075        rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list,
1076                                ctxt->sc->ca_list_size, 0, &status);
1077    } else {
1078        apr_time_ansi_put(&expiration_time,
1079                      gnutls_openpgp_crt_get_expiration_time(cert.pgp));
1080        apr_time_ansi_put(&activation_time,
1081                      gnutls_openpgp_crt_get_creation_time(cert.pgp));
1082
1083        rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list,
1084                      0, &status);
1085    }
1086
1087    if (rv < 0) {
1088        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1089                      "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
1090                      rv, gnutls_strerror(rv));
1091        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
1092            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
1093                      "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
1094        ret = HTTP_FORBIDDEN;
1095        goto exit;
1096    }
1097
1098    /* TODO: X509 CRL Verification. */
1099    /* May add later if anyone needs it.
1100     */
1101    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
1102
1103    expired = 0;
1104    cur_time = apr_time_now();
1105    if (activation_time > cur_time) {
1106        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1107                      "GnuTLS: Failed to Verify Peer: "
1108                      "Peer Certificate is not yet activated.");
1109        expired = 1;
1110    }
1111
1112    if (expiration_time < cur_time) {
1113        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1114                      "GnuTLS: Failed to Verify Peer: "
1115                      "Peer Certificate is expired.");
1116        expired = 1;
1117    }
1118
1119    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1120        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1121                      "GnuTLS: Could not find Signer for Peer Certificate");
1122    }
1123
1124    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
1125        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1126                      "GnuTLS: Peer's Certificate signer is not a CA");
1127    }
1128
1129    if (status & GNUTLS_CERT_INVALID) {
1130        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1131                      "GnuTLS: Peer Certificate is invalid.");
1132    } else if (status & GNUTLS_CERT_REVOKED) {
1133        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1134                      "GnuTLS: Peer Certificate is revoked.");
1135    }
1136
1137    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
1138        mgs_add_common_cert_vars(r, cert.x509, 1,
1139                             ctxt->sc->export_certificates_enabled);
1140    else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
1141        mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
1142                             ctxt->sc->export_certificates_enabled);
1143
1144    {
1145        /* days remaining */
1146        unsigned long remain =
1147            (apr_time_sec(expiration_time) -
1148             apr_time_sec(cur_time)) / 86400;
1149        apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
1150                       apr_psprintf(r->pool, "%lu", remain));
1151    }
1152
1153    if (status == 0 && expired == 0) {
1154        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "SUCCESS");
1155        ret = OK;
1156    } else {
1157        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "FAILED");
1158        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1159            ret = OK;
1160        else
1161            ret = HTTP_FORBIDDEN;
1162    }
1163
1164  exit:
1165    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
1166        gnutls_x509_crt_deinit(cert.x509);
1167    else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
1168        gnutls_openpgp_crt_deinit(cert.pgp);
1169    return ret;
1170
1171
1172}
Note: See TracBrowser for help on using the repository browser.