aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--README43
-rwxr-xr-xautogen.sh30
-rw-r--r--configure.ac14
-rw-r--r--include/mod_gnutls.h.in45
-rw-r--r--src/Makefile.am3
-rw-r--r--src/gnutls_cache.c25
-rw-r--r--src/gnutls_config.c405
-rw-r--r--src/gnutls_hooks.c990
-rw-r--r--src/gnutls_io.c7
-rw-r--r--src/mod_gnutls.c30
11 files changed, 985 insertions, 610 deletions
diff --git a/Makefile.am b/Makefile.am
index 77f3b84..486b962 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,8 @@ EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \
4 m4/libgnutls.m4 m4/apr_memcache.m4 \ 4 m4/libgnutls.m4 m4/apr_memcache.m4 \
5 m4/apache_test.m4 m4/lua.m4 \ 5 m4/apache_test.m4 m4/lua.m4 \
6 include/mod_gnutls.h.in \ 6 include/mod_gnutls.h.in \
7 README \ 7 README README.ENV \
8 NOTICE LICENSE autogen.sh 8 NOTICE LICENSE autogen.sh
9 9
10SUBDIRS = src data 10SUBDIRS = src data
11ACLOCAL_AMFLAGS = -I m4 \ No newline at end of file
diff --git a/README b/README
index 557ba77..85418de 100644
--- a/README
+++ b/README
@@ -19,19 +19,20 @@ lift code and ideas directly from mod_ssl. Kudos to the original authors of mod_
19 19
20---------------------------- 20----------------------------
21 21
22Author: Paul Querna <chip force-elite.com 22Author: Paul Querna <chip force-elite.com>
23
24Heavily modified by Nikos Mavrogiannopoulos <nmav gnutls.org>
23 25
24License: Apache Software License v2.0. (see the LICENSE file for details) 26License: Apache Software License v2.0. (see the LICENSE file for details)
25 27
26Current Status: 28Current Status:
27- SSL and TLS connections with all popular browsers work! 29- SSL and TLS connections with all popular browsers work!
28- Sets some enviromental vars for scripts 30- Sets enviromental vars for scripts (compatible with mod_ssl vars)
29- Supports Memcached as a distributed SSL Session Cache 31- Supports Memcached as a distributed SSL Session Cache
30- Supports DBM as a local SSL Session Cache 32- Supports DBM as a local SSL Session Cache
31 33- Support for Server Name Indication
32Future Development:
33- Support for Server Name Indication (partial support is in, but disabled)
34- Support for Client Certificates 34- Support for Client Certificates
35- Support for TLS-SRP
35 36
36Basic Configuration: 37Basic Configuration:
37 38
@@ -58,3 +59,35 @@ GnuTLSCache dbm conf/gnutls_cache
58 # This is the Server Certificate. 59 # This is the Server Certificate.
59 GnuTLSCertificateFile conf/server.cert 60 GnuTLSCertificateFile conf/server.cert
60</VirtualHost> 61</VirtualHost>
62
63
64# a more advanced configuration
65GnuTLSCache dbm "/var/cache/www-tls-cache/cache"
66GnuTLSCacheTimeout 500
67GnuTLSProtocols TLS1.1 TLS1.0 SSL3.0
68NameVirtualHost 1.2.3.4:443
69
70<VirtualHost 1.2.3.4:443>
71 Servername server.com:443
72 GnuTLSEnable on
73 GnuTLSCiphers AES-128-CBC 3DES-CBC ARCFOUR-128
74 GnuTLSKeyExchangeAlgorithms RSA DHE-RSA DHE-DSS SRP SRP-RSA SRP-DSS
75 GnuTLSMACAlgorithms SHA1 MD5
76 GnuTLSCompressionMethods NULL
77# To export exactly the same environment variables as mod_ssl to CGI scripts.
78 GNUTLSExportCertificates on
79
80 GnuTLSCertificateFile /etc/apache2/server-cert.pem
81 GnuTLSKeyFile /etc/apache2/server-key.pem
82
83# To enable SRP you must have these files installed. Check the gnutls srptool.
84 GnuTLSSRPPasswdFile /etc/apache2/tpasswd
85 GnuTLSSRPPasswdConfFile /etc/apache2/tpasswd.conf
86
87# In order to verify client certificates. Other options to
88# GnuTLSClientVerify could be ignore or require. The GnuTLSClientCAFile
89# contains the CAs to verify client certificates.
90 GnuTLSClientVerify request
91 GnuTLSClientCAFile ca.pem
92 ...
93</VirtualHost>
diff --git a/autogen.sh b/autogen.sh
index dc16b29..742b2cc 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,9 +1,25 @@
1#!/bin/sh 1#!/bin/sh
2m4/buildconf.py \
3 --libtoolize \
4 --aclocal \
5 --automake \
6 --autoconf \
7 --autoheader
8 2
9rm -rf autom4te.cache 3if [ -z $ACLOCAL ]; then
4 ACLOCAL=aclocal
5fi
6if [ -z $AUTOCONF ]; then
7 AUTOCONF=autoconf
8fi
9if [ -z $AUTOHEADER ]; then
10 AUTOHEADER=autoheader
11fi
12if [ -z $AUTORECONF ]; then
13 AUTORECONF=autoreconf
14fi
15
16#rm -rf autom4te.cache
17$AUTORECONF -f -i
18#touch stamp-h.in
19
20for x in providers/*; do
21 if [ -e $x/autogen.sh ]; then
22 echo Generating Config files in $x
23 (cd $x; ./autogen.sh $*)
24 fi
25done
diff --git a/configure.ac b/configure.ac
index fb84c67..a9111aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,11 @@
1AC_INIT(mod_gnutls, 0.2.0) 1dnl
2AC_INIT(mod_gnutls, 0.4.0)
2OOO_CONFIG_NICE(config.nice) 3OOO_CONFIG_NICE(config.nice)
3MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION 4MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
4AC_PREREQ(2.53) 5AC_PREREQ(2.53)
5AC_CONFIG_SRCDIR([src/mod_gnutls.c]) 6AC_CONFIG_SRCDIR([src/mod_gnutls.c])
6AC_CONFIG_AUX_DIR(config) 7AC_CONFIG_AUX_DIR(config)
8
7OOO_MAINTAIN_MODE 9OOO_MAINTAIN_MODE
8AM_MAINTAINER_MODE 10AM_MAINTAINER_MODE
9AC_CANONICAL_TARGET 11AC_CANONICAL_TARGET
@@ -15,7 +17,7 @@ AC_SUBST(MOD_GNUTLS_VERSION)
15AC_PROG_CC 17AC_PROG_CC
16AC_PROG_LD 18AC_PROG_LD
17AC_PROG_INSTALL 19AC_PROG_INSTALL
18 20AC_PROG_LIBTOOL
19 21
20AP_VERSION=2.0.40 22AP_VERSION=2.0.40
21CHECK_APACHE(,$AP_VERSION, 23CHECK_APACHE(,$AP_VERSION,
@@ -23,13 +25,13 @@ CHECK_APACHE(,$AP_VERSION,
23 AC_MSG_ERROR([*** Apache version $AP_VERSION not found!]) 25 AC_MSG_ERROR([*** Apache version $AP_VERSION not found!])
24) 26)
25 27
26LIBTOOL="`${APR_CONFIG} --apr-libtool`" 28dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`"
27AC_SUBST(LIBTOOL) 29dnl AC_SUBST(LIBTOOL)
28 30
29MIN_TLS_VERSION=1.2.0 31MIN_TLS_VERSION=2.1.7
30CHECK_LIBGNUTLS($MIN_TLS_VERSION) 32CHECK_LIBGNUTLS($MIN_TLS_VERSION)
31 33
32CHECK_LUA() 34dnl CHECK_LUA()
33 35
34have_apr_memcache=0 36have_apr_memcache=0
35CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0]) 37CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0])
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in
index 3473bf1..11c35aa 100644
--- a/include/mod_gnutls.h.in
+++ b/include/mod_gnutls.h.in
@@ -76,24 +76,35 @@ typedef struct
76 apr_size_t lua_bytecode_len; 76 apr_size_t lua_bytecode_len;
77} mgs_dirconf_rec; 77} mgs_dirconf_rec;
78 78
79
80/* The maximum number of client CA certificates allowed.
81 */
82#define MAX_CA_CRTS 128
83#define MAX_CIPHERS 16
84
79typedef struct 85typedef struct
80{ 86{
81 gnutls_certificate_credentials_t certs; 87 gnutls_certificate_credentials_t certs;
88 gnutls_srp_server_credentials_t srp_creds;
89 gnutls_anon_server_credentials_t anon_creds;
82 char* cert_cn; 90 char* cert_cn;
83 gnutls_x509_crt_t cert_x509; 91 gnutls_x509_crt_t cert_x509;
84 gnutls_x509_privkey_t privkey_x509; 92 gnutls_x509_privkey_t privkey_x509;
85 int enabled; 93 int enabled;
86 int ciphers[16]; 94 /* whether to send the PEM encoded certificates
87 int key_exchange[16]; 95 * to CGIs
88 int macs[16]; 96 */
89 int protocol[16]; 97 int export_certificates_enabled;
90 int compression[16]; 98 gnutls_priority_t priorities;
91 int cert_types[16]; 99 int cache_timeout;
92 apr_time_t cache_timeout;
93 mgs_cache_e cache_type; 100 mgs_cache_e cache_type;
94 const char* cache_config; 101 const char* cache_config;
95 const char* rsa_params_file; 102 const char* rsa_params_file;
96 const char* dh_params_file; 103 const char* dh_params_file;
104 const char* srp_tpasswd_file;
105 const char* srp_tpasswd_conf_file;
106 gnutls_x509_crt_t ca_list[MAX_CA_CRTS];
107 unsigned int ca_list_size;
97 int client_verify_mode; 108 int client_verify_mode;
98} mgs_srvconf_rec; 109} mgs_srvconf_rec;
99 110
@@ -214,9 +225,25 @@ int mgs_cache_session_init(mgs_handle_t *ctxt);
214char *mgs_session_id2sz(unsigned char *id, int idlen, 225char *mgs_session_id2sz(unsigned char *id, int idlen,
215 char *str, int strsize); 226 char *str, int strsize);
216 227
228/**
229 * Convert a time_t into a Null Terminated String
230 * @param t time_t time
231 * @param str Location to store the Hex Encoded String
232 * @param strsize The Maximum Length that can be stored in str
233 */
234char *mgs_time2sz(time_t t, char *str, int strsize);
235
217 236
218/* Configuration Functions */ 237/* Configuration Functions */
219 238
239const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy,
240 const char *arg);
241const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
242 const char *arg);
243const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
244 const char *arg);
245const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
246 const char *arg);
220const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 247const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
221 const char *arg); 248 const char *arg);
222 249
@@ -237,6 +264,10 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
237 264
238const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 265const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
239 const char *arg); 266 const char *arg);
267const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
268 const char *arg);
269const char *mgs_set_priorities(cmd_parms * parms, void *dummy,
270 const char *arg);
240 271
241const char *mgs_set_require_section(cmd_parms *cmd, 272const char *mgs_set_require_section(cmd_parms *cmd,
242 void *mconfig, const char *arg); 273 void *mconfig, const char *arg);
diff --git a/src/Makefile.am b/src/Makefile.am
index 59c8909..93b217d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,7 @@
1CLEANFILES = .libs/libmod_gnutls *~ 1CLEANFILES = .libs/libmod_gnutls *~
2 2
3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c gnutls_lua.c 3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c
4#gnutls_lua.c
4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} ${LUA_CFLAGS} 5libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} ${LUA_CFLAGS}
5libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS} ${LUA_LIBS} 6libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS} ${LUA_LIBS}
6 7
diff --git a/src/gnutls_cache.c b/src/gnutls_cache.c
index 4c094fa..86b843e 100644
--- a/src/gnutls_cache.c
+++ b/src/gnutls_cache.c
@@ -38,6 +38,7 @@
38 (sizeof(MC_TAG)) 38 (sizeof(MC_TAG))
39#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN) 39#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
40 40
41#if 0
41static char *gnutls_session_id2sz(unsigned char *id, int idlen, 42static char *gnutls_session_id2sz(unsigned char *id, int idlen,
42 char *str, int strsize) 43 char *str, int strsize)
43{ 44{
@@ -52,6 +53,22 @@ static char *gnutls_session_id2sz(unsigned char *id, int idlen,
52 *cp = '\0'; 53 *cp = '\0';
53 return str; 54 return str;
54} 55}
56#endif
57
58#define CTIME "%b %d %k:%M:%S %Y %Z"
59char *mgs_time2sz(time_t in_time, char *str, int strsize)
60{
61 apr_time_exp_t vtm;
62 apr_size_t ret_size;
63 apr_time_t t;
64
65
66 apr_time_ansi_put (&t, in_time);
67 apr_time_exp_gmt (&vtm, t);
68 apr_strftime(str, &ret_size, strsize-1, CTIME, &vtm);
69
70 return str;
71}
55 72
56char *mgs_session_id2sz(unsigned char *id, int idlen, 73char *mgs_session_id2sz(unsigned char *id, int idlen,
57 char *str, int strsize) 74 char *str, int strsize)
@@ -349,11 +366,9 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
349 mgs_handle_t *ctxt = baton; 366 mgs_handle_t *ctxt = baton;
350 apr_status_t rv; 367 apr_status_t rv;
351 368
352 dbmkey.dptr = key.data; 369 dbmkey.dptr = (void*)key.data;
353 dbmkey.dsize = key.size; 370 dbmkey.dsize = key.size;
354 371
355 dbm_cache_expire(ctxt);
356
357 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 372 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
358 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); 373 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
359 if (rv != APR_SUCCESS) { 374 if (rv != APR_SUCCESS) {
@@ -412,6 +427,8 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key,
412 memcpy((char *)dbmval.dptr+sizeof(apr_time_t), 427 memcpy((char *)dbmval.dptr+sizeof(apr_time_t),
413 data.data, data.size); 428 data.data, data.size);
414 429
430 /* we expire dbm only on every store
431 */
415 dbm_cache_expire(ctxt); 432 dbm_cache_expire(ctxt);
416 433
417 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 434 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
@@ -454,8 +471,6 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key)
454 dbmkey.dptr = (char *)key.data; 471 dbmkey.dptr = (char *)key.data;
455 dbmkey.dsize = key.size; 472 dbmkey.dsize = key.size;
456 473
457 dbm_cache_expire(ctxt);
458
459 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 474 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
460 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); 475 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
461 if (rv != APR_SUCCESS) { 476 if (rv != APR_SUCCESS) {
diff --git a/src/gnutls_config.c b/src/gnutls_config.c
index d3879f1..cad078c 100644
--- a/src/gnutls_config.c
+++ b/src/gnutls_config.c
@@ -17,225 +17,275 @@
17 17
18#include "mod_gnutls.h" 18#include "mod_gnutls.h"
19 19
20static int load_datum_from_file(apr_pool_t* pool, 20static int load_datum_from_file(apr_pool_t * pool,
21 const char* file, 21 const char *file, gnutls_datum_t * data)
22 gnutls_datum_t* data)
23{ 22{
24 apr_file_t* fp; 23 apr_file_t *fp;
25 apr_finfo_t finfo; 24 apr_finfo_t finfo;
26 apr_status_t rv; 25 apr_status_t rv;
27 apr_size_t br = 0; 26 apr_size_t br = 0;
28 27
29 rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, 28 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, APR_OS_DEFAULT,
30 pool); 29 pool);
31 if (rv != APR_SUCCESS) { 30 if (rv != APR_SUCCESS) {
32 return rv; 31 return rv;
33 } 32 }
34 33
35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 34 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
36 35
37 if (rv != APR_SUCCESS) { 36 if (rv != APR_SUCCESS) {
38 return rv; 37 return rv;
39 } 38 }
40 39
41 data->data = apr_palloc(pool, finfo.size+1); 40 data->data = apr_palloc(pool, finfo.size + 1);
42 rv = apr_file_read_full(fp, data->data, finfo.size, &br); 41 rv = apr_file_read_full(fp, data->data, finfo.size, &br);
43 42
44 if (rv != APR_SUCCESS) { 43 if (rv != APR_SUCCESS) {
45 return rv; 44 return rv;
46 } 45 }
47 apr_file_close(fp); 46 apr_file_close(fp);
48 47
49 data->data[br] = '\0'; 48 data->data[br] = '\0';
50 data->size = br; 49 data->size = br;
51 50
52 return 0; 51 return 0;
53} 52}
54 53
54const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
55 const char *arg)
56{
57 mgs_srvconf_rec *sc =
58 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
59 module_config,
60 &gnutls_module);
61
62 sc->dh_params_file = ap_server_root_relative(parms->pool, arg);
63
64 return NULL;
65}
66
67const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
68 const char *arg)
69{
70 mgs_srvconf_rec *sc =
71 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
72 module_config,
73 &gnutls_module);
74
75 sc->rsa_params_file = ap_server_root_relative(parms->pool, arg);
76
77 return NULL;
78}
79
80
55const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 81const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
56 const char *arg) 82 const char *arg)
57{ 83{
58 int ret; 84 int ret;
59 gnutls_datum_t data; 85 gnutls_datum_t data;
60 const char* file; 86 const char *file;
61 apr_pool_t* spool; 87 apr_pool_t *spool;
62 mgs_srvconf_rec *sc = 88 mgs_srvconf_rec *sc =
63 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 89 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
64 module_config, 90 module_config,
65 &gnutls_module); 91 &gnutls_module);
66 apr_pool_create(&spool, parms->pool); 92 apr_pool_create(&spool, parms->pool);
67 93
68 file = ap_server_root_relative(spool, arg); 94 file = ap_server_root_relative(spool, arg);
69 95
70 if (load_datum_from_file(spool, file, &data) != 0) { 96 if (load_datum_from_file(spool, file, &data) != 0) {
71 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 97 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
72 "Certificate '%s'", file); 98 "Certificate '%s'", file);
73 } 99 }
74 100
75 gnutls_x509_crt_init(&sc->cert_x509); 101 gnutls_x509_crt_init(&sc->cert_x509);
76 ret = gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM); 102 ret =
103 gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM);
77 if (ret != 0) { 104 if (ret != 0) {
78 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " 105 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
79 "Certificate'%s': (%d) %s", file, ret, 106 "Certificate'%s': (%d) %s", file, ret,
80 gnutls_strerror(ret)); 107 gnutls_strerror(ret));
81 } 108 }
82 109
83 apr_pool_destroy(spool); 110 apr_pool_destroy(spool);
84 return NULL; 111 return NULL;
85} 112}
86 113
87const char *mgs_set_key_file(cmd_parms * parms, void *dummy, 114const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
88 const char *arg) 115 const char *arg)
89{ 116{
90 int ret; 117 int ret;
91 gnutls_datum_t data; 118 gnutls_datum_t data;
92 const char* file; 119 const char *file;
93 apr_pool_t* spool; 120 apr_pool_t *spool;
94 mgs_srvconf_rec *sc = 121 mgs_srvconf_rec *sc =
95 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 122 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
96 module_config, 123 module_config,
97 &gnutls_module); 124 &gnutls_module);
98 apr_pool_create(&spool, parms->pool); 125 apr_pool_create(&spool, parms->pool);
99 126
100 file = ap_server_root_relative(spool, arg); 127 file = ap_server_root_relative(spool, arg);
101 128
102 if (load_datum_from_file(spool, file, &data) != 0) { 129 if (load_datum_from_file(spool, file, &data) != 0) {
103 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 130 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
104 "Private Key '%s'", file); 131 "Private Key '%s'", file);
105 } 132 }
106 133
107 gnutls_x509_privkey_init(&sc->privkey_x509); 134 gnutls_x509_privkey_init(&sc->privkey_x509);
108 ret = gnutls_x509_privkey_import(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM); 135 ret =
136 gnutls_x509_privkey_import(sc->privkey_x509, &data,
137 GNUTLS_X509_FMT_PEM);
109 if (ret != 0) { 138 if (ret != 0) {
110 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " 139 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
111 "Private Key '%s': (%d) %s", file, ret, 140 "Private Key '%s': (%d) %s", file, ret,
112 gnutls_strerror(ret)); 141 gnutls_strerror(ret));
113 } 142 }
114 apr_pool_destroy(spool); 143 apr_pool_destroy(spool);
115 return NULL; 144 return NULL;
116} 145}
117 146
147const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
148 const char *arg)
149{
150 mgs_srvconf_rec *sc =
151 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
152 module_config,
153 &gnutls_module);
154
155 sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
156
157 return NULL;
158}
159
160const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy,
161 const char *arg)
162{
163 mgs_srvconf_rec *sc =
164 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
165 module_config,
166 &gnutls_module);
167
168 sc->srp_tpasswd_conf_file = ap_server_root_relative(parms->pool, arg);
169
170 return NULL;
171}
172
118const char *mgs_set_cache(cmd_parms * parms, void *dummy, 173const char *mgs_set_cache(cmd_parms * parms, void *dummy,
119 const char *type, const char* arg) 174 const char *type, const char *arg)
120{ 175{
121 const char* err; 176 const char *err;
122 mgs_srvconf_rec *sc = ap_get_module_config(parms->server-> 177 mgs_srvconf_rec *sc = ap_get_module_config(parms->server->
123 module_config, 178 module_config,
124 &gnutls_module); 179 &gnutls_module);
125 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 180 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
126 return err; 181 return err;
127 } 182 }
128 183
129 if (strcasecmp("none", type) == 0) { 184 if (strcasecmp("none", type) == 0) {
130 sc->cache_type = mgs_cache_none; 185 sc->cache_type = mgs_cache_none;
131 } 186 } else if (strcasecmp("dbm", type) == 0) {
132 else if (strcasecmp("dbm", type) == 0) { 187 sc->cache_type = mgs_cache_dbm;
133 sc->cache_type = mgs_cache_dbm;
134 } 188 }
135#if HAVE_APR_MEMCACHE 189#if HAVE_APR_MEMCACHE
136 else if (strcasecmp("memcache", type) == 0) { 190 else if (strcasecmp("memcache", type) == 0) {
137 sc->cache_type = mgs_cache_memcache; 191 sc->cache_type = mgs_cache_memcache;
138 } 192 }
139#endif 193#endif
140 else { 194 else {
141 return "Invalid Type for GnuTLSCache!"; 195 return "Invalid Type for GnuTLSCache!";
142 } 196 }
143 197
144 if (sc->cache_type == mgs_cache_dbm) { 198 if (sc->cache_type == mgs_cache_dbm) {
145 sc->cache_config = ap_server_root_relative(parms->pool, arg); 199 sc->cache_config = ap_server_root_relative(parms->pool, arg);
146 } 200 } else {
147 else { 201 sc->cache_config = apr_pstrdup(parms->pool, arg);
148 sc->cache_config = apr_pstrdup(parms->pool, arg);
149 } 202 }
150 203
151 return NULL; 204 return NULL;
152} 205}
153 206
154const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy, 207const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy,
155 const char *arg) 208 const char *arg)
156{ 209{
157 int argint; 210 int argint;
158 mgs_srvconf_rec *sc = 211 mgs_srvconf_rec *sc =
159 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 212 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
160 module_config, 213 module_config,
161 &gnutls_module); 214 &gnutls_module);
162 215
163 argint = atoi(arg); 216 argint = atoi(arg);
164 217
165 if (argint < 0) { 218 if (argint < 0) {
166 return "GnuTLSCacheTimeout: Invalid argument"; 219 return "GnuTLSCacheTimeout: Invalid argument";
167 } 220 } else if (argint == 0) {
168 else if (argint == 0) { 221 sc->cache_timeout = 0;
169 sc->cache_timeout = 0; 222 } else {
223 sc->cache_timeout = apr_time_from_sec(argint);
170 } 224 }
171 else { 225
172 sc->cache_timeout = apr_time_from_sec(argint);
173 }
174
175 return NULL; 226 return NULL;
176} 227}
177 228
178const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, 229const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
179 const char *arg) 230 const char *arg)
180{ 231{
181 int mode; 232 int mode;
182 233
183 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { 234 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
184 mode = GNUTLS_CERT_IGNORE; 235 mode = GNUTLS_CERT_IGNORE;
236 } else if (strcasecmp("optional", arg) == 0
237 || strcasecmp("request", arg) == 0) {
238 mode = GNUTLS_CERT_REQUEST;
239 } else if (strcasecmp("require", arg) == 0) {
240 mode = GNUTLS_CERT_REQUIRE;
241 } else {
242 return "GnuTLSClientVerify: Invalid argument";
185 } 243 }
186 else if (strcasecmp("optional", arg) == 0 || strcasecmp("request", arg) == 0) { 244
187 mode = GNUTLS_CERT_REQUEST;
188 }
189 else if (strcasecmp("require", arg) == 0) {
190 mode = GNUTLS_CERT_REQUIRE;
191 }
192 else {
193 return "GnuTLSClientVerify: Invalid argument";
194 }
195
196 /* This was set from a directory context */ 245 /* This was set from a directory context */
197 if (parms->path) { 246 if (parms->path) {
198 mgs_dirconf_rec *dc = (mgs_dirconf_rec *)dummy; 247 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
199 dc->client_verify_mode = mode; 248 dc->client_verify_mode = mode;
200 } 249 } else {
201 else { 250 mgs_srvconf_rec *sc =
202 mgs_srvconf_rec *sc = 251 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
203 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 252 module_config,
204 module_config, 253 &gnutls_module);
205 &gnutls_module); 254 sc->client_verify_mode = mode;
206 sc->client_verify_mode = mode;
207 } 255 }
208 256
209 return NULL; 257 return NULL;
210} 258}
211 259
212const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 260const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
213 const char *arg) 261 const char *arg)
214{ 262{
215 int rv; 263 int rv;
216 const char* file; 264 const char *file;
217 apr_pool_t* spool; 265 apr_pool_t *spool;
218 gnutls_datum_t data; 266 gnutls_datum_t data;
219 267
220 mgs_srvconf_rec *sc = 268 mgs_srvconf_rec *sc =
221 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 269 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
222 module_config, 270 module_config,
223 &gnutls_module); 271 &gnutls_module);
224 apr_pool_create(&spool, parms->pool); 272 apr_pool_create(&spool, parms->pool);
225 273
226 file = ap_server_root_relative(spool, arg); 274 file = ap_server_root_relative(spool, arg);
227 275
228 sc->ca_list_size = 16; 276 if (load_datum_from_file(spool, file, &data) != 0) {
229 277 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
230 load_datum_from_file(spool, file, &data); 278 "Client CA File '%s'", file);
279 }
231 280
232 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size, 281 sc->ca_list_size = MAX_CA_CRTS;
233 &data, GNUTLS_X509_FMT_PEM, 282 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
234 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); 283 &data, GNUTLS_X509_FMT_PEM,
284 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
235 if (rv < 0) { 285 if (rv < 0) {
236 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 286 return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
237 "Client CA File '%s': (%d) %s", file, rv, 287 "Client CA File '%s': (%d) %s", file, rv,
238 gnutls_strerror(rv)); 288 gnutls_strerror(rv));
239 } 289 }
240 290
241 apr_pool_destroy(spool); 291 apr_pool_destroy(spool);
@@ -243,20 +293,57 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
243} 293}
244 294
245const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 295const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
246 const char *arg) 296 const char *arg)
247{ 297{
248 mgs_srvconf_rec *sc = 298 mgs_srvconf_rec *sc =
249 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 299 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
250 module_config, 300 module_config,
251 &gnutls_module); 301 &gnutls_module);
252 if (!strcasecmp(arg, "On")) { 302 if (!strcasecmp(arg, "On")) {
253 sc->enabled = GNUTLS_ENABLED_TRUE; 303 sc->enabled = GNUTLS_ENABLED_TRUE;
304 } else if (!strcasecmp(arg, "Off")) {
305 sc->enabled = GNUTLS_ENABLED_FALSE;
306 } else {
307 return "GnuTLSEnable must be set to 'On' or 'Off'";
254 } 308 }
255 else if (!strcasecmp(arg, "Off")) { 309
256 sc->enabled = GNUTLS_ENABLED_FALSE; 310 return NULL;
311}
312
313const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
314 const char *arg)
315{
316 mgs_srvconf_rec *sc =
317 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
318 module_config,
319 &gnutls_module);
320 if (!strcasecmp(arg, "On")) {
321 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
322 } else if (!strcasecmp(arg, "Off")) {
323 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
324 } else {
325 return "GnuTLSExportCertificates must be set to 'On' or 'Off'";
257 } 326 }
258 else { 327
259 return "GnuTLSEnable must be set to 'On' or 'Off'"; 328 return NULL;
329}
330
331
332const char *mgs_set_priorities(cmd_parms * parms, void *dummy, const char *arg)
333{
334 int ret;
335 char *err;
336 mgs_srvconf_rec *sc =
337 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
338 module_config,
339 &gnutls_module);
340
341
342 ret = gnutls_priority_init( &sc->priorities, arg, &err);
343 if (ret < 0) {
344 if (ret == GNUTLS_E_INVALID_REQUEST)
345 return apr_psprintf(parms->pool, "GnuTLS: Syntax error parsing priorities string at: %s", err);
346 return "Error setting priorities";
260 } 347 }
261 348
262 return NULL; 349 return NULL;
@@ -264,92 +351,50 @@ const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
264 351
265void *mgs_config_server_create(apr_pool_t * p, server_rec * s) 352void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
266{ 353{
267 int i;
268 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc)); 354 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
269 355
270 sc->enabled = GNUTLS_ENABLED_FALSE; 356 sc->enabled = GNUTLS_ENABLED_FALSE;
271 357
272 gnutls_certificate_allocate_credentials(&sc->certs); 358 gnutls_certificate_allocate_credentials(&sc->certs);
359 gnutls_anon_allocate_server_credentials(&sc->anon_creds);
360 gnutls_srp_allocate_server_credentials(&sc->srp_creds);
361
362 sc->srp_tpasswd_conf_file = NULL;
363 sc->srp_tpasswd_file = NULL;
273 sc->privkey_x509 = NULL; 364 sc->privkey_x509 = NULL;
274 sc->cert_x509 = NULL; 365 sc->cert_x509 = NULL;
275 sc->cache_timeout = apr_time_from_sec(300); 366 sc->cache_timeout = apr_time_from_sec(300);
276 sc->cache_type = mgs_cache_dbm; 367 sc->cache_type = mgs_cache_dbm;
277 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 368 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
278 369
279 /* TODO: Make this Configurable. But it isn't configurable in mod_ssl? */
280 sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile"); 370 sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile");
281 sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile"); 371 sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile");
282 372
283 /* Finish SSL Client Certificate Support */
284 sc->client_verify_mode = GNUTLS_CERT_IGNORE; 373 sc->client_verify_mode = GNUTLS_CERT_IGNORE;
285 374
286 /* TODO: Make this Configurable ! */
287 /* mod_ssl uses a flex based parser for this part.. sigh */
288 i = 0;
289 sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC;
290 sc->ciphers[i++] = GNUTLS_CIPHER_AES_128_CBC;
291 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_128;
292 sc->ciphers[i++] = GNUTLS_CIPHER_3DES_CBC;
293 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_40;
294 sc->ciphers[i] = 0;
295
296 i = 0;
297 sc->key_exchange[i++] = GNUTLS_KX_RSA;
298 sc->key_exchange[i++] = GNUTLS_KX_RSA_EXPORT;
299 sc->key_exchange[i++] = GNUTLS_KX_DHE_DSS;
300 sc->key_exchange[i++] = GNUTLS_KX_DHE_RSA;
301 sc->key_exchange[i++] = GNUTLS_KX_ANON_DH;
302 sc->key_exchange[i++] = GNUTLS_KX_SRP;
303 sc->key_exchange[i++] = GNUTLS_KX_SRP_RSA;
304 sc->key_exchange[i++] = GNUTLS_KX_SRP_DSS;
305 sc->key_exchange[i] = 0;
306
307 i = 0;
308 sc->macs[i++] = GNUTLS_MAC_SHA;
309 sc->macs[i++] = GNUTLS_MAC_MD5;
310 sc->macs[i++] = GNUTLS_MAC_RMD160;
311 sc->macs[i] = 0;
312
313 i = 0;
314 sc->protocol[i++] = GNUTLS_TLS1_1;
315 sc->protocol[i++] = GNUTLS_TLS1;
316 sc->protocol[i++] = GNUTLS_SSL3;
317 sc->protocol[i] = 0;
318
319 i = 0;
320 sc->compression[i++] = GNUTLS_COMP_NULL;
321 sc->compression[i++] = GNUTLS_COMP_ZLIB;
322 sc->compression[i++] = GNUTLS_COMP_LZO;
323 sc->compression[i] = 0;
324
325 i = 0;
326 sc->cert_types[i++] = GNUTLS_CRT_X509;
327 sc->cert_types[i] = 0;
328
329 return sc; 375 return sc;
330} 376}
331 377
332void *mgs_config_dir_merge(apr_pool_t *p, void *basev, void *addv) 378void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv)
333{ 379{
334 mgs_dirconf_rec *new; 380 mgs_dirconf_rec *new;
335 mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; 381/* mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
336 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv; 382 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
337 383
338 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec)); 384 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
339 new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode, 385 new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode,
340 add->lua_bytecode_len); 386 add->lua_bytecode_len);
341 new->lua_bytecode_len = add->lua_bytecode_len; 387 new->lua_bytecode_len = add->lua_bytecode_len;
342 new->client_verify_mode = add->client_verify_mode; 388 new->client_verify_mode = add->client_verify_mode;
343 return new; 389 return new;
344} 390}
345 391
346void *mgs_config_dir_create(apr_pool_t *p, char *dir) 392void *mgs_config_dir_create(apr_pool_t * p, char *dir)
347{ 393{
348 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc)); 394 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
349 395
350 dc->client_verify_mode = -1; 396 dc->client_verify_mode = -1;
351 dc->lua_bytecode = NULL; 397 dc->lua_bytecode = NULL;
352 dc->lua_bytecode_len = 0; 398 dc->lua_bytecode_len = 0;
353 return dc; 399 return dc;
354} 400}
355
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c
index 8452d36..f776def 100644
--- a/src/gnutls_hooks.c
+++ b/src/gnutls_hooks.c
@@ -1,5 +1,6 @@
1/** 1/**
2 * Copyright 2004-2005 Paul Querna 2 * Copyright 2004-2005 Paul Querna
3 * Copyright 2007 Nikos Mavrogiannopoulos
3 * 4 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 6 * you may not use this file except in compliance with the License.
@@ -28,11 +29,16 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
28#endif 29#endif
29 30
30#if MOD_GNUTLS_DEBUG 31#if MOD_GNUTLS_DEBUG
31static apr_file_t* debug_log_fp; 32static apr_file_t *debug_log_fp;
32#endif 33#endif
33 34
34static int mpm_is_threaded; 35static int mpm_is_threaded;
35 36
37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
38/* use side==0 for server and side==1 for client */
39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert,
40 int side, int export_certificates_enabled);
41
36static apr_status_t mgs_cleanup_pre_config(void *data) 42static apr_status_t mgs_cleanup_pre_config(void *data)
37{ 43{
38 gnutls_global_deinit(); 44 gnutls_global_deinit();
@@ -40,20 +46,21 @@ static apr_status_t mgs_cleanup_pre_config(void *data)
40} 46}
41 47
42#if MOD_GNUTLS_DEBUG 48#if MOD_GNUTLS_DEBUG
43static void gnutls_debug_log_all( int level, const char* str) 49static void gnutls_debug_log_all(int level, const char *str)
44{ 50{
45 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str); 51 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
46} 52}
47#endif 53#endif
48 54
49int mgs_hook_pre_config(apr_pool_t * pconf, 55int
50 apr_pool_t * plog, apr_pool_t * ptemp) 56mgs_hook_pre_config(apr_pool_t * pconf,
57 apr_pool_t * plog, apr_pool_t * ptemp)
51{ 58{
52 59
53#if APR_HAS_THREADS 60#if APR_HAS_THREADS
54 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded); 61 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
55 if (mpm_is_threaded) { 62 if (mpm_is_threaded) {
56 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); 63 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
57 } 64 }
58#else 65#else
59 mpm_is_threaded = 0; 66 mpm_is_threaded = 0;
@@ -62,11 +69,12 @@ int mgs_hook_pre_config(apr_pool_t * pconf,
62 gnutls_global_init(); 69 gnutls_global_init();
63 70
64 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 71 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
65 apr_pool_cleanup_null); 72 apr_pool_cleanup_null);
66 73
67#if MOD_GNUTLS_DEBUG 74#if MOD_GNUTLS_DEBUG
68 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", 75 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
69 APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf); 76 APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
77 pconf);
70 78
71 gnutls_global_set_log_level(9); 79 gnutls_global_set_log_level(9);
72 gnutls_global_set_log_function(gnutls_debug_log_all); 80 gnutls_global_set_log_function(gnutls_debug_log_all);
@@ -76,38 +84,38 @@ int mgs_hook_pre_config(apr_pool_t * pconf,
76} 84}
77 85
78 86
79static gnutls_datum load_params(const char* file, server_rec* s, 87static gnutls_datum
80 apr_pool_t* pool) 88load_params(const char *file, server_rec * s, apr_pool_t * pool)
81{ 89{
82 gnutls_datum ret = { NULL, 0 }; 90 gnutls_datum ret = { NULL, 0 };
83 apr_file_t* fp; 91 apr_file_t *fp;
84 apr_finfo_t finfo; 92 apr_finfo_t finfo;
85 apr_status_t rv; 93 apr_status_t rv;
86 apr_size_t br = 0; 94 apr_size_t br = 0;
87 95
88 rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, 96 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, APR_OS_DEFAULT,
89 pool); 97 pool);
90 if (rv != APR_SUCCESS) { 98 if (rv != APR_SUCCESS) {
91 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 99 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
92 "GnuTLS failed to load params file at: %s", file); 100 "GnuTLS failed to load params file at: %s. Will use internal params.", file);
93 return ret; 101 return ret;
94 } 102 }
95 103
96 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 104 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
97 105
98 if (rv != APR_SUCCESS) { 106 if (rv != APR_SUCCESS) {
99 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 107 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
100 "GnuTLS failed to stat params file at: %s", file); 108 "GnuTLS failed to stat params file at: %s", file);
101 return ret; 109 return ret;
102 } 110 }
103 111
104 ret.data = apr_palloc(pool, finfo.size+1); 112 ret.data = apr_palloc(pool, finfo.size + 1);
105 rv = apr_file_read_full(fp, ret.data, finfo.size, &br); 113 rv = apr_file_read_full(fp, ret.data, finfo.size, &br);
106 114
107 if (rv != APR_SUCCESS) { 115 if (rv != APR_SUCCESS) {
108 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 116 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
109 "GnuTLS failed to read params file at: %s", file); 117 "GnuTLS failed to read params file at: %s", file);
110 return ret; 118 return ret;
111 } 119 }
112 apr_file_close(fp); 120 apr_file_close(fp);
113 ret.data[br] = '\0'; 121 ret.data[br] = '\0';
@@ -116,12 +124,89 @@ static gnutls_datum load_params(const char* file, server_rec* s,
116 return ret; 124 return ret;
117} 125}
118 126
119int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 127/* We don't support openpgp certificates, yet */
120 apr_pool_t * ptemp, 128const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
121 server_rec * base_server) 129
130static int mgs_select_virtual_server_cb( gnutls_session_t session)
131{
132 mgs_handle_t *ctxt;
133 mgs_srvconf_rec *tsc;
134 int ret;
135
136 ctxt = gnutls_transport_get_ptr(session);
137
138 /* find the virtual server */
139 tsc = mgs_find_sni_server(session);
140
141 if (tsc != NULL)
142 ctxt->sc = tsc;
143
144 gnutls_certificate_server_set_request(session,
145 ctxt->sc->client_verify_mode);
146
147 /* set the new server credentials
148 */
149
150 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
151 ctxt->sc->certs);
152
153 gnutls_credentials_set(session, GNUTLS_CRD_ANON,
154 ctxt->sc->anon_creds);
155
156 if ( ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
157 gnutls_credentials_set(session, GNUTLS_CRD_SRP,
158 ctxt->sc->srp_creds);
159 }
160
161 /* update the priorities - to avoid negotiating a ciphersuite that is not
162 * enabled on this virtual server. Note that here we ignore the version
163 * negotiation.
164 */
165 ret = gnutls_priority_set( session, ctxt->sc->priorities);
166 gnutls_certificate_type_set_priority( session, cert_type_prio);
167
168
169 /* actually it shouldn't fail since we have checked at startup */
170 if (ret < 0) return ret;
171
172 /* allow separate caches per virtual host. Actually allowing the same is not
173 * a good idea, especially if they have different security requirements.
174 */
175 mgs_cache_session_init(ctxt);
176
177 return 0;
178}
179
180static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
181{
182 mgs_handle_t *ctxt;
183
184 ctxt = gnutls_transport_get_ptr(session);
185
186 ret->type = GNUTLS_CRT_X509;
187 ret->ncerts = 1;
188 ret->deinit_all = 0;
189
190 ret->cert.x509 = &ctxt->sc->cert_x509;
191 ret->key.x509 = ctxt->sc->privkey_x509;
192 return 0;
193}
194
195const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
196"MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
197"gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
198"KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
199"dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
200"YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
201"Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
202"-----END DH PARAMETERS-----\n";
203
204int
205mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
206 apr_pool_t * ptemp, server_rec * base_server)
122{ 207{
123 int rv; 208 int rv;
124 int data_len; 209 size_t data_len;
125 server_rec *s; 210 server_rec *s;
126 gnutls_dh_params_t dh_params; 211 gnutls_dh_params_t dh_params;
127 gnutls_rsa_params_t rsa_params; 212 gnutls_rsa_params_t rsa_params;
@@ -130,118 +215,140 @@ int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
130 void *data = NULL; 215 void *data = NULL;
131 int first_run = 0; 216 int first_run = 0;
132 const char *userdata_key = "mgs_init"; 217 const char *userdata_key = "mgs_init";
133 218
134 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool); 219 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
135 if (data == NULL) { 220 if (data == NULL) {
136 first_run = 1; 221 first_run = 1;
137 apr_pool_userdata_set((const void *)1, userdata_key, 222 apr_pool_userdata_set((const void *) 1, userdata_key,
138 apr_pool_cleanup_null, 223 apr_pool_cleanup_null,
139 base_server->process->pool); 224 base_server->process->pool);
140 } 225 }
141 226
142 227
143 { 228 {
144 gnutls_datum pdata; 229 gnutls_datum pdata;
145 apr_pool_t* tpool; 230 apr_pool_t *tpool;
146 s = base_server; 231 s = base_server;
147 sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 232 sc_base =
148 &gnutls_module); 233 (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
149 234 &gnutls_module);
150 apr_pool_create(&tpool, p); 235
151 236 apr_pool_create(&tpool, p);
152 gnutls_dh_params_init(&dh_params); 237
153 238 gnutls_dh_params_init(&dh_params);
154 pdata = load_params(sc_base->dh_params_file, s, tpool); 239
155 240 pdata = load_params(sc_base->dh_params_file, s, tpool);
156 if (pdata.size != 0) { 241
157 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 242 if (pdata.size != 0) {
158 GNUTLS_X509_FMT_PEM); 243 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
159 if (rv != 0) { 244 GNUTLS_X509_FMT_PEM);
160 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 245 if (rv != 0) {
161 "GnuTLS: Unable to load DH Params: (%d) %s", 246 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
162 rv, gnutls_strerror(rv)); 247 "GnuTLS: Unable to load DH Params: (%d) %s",
163 exit(rv); 248 rv, gnutls_strerror(rv));
164 } 249 exit(rv);
165 } 250 }
166 else { 251 } else {
167 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 252 /* If the file does not exist use internal parameters
168 "GnuTLS: Unable to load DH Params." 253 */
169 " Shutting Down."); 254 pdata.data = (void*)static_dh_params;
170 exit(-1); 255 pdata.size = sizeof( static_dh_params);
171 } 256 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
172 apr_pool_clear(tpool); 257 GNUTLS_X509_FMT_PEM);
173 258
174 gnutls_rsa_params_init(&rsa_params); 259 if (rv < 0) {
175 260 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
176 pdata = load_params(sc_base->rsa_params_file, s, tpool); 261 "GnuTLS: Unable to load internal DH Params."
177 262 " Shutting down.");
178 if (pdata.size != 0) { 263 exit(-1);
179 rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata,
180 GNUTLS_X509_FMT_PEM);
181 if (rv != 0) {
182 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
183 "GnuTLS: Unable to load RSA Params: (%d) %s",
184 rv, gnutls_strerror(rv));
185 exit(rv);
186 }
187 }
188 else {
189 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
190 "GnuTLS: Unable to load RSA Params."
191 " Shutting Down.");
192 exit(-1);
193 }
194
195 apr_pool_destroy(tpool);
196 rv = mgs_cache_post_config(p, s, sc_base);
197 if (rv != 0) {
198 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
199 "GnuTLS: Post Config for GnuTLSCache Failed."
200 " Shutting Down.");
201 exit(-1);
202 }
203
204 for (s = base_server; s; s = s->next) {
205 sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
206 &gnutls_module);
207 sc->cache_type = sc_base->cache_type;
208 sc->cache_config = sc_base->cache_config;
209
210 gnutls_certificate_set_rsa_export_params(sc->certs,
211 rsa_params);
212 gnutls_certificate_set_dh_params(sc->certs, dh_params);
213
214 if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
215 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
216 "[GnuTLS] - Host '%s:%d' is missing a "
217 "Certificate File!",
218 s->server_hostname, s->port);
219 exit(-1);
220 } 264 }
221 265 }
222 if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) { 266 apr_pool_clear(tpool);
223 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 267
224 "[GnuTLS] - Host '%s:%d' is missing a " 268 rsa_params = NULL;
225 "Private Key File!", 269
226 s->server_hostname, s->port); 270 pdata = load_params(sc_base->rsa_params_file, s, tpool);
227 exit(-1); 271
272 if (pdata.size != 0) {
273 gnutls_rsa_params_init(&rsa_params);
274 rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata,
275 GNUTLS_X509_FMT_PEM);
276 if (rv != 0) {
277 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
278 "GnuTLS: Unable to load RSA Params: (%d) %s",
279 rv, gnutls_strerror(rv));
280 exit(rv);
281 }
282 }
283 /* not an error but RSA-EXPORT ciphersuites are not available
284 */
285
286 apr_pool_destroy(tpool);
287 rv = mgs_cache_post_config(p, s, sc_base);
288 if (rv != 0) {
289 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
290 "GnuTLS: Post Config for GnuTLSCache Failed."
291 " Shutting Down.");
292 exit(-1);
293 }
294
295 for (s = base_server; s; s = s->next) {
296 sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
297 &gnutls_module);
298 sc->cache_type = sc_base->cache_type;
299 sc->cache_config = sc_base->cache_config;
300
301 if (rsa_params != NULL)
302 gnutls_certificate_set_rsa_export_params(sc->certs,
303 rsa_params);
304 gnutls_certificate_set_dh_params(sc->certs, dh_params);
305
306 gnutls_anon_set_server_dh_params( sc->anon_creds, dh_params);
307
308 gnutls_certificate_server_set_retrieve_function(sc->certs,
309 cert_retrieve_fn);
310
311 if ( sc->srp_tpasswd_conf_file != NULL && sc->srp_tpasswd_file != NULL) {
312 gnutls_srp_set_server_credentials_file( sc->srp_creds,
313 sc->srp_tpasswd_file, sc->srp_tpasswd_conf_file);
228 } 314 }
229 315
230 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, 316 if (sc->cert_x509 == NULL
231 GNUTLS_OID_X520_COMMON_NAME, 0, 0, 317 && sc->enabled == GNUTLS_ENABLED_TRUE) {
232 NULL, &data_len); 318 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
233 319 "[GnuTLS] - Host '%s:%d' is missing a "
234 if (data_len < 1) { 320 "Certificate File!", s->server_hostname,
235 sc->enabled = GNUTLS_ENABLED_FALSE; 321 s->port);
236 sc->cert_cn = NULL; 322 exit(-1);
237 continue; 323 }
324
325 if (sc->privkey_x509 == NULL
326 && sc->enabled == GNUTLS_ENABLED_TRUE) {
327 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
328 "[GnuTLS] - Host '%s:%d' is missing a "
329 "Private Key File!",
330 s->server_hostname, s->port);
331 exit(-1);
332 }
333
334 if (sc->enabled == GNUTLS_ENABLED_TRUE) {
335 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
336 GNUTLS_OID_X520_COMMON_NAME,
337 0, 0, NULL, &data_len);
338
339 if (data_len < 1) {
340 sc->enabled = GNUTLS_ENABLED_FALSE;
341 sc->cert_cn = NULL;
342 continue;
343 }
344
345 sc->cert_cn = apr_palloc(p, data_len);
346 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
347 GNUTLS_OID_X520_COMMON_NAME,
348 0, 0, sc->cert_cn,
349 &data_len);
238 } 350 }
239 351 }
240 sc->cert_cn = apr_palloc(p, data_len);
241 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
242 GNUTLS_OID_X520_COMMON_NAME, 0, 0,
243 sc->cert_cn, &data_len);
244 }
245 } 352 }
246 353
247 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 354 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
@@ -249,34 +356,32 @@ int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
249 return OK; 356 return OK;
250} 357}
251 358
252void mgs_hook_child_init(apr_pool_t *p, server_rec *s) 359void mgs_hook_child_init(apr_pool_t * p, server_rec * s)
253{ 360{
254 apr_status_t rv = APR_SUCCESS; 361 apr_status_t rv = APR_SUCCESS;
255 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 362 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
256 &gnutls_module); 363 &gnutls_module);
257 364
258 if (sc->cache_type != mgs_cache_none) { 365 if (sc->cache_type != mgs_cache_none) {
259 rv = mgs_cache_child_init(p, s, sc); 366 rv = mgs_cache_child_init(p, s, sc);
260 if(rv != APR_SUCCESS) { 367 if (rv != APR_SUCCESS) {
261 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 368 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
262 "[GnuTLS] - Failed to run Cache Init"); 369 "[GnuTLS] - Failed to run Cache Init");
263 } 370 }
264 } 371 } else {
265 else { 372 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
266 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, 373 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
267 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
268 } 374 }
269} 375}
270 376
271const char *mgs_hook_http_scheme(const request_rec * r) 377const char *mgs_hook_http_scheme(const request_rec * r)
272{ 378{
273 mgs_srvconf_rec *sc = 379 mgs_srvconf_rec *sc =
274 (mgs_srvconf_rec *) ap_get_module_config(r->server-> 380 (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
275 module_config, 381 &gnutls_module);
276 &gnutls_module);
277 382
278 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 383 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
279 return NULL; 384 return NULL;
280 } 385 }
281 386
282 return "https"; 387 return "https";
@@ -285,12 +390,11 @@ const char *mgs_hook_http_scheme(const request_rec * r)
285apr_port_t mgs_hook_default_port(const request_rec * r) 390apr_port_t mgs_hook_default_port(const request_rec * r)
286{ 391{
287 mgs_srvconf_rec *sc = 392 mgs_srvconf_rec *sc =
288 (mgs_srvconf_rec *) ap_get_module_config(r->server-> 393 (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
289 module_config, 394 &gnutls_module);
290 &gnutls_module);
291 395
292 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 396 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
293 return 0; 397 return 0;
294 } 398 }
295 399
296 return 443; 400 return 443;
@@ -299,88 +403,87 @@ apr_port_t mgs_hook_default_port(const request_rec * r)
299#define MAX_HOST_LEN 255 403#define MAX_HOST_LEN 255
300 404
301#if USING_2_1_RECENT 405#if USING_2_1_RECENT
302typedef struct 406typedef struct {
303{
304 mgs_handle_t *ctxt; 407 mgs_handle_t *ctxt;
305 mgs_srvconf_rec *sc; 408 mgs_srvconf_rec *sc;
306 const char* sni_name; 409 const char *sni_name;
307} vhost_cb_rec; 410} vhost_cb_rec;
308 411
309static int vhost_cb (void* baton, conn_rec* conn, server_rec* s) 412static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
310{ 413{
311 mgs_srvconf_rec *tsc; 414 mgs_srvconf_rec *tsc;
312 vhost_cb_rec* x = baton; 415 vhost_cb_rec *x = baton;
313 416
314 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 417 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
315 &gnutls_module); 418 &gnutls_module);
316 419
317 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 420 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
318 return 0; 421 return 0;
319 } 422 }
320 423
321 /* The CN can contain a * -- this will match those too. */ 424 /* The CN can contain a * -- this will match those too. */
322 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 425 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
323 /* found a match */ 426 /* found a match */
324#if MOD_GNUTLS_DEBUG 427#if MOD_GNUTLS_DEBUG
325 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 428 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
326 x->ctxt->c->base_server, 429 x->ctxt->c->base_server,
327 "GnuTLS: Virtual Host CB: " 430 "GnuTLS: Virtual Host CB: "
328 "'%s' == '%s'", tsc->cert_cn, x->sni_name); 431 "'%s' == '%s'", tsc->cert_cn, x->sni_name);
329#endif 432#endif
330 /* Because we actually change the server used here, we need to reset 433 /* Because we actually change the server used here, we need to reset
331 * things like ClientVerify. 434 * things like ClientVerify.
332 */ 435 */
333 x->sc = tsc; 436 x->sc = tsc;
334 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our 437 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
335 * certificate structure *should* change when the server changes. 438 * certificate structure *should* change when the server changes.
336 * acccckkkkkk. 439 * acccckkkkkk.
337 */ 440 */
338 return 1; 441 return 1;
339 } 442 }
340 return 0; 443 return 0;
341} 444}
342#endif 445#endif
343 446
344mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session) 447mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
345{ 448{
346 int rv; 449 int rv;
347 int sni_type; 450 unsigned int sni_type;
348 int data_len = MAX_HOST_LEN; 451 size_t data_len = MAX_HOST_LEN;
349 char sni_name[MAX_HOST_LEN]; 452 char sni_name[MAX_HOST_LEN];
350 mgs_handle_t *ctxt; 453 mgs_handle_t *ctxt;
351#if USING_2_1_RECENT 454#if USING_2_1_RECENT
352 vhost_cb_rec cbx; 455 vhost_cb_rec cbx;
353#else 456#else
354 server_rec* s; 457 server_rec *s;
355 mgs_srvconf_rec *tsc; 458 mgs_srvconf_rec *tsc;
356#endif 459#endif
357 460
358 ctxt = gnutls_transport_get_ptr(session); 461 ctxt = gnutls_transport_get_ptr(session);
359 462
360 sni_type = gnutls_certificate_type_get(session); 463 sni_type = gnutls_certificate_type_get(session);
361 if (sni_type != GNUTLS_CRT_X509) { 464 if (sni_type != GNUTLS_CRT_X509) {
362 /* In theory, we could support OpenPGP Certificates. Theory != code. */ 465 /* In theory, we could support OpenPGP Certificates. Theory != code. */
363 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 466 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
364 ctxt->c->base_server, 467 ctxt->c->base_server,
365 "GnuTLS: Only x509 Certificates are currently supported."); 468 "GnuTLS: Only x509 Certificates are currently supported.");
366 return NULL; 469 return NULL;
367 } 470 }
368 471
369 rv = gnutls_server_name_get(ctxt->session, sni_name, 472 rv = gnutls_server_name_get(ctxt->session, sni_name,
370 &data_len, &sni_type, 0); 473 &data_len, &sni_type, 0);
371 474
372 if (rv != 0) { 475 if (rv != 0) {
373 return NULL; 476 return NULL;
374 } 477 }
375 478
376 if (sni_type != GNUTLS_NAME_DNS) { 479 if (sni_type != GNUTLS_NAME_DNS) {
377 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 480 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
378 ctxt->c->base_server, 481 ctxt->c->base_server,
379 "GnuTLS: Unknown type '%d' for SNI: " 482 "GnuTLS: Unknown type '%d' for SNI: "
380 "'%s'", sni_type, sni_name); 483 "'%s'", sni_type, sni_name);
381 return NULL; 484 return NULL;
382 } 485 }
383 486
384 /** 487 /**
385 * Code in the Core already sets up the c->base_server as the base 488 * Code in the Core already sets up the c->base_server as the base
386 * for this IP/Port combo. Trust that the core did the 'right' thing. 489 * for this IP/Port combo. Trust that the core did the 'right' thing.
@@ -389,72 +492,56 @@ mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session)
389 cbx.ctxt = ctxt; 492 cbx.ctxt = ctxt;
390 cbx.sc = NULL; 493 cbx.sc = NULL;
391 cbx.sni_name = sni_name; 494 cbx.sni_name = sni_name;
392 495
393 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); 496 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
394 if (rv == 1) { 497 if (rv == 1) {
395 return cbx.sc; 498 return cbx.sc;
396 } 499 }
397#else 500#else
398 for (s = ap_server_conf; s; s = s->next) { 501 for (s = ap_server_conf; s; s = s->next) {
399 502
400 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 503 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
401 &gnutls_module); 504 &gnutls_module);
402 if (tsc->enabled != GNUTLS_ENABLED_TRUE) { 505 if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
403 continue; 506 continue;
404 } 507 }
405#if MOD_GNUTLS_DEBUG 508#if MOD_GNUTLS_DEBUG
406 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 509 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
407 ctxt->c->base_server, 510 ctxt->c->base_server,
408 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", tsc->cert_cn, rv, 511 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X",
409 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)), 512 tsc->cert_cn, rv,
410 (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc); 513 gnutls_pk_algorithm_get_name
411#endif 514 (gnutls_x509_privkey_get_pk_algorithm
412 /* The CN can contain a * -- this will match those too. */ 515 (ctxt->sc->privkey_x509)), (unsigned int) s,
413 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) { 516 (unsigned int) s->next, (unsigned int) tsc);
517#endif
518 /* The CN can contain a * -- this will match those too. */
519 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
414#if MOD_GNUTLS_DEBUG 520#if MOD_GNUTLS_DEBUG
415 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 521 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
416 ctxt->c->base_server, 522 ctxt->c->base_server,
417 "GnuTLS: Virtual Host: " 523 "GnuTLS: Virtual Host: "
418 "'%s' == '%s'", tsc->cert_cn, sni_name); 524 "'%s' == '%s'", tsc->cert_cn, sni_name);
419#endif 525#endif
420 return tsc; 526 return tsc;
421 } 527 }
422 } 528 }
423#endif 529#endif
424 return NULL; 530 return NULL;
425} 531}
426 532
427 533
428static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) 534static const int protocol_priority[] = {
429{ 535 GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
430 mgs_handle_t *ctxt; 536
431 mgs_srvconf_rec *tsc;
432
433 ctxt = gnutls_transport_get_ptr(session);
434 537
435 ret->type = GNUTLS_CRT_X509; 538static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
436 ret->ncerts = 1;
437 ret->deinit_all = 0;
438
439 tsc = mgs_find_sni_server(session);
440
441 if (tsc != NULL) {
442 ctxt->sc = tsc;
443 gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
444 }
445
446 ret->cert.x509 = &ctxt->sc->cert_x509;
447 ret->key.x509 = ctxt->sc->privkey_x509;
448 return 0;
449}
450
451static mgs_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
452{ 539{
453 mgs_handle_t *ctxt; 540 mgs_handle_t *ctxt;
454 mgs_srvconf_rec *sc = 541 mgs_srvconf_rec *sc =
455 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 542 (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
456 module_config, 543 module_config,
457 &gnutls_module); 544 &gnutls_module);
458 545
459 ctxt = apr_pcalloc(pool, sizeof(*ctxt)); 546 ctxt = apr_pcalloc(pool, sizeof(*ctxt));
460 ctxt->c = c; 547 ctxt->c = c;
@@ -471,20 +558,20 @@ static mgs_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
471 ctxt->output_length = 0; 558 ctxt->output_length = 0;
472 559
473 gnutls_init(&ctxt->session, GNUTLS_SERVER); 560 gnutls_init(&ctxt->session, GNUTLS_SERVER);
474
475 gnutls_protocol_set_priority(ctxt->session, sc->protocol);
476 gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
477 gnutls_compression_set_priority(ctxt->session, sc->compression);
478 gnutls_kx_set_priority(ctxt->session, sc->key_exchange);
479 gnutls_mac_set_priority(ctxt->session, sc->macs);
480 gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types);
481
482 mgs_cache_session_init(ctxt);
483 561
484 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs); 562 /* This is not very good as it trades security for compatibility,
563 * but it is the only way to be ultra-portable.
564 */
565 gnutls_session_enable_compatibility_mode( ctxt->session);
566
567 /* because we don't set any default priorities here (we set later at
568 * the user hello callback) we need to at least set this in order for
569 * gnutls to be able to read packets.
570 */
571 gnutls_protocol_set_priority( ctxt->session, protocol_priority);
572
573 gnutls_handshake_set_post_client_hello_function( ctxt->session, mgs_select_virtual_server_cb);
485 574
486 gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn);
487 gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
488 return ctxt; 575 return ctxt;
489} 576}
490 577
@@ -492,218 +579,337 @@ int mgs_hook_pre_connection(conn_rec * c, void *csd)
492{ 579{
493 mgs_handle_t *ctxt; 580 mgs_handle_t *ctxt;
494 mgs_srvconf_rec *sc = 581 mgs_srvconf_rec *sc =
495 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 582 (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
496 module_config, 583 module_config,
497 &gnutls_module); 584 &gnutls_module);
498 585
499 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 586 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
500 return DECLINED; 587 return DECLINED;
501 } 588 }
502 589
503 ctxt = create_gnutls_handle(c->pool, c); 590 ctxt = create_gnutls_handle(c->pool, c);
504 591
505 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 592 ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
506 593
507 gnutls_transport_set_pull_function(ctxt->session, 594 gnutls_transport_set_pull_function(ctxt->session, mgs_transport_read);
508 mgs_transport_read); 595 gnutls_transport_set_push_function(ctxt->session, mgs_transport_write);
509 gnutls_transport_set_push_function(ctxt->session,
510 mgs_transport_write);
511 gnutls_transport_set_ptr(ctxt->session, ctxt); 596 gnutls_transport_set_ptr(ctxt->session, ctxt);
512 597
513 ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, 598 ctxt->input_filter =
514 NULL, c); 599 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
515 ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, 600 ctxt->output_filter =
516 NULL, c); 601 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
517 602
518 return OK; 603 return OK;
519} 604}
520 605
521int mgs_hook_fixups(request_rec *r) 606int mgs_hook_fixups(request_rec * r)
522{ 607{
523 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 608 unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
524 char buf[AP_IOBUFSIZE]; 609 char buf[AP_IOBUFSIZE];
525 const char* tmp; 610 const char *tmp;
526 int len; 611 size_t len;
527 mgs_handle_t *ctxt; 612 mgs_handle_t *ctxt;
528 int rv = OK; 613 int rv = OK;
529 614
530 apr_table_t *env = r->subprocess_env; 615 apr_table_t *env = r->subprocess_env;
531 616
532 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module); 617 ctxt =
618 ap_get_module_config(r->connection->conn_config, &gnutls_module);
533 619
534 if(!ctxt) { 620 if (!ctxt) {
535 return DECLINED; 621 return DECLINED;
536 } 622 }
537 623
538 apr_table_setn(env, "HTTPS", "on"); 624 apr_table_setn(env, "HTTPS", "on");
539 625
540 apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION); 626 apr_table_setn(env, "SSL_VERSION_LIBRARY", "GnuTLS/"LIBGNUTLS_VERSION);
541 apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION); 627 apr_table_setn(env, "SSL_VERSION_INTERFACE", "mod_gnutls/"MOD_GNUTLS_VERSION);
542 628
543 apr_table_setn(env, "SSL_PROTOCOL", 629 apr_table_setn(env, "SSL_PROTOCOL",
544 gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session))); 630 gnutls_protocol_get_name(gnutls_protocol_get_version
631 (ctxt->session)));
545 632
633 /* should have been called SSL_CIPHERSUITE instead */
546 apr_table_setn(env, "SSL_CIPHER", 634 apr_table_setn(env, "SSL_CIPHER",
547 gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session))); 635 gnutls_cipher_suite_get_name(
636 gnutls_kx_get(ctxt->session), gnutls_cipher_get(ctxt->session),
637 gnutls_mac_get(ctxt->session)));
638
639 apr_table_setn(env, "SSL_COMPRESS_METHOD",
640 gnutls_compression_get_name(gnutls_compression_get
641 (ctxt->session)));
642
643 apr_table_setn(env, "SSL_SRP_USER",
644 gnutls_srp_server_get_username( ctxt->session));
548 645
549 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 646 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
647 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
550 648
551 tmp = apr_psprintf(r->pool, "%d", 649 unsigned int key_size =
552 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session))); 650 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
651 tmp = apr_psprintf(r->pool, "%u", key_size);
553 652
554 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 653 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
555 654
556 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 655 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
557 656
657 apr_table_setn(env, "SSL_CIPHER_EXPORT",
658 (key_size <= 40) ? "true" : "false");
659
558 len = sizeof(sbuf); 660 len = sizeof(sbuf);
559 gnutls_session_get_id(ctxt->session, sbuf, &len); 661 gnutls_session_get_id(ctxt->session, sbuf, &len);
560 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 662 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
561 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 663 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
562 664
563 /* TODO: There are many other env vars that we need to add */ 665 mgs_add_common_cert_vars(r, ctxt->sc->cert_x509, 0, ctxt->sc->export_certificates_enabled);
564 { 666
565 len = sizeof(buf);
566 gnutls_x509_crt_get_dn(ctxt->sc->cert_x509, buf, &len);
567 apr_table_setn(env, "SSL_SERVER_S_DN", apr_pstrmemdup(r->pool, buf, len));
568
569 len = sizeof(buf);
570 gnutls_x509_crt_get_issuer_dn(ctxt->sc->cert_x509, buf, &len);
571 apr_table_setn(env, "SSL_SERVER_I_DN", apr_pstrmemdup(r->pool, buf, len));
572 }
573 return rv; 667 return rv;
574} 668}
575 669
576int mgs_hook_authz(request_rec *r) 670int mgs_hook_authz(request_rec * r)
577{ 671{
578 int rv; 672 int rv;
579 int status;
580 mgs_handle_t *ctxt; 673 mgs_handle_t *ctxt;
581 mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config, 674 mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
582 &gnutls_module); 675 &gnutls_module);
583 676
584 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module); 677 ctxt =
585 678 ap_get_module_config(r->connection->conn_config, &gnutls_module);
679
586 if (!ctxt) { 680 if (!ctxt) {
587 return DECLINED; 681 return DECLINED;
588 } 682 }
589 683
590 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 684 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
591 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 685 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
592 "GnuTLS: Directory set to Ignore Client Certificate!"); 686 "GnuTLS: Directory set to Ignore Client Certificate!");
593 } 687 } else {
594 else { 688 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
595 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 689 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
596 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 690 "GnuTLS: Attempting to rehandshake with peer. %d %d",
597 "GnuTLS: Attempting to rehandshake with peer. %d %d", 691 ctxt->sc->client_verify_mode,
598 ctxt->sc->client_verify_mode, dc->client_verify_mode); 692 dc->client_verify_mode);
599 693
600 gnutls_certificate_server_set_request(ctxt->session, 694 gnutls_certificate_server_set_request(ctxt->session,
601 dc->client_verify_mode); 695 dc->client_verify_mode);
602 696
603 if (mgs_rehandshake(ctxt) != 0) { 697 if (mgs_rehandshake(ctxt) != 0) {
604 return HTTP_FORBIDDEN; 698 return HTTP_FORBIDDEN;
605 } 699 }
606 } 700 } else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
607 else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
608#if MOD_GNUTLS_DEBUG 701#if MOD_GNUTLS_DEBUG
609 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 702 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
610 "GnuTLS: Peer is set to IGNORE"); 703 "GnuTLS: Peer is set to IGNORE");
611#endif 704#endif
612 } 705 } else {
613 else { 706 rv = mgs_cert_verify(r, ctxt);
614 rv = mgs_cert_verify(r, ctxt); 707 if (rv != DECLINED) {
615 if (rv != DECLINED) { 708 return rv;
616 return rv; 709 }
617 } 710 }
618 } 711 }
619 712
713 return DECLINED;
714}
715
716/* variables that are not sent by default:
717 *
718 * SSL_CLIENT_CERT string PEM-encoded client certificate
719 * SSL_SERVER_CERT string PEM-encoded client certificate
720 */
620 721
621static int mgs_cert_verify(request_rec *r, mgs_handle_t *ctxt) 722/* side is either 0 for SERVER or 1 for CLIENT
723 */
724#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
725static void
726mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, int export_certificates_enabled)
622{ 727{
623 const gnutls_datum_t* cert_list; 728 unsigned char sbuf[64]; /* buffer to hold serials */
624 int cert_list_size; 729 char buf[AP_IOBUFSIZE];
625 gnutls_x509_crt_t cert; 730 const char *tmp;
731 size_t len;
732 int alg;
733
734 apr_table_t *env = r->subprocess_env;
626 735
736 if (export_certificates_enabled != 0) {
737 char cert_buf[10*1024];
738 len = sizeof(cert_buf);
739
740 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
741 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
742 apr_pstrmemdup(r->pool, cert_buf, len));
743
744 }
627 745
628 cert_list = gnutls_certificate_get_peers(ctxt->session, &cert_list_size); 746 len = sizeof(buf);
747 gnutls_x509_crt_get_dn(cert, buf, &len);
748 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
749 apr_pstrmemdup(r->pool, buf, len));
750
751 len = sizeof(buf);
752 gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
753 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
754 apr_pstrmemdup(r->pool, buf, len));
755
756 len = sizeof(sbuf);
757 gnutls_x509_crt_get_serial(cert, sbuf, &len);
758 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
759 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
760 apr_pstrdup(r->pool, tmp));
761
762 tmp =
763 mgs_time2sz(gnutls_x509_crt_get_expiration_time
764 (cert), buf, sizeof(buf));
765 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
766 apr_pstrdup(r->pool, tmp));
767
768 tmp =
769 mgs_time2sz(gnutls_x509_crt_get_activation_time
770 (cert), buf, sizeof(buf));
771 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
772 apr_pstrdup(r->pool, tmp));
773
774 alg = gnutls_x509_crt_get_signature_algorithm( cert);
775 if (alg >= 0) {
776 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", NULL),
777 gnutls_sign_algorithm_get_name( alg));
778 }
779
780 alg = gnutls_x509_crt_get_pk_algorithm( cert, NULL);
781 if (alg >= 0) {
782 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
783 gnutls_pk_algorithm_get_name( alg));
784 }
785
786
787}
788
789
790static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
791{
792 const gnutls_datum_t *cert_list;
793 unsigned int cert_list_size, status, expired;
794 int rv, ret;
795 gnutls_x509_crt_t cert;
796 apr_time_t activation_time, expiration_time, cur_time;
797
798 cert_list =
799 gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
629 800
630 if (cert_list == NULL || cert_list_size == 0) { 801 if (cert_list == NULL || cert_list_size == 0) {
631 /* no certificate provided by the client, but one was required. */ 802 /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
632 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 803 */
633 "GnuTLS: Failed to Verify Peer: " 804 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
634 "Client did not submit a certificate"); 805 return OK;
635 return HTTP_FORBIDDEN; 806
807 /* no certificate provided by the client, but one was required. */
808 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
809 "GnuTLS: Failed to Verify Peer: "
810 "Client did not submit a certificate");
811 return HTTP_FORBIDDEN;
636 } 812 }
637 813
638 if (cert_list_size > 1) { 814 if (cert_list_size > 1) {
639 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 815 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
640 "GnuTLS: Failed to Verify Peer: " 816 "GnuTLS: Failed to Verify Peer: "
641 "Chained Client Certificates are not supported."); 817 "Chained Client Certificates are not supported.");
642 return HTTP_FORBIDDEN; 818 return HTTP_FORBIDDEN;
643 } 819 }
644 820
645 gnutls_x509_crt_init(&cert); 821 gnutls_x509_crt_init(&cert);
646 gnutls_x509_crt_import(cert, &cert_chain[0], GNUTLS_X509_FMT_DER); 822 rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
823 if (rv < 0) {
824 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
825 "GnuTLS: Failed to Verify Peer: "
826 "Failed to import peer certificates.");
827 ret = HTTP_FORBIDDEN;
828 goto exit;
829 }
647 830
648 rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list, ctxt->sc->ca_list_size, 0, &status); 831 apr_time_ansi_put(&expiration_time,
832 gnutls_x509_crt_get_expiration_time(cert));
833 apr_time_ansi_put(&activation_time,
834 gnutls_x509_crt_get_activation_time(cert));
835
836 rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list,
837 ctxt->sc->ca_list_size, 0, &status);
649 838
650 if (rv < 0) { 839 if (rv < 0) {
651 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 840 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
652 "GnuTLS: Failed to Verify Peer: (%d) %s", 841 "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
653 rv, gnutls_strerror(rv)); 842 rv, gnutls_strerror(rv));
654 return HTTP_FORBIDDEN; 843 ret = HTTP_FORBIDDEN;
844 goto exit;
655 } 845 }
656 846
657 if (status < 0) { 847 expired = 0;
658 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 848 cur_time = apr_time_now();
659 "GnuTLS: Peer Status is invalid."); 849 if (activation_time > cur_time) {
660 return HTTP_FORBIDDEN; 850 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
661 } 851 "GnuTLS: Failed to Verify Peer: "
662 852 "Peer Certificate is not yet activated.");
663 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 853 expired = 1;
664 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
665 "GnuTLS: Could not find Signer for Peer Certificate");
666 }
667
668 if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
669 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
670 "GnuTLS: Could not find CA for Peer Certificate");
671 }
672
673 if (status & GNUTLS_CERT_INVALID) {
674 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
675 "GnuTLS: Peer Certificate is invalid.");
676 return HTTP_FORBIDDEN;
677 }
678 else if (status & GNUTLS_CERT_REVOKED) {
679 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
680 "GnuTLS: Peer Certificate is revoked.");
681 return HTTP_FORBIDDEN;
682 }
683
684 /* TODO: OpenPGP Certificates */
685 if (gnutls_certificate_type_get(ctxt->session) != GNUTLS_CRT_X509) {
686 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
687 "GnuTLS: Only x509 is supported for client certificates");
688 return HTTP_FORBIDDEN;
689 }
690 /* TODO: Further Verification. */
691// gnutls_x509_crt_get_expiration_time() < time
692// gnutls_x509_crt_get_activation_time() > time
693/// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size);
694 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
695 "GnuTLS: Verified Peer.");
696 } 854 }
697 855
698 ap_add_common_vars(r); 856 if (expiration_time < cur_time) {
699 mgs_hook_fixups(r); 857 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
700 status = mgs_authz_lua(r); 858 "GnuTLS: Failed to Verify Peer: "
859 "Peer Certificate is expired.");
860 expired = 1;
861 }
701 862
702 if (status != 0) { 863 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
703 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 864 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
704 "GnuTLS: FAILED Authorization Test"); 865 "GnuTLS: Could not find Signer for Peer Certificate");
705 return HTTP_FORBIDDEN;
706 } 866 }
707 867
708} 868 if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
869 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
870 "GnuTLS: Peer's Certificate signer is not a CA");
871 }
872
873 if (status & GNUTLS_CERT_INVALID) {
874 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
875 "GnuTLS: Peer Certificate is invalid.");
876 } else if (status & GNUTLS_CERT_REVOKED) {
877 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
878 "GnuTLS: Peer Certificate is revoked.");
879 }
880
881 /* TODO: Further Verification. */
882 /* Revocation is X.509 non workable paradigm, I really doubt implementation
883 * is worth doing --nmav
884 */
885/// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size);
709 886
887// mgs_hook_fixups(r);
888// rv = mgs_authz_lua(r);
889
890 mgs_add_common_cert_vars(r, cert, 1, ctxt->sc->export_certificates_enabled);
891
892 {
893 /* days remaining */
894 unsigned long remain = (apr_time_sec(expiration_time) - apr_time_sec(cur_time))/86400;
895 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
896 apr_psprintf(r->pool, "%lu", remain));
897 }
898
899 if (status == 0 && expired == 0) {
900 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "SUCCESS");
901 ret = OK;
902 } else {
903 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "FAILED");
904 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
905 ret = OK;
906 else
907 ret = HTTP_FORBIDDEN;
908 }
909
910 exit:
911 gnutls_x509_crt_deinit(cert);
912 return ret;
913
914
915}
diff --git a/src/gnutls_io.c b/src/gnutls_io.c
index 14e7cf6..753c87b 100644
--- a/src/gnutls_io.c
+++ b/src/gnutls_io.c
@@ -543,8 +543,7 @@ apr_status_t mgs_filter_output(ap_filter_t * f,
543 apr_bucket *bucket = APR_BRIGADE_FIRST(bb); 543 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
544 if (AP_BUCKET_IS_EOC(bucket)) { 544 if (AP_BUCKET_IS_EOC(bucket)) {
545 do { 545 do {
546 ret = gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, 546 ret = gnutls_bye( ctxt->session, GNUTLS_SHUT_WR);
547 GNUTLS_A_CLOSE_NOTIFY);
548 } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); 547 } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
549 548
550 apr_bucket_copy(bucket, &e); 549 apr_bucket_copy(bucket, &e);
@@ -556,7 +555,6 @@ apr_status_t mgs_filter_output(ap_filter_t * f,
556 } 555 }
557 556
558 apr_brigade_cleanup(ctxt->output_bb); 557 apr_brigade_cleanup(ctxt->output_bb);
559 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
560 gnutls_deinit(ctxt->session); 558 gnutls_deinit(ctxt->session);
561 continue; 559 continue;
562 560
@@ -568,6 +566,7 @@ apr_status_t mgs_filter_output(ap_filter_t * f,
568 apr_brigade_cleanup(ctxt->output_bb); 566 apr_brigade_cleanup(ctxt->output_bb);
569 return status; 567 return status;
570 } 568 }
569
571 apr_brigade_cleanup(ctxt->output_bb); 570 apr_brigade_cleanup(ctxt->output_bb);
572 continue; 571 continue;
573 } 572 }
@@ -599,7 +598,7 @@ apr_status_t mgs_filter_output(ap_filter_t * f,
599 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->output_rc, 598 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->output_rc,
600 ctxt->c->base_server, 599 ctxt->c->base_server,
601 "GnuTLS: Error writing data." 600 "GnuTLS: Error writing data."
602 " (%d) '%s'", ret, gnutls_strerror(ret)); 601 " (%d) '%s'", (int)ret, gnutls_strerror(ret));
603 if (ctxt->output_rc == APR_SUCCESS) { 602 if (ctxt->output_rc == APR_SUCCESS) {
604 ctxt->output_rc = APR_EGENERAL; 603 ctxt->output_rc = APR_EGENERAL;
605 } 604 }
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c
index 5ca198d..f9291f1 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -63,7 +63,15 @@ static const command_rec mgs_config_cmds[] = {
63 AP_INIT_TAKE1("GnuTLSClientCAFile", mgs_set_client_ca_file, 63 AP_INIT_TAKE1("GnuTLSClientCAFile", mgs_set_client_ca_file,
64 NULL, 64 NULL,
65 RSRC_CONF, 65 RSRC_CONF,
66 "Set the CA File for Client Certificates"), 66 "Set the CA File to verify Client Certificates"),
67 AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file,
68 NULL,
69 RSRC_CONF,
70 "Set the file to read Diffie Hellman parameters from"),
71 AP_INIT_TAKE1("GnuTLSRSAFile", mgs_set_rsa_export_file,
72 NULL,
73 RSRC_CONF,
74 "Set the file to read RSA-EXPORT parameters from"),
67 AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file, 75 AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file,
68 NULL, 76 NULL,
69 RSRC_CONF, 77 RSRC_CONF,
@@ -71,7 +79,15 @@ static const command_rec mgs_config_cmds[] = {
71 AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file, 79 AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file,
72 NULL, 80 NULL,
73 RSRC_CONF, 81 RSRC_CONF,
74 "SSL Server Certificate file"), 82 "SSL Server SRP Password file"),
83 AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file,
84 NULL,
85 RSRC_CONF,
86 "SSL Server SRP Password Conf file"),
87 AP_INIT_TAKE1("GnuTLSSRPPasswdConfFile", mgs_set_srp_tpasswd_conf_file,
88 NULL,
89 RSRC_CONF,
90 "SSL Server SRP Parameters file"),
75 AP_INIT_TAKE1("GnuTLSCacheTimeout", mgs_set_cache_timeout, 91 AP_INIT_TAKE1("GnuTLSCacheTimeout", mgs_set_cache_timeout,
76 NULL, 92 NULL,
77 RSRC_CONF, 93 RSRC_CONF,
@@ -80,10 +96,19 @@ static const command_rec mgs_config_cmds[] = {
80 NULL, 96 NULL,
81 RSRC_CONF, 97 RSRC_CONF,
82 "Cache Configuration"), 98 "Cache Configuration"),
99 AP_INIT_RAW_ARGS("GnuTLSPriorities", mgs_set_priorities,
100 NULL,
101 RSRC_CONF,
102 "The priorities to enable (ciphers, Key exchange, macs, compression)"),
83 AP_INIT_TAKE1("GnuTLSEnable", mgs_set_enabled, 103 AP_INIT_TAKE1("GnuTLSEnable", mgs_set_enabled,
84 NULL, 104 NULL,
85 RSRC_CONF, 105 RSRC_CONF,
86 "Whether this server has GnuTLS Enabled. Default: Off"), 106 "Whether this server has GnuTLS Enabled. Default: Off"),
107 AP_INIT_TAKE1("GnuTLSExportCertificates", mgs_set_export_certificates_enabled,
108 NULL,
109 RSRC_CONF,
110 "Whether to export PEM encoded certificates to CGIs. Default: Off"),
111#if 0
87 AP_INIT_RAW_ARGS("<GnuTLSRequire", mgs_set_require_section, 112 AP_INIT_RAW_ARGS("<GnuTLSRequire", mgs_set_require_section,
88 NULL, 113 NULL,
89 EXEC_ON_READ|OR_ALL, 114 EXEC_ON_READ|OR_ALL,
@@ -92,6 +117,7 @@ static const command_rec mgs_config_cmds[] = {
92 NULL, 117 NULL,
93 OR_ALL, 118 OR_ALL,
94 "Internal Command for reading Lua Bytecode."), 119 "Internal Command for reading Lua Bytecode."),
120#endif
95 {NULL} 121 {NULL}
96}; 122};
97 123