source: mod_gnutls/src/gnutls_hooks.c @ 8985a6b

debian/masterdebian/stretch-backportsjessie-backportsmsvaupstream
Last change on this file since 8985a6b was 8985a6b, checked in by Daniel Kahn Gillmor <dkg@…>, 7 years ago

allow certificate use for clients without SNI

The test removed here causes certificate lookup to fail if the client
offers no SNI. Many TLS clients cannot (or do not wish to) offer SNI,
and most TLS clients refuse to proceed with the handshake if the
server does not offer a certificate.

This enables mod_gnutls to work for all such clients (and resolves
tests/04_basic_nosni)

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