summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
-rw-r--r--Makefile.am7
-rw-r--r--NEWS30
-rw-r--r--NOTICE3
-rw-r--r--README67
-rw-r--r--README.ENV49
-rwxr-xr-xautogen.sh30
-rw-r--r--configure.ac28
-rw-r--r--include/mod_gnutls.h.in69
-rw-r--r--src/Makefile.am3
-rw-r--r--src/gnutls_cache.c97
-rw-r--r--src/gnutls_config.c603
-rw-r--r--src/gnutls_hooks.c1248
-rw-r--r--src/gnutls_io.c7
-rw-r--r--src/mod_gnutls.c56
14 files changed, 1623 insertions, 674 deletions
diff --git a/Makefile.am b/Makefile.am
index 77f3b84..a19e755 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,10 +1,11 @@
1AUTOMAKE_OPTIONS = foreign dist-bzip2 1AUTOMAKE_OPTIONS = foreign dist-bzip2
2 2
3EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \ 3EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \
4 m4/libgnutls.m4 m4/apr_memcache.m4 \ 4 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 NEWS \
8 NOTICE LICENSE autogen.sh 8 NOTICE LICENSE autogen.sh
9 9
10SUBDIRS = src data 10SUBDIRS = src
11ACLOCAL_AMFLAGS = -I m4
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..a9fe9fd
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,30 @@
1** Version 0.5.0-alpha (2008-01-24)
2
3- Added support for OpenPGP keys. The new directives are:
4 GnuTLSPGPKeyringFile, GnuTLSPGPCertificateFile, GnuTLSPGPKeyFile
5
6** Version 0.4.2 (2007-12-10)
7
8- Added support for sending a certificate chain.
9
10- Corrected bug which did not allow the TLS session cache to be used.
11
12- Do not allow resuming sessions on different servers.
13
14** Version 0.4.1 (2007-12-03)
15
16- Added support for subject alternative names in certificates.
17Only one per certificate is supported.
18
19- New enviroment variables: SSL_CLIENT_M_VERSION, SSL_CLIENT_S_SAN%,
20SSL_CLIENT_S_TYPE, SSL_SERVER_M_VERSION, SSL_SERVER_S_SAN%, SSL_SERVER_S_TYPE
21
22- The compatibility mode can now be enabled explicitely with the
23%COMPAT keyword at the GnuTLSPriorities string. It is no longer the default.
24
25- Check for GnuTLSPriorities directive. This corrects a segfault. Thanks
26to David Hrbáč.
27
28- Better handling of GnuTLSDHFile and GnuTLSRSAFile.
29
30- No longer default paths for RSA and DH parameter files.
diff --git a/NOTICE b/NOTICE
index 7b09606..25efd6f 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,4 +1,7 @@
1This product includes software developed by 1This product includes software developed by
2Nikos Mavrogiannopoulos (http://www.gnutls.org/).
3
4This product includes software developed by
2Paul Querna (http://www.outoforder.cc/). 5Paul Querna (http://www.outoforder.cc/).
3 6
4This product includes software developed by 7This product includes software developed by
diff --git a/README b/README
index 557ba77..5198ed7 100644
--- a/README
+++ b/README
@@ -11,7 +11,7 @@ to debug. I wanted to understand how it worked, and I had recently heard about
11GnuTLS, so long story short, I decided to implement a mod_gnutls. 11GnuTLS, so long story short, I decided to implement a mod_gnutls.
12 12
13Lines of Code in mod_ssl: 15,324 13Lines of Code in mod_ssl: 15,324
14Lines of Code in mod_gnutls: 1,886 14Lines of Code in mod_gnutls: 3,594
15 15
16Because of writing mod_gnutls, I now understand how input and output filters work, 16Because of writing mod_gnutls, I now understand how input and output filters work,
17better than I ever thought possible. It was a little painful at times, and some parts 17better than I ever thought possible. It was a little painful at times, and some parts
@@ -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
@@ -53,8 +54,58 @@ GnuTLSCache dbm conf/gnutls_cache
53 GnuTLSEnable On 54 GnuTLSEnable On
54 55
55 # This is the Private key for your server. 56 # This is the Private key for your server.
56 GnuTLSKeyFile conf/server.key 57 GnuTLSX509KeyFile conf/server.key
57 58
58 # This is the Server Certificate. 59 # This is the Server Certificate.
59 GnuTLSCertificateFile conf/server.cert 60 GnuTLSX509CertificateFile conf/server.cert
61</VirtualHost>
62
63# a more advanced configuration
64GnuTLSCache dbm "/var/cache/www-tls-cache/cache"
65GnuTLSCacheTimeout 600
66NameVirtualHost 1.2.3.4:443
67
68<VirtualHost 1.2.3.4:443>
69 Servername server.com:443
70 GnuTLSEnable on
71 GnuTLSPriority NORMAL
72# To export exactly the same environment variables as mod_ssl to CGI scripts.
73 GNUTLSExportCertificates on
74
75 GnuTLSX509CertificateFile /etc/apache2/server-cert.pem
76 GnuTLSX509KeyFile /etc/apache2/server-key.pem
77
78# To enable SRP you must have these files installed. Check the gnutls srptool.
79 GnuTLSSRPPasswdFile /etc/apache2/tpasswd
80 GnuTLSSRPPasswdConfFile /etc/apache2/tpasswd.conf
81
82# In order to verify client certificates. Other options to
83# GnuTLSClientVerify could be ignore or require. The GnuTLSClientCAFile
84# contains the CAs to verify client certificates.
85 GnuTLSClientVerify request
86 GnuTLSX509CAFile ca.pem
87 ...
88</VirtualHost>
89
90# A setup for OpenPGP and X.509 authentication
91<VirtualHost 1.2.3.4:443>
92 Servername crystal.lan:443
93 GnuTLSEnable on
94 GnuTLSPriorities NORMAL:+COMP-NULL
95
96# setup the openpgp keys
97 GnuTLSPGPCertificateFile /etc/apache2/test.pub.asc
98 GnuTLSPGPKeyFile /etc/apache2/test.sec.asc
99
100# and the X.509 keys
101 GnuTLSCertificateFile /etc/apache2/server-cert.pem
102 GnuTLSKeyFile /etc/apache2/server-key.pem
103 GnuTLSClientVerify ignore
104
105# To avoid using the default DH params
106 GnuTLSDHFile /etc/apache2/dh.pem
107
108# these are only needed if GnuTLSClientVerify != ignore
109 GnuTLSClientCAFile ca.pem
110 GnuTLSPGPKeyringFile /etc/apache2/ring.asc
60</VirtualHost> 111</VirtualHost>
diff --git a/README.ENV b/README.ENV
new file mode 100644
index 0000000..34dbcf6
--- /dev/null
+++ b/README.ENV
@@ -0,0 +1,49 @@
1All the environment variables set by this module are:
2
3HTTPS: can be "on" or "off"
4SSL_VERSION_LIBRARY: The version of the gnutls library
5SSL_VERSION_INTERFACE: The version of this module
6SSL_PROTOCOL: The SSL or TLS protocol name (such as "TLS 1.0" etc.)
7SSL_CIPHER: The SSL or TLS cipher suite name.
8SSL_COMPRESS_METHOD: The negotiated compression method (NULL or DEFLATE)
9SSL_SRP_USER: The SRP username used for authentication.
10SSL_CIPHER_USEKEYSIZE and SSL_CIPHER_ALGKEYSIZE: The number if bits used in the used cipher
11 algorithm. This does not fully reflect the security level since the size of
12 RSA or DHE key exchange parameters affect the security level too.
13SSL_CIPHER_EXPORT: true or false. Whether the cipher suite negotiated is an export one.
14SSL_SESSION_ID: The session ID negotiated in this session. Can be the same during
15 client reloads.
16
17SSL_CLIENT_V_REMAIN: The number of days until the client's certificate is expired.
18SSL_CLIENT_V_START: The activation time of client's certificate.
19SSL_CLIENT_V_END: The expiration time of client's certificate.
20SSL_CLIENT_S_DN: The distinguished name of client's certificate in RFC2253 format.
21SSL_CLIENT_I_DN: The distinguished name of client's issuer certificate in RFC2253 format.
22SSL_CLIENT_S_AN%: These will contain the alternative names of the client certificate
23 (% is a number starting from zero). The values will be prepended by "DNSNAME:",
24 "RFC822NAME:" or "URI:" depending on the type. If it is not supported the value
25 "UNSUPPORTED" will be set.
26SSL_CLIENT_M_SERIAL: The serial number of the client's certificate.
27SSL_CLIENT_M_VERSION: The version of the client's certificate.
28SSL_CLIENT_A_SIG: The algorithm used for the signature in client's certificate.
29SSL_CLIENT_A_KEY: The public key algorithm in client's certificate.
30SSL_CLIENT_CERT: The PEM-encoded client certificate
31SSL_CLIENT_VERIFY:
32 whether the client's certificate was verified. (NONE if none was sent, or SUCCESS or FAILED)
33SSL_CLIENT_CERT_TYPE: The certificate type can be X.509 or OPENPGP.
34
35SSL_SERVER_V_START: The activation time of server's certificate.
36SSL_SERVER_V_END: The expiration time of server's certificate.
37SSL_SERVER_S_DN: The distinguished name of the server's certificate in RFC2253 format.
38SSL_SERVER_I_DN: The distinguished name of the server's issuer certificate in RFC2253 format.
39SSL_SERVER_S_AN%: These will contain the alternative names of the server certificate
40 (% is a number starting from zero). The values will be prepended by "DNSNAME:",
41 "RFC822NAME:" or "URI:" depending on the type. If it is not supported the value
42 "UNSUPPORTED" will be set.
43SSL_SERVER_M_SERIAL: The serial number of the server's certificate.
44SSL_SERVER_M_VERSION: The version of the server's certificate.
45SSL_SERVER_A_SIG: The algorithm used for the signature in server's certificate.
46SSL_SERVER_A_KEY: The public key algorithm in server's certificate.
47SSL_SERVER_CERT: The PEM-encoded server certificate
48SSL_SERVER_CERT_TYPE: The certificate type can be X.509 or OPENPGP.
49
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..0cdcdd9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,11 @@
1AC_INIT(mod_gnutls, 0.2.0) 1dnl
2AC_INIT(mod_gnutls, 0.5.0-alpha)
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,25 +25,31 @@ 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.2.1
30CHECK_LIBGNUTLS($MIN_TLS_VERSION) 32AM_PATH_LIBGNUTLS_EXTRA($MIN_TLS_VERSION,,
33 AC_MSG_ERROR([[
34***
35*** libgnutls and libgnutls-extra were not found. You may want to get it from
36*** http://www.gnutls.org/
37***
38]]))
31 39
32CHECK_LUA() 40dnl CHECK_LUA()
33 41
34have_apr_memcache=0 42have_apr_memcache=0
35CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0]) 43CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0])
36AC_SUBST(have_apr_memcache) 44AC_SUBST(have_apr_memcache)
37 45
38MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}" 46MODULE_CFLAGS="${LIBGNUTLS_EXTRA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
39MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}" 47MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_EXTRA_LIBS}"
40 48
41AC_SUBST(MODULE_CFLAGS) 49AC_SUBST(MODULE_CFLAGS)
42AC_SUBST(MODULE_LIBS) 50AC_SUBST(MODULE_LIBS)
43 51
44AC_CONFIG_FILES([Makefile src/Makefile include/mod_gnutls.h data/Makefile]) 52AC_CONFIG_FILES([Makefile src/Makefile include/mod_gnutls.h])
45AC_OUTPUT 53AC_OUTPUT
46 54
47echo "---" 55echo "---"
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in
index 3473bf1..db7e7dd 100644
--- a/include/mod_gnutls.h.in
+++ b/include/mod_gnutls.h.in
@@ -29,6 +29,8 @@
29 29
30#include <gcrypt.h> 30#include <gcrypt.h>
31#include <gnutls/gnutls.h> 31#include <gnutls/gnutls.h>
32#include <gnutls/extra.h>
33#include <gnutls/openpgp.h>
32#include <gnutls/x509.h> 34#include <gnutls/x509.h>
33 35
34#ifndef __mod_gnutls_h_inc 36#ifndef __mod_gnutls_h_inc
@@ -76,24 +78,42 @@ typedef struct
76 apr_size_t lua_bytecode_len; 78 apr_size_t lua_bytecode_len;
77} mgs_dirconf_rec; 79} mgs_dirconf_rec;
78 80
81
82/* The maximum number of client CA certificates allowed.
83 */
84#define MAX_CA_CRTS 128
85
86/* The maximum number of certificates to send in a chain
87 */
88#define MAX_CHAIN_SIZE 8
89
79typedef struct 90typedef struct
80{ 91{
81 gnutls_certificate_credentials_t certs; 92 gnutls_certificate_credentials_t certs;
93 gnutls_srp_server_credentials_t srp_creds;
94 gnutls_anon_server_credentials_t anon_creds;
82 char* cert_cn; 95 char* cert_cn;
83 gnutls_x509_crt_t cert_x509; 96 gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */
97 unsigned int certs_x509_num;
84 gnutls_x509_privkey_t privkey_x509; 98 gnutls_x509_privkey_t privkey_x509;
99 gnutls_openpgp_crt_t cert_pgp; /* A certificate chain */
100 gnutls_openpgp_privkey_t privkey_pgp;
85 int enabled; 101 int enabled;
86 int ciphers[16]; 102 /* whether to send the PEM encoded certificates
87 int key_exchange[16]; 103 * to CGIs
88 int macs[16]; 104 */
89 int protocol[16]; 105 int export_certificates_enabled;
90 int compression[16]; 106 gnutls_priority_t priorities;
91 int cert_types[16]; 107 gnutls_rsa_params_t rsa_params;
92 apr_time_t cache_timeout; 108 gnutls_dh_params_t dh_params;
109 int cache_timeout;
93 mgs_cache_e cache_type; 110 mgs_cache_e cache_type;
94 const char* cache_config; 111 const char* cache_config;
95 const char* rsa_params_file; 112 const char* srp_tpasswd_file;
96 const char* dh_params_file; 113 const char* srp_tpasswd_conf_file;
114 gnutls_x509_crt_t ca_list[MAX_CA_CRTS];
115 gnutls_openpgp_keyring_t pgp_list;
116 unsigned int ca_list_size;
97 int client_verify_mode; 117 int client_verify_mode;
98} mgs_srvconf_rec; 118} mgs_srvconf_rec;
99 119
@@ -214,15 +234,37 @@ int mgs_cache_session_init(mgs_handle_t *ctxt);
214char *mgs_session_id2sz(unsigned char *id, int idlen, 234char *mgs_session_id2sz(unsigned char *id, int idlen,
215 char *str, int strsize); 235 char *str, int strsize);
216 236
237/**
238 * Convert a time_t into a Null Terminated String
239 * @param t time_t time
240 * @param str Location to store the Hex Encoded String
241 * @param strsize The Maximum Length that can be stored in str
242 */
243char *mgs_time2sz(time_t t, char *str, int strsize);
244
217 245
218/* Configuration Functions */ 246/* Configuration Functions */
219 247
248const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy,
249 const char *arg);
250const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
251 const char *arg);
252const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
253 const char *arg);
254const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
255 const char *arg);
220const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 256const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
221 const char *arg); 257 const char *arg);
222 258
223const char *mgs_set_key_file(cmd_parms * parms, void *dummy, 259const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
224 const char *arg); 260 const char *arg);
225 261
262const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
263 const char *arg);
264
265const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
266 const char *arg);
267
226const char *mgs_set_cache(cmd_parms * parms, void *dummy, 268const char *mgs_set_cache(cmd_parms * parms, void *dummy,
227 const char *type, const char* arg); 269 const char *type, const char* arg);
228 270
@@ -235,8 +277,15 @@ const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
235const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 277const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
236 const char *arg); 278 const char *arg);
237 279
280const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
281 const char *arg);
282
238const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 283const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
239 const char *arg); 284 const char *arg);
285const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
286 const char *arg);
287const char *mgs_set_priorities(cmd_parms * parms, void *dummy,
288 const char *arg);
240 289
241const char *mgs_set_require_section(cmd_parms *cmd, 290const char *mgs_set_require_section(cmd_parms *cmd,
242 void *mconfig, const char *arg); 291 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..83e7bb5 100644
--- a/src/gnutls_cache.c
+++ b/src/gnutls_cache.c
@@ -34,17 +34,16 @@
34 34
35 35
36#define MC_TAG "mod_gnutls:" 36#define MC_TAG "mod_gnutls:"
37#define MC_TAG_LEN \ 37#define MC_TAG_LEN sizeof(MC_TAG)
38 (sizeof(MC_TAG))
39#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN) 38#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
40 39
41static char *gnutls_session_id2sz(unsigned char *id, int idlen, 40char *mgs_session_id2sz(unsigned char *id, int idlen,
42 char *str, int strsize) 41 char *str, int strsize)
43{ 42{
44 char *cp; 43 char *cp;
45 int n; 44 int n;
46 45
47 cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN); 46 cp = str;
48 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 47 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
49 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]); 48 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
50 cp += 2; 49 cp += 2;
@@ -53,23 +52,58 @@ static char *gnutls_session_id2sz(unsigned char *id, int idlen,
53 return str; 52 return str;
54} 53}
55 54
56char *mgs_session_id2sz(unsigned char *id, int idlen, 55
57 char *str, int strsize) 56/* Name the Session ID as:
57 * server:port.SessionID
58 * to disallow resuming sessions on different servers
59 */
60static int mgs_session_id2dbm(conn_rec* c, unsigned char *id, int idlen,
61 apr_datum_t* dbmkey)
58{ 62{
59 char *cp; 63char buf[STR_SESSION_LEN];
60 int n; 64char *sz;
61 65
62 cp = str; 66 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
63 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 67 if (sz == NULL)
64 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]); 68 return -1;
65 cp += 2; 69
66 } 70 dbmkey->dptr = apr_psprintf(c->pool, "%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
67 *cp = '\0'; 71 dbmkey->dsize = strlen( dbmkey->dptr);
68 return str; 72
73 return 0;
69} 74}
70 75
76#define CTIME "%b %d %k:%M:%S %Y %Z"
77char *mgs_time2sz(time_t in_time, char *str, int strsize)
78{
79 apr_time_exp_t vtm;
80 apr_size_t ret_size;
81 apr_time_t t;
82
83
84 apr_time_ansi_put (&t, in_time);
85 apr_time_exp_gmt (&vtm, t);
86 apr_strftime(str, &ret_size, strsize-1, CTIME, &vtm);
87
88 return str;
89}
71 90
72#if HAVE_APR_MEMCACHE 91#if HAVE_APR_MEMCACHE
92/* Name the Session ID as:
93 * server:port.SessionID
94 * to disallow resuming sessions on different servers
95 */
96static char* mgs_session_id2mc(conn_rec* c, unsigned char *id, int idlen)
97{
98char buf[STR_SESSION_LEN];
99char *sz;
100
101 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
102 if (sz == NULL)
103 return NULL;
104
105 return apr_psprintf(c->pool, MC_TAG"%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
106}
73 107
74/** 108/**
75 * GnuTLS Session Cache using libmemcached 109 * GnuTLS Session Cache using libmemcached
@@ -167,11 +201,10 @@ static int mc_cache_store(void* baton, gnutls_datum_t key,
167{ 201{
168 apr_status_t rv = APR_SUCCESS; 202 apr_status_t rv = APR_SUCCESS;
169 mgs_handle_t *ctxt = baton; 203 mgs_handle_t *ctxt = baton;
170 char buf[STR_SESSION_LEN];
171 char* strkey = NULL; 204 char* strkey = NULL;
172 apr_uint32_t timeout; 205 apr_uint32_t timeout;
173 206
174 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); 207 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
175 if(!strkey) 208 if(!strkey)
176 return -1; 209 return -1;
177 210
@@ -194,13 +227,12 @@ static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
194{ 227{
195 apr_status_t rv = APR_SUCCESS; 228 apr_status_t rv = APR_SUCCESS;
196 mgs_handle_t *ctxt = baton; 229 mgs_handle_t *ctxt = baton;
197 char buf[STR_SESSION_LEN];
198 char* strkey = NULL; 230 char* strkey = NULL;
199 char* value; 231 char* value;
200 apr_size_t value_len; 232 apr_size_t value_len;
201 gnutls_datum_t data = { NULL, 0 }; 233 gnutls_datum_t data = { NULL, 0 };
202 234
203 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); 235 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
204 if (!strkey) { 236 if (!strkey) {
205 return data; 237 return data;
206 } 238 }
@@ -235,10 +267,9 @@ static int mc_cache_delete(void* baton, gnutls_datum_t key)
235{ 267{
236 apr_status_t rv = APR_SUCCESS; 268 apr_status_t rv = APR_SUCCESS;
237 mgs_handle_t *ctxt = baton; 269 mgs_handle_t *ctxt = baton;
238 char buf[STR_SESSION_LEN];
239 char* strkey = NULL; 270 char* strkey = NULL;
240 271
241 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); 272 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
242 if(!strkey) 273 if(!strkey)
243 return -1; 274 return -1;
244 275
@@ -349,10 +380,8 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
349 mgs_handle_t *ctxt = baton; 380 mgs_handle_t *ctxt = baton;
350 apr_status_t rv; 381 apr_status_t rv;
351 382
352 dbmkey.dptr = key.data; 383 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
353 dbmkey.dsize = key.size; 384 return data;
354
355 dbm_cache_expire(ctxt);
356 385
357 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 386 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
358 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); 387 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
@@ -398,9 +427,9 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key,
398 mgs_handle_t *ctxt = baton; 427 mgs_handle_t *ctxt = baton;
399 apr_status_t rv; 428 apr_status_t rv;
400 apr_time_t expiry; 429 apr_time_t expiry;
401 430
402 dbmkey.dptr = (char *)key.data; 431 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
403 dbmkey.dsize = key.size; 432 return -1;
404 433
405 /* create DBM value */ 434 /* create DBM value */
406 dbmval.dsize = data.size + sizeof(apr_time_t); 435 dbmval.dsize = data.size + sizeof(apr_time_t);
@@ -412,6 +441,8 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key,
412 memcpy((char *)dbmval.dptr+sizeof(apr_time_t), 441 memcpy((char *)dbmval.dptr+sizeof(apr_time_t),
413 data.data, data.size); 442 data.data, data.size);
414 443
444 /* we expire dbm only on every store
445 */
415 dbm_cache_expire(ctxt); 446 dbm_cache_expire(ctxt);
416 447
417 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 448 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
@@ -450,12 +481,10 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key)
450 apr_datum_t dbmkey; 481 apr_datum_t dbmkey;
451 mgs_handle_t *ctxt = baton; 482 mgs_handle_t *ctxt = baton;
452 apr_status_t rv; 483 apr_status_t rv;
453
454 dbmkey.dptr = (char *)key.data;
455 dbmkey.dsize = key.size;
456 484
457 dbm_cache_expire(ctxt); 485 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
458 486 return -1;
487
459 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 488 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
460 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); 489 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
461 if (rv != APR_SUCCESS) { 490 if (rv != APR_SUCCESS) {
diff --git a/src/gnutls_config.c b/src/gnutls_config.c
index d3879f1..f08512e 100644
--- a/src/gnutls_config.c
+++ b/src/gnutls_config.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.
@@ -17,225 +18,449 @@
17 18
18#include "mod_gnutls.h" 19#include "mod_gnutls.h"
19 20
20static int load_datum_from_file(apr_pool_t* pool, 21static int load_datum_from_file(apr_pool_t * pool,
21 const char* file, 22 const char *file, gnutls_datum_t * data)
22 gnutls_datum_t* data)
23{ 23{
24 apr_file_t* fp; 24 apr_file_t *fp;
25 apr_finfo_t finfo; 25 apr_finfo_t finfo;
26 apr_status_t rv; 26 apr_status_t rv;
27 apr_size_t br = 0; 27 apr_size_t br = 0;
28 28
29 rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, 29 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, APR_OS_DEFAULT,
30 pool); 30 pool);
31 if (rv != APR_SUCCESS) { 31 if (rv != APR_SUCCESS) {
32 return rv; 32 return rv;
33 } 33 }
34 34
35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
36 36
37 if (rv != APR_SUCCESS) { 37 if (rv != APR_SUCCESS) {
38 return rv; 38 return rv;
39 } 39 }
40 40
41 data->data = apr_palloc(pool, finfo.size+1); 41 data->data = apr_palloc(pool, finfo.size + 1);
42 rv = apr_file_read_full(fp, data->data, finfo.size, &br); 42 rv = apr_file_read_full(fp, data->data, finfo.size, &br);
43 43
44 if (rv != APR_SUCCESS) { 44 if (rv != APR_SUCCESS) {
45 return rv; 45 return rv;
46 } 46 }
47 apr_file_close(fp); 47 apr_file_close(fp);
48 48
49 data->data[br] = '\0'; 49 data->data[br] = '\0';
50 data->size = br; 50 data->size = br;
51 51
52 return 0; 52 return 0;
53} 53}
54 54
55const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 55const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
56 const char *arg) 56 const char *arg)
57{ 57{
58 int ret; 58 int ret;
59 gnutls_datum_t data; 59 gnutls_datum_t data;
60 const char* file; 60 const char *file;
61 apr_pool_t* spool; 61 apr_pool_t *spool;
62 mgs_srvconf_rec *sc = 62 mgs_srvconf_rec *sc =
63 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 63 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
64 module_config, 64 module_config,
65 &gnutls_module); 65 &gnutls_module);
66
66 apr_pool_create(&spool, parms->pool); 67 apr_pool_create(&spool, parms->pool);
67 68
68 file = ap_server_root_relative(spool, arg); 69 file = ap_server_root_relative(spool, arg);
69 70
70 if (load_datum_from_file(spool, file, &data) != 0) { 71 if (load_datum_from_file(spool, file, &data) != 0) {
71 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 72 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
72 "Certificate '%s'", file); 73 "DH params '%s'", file);
73 } 74 }
74 75
75 gnutls_x509_crt_init(&sc->cert_x509); 76 ret = gnutls_dh_params_init(&sc->dh_params);
76 ret = gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM); 77 if (ret < 0) {
78 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
79 ": (%d) %s", ret, gnutls_strerror(ret));
80 }
81
82 ret =
83 gnutls_dh_params_import_pkcs3(sc->dh_params, &data, GNUTLS_X509_FMT_PEM);
84 if (ret < 0) {
85 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
86 "DH params '%s': (%d) %s", file, ret,
87 gnutls_strerror(ret));
88 }
89
90 apr_pool_destroy(spool);
91
92 return NULL;
93}
94
95const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
96 const char *arg)
97{
98 int ret;
99 gnutls_datum_t data;
100 const char *file;
101 apr_pool_t *spool;
102 mgs_srvconf_rec *sc =
103 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
104 module_config,
105 &gnutls_module);
106
107 apr_pool_create(&spool, parms->pool);
108
109 file = ap_server_root_relative(spool, arg);
110
111 if (load_datum_from_file(spool, file, &data) != 0) {
112 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
113 "RSA params '%s'", file);
114 }
115
116 ret = gnutls_rsa_params_init(&sc->rsa_params);
117 if (ret < 0) {
118 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
119 ": (%d) %s", ret, gnutls_strerror(ret));
120 }
121
122 ret =
123 gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data, GNUTLS_X509_FMT_PEM);
77 if (ret != 0) { 124 if (ret != 0) {
78 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " 125 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
79 "Certificate'%s': (%d) %s", file, ret, 126 "RSA params '%s': (%d) %s", file, ret,
80 gnutls_strerror(ret)); 127 gnutls_strerror(ret));
81 } 128 }
82 129
130 apr_pool_destroy(spool);
131 return NULL;
132}
133
134
135const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
136 const char *arg)
137{
138 int ret;
139 gnutls_datum_t data;
140 const char *file;
141 apr_pool_t *spool;
142 mgs_srvconf_rec *sc =
143 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
144 module_config,
145 &gnutls_module);
146 apr_pool_create(&spool, parms->pool);
147
148 file = ap_server_root_relative(spool, arg);
149
150 if (load_datum_from_file(spool, file, &data) != 0) {
151 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
152 "Certificate '%s'", file);
153 }
154
155 sc->certs_x509_num = MAX_CHAIN_SIZE;
156 ret =
157 gnutls_x509_crt_list_import(sc->certs_x509, &sc->certs_x509_num, &data, GNUTLS_X509_FMT_PEM, 0);
158 if (ret < 0) {
159 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
160 "Certificate '%s': (%d) %s", file, ret,
161 gnutls_strerror(ret));
162 }
163
83 apr_pool_destroy(spool); 164 apr_pool_destroy(spool);
84 return NULL; 165 return NULL;
85} 166}
86 167
87const char *mgs_set_key_file(cmd_parms * parms, void *dummy, 168const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
88 const char *arg) 169 const char *arg)
89{ 170{
90 int ret; 171 int ret;
91 gnutls_datum_t data; 172 gnutls_datum_t data;
92 const char* file; 173 const char *file;
93 apr_pool_t* spool; 174 apr_pool_t *spool;
94 mgs_srvconf_rec *sc = 175 mgs_srvconf_rec *sc =
95 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 176 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
96 module_config, 177 module_config,
97 &gnutls_module); 178 &gnutls_module);
98 apr_pool_create(&spool, parms->pool); 179 apr_pool_create(&spool, parms->pool);
99 180
100 file = ap_server_root_relative(spool, arg); 181 file = ap_server_root_relative(spool, arg);
101 182
102 if (load_datum_from_file(spool, file, &data) != 0) { 183 if (load_datum_from_file(spool, file, &data) != 0) {
103 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 184 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
104 "Private Key '%s'", file); 185 "Private Key '%s'", file);
105 } 186 }
106 187
107 gnutls_x509_privkey_init(&sc->privkey_x509); 188 ret = gnutls_x509_privkey_init(&sc->privkey_x509);
108 ret = gnutls_x509_privkey_import(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM); 189 if (ret < 0) {
190 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
191 ": (%d) %s", ret, gnutls_strerror(ret));
192 }
193
194 ret =
195 gnutls_x509_privkey_import(sc->privkey_x509, &data,
196 GNUTLS_X509_FMT_PEM);
109 if (ret != 0) { 197 if (ret != 0) {
110 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " 198 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
111 "Private Key '%s': (%d) %s", file, ret, 199 "Private Key '%s': (%d) %s", file, ret,
112 gnutls_strerror(ret)); 200 gnutls_strerror(ret));
113 } 201 }
114 apr_pool_destroy(spool); 202 apr_pool_destroy(spool);
115 return NULL; 203 return NULL;
116} 204}
117 205
206const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
207 const char *arg)
208{
209 int ret;
210 gnutls_datum_t data;
211 const char *file;
212 apr_pool_t *spool;
213 mgs_srvconf_rec *sc =
214 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
215 module_config,
216 &gnutls_module);
217 apr_pool_create(&spool, parms->pool);
218
219 file = ap_server_root_relative(spool, arg);
220
221 if (load_datum_from_file(spool, file, &data) != 0) {
222 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
223 "Certificate '%s'", file);
224 }
225
226 ret = gnutls_openpgp_crt_init( &sc->cert_pgp);
227 if (ret < 0) {
228 return apr_psprintf(parms->pool, "GnuTLS: Failed to Init "
229 "PGP Certificate: (%d) %s", ret,
230 gnutls_strerror(ret));
231 }
232
233 ret =
234 gnutls_openpgp_crt_import(sc->cert_pgp, &data, GNUTLS_OPENPGP_FMT_BASE64);
235 if (ret < 0) {
236 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
237 "PGP Certificate '%s': (%d) %s", file, ret,
238 gnutls_strerror(ret));
239 }
240
241 apr_pool_destroy(spool);
242 return NULL;
243}
244
245const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
246 const char *arg)
247{
248 int ret;
249 gnutls_datum_t data;
250 const char *file;
251 apr_pool_t *spool;
252 mgs_srvconf_rec *sc =
253 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
254 module_config,
255 &gnutls_module);
256 apr_pool_create(&spool, parms->pool);
257
258 file = ap_server_root_relative(spool, arg);
259
260 if (load_datum_from_file(spool, file, &data) != 0) {
261 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
262 "Private Key '%s'", file);
263 }
264
265 ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp);
266 if (ret < 0) {
267 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
268 ": (%d) %s", ret, gnutls_strerror(ret));
269 }
270
271 ret =
272 gnutls_openpgp_privkey_import(sc->privkey_pgp, &data,
273 GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
274 if (ret != 0) {
275 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
276 "PGP Private Key '%s': (%d) %s", file, ret,
277 gnutls_strerror(ret));
278 }
279 apr_pool_destroy(spool);
280 return NULL;
281}
282
283
284const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
285 const char *arg)
286{
287 mgs_srvconf_rec *sc =
288 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
289 module_config,
290 &gnutls_module);
291
292 sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
293
294 return NULL;
295}
296
297const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy,
298 const char *arg)
299{
300 mgs_srvconf_rec *sc =
301 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
302 module_config,
303 &gnutls_module);
304
305 sc->srp_tpasswd_conf_file = ap_server_root_relative(parms->pool, arg);
306
307 return NULL;
308}
309
118const char *mgs_set_cache(cmd_parms * parms, void *dummy, 310const char *mgs_set_cache(cmd_parms * parms, void *dummy,
119 const char *type, const char* arg) 311 const char *type, const char *arg)
120{ 312{
121 const char* err; 313 const char *err;
122 mgs_srvconf_rec *sc = ap_get_module_config(parms->server-> 314 mgs_srvconf_rec *sc = ap_get_module_config(parms->server->
123 module_config, 315 module_config,
124 &gnutls_module); 316 &gnutls_module);
125 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 317 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
126 return err; 318 return err;
127 } 319 }
128 320
129 if (strcasecmp("none", type) == 0) { 321 if (strcasecmp("none", type) == 0) {
130 sc->cache_type = mgs_cache_none; 322 sc->cache_type = mgs_cache_none;
131 } 323 } else if (strcasecmp("dbm", type) == 0) {
132 else if (strcasecmp("dbm", type) == 0) { 324 sc->cache_type = mgs_cache_dbm;
133 sc->cache_type = mgs_cache_dbm;
134 } 325 }
135#if HAVE_APR_MEMCACHE 326#if HAVE_APR_MEMCACHE
136 else if (strcasecmp("memcache", type) == 0) { 327 else if (strcasecmp("memcache", type) == 0) {
137 sc->cache_type = mgs_cache_memcache; 328 sc->cache_type = mgs_cache_memcache;
138 } 329 }
139#endif 330#endif
140 else { 331 else {
141 return "Invalid Type for GnuTLSCache!"; 332 return "Invalid Type for GnuTLSCache!";
142 } 333 }
143 334
144 if (sc->cache_type == mgs_cache_dbm) { 335 if (sc->cache_type == mgs_cache_dbm) {
145 sc->cache_config = ap_server_root_relative(parms->pool, arg); 336 sc->cache_config = ap_server_root_relative(parms->pool, arg);
146 } 337 } else {
147 else { 338 sc->cache_config = apr_pstrdup(parms->pool, arg);
148 sc->cache_config = apr_pstrdup(parms->pool, arg);
149 } 339 }
150 340
151 return NULL; 341 return NULL;
152} 342}
153 343
154const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy, 344const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy,
155 const char *arg) 345 const char *arg)
156{ 346{
157 int argint; 347 int argint;
158 mgs_srvconf_rec *sc = 348 mgs_srvconf_rec *sc =
159 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 349 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
160 module_config, 350 module_config,
161 &gnutls_module); 351 &gnutls_module);
162 352
163 argint = atoi(arg); 353 argint = atoi(arg);
164 354
165 if (argint < 0) { 355 if (argint < 0) {
166 return "GnuTLSCacheTimeout: Invalid argument"; 356 return "GnuTLSCacheTimeout: Invalid argument";
167 } 357 } else if (argint == 0) {
168 else if (argint == 0) { 358 sc->cache_timeout = 0;
169 sc->cache_timeout = 0; 359 } else {
360 sc->cache_timeout = apr_time_from_sec(argint);
170 } 361 }
171 else { 362
172 sc->cache_timeout = apr_time_from_sec(argint);
173 }
174
175 return NULL; 363 return NULL;
176} 364}
177 365
178const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, 366const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
179 const char *arg) 367 const char *arg)
180{ 368{
181 int mode; 369 int mode;
182 370
183 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { 371 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
184 mode = GNUTLS_CERT_IGNORE; 372 mode = GNUTLS_CERT_IGNORE;
185 } 373 } else if (strcasecmp("optional", arg) == 0
186 else if (strcasecmp("optional", arg) == 0 || strcasecmp("request", arg) == 0) { 374 || strcasecmp("request", arg) == 0) {
187 mode = GNUTLS_CERT_REQUEST; 375 mode = GNUTLS_CERT_REQUEST;
188 } 376 } else if (strcasecmp("require", arg) == 0) {
189 else if (strcasecmp("require", arg) == 0) { 377 mode = GNUTLS_CERT_REQUIRE;
190 mode = GNUTLS_CERT_REQUIRE; 378 } else {
191 } 379 return "GnuTLSClientVerify: Invalid argument";
192 else {
193 return "GnuTLSClientVerify: Invalid argument";
194 } 380 }
195 381
196 /* This was set from a directory context */ 382 /* This was set from a directory context */
197 if (parms->path) { 383 if (parms->path) {
198 mgs_dirconf_rec *dc = (mgs_dirconf_rec *)dummy; 384 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
199 dc->client_verify_mode = mode; 385 dc->client_verify_mode = mode;
200 } 386 } else {
201 else { 387 mgs_srvconf_rec *sc =
202 mgs_srvconf_rec *sc = 388 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
203 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 389 module_config,
204 module_config, 390 &gnutls_module);
205 &gnutls_module); 391 sc->client_verify_mode = mode;
206 sc->client_verify_mode = mode;
207 } 392 }
208 393
209 return NULL; 394 return NULL;
210} 395}
211 396
212const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 397const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
213 const char *arg) 398 const char *arg)
214{ 399{
215 int rv; 400 int rv;
216 const char* file; 401 const char *file;
217 apr_pool_t* spool; 402 apr_pool_t *spool;
218 gnutls_datum_t data; 403 gnutls_datum_t data;
219 404
220 mgs_srvconf_rec *sc = 405 mgs_srvconf_rec *sc =
221 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 406 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
222 module_config, 407 module_config,
223 &gnutls_module); 408 &gnutls_module);
224 apr_pool_create(&spool, parms->pool); 409 apr_pool_create(&spool, parms->pool);
225 410
226 file = ap_server_root_relative(spool, arg); 411 file = ap_server_root_relative(spool, arg);
227 412
228 sc->ca_list_size = 16; 413 if (load_datum_from_file(spool, file, &data) != 0) {
414 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
415 "Client CA File '%s'", file);
416 }
417
418 sc->ca_list_size = MAX_CA_CRTS;
419 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
420 &data, GNUTLS_X509_FMT_PEM,
421 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
422 if (rv < 0) {
423 return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
424 "Client CA File '%s': (%d) %s", file, rv,
425 gnutls_strerror(rv));
426 }
229 427
230 load_datum_from_file(spool, file, &data); 428 apr_pool_destroy(spool);
429 return NULL;
430}
231 431
232 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size, 432const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
233 &data, GNUTLS_X509_FMT_PEM, 433 const char *arg)
234 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); 434{
435 int rv;
436 const char *file;
437 apr_pool_t *spool;
438 gnutls_datum_t data;
439
440 mgs_srvconf_rec *sc =
441 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
442 module_config,
443 &gnutls_module);
444 apr_pool_create(&spool, parms->pool);
445
446 file = ap_server_root_relative(spool, arg);
447
448 if (load_datum_from_file(spool, file, &data) != 0) {
449 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
450 "Keyring File '%s'", file);
451 }
452
453 rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
235 if (rv < 0) { 454 if (rv < 0) {
236 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 455 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
237 "Client CA File '%s': (%d) %s", file, rv, 456 "keyring: (%d) %s", rv, gnutls_strerror(rv));
238 gnutls_strerror(rv)); 457 }
458
459 rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, GNUTLS_OPENPGP_FMT_BASE64);
460 if (rv < 0) {
461 return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
462 "Keyring File '%s': (%d) %s", file, rv,
463 gnutls_strerror(rv));
239 } 464 }
240 465
241 apr_pool_destroy(spool); 466 apr_pool_destroy(spool);
@@ -243,20 +468,57 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
243} 468}
244 469
245const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 470const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
246 const char *arg) 471 const char *arg)
247{ 472{
248 mgs_srvconf_rec *sc = 473 mgs_srvconf_rec *sc =
249 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 474 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
250 module_config, 475 module_config,
251 &gnutls_module); 476 &gnutls_module);
252 if (!strcasecmp(arg, "On")) { 477 if (!strcasecmp(arg, "On")) {
253 sc->enabled = GNUTLS_ENABLED_TRUE; 478 sc->enabled = GNUTLS_ENABLED_TRUE;
479 } else if (!strcasecmp(arg, "Off")) {
480 sc->enabled = GNUTLS_ENABLED_FALSE;
481 } else {
482 return "GnuTLSEnable must be set to 'On' or 'Off'";
254 } 483 }
255 else if (!strcasecmp(arg, "Off")) { 484
256 sc->enabled = GNUTLS_ENABLED_FALSE; 485 return NULL;
486}
487
488const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
489 const char *arg)
490{
491 mgs_srvconf_rec *sc =
492 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
493 module_config,
494 &gnutls_module);
495 if (!strcasecmp(arg, "On")) {
496 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
497 } else if (!strcasecmp(arg, "Off")) {
498 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
499 } else {
500 return "GnuTLSExportCertificates must be set to 'On' or 'Off'";
257 } 501 }
258 else { 502
259 return "GnuTLSEnable must be set to 'On' or 'Off'"; 503 return NULL;
504}
505
506
507const char *mgs_set_priorities(cmd_parms * parms, void *dummy, const char *arg)
508{
509 int ret;
510 const char *err;
511 mgs_srvconf_rec *sc =
512 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
513 module_config,
514 &gnutls_module);
515
516
517 ret = gnutls_priority_init( &sc->priorities, arg, &err);
518 if (ret < 0) {
519 if (ret == GNUTLS_E_INVALID_REQUEST)
520 return apr_psprintf(parms->pool, "GnuTLS: Syntax error parsing priorities string at: %s", err);
521 return "Error setting priorities";
260 } 522 }
261 523
262 return NULL; 524 return NULL;
@@ -264,92 +526,63 @@ const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
264 526
265void *mgs_config_server_create(apr_pool_t * p, server_rec * s) 527void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
266{ 528{
267 int i;
268 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc)); 529 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
530 int ret;
269 531
270 sc->enabled = GNUTLS_ENABLED_FALSE; 532 sc->enabled = GNUTLS_ENABLED_FALSE;
271 533
272 gnutls_certificate_allocate_credentials(&sc->certs); 534 ret = gnutls_certificate_allocate_credentials(&sc->certs);
535 if (ret < 0) {
536 return apr_psprintf(p, "GnuTLS: Failed to initialize"
537 ": (%d) %s", ret, gnutls_strerror(ret));
538 }
539
540 ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
541 if (ret < 0) {
542 return apr_psprintf(p, "GnuTLS: Failed to initialize"
543 ": (%d) %s", ret, gnutls_strerror(ret));
544 }
545
546 ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
547 if (ret < 0) {
548 return apr_psprintf(p, "GnuTLS: Failed to initialize"
549 ": (%d) %s", ret, gnutls_strerror(ret));
550 }
551
552 sc->srp_tpasswd_conf_file = NULL;
553 sc->srp_tpasswd_file = NULL;
273 sc->privkey_x509 = NULL; 554 sc->privkey_x509 = NULL;
274 sc->cert_x509 = NULL; 555 memset( sc->certs_x509, 0, sizeof(sc->certs_x509));
556 sc->certs_x509_num = 0;
275 sc->cache_timeout = apr_time_from_sec(300); 557 sc->cache_timeout = apr_time_from_sec(300);
276 sc->cache_type = mgs_cache_dbm; 558 sc->cache_type = mgs_cache_dbm;
277 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 559 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
278 560
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");
281 sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile");
282
283 /* Finish SSL Client Certificate Support */
284 sc->client_verify_mode = GNUTLS_CERT_IGNORE; 561 sc->client_verify_mode = GNUTLS_CERT_IGNORE;
285 562
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; 563 return sc;
330} 564}
331 565
332void *mgs_config_dir_merge(apr_pool_t *p, void *basev, void *addv) 566void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv)
333{ 567{
334 mgs_dirconf_rec *new; 568 mgs_dirconf_rec *new;
335 mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; 569/* mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
336 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv; 570 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
337 571
338 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec)); 572 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
339 new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode, 573 new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode,
340 add->lua_bytecode_len); 574 add->lua_bytecode_len);
341 new->lua_bytecode_len = add->lua_bytecode_len; 575 new->lua_bytecode_len = add->lua_bytecode_len;
342 new->client_verify_mode = add->client_verify_mode; 576 new->client_verify_mode = add->client_verify_mode;
343 return new; 577 return new;
344} 578}
345 579
346void *mgs_config_dir_create(apr_pool_t *p, char *dir) 580void *mgs_config_dir_create(apr_pool_t * p, char *dir)
347{ 581{
348 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc)); 582 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
349 583
350 dc->client_verify_mode = -1; 584 dc->client_verify_mode = -1;
351 dc->lua_bytecode = NULL; 585 dc->lua_bytecode = NULL;
352 dc->lua_bytecode_len = 0; 586 dc->lua_bytecode_len = 0;
353 return dc; 587 return dc;
354} 588}
355
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c
index 8452d36..26917b8 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,20 @@ 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_t cert,
40 int side,
41 int export_certificates_enabled);
42static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
43 int side,
44 int export_certificates_enabled);
45
36static apr_status_t mgs_cleanup_pre_config(void *data) 46static apr_status_t mgs_cleanup_pre_config(void *data)
37{ 47{
38 gnutls_global_deinit(); 48 gnutls_global_deinit();
@@ -40,208 +50,384 @@ static apr_status_t mgs_cleanup_pre_config(void *data)
40} 50}
41 51
42#if MOD_GNUTLS_DEBUG 52#if MOD_GNUTLS_DEBUG
43static void gnutls_debug_log_all( int level, const char* str) 53static void gnutls_debug_log_all(int level, const char *str)
44{ 54{
45 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str); 55 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
46} 56}
47#endif 57#endif
48 58
49int mgs_hook_pre_config(apr_pool_t * pconf, 59int
50 apr_pool_t * plog, apr_pool_t * ptemp) 60mgs_hook_pre_config(apr_pool_t * pconf,
61 apr_pool_t * plog, apr_pool_t * ptemp)
51{ 62{
63int ret;
52 64
53#if APR_HAS_THREADS 65#if APR_HAS_THREADS
54 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded); 66 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
55 if (mpm_is_threaded) { 67 if (mpm_is_threaded) {
56 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); 68 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
57 } 69 }
58#else 70#else
59 mpm_is_threaded = 0; 71 mpm_is_threaded = 0;
60#endif 72#endif
61 73
62 gnutls_global_init(); 74 if (gnutls_check_version(LIBGNUTLS_VERSION)==NULL) {
75 fprintf(stderr, "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
76 LIBGNUTLS_VERSION, gnutls_check_version(NULL));
77 return -3;
78 }
79
80 ret = gnutls_global_init();
81 if (ret < 0) {
82 fprintf(stderr, "gnutls_global_init: %s\n", gnutls_strerror(ret));
83 return -3;
84 }
63 85
86 ret = gnutls_global_init_extra();
87 if (ret < 0) {
88 fprintf(stderr, "gnutls_global_init_extra: %s\n", gnutls_strerror(ret));
89 return -3;
90 }
91
64 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 92 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
65 apr_pool_cleanup_null); 93 apr_pool_cleanup_null);
66 94
67#if MOD_GNUTLS_DEBUG 95#if MOD_GNUTLS_DEBUG
68 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", 96 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
69 APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf); 97 APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
98 pconf);
70 99
71 gnutls_global_set_log_level(9); 100 gnutls_global_set_log_level(9);
72 gnutls_global_set_log_function(gnutls_debug_log_all); 101 gnutls_global_set_log_function(gnutls_debug_log_all);
102 apr_file_printf(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
73#endif 103#endif
74 104
75 return OK; 105 return OK;
76} 106}
77 107
108static int mgs_select_virtual_server_cb(gnutls_session_t session)
109{
110 mgs_handle_t *ctxt;
111 mgs_srvconf_rec *tsc;
112 int ret;
113 int cprio[2];
114
115 ctxt = gnutls_transport_get_ptr(session);
116
117 /* find the virtual server */
118 tsc = mgs_find_sni_server(session);
119
120 if (tsc != NULL)
121 ctxt->sc = tsc;
122
123 gnutls_certificate_server_set_request(session,
124 ctxt->sc->client_verify_mode);
125
126 /* set the new server credentials
127 */
128
129 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
130 ctxt->sc->certs);
131
132 gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
133
134 if (ctxt->sc->srp_tpasswd_conf_file != NULL
135 && ctxt->sc->srp_tpasswd_file != NULL) {
136 gnutls_credentials_set(session, GNUTLS_CRD_SRP,
137 ctxt->sc->srp_creds);
138 }
139
140 /* update the priorities - to avoid negotiating a ciphersuite that is not
141 * enabled on this virtual server. Note that here we ignore the version
142 * negotiation.
143 */
144 ret = gnutls_priority_set(session, ctxt->sc->priorities);
145 /* actually it shouldn't fail since we have checked at startup */
146 if (ret < 0)
147 return ret;
148
149 /* If both certificate types are not present disallow them from
150 * being negotiated.
151 */
152 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
153 cprio[0] = GNUTLS_CRT_X509;
154 cprio[1] = 0;
155 gnutls_certificate_type_set_priority( session, cprio);
156 } else if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0]==NULL) {
157 cprio[0] = GNUTLS_CRT_OPENPGP;
158 cprio[1] = 0;
159 gnutls_certificate_type_set_priority( session, cprio);
160 }
161
162 return 0;
163}
78 164
79static gnutls_datum load_params(const char* file, server_rec* s, 165static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
80 apr_pool_t* pool)
81{ 166{
82 gnutls_datum ret = { NULL, 0 }; 167 mgs_handle_t *ctxt;
83 apr_file_t* fp; 168
84 apr_finfo_t finfo; 169 ctxt = gnutls_transport_get_ptr(session);
85 apr_status_t rv; 170
86 apr_size_t br = 0; 171 if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) {
172 ret->type = GNUTLS_CRT_X509;
173 ret->ncerts = ctxt->sc->certs_x509_num;
174 ret->deinit_all = 0;
87 175
88 rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, 176 ret->cert.x509 = ctxt->sc->certs_x509;
89 pool); 177 ret->key.x509 = ctxt->sc->privkey_x509;
90 if (rv != APR_SUCCESS) { 178
91 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 179 return 0;
92 "GnuTLS failed to load params file at: %s", file); 180 } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) {
93 return ret; 181 ret->type = GNUTLS_CRT_OPENPGP;
182 ret->ncerts = 1;
183 ret->deinit_all = 0;
184
185 ret->cert.pgp = ctxt->sc->cert_pgp;
186 ret->key.pgp = ctxt->sc->privkey_pgp;
187
188 return 0;
189
94 } 190 }
95 191
96 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 192 return GNUTLS_E_INTERNAL_ERROR;
193}
97 194
98 if (rv != APR_SUCCESS) { 195/* 2048-bit group parameters from SRP specification */
99 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 196const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
100 "GnuTLS failed to stat params file at: %s", file); 197 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
101 return ret; 198 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
199 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
200 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
201 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
202 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
203 "-----END DH PARAMETERS-----\n";
204
205/* Read the common name or the alternative name of the certificate.
206 * We only support a single name per certificate.
207 *
208 * Returns negative on error.
209 */
210static int read_crt_cn(server_rec * s, apr_pool_t * p,
211 gnutls_x509_crt_t cert, char **cert_cn)
212{
213 int rv = 0, i;
214 size_t data_len;
215
216
217 *cert_cn = NULL;
218
219 data_len = 0;
220 rv = gnutls_x509_crt_get_dn_by_oid(cert,
221 GNUTLS_OID_X520_COMMON_NAME,
222 0, 0, NULL, &data_len);
223
224 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
225 *cert_cn = apr_palloc(p, data_len);
226 rv = gnutls_x509_crt_get_dn_by_oid(cert,
227 GNUTLS_OID_X520_COMMON_NAME, 0,
228 0, *cert_cn, &data_len);
229 } else { /* No CN return subject alternative name */
230 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
231 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
232 s->server_hostname, s->port);
233 rv = 0;
234 /* read subject alternative name */
235 for (i = 0; !(rv < 0); i++) {
236 data_len = 0;
237 rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
238 NULL, &data_len,
239 NULL);
240
241 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
242 /* FIXME: not very efficient. What if we have several alt names
243 * before DNSName?
244 */
245 *cert_cn = apr_palloc(p, data_len + 1);
246
247 rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
248 *cert_cn,
249 &data_len, NULL);
250 (*cert_cn)[data_len] = 0;
251
252 if (rv == GNUTLS_SAN_DNSNAME)
253 break;
254 }
255 }
102 } 256 }
103 257
104 ret.data = apr_palloc(pool, finfo.size+1); 258 return rv;
105 rv = apr_file_read_full(fp, ret.data, finfo.size, &br); 259}
260
261static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
262 gnutls_openpgp_crt_t cert, char **cert_cn)
263{
264 int rv = 0;
265 size_t data_len;
266
106 267
107 if (rv != APR_SUCCESS) { 268 *cert_cn = NULL;
108 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 269
109 "GnuTLS failed to read params file at: %s", file); 270 data_len = 0;
110 return ret; 271 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
272
273 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
274 *cert_cn = apr_palloc(p, data_len);
275 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len);
276 } else { /* No CN return subject alternative name */
277 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
278 "No name found in PGP certificate for '%s:%d'.",
279 s->server_hostname, s->port);
111 } 280 }
112 apr_file_close(fp);
113 ret.data[br] = '\0';
114 ret.size = br;
115 281
116 return ret; 282 return rv;
117} 283}
118 284
119int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 285
120 apr_pool_t * ptemp, 286int
121 server_rec * base_server) 287mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
288 apr_pool_t * ptemp, server_rec * base_server)
122{ 289{
123 int rv; 290 int rv;
124 int data_len;
125 server_rec *s; 291 server_rec *s;
126 gnutls_dh_params_t dh_params; 292 gnutls_dh_params_t dh_params = NULL;
127 gnutls_rsa_params_t rsa_params; 293 gnutls_rsa_params_t rsa_params = NULL;
128 mgs_srvconf_rec *sc; 294 mgs_srvconf_rec *sc;
129 mgs_srvconf_rec *sc_base; 295 mgs_srvconf_rec *sc_base;
130 void *data = NULL; 296 void *data = NULL;
131 int first_run = 0; 297 int first_run = 0;
132 const char *userdata_key = "mgs_init"; 298 const char *userdata_key = "mgs_init";
133 299
134 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool); 300 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
135 if (data == NULL) { 301 if (data == NULL) {
136 first_run = 1; 302 first_run = 1;
137 apr_pool_userdata_set((const void *)1, userdata_key, 303 apr_pool_userdata_set((const void *) 1, userdata_key,
138 apr_pool_cleanup_null, 304 apr_pool_cleanup_null,
139 base_server->process->pool); 305 base_server->process->pool);
140 } 306 }
141 307
142 308
143 { 309 {
144 gnutls_datum pdata; 310 s = base_server;
145 apr_pool_t* tpool; 311 sc_base =
146 s = base_server; 312 (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
147 sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 313 &gnutls_module);
148 &gnutls_module); 314
149 315 gnutls_dh_params_init(&dh_params);
150 apr_pool_create(&tpool, p); 316
151 317 if (sc_base->dh_params == NULL) {
152 gnutls_dh_params_init(&dh_params); 318 gnutls_datum pdata = { (void *) static_dh_params, sizeof(static_dh_params) };
153 319 /* loading defaults */
154 pdata = load_params(sc_base->dh_params_file, s, tpool); 320 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
155 321 GNUTLS_X509_FMT_PEM);
156 if (pdata.size != 0) { 322
157 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 323 if (rv < 0) {
158 GNUTLS_X509_FMT_PEM); 324 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
159 if (rv != 0) { 325 "GnuTLS: Unable to load DH Params: (%d) %s",
160 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 326 rv, gnutls_strerror(rv));
161 "GnuTLS: Unable to load DH Params: (%d) %s",
162 rv, gnutls_strerror(rv));
163 exit(rv); 327 exit(rv);
164 } 328 }
165 } 329 } else dh_params = sc_base->dh_params;
166 else { 330
167 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 331 if (sc_base->rsa_params != NULL)
168 "GnuTLS: Unable to load DH Params." 332 rsa_params = sc_base->rsa_params;
169 " Shutting Down."); 333
170 exit(-1); 334 /* else not an error but RSA-EXPORT ciphersuites are not available
171 } 335 */
172 apr_pool_clear(tpool); 336
173 337 rv = mgs_cache_post_config(p, s, sc_base);
174 gnutls_rsa_params_init(&rsa_params); 338 if (rv != 0) {
175 339 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
176 pdata = load_params(sc_base->rsa_params_file, s, tpool); 340 "GnuTLS: Post Config for GnuTLSCache Failed."
177 341 " Shutting Down.");
178 if (pdata.size != 0) { 342 exit(-1);
179 rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata, 343 }
180 GNUTLS_X509_FMT_PEM); 344
181 if (rv != 0) { 345 for (s = base_server; s; s = s->next) {
182 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 346 void *load = NULL;
183 "GnuTLS: Unable to load RSA Params: (%d) %s", 347 sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
184 rv, gnutls_strerror(rv)); 348 &gnutls_module);
185 exit(rv); 349 sc->cache_type = sc_base->cache_type;
186 } 350 sc->cache_config = sc_base->cache_config;
187 } 351
188 else { 352 /* Check if the priorities have been set */
189 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 353 if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
190 "GnuTLS: Unable to load RSA Params." 354 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
191 " Shutting Down."); 355 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
192 exit(-1); 356 s->server_hostname, s->port);
193 } 357 exit(-1);
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 } 358 }
221 359
222 if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) { 360 /* Check if DH or RSA params have been set per host */
223 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 361 if (sc->rsa_params != NULL)
224 "[GnuTLS] - Host '%s:%d' is missing a " 362 load = sc->rsa_params;
225 "Private Key File!", 363 else if (rsa_params) load = rsa_params;
226 s->server_hostname, s->port);
227 exit(-1);
228 }
229 364
230 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, 365 if (load != NULL)
231 GNUTLS_OID_X520_COMMON_NAME, 0, 0, 366 gnutls_certificate_set_rsa_export_params(sc->certs, load);
232 NULL, &data_len); 367
368
369 load = NULL;
370 if (sc->dh_params != NULL)
371 load = sc->dh_params;
372 else if (dh_params) load = dh_params;
233 373
234 if (data_len < 1) { 374 if (load != NULL) { /* not needed but anyway */
235 sc->enabled = GNUTLS_ENABLED_FALSE; 375 gnutls_certificate_set_dh_params(sc->certs, load);
236 sc->cert_cn = NULL; 376 gnutls_anon_set_server_dh_params(sc->anon_creds, load);
237 continue;
238 } 377 }
239 378
240 sc->cert_cn = apr_palloc(p, data_len); 379 gnutls_certificate_server_set_retrieve_function(sc->certs,
241 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, 380 cert_retrieve_fn);
242 GNUTLS_OID_X520_COMMON_NAME, 0, 0, 381
243 sc->cert_cn, &data_len); 382 if (sc->srp_tpasswd_conf_file != NULL
244 } 383 && sc->srp_tpasswd_file != NULL) {
384 rv = gnutls_srp_set_server_credentials_file(sc->srp_creds,
385 sc->
386 srp_tpasswd_file,
387 sc->
388 srp_tpasswd_conf_file);
389
390 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
391 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
392 "[GnuTLS] - Host '%s:%d' is missing a "
393 "SRP password or conf File!",
394 s->server_hostname, s->port);
395 exit(-1);
396 }
397 }
398
399 if (sc->certs_x509[0] == NULL
400 && sc->enabled == GNUTLS_ENABLED_TRUE) {
401 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
402 "[GnuTLS] - Host '%s:%d' is missing a "
403 "Certificate File!", s->server_hostname,
404 s->port);
405 exit(-1);
406 }
407
408 if (sc->privkey_x509 == NULL
409 && sc->enabled == GNUTLS_ENABLED_TRUE) {
410 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
411 "[GnuTLS] - Host '%s:%d' is missing a "
412 "Private Key File!",
413 s->server_hostname, s->port);
414 exit(-1);
415 }
416
417 if (sc->enabled == GNUTLS_ENABLED_TRUE) {
418 rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn);
419 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */
420 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
421
422 if (rv < 0) {
423 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
424 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
425 s->server_hostname, s->port);
426 sc->cert_cn = NULL;
427 continue;
428 }
429 }
430 }
245 } 431 }
246 432
247 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 433 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
@@ -249,34 +435,32 @@ int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
249 return OK; 435 return OK;
250} 436}
251 437
252void mgs_hook_child_init(apr_pool_t *p, server_rec *s) 438void mgs_hook_child_init(apr_pool_t * p, server_rec * s)
253{ 439{
254 apr_status_t rv = APR_SUCCESS; 440 apr_status_t rv = APR_SUCCESS;
255 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 441 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
256 &gnutls_module); 442 &gnutls_module);
257 443
258 if (sc->cache_type != mgs_cache_none) { 444 if (sc->cache_type != mgs_cache_none) {
259 rv = mgs_cache_child_init(p, s, sc); 445 rv = mgs_cache_child_init(p, s, sc);
260 if(rv != APR_SUCCESS) { 446 if (rv != APR_SUCCESS) {
261 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 447 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
262 "[GnuTLS] - Failed to run Cache Init"); 448 "[GnuTLS] - Failed to run Cache Init");
263 } 449 }
264 } 450 } else {
265 else { 451 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
266 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, 452 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
267 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
268 } 453 }
269} 454}
270 455
271const char *mgs_hook_http_scheme(const request_rec * r) 456const char *mgs_hook_http_scheme(const request_rec * r)
272{ 457{
273 mgs_srvconf_rec *sc = 458 mgs_srvconf_rec *sc =
274 (mgs_srvconf_rec *) ap_get_module_config(r->server-> 459 (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
275 module_config, 460 &gnutls_module);
276 &gnutls_module);
277 461
278 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 462 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
279 return NULL; 463 return NULL;
280 } 464 }
281 465
282 return "https"; 466 return "https";
@@ -285,12 +469,11 @@ const char *mgs_hook_http_scheme(const request_rec * r)
285apr_port_t mgs_hook_default_port(const request_rec * r) 469apr_port_t mgs_hook_default_port(const request_rec * r)
286{ 470{
287 mgs_srvconf_rec *sc = 471 mgs_srvconf_rec *sc =
288 (mgs_srvconf_rec *) ap_get_module_config(r->server-> 472 (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config,
289 module_config, 473 &gnutls_module);
290 &gnutls_module);
291 474
292 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 475 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
293 return 0; 476 return 0;
294 } 477 }
295 478
296 return 443; 479 return 443;
@@ -299,88 +482,86 @@ apr_port_t mgs_hook_default_port(const request_rec * r)
299#define MAX_HOST_LEN 255 482#define MAX_HOST_LEN 255
300 483
301#if USING_2_1_RECENT 484#if USING_2_1_RECENT
302typedef struct 485typedef struct {
303{
304 mgs_handle_t *ctxt; 486 mgs_handle_t *ctxt;
305 mgs_srvconf_rec *sc; 487 mgs_srvconf_rec *sc;
306 const char* sni_name; 488 const char *sni_name;
307} vhost_cb_rec; 489} vhost_cb_rec;
308 490
309static int vhost_cb (void* baton, conn_rec* conn, server_rec* s) 491static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
310{ 492{
311 mgs_srvconf_rec *tsc; 493 mgs_srvconf_rec *tsc;
312 vhost_cb_rec* x = baton; 494 vhost_cb_rec *x = baton;
313 495
314 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 496 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
315 &gnutls_module); 497 &gnutls_module);
316 498
317 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 499 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
318 return 0; 500 return 0;
319 } 501 }
320 502
321 /* The CN can contain a * -- this will match those too. */ 503 /* The CN can contain a * -- this will match those too. */
322 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 504 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
323 /* found a match */ 505 /* found a match */
324#if MOD_GNUTLS_DEBUG 506#if MOD_GNUTLS_DEBUG
325 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 507 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
326 x->ctxt->c->base_server, 508 x->ctxt->c->base_server,
327 "GnuTLS: Virtual Host CB: " 509 "GnuTLS: Virtual Host CB: "
328 "'%s' == '%s'", tsc->cert_cn, x->sni_name); 510 "'%s' == '%s'", tsc->cert_cn, x->sni_name);
329#endif 511#endif
330 /* Because we actually change the server used here, we need to reset 512 /* Because we actually change the server used here, we need to reset
331 * things like ClientVerify. 513 * things like ClientVerify.
332 */ 514 */
333 x->sc = tsc; 515 x->sc = tsc;
334 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our 516 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
335 * certificate structure *should* change when the server changes. 517 * certificate structure *should* change when the server changes.
336 * acccckkkkkk. 518 * acccckkkkkk.
337 */ 519 */
338 return 1; 520 return 1;
521 } else {
522#if MOD_GNUTLS_DEBUG
523 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
524 x->ctxt->c->base_server,
525 "GnuTLS: Virtual Host CB: "
526 "'%s' != '%s'", tsc->cert_cn, x->sni_name);
527#endif
528
339 } 529 }
340 return 0; 530 return 0;
341} 531}
342#endif 532#endif
343 533
344mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session) 534mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
345{ 535{
346 int rv; 536 int rv;
347 int sni_type; 537 unsigned int sni_type;
348 int data_len = MAX_HOST_LEN; 538 size_t data_len = MAX_HOST_LEN;
349 char sni_name[MAX_HOST_LEN]; 539 char sni_name[MAX_HOST_LEN];
350 mgs_handle_t *ctxt; 540 mgs_handle_t *ctxt;
351#if USING_2_1_RECENT 541#if USING_2_1_RECENT
352 vhost_cb_rec cbx; 542 vhost_cb_rec cbx;
353#else 543#else
354 server_rec* s; 544 server_rec *s;
355 mgs_srvconf_rec *tsc; 545 mgs_srvconf_rec *tsc;
356#endif 546#endif
357 547
358 ctxt = gnutls_transport_get_ptr(session); 548 ctxt = gnutls_transport_get_ptr(session);
359 549
360 sni_type = gnutls_certificate_type_get(session); 550 rv = gnutls_server_name_get(ctxt->session, sni_name,
361 if (sni_type != GNUTLS_CRT_X509) { 551 &data_len, &sni_type, 0);
362 /* In theory, we could support OpenPGP Certificates. Theory != code. */ 552
363 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
364 ctxt->c->base_server,
365 "GnuTLS: Only x509 Certificates are currently supported.");
366 return NULL;
367 }
368
369 rv = gnutls_server_name_get(ctxt->session, sni_name,
370 &data_len, &sni_type, 0);
371
372 if (rv != 0) { 553 if (rv != 0) {
373 return NULL; 554 return NULL;
374 } 555 }
375 556
376 if (sni_type != GNUTLS_NAME_DNS) { 557 if (sni_type != GNUTLS_NAME_DNS) {
377 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 558 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
378 ctxt->c->base_server, 559 ctxt->c->base_server,
379 "GnuTLS: Unknown type '%d' for SNI: " 560 "GnuTLS: Unknown type '%d' for SNI: "
380 "'%s'", sni_type, sni_name); 561 "'%s'", sni_type, sni_name);
381 return NULL; 562 return NULL;
382 } 563 }
383 564
384 /** 565 /**
385 * Code in the Core already sets up the c->base_server as the base 566 * 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. 567 * for this IP/Port combo. Trust that the core did the 'right' thing.
@@ -389,72 +570,57 @@ mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session)
389 cbx.ctxt = ctxt; 570 cbx.ctxt = ctxt;
390 cbx.sc = NULL; 571 cbx.sc = NULL;
391 cbx.sni_name = sni_name; 572 cbx.sni_name = sni_name;
392 573
393 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); 574 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
394 if (rv == 1) { 575 if (rv == 1) {
395 return cbx.sc; 576 return cbx.sc;
396 } 577 }
397#else 578#else
398 for (s = ap_server_conf; s; s = s->next) { 579 for (s = ap_server_conf; s; s = s->next) {
399 580
400 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 581 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
401 &gnutls_module); 582 &gnutls_module);
402 if (tsc->enabled != GNUTLS_ENABLED_TRUE) { 583 if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
403 continue; 584 continue;
404 } 585 }
405#if MOD_GNUTLS_DEBUG 586#if MOD_GNUTLS_DEBUG
406 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 587 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
407 ctxt->c->base_server, 588 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, 589 "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)), 590 tsc->cert_cn, rv,
410 (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc); 591 gnutls_pk_algorithm_get_name
411#endif 592 (gnutls_x509_privkey_get_pk_algorithm
412 /* The CN can contain a * -- this will match those too. */ 593 (ctxt->sc->privkey_x509)), (unsigned int) s,
413 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) { 594 (unsigned int) s->next, (unsigned int) tsc);
595#endif
596 /* The CN can contain a * -- this will match those too. */
597 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
414#if MOD_GNUTLS_DEBUG 598#if MOD_GNUTLS_DEBUG
415 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 599 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
416 ctxt->c->base_server, 600 ctxt->c->base_server,
417 "GnuTLS: Virtual Host: " 601 "GnuTLS: Virtual Host: "
418 "'%s' == '%s'", tsc->cert_cn, sni_name); 602 "'%s' == '%s'", tsc->cert_cn, sni_name);
419#endif 603#endif
420 return tsc; 604 return tsc;
421 } 605 }
422 } 606 }
423#endif 607#endif
424 return NULL; 608 return NULL;
425} 609}
426 610
427 611
428static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) 612static const int protocol_priority[] = {
429{ 613 GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
430 mgs_handle_t *ctxt; 614};
431 mgs_srvconf_rec *tsc;
432
433 ctxt = gnutls_transport_get_ptr(session);
434 615
435 ret->type = GNUTLS_CRT_X509;
436 ret->ncerts = 1;
437 ret->deinit_all = 0;
438 616
439 tsc = mgs_find_sni_server(session); 617static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
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{ 618{
453 mgs_handle_t *ctxt; 619 mgs_handle_t *ctxt;
454 mgs_srvconf_rec *sc = 620 mgs_srvconf_rec *sc =
455 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 621 (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
456 module_config, 622 module_config,
457 &gnutls_module); 623 &gnutls_module);
458 624
459 ctxt = apr_pcalloc(pool, sizeof(*ctxt)); 625 ctxt = apr_pcalloc(pool, sizeof(*ctxt));
460 ctxt->c = c; 626 ctxt->c = c;
@@ -472,19 +638,17 @@ static mgs_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
472 638
473 gnutls_init(&ctxt->session, GNUTLS_SERVER); 639 gnutls_init(&ctxt->session, GNUTLS_SERVER);
474 640
475 gnutls_protocol_set_priority(ctxt->session, sc->protocol); 641 /* because we don't set any default priorities here (we set later at
476 gnutls_cipher_set_priority(ctxt->session, sc->ciphers); 642 * the user hello callback) we need to at least set this in order for
477 gnutls_compression_set_priority(ctxt->session, sc->compression); 643 * gnutls to be able to read packets.
478 gnutls_kx_set_priority(ctxt->session, sc->key_exchange); 644 */
479 gnutls_mac_set_priority(ctxt->session, sc->macs); 645 gnutls_protocol_set_priority(ctxt->session, protocol_priority);
480 gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types); 646
647 gnutls_handshake_set_post_client_hello_function(ctxt->session,
648 mgs_select_virtual_server_cb);
481 649
482 mgs_cache_session_init(ctxt); 650 mgs_cache_session_init(ctxt);
483
484 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
485 651
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; 652 return ctxt;
489} 653}
490 654
@@ -492,218 +656,484 @@ int mgs_hook_pre_connection(conn_rec * c, void *csd)
492{ 656{
493 mgs_handle_t *ctxt; 657 mgs_handle_t *ctxt;
494 mgs_srvconf_rec *sc = 658 mgs_srvconf_rec *sc =
495 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 659 (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
496 module_config, 660 module_config,
497 &gnutls_module); 661 &gnutls_module);
498 662
499 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 663 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
500 return DECLINED; 664 return DECLINED;
501 } 665 }
502 666
503 ctxt = create_gnutls_handle(c->pool, c); 667 ctxt = create_gnutls_handle(c->pool, c);
504 668
505 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 669 ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
506 670
507 gnutls_transport_set_pull_function(ctxt->session, 671 gnutls_transport_set_pull_function(ctxt->session, mgs_transport_read);
508 mgs_transport_read); 672 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); 673 gnutls_transport_set_ptr(ctxt->session, ctxt);
512 674
513 ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, 675 ctxt->input_filter =
514 NULL, c); 676 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
515 ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, 677 ctxt->output_filter =
516 NULL, c); 678 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
517 679
518 return OK; 680 return OK;
519} 681}
520 682
521int mgs_hook_fixups(request_rec *r) 683int mgs_hook_fixups(request_rec * r)
522{ 684{
523 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 685 unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
524 char buf[AP_IOBUFSIZE]; 686 char buf[AP_IOBUFSIZE];
525 const char* tmp; 687 const char *tmp;
526 int len; 688 size_t len;
527 mgs_handle_t *ctxt; 689 mgs_handle_t *ctxt;
528 int rv = OK; 690 int rv = OK;
529 691
530 apr_table_t *env = r->subprocess_env; 692 apr_table_t *env = r->subprocess_env;
531 693
532 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module); 694 ctxt =
695 ap_get_module_config(r->connection->conn_config, &gnutls_module);
533 696
534 if(!ctxt) { 697 if (!ctxt) {
535 return DECLINED; 698 return DECLINED;
536 } 699 }
537 700
538 apr_table_setn(env, "HTTPS", "on"); 701 apr_table_setn(env, "HTTPS", "on");
539 702
540 apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION); 703 apr_table_setn(env, "SSL_VERSION_LIBRARY",
541 apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION); 704 "GnuTLS/" LIBGNUTLS_VERSION);
705 apr_table_setn(env, "SSL_VERSION_INTERFACE",
706 "mod_gnutls/" MOD_GNUTLS_VERSION);
542 707
543 apr_table_setn(env, "SSL_PROTOCOL", 708 apr_table_setn(env, "SSL_PROTOCOL",
544 gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session))); 709 gnutls_protocol_get_name(gnutls_protocol_get_version
710 (ctxt->session)));
545 711
712 /* should have been called SSL_CIPHERSUITE instead */
546 apr_table_setn(env, "SSL_CIPHER", 713 apr_table_setn(env, "SSL_CIPHER",
547 gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session))); 714 gnutls_cipher_suite_get_name(gnutls_kx_get
715 (ctxt->session),
716 gnutls_cipher_get(ctxt->
717 session),
718 gnutls_mac_get(ctxt->
719 session)));
720
721 apr_table_setn(env, "SSL_COMPRESS_METHOD",
722 gnutls_compression_get_name(gnutls_compression_get
723 (ctxt->session)));
548 724
549 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 725 apr_table_setn(env, "SSL_SRP_USER",
726 gnutls_srp_server_get_username(ctxt->session));
550 727
551 tmp = apr_psprintf(r->pool, "%d", 728 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
552 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session))); 729 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
730
731 unsigned int key_size =
732 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
733 tmp = apr_psprintf(r->pool, "%u", key_size);
553 734
554 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 735 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
555 736
556 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 737 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
557 738
739 apr_table_setn(env, "SSL_CIPHER_EXPORT",
740 (key_size <= 40) ? "true" : "false");
741
558 len = sizeof(sbuf); 742 len = sizeof(sbuf);
559 gnutls_session_get_id(ctxt->session, sbuf, &len); 743 gnutls_session_get_id(ctxt->session, sbuf, &len);
560 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 744 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
561 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 745 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
562 746
563 /* TODO: There are many other env vars that we need to add */ 747 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
564 { 748 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
565 len = sizeof(buf); 749 ctxt->sc->export_certificates_enabled);
566 gnutls_x509_crt_get_dn(ctxt->sc->cert_x509, buf, &len); 750 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
567 apr_table_setn(env, "SSL_SERVER_S_DN", apr_pstrmemdup(r->pool, buf, len)); 751 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
568 752 ctxt->sc->export_certificates_enabled);
569 len = sizeof(buf); 753
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; 754 return rv;
574} 755}
575 756
576int mgs_hook_authz(request_rec *r) 757int mgs_hook_authz(request_rec * r)
577{ 758{
578 int rv; 759 int rv;
579 int status;
580 mgs_handle_t *ctxt; 760 mgs_handle_t *ctxt;
581 mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config, 761 mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
582 &gnutls_module); 762 &gnutls_module);
583 763
584 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module); 764 ctxt =
585 765 ap_get_module_config(r->connection->conn_config, &gnutls_module);
766
586 if (!ctxt) { 767 if (!ctxt) {
587 return DECLINED; 768 return DECLINED;
588 } 769 }
589 770
590 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 771 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
591 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 772 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
592 "GnuTLS: Directory set to Ignore Client Certificate!"); 773 "GnuTLS: Directory set to Ignore Client Certificate!");
593 } 774 } else {
594 else { 775 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
595 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 776 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
596 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 777 "GnuTLS: Attempting to rehandshake with peer. %d %d",
597 "GnuTLS: Attempting to rehandshake with peer. %d %d", 778 ctxt->sc->client_verify_mode,
598 ctxt->sc->client_verify_mode, dc->client_verify_mode); 779 dc->client_verify_mode);
599 780
600 gnutls_certificate_server_set_request(ctxt->session, 781 gnutls_certificate_server_set_request(ctxt->session,
601 dc->client_verify_mode); 782 dc->client_verify_mode);
602 783
603 if (mgs_rehandshake(ctxt) != 0) { 784 if (mgs_rehandshake(ctxt) != 0) {
604 return HTTP_FORBIDDEN; 785 return HTTP_FORBIDDEN;
605 } 786 }
606 } 787 } 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 788#if MOD_GNUTLS_DEBUG
609 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 789 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
610 "GnuTLS: Peer is set to IGNORE"); 790 "GnuTLS: Peer is set to IGNORE");
611#endif 791#endif
612 } 792 } else {
613 else { 793 rv = mgs_cert_verify(r, ctxt);
614 rv = mgs_cert_verify(r, ctxt); 794 if (rv != DECLINED) {
615 if (rv != DECLINED) { 795 return rv;
616 return rv; 796 }
617 } 797 }
618 } 798 }
799
800 return DECLINED;
801}
802
803/* variables that are not sent by default:
804 *
805 * SSL_CLIENT_CERT string PEM-encoded client certificate
806 * SSL_SERVER_CERT string PEM-encoded client certificate
807 */
808
809/* side is either 0 for SERVER or 1 for CLIENT
810 */
811#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
812static void
813mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
814 int export_certificates_enabled)
815{
816 unsigned char sbuf[64]; /* buffer to hold serials */
817 char buf[AP_IOBUFSIZE];
818 const char *tmp;
819 char *tmp2;
820 size_t len;
821 int ret, i;
822
823 apr_table_t *env = r->subprocess_env;
824
825 if (export_certificates_enabled != 0) {
826 char cert_buf[10 * 1024];
827 len = sizeof(cert_buf);
828
829 if (gnutls_x509_crt_export
830 (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
831 apr_table_setn(env,
832 apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
833 apr_pstrmemdup(r->pool, cert_buf, len));
834
835 }
836
837 len = sizeof(buf);
838 gnutls_x509_crt_get_dn(cert, buf, &len);
839 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
840 apr_pstrmemdup(r->pool, buf, len));
841
842 len = sizeof(buf);
843 gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
844 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
845 apr_pstrmemdup(r->pool, buf, len));
846
847 len = sizeof(sbuf);
848 gnutls_x509_crt_get_serial(cert, sbuf, &len);
849 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
850 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
851 apr_pstrdup(r->pool, tmp));
852
853 ret = gnutls_x509_crt_get_version(cert);
854 if (ret > 0)
855 apr_table_setn(env,
856 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
857 apr_psprintf(r->pool, "%u", ret));
858
859 apr_table_setn(env,
860 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "X.509");
861
862 tmp =
863 mgs_time2sz(gnutls_x509_crt_get_expiration_time
864 (cert), buf, sizeof(buf));
865 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
866 apr_pstrdup(r->pool, tmp));
867
868 tmp =
869 mgs_time2sz(gnutls_x509_crt_get_activation_time
870 (cert), buf, sizeof(buf));
871 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
872 apr_pstrdup(r->pool, tmp));
873
874 ret = gnutls_x509_crt_get_signature_algorithm(cert);
875 if (ret >= 0) {
876 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", NULL),
877 gnutls_sign_algorithm_get_name(ret));
878 }
879
880 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
881 if (ret >= 0) {
882 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
883 gnutls_pk_algorithm_get_name(ret));
884 }
619 885
886 /* export all the alternative names (DNS, RFC822 and URI) */
887 for (i = 0; !(ret < 0); i++) {
888 len = 0;
889 ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
890 NULL, &len, NULL);
891
892 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
893 tmp2 = apr_palloc(r->pool, len + 1);
894
895 ret =
896 gnutls_x509_crt_get_subject_alt_name(cert, i, tmp2, &len,
897 NULL);
898 tmp2[len] = 0;
899
900 if (ret == GNUTLS_SAN_DNSNAME) {
901 apr_table_setn(env,
902 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
903 apr_psprintf(r->pool, "DNSNAME:%s", tmp2));
904 } else if (ret == GNUTLS_SAN_RFC822NAME) {
905 apr_table_setn(env,
906 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
907 apr_psprintf(r->pool, "RFC822NAME:%s", tmp2));
908 } else if (ret == GNUTLS_SAN_URI) {
909 apr_table_setn(env,
910 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
911 apr_psprintf(r->pool, "URI:%s", tmp2));
912 } else {
913 apr_table_setn(env,
914 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
915 "UNSUPPORTED");
916 }
917 }
918 }
919}
620 920
621static int mgs_cert_verify(request_rec *r, mgs_handle_t *ctxt) 921static void
922mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side,
923 int export_certificates_enabled)
622{ 924{
623 const gnutls_datum_t* cert_list; 925 unsigned char sbuf[64]; /* buffer to hold serials */
624 int cert_list_size; 926 char buf[AP_IOBUFSIZE];
625 gnutls_x509_crt_t cert; 927 const char *tmp;
928 size_t len;
929 int ret;
930
931 apr_table_t *env = r->subprocess_env;
626 932
933 if (export_certificates_enabled != 0) {
934 char cert_buf[10 * 1024];
935 len = sizeof(cert_buf);
936
937 if (gnutls_openpgp_crt_export
938 (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
939 apr_table_setn(env,
940 apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
941 apr_pstrmemdup(r->pool, cert_buf, len));
942
943 }
627 944
628 cert_list = gnutls_certificate_get_peers(ctxt->session, &cert_list_size); 945 len = sizeof(buf);
946 gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
947 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
948 apr_pstrmemdup(r->pool, buf, len));
949
950 len = sizeof(sbuf);
951 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
952 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
953 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL),
954 apr_pstrdup(r->pool, tmp));
955
956 ret = gnutls_openpgp_crt_get_version(cert);
957 if (ret > 0)
958 apr_table_setn(env,
959 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
960 apr_psprintf(r->pool, "%u", ret));
961
962 apr_table_setn(env,
963 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP");
964
965 tmp =
966 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
967 (cert), buf, sizeof(buf));
968 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
969 apr_pstrdup(r->pool, tmp));
970
971 tmp =
972 mgs_time2sz(gnutls_openpgp_crt_get_creation_time
973 (cert), buf, sizeof(buf));
974 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
975 apr_pstrdup(r->pool, tmp));
976
977 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
978 if (ret >= 0) {
979 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
980 gnutls_pk_algorithm_get_name(ret));
981 }
982
983}
984
985/* TODO: Allow client sending a X.509 certificate chain */
986static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
987{
988 const gnutls_datum_t *cert_list;
989 unsigned int cert_list_size, status, expired;
990 int rv, ret;
991 union {
992 gnutls_x509_crt_t x509;
993 gnutls_openpgp_crt_t pgp;
994 } cert;
995 apr_time_t activation_time, expiration_time, cur_time;
996
997 cert_list =
998 gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
629 999
630 if (cert_list == NULL || cert_list_size == 0) { 1000 if (cert_list == NULL || cert_list_size == 0) {
631 /* no certificate provided by the client, but one was required. */ 1001 /* 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, 1002 */
633 "GnuTLS: Failed to Verify Peer: " 1003 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
634 "Client did not submit a certificate"); 1004 return OK;
635 return HTTP_FORBIDDEN; 1005
1006 /* no certificate provided by the client, but one was required. */
1007 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1008 "GnuTLS: Failed to Verify Peer: "
1009 "Client did not submit a certificate");
1010 return HTTP_FORBIDDEN;
636 } 1011 }
637 1012
638 if (cert_list_size > 1) { 1013 if (cert_list_size > 1) {
639 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1014 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
640 "GnuTLS: Failed to Verify Peer: " 1015 "GnuTLS: Failed to Verify Peer: "
641 "Chained Client Certificates are not supported."); 1016 "Chained Client Certificates are not supported.");
642 return HTTP_FORBIDDEN; 1017 return HTTP_FORBIDDEN;
643 } 1018 }
644 1019
645 gnutls_x509_crt_init(&cert); 1020 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
646 gnutls_x509_crt_import(cert, &cert_chain[0], GNUTLS_X509_FMT_DER); 1021 gnutls_x509_crt_init(&cert.x509);
1022 rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER);
1023 } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) {
1024 gnutls_openpgp_crt_init(&cert.pgp);
1025 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW);
1026 } else return HTTP_FORBIDDEN;
1027
1028 if (rv < 0) {
1029 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1030 "GnuTLS: Failed to Verify Peer: "
1031 "Failed to import peer certificates.");
1032 ret = HTTP_FORBIDDEN;
1033 goto exit;
1034 }
647 1035
648 rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list, ctxt->sc->ca_list_size, 0, &status); 1036 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
1037 apr_time_ansi_put(&expiration_time,
1038 gnutls_x509_crt_get_expiration_time(cert.x509));
1039 apr_time_ansi_put(&activation_time,
1040 gnutls_x509_crt_get_activation_time(cert.x509));
1041
1042 rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list,
1043 ctxt->sc->ca_list_size, 0, &status);
1044 } else {
1045 apr_time_ansi_put(&expiration_time,
1046 gnutls_openpgp_crt_get_expiration_time(cert.pgp));
1047 apr_time_ansi_put(&activation_time,
1048 gnutls_openpgp_crt_get_creation_time(cert.pgp));
1049
1050 rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list,
1051 0, &status);
1052 }
649 1053
650 if (rv < 0) { 1054 if (rv < 0) {
651 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1055 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
652 "GnuTLS: Failed to Verify Peer: (%d) %s", 1056 "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
653 rv, gnutls_strerror(rv)); 1057 rv, gnutls_strerror(rv));
654 return HTTP_FORBIDDEN; 1058 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
1059 ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
1060 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
1061 ret = HTTP_FORBIDDEN;
1062 goto exit;
655 } 1063 }
656 1064
657 if (status < 0) { 1065 /* TODO: X509 CRL Verification. */
658 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1066 /* May add later if anyone needs it.
659 "GnuTLS: Peer Status is invalid."); 1067 */
660 return HTTP_FORBIDDEN; 1068 /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
661 } 1069
662 1070 expired = 0;
663 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 1071 cur_time = apr_time_now();
664 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1072 if (activation_time > cur_time) {
665 "GnuTLS: Could not find Signer for Peer Certificate"); 1073 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
666 } 1074 "GnuTLS: Failed to Verify Peer: "
667 1075 "Peer Certificate is not yet activated.");
668 if (status & GNUTLS_CERT_SIGNER_NOT_CA) { 1076 expired = 1;
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 }
697
698 ap_add_common_vars(r);
699 mgs_hook_fixups(r);
700 status = mgs_authz_lua(r);
701
702 if (status != 0) {
703 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
704 "GnuTLS: FAILED Authorization Test");
705 return HTTP_FORBIDDEN;
706 } 1077 }
707 1078
708} 1079 if (expiration_time < cur_time) {
1080 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1081 "GnuTLS: Failed to Verify Peer: "
1082 "Peer Certificate is expired.");
1083 expired = 1;
1084 }
1085
1086 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1087 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1088 "GnuTLS: Could not find Signer for Peer Certificate");
1089 }
1090
1091 if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
1092 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1093 "GnuTLS: Peer's Certificate signer is not a CA");
1094 }
709 1095
1096 if (status & GNUTLS_CERT_INVALID) {
1097 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1098 "GnuTLS: Peer Certificate is invalid.");
1099 } else if (status & GNUTLS_CERT_REVOKED) {
1100 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1101 "GnuTLS: Peer Certificate is revoked.");
1102 }
1103
1104 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
1105 mgs_add_common_cert_vars(r, cert.x509, 1,
1106 ctxt->sc->export_certificates_enabled);
1107 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
1108 mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
1109 ctxt->sc->export_certificates_enabled);
1110
1111 {
1112 /* days remaining */
1113 unsigned long remain =
1114 (apr_time_sec(expiration_time) -
1115 apr_time_sec(cur_time)) / 86400;
1116 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
1117 apr_psprintf(r->pool, "%lu", remain));
1118 }
1119
1120 if (status == 0 && expired == 0) {
1121 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "SUCCESS");
1122 ret = OK;
1123 } else {
1124 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", "FAILED");
1125 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1126 ret = OK;
1127 else
1128 ret = HTTP_FORBIDDEN;
1129 }
1130
1131 exit:
1132 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
1133 gnutls_x509_crt_deinit(cert.x509);
1134 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
1135 gnutls_openpgp_crt_deinit(cert.pgp);
1136 return ret;
1137
1138
1139}
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..014bfc8 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -63,15 +63,55 @@ 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("GnuTLSX509CAFile", mgs_set_client_ca_file,
68 NULL,
69 RSRC_CONF,
70 "Set the CA File to verify Client Certificates"),
71 AP_INIT_TAKE1("GnuTLSPGPKeyringFile", mgs_set_keyring_file,
72 NULL,
73 RSRC_CONF,
74 "Set the Keyring File to verify Client Certificates"),
75 AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file,
76 NULL,
77 RSRC_CONF,
78 "Set the file to read Diffie Hellman parameters from"),
79 AP_INIT_TAKE1("GnuTLSRSAFile", mgs_set_rsa_export_file,
80 NULL,
81 RSRC_CONF,
82 "Set the file to read RSA-EXPORT parameters from"),
67 AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file, 83 AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file,
68 NULL, 84 NULL,
69 RSRC_CONF, 85 RSRC_CONF,
70 "SSL Server Key file"), 86 "SSL Server X509 Certificate file"),
71 AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file, 87 AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file,
72 NULL, 88 NULL,
73 RSRC_CONF, 89 RSRC_CONF,
74 "SSL Server Certificate file"), 90 "SSL Server X509 Private Key file"),
91 AP_INIT_TAKE1("GnuTLSX509CertificateFile", mgs_set_cert_file,
92 NULL,
93 RSRC_CONF,
94 "SSL Server X509 Certificate file"),
95 AP_INIT_TAKE1("GnuTLSX509KeyFile", mgs_set_key_file,
96 NULL,
97 RSRC_CONF,
98 "SSL Server X509 Private Key file"),
99 AP_INIT_TAKE1("GnuTLSPGPCertificateFile", mgs_set_pgpcert_file,
100 NULL,
101 RSRC_CONF,
102 "SSL Server PGP Certificate file"),
103 AP_INIT_TAKE1("GnuTLSPGPKeyFile", mgs_set_pgpkey_file,
104 NULL,
105 RSRC_CONF,
106 "SSL Server PGP Private key file"),
107 AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file,
108 NULL,
109 RSRC_CONF,
110 "SSL Server SRP Password Conf file"),
111 AP_INIT_TAKE1("GnuTLSSRPPasswdConfFile", mgs_set_srp_tpasswd_conf_file,
112 NULL,
113 RSRC_CONF,
114 "SSL Server SRP Parameters file"),
75 AP_INIT_TAKE1("GnuTLSCacheTimeout", mgs_set_cache_timeout, 115 AP_INIT_TAKE1("GnuTLSCacheTimeout", mgs_set_cache_timeout,
76 NULL, 116 NULL,
77 RSRC_CONF, 117 RSRC_CONF,
@@ -80,10 +120,19 @@ static const command_rec mgs_config_cmds[] = {
80 NULL, 120 NULL,
81 RSRC_CONF, 121 RSRC_CONF,
82 "Cache Configuration"), 122 "Cache Configuration"),
123 AP_INIT_RAW_ARGS("GnuTLSPriorities", mgs_set_priorities,
124 NULL,
125 RSRC_CONF,
126 "The priorities to enable (ciphers, Key exchange, macs, compression)."),
83 AP_INIT_TAKE1("GnuTLSEnable", mgs_set_enabled, 127 AP_INIT_TAKE1("GnuTLSEnable", mgs_set_enabled,
84 NULL, 128 NULL,
85 RSRC_CONF, 129 RSRC_CONF,
86 "Whether this server has GnuTLS Enabled. Default: Off"), 130 "Whether this server has GnuTLS Enabled. Default: Off"),
131 AP_INIT_TAKE1("GnuTLSExportCertificates", mgs_set_export_certificates_enabled,
132 NULL,
133 RSRC_CONF,
134 "Whether to export PEM encoded certificates to CGIs. Default: Off"),
135#if 0
87 AP_INIT_RAW_ARGS("<GnuTLSRequire", mgs_set_require_section, 136 AP_INIT_RAW_ARGS("<GnuTLSRequire", mgs_set_require_section,
88 NULL, 137 NULL,
89 EXEC_ON_READ|OR_ALL, 138 EXEC_ON_READ|OR_ALL,
@@ -92,6 +141,7 @@ static const command_rec mgs_config_cmds[] = {
92 NULL, 141 NULL,
93 OR_ALL, 142 OR_ALL,
94 "Internal Command for reading Lua Bytecode."), 143 "Internal Command for reading Lua Bytecode."),
144#endif
95 {NULL} 145 {NULL}
96}; 146};
97 147