From 75636faa679422cb7e360167d03163ca1985f772 Mon Sep 17 00:00:00 2001
From: Nokis Mavrogiannopoulos
Date: Wed, 20 Feb 2008 18:50:41 +0000
Subject: added tags
---
Makefile.am | 4 +-
NEWS | 13 +++
NOTICE | 3 +
README | 44 +++++---
README.ENV | 8 +-
configure.ac | 18 ++--
include/mod_gnutls.h.in | 22 +++-
libgnutls.m4 | 174 ++++++++++++++++++++++++++++++
src/gnutls_cache.c | 84 ++++++++-------
src/gnutls_config.c | 131 +++++++++++++++++++++--
src/gnutls_hooks.c | 273 +++++++++++++++++++++++++++++++++++++-----------
src/mod_gnutls.c | 28 ++++-
12 files changed, 667 insertions(+), 135 deletions(-)
create mode 100644 libgnutls.m4
diff --git a/Makefile.am b/Makefile.am
index d61ebd3..a19e755 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,11 +1,11 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2
EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \
- m4/libgnutls.m4 m4/apr_memcache.m4 \
+ libgnutls.m4 m4/apr_memcache.m4 \
m4/apache_test.m4 m4/lua.m4 \
include/mod_gnutls.h.in \
README README.ENV NEWS \
NOTICE LICENSE autogen.sh
-SUBDIRS = src data
+SUBDIRS = src
ACLOCAL_AMFLAGS = -I m4
diff --git a/NEWS b/NEWS
index e4b908d..a9fe9fd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,16 @@
+** Version 0.5.0-alpha (2008-01-24)
+
+- Added support for OpenPGP keys. The new directives are:
+ GnuTLSPGPKeyringFile, GnuTLSPGPCertificateFile, GnuTLSPGPKeyFile
+
+** Version 0.4.2 (2007-12-10)
+
+- Added support for sending a certificate chain.
+
+- Corrected bug which did not allow the TLS session cache to be used.
+
+- Do not allow resuming sessions on different servers.
+
** Version 0.4.1 (2007-12-03)
- Added support for subject alternative names in certificates.
diff --git a/NOTICE b/NOTICE
index 7b09606..25efd6f 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,3 +1,6 @@
+This product includes software developed by
+Nikos Mavrogiannopoulos (http://www.gnutls.org/).
+
This product includes software developed by
Paul Querna (http://www.outoforder.cc/).
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
GnuTLS, so long story short, I decided to implement a mod_gnutls.
Lines of Code in mod_ssl: 15,324
-Lines of Code in mod_gnutls: 1,886
+Lines of Code in mod_gnutls: 3,594
Because of writing mod_gnutls, I now understand how input and output filters work,
better than I ever thought possible. It was a little painful at times, and some parts
@@ -54,31 +54,26 @@ GnuTLSCache dbm conf/gnutls_cache
GnuTLSEnable On
# This is the Private key for your server.
- GnuTLSKeyFile conf/server.key
+ GnuTLSX509KeyFile conf/server.key
# This is the Server Certificate.
- GnuTLSCertificateFile conf/server.cert
+ GnuTLSX509CertificateFile conf/server.cert
-
# a more advanced configuration
GnuTLSCache dbm "/var/cache/www-tls-cache/cache"
-GnuTLSCacheTimeout 500
-GnuTLSProtocols TLS1.1 TLS1.0 SSL3.0
+GnuTLSCacheTimeout 600
NameVirtualHost 1.2.3.4:443
Servername server.com:443
GnuTLSEnable on
- GnuTLSCiphers AES-128-CBC 3DES-CBC ARCFOUR-128
- GnuTLSKeyExchangeAlgorithms RSA DHE-RSA DHE-DSS SRP SRP-RSA SRP-DSS
- GnuTLSMACAlgorithms SHA1 MD5
- GnuTLSCompressionMethods NULL
+ GnuTLSPriority NORMAL
# To export exactly the same environment variables as mod_ssl to CGI scripts.
GNUTLSExportCertificates on
- GnuTLSCertificateFile /etc/apache2/server-cert.pem
- GnuTLSKeyFile /etc/apache2/server-key.pem
+ GnuTLSX509CertificateFile /etc/apache2/server-cert.pem
+ GnuTLSX509KeyFile /etc/apache2/server-key.pem
# To enable SRP you must have these files installed. Check the gnutls srptool.
GnuTLSSRPPasswdFile /etc/apache2/tpasswd
@@ -88,6 +83,29 @@ NameVirtualHost 1.2.3.4:443
# GnuTLSClientVerify could be ignore or require. The GnuTLSClientCAFile
# contains the CAs to verify client certificates.
GnuTLSClientVerify request
- GnuTLSClientCAFile ca.pem
+ GnuTLSX509CAFile ca.pem
...
+
+# A setup for OpenPGP and X.509 authentication
+
+ Servername crystal.lan:443
+ GnuTLSEnable on
+ GnuTLSPriorities NORMAL:+COMP-NULL
+
+# setup the openpgp keys
+ GnuTLSPGPCertificateFile /etc/apache2/test.pub.asc
+ GnuTLSPGPKeyFile /etc/apache2/test.sec.asc
+
+# and the X.509 keys
+ GnuTLSCertificateFile /etc/apache2/server-cert.pem
+ GnuTLSKeyFile /etc/apache2/server-key.pem
+ GnuTLSClientVerify ignore
+
+# To avoid using the default DH params
+ GnuTLSDHFile /etc/apache2/dh.pem
+
+# these are only needed if GnuTLSClientVerify != ignore
+ GnuTLSClientCAFile ca.pem
+ GnuTLSPGPKeyringFile /etc/apache2/ring.asc
+
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.
SSL_CLIENT_V_END: The expiration time of client's certificate.
SSL_CLIENT_S_DN: The distinguished name of client's certificate in RFC2253 format.
SSL_CLIENT_I_DN: The distinguished name of client's issuer certificate in RFC2253 format.
-SSL_CLIENT_S_SAN%: These will contain the alternative names of the client certificate
+SSL_CLIENT_S_AN%: These will contain the alternative names of the client certificate
(% is a number starting from zero). The values will be prepended by "DNSNAME:",
"RFC822NAME:" or "URI:" depending on the type. If it is not supported the value
"UNSUPPORTED" will be set.
@@ -30,13 +30,13 @@ SSL_CLIENT_A_KEY: The public key algorithm in client's certificate.
SSL_CLIENT_CERT: The PEM-encoded client certificate
SSL_CLIENT_VERIFY:
whether the client's certificate was verified. (NONE if none was sent, or SUCCESS or FAILED)
-SSL_CLIENT_S_TYPE: The certificate type can be X.509 or OPENPGP.
+SSL_CLIENT_CERT_TYPE: The certificate type can be X.509 or OPENPGP.
SSL_SERVER_V_START: The activation time of server's certificate.
SSL_SERVER_V_END: The expiration time of server's certificate.
SSL_SERVER_S_DN: The distinguished name of the server's certificate in RFC2253 format.
SSL_SERVER_I_DN: The distinguished name of the server's issuer certificate in RFC2253 format.
-SSL_SERVER_S_SAN%: These will contain the alternative names of the server certificate
+SSL_SERVER_S_AN%: These will contain the alternative names of the server certificate
(% is a number starting from zero). The values will be prepended by "DNSNAME:",
"RFC822NAME:" or "URI:" depending on the type. If it is not supported the value
"UNSUPPORTED" will be set.
@@ -45,5 +45,5 @@ SSL_SERVER_M_VERSION: The version of the server's certificate.
SSL_SERVER_A_SIG: The algorithm used for the signature in server's certificate.
SSL_SERVER_A_KEY: The public key algorithm in server's certificate.
SSL_SERVER_CERT: The PEM-encoded server certificate
-SSL_SERVER_S_TYPE: The certificate type can be X.509 or OPENPGP.
+SSL_SERVER_CERT_TYPE: The certificate type can be X.509 or OPENPGP.
diff --git a/configure.ac b/configure.ac
index c401940..0cdcdd9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
dnl
-AC_INIT(mod_gnutls, 0.4.1)
+AC_INIT(mod_gnutls, 0.5.0-alpha)
OOO_CONFIG_NICE(config.nice)
MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
AC_PREREQ(2.53)
@@ -28,8 +28,14 @@ CHECK_APACHE(,$AP_VERSION,
dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`"
dnl AC_SUBST(LIBTOOL)
-MIN_TLS_VERSION=2.1.7
-CHECK_LIBGNUTLS($MIN_TLS_VERSION)
+MIN_TLS_VERSION=2.2.1
+AM_PATH_LIBGNUTLS_EXTRA($MIN_TLS_VERSION,,
+ AC_MSG_ERROR([[
+***
+*** libgnutls and libgnutls-extra were not found. You may want to get it from
+*** http://www.gnutls.org/
+***
+]]))
dnl CHECK_LUA()
@@ -37,13 +43,13 @@ have_apr_memcache=0
CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0])
AC_SUBST(have_apr_memcache)
-MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
-MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}"
+MODULE_CFLAGS="${LIBGNUTLS_EXTRA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
+MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_EXTRA_LIBS}"
AC_SUBST(MODULE_CFLAGS)
AC_SUBST(MODULE_LIBS)
-AC_CONFIG_FILES([Makefile src/Makefile include/mod_gnutls.h data/Makefile])
+AC_CONFIG_FILES([Makefile src/Makefile include/mod_gnutls.h])
AC_OUTPUT
echo "---"
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 @@
#include
#include
+#include
+#include
#include
#ifndef __mod_gnutls_h_inc
@@ -80,7 +82,10 @@ typedef struct
/* The maximum number of client CA certificates allowed.
*/
#define MAX_CA_CRTS 128
-#define MAX_CIPHERS 16
+
+/* The maximum number of certificates to send in a chain
+ */
+#define MAX_CHAIN_SIZE 8
typedef struct
{
@@ -88,8 +93,11 @@ typedef struct
gnutls_srp_server_credentials_t srp_creds;
gnutls_anon_server_credentials_t anon_creds;
char* cert_cn;
- gnutls_x509_crt_t cert_x509;
+ gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */
+ unsigned int certs_x509_num;
gnutls_x509_privkey_t privkey_x509;
+ gnutls_openpgp_crt_t cert_pgp; /* A certificate chain */
+ gnutls_openpgp_privkey_t privkey_pgp;
int enabled;
/* whether to send the PEM encoded certificates
* to CGIs
@@ -104,6 +112,7 @@ typedef struct
const char* srp_tpasswd_file;
const char* srp_tpasswd_conf_file;
gnutls_x509_crt_t ca_list[MAX_CA_CRTS];
+ gnutls_openpgp_keyring_t pgp_list;
unsigned int ca_list_size;
int client_verify_mode;
} mgs_srvconf_rec;
@@ -250,6 +259,12 @@ const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
const char *arg);
+const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
+ const char *arg);
+
+const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
+ const char *arg);
+
const char *mgs_set_cache(cmd_parms * parms, void *dummy,
const char *type, const char* arg);
@@ -262,6 +277,9 @@ const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
const char *arg);
+const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
+ const char *arg);
+
const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
const char *arg);
const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
diff --git a/libgnutls.m4 b/libgnutls.m4
new file mode 100644
index 0000000..dd86431
--- /dev/null
+++ b/libgnutls.m4
@@ -0,0 +1,174 @@
+dnl Autoconf macros for libgnutls-extra
+dnl $id$
+
+# Modified for LIBGNUTLS_EXTRA -- nmav
+# Configure paths for LIBGCRYPT
+# Shamelessly stolen from the one of XDELTA by Owen Taylor
+# Werner Koch 99-12-09
+
+dnl AM_PATH_LIBGNUTLS_EXTRA([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgnutls-extra, and define LIBGNUTLS_EXTRA_CFLAGS and LIBGNUTLS_EXTRA_LIBS
+dnl
+AC_DEFUN([AM_PATH_LIBGNUTLS_EXTRA],
+[dnl
+dnl Get the cflags and libraries from the libgnutls-extra-config script
+dnl
+AC_ARG_WITH(libgnutls-extra-prefix,
+ [ --with-libgnutls-extra-prefix=PFX Prefix where libgnutls-extra is installed (optional)],
+ libgnutls_extra_config_prefix="$withval", libgnutls_extra_config_prefix="")
+
+ if test x$libgnutls_extra_config_prefix != x ; then
+ if test x${LIBGNUTLS_EXTRA_CONFIG+set} != xset ; then
+ LIBGNUTLS_EXTRA_CONFIG=$libgnutls_extra_config_prefix/bin/libgnutls-extra-config
+ fi
+ fi
+
+ AC_PATH_PROG(LIBGNUTLS_EXTRA_CONFIG, libgnutls-extra-config, no)
+ min_libgnutls_version=ifelse([$1], ,0.1.0,$1)
+ AC_MSG_CHECKING(for libgnutls - version >= $min_libgnutls_version)
+ no_libgnutls=""
+ if test "$LIBGNUTLS_EXTRA_CONFIG" = "no" ; then
+ no_libgnutls=yes
+ else
+ LIBGNUTLS_EXTRA_CFLAGS=`$LIBGNUTLS_EXTRA_CONFIG $libgnutls_extra_config_args --cflags`
+ LIBGNUTLS_EXTRA_LIBS=`$LIBGNUTLS_EXTRA_CONFIG $libgnutls_extra_config_args --libs`
+ libgnutls_extra_config_version=`$LIBGNUTLS_EXTRA_CONFIG $libgnutls_extra_config_args --version`
+
+
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $LIBGNUTLS_EXTRA_CFLAGS"
+ LIBS="$LIBS $LIBGNUTLS_EXTRA_LIBS"
+dnl
+dnl Now check if the installed libgnutls is sufficiently new. Also sanity
+dnl checks the results of libgnutls-extra-config to some extent
+dnl
+ rm -f conf.libgnutlstest
+ AC_TRY_RUN([
+#include
+#include
+#include
+#include
+
+int
+main ()
+{
+ system ("touch conf.libgnutlstest");
+
+ if( strcmp( gnutls_extra_check_version(NULL), "$libgnutls_extra_config_version" ) )
+ {
+ printf("\n*** 'libgnutls-extra-config --version' returned %s, but LIBGNUTLS_EXTRA (%s)\n",
+ "$libgnutls_extra_config_version", gnutls_extra_check_version(NULL) );
+ printf("*** was found! If libgnutls-extra-config was correct, then it is best\n");
+ printf("*** to remove the old version of LIBGNUTLS_EXTRA. You may also be able to fix the error\n");
+ printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+ printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+ printf("*** required on your system.\n");
+ printf("*** If libgnutls-extra-config was wrong, set the environment variable LIBGNUTLS_EXTRA_CONFIG\n");
+ printf("*** to point to the correct copy of libgnutls-extra-config, and remove the file config.cache\n");
+ printf("*** before re-running configure\n");
+ }
+ else if ( strcmp(gnutls_extra_check_version(NULL), LIBGNUTLS_EXTRA_VERSION ) )
+ {
+ printf("\n*** LIBGNUTLS_EXTRA header file (version %s) does not match\n", LIBGNUTLS_EXTRA_VERSION);
+ printf("*** library (version %s). This is may be due to a different version of gnutls\n", gnutls_extra_check_version(NULL) );
+ printf("*** and gnutls-extra.\n");
+ }
+ else
+ {
+ if ( gnutls_extra_check_version( "$min_libgnutls_version" ) )
+ {
+ return 0;
+ }
+ else
+ {
+ printf("no\n*** An old version of LIBGNUTLS_EXTRA (%s) was found.\n",
+ gnutls_extra_check_version(NULL) );
+ printf("*** You need a version of LIBGNUTLS_EXTRA newer than %s. The latest version of\n",
+ "$min_libgnutls_version" );
+ printf("*** LIBGNUTLS_EXTRA is always available from ftp://gnutls.hellug.gr/pub/gnutls.\n");
+ printf("*** \n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the libgnutls-extra-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of LIBGNUTLS_EXTRA, but you can also set the LIBGNUTLS_EXTRA_CONFIG environment to point to the\n");
+ printf("*** correct copy of libgnutls-extra-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ }
+ return 1;
+}
+],, no_libgnutls=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ if test "x$no_libgnutls" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ if test -f conf.libgnutlstest ; then
+ :
+ else
+ AC_MSG_RESULT(no)
+ fi
+ if test "$LIBGNUTLS_EXTRA_CONFIG" = "no" ; then
+ echo "*** The libgnutls-extra-config script installed by LIBGNUTLS_EXTRA could not be found"
+ echo "*** If LIBGNUTLS_EXTRA was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the LIBGNUTLS_EXTRA_CONFIG environment variable to the"
+ echo "*** full path to libgnutls-extra-config."
+ else
+ if test -f conf.libgnutlstest ; then
+ :
+ else
+ echo "*** Could not run libgnutls test program, checking why..."
+ CFLAGS="$CFLAGS $LIBGNUTLS_EXTRA_CFLAGS"
+ LIBS="$LIBS $LIBGNUTLS_EXTRA_LIBS"
+ AC_TRY_LINK([
+#include
+#include
+#include
+#include
+], [ return !!gnutls_extra_check_version(NULL); ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding LIBGNUTLS_EXTRA or finding the wrong"
+ echo "*** version of LIBGNUTLS_EXTRA. If it is not finding LIBGNUTLS_EXTRA, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***" ],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means LIBGNUTLS_EXTRA was incorrectly installed"
+ echo "*** or that you have moved LIBGNUTLS_EXTRA since it was installed. In the latter case, you"
+ echo "*** may want to edit the libgnutls-extra-config script: $LIBGNUTLS_EXTRA_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ LIBGNUTLS_EXTRA_CFLAGS=""
+ LIBGNUTLS_EXTRA_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ rm -f conf.libgnutlstest
+ AC_SUBST(LIBGNUTLS_EXTRA_CFLAGS)
+ AC_SUBST(LIBGNUTLS_EXTRA_LIBS)
+
+ LIBGNUTLS_LIBS=$LIBGNUTLS_EXTRA_LIBS
+ LIBGNUTLS_CFLAGS=$LIBGNUTLS_EXTRA_CFLAGS
+ LIBGNUTLS_VERSION=`$LIBGNUTLS_EXTRA_CONFIG $libgnutls_extra_config_args --version`
+ LIBGNUTLS_PREFIX="`$LIBGNUTLS_EXTRA_CONFIG $libgnutls_extra_config_args --prefix`"
+ GNUTLS_CERTTOOL="${LIBGNUTLS_PREFIX}/bin/certtool"
+
+ AC_SUBST(LIBGNUTLS_CFLAGS)
+ AC_SUBST(LIBGNUTLS_LIBS)
+ AC_SUBST(LIBGNUTLS_VERSION)
+ AC_SUBST(LIBGNUTLS_PREFIX)
+ AC_SUBST(LIBGNUTLS_CERTTOOL)
+
+])
+
+dnl *-*wedit:notab*-* Please keep this as the last line.
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 @@
#define MC_TAG "mod_gnutls:"
-#define MC_TAG_LEN \
- (sizeof(MC_TAG))
+#define MC_TAG_LEN sizeof(MC_TAG)
#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
-#if 0
-static char *gnutls_session_id2sz(unsigned char *id, int idlen,
+char *mgs_session_id2sz(unsigned char *id, int idlen,
char *str, int strsize)
{
char *cp;
int n;
-
- cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN);
+
+ cp = str;
for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
cp += 2;
@@ -53,7 +51,27 @@ static char *gnutls_session_id2sz(unsigned char *id, int idlen,
*cp = '\0';
return str;
}
-#endif
+
+
+/* Name the Session ID as:
+ * server:port.SessionID
+ * to disallow resuming sessions on different servers
+ */
+static int mgs_session_id2dbm(conn_rec* c, unsigned char *id, int idlen,
+ apr_datum_t* dbmkey)
+{
+char buf[STR_SESSION_LEN];
+char *sz;
+
+ sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
+ if (sz == NULL)
+ return -1;
+
+ dbmkey->dptr = apr_psprintf(c->pool, "%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
+ dbmkey->dsize = strlen( dbmkey->dptr);
+
+ return 0;
+}
#define CTIME "%b %d %k:%M:%S %Y %Z"
char *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)
return str;
}
-char *mgs_session_id2sz(unsigned char *id, int idlen,
- char *str, int strsize)
+#if HAVE_APR_MEMCACHE
+/* Name the Session ID as:
+ * server:port.SessionID
+ * to disallow resuming sessions on different servers
+ */
+static char* mgs_session_id2mc(conn_rec* c, unsigned char *id, int idlen)
{
- char *cp;
- int n;
+char buf[STR_SESSION_LEN];
+char *sz;
- cp = str;
- for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
- apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
- cp += 2;
- }
- *cp = '\0';
- return str;
+ sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
+ if (sz == NULL)
+ return NULL;
+
+ return apr_psprintf(c->pool, MC_TAG"%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
}
-
-#if HAVE_APR_MEMCACHE
-
/**
* GnuTLS Session Cache using libmemcached
*
@@ -184,11 +201,10 @@ static int mc_cache_store(void* baton, gnutls_datum_t key,
{
apr_status_t rv = APR_SUCCESS;
mgs_handle_t *ctxt = baton;
- char buf[STR_SESSION_LEN];
char* strkey = NULL;
apr_uint32_t timeout;
- strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
+ strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
if(!strkey)
return -1;
@@ -211,13 +227,12 @@ static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
{
apr_status_t rv = APR_SUCCESS;
mgs_handle_t *ctxt = baton;
- char buf[STR_SESSION_LEN];
char* strkey = NULL;
char* value;
apr_size_t value_len;
gnutls_datum_t data = { NULL, 0 };
- strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
+ strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
if (!strkey) {
return data;
}
@@ -252,10 +267,9 @@ static int mc_cache_delete(void* baton, gnutls_datum_t key)
{
apr_status_t rv = APR_SUCCESS;
mgs_handle_t *ctxt = baton;
- char buf[STR_SESSION_LEN];
char* strkey = NULL;
- strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
+ strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
if(!strkey)
return -1;
@@ -366,8 +380,8 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
mgs_handle_t *ctxt = baton;
apr_status_t rv;
- dbmkey.dptr = (void*)key.data;
- dbmkey.dsize = key.size;
+ if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
+ return data;
rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
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,
mgs_handle_t *ctxt = baton;
apr_status_t rv;
apr_time_t expiry;
-
- dbmkey.dptr = (char *)key.data;
- dbmkey.dsize = key.size;
+
+ if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
+ return -1;
/* create DBM value */
dbmval.dsize = data.size + sizeof(apr_time_t);
@@ -467,9 +481,9 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key)
apr_datum_t dbmkey;
mgs_handle_t *ctxt = baton;
apr_status_t rv;
-
- dbmkey.dptr = (char *)key.data;
- dbmkey.dsize = key.size;
+
+ if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
+ return -1;
rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
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 @@
/**
* Copyright 2004-2005 Paul Querna
+ * Copyright 2007 Nikos Mavrogiannopoulos
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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,
"Certificate '%s'", file);
}
- ret = gnutls_x509_crt_init(&sc->cert_x509);
- if (ret < 0) {
- return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
- ": (%d) %s", ret, gnutls_strerror(ret));
- }
-
+ sc->certs_x509_num = MAX_CHAIN_SIZE;
ret =
- gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM);
- if (ret != 0) {
+ gnutls_x509_crt_list_import(sc->certs_x509, &sc->certs_x509_num, &data, GNUTLS_X509_FMT_PEM, 0);
+ if (ret < 0) {
return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
"Certificate '%s': (%d) %s", file, ret,
gnutls_strerror(ret));
@@ -207,6 +203,84 @@ const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
return NULL;
}
+const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
+ const char *arg)
+{
+ int ret;
+ gnutls_datum_t data;
+ const char *file;
+ apr_pool_t *spool;
+ mgs_srvconf_rec *sc =
+ (mgs_srvconf_rec *) ap_get_module_config(parms->server->
+ module_config,
+ &gnutls_module);
+ apr_pool_create(&spool, parms->pool);
+
+ file = ap_server_root_relative(spool, arg);
+
+ if (load_datum_from_file(spool, file, &data) != 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
+ "Certificate '%s'", file);
+ }
+
+ ret = gnutls_openpgp_crt_init( &sc->cert_pgp);
+ if (ret < 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Failed to Init "
+ "PGP Certificate: (%d) %s", ret,
+ gnutls_strerror(ret));
+ }
+
+ ret =
+ gnutls_openpgp_crt_import(sc->cert_pgp, &data, GNUTLS_OPENPGP_FMT_BASE64);
+ if (ret < 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
+ "PGP Certificate '%s': (%d) %s", file, ret,
+ gnutls_strerror(ret));
+ }
+
+ apr_pool_destroy(spool);
+ return NULL;
+}
+
+const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
+ const char *arg)
+{
+ int ret;
+ gnutls_datum_t data;
+ const char *file;
+ apr_pool_t *spool;
+ mgs_srvconf_rec *sc =
+ (mgs_srvconf_rec *) ap_get_module_config(parms->server->
+ module_config,
+ &gnutls_module);
+ apr_pool_create(&spool, parms->pool);
+
+ file = ap_server_root_relative(spool, arg);
+
+ if (load_datum_from_file(spool, file, &data) != 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
+ "Private Key '%s'", file);
+ }
+
+ ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp);
+ if (ret < 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
+ ": (%d) %s", ret, gnutls_strerror(ret));
+ }
+
+ ret =
+ gnutls_openpgp_privkey_import(sc->privkey_pgp, &data,
+ GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
+ if (ret != 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
+ "PGP Private Key '%s': (%d) %s", file, ret,
+ gnutls_strerror(ret));
+ }
+ apr_pool_destroy(spool);
+ return NULL;
+}
+
+
const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
const char *arg)
{
@@ -355,6 +429,44 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
return NULL;
}
+const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
+ const char *arg)
+{
+ int rv;
+ const char *file;
+ apr_pool_t *spool;
+ gnutls_datum_t data;
+
+ mgs_srvconf_rec *sc =
+ (mgs_srvconf_rec *) ap_get_module_config(parms->server->
+ module_config,
+ &gnutls_module);
+ apr_pool_create(&spool, parms->pool);
+
+ file = ap_server_root_relative(spool, arg);
+
+ if (load_datum_from_file(spool, file, &data) != 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
+ "Keyring File '%s'", file);
+ }
+
+ rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
+ if (rv < 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
+ "keyring: (%d) %s", rv, gnutls_strerror(rv));
+ }
+
+ rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, GNUTLS_OPENPGP_FMT_BASE64);
+ if (rv < 0) {
+ return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
+ "Keyring File '%s': (%d) %s", file, rv,
+ gnutls_strerror(rv));
+ }
+
+ apr_pool_destroy(spool);
+ return NULL;
+}
+
const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
const char *arg)
{
@@ -440,7 +552,8 @@ void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
sc->srp_tpasswd_conf_file = NULL;
sc->srp_tpasswd_file = NULL;
sc->privkey_x509 = NULL;
- sc->cert_x509 = NULL;
+ memset( sc->certs_x509, 0, sizeof(sc->certs_x509));
+ sc->certs_x509_num = 0;
sc->cache_timeout = apr_time_from_sec(300);
sc->cache_type = mgs_cache_dbm;
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;
static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
/* use side==0 for server and side==1 for client */
-static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert,
+static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert,
+ int side,
+ int export_certificates_enabled);
+static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
int side,
int export_certificates_enabled);
@@ -68,9 +71,23 @@ int ret;
mpm_is_threaded = 0;
#endif
+ if (gnutls_check_version(LIBGNUTLS_VERSION)==NULL) {
+ fprintf(stderr, "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
+ LIBGNUTLS_VERSION, gnutls_check_version(NULL));
+ return -3;
+ }
+
ret = gnutls_global_init();
- if (ret < 0) /* FIXME: can we print here? */
- exit(ret);
+ if (ret < 0) {
+ fprintf(stderr, "gnutls_global_init: %s\n", gnutls_strerror(ret));
+ return -3;
+ }
+
+ ret = gnutls_global_init_extra();
+ if (ret < 0) {
+ fprintf(stderr, "gnutls_global_init_extra: %s\n", gnutls_strerror(ret));
+ return -3;
+ }
apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
apr_pool_cleanup_null);
@@ -82,19 +99,18 @@ int ret;
gnutls_global_set_log_level(9);
gnutls_global_set_log_function(gnutls_debug_log_all);
+ apr_file_printf(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
#endif
return OK;
}
-/* We don't support openpgp certificates, yet */
-const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
-
static int mgs_select_virtual_server_cb(gnutls_session_t session)
{
mgs_handle_t *ctxt;
mgs_srvconf_rec *tsc;
int ret;
+ int cprio[2];
ctxt = gnutls_transport_get_ptr(session);
@@ -126,17 +142,22 @@ static int mgs_select_virtual_server_cb(gnutls_session_t session)
* negotiation.
*/
ret = gnutls_priority_set(session, ctxt->sc->priorities);
- gnutls_certificate_type_set_priority(session, cert_type_prio);
-
-
/* actually it shouldn't fail since we have checked at startup */
if (ret < 0)
return ret;
- /* allow separate caches per virtual host. Actually allowing the same is a
- * bad idea, since they might have different security requirements.
+ /* If both certificate types are not present disallow them from
+ * being negotiated.
*/
- mgs_cache_session_init(ctxt);
+ if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
+ cprio[0] = GNUTLS_CRT_X509;
+ cprio[1] = 0;
+ gnutls_certificate_type_set_priority( session, cprio);
+ } else if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0]==NULL) {
+ cprio[0] = GNUTLS_CRT_OPENPGP;
+ cprio[1] = 0;
+ gnutls_certificate_type_set_priority( session, cprio);
+ }
return 0;
}
@@ -147,15 +168,31 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
ctxt = gnutls_transport_get_ptr(session);
- ret->type = GNUTLS_CRT_X509;
- ret->ncerts = 1;
- ret->deinit_all = 0;
+ if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) {
+ ret->type = GNUTLS_CRT_X509;
+ ret->ncerts = ctxt->sc->certs_x509_num;
+ ret->deinit_all = 0;
+
+ ret->cert.x509 = ctxt->sc->certs_x509;
+ ret->key.x509 = ctxt->sc->privkey_x509;
+
+ return 0;
+ } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) {
+ ret->type = GNUTLS_CRT_OPENPGP;
+ ret->ncerts = 1;
+ ret->deinit_all = 0;
+
+ ret->cert.pgp = ctxt->sc->cert_pgp;
+ ret->key.pgp = ctxt->sc->privkey_pgp;
+
+ return 0;
+
+ }
- ret->cert.x509 = &ctxt->sc->cert_x509;
- ret->key.x509 = ctxt->sc->privkey_x509;
- return 0;
+ return GNUTLS_E_INTERNAL_ERROR;
}
+/* 2048-bit group parameters from SRP specification */
const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
"MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
"gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
@@ -171,7 +208,7 @@ const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
* Returns negative on error.
*/
static int read_crt_cn(server_rec * s, apr_pool_t * p,
- gnutls_x509_crt cert, char **cert_cn)
+ gnutls_x509_crt_t cert, char **cert_cn)
{
int rv = 0, i;
size_t data_len;
@@ -179,6 +216,7 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
*cert_cn = NULL;
+ data_len = 0;
rv = gnutls_x509_crt_get_dn_by_oid(cert,
GNUTLS_OID_X520_COMMON_NAME,
0, 0, NULL, &data_len);
@@ -189,8 +227,8 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
GNUTLS_OID_X520_COMMON_NAME, 0,
0, *cert_cn, &data_len);
} else { /* No CN return subject alternative name */
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
- "No common name found in certificate for '%s:%d'. Looking for subject alternative name.",
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
s->server_hostname, s->port);
rv = 0;
/* read subject alternative name */
@@ -218,9 +256,33 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
}
return rv;
+}
+
+static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
+ gnutls_openpgp_crt_t cert, char **cert_cn)
+{
+ int rv = 0;
+ size_t data_len;
+
+
+ *cert_cn = NULL;
+
+ data_len = 0;
+ rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
+
+ if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
+ *cert_cn = apr_palloc(p, data_len);
+ rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len);
+ } else { /* No CN return subject alternative name */
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
+ "No name found in PGP certificate for '%s:%d'.",
+ s->server_hostname, s->port);
+ }
+ return rv;
}
+
int
mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
apr_pool_t * ptemp, server_rec * base_server)
@@ -334,7 +396,7 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
}
}
- if (sc->cert_x509 == NULL
+ if (sc->certs_x509[0] == NULL
&& sc->enabled == GNUTLS_ENABLED_TRUE) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
"[GnuTLS] - Host '%s:%d' is missing a "
@@ -353,7 +415,10 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
}
if (sc->enabled == GNUTLS_ENABLED_TRUE) {
- rv = read_crt_cn(s, p, sc->cert_x509, &sc->cert_cn);
+ rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn);
+ if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */
+ rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
+
if (rv < 0) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
"[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
@@ -482,15 +547,6 @@ mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
ctxt = gnutls_transport_get_ptr(session);
- sni_type = gnutls_certificate_type_get(session);
- if (sni_type != GNUTLS_CRT_X509) {
- /* In theory, we could support OpenPGP Certificates. Theory != code. */
- ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
- ctxt->c->base_server,
- "GnuTLS: Only x509 Certificates are currently supported.");
- return NULL;
- }
-
rv = gnutls_server_name_get(ctxt->session, sni_name,
&data_len, &sni_type, 0);
@@ -591,6 +647,8 @@ static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
gnutls_handshake_set_post_client_hello_function(ctxt->session,
mgs_select_virtual_server_cb);
+ mgs_cache_session_init(ctxt);
+
return ctxt;
}
@@ -686,7 +744,11 @@ int mgs_hook_fixups(request_rec * r)
tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
- mgs_add_common_cert_vars(r, ctxt->sc->cert_x509, 0,
+ if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
+ mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
+ ctxt->sc->export_certificates_enabled);
+ else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
+ mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
ctxt->sc->export_certificates_enabled);
return rv;
@@ -748,7 +810,7 @@ int mgs_hook_authz(request_rec * r)
*/
#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
static void
-mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side,
+mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
int export_certificates_enabled)
{
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,
apr_psprintf(r->pool, "%u", ret));
apr_table_setn(env,
- apr_pstrcat(r->pool, MGS_SIDE, "_S_TYPE", NULL), "X.509");
+ apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "X.509");
tmp =
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,
if (ret == GNUTLS_SAN_DNSNAME) {
apr_table_setn(env,
- apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i),
+ apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
apr_psprintf(r->pool, "DNSNAME:%s", tmp2));
} else if (ret == GNUTLS_SAN_RFC822NAME) {
apr_table_setn(env,
- apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i),
+ apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
apr_psprintf(r->pool, "RFC822NAME:%s", tmp2));
} else if (ret == GNUTLS_SAN_URI) {
apr_table_setn(env,
- apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i),
+ apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
apr_psprintf(r->pool, "URI:%s", tmp2));
} else {
apr_table_setn(env,
- apr_psprintf(r->pool, "%s_S_SAN%u", MGS_SIDE, i),
+ apr_psprintf(r->pool, "%s_S_AN%u", MGS_SIDE, i),
"UNSUPPORTED");
}
}
}
+}
+static void
+mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side,
+ int export_certificates_enabled)
+{
+ unsigned char sbuf[64]; /* buffer to hold serials */
+ char buf[AP_IOBUFSIZE];
+ const char *tmp;
+ size_t len;
+ int ret;
-}
+ apr_table_t *env = r->subprocess_env;
+ if (export_certificates_enabled != 0) {
+ char cert_buf[10 * 1024];
+ len = sizeof(cert_buf);
+
+ if (gnutls_openpgp_crt_export
+ (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
+ apr_table_setn(env,
+ apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
+ apr_pstrmemdup(r->pool, cert_buf, len));
+
+ }
+
+ len = sizeof(buf);
+ gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
+ apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
+ apr_pstrmemdup(r->pool, buf, len));
+
+ len = sizeof(sbuf);
+ gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
+ tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
+ apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL),
+ apr_pstrdup(r->pool, tmp));
+
+ ret = gnutls_openpgp_crt_get_version(cert);
+ if (ret > 0)
+ apr_table_setn(env,
+ apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
+ apr_psprintf(r->pool, "%u", ret));
+
+ apr_table_setn(env,
+ apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP");
+
+ tmp =
+ mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
+ (cert), buf, sizeof(buf));
+ apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
+ apr_pstrdup(r->pool, tmp));
+
+ tmp =
+ mgs_time2sz(gnutls_openpgp_crt_get_creation_time
+ (cert), buf, sizeof(buf));
+ apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
+ apr_pstrdup(r->pool, tmp));
+
+ ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
+ if (ret >= 0) {
+ apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
+ gnutls_pk_algorithm_get_name(ret));
+ }
+
+}
+/* TODO: Allow client sending a X.509 certificate chain */
static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
{
const gnutls_datum_t *cert_list;
unsigned int cert_list_size, status, expired;
int rv, ret;
- gnutls_x509_crt_t cert;
+ union {
+ gnutls_x509_crt_t x509;
+ gnutls_openpgp_crt_t pgp;
+ } cert;
apr_time_t activation_time, expiration_time, cur_time;
cert_list =
@@ -890,32 +1017,56 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
return HTTP_FORBIDDEN;
}
- gnutls_x509_crt_init(&cert);
- rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
+ if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
+ gnutls_x509_crt_init(&cert.x509);
+ rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER);
+ } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) {
+ gnutls_openpgp_crt_init(&cert.pgp);
+ rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW);
+ } else return HTTP_FORBIDDEN;
+
if (rv < 0) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"GnuTLS: Failed to Verify Peer: "
"Failed to import peer certificates.");
- ret = HTTP_FORBIDDEN;
- goto exit;
+ ret = HTTP_FORBIDDEN;
+ goto exit;
}
- apr_time_ansi_put(&expiration_time,
- gnutls_x509_crt_get_expiration_time(cert));
- apr_time_ansi_put(&activation_time,
- gnutls_x509_crt_get_activation_time(cert));
+ if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
+ apr_time_ansi_put(&expiration_time,
+ gnutls_x509_crt_get_expiration_time(cert.x509));
+ apr_time_ansi_put(&activation_time,
+ gnutls_x509_crt_get_activation_time(cert.x509));
- rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list,
+ rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list,
ctxt->sc->ca_list_size, 0, &status);
+ } else {
+ apr_time_ansi_put(&expiration_time,
+ gnutls_openpgp_crt_get_expiration_time(cert.pgp));
+ apr_time_ansi_put(&activation_time,
+ gnutls_openpgp_crt_get_creation_time(cert.pgp));
+
+ rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list,
+ 0, &status);
+ }
if (rv < 0) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"GnuTLS: Failed to Verify Peer certificate: (%d) %s",
rv, gnutls_strerror(rv));
+ if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
+ ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
+ "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
ret = HTTP_FORBIDDEN;
goto exit;
}
+ /* TODO: X509 CRL Verification. */
+ /* May add later if anyone needs it.
+ */
+ /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
+
expired = 0;
cur_time = apr_time_now();
if (activation_time > cur_time) {
@@ -950,16 +1101,11 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
"GnuTLS: Peer Certificate is revoked.");
}
- /* TODO: Further Verification. */
- /* Revocation is X.509 non workable paradigm, I really doubt implementation
- * is worth doing --nmav
- */
-/// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size);
-
-// mgs_hook_fixups(r);
-// rv = mgs_authz_lua(r);
-
- mgs_add_common_cert_vars(r, cert, 1,
+ if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
+ mgs_add_common_cert_vars(r, cert.x509, 1,
+ ctxt->sc->export_certificates_enabled);
+ else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
+ mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
ctxt->sc->export_certificates_enabled);
{
@@ -983,7 +1129,10 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
}
exit:
- gnutls_x509_crt_deinit(cert);
+ if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
+ gnutls_x509_crt_deinit(cert.x509);
+ else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
+ gnutls_openpgp_crt_deinit(cert.pgp);
return ret;
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[] = {
NULL,
RSRC_CONF,
"Set the CA File to verify Client Certificates"),
+ AP_INIT_TAKE1("GnuTLSX509CAFile", mgs_set_client_ca_file,
+ NULL,
+ RSRC_CONF,
+ "Set the CA File to verify Client Certificates"),
+ AP_INIT_TAKE1("GnuTLSPGPKeyringFile", mgs_set_keyring_file,
+ NULL,
+ RSRC_CONF,
+ "Set the Keyring File to verify Client Certificates"),
AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file,
NULL,
RSRC_CONF,
@@ -75,11 +83,27 @@ static const command_rec mgs_config_cmds[] = {
AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file,
NULL,
RSRC_CONF,
- "SSL Server Key file"),
+ "SSL Server X509 Certificate file"),
AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file,
NULL,
RSRC_CONF,
- "SSL Server SRP Password file"),
+ "SSL Server X509 Private Key file"),
+ AP_INIT_TAKE1("GnuTLSX509CertificateFile", mgs_set_cert_file,
+ NULL,
+ RSRC_CONF,
+ "SSL Server X509 Certificate file"),
+ AP_INIT_TAKE1("GnuTLSX509KeyFile", mgs_set_key_file,
+ NULL,
+ RSRC_CONF,
+ "SSL Server X509 Private Key file"),
+ AP_INIT_TAKE1("GnuTLSPGPCertificateFile", mgs_set_pgpcert_file,
+ NULL,
+ RSRC_CONF,
+ "SSL Server PGP Certificate file"),
+ AP_INIT_TAKE1("GnuTLSPGPKeyFile", mgs_set_pgpkey_file,
+ NULL,
+ RSRC_CONF,
+ "SSL Server PGP Private key file"),
AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file,
NULL,
RSRC_CONF,
--
cgit