From 42307a9120b12fa5eb6fe1b316ef521ae46dbeb9 Mon Sep 17 00:00:00 2001 From: Paul Querna Date: Wed, 6 Apr 2005 04:52:25 +0000 Subject: - remove anno creds - initial attempt at Server Name Extension - change to adding 'mod_gnutls' to the server sig instead of GnuTLS/ - fix for EOF/EOC/EOS buckets - 'general' code cleanups --- src/gnutls_cache.c | 153 +++++++++++++++++++++++++++++++++++++++++------------ src/gnutls_io.c | 99 +++++++++++++++++++++++++--------- src/mod_gnutls.c | 52 +++++++++++++++--- 3 files changed, 237 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/gnutls_cache.c b/src/gnutls_cache.c index 868568b..91e6ec9 100644 --- a/src/gnutls_cache.c +++ b/src/gnutls_cache.c @@ -32,15 +32,14 @@ #include "unixd.h" #endif -#define GNUTLS_SESSION_ID_STRING_LEN \ - ((GNUTLS_MAX_SESSION_ID + 1) * 2) + #define MC_TAG "mod_gnutls:" #define MC_TAG_LEN \ (sizeof(MC_TAG)) #define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN) static char *gnutls_session_id2sz(unsigned char *id, int idlen, - char *str, int strsize) + char *str, int strsize) { char *cp; int n; @@ -54,6 +53,21 @@ static char *gnutls_session_id2sz(unsigned char *id, int idlen, return str; } +char *mod_gnutls_session_id2sz(unsigned char *id, int idlen, + char *str, int strsize) +{ + char *cp; + int n; + + cp = str; + for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { + apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]); + cp += 2; + } + *cp = '\0'; + return str; +} + #if HAVE_APR_MEMCACHE @@ -103,13 +117,13 @@ int mc_cache_child_init(apr_pool_t *p, server_rec *s, apr_port_t port; rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p); - if(rv != APR_SUCCESS) { + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "[gnutls_cache] Failed to Parse Server: '%s'", split); return rv; } - if(host_str == NULL) { + if (host_str == NULL) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "[gnutls_cache] Failed to Parse Server, " "no hostname specified: '%s'", split); @@ -128,7 +142,7 @@ int mc_cache_child_init(apr_pool_t *p, server_rec *s, thread_limit, 600, &st); - if(rv != APR_SUCCESS) { + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "[gnutls_cache] Failed to Create Server: %s:%d", host_str, port); @@ -136,7 +150,7 @@ int mc_cache_child_init(apr_pool_t *p, server_rec *s, } rv = apr_memcache_add_server(mc, st); - if(rv != APR_SUCCESS) { + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "[gnutls_cache] Failed to Add Server: %s:%d", host_str, port); @@ -161,11 +175,11 @@ static int mc_cache_store(void* baton, gnutls_datum_t key, if(!strkey) return -1; - timeout = ctxt->sc->cache_timeout; + timeout = apr_time_sec(ctxt->sc->cache_timeout); - rv = apr_memcache_set(mc, strkey, data.data, data.size, timeout, 0); + rv = apr_memcache_set(mc, strkey, data.data, data.size, timeout, 0); - if(rv != APR_SUCCESS) { + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctxt->c->base_server, "[gnutls_cache] error setting key '%s' " @@ -187,14 +201,14 @@ static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key) gnutls_datum_t data = { NULL, 0 }; strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); - if(!strkey) { + if (!strkey) { return data; } rv = apr_memcache_getp(mc, ctxt->c->pool, strkey, &value, &value_len, NULL); - if(rv != APR_SUCCESS) { + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctxt->c->base_server, "[gnutls_cache] error fetching key '%s' ", @@ -229,7 +243,7 @@ static int mc_cache_delete(void* baton, gnutls_datum_t key) rv = apr_memcache_delete(mc, strkey, 0); - if(rv != APR_SUCCESS) { + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctxt->c->base_server, "[gnutls_cache] error deleting key '%s' ", @@ -248,18 +262,80 @@ static int dbm_cache_expire(mod_gnutls_handle_t *ctxt) { apr_status_t rv; apr_dbm_t *dbm; - - rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, - APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); + apr_datum_t *keylist; + apr_datum_t dbmkey; + apr_datum_t dbmval; + apr_time_t ex; + apr_time_t dtime; + apr_pool_t* spool; + int i = 0; + int keyidx = 0; + int should_delete = 0; + + apr_pool_create(&spool, ctxt->c->pool); + ex = apr_time_now(); + + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, APR_DBM_READONLY, + SSL_DBM_FILE_MODE, spool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ctxt->c->base_server, - "[gnutls_cache] error opening cache '%s'", + "[gnutls_cache] error opening cache searcher '%s'", ctxt->sc->cache_config); return -1; } + +#define KEYMAX 128 + + keylist = apr_palloc(spool, sizeof(dbmkey)*KEYMAX); + + apr_dbm_firstkey(dbm, &dbmkey); + while (dbmkey.dptr != NULL) { + apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (dbmval.dptr != NULL) { + if (dbmval.dsize >= sizeof(apr_time_t)) { + memcpy(&dtime, dbmval.dptr, sizeof(apr_time_t)); + if (dtime < ex) { + should_delete = 1; + } + } + else { + should_delete = 1; + } + + if (should_delete == 1) { + should_delete = 0; + keylist[keyidx].dptr = apr_palloc(spool, dbmkey.dsize) ; + memcpy(keylist[keyidx].dptr, dbmkey.dptr, dbmkey.dsize); + keylist[keyidx].dsize = dbmkey.dsize; + keyidx++; + if (keyidx == KEYMAX) { + break; + } + } + + } + apr_dbm_nextkey(dbm, &dbmkey); + } apr_dbm_close(dbm); + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, spool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error opening cache writer '%s'", + ctxt->sc->cache_config); + return -1; + } + + for (i = 0; i < keyidx; i++) { + apr_dbm_delete(dbm, keylist[i]); + } + + apr_dbm_close(dbm); + apr_pool_destroy(spool); + return 0; } @@ -275,6 +351,8 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key) dbmkey.dptr = key.data; dbmkey.dsize = key.size; + dbm_cache_expire(ctxt); + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); if (rv != APR_SUCCESS) { @@ -286,7 +364,7 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key) } rv = apr_dbm_fetch(dbm, dbmkey, &dbmval); - + if (rv != APR_SUCCESS) { apr_dbm_close(dbm); return data; @@ -296,15 +374,17 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key) apr_dbm_close(dbm); return data; } - - data.data = gnutls_malloc(dbmval.dsize - sizeof(apr_time_t)); - if (data.data == NULL) - return data; + apr_dbm_close(dbm); data.size = dbmval.dsize - sizeof(apr_time_t); + + data.data = gnutls_malloc(data.size); + if (data.data == NULL) { + return data; + } + memcpy(data.data, dbmval.dptr+sizeof(apr_time_t), data.size); - apr_dbm_close(dbm); return data; } @@ -316,18 +396,23 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key, apr_datum_t dbmval; mod_gnutls_handle_t *ctxt = baton; apr_status_t rv; - apr_time_t timeout; + apr_time_t expiry; dbmkey.dptr = (char *)key.data; dbmkey.dsize = key.size; /* create DBM value */ - dbmval.dsize = data.size; - dbmval.dptr = (char *)malloc(dbmval.dsize+sizeof(apr_time_t)); + dbmval.dsize = data.size + sizeof(apr_time_t); + dbmval.dptr = (char *)malloc(dbmval.dsize); + + expiry = apr_time_now() + ctxt->sc->cache_timeout; + memcpy((char *)dbmval.dptr, &expiry, sizeof(apr_time_t)); memcpy((char *)dbmval.dptr+sizeof(apr_time_t), data.data, data.size); + dbm_cache_expire(ctxt); + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); if (rv != APR_SUCCESS) { @@ -340,7 +425,7 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key, } rv = apr_dbm_store(dbm, dbmkey, dbmval); - + if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ctxt->c->base_server, @@ -368,6 +453,8 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key) dbmkey.dptr = (char *)key.data; dbmkey.dsize = key.size; + dbm_cache_expire(ctxt); + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); if (rv != APR_SUCCESS) { @@ -383,7 +470,7 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key) if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ctxt->c->base_server, - "[gnutls_cache] error storing in cache '%s'", + "[gnutls_cache] error deleting from cache '%s'", ctxt->sc->cache_config); apr_dbm_close(dbm); return -1; @@ -394,7 +481,7 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key) return 0; } -static int dbm_cache_child_init(apr_pool_t *p, server_rec *s, +static int dbm_cache_post_config(apr_pool_t *p, server_rec *s, mod_gnutls_srvconf_rec *sc) { apr_status_t rv; @@ -434,7 +521,7 @@ int mod_gnutls_cache_post_config(apr_pool_t *p, server_rec *s, mod_gnutls_srvconf_rec *sc) { if (sc->cache_type == mod_gnutls_cache_dbm) { - return dbm_cache_child_init(p, s, sc); + return dbm_cache_post_config(p, s, sc); } return 0; } @@ -457,7 +544,6 @@ int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s, int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt) { - printf("Type: %d Params: %s\n",ctxt->sc->cache_type, ctxt->sc->cache_config); if (ctxt->sc->cache_type == mod_gnutls_cache_dbm) { gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch); gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete); @@ -472,9 +558,6 @@ int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt) gnutls_db_set_ptr(ctxt->session, ctxt); } #endif - else { - assert(1); - /* No Session Cache is Available. Opps. */ - } + return 0; } diff --git a/src/gnutls_io.c b/src/gnutls_io.c index a44ba9c..f761f96 100644 --- a/src/gnutls_io.c +++ b/src/gnutls_io.c @@ -271,6 +271,22 @@ static apr_status_t gnutls_io_input_read(mod_gnutls_handle_t * ctxt, "GnuTLS: Error reading data. Client Requested a New Handshake." " (%d) '%s'", rc, gnutls_strerror(rc)); } + else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { + rc = gnutls_alert_get(ctxt->session); + ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, + ctxt->c->base_server, + "GnuTLS: Warning Alert From Client: " + " (%d) '%s'", rc, gnutls_alert_get_name(rc)); + } + else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { + rc = gnutls_alert_get(ctxt->session); + ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, + ctxt->c->base_server, + "GnuTLS: Fatal Alert From Client: " + "(%d) '%s'", rc, gnutls_alert_get_name(rc)); + ctxt->input_rc = APR_EGENERAL; + break; + } else { /* Some Other Error. Report it. Die. */ if(gnutls_error_is_fatal(rc)) { @@ -341,7 +357,7 @@ static apr_status_t gnutls_io_input_getline(mod_gnutls_handle_t * ctxt, static void gnutls_do_handshake(mod_gnutls_handle_t * ctxt) { int ret; - + int errcode; if (ctxt->status != 0) { return; } @@ -352,10 +368,10 @@ tryagain: if (ret < 0) { if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { - ret = gnutls_alert_get(ctxt->session); + errcode = gnutls_alert_get(ctxt->session); ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server, - "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret, - gnutls_alert_get_name(ret)); + "GnuTLS: Hanshake Alert (%d) '%s'.", errcode, + gnutls_alert_get_name(errcode)); } if (!gnutls_error_is_fatal(ret)) { @@ -398,7 +414,26 @@ apr_status_t mod_gnutls_filter_input(ap_filter_t* f, } if (ctxt->status == 0) { + char* server_name; + int server_type; + int data_len = 256; + gnutls_do_handshake(ctxt); + + /** + * Due to issues inside the GnuTLS API, we cannot currently do TLS 1.1 + * Server Name Indication. + */ + server_name = apr_palloc(ctxt->c->pool, data_len); + if (gnutls_server_name_get(ctxt->session, server_name, &data_len, &server_type, 0) == 0) { + if (server_type == GNUTLS_NAME_DNS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, + ctxt->c->base_server, + "GnuTLS: TLS 1.1 Server Name: " + "%s", server_name); + + } + } } if (ctxt->status < 0) { @@ -449,6 +484,7 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f, apr_bucket_brigade * bb) { apr_size_t ret; + apr_bucket* e; mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx; apr_status_t status = APR_SUCCESS; apr_read_type_e rblock = APR_NONBLOCK_READ; @@ -469,21 +505,34 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f, while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *bucket = APR_BRIGADE_FIRST(bb); if (AP_BUCKET_IS_EOC(bucket)) { + do { + ret = gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, + GNUTLS_A_CLOSE_NOTIFY); + } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + + apr_bucket_copy(bucket, &e); + APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e); + + if ((status = ap_pass_brigade(f->next, ctxt->output_bb)) != APR_SUCCESS) { + apr_brigade_cleanup(ctxt->output_bb); + return status; + } + apr_brigade_cleanup(ctxt->output_bb); gnutls_bye(ctxt->session, GNUTLS_SHUT_WR); gnutls_deinit(ctxt->session); - - if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { - return status; - } - break; + continue; } else if (APR_BUCKET_IS_FLUSH(bucket) || APR_BUCKET_IS_EOS(bucket)) { + apr_bucket_copy(bucket, &e); + APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e); if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { + apr_brigade_cleanup(ctxt->output_bb); return status; } - break; + apr_brigade_cleanup(ctxt->output_bb); + continue; } else { /* filter output */ @@ -628,9 +677,9 @@ static ssize_t write_flush(mod_gnutls_handle_t * ctxt) ctxt->output_rc = ap_pass_brigade(ctxt->output_filter->next, ctxt->output_bb); - /* create new brigade ready for next time through */ - ctxt->output_bb = - apr_brigade_create(ctxt->c->pool, ctxt->c->bucket_alloc); + /* clear the brigade to be ready for next time */ + apr_brigade_cleanup(ctxt->output_bb); + return (ctxt->output_rc == APR_SUCCESS) ? 1 : -1; } @@ -639,19 +688,17 @@ ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr, { mod_gnutls_handle_t *ctxt = ptr; - /* pass along the encrypted data - * need to flush since we're using SSL's malloc-ed buffer - * which will be overwritten once we leave here - */ - apr_bucket *bucket = apr_bucket_transient_create(buffer, len, - ctxt->output_bb-> - bucket_alloc); - - ctxt->output_length += len; - APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, bucket); + /* pass along the encrypted data + * need to flush since we're using SSL's malloc-ed buffer + * which will be overwritten once we leave here + */ + apr_bucket *bucket = apr_bucket_transient_create(buffer, len, + ctxt->output_bb->bucket_alloc); + ctxt->output_length += len; + APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, bucket); - if (write_flush(ctxt) < 0) { - return -1; - } + if (write_flush(ctxt) < 0) { + return -1; + } return len; } diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index edf7068..b803ce7 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c @@ -189,6 +189,7 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, sc->cache_config = sc_base->cache_config; if (sc->cert_file != NULL && sc->key_file != NULL) { + rv = gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file, sc->key_file, GNUTLS_X509_FMT_PEM); @@ -214,7 +215,7 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, } } /* first_run */ - ap_add_version_component(p, "GnuTLS/" LIBGNUTLS_VERSION); + ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); return OK; } @@ -266,6 +267,30 @@ static apr_port_t mod_gnutls_hook_default_port(const request_rec * r) return 443; } +/* TODO: Complete support for Server Name Indication */ +static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) +{ + char* server_name; + int server_type; + int data_len = 256; + mod_gnutls_handle_t *ctxt; + ctxt = gnutls_transport_get_ptr(session); + + ret->type = GNUTLS_CRT_X509; + ret->ncerts = 1; + server_name = apr_palloc(ctxt->c->pool, data_len); + if (gnutls_server_name_get(ctxt->session, server_name, &data_len, &server_type, 0) == 0) { + if (server_type == GNUTLS_NAME_DNS) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, + ctxt->c->base_server, + "GnuTLS: Virtual Host: " + "%s", server_name); + } + } + + return 0; +} + static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c) { mod_gnutls_handle_t *ctxt; @@ -299,13 +324,12 @@ static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c) gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs); -// if(anon) { -// gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON, sc->anoncred); -// } - gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE); mod_gnutls_cache_session_init(ctxt); + + /* TODO: Finish Support for Server Name Indication */ + /* gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn); */ return ctxt; } @@ -341,7 +365,10 @@ static int mod_gnutls_hook_pre_connection(conn_rec * c, void *csd) static int mod_gnutls_hook_fixups(request_rec *r) { + unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; + char buf[GNUTLS_SESSION_ID_STRING_LEN]; const char* tmp; + int len; mod_gnutls_handle_t *ctxt; apr_table_t *env = r->subprocess_env; @@ -352,17 +379,30 @@ static int mod_gnutls_hook_fixups(request_rec *r) } apr_table_setn(env, "HTTPS", "on"); + + apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION); + apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION); + apr_table_setn(env, "SSL_PROTOCOL", gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session))); + apr_table_setn(env, "SSL_CIPHER", gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session))); + apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); + tmp = apr_psprintf(r->pool, "%d", 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session))); apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); + apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); + len = sizeof(sbuf); + gnutls_session_get_id(ctxt->session, sbuf, &len); + tmp = mod_gnutls_session_id2sz(sbuf, len, buf, sizeof(buf)); + apr_table_setn(env, "SSL_SESSION_ID", tmp); + return OK; } @@ -384,6 +424,7 @@ static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> module_config, &gnutls_module); + sc->key_file = ap_server_root_relative(parms->pool, arg); return NULL; } @@ -508,7 +549,6 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) sc->enabled = GNUTLS_ENABLED_FALSE; gnutls_certificate_allocate_credentials(&sc->certs); - gnutls_anon_allocate_server_credentials(&sc->anoncred); sc->key_file = NULL; sc->cert_file = NULL; sc->cache_timeout = apr_time_from_sec(3600); -- cgit