summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--NEWS13
-rw-r--r--NOTICE3
-rw-r--r--README44
-rw-r--r--README.ENV8
-rw-r--r--configure.ac18
-rw-r--r--include/mod_gnutls.h.in22
-rw-r--r--src/gnutls_cache.c84
-rw-r--r--src/gnutls_config.c131
-rw-r--r--src/gnutls_hooks.c273
-rw-r--r--src/mod_gnutls.c28
11 files changed, 493 insertions, 135 deletions
diff --git a/Makefile.am b/Makefile.am
index d61ebd3..a19e755 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,11 +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 README.ENV NEWS \ 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 11ACLOCAL_AMFLAGS = -I m4
diff --git a/NEWS b/NEWS
index e4b908d..a9fe9fd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,16 @@
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
1** Version 0.4.1 (2007-12-03) 14** Version 0.4.1 (2007-12-03)
2 15
3- Added support for subject alternative names in certificates. 16- Added support for subject alternative names in certificates.
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 85418de..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
@@ -54,31 +54,26 @@ GnuTLSCache dbm conf/gnutls_cache
54 GnuTLSEnable On 54 GnuTLSEnable On
55 55
56 # This is the Private key for your server. 56 # This is the Private key for your server.
57 GnuTLSKeyFile conf/server.key 57 GnuTLSX509KeyFile conf/server.key
58 58
59 # This is the Server Certificate. 59 # This is the Server Certificate.
60 GnuTLSCertificateFile conf/server.cert 60 GnuTLSX509CertificateFile conf/server.cert
61</VirtualHost> 61</VirtualHost>
62 62
63
64# a more advanced configuration 63# a more advanced configuration
65GnuTLSCache dbm "/var/cache/www-tls-cache/cache" 64GnuTLSCache dbm "/var/cache/www-tls-cache/cache"
66GnuTLSCacheTimeout 500 65GnuTLSCacheTimeout 600
67GnuTLSProtocols TLS1.1 TLS1.0 SSL3.0
68NameVirtualHost 1.2.3.4:443 66NameVirtualHost 1.2.3.4:443
69 67
70<VirtualHost 1.2.3.4:443> 68<VirtualHost 1.2.3.4:443>
71 Servername server.com:443 69 Servername server.com:443
72 GnuTLSEnable on 70 GnuTLSEnable on
73 GnuTLSCiphers AES-128-CBC 3DES-CBC ARCFOUR-128 71 GnuTLSPriority NORMAL
74 GnuTLSKeyExchangeAlgorithms RSA DHE-RSA DHE-DSS SRP SRP-RSA SRP-DSS
75 GnuTLSMACAlgorithms SHA1 MD5
76 GnuTLSCompressionMethods NULL
77# To export exactly the same environment variables as mod_ssl to CGI scripts. 72# To export exactly the same environment variables as mod_ssl to CGI scripts.
78 GNUTLSExportCertificates on 73 GNUTLSExportCertificates on
79 74
80 GnuTLSCertificateFile /etc/apache2/server-cert.pem 75 GnuTLSX509CertificateFile /etc/apache2/server-cert.pem
81 GnuTLSKeyFile /etc/apache2/server-key.pem 76 GnuTLSX509KeyFile /etc/apache2/server-key.pem
82 77
83# To enable SRP you must have these files installed. Check the gnutls srptool. 78# To enable SRP you must have these files installed. Check the gnutls srptool.
84 GnuTLSSRPPasswdFile /etc/apache2/tpasswd 79 GnuTLSSRPPasswdFile /etc/apache2/tpasswd
@@ -88,6 +83,29 @@ NameVirtualHost 1.2.3.4:443
88# GnuTLSClientVerify could be ignore or require. The GnuTLSClientCAFile 83# GnuTLSClientVerify could be ignore or require. The GnuTLSClientCAFile
89# contains the CAs to verify client certificates. 84# contains the CAs to verify client certificates.
90 GnuTLSClientVerify request 85 GnuTLSClientVerify request
91 GnuTLSClientCAFile ca.pem 86 GnuTLSX509CAFile ca.pem
92 ... 87 ...
93</VirtualHost> 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
111</VirtualHost>
diff --git a/README.ENV b/README.ENV
index c055dfe..34dbcf6 100644
--- a/README.ENV
+++ b/README.ENV
@@ -19,7 +19,7 @@ SSL_CLIENT_V_START: The activation time of client's certificate.
19SSL_CLIENT_V_END: The expiration 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. 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. 21SSL_CLIENT_I_DN: The distinguished name of client's issuer certificate in RFC2253 format.
22SSL_CLIENT_S_SAN%: These will contain the alternative names of the client certificate 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:", 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 24 "RFC822NAME:" or "URI:" depending on the type. If it is not supported the value
25 "UNSUPPORTED" will be set. 25 "UNSUPPORTED" will be set.
@@ -30,13 +30,13 @@ SSL_CLIENT_A_KEY: The public key algorithm in client's certificate.
30SSL_CLIENT_CERT: The PEM-encoded client certificate 30SSL_CLIENT_CERT: The PEM-encoded client certificate
31SSL_CLIENT_VERIFY: 31SSL_CLIENT_VERIFY:
32 whether the client's certificate was verified. (NONE if none was sent, or SUCCESS or FAILED) 32 whether the client's certificate was verified. (NONE if none was sent, or SUCCESS or FAILED)
33SSL_CLIENT_S_TYPE: The certificate type can be X.509 or OPENPGP. 33SSL_CLIENT_CERT_TYPE: The certificate type can be X.509 or OPENPGP.
34 34
35SSL_SERVER_V_START: The activation time of server's certificate. 35SSL_SERVER_V_START: The activation time of server's certificate.
36SSL_SERVER_V_END: The expiration 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. 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. 38SSL_SERVER_I_DN: The distinguished name of the server's issuer certificate in RFC2253 format.
39SSL_SERVER_S_SAN%: These will contain the alternative names of the server certificate 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:", 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 41 "RFC822NAME:" or "URI:" depending on the type. If it is not supported the value
42 "UNSUPPORTED" will be set. 42 "UNSUPPORTED" will be set.
@@ -45,5 +45,5 @@ SSL_SERVER_M_VERSION: The version of the server's certificate.
45SSL_SERVER_A_SIG: The algorithm used for the signature in 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. 46SSL_SERVER_A_KEY: The public key algorithm in server's certificate.
47SSL_SERVER_CERT: The PEM-encoded server certificate 47SSL_SERVER_CERT: The PEM-encoded server certificate
48SSL_SERVER_S_TYPE: The certificate type can be X.509 or OPENPGP. 48SSL_SERVER_CERT_TYPE: The certificate type can be X.509 or OPENPGP.
49 49
diff --git a/configure.ac b/configure.ac
index c401940..0cdcdd9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
1dnl 1dnl
2AC_INIT(mod_gnutls, 0.4.1) 2AC_INIT(mod_gnutls, 0.5.0-alpha)
3OOO_CONFIG_NICE(config.nice) 3OOO_CONFIG_NICE(config.nice)
4MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION 4MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
5AC_PREREQ(2.53) 5AC_PREREQ(2.53)
@@ -28,8 +28,14 @@ CHECK_APACHE(,$AP_VERSION,
28dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`" 28dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`"
29dnl AC_SUBST(LIBTOOL) 29dnl AC_SUBST(LIBTOOL)
30 30
31MIN_TLS_VERSION=2.1.7 31MIN_TLS_VERSION=2.2.1
32CHECK_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]]))
33 39
34dnl CHECK_LUA() 40dnl CHECK_LUA()
35 41
@@ -37,13 +43,13 @@ have_apr_memcache=0
37CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0]) 43CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0])
38AC_SUBST(have_apr_memcache) 44AC_SUBST(have_apr_memcache)
39 45
40MODULE_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}"
41MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}" 47MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_EXTRA_LIBS}"
42 48
43AC_SUBST(MODULE_CFLAGS) 49AC_SUBST(MODULE_CFLAGS)
44AC_SUBST(MODULE_LIBS) 50AC_SUBST(MODULE_LIBS)
45 51
46AC_CONFIG_FILES([Makefile src/Makefile include/mod_gnutls.h data/Makefile]) 52AC_CONFIG_FILES([Makefile src/Makefile include/mod_gnutls.h])
47AC_OUTPUT 53AC_OUTPUT
48 54
49echo "---" 55echo "---"
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in
index 6a311a3..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
@@ -80,7 +82,10 @@ typedef struct
80/* The maximum number of client CA certificates allowed. 82/* The maximum number of client CA certificates allowed.
81 */ 83 */
82#define MAX_CA_CRTS 128 84#define MAX_CA_CRTS 128
83#define MAX_CIPHERS 16 85
86/* The maximum number of certificates to send in a chain
87 */
88#define MAX_CHAIN_SIZE 8
84 89
85typedef struct 90typedef struct
86{ 91{
@@ -88,8 +93,11 @@ typedef struct
88 gnutls_srp_server_credentials_t srp_creds; 93 gnutls_srp_server_credentials_t srp_creds;
89 gnutls_anon_server_credentials_t anon_creds; 94 gnutls_anon_server_credentials_t anon_creds;
90 char* cert_cn; 95 char* cert_cn;
91 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;
92 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;
93 int enabled; 101 int enabled;
94 /* whether to send the PEM encoded certificates 102 /* whether to send the PEM encoded certificates
95 * to CGIs 103 * to CGIs
@@ -104,6 +112,7 @@ typedef struct
104 const char* srp_tpasswd_file; 112 const char* srp_tpasswd_file;
105 const char* srp_tpasswd_conf_file; 113 const char* srp_tpasswd_conf_file;
106 gnutls_x509_crt_t ca_list[MAX_CA_CRTS]; 114 gnutls_x509_crt_t ca_list[MAX_CA_CRTS];
115 gnutls_openpgp_keyring_t pgp_list;
107 unsigned int ca_list_size; 116 unsigned int ca_list_size;
108 int client_verify_mode; 117 int client_verify_mode;
109} mgs_srvconf_rec; 118} mgs_srvconf_rec;
@@ -250,6 +259,12 @@ const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
250const char *mgs_set_key_file(cmd_parms * parms, void *dummy, 259const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
251 const char *arg); 260 const char *arg);
252 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
253const char *mgs_set_cache(cmd_parms * parms, void *dummy, 268const char *mgs_set_cache(cmd_parms * parms, void *dummy,
254 const char *type, const char* arg); 269 const char *type, const char* arg);
255 270
@@ -262,6 +277,9 @@ const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
262const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 277const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
263 const char *arg); 278 const char *arg);
264 279
280const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
281 const char *arg);
282
265const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 283const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
266 const char *arg); 284 const char *arg);
267const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy, 285const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
diff --git a/src/gnutls_cache.c b/src/gnutls_cache.c
index 86b843e..83e7bb5 100644
--- a/src/gnutls_cache.c
+++ b/src/gnutls_cache.c
@@ -34,18 +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
41#if 0 40char *mgs_session_id2sz(unsigned char *id, int idlen,
42static char *gnutls_session_id2sz(unsigned char *id, int idlen,
43 char *str, int strsize) 41 char *str, int strsize)
44{ 42{
45 char *cp; 43 char *cp;
46 int n; 44 int n;
47 45
48 cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN); 46 cp = str;
49 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 47 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
50 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]); 48 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
51 cp += 2; 49 cp += 2;
@@ -53,7 +51,27 @@ static char *gnutls_session_id2sz(unsigned char *id, int idlen,
53 *cp = '\0'; 51 *cp = '\0';
54 return str; 52 return str;
55} 53}
56#endif 54
55
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)
62{
63char buf[STR_SESSION_LEN];
64char *sz;
65
66 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
67 if (sz == NULL)
68 return -1;
69
70 dbmkey->dptr = apr_psprintf(c->pool, "%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
71 dbmkey->dsize = strlen( dbmkey->dptr);
72
73 return 0;
74}
57 75
58#define CTIME "%b %d %k:%M:%S %Y %Z" 76#define CTIME "%b %d %k:%M:%S %Y %Z"
59char *mgs_time2sz(time_t in_time, char *str, int strsize) 77char *mgs_time2sz(time_t in_time, char *str, int strsize)
@@ -70,24 +88,23 @@ char *mgs_time2sz(time_t in_time, char *str, int strsize)
70 return str; 88 return str;
71} 89}
72 90
73char *mgs_session_id2sz(unsigned char *id, int idlen, 91#if HAVE_APR_MEMCACHE
74 char *str, int strsize) 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)
75{ 97{
76 char *cp; 98char buf[STR_SESSION_LEN];
77 int n; 99char *sz;
78 100
79 cp = str; 101 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
80 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 102 if (sz == NULL)
81 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]); 103 return NULL;
82 cp += 2; 104
83 } 105 return apr_psprintf(c->pool, MC_TAG"%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
84 *cp = '\0';
85 return str;
86} 106}
87 107
88
89#if HAVE_APR_MEMCACHE
90
91/** 108/**
92 * GnuTLS Session Cache using libmemcached 109 * GnuTLS Session Cache using libmemcached
93 * 110 *
@@ -184,11 +201,10 @@ static int mc_cache_store(void* baton, gnutls_datum_t key,
184{ 201{
185 apr_status_t rv = APR_SUCCESS; 202 apr_status_t rv = APR_SUCCESS;
186 mgs_handle_t *ctxt = baton; 203 mgs_handle_t *ctxt = baton;
187 char buf[STR_SESSION_LEN];
188 char* strkey = NULL; 204 char* strkey = NULL;
189 apr_uint32_t timeout; 205 apr_uint32_t timeout;
190 206
191 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); 207 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
192 if(!strkey) 208 if(!strkey)
193 return -1; 209 return -1;
194 210
@@ -211,13 +227,12 @@ static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
211{ 227{
212 apr_status_t rv = APR_SUCCESS; 228 apr_status_t rv = APR_SUCCESS;
213 mgs_handle_t *ctxt = baton; 229 mgs_handle_t *ctxt = baton;
214 char buf[STR_SESSION_LEN];
215 char* strkey = NULL; 230 char* strkey = NULL;
216 char* value; 231 char* value;
217 apr_size_t value_len; 232 apr_size_t value_len;
218 gnutls_datum_t data = { NULL, 0 }; 233 gnutls_datum_t data = { NULL, 0 };
219 234
220 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); 235 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
221 if (!strkey) { 236 if (!strkey) {
222 return data; 237 return data;
223 } 238 }
@@ -252,10 +267,9 @@ static int mc_cache_delete(void* baton, gnutls_datum_t key)
252{ 267{
253 apr_status_t rv = APR_SUCCESS; 268 apr_status_t rv = APR_SUCCESS;
254 mgs_handle_t *ctxt = baton; 269 mgs_handle_t *ctxt = baton;
255 char buf[STR_SESSION_LEN];
256 char* strkey = NULL; 270 char* strkey = NULL;
257 271
258 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf)); 272 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
259 if(!strkey) 273 if(!strkey)
260 return -1; 274 return -1;
261 275
@@ -366,8 +380,8 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
366 mgs_handle_t *ctxt = baton; 380 mgs_handle_t *ctxt = baton;
367 apr_status_t rv; 381 apr_status_t rv;
368 382
369 dbmkey.dptr = (void*)key.data; 383 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
370 dbmkey.dsize = key.size; 384 return data;
371 385
372 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 386 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
373 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); 387 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
@@ -413,9 +427,9 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key,
413 mgs_handle_t *ctxt = baton; 427 mgs_handle_t *ctxt = baton;
414 apr_status_t rv; 428 apr_status_t rv;
415 apr_time_t expiry; 429 apr_time_t expiry;
416 430
417 dbmkey.dptr = (char *)key.data; 431 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
418 dbmkey.dsize = key.size; 432 return -1;
419 433
420 /* create DBM value */ 434 /* create DBM value */
421 dbmval.dsize = data.size + sizeof(apr_time_t); 435 dbmval.dsize = data.size + sizeof(apr_time_t);
@@ -467,9 +481,9 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key)
467 apr_datum_t dbmkey; 481 apr_datum_t dbmkey;
468 mgs_handle_t *ctxt = baton; 482 mgs_handle_t *ctxt = baton;
469 apr_status_t rv; 483 apr_status_t rv;
470 484
471 dbmkey.dptr = (char *)key.data; 485 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
472 dbmkey.dsize = key.size; 486 return -1;
473 487
474 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, 488 rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
475 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); 489 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
diff --git a/src/gnutls_config.c b/src/gnutls_config.c
index 7b5a42b..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.
@@ -151,15 +152,10 @@ const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
151 "Certificate '%s'", file); 152 "Certificate '%s'", file);
152 } 153 }
153 154
154 ret = gnutls_x509_crt_init(&sc->cert_x509); 155 sc->certs_x509_num = MAX_CHAIN_SIZE;
155 if (ret < 0) {
156 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
157 ": (%d) %s", ret, gnutls_strerror(ret));
158 }
159
160 ret = 156 ret =
161 gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM); 157 gnutls_x509_crt_list_import(sc->certs_x509, &sc->certs_x509_num, &data, GNUTLS_X509_FMT_PEM, 0);
162 if (ret != 0) { 158 if (ret < 0) {
163 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import " 159 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
164 "Certificate '%s': (%d) %s", file, ret, 160 "Certificate '%s': (%d) %s", file, ret,
165 gnutls_strerror(ret)); 161 gnutls_strerror(ret));
@@ -207,6 +203,84 @@ const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
207 return NULL; 203 return NULL;
208} 204}
209 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
210const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy, 284const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
211 const char *arg) 285 const char *arg)
212{ 286{
@@ -355,6 +429,44 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
355 return NULL; 429 return NULL;
356} 430}
357 431
432const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
433 const char *arg)
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);
454 if (rv < 0) {
455 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
456 "keyring: (%d) %s", rv, 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));
464 }
465
466 apr_pool_destroy(spool);
467 return NULL;
468}
469
358const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 470const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
359 const char *arg) 471 const char *arg)
360{ 472{
@@ -440,7 +552,8 @@ void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
440 sc->srp_tpasswd_conf_file = NULL; 552 sc->srp_tpasswd_conf_file = NULL;
441 sc->srp_tpasswd_file = NULL; 553 sc->srp_tpasswd_file = NULL;
442 sc->privkey_x509 = NULL; 554 sc->privkey_x509 = NULL;
443 sc->cert_x509 = NULL; 555 memset( sc->certs_x509, 0, sizeof(sc->certs_x509));
556 sc->certs_x509_num = 0;
444 sc->cache_timeout = apr_time_from_sec(300); 557 sc->cache_timeout = apr_time_from_sec(300);
445 sc->cache_type = mgs_cache_dbm; 558 sc->cache_type = mgs_cache_dbm;
446 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 559 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c
index 4364add..26917b8 100644
--- a/src/gnutls_hooks.c
+++ b/src/gnutls_hooks.c
@@ -36,7 +36,10 @@ static int mpm_is_threaded;
36 36
37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); 37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
38/* use side==0 for server and side==1 for client */ 38/* use side==0 for server and side==1 for client */
39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, 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,
40 int side, 43 int side,
41 int export_certificates_enabled); 44 int export_certificates_enabled);
42 45
@@ -68,9 +71,23 @@ int ret;
68 mpm_is_threaded = 0; 71 mpm_is_threaded = 0;
69#endif 72#endif
70 73
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
71 ret = gnutls_global_init(); 80 ret = gnutls_global_init();
72 if (ret < 0) /* FIXME: can we print here? */ 81 if (ret < 0) {
73 exit(ret); 82 fprintf(stderr, "gnutls_global_init: %s\n", gnutls_strerror(ret));
83 return -3;
84 }
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 }
74 91
75 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 92 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
76 apr_pool_cleanup_null); 93 apr_pool_cleanup_null);
@@ -82,19 +99,18 @@ int ret;
82 99
83 gnutls_global_set_log_level(9); 100 gnutls_global_set_log_level(9);
84 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));
85#endif 103#endif
86 104
87 return OK; 105 return OK;
88} 106}
89 107
90/* We don't support openpgp certificates, yet */
91const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
92
93static int mgs_select_virtual_server_cb(gnutls_session_t session) 108static int mgs_select_virtual_server_cb(gnutls_session_t session)
94{ 109{
95 mgs_handle_t *ctxt; 110 mgs_handle_t *ctxt;
96 mgs_srvconf_rec *tsc; 111 mgs_srvconf_rec *tsc;
97 int ret; 112 int ret;
113 int cprio[2];
98 114
99 ctxt = gnutls_transport_get_ptr(session); 115 ctxt = gnutls_transport_get_ptr(session);
100 116
@@ -126,17 +142,22 @@ static int mgs_select_virtual_server_cb(gnutls_session_t session)
126 * negotiation. 142 * negotiation.
127 */ 143 */
128 ret = gnutls_priority_set(session, ctxt->sc->priorities); 144 ret = gnutls_priority_set(session, ctxt->sc->priorities);
129 gnutls_certificate_type_set_priority(session, cert_type_prio);
130
131
132 /* actually it shouldn't fail since we have checked at startup */ 145 /* actually it shouldn't fail since we have checked at startup */
133 if (ret < 0) 146 if (ret < 0)
134 return ret; 147 return ret;
135 148
136 /* allow separate caches per virtual host. Actually allowing the same is a 149 /* If both certificate types are not present disallow them from
137 * bad idea, since they might have different security requirements. 150 * being negotiated.
138 */ 151 */
139 mgs_cache_session_init(ctxt); 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 }
140 161
141 return 0; 162 return 0;
142} 163}
@@ -147,15 +168,31 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
147 168
148 ctxt = gnutls_transport_get_ptr(session); 169 ctxt = gnutls_transport_get_ptr(session);
149 170
150 ret->type = GNUTLS_CRT_X509; 171 if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) {
151 ret->ncerts = 1; 172 ret->type = GNUTLS_CRT_X509;
152 ret->deinit_all = 0; 173 ret->ncerts = ctxt->sc->certs_x509_num;
174 ret->deinit_all = 0;
175
176 ret->cert.x509 = ctxt->sc->certs_x509;
177 ret->key.x509 = ctxt->sc->privkey_x509;
178
179 return 0;
180 } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) {
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
190 }
153 191
154 ret->cert.x509 = &ctxt->sc->cert_x509; 192 return GNUTLS_E_INTERNAL_ERROR;
155 ret->key.x509 = ctxt->sc->privkey_x509;
156 return 0;
157} 193}
158 194
195/* 2048-bit group parameters from SRP specification */
159const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" 196const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
160 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" 197 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
161 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" 198 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
@@ -171,7 +208,7 @@ const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
171 * Returns negative on error. 208 * Returns negative on error.
172 */ 209 */
173static int read_crt_cn(server_rec * s, apr_pool_t * p, 210static int read_crt_cn(server_rec * s, apr_pool_t * p,
174 gnutls_x509_crt cert, char **cert_cn) 211 gnutls_x509_crt_t cert, char **cert_cn)
175{ 212{
176 int rv = 0, i; 213 int rv = 0, i;
177 size_t data_len; 214 size_t data_len;
@@ -179,6 +216,7 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
179 216
180 *cert_cn = NULL; 217 *cert_cn = NULL;
181 218
219 data_len = 0;
182 rv = gnutls_x509_crt_get_dn_by_oid(cert, 220 rv = gnutls_x509_crt_get_dn_by_oid(cert,
183 GNUTLS_OID_X520_COMMON_NAME, 221 GNUTLS_OID_X520_COMMON_NAME,
184 0, 0, NULL, &data_len); 222 0, 0, NULL, &data_len);
@@ -189,8 +227,8 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
189 GNUTLS_OID_X520_COMMON_NAME, 0, 227 GNUTLS_OID_X520_COMMON_NAME, 0,
190 0, *cert_cn, &data_len); 228 0, *cert_cn, &data_len);
191 } else { /* No CN return subject alternative name */ 229 } else { /* No CN return subject alternative name */
192 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 230 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
193 "No common name found in certificate for '%s:%d'. Looking for subject alternative name.", 231 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
194 s->server_hostname, s->port); 232 s->server_hostname, s->port);
195 rv = 0; 233 rv = 0;
196 /* read subject alternative name */ 234 /* read subject alternative name */
@@ -218,9 +256,33 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
218 } 256 }
219 257
220 return rv; 258 return rv;
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
267
268 *cert_cn = NULL;
269
270 data_len = 0;
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);
280 }
221 281
282 return rv;
222} 283}
223 284
285
224int 286int
225mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 287mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
226 apr_pool_t * ptemp, server_rec * base_server) 288 apr_pool_t * ptemp, server_rec * base_server)
@@ -334,7 +396,7 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
334 } 396 }
335 } 397 }
336 398
337 if (sc->cert_x509 == NULL 399 if (sc->certs_x509[0] == NULL
338 && sc->enabled == GNUTLS_ENABLED_TRUE) { 400 && sc->enabled == GNUTLS_ENABLED_TRUE) {
339 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 401 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
340 "[GnuTLS] - Host '%s:%d' is missing a " 402 "[GnuTLS] - Host '%s:%d' is missing a "
@@ -353,7 +415,10 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
353 } 415 }
354 416
355 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 417 if (sc->enabled == GNUTLS_ENABLED_TRUE) {
356 rv = read_crt_cn(s, p, sc->cert_x509, &sc->cert_cn); 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
357 if (rv < 0) { 422 if (rv < 0) {
358 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 423 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
359 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 424 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
@@ -482,15 +547,6 @@ mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
482 547
483 ctxt = gnutls_transport_get_ptr(session); 548 ctxt = gnutls_transport_get_ptr(session);
484 549
485 sni_type = gnutls_certificate_type_get(session);
486 if (sni_type != GNUTLS_CRT_X509) {
487 /* In theory, we could support OpenPGP Certificates. Theory != code. */
488 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
489 ctxt->c->base_server,
490 "GnuTLS: Only x509 Certificates are currently supported.");
491 return NULL;
492 }
493
494 rv = gnutls_server_name_get(ctxt->session, sni_name, 550 rv = gnutls_server_name_get(ctxt->session, sni_name,
495 &data_len, &sni_type, 0); 551 &data_len, &sni_type, 0);
496 552
@@ -591,6 +647,8 @@ static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
591 gnutls_handshake_set_post_client_hello_function(ctxt->session, 647 gnutls_handshake_set_post_client_hello_function(ctxt->session,
592 mgs_select_virtual_server_cb); 648 mgs_select_virtual_server_cb);
593 649
650 mgs_cache_session_init(ctxt);
651
594 return ctxt; 652 return ctxt;
595} 653}
596 654
@@ -686,7 +744,11 @@ int mgs_hook_fixups(request_rec * r)
686 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 744 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
687 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));
688 746
689 mgs_add_common_cert_vars(r, ctxt->sc->cert_x509, 0, 747 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
748 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
749 ctxt->sc->export_certificates_enabled);
750 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
751 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
690 ctxt->sc->export_certificates_enabled); 752 ctxt->sc->export_certificates_enabled);
691 753
692 return rv; 754 return rv;
@@ -748,7 +810,7 @@ int mgs_hook_authz(request_rec * r)
748 */ 810 */
749#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") 811#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
750static void 812static void
751mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side, 813mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
752 int export_certificates_enabled) 814 int export_certificates_enabled)
753{ 815{
754 unsigned char sbuf[64]; /* buffer to hold serials */ 816 unsigned char sbuf[64]; /* buffer to hold serials */
@@ -795,7 +857,7 @@ mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side,
795 apr_psprintf(r->pool, "%u", ret)); 857 apr_psprintf(r->pool, "%u", ret));
796 858
797 apr_table_setn(env, 859 apr_table_setn(env,
798 apr_pstrcat(r->pool, MGS_SIDE, "_S_TYPE", NULL), "X.509"); 860 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "X.509");
799 861
800 tmp = 862 tmp =
801 mgs_time2sz(gnutls_x509_crt_get_expiration_time 863 mgs_time2sz(gnutls_x509_crt_get_expiration_time
@@ -837,34 +899,99 @@ mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side,
837 899
838 if (ret == GNUTLS_SAN_DNSNAME) { 900 if (ret == GNUTLS_SAN_DNSNAME) {
839 apr_table_setn(env, 901 apr_table_setn(env,
840 apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), 902 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
841 apr_psprintf(r->pool, "DNSNAME:%s", tmp2)); 903 apr_psprintf(r->pool, "DNSNAME:%s", tmp2));
842 } else if (ret == GNUTLS_SAN_RFC822NAME) { 904 } else if (ret == GNUTLS_SAN_RFC822NAME) {
843 apr_table_setn(env, 905 apr_table_setn(env,
844 apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), 906 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
845 apr_psprintf(r->pool, "RFC822NAME:%s", tmp2)); 907 apr_psprintf(r->pool, "RFC822NAME:%s", tmp2));
846 } else if (ret == GNUTLS_SAN_URI) { 908 } else if (ret == GNUTLS_SAN_URI) {
847 apr_table_setn(env, 909 apr_table_setn(env,
848 apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), 910 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
849 apr_psprintf(r->pool, "URI:%s", tmp2)); 911 apr_psprintf(r->pool, "URI:%s", tmp2));
850 } else { 912 } else {
851 apr_table_setn(env, 913 apr_table_setn(env,
852 apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i), 914 apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
853 "UNSUPPORTED"); 915 "UNSUPPORTED");
854 } 916 }
855 } 917 }
856 } 918 }
919}
857 920
921static void
922mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side,
923 int export_certificates_enabled)
924{
925 unsigned char sbuf[64]; /* buffer to hold serials */
926 char buf[AP_IOBUFSIZE];
927 const char *tmp;
928 size_t len;
929 int ret;
858 930
859} 931 apr_table_t *env = r->subprocess_env;
860 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 }
944
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}
861 984
985/* TODO: Allow client sending a X.509 certificate chain */
862static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) 986static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
863{ 987{
864 const gnutls_datum_t *cert_list; 988 const gnutls_datum_t *cert_list;
865 unsigned int cert_list_size, status, expired; 989 unsigned int cert_list_size, status, expired;
866 int rv, ret; 990 int rv, ret;
867 gnutls_x509_crt_t cert; 991 union {
992 gnutls_x509_crt_t x509;
993 gnutls_openpgp_crt_t pgp;
994 } cert;
868 apr_time_t activation_time, expiration_time, cur_time; 995 apr_time_t activation_time, expiration_time, cur_time;
869 996
870 cert_list = 997 cert_list =
@@ -890,32 +1017,56 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
890 return HTTP_FORBIDDEN; 1017 return HTTP_FORBIDDEN;
891 } 1018 }
892 1019
893 gnutls_x509_crt_init(&cert); 1020 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
894 rv = gnutls_x509_crt_import(cert, &cert_list[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
895 if (rv < 0) { 1028 if (rv < 0) {
896 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1029 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
897 "GnuTLS: Failed to Verify Peer: " 1030 "GnuTLS: Failed to Verify Peer: "
898 "Failed to import peer certificates."); 1031 "Failed to import peer certificates.");
899 ret = HTTP_FORBIDDEN; 1032 ret = HTTP_FORBIDDEN;
900 goto exit; 1033 goto exit;
901 } 1034 }
902 1035
903 apr_time_ansi_put(&expiration_time, 1036 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
904 gnutls_x509_crt_get_expiration_time(cert)); 1037 apr_time_ansi_put(&expiration_time,
905 apr_time_ansi_put(&activation_time, 1038 gnutls_x509_crt_get_expiration_time(cert.x509));
906 gnutls_x509_crt_get_activation_time(cert)); 1039 apr_time_ansi_put(&activation_time,
1040 gnutls_x509_crt_get_activation_time(cert.x509));
907 1041
908 rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list, 1042 rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list,
909 ctxt->sc->ca_list_size, 0, &status); 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 }
910 1053
911 if (rv < 0) { 1054 if (rv < 0) {
912 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1055 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
913 "GnuTLS: Failed to Verify Peer certificate: (%d) %s", 1056 "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
914 rv, gnutls_strerror(rv)); 1057 rv, gnutls_strerror(rv));
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?");
915 ret = HTTP_FORBIDDEN; 1061 ret = HTTP_FORBIDDEN;
916 goto exit; 1062 goto exit;
917 } 1063 }
918 1064
1065 /* TODO: X509 CRL Verification. */
1066 /* May add later if anyone needs it.
1067 */
1068 /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
1069
919 expired = 0; 1070 expired = 0;
920 cur_time = apr_time_now(); 1071 cur_time = apr_time_now();
921 if (activation_time > cur_time) { 1072 if (activation_time > cur_time) {
@@ -950,16 +1101,11 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
950 "GnuTLS: Peer Certificate is revoked."); 1101 "GnuTLS: Peer Certificate is revoked.");
951 } 1102 }
952 1103
953 /* TODO: Further Verification. */ 1104 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
954 /* Revocation is X.509 non workable paradigm, I really doubt implementation 1105 mgs_add_common_cert_vars(r, cert.x509, 1,
955 * is worth doing --nmav 1106 ctxt->sc->export_certificates_enabled);
956 */ 1107 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
957/// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); 1108 mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
958
959// mgs_hook_fixups(r);
960// rv = mgs_authz_lua(r);
961
962 mgs_add_common_cert_vars(r, cert, 1,
963 ctxt->sc->export_certificates_enabled); 1109 ctxt->sc->export_certificates_enabled);
964 1110
965 { 1111 {
@@ -983,7 +1129,10 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
983 } 1129 }
984 1130
985 exit: 1131 exit:
986 gnutls_x509_crt_deinit(cert); 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);
987 return ret; 1136 return ret;
988 1137
989 1138
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c
index a6e5528..014bfc8 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -64,6 +64,14 @@ static const command_rec mgs_config_cmds[] = {
64 NULL, 64 NULL,
65 RSRC_CONF, 65 RSRC_CONF,
66 "Set the CA File to verify 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"),
67 AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file, 75 AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file,
68 NULL, 76 NULL,
69 RSRC_CONF, 77 RSRC_CONF,
@@ -75,11 +83,27 @@ static const command_rec mgs_config_cmds[] = {
75 AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file, 83 AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file,
76 NULL, 84 NULL,
77 RSRC_CONF, 85 RSRC_CONF,
78 "SSL Server Key file"), 86 "SSL Server X509 Certificate file"),
79 AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file, 87 AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file,
80 NULL, 88 NULL,
81 RSRC_CONF, 89 RSRC_CONF,
82 "SSL Server SRP Password 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"),
83 AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file, 107 AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file,
84 NULL, 108 NULL,
85 RSRC_CONF, 109 RSRC_CONF,