source: mod_gnutls/src/gnutls_hooks.c @ d0be765

debian/masterdebian/stretch-backportsjessie-backportsmsvaupstream
Last change on this file since d0be765 was d0be765, checked in by Dash Shendy <neuromancer@…>, 8 years ago

Added some comments

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