source: mod_gnutls/src/gnutls_hooks.c @ 9180a60

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

Applied New Functions Patch from Nikos

  • 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    mgs_srvconf_rec *sc =
646            (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
647            module_config,
648            &gnutls_module);
649
650    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
651    ctxt = apr_pcalloc(pool, sizeof (*ctxt));
652    ctxt->c = c;
653    ctxt->sc = sc;
654    ctxt->status = 0;
655
656    ctxt->input_rc = APR_SUCCESS;
657    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
658    ctxt->input_cbuf.length = 0;
659
660    ctxt->output_rc = APR_SUCCESS;
661    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
662    ctxt->output_blen = 0;
663    ctxt->output_length = 0;
664
665    gnutls_init(&ctxt->session, GNUTLS_SERVER);
666    if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
667        gnutls_session_ticket_enable_server(ctxt->session,
668            &session_ticket_key);
669
670    /* because we don't set any default priorities here (we set later at
671     * the user hello callback) we need to at least set this in order for
672     * gnutls to be able to read packets.
673     */
674    gnutls_set_default_priority(ctxt->session);
675
676    gnutls_handshake_set_post_client_hello_function(ctxt->session,
677            mgs_select_virtual_server_cb);
678
679    mgs_cache_session_init(ctxt);
680
681    return ctxt;
682}
683
684int mgs_hook_pre_connection(conn_rec * c, void *csd) {
685    mgs_handle_t *ctxt;
686    mgs_srvconf_rec *sc;
687
688    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
689
690    if (c == NULL) {
691        return DECLINED;
692    }
693
694    sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
695            module_config,
696            &gnutls_module);
697
698    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
699        return DECLINED;
700    }
701
702    if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip, c->local_ip) == 0) {
703        /* Connection initiated by Apache (mod_proxy) => ignore */
704        return OK;
705    }
706
707    ctxt = create_gnutls_handle(c->pool, c);
708
709    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
710
711    gnutls_transport_set_pull_function(ctxt->session,
712            mgs_transport_read);
713    gnutls_transport_set_push_function(ctxt->session,
714            mgs_transport_write);
715    gnutls_transport_set_ptr(ctxt->session, ctxt);
716
717    ctxt->input_filter =
718            ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
719    ctxt->output_filter =
720            ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
721
722    return OK;
723}
724
725int mgs_hook_fixups(request_rec * r) {
726    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
727    char buf[AP_IOBUFSIZE];
728    const char *tmp;
729    size_t len;
730    mgs_handle_t *ctxt;
731    int rv = OK;
732
733    if (r == NULL)
734        return DECLINED;
735
736    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
737    apr_table_t *env = r->subprocess_env;
738
739    ctxt =
740            ap_get_module_config(r->connection->conn_config,
741            &gnutls_module);
742
743    if (!ctxt || ctxt->session == NULL) {
744        return DECLINED;
745    }
746
747    apr_table_setn(env, "HTTPS", "on");
748
749    apr_table_setn(env, "SSL_VERSION_LIBRARY",
750            "GnuTLS/" LIBGNUTLS_VERSION);
751    apr_table_setn(env, "SSL_VERSION_INTERFACE",
752            "mod_gnutls/" MOD_GNUTLS_VERSION);
753
754    apr_table_setn(env, "SSL_PROTOCOL",
755            gnutls_protocol_get_name(gnutls_protocol_get_version
756            (ctxt->session)));
757
758    /* should have been called SSL_CIPHERSUITE instead */
759    apr_table_setn(env, "SSL_CIPHER",
760            gnutls_cipher_suite_get_name(gnutls_kx_get
761            (ctxt->session),
762            gnutls_cipher_get
763            (ctxt->session),
764            gnutls_mac_get
765            (ctxt->session)));
766
767    apr_table_setn(env, "SSL_COMPRESS_METHOD",
768            gnutls_compression_get_name(gnutls_compression_get
769            (ctxt->session)));
770
771#ifdef ENABLE_SRP
772    tmp = gnutls_srp_server_get_username(ctxt->session);
773    apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
774#endif
775
776    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
777        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
778
779    unsigned int key_size =
780            8 *
781            gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
782    tmp = apr_psprintf(r->pool, "%u", key_size);
783
784    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
785
786    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
787
788    apr_table_setn(env, "SSL_CIPHER_EXPORT",
789            (key_size <= 40) ? "true" : "false");
790
791    len = sizeof (sbuf);
792    gnutls_session_get_id(ctxt->session, sbuf, &len);
793    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
794    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
795
796    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
797        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
798            ctxt->
799            sc->export_certificates_enabled);
800    else if (gnutls_certificate_type_get(ctxt->session) ==
801            GNUTLS_CRT_OPENPGP)
802        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
803            ctxt->
804            sc->export_certificates_enabled);
805
806    return rv;
807}
808
809int mgs_hook_authz(request_rec * r) {
810    int rv;
811    mgs_handle_t *ctxt;
812    mgs_dirconf_rec *dc;
813
814    if (r == NULL)
815        return DECLINED;
816
817    dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
818
819    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
820    ctxt =
821            ap_get_module_config(r->connection->conn_config,
822            &gnutls_module);
823
824    if (!ctxt || ctxt->session == NULL) {
825        return DECLINED;
826    }
827
828    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
829        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
830                "GnuTLS: Directory set to Ignore Client Certificate!");
831    } else {
832        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
833            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
834                    "GnuTLS: Attempting to rehandshake with peer. %d %d",
835                    ctxt->sc->client_verify_mode,
836                    dc->client_verify_mode);
837
838            /* If we already have a client certificate, there's no point in
839             * re-handshaking... */
840            rv = mgs_cert_verify(r, ctxt);
841            if (rv != DECLINED && rv != HTTP_FORBIDDEN)
842                return rv;
843
844            gnutls_certificate_server_set_request
845                    (ctxt->session, dc->client_verify_mode);
846
847            if (mgs_rehandshake(ctxt) != 0) {
848                return HTTP_FORBIDDEN;
849            }
850        } else if (ctxt->sc->client_verify_mode ==
851                GNUTLS_CERT_IGNORE) {
852#if MOD_GNUTLS_DEBUG
853            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
854                    "GnuTLS: Peer is set to IGNORE");
855#endif
856            return DECLINED;
857        }
858        rv = mgs_cert_verify(r, ctxt);
859        if (rv != DECLINED &&
860                (rv != HTTP_FORBIDDEN ||
861                dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
862            return rv;
863        }
864    }
865
866    return DECLINED;
867}
868
869/* variables that are not sent by default:
870 *
871 * SSL_CLIENT_CERT      string  PEM-encoded client certificate
872 * SSL_SERVER_CERT      string  PEM-encoded client certificate
873 */
874
875/* side is either 0 for SERVER or 1 for CLIENT
876 */
877#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
878
879static void
880mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
881        int export_certificates_enabled) {
882    unsigned char sbuf[64]; /* buffer to hold serials */
883    char buf[AP_IOBUFSIZE];
884    const char *tmp;
885    char *tmp2;
886    size_t len;
887    int ret, i;
888
889    if (r == NULL)
890        return;
891
892    apr_table_t *env = r->subprocess_env;
893
894    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
895    if (export_certificates_enabled != 0) {
896        char cert_buf[10 * 1024];
897        len = sizeof (cert_buf);
898
899        if (gnutls_x509_crt_export
900                (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
901            apr_table_setn(env,
902                apr_pstrcat(r->pool, MGS_SIDE,
903                "_CERT", NULL),
904                apr_pstrmemdup(r->pool, cert_buf,
905                len));
906
907    }
908
909    len = sizeof (buf);
910    gnutls_x509_crt_get_dn(cert, buf, &len);
911    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
912            apr_pstrmemdup(r->pool, buf, len));
913
914    len = sizeof (buf);
915    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
916    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
917            apr_pstrmemdup(r->pool, buf, len));
918
919    len = sizeof (sbuf);
920    gnutls_x509_crt_get_serial(cert, sbuf, &len);
921    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
922    apr_table_setn(env,
923            apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
924            apr_pstrdup(r->pool, tmp));
925
926    ret = gnutls_x509_crt_get_version(cert);
927    if (ret > 0)
928        apr_table_setn(env,
929            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
930            NULL), apr_psprintf(r->pool,
931            "%u", ret));
932
933    apr_table_setn(env,
934            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
935            "X.509");
936
937    tmp =
938            mgs_time2sz(gnutls_x509_crt_get_expiration_time
939            (cert), buf, sizeof (buf));
940    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
941            apr_pstrdup(r->pool, tmp));
942
943    tmp =
944            mgs_time2sz(gnutls_x509_crt_get_activation_time
945            (cert), buf, sizeof (buf));
946    apr_table_setn(env,
947            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
948            apr_pstrdup(r->pool, tmp));
949
950    ret = gnutls_x509_crt_get_signature_algorithm(cert);
951    if (ret >= 0) {
952        apr_table_setn(env,
953                apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
954                NULL),
955                gnutls_sign_algorithm_get_name(ret));
956    }
957
958    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
959    if (ret >= 0) {
960        apr_table_setn(env,
961                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
962                NULL),
963                gnutls_pk_algorithm_get_name(ret));
964    }
965
966    /* export all the alternative names (DNS, RFC822 and URI) */
967    for (i = 0; !(ret < 0); i++) {
968        len = 0;
969        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
970                NULL, &len,
971                NULL);
972
973        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
974            tmp2 = apr_palloc(r->pool, len + 1);
975
976            ret =
977                    gnutls_x509_crt_get_subject_alt_name(cert, i,
978                    tmp2,
979                    &len,
980                    NULL);
981            tmp2[len] = 0;
982
983            if (ret == GNUTLS_SAN_DNSNAME) {
984                apr_table_setn(env,
985                        apr_psprintf(r->pool,
986                        "%s_S_AN%u",
987                        MGS_SIDE, i),
988                        apr_psprintf(r->pool,
989                        "DNSNAME:%s",
990                        tmp2));
991            } else if (ret == GNUTLS_SAN_RFC822NAME) {
992                apr_table_setn(env,
993                        apr_psprintf(r->pool,
994                        "%s_S_AN%u",
995                        MGS_SIDE, i),
996                        apr_psprintf(r->pool,
997                        "RFC822NAME:%s",
998                        tmp2));
999            } else if (ret == GNUTLS_SAN_URI) {
1000                apr_table_setn(env,
1001                        apr_psprintf(r->pool,
1002                        "%s_S_AN%u",
1003                        MGS_SIDE, i),
1004                        apr_psprintf(r->pool,
1005                        "URI:%s",
1006                        tmp2));
1007            } else {
1008                apr_table_setn(env,
1009                        apr_psprintf(r->pool,
1010                        "%s_S_AN%u",
1011                        MGS_SIDE, i),
1012                        "UNSUPPORTED");
1013            }
1014        }
1015    }
1016}
1017
1018static void
1019mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
1020        int side, int export_certificates_enabled) {
1021    unsigned char sbuf[64]; /* buffer to hold serials */
1022    char buf[AP_IOBUFSIZE];
1023    const char *tmp;
1024    size_t len;
1025    int ret;
1026
1027    if (r == NULL)
1028        return;
1029
1030    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1031    apr_table_t *env = r->subprocess_env;
1032
1033    if (export_certificates_enabled != 0) {
1034        char cert_buf[10 * 1024];
1035        len = sizeof (cert_buf);
1036
1037        if (gnutls_openpgp_crt_export
1038                (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
1039            apr_table_setn(env,
1040                apr_pstrcat(r->pool, MGS_SIDE,
1041                "_CERT", NULL),
1042                apr_pstrmemdup(r->pool, cert_buf,
1043                len));
1044
1045    }
1046
1047    len = sizeof (buf);
1048    gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
1049    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
1050            apr_pstrmemdup(r->pool, buf, len));
1051
1052    len = sizeof (sbuf);
1053    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
1054    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
1055    apr_table_setn(env,
1056            apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
1057            NULL), apr_pstrdup(r->pool, tmp));
1058
1059    ret = gnutls_openpgp_crt_get_version(cert);
1060    if (ret > 0)
1061        apr_table_setn(env,
1062            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
1063            NULL), apr_psprintf(r->pool,
1064            "%u", ret));
1065
1066    apr_table_setn(env,
1067            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
1068            "OPENPGP");
1069
1070    tmp =
1071            mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
1072            (cert), buf, sizeof (buf));
1073    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
1074            apr_pstrdup(r->pool, tmp));
1075
1076    tmp =
1077            mgs_time2sz(gnutls_openpgp_crt_get_creation_time
1078            (cert), buf, sizeof (buf));
1079    apr_table_setn(env,
1080            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
1081            apr_pstrdup(r->pool, tmp));
1082
1083    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
1084    if (ret >= 0) {
1085        apr_table_setn(env,
1086                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
1087                NULL),
1088                gnutls_pk_algorithm_get_name(ret));
1089    }
1090
1091}
1092
1093/* TODO: Allow client sending a X.509 certificate chain */
1094static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) {
1095    const gnutls_datum_t *cert_list;
1096    unsigned int cert_list_size, status;
1097    int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
1098    unsigned int ch_size = 0;
1099
1100    union {
1101        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
1102        gnutls_openpgp_crt_t pgp;
1103    } cert;
1104    apr_time_t expiration_time, cur_time;
1105
1106    if (r == NULL || ctxt == NULL || ctxt->session == NULL)
1107        return HTTP_FORBIDDEN;
1108
1109    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1110    cert_list =
1111            gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
1112
1113    if (cert_list == NULL || cert_list_size == 0) {
1114        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
1115         */
1116        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1117            return OK;
1118
1119        /* no certificate provided by the client, but one was required. */
1120        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1121                "GnuTLS: Failed to Verify Peer: "
1122                "Client did not submit a certificate");
1123        return HTTP_FORBIDDEN;
1124    }
1125
1126    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
1127        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1128                "GnuTLS: A Chain of %d certificate(s) was provided for validation",
1129                cert_list_size);
1130
1131        for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
1132            gnutls_x509_crt_init(&cert.x509[ch_size]);
1133            rv = gnutls_x509_crt_import(cert.x509[ch_size],
1134                    &cert_list[ch_size],
1135                    GNUTLS_X509_FMT_DER);
1136            // When failure to import, leave the loop
1137            if (rv != GNUTLS_E_SUCCESS) {
1138                if (ch_size < 1) {
1139                    ap_log_rerror(APLOG_MARK,
1140                            APLOG_INFO, 0, r,
1141                            "GnuTLS: Failed to Verify Peer: "
1142                            "Failed to import peer certificates.");
1143                    ret = HTTP_FORBIDDEN;
1144                    goto exit;
1145                }
1146                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1147                        "GnuTLS: Failed to import some peer certificates. Using %d certificates",
1148                        ch_size);
1149                rv = GNUTLS_E_SUCCESS;
1150                break;
1151            }
1152        }
1153    } else if (gnutls_certificate_type_get(ctxt->session) ==
1154            GNUTLS_CRT_OPENPGP) {
1155        if (cert_list_size > 1) {
1156            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1157                    "GnuTLS: Failed to Verify Peer: "
1158                    "Chained Client Certificates are not supported.");
1159            return HTTP_FORBIDDEN;
1160        }
1161
1162        gnutls_openpgp_crt_init(&cert.pgp);
1163        rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
1164                GNUTLS_OPENPGP_FMT_RAW);
1165
1166    } else
1167        return HTTP_FORBIDDEN;
1168
1169    if (rv < 0) {
1170        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1171                "GnuTLS: Failed to Verify Peer: "
1172                "Failed to import peer certificates.");
1173        ret = HTTP_FORBIDDEN;
1174        goto exit;
1175    }
1176
1177    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
1178        apr_time_ansi_put(&expiration_time,
1179                gnutls_x509_crt_get_expiration_time
1180                (cert.x509[0]));
1181
1182        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1183                "GnuTLS: Verifying list of  %d certificate(s)",
1184                ch_size);
1185        rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
1186                ctxt->sc->ca_list,
1187                ctxt->sc->ca_list_size,
1188                NULL, 0, 0, &status);
1189    } else {
1190        apr_time_ansi_put(&expiration_time,
1191                gnutls_openpgp_crt_get_expiration_time
1192                (cert.pgp));
1193
1194        rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
1195                ctxt->sc->pgp_list, 0,
1196                &status);
1197    }
1198
1199    if (rv < 0) {
1200        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1201                "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
1202                rv, gnutls_strerror(rv));
1203        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
1204            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
1205                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
1206        ret = HTTP_FORBIDDEN;
1207        goto exit;
1208    }
1209
1210    /* TODO: X509 CRL Verification. */
1211    /* May add later if anyone needs it.
1212     */
1213    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
1214
1215    cur_time = apr_time_now();
1216
1217    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1218        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1219                "GnuTLS: Could not find Signer for Peer Certificate");
1220    }
1221
1222    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
1223        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1224                "GnuTLS: Peer's Certificate signer is not a CA");
1225    }
1226
1227    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1228        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1229                "GnuTLS: Peer's Certificate is using insecure algorithms");
1230    }
1231
1232    if (status & GNUTLS_CERT_EXPIRED
1233            || status & GNUTLS_CERT_NOT_ACTIVATED) {
1234        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1235                "GnuTLS: Peer's Certificate signer is expired or not yet activated");
1236    }
1237
1238    if (status & GNUTLS_CERT_INVALID) {
1239        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1240                "GnuTLS: Peer Certificate is invalid.");
1241    } else if (status & GNUTLS_CERT_REVOKED) {
1242        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1243                "GnuTLS: Peer Certificate is revoked.");
1244    }
1245
1246    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
1247        mgs_add_common_cert_vars(r, cert.x509[0], 1,
1248            ctxt->
1249            sc->export_certificates_enabled);
1250    else if (gnutls_certificate_type_get(ctxt->session) ==
1251            GNUTLS_CRT_OPENPGP)
1252        mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
1253            ctxt->
1254            sc->export_certificates_enabled);
1255
1256    {
1257        /* days remaining */
1258        unsigned long remain =
1259                (apr_time_sec(expiration_time) -
1260                apr_time_sec(cur_time)) / 86400;
1261        apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
1262                apr_psprintf(r->pool, "%lu", remain));
1263    }
1264
1265    if (status == 0) {
1266        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
1267                "SUCCESS");
1268        ret = OK;
1269    } else {
1270        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
1271                "FAILED");
1272        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1273            ret = OK;
1274        else
1275            ret = HTTP_FORBIDDEN;
1276    }
1277
1278exit:
1279    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
1280        int i;
1281        for (i = 0; i < ch_size; i++) {
1282            gnutls_x509_crt_deinit(cert.x509[i]);
1283        }
1284    } else if (gnutls_certificate_type_get(ctxt->session) ==
1285            GNUTLS_CRT_OPENPGP)
1286        gnutls_openpgp_crt_deinit(cert.pgp);
1287    return ret;
1288
1289
1290}
Note: See TracBrowser for help on using the repository browser.