Changeset ae29683 in mod_gnutls
- Timestamp:
- Feb 21, 2014, 12:15:56 AM (9 years ago)
- Branches:
- debian/master, debian/stretch-backports, jessie-backports, upstream
- Children:
- 4addf74, 62f781c
- Parents:
- 180e49f (diff), 1a99240 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 103 added
- 20 deleted
- 11 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
CHANGELOG
r180e49f rae29683 1 ** Version 0.6.0 2 - GnuTLSCache none is now an allowed option. 1 **TODO: 2 - Fix support for proxy termination 3 - Handle Unclean Shutdowns 4 - make session cache use generic apache caches 5 6 ** Version 0.6 (2014-02-17) 7 - Generating DH Params instead of using static ones. 8 - Now considering ServerAlias Directives. 9 - Major Legacy Code Cleanup. 10 - html and pdf and manual documentation generated from markdown sources 11 - support monkeysphere validation agent (MSVA) client-certificate verification 12 - wider test suite 13 - GnuTLSExportCertificates off by default 14 15 ** Version 0.5.10 (2011-07-12) 16 - Patched a bug responsible for excessive memory consumption by mod_gnutls. 17 - Support for proxying from SSL to plain HTTP was added (ie. proxy termination). 3 18 4 19 ** Version 0.5.9 (2010-09-24) 20 - GnuTLSCache none is now an allowed option. 5 21 - Corrected behavior in Keep-Alive connections (do not 6 22 terminate the connection prematurely) 7 8 23 - The GnuTLSCache variable now can be given the specific 9 24 option "gdbm" instead of "dbm". "dbm" will use the berkeley … … 13 28 ** Version 0.5.8 (2010-08-18) 14 29 - Session tickets are enabled by default. 15 16 30 - Fixes some segmentation faults noticed in some 17 31 configurations. … … 21 35 my system had issues after reaching a limit of entries. 22 36 SDBM seems stable so force it. 23 24 37 - Optimizations in session caching. 25 26 38 - Added support for session tickets. This allows a 27 39 server to avoid using a session cache and still support … … 29 41 session data during handshake. New option 30 42 GnuTLSSessionTickets [on|off] 31 32 43 - Depend on gnutls 2.10.0 to force support for safe 33 44 renegotiation. … … 36 47 - Corrected issue with firefox and long POST data (by 37 48 handling EINTR and EAGAIN errors in read). 38 39 49 - Added support for chained client certificates 40 41 50 - Corrected more issues related to double frees 42 51 http://issues.outoforder.cc/view.php?id=102 43 52 44 53 ** Version 0.5.5 (2009-06-13) 45 46 54 - Removed limits on CA certificate loading. Reported by 47 55 Sander Marechal and Jack Bates. 48 49 56 - Do not allow sending empty TLS packets even when instructed to. 50 57 This had the side effect of clients closing connection. 51 58 52 59 ** Version 0.5.4 (2009-01-04) 53 54 60 - mod_gnutls.h: modified definition to extern to avoid compilation 55 61 errors in darwin. 56 57 62 - Added patch to fix issue with mod_proxy. Investigation and patch by Alain 58 63 Knaff. 59 60 64 - libgnutls detection uses pkg-config. 61 65 62 66 ** Version 0.5.3 (2008-10-16) 63 64 67 - Corrected bug to allow having an OpenPGP-only web site. 65 66 68 - Increased Max handshake tries due to interrupted system calls. 67 69 68 70 ** Version 0.5.2 (2008-06-29) 69 70 71 - Depend on gnutls 2.4 which has openpgp support in main library. 71 72 72 73 ** Version 0.5.1 (2008-03-05) 73 74 74 - Added --disable-srp configure option 75 76 75 - Better check for memcache (patch by Guillaume Rousse) 77 78 76 - Corrected possible memory leak in DBM support for resuming sessions. 79 77 80 78 ** Version 0.5.0-alpha (2008-01-24) 81 82 79 - Added support for OpenPGP keys. The new directives are: 83 80 GnuTLSPGPKeyringFile, GnuTLSPGPCertificateFile, GnuTLSPGPKeyFile 84 81 85 82 ** Version 0.4.2 (2007-12-10) 86 87 83 - Added support for sending a certificate chain. 88 89 84 - Corrected bug which did not allow the TLS session cache to be used. 90 91 85 - Do not allow resuming sessions on different servers. 92 86 93 87 ** Version 0.4.1 (2007-12-03) 94 95 88 - Added support for subject alternative names in certificates. 96 89 Only one per certificate is supported. 97 98 90 - New enviroment variables: SSL_CLIENT_M_VERSION, SSL_CLIENT_S_SAN%, 99 91 SSL_CLIENT_S_TYPE, SSL_SERVER_M_VERSION, SSL_SERVER_S_SAN%, SSL_SERVER_S_TYPE 100 101 92 - The compatibility mode can now be enabled explicitely with the 102 93 %COMPAT keyword at the GnuTLSPriorities string. It is no longer the default. 103 104 94 - Check for GnuTLSPriorities directive. This corrects a segfault. Thanks 105 95 to David Hrbáč. 106 107 96 - Better handling of GnuTLSDHFile and GnuTLSRSAFile. 108 109 97 - No longer default paths for RSA and DH parameter files. -
Makefile.am
r180e49f rae29683 3 3 EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \ 4 4 m4/libgnutls.m4 m4/apr_memcache.m4 \ 5 m4/apache_test.m4 m4/lua.m4\5 m4/apache_test.m4 \ 6 6 include/mod_gnutls.h.in \ 7 7 README README.ENV NEWS \ … … 10 10 SUBDIRS = src 11 11 ACLOCAL_AMFLAGS = -I m4 12 TESTS = run_tests.sh -
NOTICE
r180e49f rae29683 1 1 This product includes software developed by 2 Nikos Mavrogiannopoulos (http://www.gnutls.org/). 2 -Dash Shendy (http://dash.za.net/) 3 -Nikos Mavrogiannopoulos (http://www.gnutls.org/). 4 -Paul Querna (http://www.outoforder.cc/). 5 -The Apache Software Foundation (http://www.apache.org/). 3 6 4 This product includes software developed by5 Paul Querna (http://www.outoforder.cc/).6 7 This product includes software developed by8 The Apache Software Foundation (http://www.apache.org/).9 -
README
r180e49f rae29683 9 9 I. ABOUT 10 10 II. AUTHORS 11 III. LICENSE 12 IV. STATUS 13 V. BASIC CONFIGURATION 14 VI. CREATE OPENPGP CREDENTIALS FOR THE SERVER 11 III. MAINTAINERS 12 IV. LICENSE 13 V. PREREQUISITES 14 VI. INSTALLATION 15 VII. BASIC CONFIGURATION 16 VIII. CREATE OPENPGP CREDENTIALS FOR THE SERVER 15 17 16 18 … … 42 44 II. AUTHORS 43 45 44 Paul Querna <chip force-elite.com> 45 Nikos Mavrogiannopoulos <nmav gnutls.org> 46 Paul Querna <chip at force-elite.com> 47 Nikos Mavrogiannopoulos <nmav at gnutls.org> 48 Dash Shendy <neuromancer at dash.za.net> 46 49 50 III. MAINTAINERS 47 51 52 Dash Shendy <neuromancer at dash.za.net> 53 Execute `autoreconf -v -i -f` to Auto-generate files 48 54 49 I II.LICENSE55 IV. LICENSE 50 56 51 57 Apache License, Version 2.0 (see the LICENSE file for details) 52 58 59 V. PREREQUISITES 60 61 * GnuTLS >= 2.12.6 <http://www.gnu.org/software/gnutls/> 62 * Apache HTTPD >= 2.0.42 <http://httpd.apache.org/> 63 * >= 2.1.5-dev 64 * ARP Memcache >= 0.7.0 (Optinal) 53 65 54 66 55 IV. STATUS 67 VI. INSTALLATION 56 68 57 * SSL and TLS connections with all popular browsers work!58 * Sets environmental vars for scripts (compatible with mod_ssl vars)59 * Supports memcached as a distributed SSL session cache60 * Supports DBM as a local SSL session cache61 * Support for server name indication (SNI), RFC354662 * Support for client certificates63 * Support for secure remote password (SRP), RFC505469 * tar xzvf mod_gnutls-version.tar.gz 70 * cd mod_gnutls-version/ 71 * ./configure --with-apxs=PATH --with-apr-memcache-prefix=PATH \ 72 --with-apr-memcache-libs=PATH --with-apr-memcache-includes=PATH 73 * make 74 * make install 75 * Configure & restart apache 64 76 65 66 67 V. BASIC CONFIGURATION 77 VII. BASIC CONFIGURATION 68 78 69 79 LoadModule gnutls_module modules/mod_gnutls.so … … 151 161 152 162 153 VI. CREATE OPENPGP CREDENTIALS FOR THE SERVER163 IX. CREATE OPENPGP CREDENTIALS FOR THE SERVER 154 164 155 165 mod_gnutls currently cannot read encrypted OpenPGP credentials. That is, -
configure.ac
r180e49f rae29683 1 1 dnl 2 AC_INIT(mod_gnutls, 0. 5.10)2 AC_INIT(mod_gnutls, 0.6) 3 3 OOO_CONFIG_NICE(config.nice) 4 4 MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION … … 20 20 AC_PROG_LIBTOOL 21 21 22 AC_CONFIG_MACRO_DIR([m4]) 23 22 24 AP_VERSION=2.0.40 23 25 CHECK_APACHE(,$AP_VERSION, … … 26 28 ) 27 29 28 dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`" 29 dnl AC_SUBST(LIBTOOL) 30 PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.12.6]) 30 31 31 dnl Depend on 2.10.0 due to safe renegotiation addition. 32 MIN_TLS_VERSION=2.10.0 33 AM_PATH_LIBGNUTLS($MIN_TLS_VERSION,, 34 AC_MSG_ERROR([[ 35 *** 36 *** libgnutls was not found. You may want to get it from 37 *** http://www.gnutls.org/ 38 *** 39 ]])) 32 LIBGNUTLS_VERSION=`pkg-config --modversion gnutls` 40 33 41 34 AC_ARG_ENABLE(srp, … … 48 41 SRP_CFLAGS="-DENABLE_SRP=1" 49 42 fi 43 50 44 AC_MSG_CHECKING([whether to enable SRP functionality]) 51 45 AC_MSG_RESULT($use_srp) 52 46 53 dnl CHECK_LUA() 47 AC_ARG_ENABLE(msva, 48 AS_HELP_STRING([--enable-msva], 49 [enable Monkeysphere client certificate verification]), 50 use_msva=$enableval, use_msva=no) 51 52 MSVA_CFLAGS="" 53 if test "$use_msva" != "no"; then 54 AC_CHECK_HEADERS([msv/msv.h], [], 55 [AC_MSG_ERROR([*** No libmsv headers found!])]) 56 AC_SEARCH_LIBS([msv_query_agent], [msv], [], 57 [AC_MSG_ERROR([*** No libmsv found with msv_query_agent!])]) 58 MSVA_CFLAGS="-DENABLE_MSVA=1" 59 fi 60 61 AC_MSG_CHECKING([whether to enable MSVA functionality]) 62 AC_MSG_RESULT($use_msva) 54 63 55 64 have_apr_memcache=0 … … 57 66 AC_SUBST(have_apr_memcache) 58 67 59 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${ APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"68 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${MSVA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}" 60 69 MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}" 61 70 … … 73 82 echo " * GnuTLS Library version: ${LIBGNUTLS_VERSION}" 74 83 echo " * SRP Authentication: ${use_srp}" 84 echo " * MSVA Client Verification: ${use_msva}" 75 85 echo "" 76 86 echo "---" -
include/mod_gnutls.h.in
r180e49f rae29683 16 16 */ 17 17 18 /* Apache Runtime Headers */ 18 19 #include "httpd.h" 19 20 #include "http_config.h" … … 27 28 #include "apr_tables.h" 28 29 #include "ap_release.h" 29 30 #include "apr_fnmatch.h" 31 /* GnuTLS Library Headers */ 30 32 #include <gnutls/gnutls.h> 33 #if GNUTLS_VERSION_MAJOR == 2 31 34 #include <gnutls/extra.h> 35 #endif 32 36 #include <gnutls/openpgp.h> 33 37 #include <gnutls/x509.h> … … 40 44 extern module AP_MODULE_DECLARE_DATA gnutls_module; 41 45 46 /* IO Filter names */ 42 47 #define GNUTLS_OUTPUT_FILTER_NAME "gnutls_output_filter" 43 48 #define GNUTLS_INPUT_FILTER_NAME "gnutls_input_filter" 44 49 /* GnuTLS Constants */ 45 50 #define GNUTLS_ENABLED_FALSE 0 46 51 #define GNUTLS_ENABLED_TRUE 1 47 52 #define GNUTLS_ENABLED_UNSET 2 53 /* Current module version */ 48 54 #define MOD_GNUTLS_VERSION "@MOD_GNUTLS_VERSION@" 49 55 56 /* Module Debug Mode */ 50 57 #define MOD_GNUTLS_DEBUG @OOO_MAINTAIN@ 51 58 52 /* Recent Versions of 2.1 renamed several hooks. This allows us to 53 compile on 2.0.xx */ 59 /* 60 * Recent Versions of 2.1 renamed several hooks. 61 * This allows us to compile on 2.0.xx 62 */ 54 63 #if AP_SERVER_MINORVERSION_NUMBER >= 2 || (AP_SERVER_MINORVERSION_NUMBER == 1 && AP_SERVER_PATCHLEVEL_NUMBER >= 3) 55 #define USING_2_1_RECENT 1 56 #endif 57 58 #ifndef USING_2_1_RECENT 59 #define USING_2_1_RECENT 0 64 #define USING_2_1_RECENT 1 65 #else 66 #define USING_2_1_RECENT 0 60 67 #endif 61 68 62 typedef enum 63 { 69 /* mod_gnutls Cache Types */ 70 typedef enum { 71 /* No Cache */ 64 72 mgs_cache_none, 73 /* Use Old Berkley DB */ 65 74 mgs_cache_dbm, 75 /* Use Gnu's version of Berkley DB */ 66 76 mgs_cache_gdbm, 67 77 #if HAVE_APR_MEMCACHE 68 mgs_cache_memcache 78 /* Use Memcache */ 79 mgs_cache_memcache, 69 80 #endif 81 mgs_cache_unset 70 82 } mgs_cache_e; 71 83 72 typedef struct 73 { 84 typedef enum { 85 mgs_cvm_unset, 86 mgs_cvm_cartel, 87 mgs_cvm_msva 88 } mgs_client_verification_method_e; 89 90 91 /* Directory Configuration Record */ 92 typedef struct { 74 93 int client_verify_mode; 75 94 const char* lua_bytecode; … … 78 97 79 98 80 /* The maximum number of certificates to send in a chain 81 */ 99 /* The maximum number of certificates to send in a chain */ 82 100 #define MAX_CHAIN_SIZE 8 83 84 typedef struct 85 { 101 /* The maximum number of SANs to read from a x509 certificate */ 102 #define MAX_CERT_SAN 5 103 104 /* Server Configuration Record */ 105 typedef struct { 106 /* x509 Certificate Structure */ 86 107 gnutls_certificate_credentials_t certs; 108 /* SRP Certificate Structure*/ 87 109 gnutls_srp_server_credentials_t srp_creds; 110 /* Annonymous Certificate Structure */ 88 111 gnutls_anon_server_credentials_t anon_creds; 112 /* Current x509 Certificate CN [Common Name] */ 89 113 char* cert_cn; 90 gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */ 91 unsigned int certs_x509_num; 114 /* Current x509 Certificate SAN [Subject Alternate Name]s*/ 115 char* cert_san[MAX_CERT_SAN]; 116 /* A x509 Certificate Chain */ 117 gnutls_x509_crt_t *certs_x509_chain; 118 /* Current x509 Certificate Private Key */ 92 119 gnutls_x509_privkey_t privkey_x509; 93 gnutls_openpgp_crt_t cert_pgp; /* A certificate chain */ 120 /* OpenPGP Certificate */ 121 gnutls_openpgp_crt_t cert_pgp; 122 /* OpenPGP Certificate Private Key */ 94 123 gnutls_openpgp_privkey_t privkey_pgp; 124 /* Number of Certificates in Chain */ 125 unsigned int certs_x509_chain_num; 126 /* Is the module enabled? */ 95 127 int enabled; 96 /* whether to send the PEM encoded certificates 97 * to CGIs 98 */ 128 /* Export full certificates to CGI environment: */ 99 129 int export_certificates_enabled; 130 /* GnuTLS Priorities */ 100 131 gnutls_priority_t priorities; 101 gnutls_rsa_params_t rsa_params; 132 /* GnuTLS DH Parameters */ 102 133 gnutls_dh_params_t dh_params; 134 /* Cache timeout value */ 103 135 int cache_timeout; 136 /* Chose Cache Type */ 104 137 mgs_cache_e cache_type; 105 138 const char* cache_config; 106 139 const char* srp_tpasswd_file; 107 140 const char* srp_tpasswd_conf_file; 141 /* A list of CA Certificates */ 108 142 gnutls_x509_crt_t *ca_list; 143 /* OpenPGP Key Ring */ 109 144 gnutls_openpgp_keyring_t pgp_list; 145 /* CA Certificate list size */ 110 146 unsigned int ca_list_size; 147 /* Client Certificate Verification Mode */ 111 148 int client_verify_mode; 149 /* Client Certificate Verification Method */ 150 mgs_client_verification_method_e client_verify_method; 151 /* Last Cache timestamp */ 112 152 apr_time_t last_cache_check; 113 int tickets; /* whether session tickets are allowed */ 153 /* GnuTLS uses Session Tickets */ 154 int tickets; 155 /* Is mod_proxy enabled? */ 156 int proxy_enabled; 157 /* A Plain HTTP request */ 158 int non_ssl_request; 114 159 } mgs_srvconf_rec; 115 160 161 /* Character Buffer */ 116 162 typedef struct { 117 163 int length; … … 119 165 } mgs_char_buffer_t; 120 166 121 typedef struct 122 { 167 /* GnuTLS Handle */ 168 typedef struct { 169 /* Server configuration record */ 123 170 mgs_srvconf_rec *sc; 171 /* Connection record */ 124 172 conn_rec* c; 173 /* GnuTLS Session handle */ 125 174 gnutls_session_t session; 126 175 /* module input status */ 127 176 apr_status_t input_rc; 177 /* Input filter */ 128 178 ap_filter_t *input_filter; 179 /* Input Bucket Brigade */ 129 180 apr_bucket_brigade *input_bb; 181 /* Input Read Type */ 130 182 apr_read_type_e input_block; 183 /* Input Mode */ 131 184 ap_input_mode_t input_mode; 185 /* Input Character Buffer */ 132 186 mgs_char_buffer_t input_cbuf; 187 /* Input Character Array */ 133 188 char input_buffer[AP_IOBUFSIZE]; 134 189 /* module Output status */ 135 190 apr_status_t output_rc; 191 /* Output filter */ 136 192 ap_filter_t *output_filter; 193 /* Output Bucket Brigade */ 137 194 apr_bucket_brigade *output_bb; 195 /* Output character array */ 138 196 char output_buffer[AP_IOBUFSIZE]; 197 /* Output buffer length */ 139 198 apr_size_t output_blen; 199 /* Output length */ 140 200 apr_size_t output_length; 141 201 /* General Status */ 142 202 int status; 143 int non_https;144 203 } mgs_handle_t; 145 204 205 206 146 207 /** Functions in gnutls_io.c **/ 147 208 148 /** 149 * write_flush will flush data 150 */ 151 static ssize_t write_flush(mgs_handle_t * ctxt); 209 /* apr_signal_block() for blocking SIGPIPE */ 210 apr_status_t apr_signal_block(int signum); 211 212 /* Proxy Support */ 213 /* An optional function which returns non-zero if the given connection 214 is using SSL/TLS. */ 215 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); 216 /* The ssl_proxy_enable() and ssl_engine_disable() optional functions 217 * are used by mod_proxy to enable use of SSL for outgoing 218 * connections. */ 219 APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); 220 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); 221 int ssl_is_https(conn_rec *c); 222 int ssl_proxy_enable(conn_rec *c); 223 int ssl_engine_disable(conn_rec *c); 224 const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy, 225 const char *arg); 226 apr_status_t mgs_cleanup_pre_config(void *data); 152 227 153 228 /** … … 180 255 181 256 /** 182 * mgs_transport_read is called from GnuTLS to provide encrypted 257 * mgs_transport_read is called from GnuTLS to provide encrypted 183 258 * data from the client. 184 259 * … … 192 267 193 268 /** 194 * mgs_transport_write is called from GnuTLS to 269 * mgs_transport_write is called from GnuTLS to 195 270 * write data to the client. 196 271 * … … 211 286 * Init the Cache after Configuration is done 212 287 */ 213 int mgs_cache_post_config(apr_pool_t *p, server_rec *s, 288 int mgs_cache_post_config(apr_pool_t *p, server_rec *s, 214 289 mgs_srvconf_rec *sc); 215 290 /** 216 291 * Init the Cache inside each Process 217 292 */ 218 int mgs_cache_child_init(apr_pool_t *p, server_rec *s, 293 int mgs_cache_child_init(apr_pool_t *p, server_rec *s, 219 294 mgs_srvconf_rec *sc); 220 295 /** … … 225 300 #define GNUTLS_SESSION_ID_STRING_LEN \ 226 301 ((GNUTLS_MAX_SESSION_ID + 1) * 2) 227 302 228 303 /** 229 304 * Convert a SSL Session ID into a Null Terminated Hex Encoded String … … 253 328 const char *mgs_set_dh_file(cmd_parms * parms, void *dummy, 254 329 const char *arg); 255 const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,256 const char *arg);257 330 const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 258 331 const char *arg); … … 275 348 const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, 276 349 const char *arg); 350 351 const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy, 352 const char *arg); 277 353 278 354 const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, … … 290 366 const char *mgs_set_tickets(cmd_parms * parms, void *dummy, 291 367 const char *arg); 292 293 const char *mgs_set_require_section(cmd_parms *cmd, 368 369 const char *mgs_set_require_section(cmd_parms *cmd, 294 370 void *mconfig, const char *arg); 295 371 void *mgs_config_server_create(apr_pool_t * p, server_rec * s); 372 void *mgs_config_server_merge(apr_pool_t *p, void *BASE, void *ADD); 296 373 297 374 void *mgs_config_dir_merge(apr_pool_t *p, void *basev, void *addv); … … 299 376 void *mgs_config_dir_create(apr_pool_t *p, char *dir); 300 377 301 const char *mgs_set_require_bytecode(cmd_parms *cmd, 378 const char *mgs_set_require_bytecode(cmd_parms *cmd, 302 379 void *mconfig, const char *arg); 303 380 … … 325 402 int mgs_hook_authz(request_rec *r); 326 403 327 int mgs_authz_lua(request_rec* r);328 329 404 #endif /* __mod_gnutls_h_inc */ -
src/Makefile.am
r180e49f rae29683 1 1 CLEANFILES = .libs/libmod_gnutls *~ 2 2 3 libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c 4 #gnutls_lua.c 5 libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} ${LUA_CFLAGS} 6 libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS} ${LUA_LIBS} 3 libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c 4 libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} 5 libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS} 7 6 8 7 lib_LTLIBRARIES = libmod_gnutls.la … … 11 10 @if test ! -L mod_gnutls.so ; then ln -s .libs/libmod_gnutls.so mod_gnutls.so ; fi 12 11 13 clean: 12 clean: 14 13 rm -f mod_gnutls.so 15 rm -f *.o *.lo *.la 14 rm -f *.o *.lo *.la 16 15 rm -fr .libs 17 16 … … 23 22 @echo "" 24 23 @echo " Please read the documentation at " 25 @echo " http:// www.outoforder.cc/for "24 @echo " http://modgnutls.sourceforge.net/?p=docs for " 26 25 @echo " details on configuration of this module " 27 26 @echo "" -
src/gnutls_cache.c
r180e49f rae29683 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Portions Copyright 2008 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 34 35 #endif 35 36 36 /* it seems the default has some strange errors. Use SDBM 37 /* it seems the default has some strange errors. Use SDBM 37 38 */ 38 39 #define MC_TAG "mod_gnutls:" … … 45 46 46 47 char *mgs_session_id2sz(unsigned char *id, int idlen, 47 char *str, int strsize) 48 { 49 char *cp; 50 int n; 51 52 cp = str; 53 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 54 apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]); 55 cp += 2; 56 } 57 *cp = '\0'; 58 return str; 59 } 60 48 char *str, int strsize) { 49 char *cp; 50 int n; 51 52 cp = str; 53 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 54 apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]); 55 cp += 2; 56 } 57 *cp = '\0'; 58 return str; 59 } 61 60 62 61 /* Name the Session ID as: … … 65 64 */ 66 65 static int mgs_session_id2dbm(conn_rec * c, unsigned char *id, int idlen, 67 apr_datum_t * dbmkey) 68 { 69 char buf[STR_SESSION_LEN]; 70 char *sz; 71 72 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf)); 73 if (sz == NULL) 74 return -1; 75 76 dbmkey->dptr = 77 apr_psprintf(c->pool, "%s:%d.%s", 78 c->base_server->server_hostname, 79 c->base_server->port, sz); 80 dbmkey->dsize = strlen(dbmkey->dptr); 81 82 return 0; 66 apr_datum_t * dbmkey) { 67 char buf[STR_SESSION_LEN]; 68 char *sz; 69 70 sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf)); 71 if (sz == NULL) 72 return -1; 73 74 dbmkey->dptr = 75 apr_psprintf(c->pool, "%s:%d.%s", 76 c->base_server->server_hostname, 77 c->base_server->port, sz); 78 dbmkey->dsize = strlen(dbmkey->dptr); 79 80 return 0; 83 81 } 84 82 85 83 #define CTIME "%b %d %k:%M:%S %Y %Z" 86 char *mgs_time2sz(time_t in_time, char *str, int strsize) 87 {88 89 90 91 92 93 94 95 96 97 84 85 char *mgs_time2sz(time_t in_time, char *str, int strsize) { 86 apr_time_exp_t vtm; 87 apr_size_t ret_size; 88 apr_time_t t; 89 90 91 apr_time_ansi_put(&t, in_time); 92 apr_time_exp_gmt(&vtm, t); 93 apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm); 94 95 return str; 98 96 } 99 97 100 98 #if HAVE_APR_MEMCACHE 99 101 100 /* Name the Session ID as: 102 101 * server:port.SessionID 103 102 * to disallow resuming sessions on different servers 104 103 */ 105 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) 106 { 107 char buf[STR_SESSION_LEN]; 108 char *sz; 109 110 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf)); 111 if (sz == NULL) 112 return NULL; 113 114 return apr_psprintf(c->pool, MC_TAG "%s:%d.%s", 115 c->base_server->server_hostname, 116 c->base_server->port, sz); 104 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) { 105 char buf[STR_SESSION_LEN]; 106 char *sz; 107 108 sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf)); 109 if (sz == NULL) 110 return NULL; 111 112 return apr_psprintf(c->pool, MC_TAG "%s:%d.%s", 113 c->base_server->server_hostname, 114 c->base_server->port, sz); 117 115 } 118 116 … … 126 124 127 125 static int mc_cache_child_init(apr_pool_t * p, server_rec * s, 128 mgs_srvconf_rec * sc) 129 { 130 apr_status_t rv = APR_SUCCESS; 131 int thread_limit = 0; 132 int nservers = 0; 133 char *cache_config; 134 char *split; 135 char *tok; 136 137 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); 138 139 /* Find all the servers in the first run to get a total count */ 140 cache_config = apr_pstrdup(p, sc->cache_config); 141 split = apr_strtok(cache_config, " ", &tok); 142 while (split) { 143 nservers++; 144 split = apr_strtok(NULL, " ", &tok); 145 } 146 147 rv = apr_memcache_create(p, nservers, 0, &mc); 148 if (rv != APR_SUCCESS) { 149 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 150 "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 151 nservers); 152 return rv; 153 } 154 155 /* Now add each server to the memcache */ 156 cache_config = apr_pstrdup(p, sc->cache_config); 157 split = apr_strtok(cache_config, " ", &tok); 158 while (split) { 159 apr_memcache_server_t *st; 160 char *host_str; 161 char *scope_id; 162 apr_port_t port; 163 164 rv = apr_parse_addr_port(&host_str, &scope_id, &port, 165 split, p); 166 if (rv != APR_SUCCESS) { 167 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 168 "[gnutls_cache] Failed to Parse Server: '%s'", 169 split); 170 return rv; 171 } 172 173 if (host_str == NULL) { 174 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 175 "[gnutls_cache] Failed to Parse Server, " 176 "no hostname specified: '%s'", split); 177 return rv; 178 } 179 180 if (port == 0) { 181 port = 11211; /* default port */ 182 } 183 184 /* Should Max Conns be (thread_limit / nservers) ? */ 185 rv = apr_memcache_server_create(p, 186 host_str, port, 187 0, 188 1, thread_limit, 600, &st); 189 if (rv != APR_SUCCESS) { 190 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 191 "[gnutls_cache] Failed to Create Server: %s:%d", 192 host_str, port); 193 return rv; 194 } 195 196 rv = apr_memcache_add_server(mc, st); 197 if (rv != APR_SUCCESS) { 198 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 199 "[gnutls_cache] Failed to Add Server: %s:%d", 200 host_str, port); 201 return rv; 202 } 203 204 split = apr_strtok(NULL, " ", &tok); 205 } 206 return rv; 126 mgs_srvconf_rec * sc) { 127 apr_status_t rv = APR_SUCCESS; 128 int thread_limit = 0; 129 int nservers = 0; 130 char *cache_config; 131 char *split; 132 char *tok; 133 134 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); 135 136 /* Find all the servers in the first run to get a total count */ 137 cache_config = apr_pstrdup(p, sc->cache_config); 138 split = apr_strtok(cache_config, " ", &tok); 139 while (split) { 140 nservers++; 141 split = apr_strtok(NULL, " ", &tok); 142 } 143 144 rv = apr_memcache_create(p, nservers, 0, &mc); 145 if (rv != APR_SUCCESS) { 146 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 147 "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 148 nservers); 149 return rv; 150 } 151 152 /* Now add each server to the memcache */ 153 cache_config = apr_pstrdup(p, sc->cache_config); 154 split = apr_strtok(cache_config, " ", &tok); 155 while (split) { 156 apr_memcache_server_t *st; 157 char *host_str; 158 char *scope_id; 159 apr_port_t port; 160 161 rv = apr_parse_addr_port(&host_str, &scope_id, &port, 162 split, p); 163 if (rv != APR_SUCCESS) { 164 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 165 "[gnutls_cache] Failed to Parse Server: '%s'", 166 split); 167 return rv; 168 } 169 170 if (host_str == NULL) { 171 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 172 "[gnutls_cache] Failed to Parse Server, " 173 "no hostname specified: '%s'", split); 174 return rv; 175 } 176 177 if (port == 0) { 178 port = 11211; /* default port */ 179 } 180 181 /* Should Max Conns be (thread_limit / nservers) ? */ 182 rv = apr_memcache_server_create(p, 183 host_str, port, 184 0, 185 1, thread_limit, 600, &st); 186 if (rv != APR_SUCCESS) { 187 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 188 "[gnutls_cache] Failed to Create Server: %s:%d", 189 host_str, port); 190 return rv; 191 } 192 193 rv = apr_memcache_add_server(mc, st); 194 if (rv != APR_SUCCESS) { 195 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 196 "[gnutls_cache] Failed to Add Server: %s:%d", 197 host_str, port); 198 return rv; 199 } 200 201 split = apr_strtok(NULL, " ", &tok); 202 } 203 return rv; 207 204 } 208 205 209 206 static int mc_cache_store(void *baton, gnutls_datum_t key, 210 gnutls_datum_t data) 211 { 212 apr_status_t rv = APR_SUCCESS; 213 mgs_handle_t *ctxt = baton; 214 char *strkey = NULL; 215 apr_uint32_t timeout; 216 217 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 218 if (!strkey) 219 return -1; 220 221 timeout = apr_time_sec(ctxt->sc->cache_timeout); 222 223 rv = apr_memcache_set(mc, strkey, data.data, data.size, timeout, 224 0); 225 226 if (rv != APR_SUCCESS) { 227 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, 228 ctxt->c->base_server, 229 "[gnutls_cache] error setting key '%s' " 230 "with %d bytes of data", strkey, data.size); 231 return -1; 232 } 233 234 return 0; 235 } 236 237 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) 238 { 239 apr_status_t rv = APR_SUCCESS; 240 mgs_handle_t *ctxt = baton; 241 char *strkey = NULL; 242 char *value; 243 apr_size_t value_len; 244 gnutls_datum_t data = { NULL, 0 }; 245 246 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 247 if (!strkey) { 248 return data; 249 } 250 251 rv = apr_memcache_getp(mc, ctxt->c->pool, strkey, 252 &value, &value_len, NULL); 253 254 if (rv != APR_SUCCESS) { 207 gnutls_datum_t data) { 208 apr_status_t rv = APR_SUCCESS; 209 mgs_handle_t *ctxt = baton; 210 char *strkey = NULL; 211 apr_uint32_t timeout; 212 213 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 214 if (!strkey) 215 return -1; 216 217 timeout = apr_time_sec(ctxt->sc->cache_timeout); 218 219 rv = apr_memcache_set(mc, strkey, (char *) data.data, data.size, timeout, 220 0); 221 222 if (rv != APR_SUCCESS) { 223 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, 224 ctxt->c->base_server, 225 "[gnutls_cache] error setting key '%s' " 226 "with %d bytes of data", strkey, data.size); 227 return -1; 228 } 229 230 return 0; 231 } 232 233 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) { 234 apr_status_t rv = APR_SUCCESS; 235 mgs_handle_t *ctxt = baton; 236 char *strkey = NULL; 237 char *value; 238 apr_size_t value_len; 239 gnutls_datum_t data = {NULL, 0}; 240 241 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 242 if (!strkey) { 243 return data; 244 } 245 246 rv = apr_memcache_getp(mc, ctxt->c->pool, strkey, 247 &value, &value_len, NULL); 248 249 if (rv != APR_SUCCESS) { 255 250 #if MOD_GNUTLS_DEBUG 256 257 258 259 251 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 252 ctxt->c->base_server, 253 "[gnutls_cache] error fetching key '%s' ", 254 strkey); 260 255 #endif 261 data.size = 0; 262 data.data = NULL; 263 return data; 264 } 265 266 /* TODO: Eliminate this memcpy. gnutls-- */ 267 data.data = gnutls_malloc(value_len); 268 if (data.data == NULL) 269 return data; 270 271 data.size = value_len; 272 memcpy(data.data, value, value_len); 273 274 return data; 275 } 276 277 static int mc_cache_delete(void *baton, gnutls_datum_t key) 278 { 279 apr_status_t rv = APR_SUCCESS; 280 mgs_handle_t *ctxt = baton; 281 char *strkey = NULL; 282 283 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 284 if (!strkey) 285 return -1; 286 287 rv = apr_memcache_delete(mc, strkey, 0); 288 289 if (rv != APR_SUCCESS) { 290 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 291 ctxt->c->base_server, 292 "[gnutls_cache] error deleting key '%s' ", 293 strkey); 294 return -1; 295 } 296 297 return 0; 298 } 299 300 #endif /* have_apr_memcache */ 301 302 const char *db_type(mgs_srvconf_rec * sc) 303 { 304 if (sc->cache_type == mgs_cache_gdbm) 305 return "gdbm"; 306 else 307 return "db"; 256 data.size = 0; 257 data.data = NULL; 258 return data; 259 } 260 261 /* TODO: Eliminate this memcpy. gnutls-- */ 262 data.data = gnutls_malloc(value_len); 263 if (data.data == NULL) 264 return data; 265 266 data.size = value_len; 267 memcpy(data.data, value, value_len); 268 269 return data; 270 } 271 272 static int mc_cache_delete(void *baton, gnutls_datum_t key) { 273 apr_status_t rv = APR_SUCCESS; 274 mgs_handle_t *ctxt = baton; 275 char *strkey = NULL; 276 277 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 278 if (!strkey) 279 return -1; 280 281 rv = apr_memcache_delete(mc, strkey, 0); 282 283 if (rv != APR_SUCCESS) { 284 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 285 ctxt->c->base_server, 286 "[gnutls_cache] error deleting key '%s' ", 287 strkey); 288 return -1; 289 } 290 291 return 0; 292 } 293 294 #endif /* have_apr_memcache */ 295 296 static const char *db_type(mgs_srvconf_rec * sc) { 297 if (sc->cache_type == mgs_cache_gdbm) 298 return "gdbm"; 299 else 300 return "db"; 308 301 } 309 302 310 303 #define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) 311 304 312 static void dbm_cache_expire(mgs_handle_t * ctxt) 313 { 314 apr_status_t rv; 315 apr_dbm_t *dbm; 316 apr_datum_t dbmkey; 317 apr_datum_t dbmval; 318 apr_time_t now; 319 apr_time_t dtime; 320 apr_pool_t *spool; 321 int total, deleted; 322 323 now = apr_time_now(); 324 325 if (now - ctxt->sc->last_cache_check < 326 (ctxt->sc->cache_timeout) / 2) 327 return; 328 329 ctxt->sc->last_cache_check = now; 330 331 apr_pool_create(&spool, ctxt->c->pool); 332 333 total = 0; 334 deleted = 0; 335 336 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 337 ctxt->sc->cache_config, APR_DBM_RWCREATE, 338 SSL_DBM_FILE_MODE, spool); 339 if (rv != APR_SUCCESS) { 340 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 341 ctxt->c->base_server, 342 "[gnutls_cache] error opening cache searcher '%s'", 343 ctxt->sc->cache_config); 344 apr_pool_destroy(spool); 345 return; 346 } 347 348 apr_dbm_firstkey(dbm, &dbmkey); 349 while (dbmkey.dptr != NULL) { 350 apr_dbm_fetch(dbm, dbmkey, &dbmval); 351 if (dbmval.dptr != NULL 352 && dbmval.dsize >= sizeof(apr_time_t)) { 353 memcpy(&dtime, dbmval.dptr, sizeof(apr_time_t)); 354 355 if (now >= dtime) { 356 apr_dbm_delete(dbm, dbmkey); 357 deleted++; 358 } 359 apr_dbm_freedatum(dbm, dbmval); 360 } else { 361 apr_dbm_delete(dbm, dbmkey); 362 deleted++; 363 } 364 total++; 365 apr_dbm_nextkey(dbm, &dbmkey); 366 } 367 apr_dbm_close(dbm); 368 369 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 370 ctxt->c->base_server, 371 "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d", 372 ctxt->sc->cache_config, deleted, total - deleted); 373 374 apr_pool_destroy(spool); 375 376 return; 377 } 378 379 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) 380 { 381 gnutls_datum_t data = { NULL, 0 }; 382 apr_dbm_t *dbm; 383 apr_datum_t dbmkey; 384 apr_datum_t dbmval; 385 mgs_handle_t *ctxt = baton; 386 apr_status_t rv; 387 388 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 389 return data; 390 391 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 392 ctxt->sc->cache_config, APR_DBM_READONLY, 393 SSL_DBM_FILE_MODE, ctxt->c->pool); 394 if (rv != APR_SUCCESS) { 395 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 396 ctxt->c->base_server, 397 "[gnutls_cache] error opening cache '%s'", 398 ctxt->sc->cache_config); 399 return data; 400 } 401 402 rv = apr_dbm_fetch(dbm, dbmkey, &dbmval); 403 404 if (rv != APR_SUCCESS) { 405 apr_dbm_close(dbm); 406 return data; 407 } 408 409 if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) { 410 apr_dbm_freedatum(dbm, dbmval); 411 apr_dbm_close(dbm); 412 return data; 413 } 414 415 data.size = dbmval.dsize - sizeof(apr_time_t); 416 417 data.data = gnutls_malloc(data.size); 418 if (data.data == NULL) { 419 apr_dbm_freedatum(dbm, dbmval); 420 apr_dbm_close(dbm); 421 return data; 422 } 423 424 memcpy(data.data, dbmval.dptr + sizeof(apr_time_t), data.size); 425 426 apr_dbm_freedatum(dbm, dbmval); 427 apr_dbm_close(dbm); 428 429 return data; 305 static void dbm_cache_expire(mgs_handle_t * ctxt) { 306 apr_status_t rv; 307 apr_dbm_t *dbm; 308 apr_datum_t dbmkey; 309 apr_datum_t dbmval; 310 apr_time_t now; 311 apr_time_t dtime; 312 apr_pool_t *spool; 313 int total, deleted; 314 315 now = apr_time_now(); 316 317 if (now - ctxt->sc->last_cache_check < 318 (ctxt->sc->cache_timeout) / 2) 319 return; 320 321 ctxt->sc->last_cache_check = now; 322 323 apr_pool_create(&spool, ctxt->c->pool); 324 325 total = 0; 326 deleted = 0; 327 328 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 329 ctxt->sc->cache_config, APR_DBM_RWCREATE, 330 SSL_DBM_FILE_MODE, spool); 331 if (rv != APR_SUCCESS) { 332 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 333 ctxt->c->base_server, 334 "[gnutls_cache] error opening cache searcher '%s'", 335 ctxt->sc->cache_config); 336 apr_pool_destroy(spool); 337 return; 338 } 339 340 apr_dbm_firstkey(dbm, &dbmkey); 341 while (dbmkey.dptr != NULL) { 342 apr_dbm_fetch(dbm, dbmkey, &dbmval); 343 if (dbmval.dptr != NULL 344 && dbmval.dsize >= sizeof (apr_time_t)) { 345 memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t)); 346 347 if (now >= dtime) { 348 apr_dbm_delete(dbm, dbmkey); 349 deleted++; 350 } 351 apr_dbm_freedatum(dbm, dbmval); 352 } else { 353 apr_dbm_delete(dbm, dbmkey); 354 deleted++; 355 } 356 total++; 357 apr_dbm_nextkey(dbm, &dbmkey); 358 } 359 apr_dbm_close(dbm); 360 361 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 362 ctxt->c->base_server, 363 "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d", 364 ctxt->sc->cache_config, deleted, total - deleted); 365 366 apr_pool_destroy(spool); 367 368 return; 369 } 370 371 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) { 372 gnutls_datum_t data = {NULL, 0}; 373 apr_dbm_t *dbm; 374 apr_datum_t dbmkey; 375 apr_datum_t dbmval; 376 mgs_handle_t *ctxt = baton; 377 apr_status_t rv; 378 379 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 380 return data; 381 382 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 383 ctxt->sc->cache_config, APR_DBM_READONLY, 384 SSL_DBM_FILE_MODE, ctxt->c->pool); 385 if (rv != APR_SUCCESS) { 386 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 387 ctxt->c->base_server, 388 "[gnutls_cache] error opening cache '%s'", 389 ctxt->sc->cache_config); 390 return data; 391 } 392 393 rv = apr_dbm_fetch(dbm, dbmkey, &dbmval); 394 395 if (rv != APR_SUCCESS) { 396 apr_dbm_close(dbm); 397 return data; 398 } 399 400 if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t)) { 401 apr_dbm_freedatum(dbm, dbmval); 402 apr_dbm_close(dbm); 403 return data; 404 } 405 406 data.size = dbmval.dsize - sizeof (apr_time_t); 407 408 data.data = gnutls_malloc(data.size); 409 if (data.data == NULL) { 410 apr_dbm_freedatum(dbm, dbmval); 411 apr_dbm_close(dbm); 412 return data; 413 } 414 415 memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size); 416 417 apr_dbm_freedatum(dbm, dbmval); 418 apr_dbm_close(dbm); 419 420 return data; 430 421 } 431 422 432 423 static int dbm_cache_store(void *baton, gnutls_datum_t key, 433 gnutls_datum_t data) 434 { 435 apr_dbm_t *dbm; 436 apr_datum_t dbmkey; 437 apr_datum_t dbmval; 438 mgs_handle_t *ctxt = baton; 439 apr_status_t rv; 440 apr_time_t expiry; 441 apr_pool_t *spool; 442 443 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 444 return -1; 445 446 /* we expire dbm only on every store 447 */ 448 dbm_cache_expire(ctxt); 449 450 apr_pool_create(&spool, ctxt->c->pool); 451 452 /* create DBM value */ 453 dbmval.dsize = data.size + sizeof(apr_time_t); 454 dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize); 455 456 expiry = apr_time_now() + ctxt->sc->cache_timeout; 457 458 memcpy((char *) dbmval.dptr, &expiry, sizeof(apr_time_t)); 459 memcpy((char *) dbmval.dptr + sizeof(apr_time_t), 460 data.data, data.size); 461 462 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 463 ctxt->sc->cache_config, APR_DBM_RWCREATE, 464 SSL_DBM_FILE_MODE, ctxt->c->pool); 465 if (rv != APR_SUCCESS) { 466 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 467 ctxt->c->base_server, 468 "[gnutls_cache] error opening cache '%s'", 469 ctxt->sc->cache_config); 470 apr_pool_destroy(spool); 471 return -1; 472 } 473 474 rv = apr_dbm_store(dbm, dbmkey, dbmval); 475 476 if (rv != APR_SUCCESS) { 477 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 478 ctxt->c->base_server, 479 "[gnutls_cache] error storing in cache '%s'", 480 ctxt->sc->cache_config); 481 apr_dbm_close(dbm); 482 apr_pool_destroy(spool); 483 return -1; 484 } 485 486 apr_dbm_close(dbm); 487 488 apr_pool_destroy(spool); 489 490 return 0; 491 } 492 493 static int dbm_cache_delete(void *baton, gnutls_datum_t key) 494 { 495 apr_dbm_t *dbm; 496 apr_datum_t dbmkey; 497 mgs_handle_t *ctxt = baton; 498 apr_status_t rv; 499 500 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 501 return -1; 502 503 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 504 ctxt->sc->cache_config, APR_DBM_RWCREATE, 505 SSL_DBM_FILE_MODE, ctxt->c->pool); 506 if (rv != APR_SUCCESS) { 507 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 508 ctxt->c->base_server, 509 "[gnutls_cache] error opening cache '%s'", 510 ctxt->sc->cache_config); 511 return -1; 512 } 513 514 rv = apr_dbm_delete(dbm, dbmkey); 515 516 if (rv != APR_SUCCESS) { 517 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 518 ctxt->c->base_server, 519 "[gnutls_cache] error deleting from cache '%s'", 520 ctxt->sc->cache_config); 521 apr_dbm_close(dbm); 522 return -1; 523 } 524 525 apr_dbm_close(dbm); 526 527 return 0; 424 gnutls_datum_t data) { 425 apr_dbm_t *dbm; 426 apr_datum_t dbmkey; 427 apr_datum_t dbmval; 428 mgs_handle_t *ctxt = baton; 429 apr_status_t rv; 430 apr_time_t expiry; 431 apr_pool_t *spool; 432 433 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 434 return -1; 435 436 /* we expire dbm only on every store 437 */ 438 dbm_cache_expire(ctxt); 439 440 apr_pool_create(&spool, ctxt->c->pool); 441 442 /* create DBM value */ 443 dbmval.dsize = data.size + sizeof (apr_time_t); 444 dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize); 445 446 expiry = apr_time_now() + ctxt->sc->cache_timeout; 447 448 memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t)); 449 memcpy((char *) dbmval.dptr + sizeof (apr_time_t), 450 data.data, data.size); 451 452 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 453 ctxt->sc->cache_config, APR_DBM_RWCREATE, 454 SSL_DBM_FILE_MODE, ctxt->c->pool); 455 if (rv != APR_SUCCESS) { 456 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 457 ctxt->c->base_server, 458 "[gnutls_cache] error opening cache '%s'", 459 ctxt->sc->cache_config); 460 apr_pool_destroy(spool); 461 return -1; 462 } 463 464 rv = apr_dbm_store(dbm, dbmkey, dbmval); 465 466 if (rv != APR_SUCCESS) { 467 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 468 ctxt->c->base_server, 469 "[gnutls_cache] error storing in cache '%s'", 470 ctxt->sc->cache_config); 471 apr_dbm_close(dbm); 472 apr_pool_destroy(spool); 473 return -1; 474 } 475 476 apr_dbm_close(dbm); 477 478 apr_pool_destroy(spool); 479 480 return 0; 481 } 482 483 static int dbm_cache_delete(void *baton, gnutls_datum_t key) { 484 apr_dbm_t *dbm; 485 apr_datum_t dbmkey; 486 mgs_handle_t *ctxt = baton; 487 apr_status_t rv; 488 489 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 490 return -1; 491 492 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 493 ctxt->sc->cache_config, APR_DBM_RWCREATE, 494 SSL_DBM_FILE_MODE, ctxt->c->pool); 495 if (rv != APR_SUCCESS) { 496 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 497 ctxt->c->base_server, 498 "[gnutls_cache] error opening cache '%s'", 499 ctxt->sc->cache_config); 500 return -1; 501 } 502 503 rv = apr_dbm_delete(dbm, dbmkey); 504 505 if (rv != APR_SUCCESS) { 506 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 507 ctxt->c->base_server, 508 "[gnutls_cache] error deleting from cache '%s'", 509 ctxt->sc->cache_config); 510 apr_dbm_close(dbm); 511 return -1; 512 } 513 514 apr_dbm_close(dbm); 515 516 return 0; 528 517 } 529 518 530 519 static int dbm_cache_post_config(apr_pool_t * p, server_rec * s, 531 mgs_srvconf_rec * sc) 532 { 533 apr_status_t rv; 534 apr_dbm_t *dbm; 535 const char *path1; 536 const char *path2; 537 538 rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config, 539 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p); 540 541 if (rv != APR_SUCCESS) { 542 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, 543 "GnuTLS: Cannot create DBM Cache at `%s'", 544 sc->cache_config); 545 return rv; 546 } 547 548 apr_dbm_close(dbm); 549 550 apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1, 551 &path2); 552 553 /* The Following Code takes logic directly from mod_ssl's DBM Cache */ 520 mgs_srvconf_rec * sc) { 521 apr_status_t rv; 522 apr_dbm_t *dbm; 523 const char *path1; 524 const char *path2; 525 526 rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config, 527 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p); 528 529 if (rv != APR_SUCCESS) { 530 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, 531 "GnuTLS: Cannot create DBM Cache at `%s'", 532 sc->cache_config); 533 return rv; 534 } 535 536 apr_dbm_close(dbm); 537 538 apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1, 539 &path2); 540 541 /* The Following Code takes logic directly from mod_ssl's DBM Cache */ 554 542 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) 555 /* Running as Root */ 556 if (path1 && geteuid() == 0) { 557 chown(path1, ap_unixd_config.user_id, -1); 558 if (path2 != NULL) { 559 chown(path2, ap_unixd_config.user_id, -1); 560 } 561 } 543 /* Running as Root */ 544 if (path1 && geteuid() == 0) { 545 if (0 != chown(path1, ap_unixd_config.user_id, -1)) 546 ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s, 547 "GnuTLS: could not chown cache path1 `%s' to uid %d (errno: %d)", 548 path1, ap_unixd_config.user_id, errno); 549 if (path2 != NULL) { 550 if (0 != chown(path2, ap_unixd_config.user_id, -1)) 551 ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s, 552 "GnuTLS: could not chown cache path2 `%s' to uid %d (errno: %d)", 553 path2, ap_unixd_config.user_id, errno); 554 } 555 } 562 556 #endif 563 557 564 558 return rv; 565 559 } 566 560 567 561 int mgs_cache_post_config(apr_pool_t * p, server_rec * s, 568 mgs_srvconf_rec * sc) 569 { 570 if (sc->cache_type == mgs_cache_dbm 571 || sc->cache_type == mgs_cache_gdbm) { 572 return dbm_cache_post_config(p, s, sc); 573 } 574 return 0; 562 mgs_srvconf_rec * sc) { 563 564 /* if GnuTLSCache was never explicitly set: */ 565 if (sc->cache_type == mgs_cache_unset) 566 sc->cache_type = mgs_cache_none; 567 /* if GnuTLSCacheTimeout was never explicitly set: */ 568 if (sc->cache_timeout == -1) 569 sc->cache_timeout = apr_time_from_sec(300); 570 571 if (sc->cache_type == mgs_cache_dbm 572 || sc->cache_type == mgs_cache_gdbm) { 573 return dbm_cache_post_config(p, s, sc); 574 } 575 return 0; 575 576 } 576 577 577 578 int mgs_cache_child_init(apr_pool_t * p, server_rec * s, 578 mgs_srvconf_rec * sc) 579 { 580 if (sc->cache_type == mgs_cache_dbm 581 || sc->cache_type == mgs_cache_gdbm) { 582 return 0; 583 } 579 mgs_srvconf_rec * sc) { 580 if (sc->cache_type == mgs_cache_dbm 581 || sc->cache_type == mgs_cache_gdbm) { 582 return 0; 583 } 584 584 #if HAVE_APR_MEMCACHE 585 586 587 585 else if (sc->cache_type == mgs_cache_memcache) { 586 return mc_cache_child_init(p, s, sc); 587 } 588 588 #endif 589 589 return 0; 590 590 } 591 591 592 592 #include <assert.h> 593 593 594 int mgs_cache_session_init(mgs_handle_t * ctxt) 595 { 596 if (ctxt->sc->cache_type == mgs_cache_dbm 597 || ctxt->sc->cache_type == mgs_cache_gdbm) { 598 gnutls_db_set_retrieve_function(ctxt->session, 599 dbm_cache_fetch); 600 gnutls_db_set_remove_function(ctxt->session, 601 dbm_cache_delete); 602 gnutls_db_set_store_function(ctxt->session, 603 dbm_cache_store); 604 gnutls_db_set_ptr(ctxt->session, ctxt); 605 } 594 int mgs_cache_session_init(mgs_handle_t * ctxt) { 595 if (ctxt->sc->cache_type == mgs_cache_dbm 596 || ctxt->sc->cache_type == mgs_cache_gdbm) { 597 gnutls_db_set_retrieve_function(ctxt->session, 598 dbm_cache_fetch); 599 gnutls_db_set_remove_function(ctxt->session, 600 dbm_cache_delete); 601 gnutls_db_set_store_function(ctxt->session, 602 dbm_cache_store); 603 gnutls_db_set_ptr(ctxt->session, ctxt); 604 } 606 605 #if HAVE_APR_MEMCACHE 607 608 609 610 611 612 613 614 615 606 else if (ctxt->sc->cache_type == mgs_cache_memcache) { 607 gnutls_db_set_retrieve_function(ctxt->session, 608 mc_cache_fetch); 609 gnutls_db_set_remove_function(ctxt->session, 610 mc_cache_delete); 611 gnutls_db_set_store_function(ctxt->session, 612 mc_cache_store); 613 gnutls_db_set_ptr(ctxt->session, ctxt); 614 } 616 615 #endif 617 616 618 619 } 617 return 0; 618 } -
src/gnutls_config.c
r180e49f rae29683 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Copyright 2007 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 20 21 21 22 static int load_datum_from_file(apr_pool_t * pool, 22 const char *file, gnutls_datum_t * data) 23 { 24 apr_file_t *fp; 25 apr_finfo_t finfo; 26 apr_status_t rv; 27 apr_size_t br = 0; 28 29 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, 30 APR_OS_DEFAULT, pool); 31 if (rv != APR_SUCCESS) { 32 return rv; 23 const char *file, gnutls_datum_t * data) { 24 apr_file_t *fp; 25 apr_finfo_t finfo; 26 apr_status_t rv; 27 apr_size_t br = 0; 28 29 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, 30 APR_OS_DEFAULT, pool); 31 if (rv != APR_SUCCESS) { 32 return rv; 33 } 34 35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 36 37 if (rv != APR_SUCCESS) { 38 return rv; 39 } 40 41 data->data = apr_palloc(pool, finfo.size + 1); 42 rv = apr_file_read_full(fp, data->data, finfo.size, &br); 43 44 if (rv != APR_SUCCESS) { 45 return rv; 46 } 47 apr_file_close(fp); 48 49 data->data[br] = '\0'; 50 data->size = br; 51 52 return 0; 53 } 54 55 const char *mgs_set_dh_file(cmd_parms * parms, void *dummy, 56 const char *arg) { 57 int ret; 58 gnutls_datum_t data; 59 const char *file; 60 apr_pool_t *spool; 61 mgs_srvconf_rec *sc = 62 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 63 module_config, 64 &gnutls_module); 65 66 apr_pool_create(&spool, parms->pool); 67 68 file = ap_server_root_relative(spool, arg); 69 70 if (load_datum_from_file(spool, file, &data) != 0) { 71 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 72 "DH params '%s'", file); 73 } 74 75 ret = gnutls_dh_params_init(&sc->dh_params); 76 if (ret < 0) { 77 return apr_psprintf(parms->pool, 78 "GnuTLS: Failed to initialize" 79 ": (%d) %s", ret, 80 gnutls_strerror(ret)); 81 } 82 83 ret = 84 gnutls_dh_params_import_pkcs3(sc->dh_params, &data, 85 GNUTLS_X509_FMT_PEM); 86 if (ret < 0) { 87 return apr_psprintf(parms->pool, 88 "GnuTLS: Failed to Import " 89 "DH params '%s': (%d) %s", file, ret, 90 gnutls_strerror(ret)); 91 } 92 93 apr_pool_destroy(spool); 94 95 return NULL; 96 } 97 98 const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, const char *arg) { 99 100 int ret; 101 gnutls_datum_t data; 102 const char *file; 103 apr_pool_t *spool; 104 105 mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module); 106 apr_pool_create(&spool, parms->pool); 107 108 file = ap_server_root_relative(spool, arg); 109 110 if (load_datum_from_file(spool, file, &data) != 0) { 111 apr_pool_destroy(spool); 112 return apr_psprintf(parms->pool, "GnuTLS: Error Reading Certificate '%s'", file); 113 } 114 115 sc->certs_x509_chain_num = MAX_CHAIN_SIZE; 116 ret = gnutls_x509_crt_list_import(sc->certs_x509_chain, &sc->certs_x509_chain_num, &data, GNUTLS_X509_FMT_PEM, 0); 117 if (ret < 0) { 118 apr_pool_destroy(spool); 119 return apr_psprintf(parms->pool, "GnuTLS: Failed to Import Certificate '%s': (%d) %s", file, ret, gnutls_strerror(ret)); 120 } 121 122 apr_pool_destroy(spool); 123 return NULL; 124 125 } 126 127 const char *mgs_set_key_file(cmd_parms * parms, void *dummy, const char *arg) { 128 129 int ret; 130 gnutls_datum_t data; 131 const char *file; 132 apr_pool_t *spool; 133 const char *out; 134 135 mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module); 136 137 apr_pool_create(&spool, parms->pool); 138 139 file = ap_server_root_relative(spool, arg); 140 141 if (load_datum_from_file(spool, file, &data) != 0) { 142 out = apr_psprintf(parms->pool, "GnuTLS: Error Reading Private Key '%s'", file); 143 apr_pool_destroy(spool); 144 return out; 145 } 146 147 ret = gnutls_x509_privkey_init(&sc->privkey_x509); 148 149 if (ret < 0) { 150 apr_pool_destroy(spool); 151 return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize: (%d) %s", ret, gnutls_strerror(ret)); 152 } 153 154 ret = gnutls_x509_privkey_import(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM); 155 156 if (ret < 0) { 157 ret = gnutls_x509_privkey_import_pkcs8(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM, NULL, GNUTLS_PKCS_PLAIN); 33 158 } 34 159 35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 36 37 if (rv != APR_SUCCESS) { 38 return rv; 39 } 40 41 data->data = apr_palloc(pool, finfo.size + 1); 42 rv = apr_file_read_full(fp, data->data, finfo.size, &br); 43 44 if (rv != APR_SUCCESS) { 45 return rv; 46 } 47 apr_file_close(fp); 48 49 data->data[br] = '\0'; 50 data->size = br; 51 52 return 0; 53 } 54 55 const char *mgs_set_dh_file(cmd_parms * parms, void *dummy, 56 const char *arg) 57 { 160 if (ret < 0) { 161 out = apr_psprintf(parms->pool, "GnuTLS: Failed to Import Private Key '%s': (%d) %s", file, ret, gnutls_strerror(ret)); 162 apr_pool_destroy(spool); 163 return out; 164 } 165 166 apr_pool_destroy(spool); 167 168 return NULL; 169 } 170 171 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy, 172 const char *arg) { 173 int ret; 174 gnutls_datum_t data; 175 const char *file; 176 apr_pool_t *spool; 177 mgs_srvconf_rec *sc = 178 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 179 module_config, 180 &gnutls_module); 181 apr_pool_create(&spool, parms->pool); 182 183 file = ap_server_root_relative(spool, arg); 184 185 if (load_datum_from_file(spool, file, &data) != 0) { 186 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 187 "Certificate '%s'", file); 188 } 189 190 ret = gnutls_openpgp_crt_init(&sc->cert_pgp); 191 if (ret < 0) { 192 return apr_psprintf(parms->pool, "GnuTLS: Failed to Init " 193 "PGP Certificate: (%d) %s", ret, 194 gnutls_strerror(ret)); 195 } 196 197 ret = 198 gnutls_openpgp_crt_import(sc->cert_pgp, &data, 199 GNUTLS_OPENPGP_FMT_BASE64); 200 if (ret < 0) { 201 return apr_psprintf(parms->pool, 202 "GnuTLS: Failed to Import " 203 "PGP Certificate '%s': (%d) %s", file, 204 ret, gnutls_strerror(ret)); 205 } 206 207 apr_pool_destroy(spool); 208 return NULL; 209 } 210 211 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy, 212 const char *arg) { 213 int ret; 214 gnutls_datum_t data; 215 const char *file; 216 apr_pool_t *spool; 217 mgs_srvconf_rec *sc = 218 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 219 module_config, 220 &gnutls_module); 221 apr_pool_create(&spool, parms->pool); 222 223 file = ap_server_root_relative(spool, arg); 224 225 if (load_datum_from_file(spool, file, &data) != 0) { 226 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 227 "Private Key '%s'", file); 228 } 229 230 ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp); 231 if (ret < 0) { 232 return apr_psprintf(parms->pool, 233 "GnuTLS: Failed to initialize" 234 ": (%d) %s", ret, 235 gnutls_strerror(ret)); 236 } 237 238 ret = 239 gnutls_openpgp_privkey_import(sc->privkey_pgp, &data, 240 GNUTLS_OPENPGP_FMT_BASE64, NULL, 241 0); 242 if (ret != 0) { 243 return apr_psprintf(parms->pool, 244 "GnuTLS: Failed to Import " 245 "PGP Private Key '%s': (%d) %s", file, 246 ret, gnutls_strerror(ret)); 247 } 248 apr_pool_destroy(spool); 249 return NULL; 250 } 251 252 const char *mgs_set_tickets(cmd_parms * parms, void *dummy, 253 const char *arg) { 254 mgs_srvconf_rec *sc = 255 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 256 module_config, 257 &gnutls_module); 258 259 sc->tickets = 0; 260 if (strcasecmp("on", arg) == 0) { 261 sc->tickets = 1; 262 } 263 264 return NULL; 265 } 266 267 268 #ifdef ENABLE_SRP 269 270 const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy, 271 const char *arg) { 272 mgs_srvconf_rec *sc = 273 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 274 module_config, 275 &gnutls_module); 276 277 sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg); 278 279 return NULL; 280 } 281 282 const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy, 283 const char *arg) { 284 mgs_srvconf_rec *sc = 285 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 286 module_config, 287 &gnutls_module); 288 289 sc->srp_tpasswd_conf_file = 290 ap_server_root_relative(parms->pool, arg); 291 292 return NULL; 293 } 294 295 #endif 296 297 const char *mgs_set_cache(cmd_parms * parms, void *dummy, 298 const char *type, const char *arg) { 299 const char *err; 300 mgs_srvconf_rec *sc = 301 ap_get_module_config(parms->server->module_config, 302 &gnutls_module); 303 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 304 return err; 305 } 306 307 if (strcasecmp("none", type) == 0) { 308 sc->cache_type = mgs_cache_none; 309 sc->cache_config = NULL; 310 return NULL; 311 } else if (strcasecmp("dbm", type) == 0) { 312 sc->cache_type = mgs_cache_dbm; 313 } else if (strcasecmp("gdbm", type) == 0) { 314 sc->cache_type = mgs_cache_gdbm; 315 } 316 #if HAVE_APR_MEMCACHE 317 else if (strcasecmp("memcache", type) == 0) { 318 sc->cache_type = mgs_cache_memcache; 319 } 320 #endif 321 else { 322 return "Invalid Type for GnuTLSCache!"; 323 } 324 325 if (arg == NULL) 326 return "Invalid argument 2 for GnuTLSCache!"; 327 328 if (sc->cache_type == mgs_cache_dbm 329 || sc->cache_type == mgs_cache_gdbm) { 330 sc->cache_config = 331 ap_server_root_relative(parms->pool, arg); 332 } else { 333 sc->cache_config = apr_pstrdup(parms->pool, arg); 334 } 335 336 return NULL; 337 } 338 339 const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy, 340 const char *arg) { 341 int argint; 342 const char *err; 343 mgs_srvconf_rec *sc = 344 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 345 module_config, 346 &gnutls_module); 347 348 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 349 return err; 350 } 351 352 argint = atoi(arg); 353 354 if (argint < 0) { 355 return "GnuTLSCacheTimeout: Invalid argument"; 356 } else if (argint == 0) { 357 sc->cache_timeout = 0; 358 } else { 359 sc->cache_timeout = apr_time_from_sec(argint); 360 } 361 362 return NULL; 363 } 364 365 const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy, 366 const char *arg) { 367 mgs_srvconf_rec *sc = (mgs_srvconf_rec *)ap_get_module_config(parms->server->module_config, &gnutls_module); 368 369 if (strcasecmp("cartel", arg) == 0) { 370 sc->client_verify_method = mgs_cvm_cartel; 371 } else if (strcasecmp("msva", arg) == 0) { 372 #ifdef ENABLE_MSVA 373 sc->client_verify_method = mgs_cvm_msva; 374 #else 375 return "GnuTLSClientVerifyMethod: msva is not supported"; 376 #endif 377 } else { 378 return "GnuTLSClientVerifyMethod: Invalid argument"; 379 } 380 381 return NULL; 382 } 383 384 const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, 385 const char *arg) { 386 int mode; 387 388 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { 389 mode = GNUTLS_CERT_IGNORE; 390 } else if (strcasecmp("optional", arg) == 0 391 || strcasecmp("request", arg) == 0) { 392 mode = GNUTLS_CERT_REQUEST; 393 } else if (strcasecmp("require", arg) == 0) { 394 mode = GNUTLS_CERT_REQUIRE; 395 } else { 396 return "GnuTLSClientVerify: Invalid argument"; 397 } 398 399 /* This was set from a directory context */ 400 if (parms->path) { 401 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy; 402 dc->client_verify_mode = mode; 403 } else { 404 mgs_srvconf_rec *sc = 405 (mgs_srvconf_rec *) 406 ap_get_module_config(parms->server->module_config, 407 &gnutls_module); 408 sc->client_verify_mode = mode; 409 } 410 411 return NULL; 412 } 413 414 #define INIT_CA_SIZE 128 415 416 const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 417 const char *arg) { 418 int rv; 419 const char *file; 420 apr_pool_t *spool; 421 gnutls_datum_t data; 422 423 mgs_srvconf_rec *sc = 424 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 425 module_config, 426 &gnutls_module); 427 apr_pool_create(&spool, parms->pool); 428 429 file = ap_server_root_relative(spool, arg); 430 431 if (load_datum_from_file(spool, file, &data) != 0) { 432 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 433 "Client CA File '%s'", file); 434 } 435 436 sc->ca_list_size = INIT_CA_SIZE; 437 sc->ca_list = malloc(sc->ca_list_size * sizeof (*sc->ca_list)); 438 if (sc->ca_list == NULL) { 439 return apr_psprintf(parms->pool, 440 "mod_gnutls: Memory allocation error"); 441 } 442 443 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size, 444 &data, GNUTLS_X509_FMT_PEM, 445 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); 446 if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) { 447 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 448 "Client CA File '%s': (%d) %s", file, 449 rv, gnutls_strerror(rv)); 450 } 451 452 if (INIT_CA_SIZE < sc->ca_list_size) { 453 sc->ca_list = 454 realloc(sc->ca_list, 455 sc->ca_list_size * sizeof (*sc->ca_list)); 456 if (sc->ca_list == NULL) { 457 return apr_psprintf(parms->pool, 458 "mod_gnutls: Memory allocation error"); 459 } 460 461 /* re-read */ 462 rv = gnutls_x509_crt_list_import(sc->ca_list, 463 &sc->ca_list_size, &data, 464 GNUTLS_X509_FMT_PEM, 0); 465 466 if (rv < 0) { 467 return apr_psprintf(parms->pool, 468 "GnuTLS: Failed to load " 469 "Client CA File '%s': (%d) %s", 470 file, rv, gnutls_strerror(rv)); 471 } 472 } 473 474 apr_pool_destroy(spool); 475 return NULL; 476 } 477 478 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy, 479 const char *arg) { 480 int rv; 481 const char *file; 482 apr_pool_t *spool; 483 gnutls_datum_t data; 484 485 mgs_srvconf_rec *sc = 486 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 487 module_config, 488 &gnutls_module); 489 apr_pool_create(&spool, parms->pool); 490 491 file = ap_server_root_relative(spool, arg); 492 493 if (load_datum_from_file(spool, file, &data) != 0) { 494 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 495 "Keyring File '%s'", file); 496 } 497 498 rv = gnutls_openpgp_keyring_init(&sc->pgp_list); 499 if (rv < 0) { 500 return apr_psprintf(parms->pool, 501 "GnuTLS: Failed to initialize" 502 "keyring: (%d) %s", rv, 503 gnutls_strerror(rv)); 504 } 505 506 rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, 507 GNUTLS_OPENPGP_FMT_BASE64); 508 if (rv < 0) { 509 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 510 "Keyring File '%s': (%d) %s", file, rv, 511 gnutls_strerror(rv)); 512 } 513 514 apr_pool_destroy(spool); 515 return NULL; 516 } 517 518 const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy, 519 const char *arg) { 520 521 mgs_srvconf_rec *sc =(mgs_srvconf_rec *) 522 ap_get_module_config(parms->server->module_config, &gnutls_module); 523 524 if (!strcasecmp(arg, "On")) { 525 sc->proxy_enabled = GNUTLS_ENABLED_TRUE; 526 } else if (!strcasecmp(arg, "Off")) { 527 sc->proxy_enabled = GNUTLS_ENABLED_FALSE; 528 } else { 529 return "SSLProxyEngine must be set to 'On' or 'Off'"; 530 } 531 532 return NULL; 533 } 534 535 const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 536 const char *arg) { 537 mgs_srvconf_rec *sc = 538 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 539 module_config, 540 &gnutls_module); 541 if (!strcasecmp(arg, "On")) { 542 sc->enabled = GNUTLS_ENABLED_TRUE; 543 } else if (!strcasecmp(arg, "Off")) { 544 sc->enabled = GNUTLS_ENABLED_FALSE; 545 } else { 546 return "GnuTLSEnable must be set to 'On' or 'Off'"; 547 } 548 549 return NULL; 550 } 551 552 const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy, const char *arg) { 553 mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module); 554 if (!strcasecmp(arg, "On")) { 555 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE; 556 } else if (!strcasecmp(arg, "Off")) { 557 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE; 558 } else { 559 return 560 "GnuTLSExportCertificates must be set to 'On' or 'Off'"; 561 } 562 563 return NULL; 564 } 565 566 const char *mgs_set_priorities(cmd_parms * parms, void *dummy, const char *arg) { 567 58 568 int ret; 59 gnutls_datum_t data; 60 const char *file; 61 apr_pool_t *spool; 62 mgs_srvconf_rec *sc = 63 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 64 module_config, 65 &gnutls_module); 66 67 apr_pool_create(&spool, parms->pool); 68 69 file = ap_server_root_relative(spool, arg); 70 71 if (load_datum_from_file(spool, file, &data) != 0) { 72 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 73 "DH params '%s'", file); 74 } 75 76 ret = gnutls_dh_params_init(&sc->dh_params); 77 if (ret < 0) { 78 return apr_psprintf(parms->pool, 79 "GnuTLS: Failed to initialize" 80 ": (%d) %s", ret, 81 gnutls_strerror(ret)); 82 } 83 84 ret = 85 gnutls_dh_params_import_pkcs3(sc->dh_params, &data, 86 GNUTLS_X509_FMT_PEM); 87 if (ret < 0) { 88 return apr_psprintf(parms->pool, 89 "GnuTLS: Failed to Import " 90 "DH params '%s': (%d) %s", file, ret, 91 gnutls_strerror(ret)); 92 } 93 94 apr_pool_destroy(spool); 95 96 return NULL; 97 } 98 99 const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy, 100 const char *arg) 101 { 102 int ret; 103 gnutls_datum_t data; 104 const char *file; 105 apr_pool_t *spool; 106 mgs_srvconf_rec *sc = 107 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 108 module_config, 109 &gnutls_module); 110 111 apr_pool_create(&spool, parms->pool); 112 113 file = ap_server_root_relative(spool, arg); 114 115 if (load_datum_from_file(spool, file, &data) != 0) { 116 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 117 "RSA params '%s'", file); 118 } 119 120 ret = gnutls_rsa_params_init(&sc->rsa_params); 121 if (ret < 0) { 122 return apr_psprintf(parms->pool, 123 "GnuTLS: Failed to initialize" 124 ": (%d) %s", ret, 125 gnutls_strerror(ret)); 126 } 127 128 ret = 129 gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data, 130 GNUTLS_X509_FMT_PEM); 131 if (ret != 0) { 132 return apr_psprintf(parms->pool, 133 "GnuTLS: Failed to Import " 134 "RSA params '%s': (%d) %s", file, ret, 135 gnutls_strerror(ret)); 136 } 137 138 apr_pool_destroy(spool); 139 return NULL; 140 } 141 142 143 const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 144 const char *arg) 145 { 146 int ret; 147 gnutls_datum_t data; 148 const char *file; 149 apr_pool_t *spool; 150 mgs_srvconf_rec *sc = 151 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 152 module_config, 153 &gnutls_module); 154 apr_pool_create(&spool, parms->pool); 155 156 file = ap_server_root_relative(spool, arg); 157 158 if (load_datum_from_file(spool, file, &data) != 0) { 159 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 160 "Certificate '%s'", file); 161 } 162 163 sc->certs_x509_num = MAX_CHAIN_SIZE; 164 ret = 165 gnutls_x509_crt_list_import(sc->certs_x509, 166 &sc->certs_x509_num, &data, 167 GNUTLS_X509_FMT_PEM, 0); 168 if (ret < 0) { 169 return apr_psprintf(parms->pool, 170 "GnuTLS: Failed to Import " 171 "Certificate '%s': (%d) %s", file, ret, 172 gnutls_strerror(ret)); 173 } 174 175 apr_pool_destroy(spool); 176 return NULL; 177 } 178 179 const char *mgs_set_key_file(cmd_parms * parms, void *dummy, 180 const char *arg) 181 { 182 int ret; 183 gnutls_datum_t data; 184 const char *file; 185 apr_pool_t *spool; 186 mgs_srvconf_rec *sc = 187 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 188 module_config, 189 &gnutls_module); 190 apr_pool_create(&spool, parms->pool); 191 192 file = ap_server_root_relative(spool, arg); 193 194 if (load_datum_from_file(spool, file, &data) != 0) { 195 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 196 "Private Key '%s'", file); 197 } 198 199 ret = gnutls_x509_privkey_init(&sc->privkey_x509); 200 if (ret < 0) { 201 return apr_psprintf(parms->pool, 202 "GnuTLS: Failed to initialize" 203 ": (%d) %s", ret, 204 gnutls_strerror(ret)); 205 } 206 207 ret = 208 gnutls_x509_privkey_import(sc->privkey_x509, &data, 209 GNUTLS_X509_FMT_PEM); 210 211 if (ret < 0) 212 ret = 213 gnutls_x509_privkey_import_pkcs8(sc->privkey_x509, 214 &data, 215 GNUTLS_X509_FMT_PEM, 216 NULL, 217 GNUTLS_PKCS_PLAIN); 218 219 if (ret < 0) { 220 return apr_psprintf(parms->pool, 221 "GnuTLS: Failed to Import " 222 "Private Key '%s': (%d) %s", file, ret, 223 gnutls_strerror(ret)); 224 } 225 apr_pool_destroy(spool); 226 return NULL; 227 } 228 229 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy, 230 const char *arg) 231 { 232 int ret; 233 gnutls_datum_t data; 234 const char *file; 235 apr_pool_t *spool; 236 mgs_srvconf_rec *sc = 237 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 238 module_config, 239 &gnutls_module); 240 apr_pool_create(&spool, parms->pool); 241 242 file = ap_server_root_relative(spool, arg); 243 244 if (load_datum_from_file(spool, file, &data) != 0) { 245 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 246 "Certificate '%s'", file); 247 } 248 249 ret = gnutls_openpgp_crt_init(&sc->cert_pgp); 250 if (ret < 0) { 251 return apr_psprintf(parms->pool, "GnuTLS: Failed to Init " 252 "PGP Certificate: (%d) %s", ret, 253 gnutls_strerror(ret)); 254 } 255 256 ret = 257 gnutls_openpgp_crt_import(sc->cert_pgp, &data, 258 GNUTLS_OPENPGP_FMT_BASE64); 259 if (ret < 0) { 260 return apr_psprintf(parms->pool, 261 "GnuTLS: Failed to Import " 262 "PGP Certificate '%s': (%d) %s", file, 263 ret, gnutls_strerror(ret)); 264 } 265 266 apr_pool_destroy(spool); 267 return NULL; 268 } 269 270 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy, 271 const char *arg) 272 { 273 int ret; 274 gnutls_datum_t data; 275 const char *file; 276 apr_pool_t *spool; 277 mgs_srvconf_rec *sc = 278 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 279 module_config, 280 &gnutls_module); 281 apr_pool_create(&spool, parms->pool); 282 283 file = ap_server_root_relative(spool, arg); 284 285 if (load_datum_from_file(spool, file, &data) != 0) { 286 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 287 "Private Key '%s'", file); 288 } 289 290 ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp); 291 if (ret < 0) { 292 return apr_psprintf(parms->pool, 293 "GnuTLS: Failed to initialize" 294 ": (%d) %s", ret, 295 gnutls_strerror(ret)); 296 } 297 298 ret = 299 gnutls_openpgp_privkey_import(sc->privkey_pgp, &data, 300 GNUTLS_OPENPGP_FMT_BASE64, NULL, 301 0); 302 if (ret != 0) { 303 return apr_psprintf(parms->pool, 304 "GnuTLS: Failed to Import " 305 "PGP Private Key '%s': (%d) %s", file, 306 ret, gnutls_strerror(ret)); 307 } 308 apr_pool_destroy(spool); 309 return NULL; 310 } 311 312 const char *mgs_set_tickets(cmd_parms * parms, void *dummy, 313 const char *arg) 314 { 315 mgs_srvconf_rec *sc = 316 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 317 module_config, 318 &gnutls_module); 319 320 sc->tickets = 0; 321 if (strcasecmp("on", arg) == 0) { 322 sc->tickets = 1; 323 } 324 325 return NULL; 326 } 327 328 569 const char *err; 570 571 mgs_srvconf_rec *sc = (mgs_srvconf_rec *) 572 ap_get_module_config(parms->server->module_config, &gnutls_module); 573 574 ret = gnutls_priority_init(&sc->priorities, arg, &err); 575 576 if (ret < 0) { 577 if (ret == GNUTLS_E_INVALID_REQUEST) { 578 return apr_psprintf(parms->pool, 579 "GnuTLS: Syntax error parsing priorities string at: %s", err); 580 } 581 return "Error setting priorities"; 582 } 583 584 return NULL; 585 } 586 587 static mgs_srvconf_rec *_mgs_config_server_create(apr_pool_t * p, char** err) { 588 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof (*sc)); 589 int ret; 590 591 sc->enabled = GNUTLS_ENABLED_UNSET; 592 593 ret = gnutls_certificate_allocate_credentials(&sc->certs); 594 if (ret < 0) { 595 *err = apr_psprintf(p, "GnuTLS: Failed to initialize" 596 ": (%d) %s", ret, 597 gnutls_strerror(ret)); 598 return NULL; 599 } 600 601 ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds); 602 if (ret < 0) { 603 *err = apr_psprintf(p, "GnuTLS: Failed to initialize" 604 ": (%d) %s", ret, 605 gnutls_strerror(ret)); 606 return NULL; 607 } 329 608 #ifdef ENABLE_SRP 330 331 const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy, 332 const char *arg) 333 { 334 mgs_srvconf_rec *sc = 335 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 336 module_config, 337 &gnutls_module); 338 339 sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg); 340 341 return NULL; 342 } 343 344 const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy, 345 const char *arg) 346 { 347 mgs_srvconf_rec *sc = 348 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 349 module_config, 350 &gnutls_module); 351 352 sc->srp_tpasswd_conf_file = 353 ap_server_root_relative(parms->pool, arg); 354 355 return NULL; 356 } 357 609 ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds); 610 if (ret < 0) { 611 *err = apr_psprintf(p, "GnuTLS: Failed to initialize" 612 ": (%d) %s", ret, 613 gnutls_strerror(ret)); 614 return NULL; 615 } 616 617 sc->srp_tpasswd_conf_file = NULL; 618 sc->srp_tpasswd_file = NULL; 358 619 #endif 359 620 360 const char *mgs_set_cache(cmd_parms * parms, void *dummy, 361 const char *type, const char *arg) 362 { 363 const char *err; 364 mgs_srvconf_rec *sc = 365 ap_get_module_config(parms->server->module_config, 366 &gnutls_module); 367 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 368 return err; 369 } 370 371 if (strcasecmp("none", type) == 0) { 372 sc->cache_type = mgs_cache_none; 373 sc->cache_config = NULL; 374 return NULL; 375 } else if (strcasecmp("dbm", type) == 0) { 376 sc->cache_type = mgs_cache_dbm; 377 } else if (strcasecmp("gdbm", type) == 0) { 378 sc->cache_type = mgs_cache_gdbm; 379 } 380 #if HAVE_APR_MEMCACHE 381 else if (strcasecmp("memcache", type) == 0) { 382 sc->cache_type = mgs_cache_memcache; 383 } 384 #endif 385 else { 386 return "Invalid Type for GnuTLSCache!"; 387 } 388 389 if (arg == NULL) 390 return "Invalid argument 2 for GnuTLSCache!"; 391 392 if (sc->cache_type == mgs_cache_dbm 393 || sc->cache_type == mgs_cache_gdbm) { 394 sc->cache_config = 395 ap_server_root_relative(parms->pool, arg); 396 } else { 397 sc->cache_config = apr_pstrdup(parms->pool, arg); 398 } 399 400 return NULL; 401 } 402 403 const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy, 404 const char *arg) 405 { 406 int argint; 407 mgs_srvconf_rec *sc = 408 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 409 module_config, 410 &gnutls_module); 411 412 argint = atoi(arg); 413 414 if (argint < 0) { 415 return "GnuTLSCacheTimeout: Invalid argument"; 416 } else if (argint == 0) { 417 sc->cache_timeout = 0; 418 } else { 419 sc->cache_timeout = apr_time_from_sec(argint); 420 } 421 422 return NULL; 423 } 424 425 const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, 426 const char *arg) 427 { 428 int mode; 429 430 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { 431 mode = GNUTLS_CERT_IGNORE; 432 } else if (strcasecmp("optional", arg) == 0 433 || strcasecmp("request", arg) == 0) { 434 mode = GNUTLS_CERT_REQUEST; 435 } else if (strcasecmp("require", arg) == 0) { 436 mode = GNUTLS_CERT_REQUIRE; 437 } else { 438 return "GnuTLSClientVerify: Invalid argument"; 439 } 440 441 /* This was set from a directory context */ 442 if (parms->path) { 443 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy; 444 dc->client_verify_mode = mode; 445 } else { 446 mgs_srvconf_rec *sc = 447 (mgs_srvconf_rec *) 448 ap_get_module_config(parms->server->module_config, 449 &gnutls_module); 450 sc->client_verify_mode = mode; 451 } 452 453 return NULL; 454 } 455 456 #define INIT_CA_SIZE 128 457 const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 458 const char *arg) 459 { 460 int rv; 461 const char *file; 462 apr_pool_t *spool; 463 gnutls_datum_t data; 464 465 mgs_srvconf_rec *sc = 466 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 467 module_config, 468 &gnutls_module); 469 apr_pool_create(&spool, parms->pool); 470 471 file = ap_server_root_relative(spool, arg); 472 473 if (load_datum_from_file(spool, file, &data) != 0) { 474 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 475 "Client CA File '%s'", file); 476 } 477 478 sc->ca_list_size = INIT_CA_SIZE; 479 sc->ca_list = malloc(sc->ca_list_size * sizeof(*sc->ca_list)); 480 if (sc->ca_list == NULL) { 481 return apr_psprintf(parms->pool, 482 "mod_gnutls: Memory allocation error"); 483 } 484 485 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size, 486 &data, GNUTLS_X509_FMT_PEM, 487 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); 488 if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) { 489 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 490 "Client CA File '%s': (%d) %s", file, 491 rv, gnutls_strerror(rv)); 492 } 493 494 if (INIT_CA_SIZE < sc->ca_list_size) { 495 sc->ca_list = 496 realloc(sc->ca_list, 497 sc->ca_list_size * sizeof(*sc->ca_list)); 498 if (sc->ca_list == NULL) { 499 return apr_psprintf(parms->pool, 500 "mod_gnutls: Memory allocation error"); 501 } 502 503 /* re-read */ 504 rv = gnutls_x509_crt_list_import(sc->ca_list, 505 &sc->ca_list_size, &data, 506 GNUTLS_X509_FMT_PEM, 0); 507 508 if (rv < 0) { 509 return apr_psprintf(parms->pool, 510 "GnuTLS: Failed to load " 511 "Client CA File '%s': (%d) %s", 512 file, rv, gnutls_strerror(rv)); 513 } 514 } 515 516 apr_pool_destroy(spool); 517 return NULL; 518 } 519 520 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy, 521 const char *arg) 522 { 523 int rv; 524 const char *file; 525 apr_pool_t *spool; 526 gnutls_datum_t data; 527 528 mgs_srvconf_rec *sc = 529 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 530 module_config, 531 &gnutls_module); 532 apr_pool_create(&spool, parms->pool); 533 534 file = ap_server_root_relative(spool, arg); 535 536 if (load_datum_from_file(spool, file, &data) != 0) { 537 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 538 "Keyring File '%s'", file); 539 } 540 541 rv = gnutls_openpgp_keyring_init(&sc->pgp_list); 542 if (rv < 0) { 543 return apr_psprintf(parms->pool, 544 "GnuTLS: Failed to initialize" 545 "keyring: (%d) %s", rv, 546 gnutls_strerror(rv)); 547 } 548 549 rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, 550 GNUTLS_OPENPGP_FMT_BASE64); 551 if (rv < 0) { 552 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 553 "Keyring File '%s': (%d) %s", file, rv, 554 gnutls_strerror(rv)); 555 } 556 557 apr_pool_destroy(spool); 558 return NULL; 559 } 560 561 const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 562 const char *arg) 563 { 564 mgs_srvconf_rec *sc = 565 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 566 module_config, 567 &gnutls_module); 568 if (!strcasecmp(arg, "On")) { 569 sc->enabled = GNUTLS_ENABLED_TRUE; 570 } else if (!strcasecmp(arg, "Off")) { 571 sc->enabled = GNUTLS_ENABLED_FALSE; 572 } else { 573 return "GnuTLSEnable must be set to 'On' or 'Off'"; 574 } 575 576 return NULL; 577 } 578 579 const char *mgs_set_export_certificates_enabled(cmd_parms * parms, 580 void *dummy, 581 const char *arg) 582 { 583 mgs_srvconf_rec *sc = 584 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 585 module_config, 586 &gnutls_module); 587 if (!strcasecmp(arg, "On")) { 588 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE; 589 } else if (!strcasecmp(arg, "Off")) { 590 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE; 591 } else { 592 return 593 "GnuTLSExportCertificates must be set to 'On' or 'Off'"; 594 } 595 596 return NULL; 597 } 598 599 600 const char *mgs_set_priorities(cmd_parms * parms, void *dummy, 601 const char *arg) 602 { 603 int ret; 604 const char *err; 605 mgs_srvconf_rec *sc = 606 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 607 module_config, 608 &gnutls_module); 609 610 611 ret = gnutls_priority_init(&sc->priorities, arg, &err); 612 if (ret < 0) { 613 if (ret == GNUTLS_E_INVALID_REQUEST) 614 return apr_psprintf(parms->pool, 615 "GnuTLS: Syntax error parsing priorities string at: %s", 616 err); 617 return "Error setting priorities"; 618 } 619 620 return NULL; 621 } 622 623 void *mgs_config_server_create(apr_pool_t * p, server_rec * s) 624 { 625 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc)); 626 int ret; 627 628 sc->enabled = GNUTLS_ENABLED_FALSE; 629 630 ret = gnutls_certificate_allocate_credentials(&sc->certs); 631 if (ret < 0) { 632 return apr_psprintf(p, "GnuTLS: Failed to initialize" 633 ": (%d) %s", ret, 634 gnutls_strerror(ret)); 635 } 636 637 ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds); 638 if (ret < 0) { 639 return apr_psprintf(p, "GnuTLS: Failed to initialize" 640 ": (%d) %s", ret, 641 gnutls_strerror(ret)); 642 } 643 #ifdef ENABLE_SRP 644 ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds); 645 if (ret < 0) { 646 return apr_psprintf(p, "GnuTLS: Failed to initialize" 647 ": (%d) %s", ret, 648 gnutls_strerror(ret)); 649 } 650 651 sc->srp_tpasswd_conf_file = NULL; 652 sc->srp_tpasswd_file = NULL; 653 #endif 654 655 sc->privkey_x509 = NULL; 656 memset(sc->certs_x509, 0, sizeof(sc->certs_x509)); 657 sc->certs_x509_num = 0; 658 sc->cache_timeout = apr_time_from_sec(300); 659 sc->cache_type = mgs_cache_none; 660 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 661 sc->tickets = 1; /* by default enable session tickets */ 662 663 sc->client_verify_mode = GNUTLS_CERT_IGNORE; 664 665 return sc; 666 } 667 668 void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv) 669 { 670 mgs_dirconf_rec *new; 671 /* mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */ 672 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv; 673 674 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec)); 675 new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode, 676 add->lua_bytecode_len); 677 new->lua_bytecode_len = add->lua_bytecode_len; 678 new->client_verify_mode = add->client_verify_mode; 679 return new; 680 } 681 682 void *mgs_config_dir_create(apr_pool_t * p, char *dir) 683 { 684 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc)); 685 686 dc->client_verify_mode = -1; 687 dc->lua_bytecode = NULL; 688 dc->lua_bytecode_len = 0; 689 return dc; 690 } 621 sc->privkey_x509 = NULL; 622 /* Initialize all Certificate Chains */ 623 /* FIXME: how do we indicate that this is unset for a merge? (that 624 * is, how can a subordinate server override the chain by setting 625 * an empty one? what would that even look like in the 626 * configuration?) */ 627 sc->certs_x509_chain = malloc(MAX_CHAIN_SIZE * sizeof (*sc->certs_x509_chain)); 628 sc->certs_x509_chain_num = 0; 629 sc->cache_timeout = -1; /* -1 means "unset" */ 630 sc->cache_type = mgs_cache_unset; 631 sc->cache_config = NULL; 632 sc->tickets = GNUTLS_ENABLED_UNSET; 633 sc->priorities = NULL; 634 sc->dh_params = NULL; 635 sc->proxy_enabled = GNUTLS_ENABLED_UNSET; 636 sc->export_certificates_enabled = GNUTLS_ENABLED_UNSET; 637 sc->client_verify_method = mgs_cvm_unset; 638 639 /* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */ 640 sc->client_verify_mode = -1; 641 642 return sc; 643 } 644 645 void *mgs_config_server_create(apr_pool_t * p, server_rec * s) { 646 char *err = NULL; 647 mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err); 648 if (sc) return sc; else return err; 649 } 650 651 #define gnutls_srvconf_merge(t, unset) sc->t = (add->t == unset) ? base->t : add->t 652 #define gnutls_srvconf_assign(t) sc->t = add->t 653 654 void *mgs_config_server_merge(apr_pool_t *p, void *BASE, void *ADD) { 655 int i; 656 char *err = NULL; 657 mgs_srvconf_rec *base = (mgs_srvconf_rec *)BASE; 658 mgs_srvconf_rec *add = (mgs_srvconf_rec *)ADD; 659 mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err); 660 if (NULL == sc) return err; 661 662 gnutls_srvconf_merge(enabled, GNUTLS_ENABLED_UNSET); 663 gnutls_srvconf_merge(tickets, GNUTLS_ENABLED_UNSET); 664 gnutls_srvconf_merge(proxy_enabled, GNUTLS_ENABLED_UNSET); 665 gnutls_srvconf_merge(export_certificates_enabled, GNUTLS_ENABLED_UNSET); 666 gnutls_srvconf_merge(client_verify_method, mgs_cvm_unset); 667 gnutls_srvconf_merge(client_verify_mode, -1); 668 gnutls_srvconf_merge(srp_tpasswd_file, NULL); 669 gnutls_srvconf_merge(srp_tpasswd_conf_file, NULL); 670 gnutls_srvconf_merge(privkey_x509, NULL); 671 gnutls_srvconf_merge(priorities, NULL); 672 gnutls_srvconf_merge(dh_params, NULL); 673 674 /* FIXME: the following items are pre-allocated, and should be 675 * properly disposed of before assigning in order to avoid leaks; 676 * so at the moment, we can't actually have them in the config. 677 * what happens during de-allocation? 678 679 * This is probably leaky. 680 */ 681 gnutls_srvconf_assign(certs); 682 gnutls_srvconf_assign(anon_creds); 683 gnutls_srvconf_assign(srp_creds); 684 gnutls_srvconf_assign(certs_x509_chain); 685 gnutls_srvconf_assign(certs_x509_chain_num); 686 687 /* how do these get transferred cleanly before the data from ADD 688 * goes away? */ 689 gnutls_srvconf_assign(cert_cn); 690 for (i = 0; i < MAX_CERT_SAN; i++) 691 gnutls_srvconf_assign(cert_san[i]); 692 gnutls_srvconf_assign(ca_list); 693 gnutls_srvconf_assign(ca_list_size); 694 gnutls_srvconf_assign(cert_pgp); 695 gnutls_srvconf_assign(pgp_list); 696 gnutls_srvconf_assign(privkey_pgp); 697 698 return sc; 699 } 700 701 #undef gnutls_srvconf_merge 702 #undef gnutls_srvconf_assign 703 704 void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv) { 705 mgs_dirconf_rec *new; 706 /* mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */ 707 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv; 708 709 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof (mgs_dirconf_rec)); 710 new->client_verify_mode = add->client_verify_mode; 711 return new; 712 } 713 714 void *mgs_config_dir_create(apr_pool_t * p, char *dir) { 715 mgs_dirconf_rec *dc = apr_palloc(p, sizeof (*dc)); 716 dc->client_verify_mode = -1; 717 return dc; 718 } 719 -
src/gnutls_hooks.c
r180e49f rae29683 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Copyright 2007 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 20 21 #include "http_vhost.h" 21 22 #include "ap_mpm.h" 22 23 #if APR_HAS_THREADS 24 # if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11 25 #include <gcrypt.h> 26 GCRY_THREAD_OPTION_PTHREAD_IMPL; 27 # endif 23 #include "mod_status.h" 24 25 #ifdef ENABLE_MSVA 26 #include <msv/msv.h> 28 27 #endif 29 28 … … 36 35 #endif 37 36 38 static int mpm_is_threaded; 39 static gnutls_datum session_ticket_key = { NULL, 0 }; 37 static gnutls_datum_t session_ticket_key = {NULL, 0}; 40 38 41 39 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); 42 40 /* use side==0 for server and side==1 for client */ 43 static void mgs_add_common_cert_vars(request_rec * r, 44 gnutls_x509_crt_t cert, int side, 45 int export_certificates_enabled);46 static void mgs_add_common_pgpcert_vars(request_rec * r,47 gnutls_openpgp_crt_t cert, 48 int side, 49 int export_certificates_enabled); 50 51 static apr_status_t mgs_cleanup_pre_config(void *data) 52 { 53 gnutls_free(session_ticket_key.data);54 session_ticket_key.data = NULL;55 session_ticket_key.size = 0;56 gnutls_global_deinit();57 return APR_SUCCESS; 58 } 59 41 static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert); 42 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert); 43 static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert); 44 static int mgs_status_hook(request_rec *r, int flags); 45 46 /* Pool Cleanup Function */ 47 apr_status_t mgs_cleanup_pre_config(void *data) { 48 /* Free all session data */ 49 gnutls_free(session_ticket_key.data); 50 session_ticket_key.data = NULL; 51 session_ticket_key.size = 0; 52 /* Deinitialize GnuTLS Library */ 53 gnutls_global_deinit(); 54 return APR_SUCCESS; 55 } 56 57 /* Logging Function for Maintainers */ 60 58 #if MOD_GNUTLS_DEBUG 61 static void gnutls_debug_log_all(int level, const char *str) 62 { 63 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str); 64 } 65 59 static void gnutls_debug_log_all(int level, const char *str) { 60 apr_file_printf(debug_log_fp, "<%d> %s", level, str); 61 } 66 62 #define _gnutls_log apr_file_printf 67 63 #else 68 # 64 #define _gnutls_log(...) 69 65 #endif 70 66 71 int 72 mgs_hook_pre_config(apr_pool_t * pconf, 73 apr_pool_t * plog, apr_pool_t * ptemp) 74 { 75 int ret; 76 67 static const char* mgs_readable_cvm(mgs_client_verification_method_e m) { 68 switch(m) { 69 case mgs_cvm_unset: 70 return "unset"; 71 case mgs_cvm_cartel: 72 return "cartel"; 73 case mgs_cvm_msva: 74 return "msva"; 75 } 76 return "unknown"; 77 } 78 79 /* Pre-Configuration HOOK: Runs First */ 80 int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp) { 81 82 /* Maintainer Logging */ 77 83 #if MOD_GNUTLS_DEBUG 78 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", 79 APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, 80 pconf); 84 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pconf); 85 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 86 gnutls_global_set_log_level(9); 87 gnutls_global_set_log_function(gnutls_debug_log_all); 88 _gnutls_log(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL)); 89 #endif 90 91 int ret; 92 93 /* Check for required GnuTLS Library Version */ 94 if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) { 95 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_check_version() failed. Required: " 96 "gnutls-%s Found: gnutls-%s", LIBGNUTLS_VERSION, gnutls_check_version(NULL)); 97 return DONE; 98 } 99 100 /* Initialize GnuTLS Library */ 101 ret = gnutls_global_init(); 102 if (ret < 0) { 103 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_global_init: %s", gnutls_strerror(ret)); 104 return DONE; 105 } 106 107 /* Generate a Session Key */ 108 ret = gnutls_session_ticket_key_generate(&session_ticket_key); 109 if (ret < 0) { 110 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_session_ticket_key_generate: %s", gnutls_strerror(ret)); 111 return DONE; 112 } 113 114 AP_OPTIONAL_HOOK(status_hook, mgs_status_hook, NULL, NULL, APR_HOOK_MIDDLE); 115 116 /* Register a pool clean-up function */ 117 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, apr_pool_cleanup_null); 118 119 return OK; 120 } 121 122 static int mgs_select_virtual_server_cb(gnutls_session_t session) { 123 124 mgs_handle_t *ctxt = NULL; 125 mgs_srvconf_rec *tsc = NULL; 126 int ret = 0; 127 128 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 129 130 ctxt = gnutls_transport_get_ptr(session); 131 132 /* find the virtual server */ 133 tsc = mgs_find_sni_server(session); 134 135 if (tsc != NULL) { 136 // Found a TLS vhost based on the SNI from the client; use it instead. 137 ctxt->sc = tsc; 138 } 139 140 gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode); 141 142 /* Set Anon credentials */ 143 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs); 144 /* Set x509 credentials */ 145 gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds); 146 147 #ifdef ENABLE_SRP 148 /* Set SRP credentials */ 149 if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) { 150 gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds); 151 } 152 #endif 153 154 /* update the priorities - to avoid negotiating a ciphersuite that is not 155 * enabled on this virtual server. Note that here we ignore the version 156 * negotiation. 157 */ 158 159 ret = gnutls_priority_set(session, ctxt->sc->priorities); 160 /* actually it shouldn't fail since we have checked at startup */ 161 return ret; 162 163 } 164 165 static int cert_retrieve_fn(gnutls_session_t session, 166 const gnutls_datum_t * req_ca_rdn, int nreqs, 167 const gnutls_pk_algorithm_t * pk_algos, int pk_algos_length, 168 gnutls_retr2_st *ret) { 169 81 170 82 171 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 83 172 84 gnutls_global_set_log_level(9); 85 gnutls_global_set_log_function(gnutls_debug_log_all); 86 _gnutls_log(debug_log_fp, "gnutls: %s\n", 87 gnutls_check_version(NULL)); 88 #endif 89 90 #if APR_HAS_THREADS 91 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded); 92 #if (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 11) || GNUTLS_VERSION_MAJOR < 2 93 if (mpm_is_threaded) { 94 gcry_control(GCRYCTL_SET_THREAD_CBS, 95 &gcry_threads_pthread); 173 mgs_handle_t *ctxt; 174 175 if (session == NULL) { 176 // ERROR INVALID SESSION 177 ret->ncerts = 0; 178 ret->deinit_all = 1; 179 return -1; 96 180 } 97 #endif 98 #else 99 mpm_is_threaded = 0; 100 #endif 101 102 103 if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) { 104 _gnutls_log(debug_log_fp, 105 "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", 106 LIBGNUTLS_VERSION, gnutls_check_version(NULL)); 107 return -3; 181 ctxt = gnutls_transport_get_ptr(session); 182 183 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { 184 // X509 CERTIFICATE 185 ret->cert_type = GNUTLS_CRT_X509; 186 ret->key_type = GNUTLS_PRIVKEY_X509; 187 ret->ncerts = ctxt->sc->certs_x509_chain_num; 188 ret->deinit_all = 0; 189 ret->cert.x509 = ctxt->sc->certs_x509_chain; 190 ret->key.x509 = ctxt->sc->privkey_x509; 191 return 0; 192 } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) { 193 // OPENPGP CERTIFICATE 194 ret->cert_type = GNUTLS_CRT_OPENPGP; 195 ret->key_type = GNUTLS_PRIVKEY_OPENPGP; 196 ret->ncerts = 1; 197 ret->deinit_all = 0; 198 ret->cert.pgp = ctxt->sc->cert_pgp; 199 ret->key.pgp = ctxt->sc->privkey_pgp; 200 return 0; 201 } else { 202 // UNKNOWN CERTIFICATE 203 ret->ncerts = 0; 204 ret->deinit_all = 1; 205 return -1; 108 206 } 109 110 ret = gnutls_global_init();111 if (ret < 0) {112 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n",113 gnutls_strerror(ret));114 return -3;115 }116 117 ret = gnutls_session_ticket_key_generate(&session_ticket_key);118 if (ret < 0) {119 _gnutls_log(debug_log_fp,120 "gnutls_session_ticket_key_generate: %s\n",121 gnutls_strerror(ret));122 }123 124 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,125 apr_pool_cleanup_null);126 127 128 return OK;129 }130 131 static int mgs_select_virtual_server_cb(gnutls_session_t session)132 {133 mgs_handle_t *ctxt;134 mgs_srvconf_rec *tsc;135 int ret;136 int cprio[2];137 138 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);139 140 ctxt = gnutls_transport_get_ptr(session);141 142 /* find the virtual server */143 tsc = mgs_find_sni_server(session);144 145 if (tsc != NULL)146 ctxt->sc = tsc;147 148 gnutls_certificate_server_set_request(session,149 ctxt->150 sc->client_verify_mode);151 152 /* set the new server credentials153 */154 155 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,156 ctxt->sc->certs);157 158 gnutls_credentials_set(session, GNUTLS_CRD_ANON,159 ctxt->sc->anon_creds);160 161 #ifdef ENABLE_SRP162 if (ctxt->sc->srp_tpasswd_conf_file != NULL163 && ctxt->sc->srp_tpasswd_file != NULL) {164 gnutls_credentials_set(session, GNUTLS_CRD_SRP,165 ctxt->sc->srp_creds);166 }167 #endif168 169 /* update the priorities - to avoid negotiating a ciphersuite that is not170 * enabled on this virtual server. Note that here we ignore the version171 * negotiation.172 */173 ret = gnutls_priority_set(session, ctxt->sc->priorities);174 /* actually it shouldn't fail since we have checked at startup */175 if (ret < 0)176 return ret;177 178 /* If both certificate types are not present disallow them from179 * being negotiated.180 */181 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {182 cprio[0] = GNUTLS_CRT_X509;183 cprio[1] = 0;184 gnutls_certificate_type_set_priority(session, cprio);185 } else if (ctxt->sc->cert_pgp != NULL186 && ctxt->sc->certs_x509[0] == NULL) {187 cprio[0] = GNUTLS_CRT_OPENPGP;188 cprio[1] = 0;189 gnutls_certificate_type_set_priority(session, cprio);190 }191 192 return 0;193 }194 195 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)196 {197 mgs_handle_t *ctxt;198 199 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);200 ctxt = gnutls_transport_get_ptr(session);201 202 if (ctxt == NULL)203 return GNUTLS_E_INTERNAL_ERROR;204 205 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {206 ret->type = GNUTLS_CRT_X509;207 ret->ncerts = ctxt->sc->certs_x509_num;208 ret->deinit_all = 0;209 210 ret->cert.x509 = ctxt->sc->certs_x509;211 ret->key.x509 = ctxt->sc->privkey_x509;212 213 return 0;214 } else if (gnutls_certificate_type_get(session) ==215 GNUTLS_CRT_OPENPGP) {216 ret->type = GNUTLS_CRT_OPENPGP;217 ret->ncerts = 1;218 ret->deinit_all = 0;219 220 ret->cert.pgp = ctxt->sc->cert_pgp;221 ret->key.pgp = ctxt->sc->privkey_pgp;222 223 return 0;224 225 }226 227 return GNUTLS_E_INTERNAL_ERROR;228 207 } 229 208 230 209 /* 2048-bit group parameters from SRP specification */ 231 210 const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" 232 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"233 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"234 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"235 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"236 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"237 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"238 "-----END DH PARAMETERS-----\n";211 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" 212 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" 213 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n" 214 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n" 215 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n" 216 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n" 217 "-----END DH PARAMETERS-----\n"; 239 218 240 219 /* Read the common name or the alternative name of the certificate. … … 243 222 * Returns negative on error. 244 223 */ 245 static int read_crt_cn(server_rec * s, apr_pool_t * p, 246 gnutls_x509_crt_t cert, char **cert_cn) 247 { 248 int rv = 0, i; 249 size_t data_len; 250 251 252 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 253 *cert_cn = NULL; 254 255 data_len = 0; 256 rv = gnutls_x509_crt_get_dn_by_oid(cert, 257 GNUTLS_OID_X520_COMMON_NAME, 258 0, 0, NULL, &data_len); 259 260 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 261 *cert_cn = apr_palloc(p, data_len); 262 rv = gnutls_x509_crt_get_dn_by_oid(cert, 263 GNUTLS_OID_X520_COMMON_NAME, 264 0, 0, *cert_cn, 265 &data_len); 266 } else { /* No CN return subject alternative name */ 267 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 268 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 269 s->server_hostname, s->port); 270 rv = 0; 271 /* read subject alternative name */ 272 for (i = 0; !(rv < 0); i++) { 273 data_len = 0; 274 rv = gnutls_x509_crt_get_subject_alt_name(cert, i, 275 NULL, 276 &data_len, 277 NULL); 278 279 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER 280 && data_len > 1) { 281 /* FIXME: not very efficient. What if we have several alt names 282 * before DNSName? 283 */ 284 *cert_cn = apr_palloc(p, data_len + 1); 285 286 rv = gnutls_x509_crt_get_subject_alt_name 287 (cert, i, *cert_cn, &data_len, NULL); 288 (*cert_cn)[data_len] = 0; 289 290 if (rv == GNUTLS_SAN_DNSNAME) 291 break; 224 static int read_crt_cn(server_rec * s, apr_pool_t * p, gnutls_x509_crt_t cert, char **cert_cn) { 225 226 int rv = 0, i; 227 size_t data_len; 228 229 230 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 231 *cert_cn = NULL; 232 233 data_len = 0; 234 rv = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &data_len); 235 236 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 237 *cert_cn = apr_palloc(p, data_len); 238 rv = gnutls_x509_crt_get_dn_by_oid(cert, 239 GNUTLS_OID_X520_COMMON_NAME, 240 0, 0, *cert_cn, 241 &data_len); 242 } else { /* No CN return subject alternative name */ 243 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 244 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 245 s->server_hostname, s->port); 246 rv = 0; 247 /* read subject alternative name */ 248 for (i = 0; !(rv < 0); i++) { 249 data_len = 0; 250 rv = gnutls_x509_crt_get_subject_alt_name(cert, i, 251 NULL, 252 &data_len, 253 NULL); 254 255 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER 256 && data_len > 1) { 257 /* FIXME: not very efficient. What if we have several alt names 258 * before DNSName? 259 */ 260 *cert_cn = apr_palloc(p, data_len + 1); 261 262 rv = gnutls_x509_crt_get_subject_alt_name 263 (cert, i, *cert_cn, &data_len, NULL); 264 (*cert_cn)[data_len] = 0; 265 266 if (rv == GNUTLS_SAN_DNSNAME) 267 break; 268 } 269 } 270 } 271 272 return rv; 273 } 274 275 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p, 276 gnutls_openpgp_crt_t cert, char **cert_cn) { 277 int rv = 0; 278 size_t data_len; 279 280 281 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 282 *cert_cn = NULL; 283 284 data_len = 0; 285 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); 286 287 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 288 *cert_cn = apr_palloc(p, data_len); 289 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, 290 &data_len); 291 } else { /* No CN return subject alternative name */ 292 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 293 "No name found in PGP certificate for '%s:%d'.", 294 s->server_hostname, s->port); 295 } 296 297 return rv; 298 } 299 300 int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * base_server) { 301 302 int rv; 303 server_rec *s; 304 gnutls_dh_params_t dh_params = NULL; 305 mgs_srvconf_rec *sc; 306 mgs_srvconf_rec *sc_base; 307 void *data = NULL; 308 const char *userdata_key = "mgs_init"; 309 310 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 311 312 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool); 313 if (data == NULL) { 314 apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, base_server->process->pool); 315 } 316 317 318 s = base_server; 319 sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module); 320 321 gnutls_dh_params_init(&dh_params); 322 323 if (sc_base->dh_params == NULL) { 324 gnutls_datum_t pdata = { 325 (void *) static_dh_params, 326 sizeof(static_dh_params) 327 }; 328 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, GNUTLS_X509_FMT_PEM); 329 /* Generate DH Params 330 int dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, 331 GNUTLS_SEC_PARAM_NORMAL); 332 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 333 "GnuTLS: Generating DH Params of %i bits. " 334 "To avoid this use GnuTLSDHFile to specify DH Params for this host", 335 dh_bits); 336 #if MOD_GNUTLS_DEBUG 337 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 338 "GnuTLS: Generated DH Params of %i bits",dh_bits); 339 #endif 340 rv = gnutls_dh_params_generate2 (dh_params,dh_bits); 341 */ 342 if (rv < 0) { 343 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 344 "GnuTLS: Unable to generate or load DH Params: (%d) %s", 345 rv, gnutls_strerror(rv)); 346 exit(rv); 347 } 348 } else { 349 dh_params = sc_base->dh_params; 350 } 351 352 rv = mgs_cache_post_config(p, s, sc_base); 353 if (rv != 0) { 354 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 355 "GnuTLS: Post Config for GnuTLSCache Failed." 356 " Shutting Down."); 357 exit(-1); 358 } 359 360 for (s = base_server; s; s = s->next) { 361 sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module); 362 sc->cache_type = sc_base->cache_type; 363 sc->cache_config = sc_base->cache_config; 364 sc->cache_timeout = sc_base->cache_timeout; 365 366 /* defaults for unset values: */ 367 if (sc->enabled == GNUTLS_ENABLED_UNSET) 368 sc->enabled = GNUTLS_ENABLED_FALSE; 369 if (sc->tickets == GNUTLS_ENABLED_UNSET) 370 sc->tickets = GNUTLS_ENABLED_TRUE; 371 if (sc->export_certificates_enabled == GNUTLS_ENABLED_UNSET) 372 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE; 373 if (sc->client_verify_mode == -1) 374 sc->client_verify_mode = GNUTLS_CERT_IGNORE; 375 if (sc->client_verify_method == mgs_cvm_unset) 376 sc->client_verify_method = mgs_cvm_cartel; 377 378 379 /* Check if the priorities have been set */ 380 if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) { 381 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 382 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!", 383 s->server_hostname, s->port); 384 exit(-1); 385 } 386 387 /* Check if DH params have been set per host */ 388 if (sc->dh_params != NULL) { 389 gnutls_certificate_set_dh_params(sc->certs, sc->dh_params); 390 gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params); 391 } else if (dh_params) { 392 gnutls_certificate_set_dh_params(sc->certs, dh_params); 393 gnutls_anon_set_server_dh_params(sc->anon_creds, dh_params); 394 } 395 396 gnutls_certificate_set_retrieve_function(sc->certs, cert_retrieve_fn); 397 398 #ifdef ENABLE_SRP 399 if (sc->srp_tpasswd_conf_file != NULL 400 && sc->srp_tpasswd_file != NULL) { 401 rv = gnutls_srp_set_server_credentials_file 402 (sc->srp_creds, sc->srp_tpasswd_file, 403 sc->srp_tpasswd_conf_file); 404 405 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) { 406 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 407 s, 408 "[GnuTLS] - Host '%s:%d' is missing a " 409 "SRP password or conf File!", 410 s->server_hostname, s->port); 411 exit(-1); 412 } 413 } 414 #endif 415 416 if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) && 417 sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) { 418 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 419 "[GnuTLS] - Host '%s:%d' is missing a Certificate File!", 420 s->server_hostname, s->port); 421 exit(-1); 422 } 423 424 if (sc->enabled == GNUTLS_ENABLED_TRUE && 425 ((sc->certs_x509_chain != NULL && sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) || 426 (sc->cert_pgp != NULL && sc->privkey_pgp == NULL))) { 427 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 428 "[GnuTLS] - Host '%s:%d' is missing a Private Key File!", 429 s->server_hostname, s->port); 430 exit(-1); 431 } 432 433 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 434 rv = -1; 435 if (sc->certs_x509_chain_num > 0) { 436 rv = read_crt_cn(s, p, sc->certs_x509_chain[0], &sc->cert_cn); 437 } 438 if (rv < 0 && sc->cert_pgp != NULL) { 439 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn); 440 } 441 442 if (rv < 0) { 443 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 444 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 445 s->server_hostname, s->port); 446 sc->cert_cn = NULL; 447 continue; 448 } 449 } 450 } 451 452 453 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 454 455 { 456 const char* libvers = gnutls_check_version(NULL); 457 char* gnutls_version = NULL; 458 if(libvers && (gnutls_version = apr_psprintf(p, "GnuTLS/%s", libvers))) { 459 ap_add_version_component(p, gnutls_version); 460 } else { 461 // In case we could not create the above string go for the static version instead 462 ap_add_version_component(p, "GnuTLS/" GNUTLS_VERSION "-static"); 463 } 464 } 465 466 return OK; 467 } 468 469 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) { 470 apr_status_t rv = APR_SUCCESS; 471 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 472 &gnutls_module); 473 474 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 475 if (sc->cache_type != mgs_cache_none) { 476 rv = mgs_cache_child_init(p, s, sc); 477 if (rv != APR_SUCCESS) { 478 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 479 "[GnuTLS] - Failed to run Cache Init"); 480 } 481 } 482 /* Block SIGPIPE Signals */ 483 rv = apr_signal_block(SIGPIPE); 484 if(rv != APR_SUCCESS) { 485 /* error sending output */ 486 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 487 "GnuTLS: Error Blocking SIGPIPE Signal!"); 488 } 489 } 490 491 const char *mgs_hook_http_scheme(const request_rec * r) { 492 mgs_srvconf_rec *sc; 493 494 if (r == NULL) 495 return NULL; 496 497 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 498 server->module_config, 499 &gnutls_module); 500 501 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 502 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 503 return NULL; 504 } 505 506 return "https"; 507 } 508 509 apr_port_t mgs_hook_default_port(const request_rec * r) { 510 mgs_srvconf_rec *sc; 511 512 if (r == NULL) 513 return 0; 514 515 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 516 server->module_config, 517 &gnutls_module); 518 519 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 520 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 521 return 0; 522 } 523 524 return 443; 525 } 526 527 #define MAX_HOST_LEN 255 528 529 #if USING_2_1_RECENT 530 531 typedef struct { 532 mgs_handle_t *ctxt; 533 mgs_srvconf_rec *sc; 534 const char *sni_name; 535 } vhost_cb_rec; 536 537 /** 538 * Matches the current vhost's ServerAlias directives 539 * 540 * @param x vhost callback record 541 * @param s server record 542 * @return true if a match, false otherwise 543 * 544 */ 545 int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc) { 546 apr_array_header_t *names; 547 int i,rv = 0; 548 char ** name; 549 550 /* Check ServerName First! */ 551 if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) { 552 // We have a match, save this server configuration 553 x->sc = tsc; 554 rv = 1; 555 /* Check any ServerAlias directives */ 556 } else if(s->names->nelts) { 557 names = s->names; 558 name = (char **)names->elts; 559 for (i = 0; i < names->nelts; ++i) { 560 if (!name[i]) { continue; } 561 if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) { 562 // We have a match, save this server configuration 563 x->sc = tsc; 564 rv = 1; 565 } 566 } 567 /* Wild any ServerAlias Directives */ 568 } else if(s->wild_names->nelts) { 569 names = s->wild_names; 570 name = (char **)names->elts; 571 for (i = 0; i < names->nelts; ++i) { 572 if (!name[i]) { continue; } 573 if(apr_fnmatch(name[i], x->sni_name , 574 APR_FNM_CASE_BLIND| 575 APR_FNM_PERIOD| 576 APR_FNM_PATHNAME| 577 APR_FNM_NOESCAPE) == APR_SUCCESS) { 578 x->sc = tsc; 579 rv = 1; 292 580 } 293 581 } 294 582 } 295 296 583 return rv; 297 584 } 298 585 299 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p, 300 gnutls_openpgp_crt_t cert, char **cert_cn) 301 { 302 int rv = 0; 303 size_t data_len; 304 305 306 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 307 *cert_cn = NULL; 308 309 data_len = 0; 310 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); 311 312 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 313 *cert_cn = apr_palloc(p, data_len); 314 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, 315 &data_len); 316 } else { /* No CN return subject alternative name */ 317 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 318 "No name found in PGP certificate for '%s:%d'.", 319 s->server_hostname, s->port); 320 } 321 322 return rv; 323 } 324 325 326 int 327 mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 328 apr_pool_t * ptemp, server_rec * base_server) 329 { 330 int rv; 331 server_rec *s; 332 gnutls_dh_params_t dh_params = NULL; 333 gnutls_rsa_params_t rsa_params = NULL; 334 mgs_srvconf_rec *sc; 335 mgs_srvconf_rec *sc_base; 336 void *data = NULL; 337 int first_run = 0; 338 const char *userdata_key = "mgs_init"; 339 340 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 341 apr_pool_userdata_get(&data, userdata_key, 342 base_server->process->pool); 343 if (data == NULL) { 344 first_run = 1; 345 apr_pool_userdata_set((const void *) 1, userdata_key, 346 apr_pool_cleanup_null, 347 base_server->process->pool); 348 } 349 350 351 s = base_server; 352 sc_base = 353 (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 354 &gnutls_module); 355 356 gnutls_dh_params_init(&dh_params); 357 358 if (sc_base->dh_params == NULL) { 359 gnutls_datum pdata = { 360 (void *) static_dh_params, 361 sizeof(static_dh_params) 362 }; 363 /* loading defaults */ 364 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 365 GNUTLS_X509_FMT_PEM); 366 367 if (rv < 0) { 368 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 369 "GnuTLS: Unable to load DH Params: (%d) %s", 370 rv, gnutls_strerror(rv)); 371 exit(rv); 372 } 373 } else 374 dh_params = sc_base->dh_params; 375 376 if (sc_base->rsa_params != NULL) 377 rsa_params = sc_base->rsa_params; 378 379 /* else not an error but RSA-EXPORT ciphersuites are not available 380 */ 381 382 rv = mgs_cache_post_config(p, s, sc_base); 383 if (rv != 0) { 384 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 385 "GnuTLS: Post Config for GnuTLSCache Failed." 386 " Shutting Down."); 387 exit(-1); 388 } 389 390 for (s = base_server; s; s = s->next) { 391 void *load = NULL; 392 sc = (mgs_srvconf_rec *) 393 ap_get_module_config(s->module_config, &gnutls_module); 394 sc->cache_type = sc_base->cache_type; 395 sc->cache_config = sc_base->cache_config; 396 397 /* Check if the priorities have been set */ 398 if (sc->priorities == NULL 399 && sc->enabled == GNUTLS_ENABLED_TRUE) { 400 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 401 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!", 402 s->server_hostname, s->port); 403 exit(-1); 404 } 405 406 /* Check if DH or RSA params have been set per host */ 407 if (sc->rsa_params != NULL) 408 load = sc->rsa_params; 409 else if (rsa_params) 410 load = rsa_params; 411 412 if (load != NULL) 413 gnutls_certificate_set_rsa_export_params(sc->certs, 414 load); 415 416 417 load = NULL; 418 if (sc->dh_params != NULL) 419 load = sc->dh_params; 420 else if (dh_params) 421 load = dh_params; 422 423 if (load != NULL) { /* not needed but anyway */ 424 gnutls_certificate_set_dh_params(sc->certs, load); 425 gnutls_anon_set_server_dh_params(sc->anon_creds, 426 load); 427 } 428 429 gnutls_certificate_server_set_retrieve_function(sc->certs, 430 cert_retrieve_fn); 431 432 #ifdef ENABLE_SRP 433 if (sc->srp_tpasswd_conf_file != NULL 434 && sc->srp_tpasswd_file != NULL) { 435 rv = gnutls_srp_set_server_credentials_file 436 (sc->srp_creds, sc->srp_tpasswd_file, 437 sc->srp_tpasswd_conf_file); 438 439 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) { 440 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 441 s, 442 "[GnuTLS] - Host '%s:%d' is missing a " 443 "SRP password or conf File!", 444 s->server_hostname, s->port); 445 exit(-1); 446 } 447 } 586 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) { 587 mgs_srvconf_rec *tsc; 588 vhost_cb_rec *x = baton; 589 int ret; 590 591 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 592 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 593 &gnutls_module); 594 595 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 596 return 0; 597 } 598 599 if (tsc->certs_x509_chain_num > 0) { 600 /* why are we doing this check? */ 601 ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_chain[0], s->server_hostname); 602 if (0 == ret) 603 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 604 "GnuTLS: Error checking certificate for hostname " 605 "'%s'", s->server_hostname); 606 } else { 607 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 608 "GnuTLS: SNI request for '%s' but no X.509 certs available at all", 609 s->server_hostname); 610 } 611 return check_server_aliases(x, s, tsc); 612 } 448 613 #endif 449 614 450 if (sc->certs_x509[0] == NULL && 451 sc->cert_pgp == NULL && 452 sc->enabled == GNUTLS_ENABLED_TRUE) { 453 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 454 "[GnuTLS] - Host '%s:%d' is missing a " 455 "Certificate File!", 456 s->server_hostname, s->port); 457 exit(-1); 458 } 459 460 if (sc->enabled == GNUTLS_ENABLED_TRUE && 461 ((sc->certs_x509[0] != NULL 462 && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL 463 && sc->privkey_pgp 464 == NULL))) { 465 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 466 "[GnuTLS] - Host '%s:%d' is missing a " 467 "Private Key File!", 468 s->server_hostname, s->port); 469 exit(-1); 470 } 471 472 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 473 rv = read_crt_cn(s, p, sc->certs_x509[0], 474 &sc->cert_cn); 475 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */ 476 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, 477 &sc->cert_cn); 478 479 if (rv < 0) { 480 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 481 s, 482 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 483 s->server_hostname, s->port); 484 sc->cert_cn = NULL; 485 continue; 486 } 487 } 488 } 489 490 491 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 492 493 return OK; 494 } 495 496 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) 497 { 498 apr_status_t rv = APR_SUCCESS; 499 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 500 &gnutls_module); 501 502 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 503 if (sc->cache_type != mgs_cache_none) { 504 rv = mgs_cache_child_init(p, s, sc); 505 if (rv != APR_SUCCESS) { 506 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 507 "[GnuTLS] - Failed to run Cache Init"); 508 } 509 } 510 } 511 512 const char *mgs_hook_http_scheme(const request_rec * r) 513 { 514 mgs_srvconf_rec *sc; 515 516 if (r == NULL) 517 return NULL; 518 519 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 520 server->module_config, 521 &gnutls_module); 522 523 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 524 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 525 return NULL; 526 } 527 528 return "https"; 529 } 530 531 apr_port_t mgs_hook_default_port(const request_rec * r) 532 { 533 mgs_srvconf_rec *sc; 534 535 if (r == NULL) 536 return 0; 537 538 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 539 server->module_config, 540 &gnutls_module); 541 542 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 543 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 544 return 0; 545 } 546 547 return 443; 548 } 549 550 #define MAX_HOST_LEN 255 551 615 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) { 616 int rv; 617 unsigned int sni_type; 618 size_t data_len = MAX_HOST_LEN; 619 char sni_name[MAX_HOST_LEN]; 620 mgs_handle_t *ctxt; 552 621 #if USING_2_1_RECENT 553 typedef struct { 554 mgs_handle_t *ctxt; 555 mgs_srvconf_rec *sc; 556 const char *sni_name; 557 } vhost_cb_rec; 558 559 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) 560 { 561 mgs_srvconf_rec *tsc; 562 vhost_cb_rec *x = baton; 563 564 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 565 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 566 &gnutls_module); 567 568 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 569 return 0; 570 } 571 572 /* The CN can contain a * -- this will match those too. */ 573 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 574 /* found a match */ 575 #if MOD_GNUTLS_DEBUG 576 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 577 x->ctxt->c->base_server, 578 "GnuTLS: Virtual Host CB: " 579 "'%s' == '%s'", tsc->cert_cn, x->sni_name); 622 vhost_cb_rec cbx; 623 #else 624 server_rec *s; 625 mgs_srvconf_rec *tsc; 580 626 #endif 581 /* Because we actually change the server used here, we need to reset 582 * things like ClientVerify. 583 */ 584 x->sc = tsc; 585 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our 586 * certificate structure *should* change when the server changes. 587 * acccckkkkkk. 588 */ 589 return 1; 590 } else { 591 #if MOD_GNUTLS_DEBUG 592 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 593 x->ctxt->c->base_server, 594 "GnuTLS: Virtual Host CB: " 595 "'%s' != '%s'", tsc->cert_cn, x->sni_name); 596 #endif 597 598 } 599 return 0; 600 } 601 #endif 602 603 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) 604 { 605 int rv; 606 unsigned int sni_type; 607 size_t data_len = MAX_HOST_LEN; 608 char sni_name[MAX_HOST_LEN]; 609 mgs_handle_t *ctxt; 610 #if USING_2_1_RECENT 611 vhost_cb_rec cbx; 612 #else 613 server_rec *s; 614 mgs_srvconf_rec *tsc; 615 #endif 616 617 if (session == NULL) 618 return NULL; 619 620 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 621 ctxt = gnutls_transport_get_ptr(session); 622 623 rv = gnutls_server_name_get(ctxt->session, sni_name, 624 &data_len, &sni_type, 0); 625 626 if (rv != 0) { 627 return NULL; 628 } 629 630 if (sni_type != GNUTLS_NAME_DNS) { 631 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 632 ctxt->c->base_server, 633 "GnuTLS: Unknown type '%d' for SNI: " 634 "'%s'", sni_type, sni_name); 635 return NULL; 636 } 627 628 if (session == NULL) 629 return NULL; 630 631 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 632 ctxt = gnutls_transport_get_ptr(session); 633 634 rv = gnutls_server_name_get(ctxt->session, sni_name, 635 &data_len, &sni_type, 0); 636 637 if (rv != 0) { 638 return NULL; 639 } 640 641 if (sni_type != GNUTLS_NAME_DNS) { 642 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 643 ctxt->c->base_server, 644 "GnuTLS: Unknown type '%d' for SNI: " 645 "'%s'", sni_type, sni_name); 646 return NULL; 647 } 637 648 638 649 /** … … 641 652 */ 642 653 #if USING_2_1_RECENT 643 cbx.ctxt = ctxt; 644 cbx.sc = NULL; 645 cbx.sni_name = sni_name; 646 647 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); 648 if (rv == 1) { 649 return cbx.sc; 654 cbx.ctxt = ctxt; 655 cbx.sc = NULL; 656 cbx.sni_name = sni_name; 657 658 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); 659 if (rv == 1) { 660 return cbx.sc; 661 } 662 #else 663 for (s = ap_server_conf; s; s = s->next) { 664 665 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 666 &gnutls_module); 667 668 if (tsc->enabled != GNUTLS_ENABLED_TRUE) { continue; } 669 670 if(check_server_aliases(x, s, tsc)) { 671 return tsc; 672 } 673 #endif 674 return NULL; 675 } 676 677 static void create_gnutls_handle(conn_rec * c) { 678 mgs_handle_t *ctxt; 679 /* Get mod_gnutls Configuration Record */ 680 mgs_srvconf_rec *sc =(mgs_srvconf_rec *) 681 ap_get_module_config(c->base_server->module_config,&gnutls_module); 682 683 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 684 ctxt = apr_pcalloc(c->pool, sizeof (*ctxt)); 685 ctxt->c = c; 686 ctxt->sc = sc; 687 ctxt->status = 0; 688 ctxt->input_rc = APR_SUCCESS; 689 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc); 690 ctxt->input_cbuf.length = 0; 691 ctxt->output_rc = APR_SUCCESS; 692 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc); 693 ctxt->output_blen = 0; 694 ctxt->output_length = 0; 695 /* Initialize GnuTLS Library */ 696 gnutls_init(&ctxt->session, GNUTLS_SERVER); 697 /* Initialize Session Tickets */ 698 if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) { 699 gnutls_session_ticket_enable_server(ctxt->session,&session_ticket_key); 700 } 701 702 /* Set Default Priority */ 703 gnutls_priority_set_direct (ctxt->session, "NORMAL", NULL); 704 /* Set Handshake function */ 705 gnutls_handshake_set_post_client_hello_function(ctxt->session, 706 mgs_select_virtual_server_cb); 707 /* Initialize Session Cache */ 708 mgs_cache_session_init(ctxt); 709 710 /* Set this config for this connection */ 711 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 712 /* Set pull, push & ptr functions */ 713 gnutls_transport_set_pull_function(ctxt->session, 714 mgs_transport_read); 715 gnutls_transport_set_push_function(ctxt->session, 716 mgs_transport_write); 717 gnutls_transport_set_ptr(ctxt->session, ctxt); 718 /* Add IO filters */ 719 ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, 720 ctxt, NULL, c); 721 ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, 722 ctxt, NULL, c); 723 } 724 725 int mgs_hook_pre_connection(conn_rec * c, void *csd) { 726 mgs_srvconf_rec *sc; 727 728 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 729 730 sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->module_config, 731 &gnutls_module); 732 733 if (sc && (!sc->enabled || sc->proxy_enabled == GNUTLS_ENABLED_TRUE)) { 734 return DECLINED; 735 } 736 737 create_gnutls_handle(c); 738 return OK; 739 } 740 741 int mgs_hook_fixups(request_rec * r) { 742 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 743 char buf[AP_IOBUFSIZE]; 744 const char *tmp; 745 size_t len; 746 mgs_handle_t *ctxt; 747 int rv = OK; 748 749 if (r == NULL) 750 return DECLINED; 751 752 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 753 apr_table_t *env = r->subprocess_env; 754 755 ctxt = 756 ap_get_module_config(r->connection->conn_config, 757 &gnutls_module); 758 759 if (!ctxt || ctxt->session == NULL) { 760 return DECLINED; 761 } 762 763 apr_table_setn(env, "HTTPS", "on"); 764 765 apr_table_setn(env, "SSL_VERSION_LIBRARY", 766 "GnuTLS/" LIBGNUTLS_VERSION); 767 apr_table_setn(env, "SSL_VERSION_INTERFACE", 768 "mod_gnutls/" MOD_GNUTLS_VERSION); 769 770 apr_table_setn(env, "SSL_PROTOCOL", 771 gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session))); 772 773 /* should have been called SSL_CIPHERSUITE instead */ 774 apr_table_setn(env, "SSL_CIPHER", 775 gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session), 776 gnutls_cipher_get(ctxt->session), 777 gnutls_mac_get(ctxt->session))); 778 779 apr_table_setn(env, "SSL_COMPRESS_METHOD", 780 gnutls_compression_get_name(gnutls_compression_get(ctxt->session))); 781 782 #ifdef ENABLE_SRP 783 if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) { 784 tmp = gnutls_srp_server_get_username(ctxt->session); 785 apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : ""); 786 } else { 787 apr_table_unset(env, "SSL_SRP_USER"); 788 } 789 #endif 790 791 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL) 792 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 793 794 unsigned int key_size = 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)); 795 tmp = apr_psprintf(r->pool, "%u", key_size); 796 797 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 798 799 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 800 801 apr_table_setn(env, "SSL_CIPHER_EXPORT", 802 (key_size <= 40) ? "true" : "false"); 803 804 int dhsize = gnutls_dh_get_prime_bits(ctxt->session); 805 if (dhsize > 0) { 806 tmp = apr_psprintf(r->pool, "%d", dhsize); 807 apr_table_setn(env, "SSL_DH_PRIME_BITS", tmp); 808 } 809 810 len = sizeof (sbuf); 811 gnutls_session_get_id(ctxt->session, sbuf, &len); 812 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 813 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 814 815 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 816 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_chain[0], 0, ctxt->sc->export_certificates_enabled); 817 } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) { 818 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, ctxt->sc->export_certificates_enabled); 650 819 } 651 #else 652 for (s = ap_server_conf; s; s = s->next) { 653 654 tsc = 655 (mgs_srvconf_rec *) 656 ap_get_module_config(s->module_config, &gnutls_module); 657 if (tsc->enabled != GNUTLS_ENABLED_TRUE) { 658 continue; 659 } 820 821 return rv; 822 } 823 824 int mgs_hook_authz(request_rec * r) { 825 int rv; 826 mgs_handle_t *ctxt; 827 mgs_dirconf_rec *dc; 828 829 if (r == NULL) 830 return DECLINED; 831 832 dc = ap_get_module_config(r->per_dir_config, &gnutls_module); 833 834 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 835 ctxt = 836 ap_get_module_config(r->connection->conn_config, 837 &gnutls_module); 838 839 if (!ctxt || ctxt->session == NULL) { 840 return DECLINED; 841 } 842 843 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 844 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 845 "GnuTLS: Directory set to Ignore Client Certificate!"); 846 } else { 847 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 848 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 849 "GnuTLS: Attempting to rehandshake with peer. %d %d", 850 ctxt->sc->client_verify_mode, 851 dc->client_verify_mode); 852 853 /* If we already have a client certificate, there's no point in 854 * re-handshaking... */ 855 rv = mgs_cert_verify(r, ctxt); 856 if (rv != DECLINED && rv != HTTP_FORBIDDEN) 857 return rv; 858 859 gnutls_certificate_server_set_request 860 (ctxt->session, dc->client_verify_mode); 861 862 if (mgs_rehandshake(ctxt) != 0) { 863 return HTTP_FORBIDDEN; 864 } 865 } else if (ctxt->sc->client_verify_mode == 866 GNUTLS_CERT_IGNORE) { 660 867 #if MOD_GNUTLS_DEBUG 661 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 662 ctxt->c->base_server, 663 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", 664 tsc->cert_cn, rv, 665 gnutls_pk_algorithm_get_name 666 (gnutls_x509_privkey_get_pk_algorithm 667 (ctxt->sc->privkey_x509)), (unsigned int) s, 668 (unsigned int) s->next, (unsigned int) tsc); 868 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 869 "GnuTLS: Peer is set to IGNORE"); 669 870 #endif 670 /* The CN can contain a * -- this will match those too. */ 671 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) { 672 #if MOD_GNUTLS_DEBUG 673 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 674 ctxt->c->base_server, 675 "GnuTLS: Virtual Host: " 676 "'%s' == '%s'", tsc->cert_cn, 677 sni_name); 678 #endif 679 return tsc; 680 } 681 } 682 #endif 683 return NULL; 684 } 685 686 687 static const int protocol_priority[] = { 688 GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 689 }; 690 691 692 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) 693 { 694 mgs_handle_t *ctxt; 695 mgs_srvconf_rec *sc = 696 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 697 module_config, 698 &gnutls_module); 699 700 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 701 ctxt = apr_pcalloc(pool, sizeof(*ctxt)); 702 ctxt->c = c; 703 ctxt->sc = sc; 704 ctxt->status = 0; 705 706 ctxt->input_rc = APR_SUCCESS; 707 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc); 708 ctxt->input_cbuf.length = 0; 709 710 ctxt->output_rc = APR_SUCCESS; 711 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc); 712 ctxt->output_blen = 0; 713 ctxt->output_length = 0; 714 715 gnutls_init(&ctxt->session, GNUTLS_SERVER); 716 if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) 717 gnutls_session_ticket_enable_server(ctxt->session, 718 &session_ticket_key); 719 720 /* because we don't set any default priorities here (we set later at 721 * the user hello callback) we need to at least set this in order for 722 * gnutls to be able to read packets. 723 */ 724 gnutls_protocol_set_priority(ctxt->session, protocol_priority); 725 726 gnutls_handshake_set_post_client_hello_function(ctxt->session, 727 mgs_select_virtual_server_cb); 728 729 mgs_cache_session_init(ctxt); 730 731 return ctxt; 732 } 733 734 int mgs_hook_pre_connection(conn_rec * c, void *csd) 735 { 736 mgs_handle_t *ctxt; 737 mgs_srvconf_rec *sc; 738 739 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 740 741 if (c == NULL) { 742 return DECLINED; 743 } 744 745 sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 746 module_config, 747 &gnutls_module); 748 749 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 750 return DECLINED; 751 } 752 753 if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip,c->local_ip) == 0) { 754 /* Connection initiated by Apache (mod_proxy) => ignore */ 755 return OK; 756 } 757 758 ctxt = create_gnutls_handle(c->pool, c); 759 760 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 761 762 gnutls_transport_set_pull_function(ctxt->session, 763 mgs_transport_read); 764 gnutls_transport_set_push_function(ctxt->session, 765 mgs_transport_write); 766 gnutls_transport_set_ptr(ctxt->session, ctxt); 767 768 ctxt->input_filter = 769 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 770 ctxt->output_filter = 771 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 772 773 return OK; 774 } 775 776 int mgs_hook_fixups(request_rec * r) 777 { 778 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 779 char buf[AP_IOBUFSIZE]; 780 const char *tmp; 781 size_t len; 782 mgs_handle_t *ctxt; 783 int rv = OK; 784 785 if (r == NULL) 786 return DECLINED; 787 788 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 789 apr_table_t *env = r->subprocess_env; 790 791 ctxt = 792 ap_get_module_config(r->connection->conn_config, 793 &gnutls_module); 794 795 if (!ctxt || ctxt->session == NULL) { 796 return DECLINED; 797 } 798 799 apr_table_setn(env, "HTTPS", "on"); 800 801 apr_table_setn(env, "SSL_VERSION_LIBRARY", 802 "GnuTLS/" LIBGNUTLS_VERSION); 803 apr_table_setn(env, "SSL_VERSION_INTERFACE", 804 "mod_gnutls/" MOD_GNUTLS_VERSION); 805 806 apr_table_setn(env, "SSL_PROTOCOL", 807 gnutls_protocol_get_name(gnutls_protocol_get_version 808 (ctxt->session))); 809 810 /* should have been called SSL_CIPHERSUITE instead */ 811 apr_table_setn(env, "SSL_CIPHER", 812 gnutls_cipher_suite_get_name(gnutls_kx_get 813 (ctxt->session), 814 gnutls_cipher_get 815 (ctxt->session), 816 gnutls_mac_get 817 (ctxt->session))); 818 819 apr_table_setn(env, "SSL_COMPRESS_METHOD", 820 gnutls_compression_get_name(gnutls_compression_get 821 (ctxt->session))); 822 823 #ifdef ENABLE_SRP 824 tmp = gnutls_srp_server_get_username(ctxt->session); 825 apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : ""); 826 #endif 827 828 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL) 829 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 830 831 unsigned int key_size = 832 8 * 833 gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)); 834 tmp = apr_psprintf(r->pool, "%u", key_size); 835 836 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 837 838 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 839 840 apr_table_setn(env, "SSL_CIPHER_EXPORT", 841 (key_size <= 40) ? "true" : "false"); 842 843 len = sizeof(sbuf); 844 gnutls_session_get_id(ctxt->session, sbuf, &len); 845 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 846 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 847 848 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 849 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, 850 ctxt-> 851 sc->export_certificates_enabled); 852 else if (gnutls_certificate_type_get(ctxt->session) == 853 GNUTLS_CRT_OPENPGP) 854 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, 855 ctxt-> 856 sc->export_certificates_enabled); 857 858 return rv; 859 } 860 861 int mgs_hook_authz(request_rec * r) 862 { 863 int rv; 864 mgs_handle_t *ctxt; 865 mgs_dirconf_rec *dc; 866 867 if (r == NULL) 868 return DECLINED; 869 870 dc = ap_get_module_config(r->per_dir_config, &gnutls_module); 871 872 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 873 ctxt = 874 ap_get_module_config(r->connection->conn_config, 875 &gnutls_module); 876 877 if (!ctxt || ctxt->session == NULL) { 878 return DECLINED; 879 } 880 881 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 882 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 883 "GnuTLS: Directory set to Ignore Client Certificate!"); 884 } else { 885 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 886 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 887 "GnuTLS: Attempting to rehandshake with peer. %d %d", 888 ctxt->sc->client_verify_mode, 889 dc->client_verify_mode); 890 891 /* If we already have a client certificate, there's no point in 892 * re-handshaking... */ 893 rv = mgs_cert_verify(r, ctxt); 894 if (rv != DECLINED && rv != HTTP_FORBIDDEN) 895 return rv; 896 897 gnutls_certificate_server_set_request 898 (ctxt->session, dc->client_verify_mode); 899 900 if (mgs_rehandshake(ctxt) != 0) { 901 return HTTP_FORBIDDEN; 902 } 903 } else if (ctxt->sc->client_verify_mode == 904 GNUTLS_CERT_IGNORE) { 905 #if MOD_GNUTLS_DEBUG 906 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 907 "GnuTLS: Peer is set to IGNORE"); 908 #endif 909 return DECLINED; 910 } 911 rv = mgs_cert_verify(r, ctxt); 912 if (rv != DECLINED && 913 (rv != HTTP_FORBIDDEN || 914 dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) { 915 return rv; 916 } 917 } 918 919 return DECLINED; 871 return DECLINED; 872 } 873 rv = mgs_cert_verify(r, ctxt); 874 if (rv != DECLINED && 875 (rv != HTTP_FORBIDDEN || 876 dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) { 877 return rv; 878 } 879 } 880 881 return DECLINED; 920 882 } 921 883 … … 926 888 */ 927 889 928 /* side is either 0 for SERVER or 1 for CLIENT 890 /* @param side is either 0 for SERVER or 1 for CLIENT 891 * 892 * @param export_full_cert (boolean) export the PEM-encoded 893 * certificate in full as an environment variable. 929 894 */ 930 895 #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") 931 static void 932 mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, 933 int export_certificates_enabled) 896 897 static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert) { 898 unsigned char sbuf[64]; /* buffer to hold serials */ 899 char buf[AP_IOBUFSIZE]; 900 const char *tmp; 901 char *tmp2; 902 size_t len; 903 int ret, i; 904 905 if (r == NULL) 906 return; 907 908 apr_table_t *env = r->subprocess_env; 909 910 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 911 if (export_full_cert != 0) { 912 char cert_buf[10 * 1024]; 913 len = sizeof (cert_buf); 914 915 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) 916 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL), 917 apr_pstrmemdup(r->pool, cert_buf, len)); 918 else 919 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 920 "GnuTLS: Failed to export X.509 certificate to environment"); 921 } 922 923 len = sizeof (buf); 924 gnutls_x509_crt_get_dn(cert, buf, &len); 925 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL), 926 apr_pstrmemdup(r->pool, buf, len)); 927 928 len = sizeof (buf); 929 gnutls_x509_crt_get_issuer_dn(cert, buf, &len); 930 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL), 931 apr_pstrmemdup(r->pool, buf, len)); 932 933 len = sizeof (sbuf); 934 gnutls_x509_crt_get_serial(cert, sbuf, &len); 935 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 936 apr_table_setn(env, 937 apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL), 938 apr_pstrdup(r->pool, tmp)); 939 940 ret = gnutls_x509_crt_get_version(cert); 941 if (ret > 0) 942 apr_table_setn(env, 943 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 944 NULL), apr_psprintf(r->pool, 945 "%u", ret)); 946 947 apr_table_setn(env, 948 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 949 "X.509"); 950 951 tmp = 952 mgs_time2sz(gnutls_x509_crt_get_expiration_time 953 (cert), buf, sizeof (buf)); 954 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 955 apr_pstrdup(r->pool, tmp)); 956 957 tmp = 958 mgs_time2sz(gnutls_x509_crt_get_activation_time 959 (cert), buf, sizeof (buf)); 960 apr_table_setn(env, 961 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 962 apr_pstrdup(r->pool, tmp)); 963 964 ret = gnutls_x509_crt_get_signature_algorithm(cert); 965 if (ret >= 0) { 966 apr_table_setn(env, 967 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", 968 NULL), 969 gnutls_sign_algorithm_get_name(ret)); 970 } 971 972 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL); 973 if (ret >= 0) { 974 apr_table_setn(env, 975 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 976 NULL), 977 gnutls_pk_algorithm_get_name(ret)); 978 } 979 980 /* export all the alternative names (DNS, RFC822 and URI) */ 981 for (i = 0; !(ret < 0); i++) { 982 len = 0; 983 ret = gnutls_x509_crt_get_subject_alt_name(cert, i, 984 NULL, &len, 985 NULL); 986 987 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) { 988 tmp2 = apr_palloc(r->pool, len + 1); 989 990 ret = 991 gnutls_x509_crt_get_subject_alt_name(cert, i, 992 tmp2, 993 &len, 994 NULL); 995 tmp2[len] = 0; 996 997 if (ret == GNUTLS_SAN_DNSNAME) { 998 apr_table_setn(env, 999 apr_psprintf(r->pool, 1000 "%s_S_AN%u", 1001 MGS_SIDE, i), 1002 apr_psprintf(r->pool, 1003 "DNSNAME:%s", 1004 tmp2)); 1005 } else if (ret == GNUTLS_SAN_RFC822NAME) { 1006 apr_table_setn(env, 1007 apr_psprintf(r->pool, 1008 "%s_S_AN%u", 1009 MGS_SIDE, i), 1010 apr_psprintf(r->pool, 1011 "RFC822NAME:%s", 1012 tmp2)); 1013 } else if (ret == GNUTLS_SAN_URI) { 1014 apr_table_setn(env, 1015 apr_psprintf(r->pool, 1016 "%s_S_AN%u", 1017 MGS_SIDE, i), 1018 apr_psprintf(r->pool, 1019 "URI:%s", 1020 tmp2)); 1021 } else { 1022 apr_table_setn(env, 1023 apr_psprintf(r->pool, 1024 "%s_S_AN%u", 1025 MGS_SIDE, i), 1026 "UNSUPPORTED"); 1027 } 1028 } 1029 } 1030 } 1031 1032 1033 /* @param side 0: server, 1: client 1034 * 1035 * @param export_full_cert (boolean) export the PEM-encoded 1036 * certificate in full as an environment variable. 1037 */ 1038 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert) { 1039 1040 unsigned char sbuf[64]; /* buffer to hold serials */ 1041 char buf[AP_IOBUFSIZE]; 1042 const char *tmp; 1043 size_t len; 1044 int ret; 1045 1046 if (r == NULL) 1047 return; 1048 1049 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1050 apr_table_t *env = r->subprocess_env; 1051 1052 if (export_full_cert != 0) { 1053 char cert_buf[10 * 1024]; 1054 len = sizeof (cert_buf); 1055 1056 if (gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) 1057 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL), 1058 apr_pstrmemdup(r->pool, cert_buf, len)); 1059 else 1060 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1061 "GnuTLS: Failed to export OpenPGP certificate to environment"); 1062 } 1063 1064 len = sizeof (buf); 1065 gnutls_openpgp_crt_get_name(cert, 0, buf, &len); 1066 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), 1067 apr_pstrmemdup(r->pool, buf, len)); 1068 1069 len = sizeof (sbuf); 1070 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); 1071 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 1072 apr_table_setn(env, 1073 apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", 1074 NULL), apr_pstrdup(r->pool, tmp)); 1075 1076 ret = gnutls_openpgp_crt_get_version(cert); 1077 if (ret > 0) 1078 apr_table_setn(env, 1079 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 1080 NULL), apr_psprintf(r->pool, 1081 "%u", ret)); 1082 1083 apr_table_setn(env, 1084 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 1085 "OPENPGP"); 1086 1087 tmp = 1088 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time 1089 (cert), buf, sizeof (buf)); 1090 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 1091 apr_pstrdup(r->pool, tmp)); 1092 1093 tmp = 1094 mgs_time2sz(gnutls_openpgp_crt_get_creation_time 1095 (cert), buf, sizeof (buf)); 1096 apr_table_setn(env, 1097 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1098 apr_pstrdup(r->pool, tmp)); 1099 1100 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); 1101 if (ret >= 0) { 1102 apr_table_setn(env, 1103 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1104 NULL), 1105 gnutls_pk_algorithm_get_name(ret)); 1106 } 1107 1108 } 1109 1110 /* TODO: Allow client sending a X.509 certificate chain */ 1111 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) { 1112 const gnutls_datum_t *cert_list; 1113 unsigned int cert_list_size, status; 1114 int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret; 1115 unsigned int ch_size = 0; 1116 1117 union { 1118 gnutls_x509_crt_t x509[MAX_CHAIN_SIZE]; 1119 gnutls_openpgp_crt_t pgp; 1120 } cert; 1121 apr_time_t expiration_time, cur_time; 1122 1123 if (r == NULL || ctxt == NULL || ctxt->session == NULL) 1124 return HTTP_FORBIDDEN; 1125 1126 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1127 cert_list = 1128 gnutls_certificate_get_peers(ctxt->session, &cert_list_size); 1129 1130 if (cert_list == NULL || cert_list_size == 0) { 1131 /* It is perfectly OK for a client not to send a certificate if on REQUEST mode 1132 */ 1133 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST) 1134 return OK; 1135 1136 /* no certificate provided by the client, but one was required. */ 1137 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1138 "GnuTLS: Failed to Verify Peer: " 1139 "Client did not submit a certificate"); 1140 return HTTP_FORBIDDEN; 1141 } 1142 1143 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1144 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1145 "GnuTLS: A Chain of %d certificate(s) was provided for validation", 1146 cert_list_size); 1147 1148 for (ch_size = 0; ch_size < cert_list_size; ch_size++) { 1149 gnutls_x509_crt_init(&cert.x509[ch_size]); 1150 rv = gnutls_x509_crt_import(cert.x509[ch_size], 1151 &cert_list[ch_size], 1152 GNUTLS_X509_FMT_DER); 1153 // When failure to import, leave the loop 1154 if (rv != GNUTLS_E_SUCCESS) { 1155 if (ch_size < 1) { 1156 ap_log_rerror(APLOG_MARK, 1157 APLOG_INFO, 0, r, 1158 "GnuTLS: Failed to Verify Peer: " 1159 "Failed to import peer certificates."); 1160 ret = HTTP_FORBIDDEN; 1161 goto exit; 1162 } 1163 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1164 "GnuTLS: Failed to import some peer certificates. Using %d certificates", 1165 ch_size); 1166 rv = GNUTLS_E_SUCCESS; 1167 break; 1168 } 1169 } 1170 } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) { 1171 if (cert_list_size > 1) { 1172 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1173 "GnuTLS: Failed to Verify Peer: " 1174 "Chained Client Certificates are not supported."); 1175 return HTTP_FORBIDDEN; 1176 } 1177 1178 gnutls_openpgp_crt_init(&cert.pgp); 1179 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], 1180 GNUTLS_OPENPGP_FMT_RAW); 1181 1182 } else 1183 return HTTP_FORBIDDEN; 1184 1185 if (rv < 0) { 1186 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1187 "GnuTLS: Failed to Verify Peer: " 1188 "Failed to import peer certificates."); 1189 ret = HTTP_FORBIDDEN; 1190 goto exit; 1191 } 1192 1193 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1194 apr_time_ansi_put(&expiration_time, 1195 gnutls_x509_crt_get_expiration_time 1196 (cert.x509[0])); 1197 1198 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1199 "GnuTLS: Verifying list of %d certificate(s) via method '%s'", 1200 ch_size, mgs_readable_cvm(ctxt->sc->client_verify_method)); 1201 switch(ctxt->sc->client_verify_method) { 1202 case mgs_cvm_cartel: 1203 rv = gnutls_x509_crt_list_verify(cert.x509, ch_size, 1204 ctxt->sc->ca_list, 1205 ctxt->sc->ca_list_size, 1206 NULL, 0, 0, &status); 1207 break; 1208 #ifdef ENABLE_MSVA 1209 case mgs_cvm_msva: 1210 { 1211 struct msv_response* resp = NULL; 1212 struct msv_query q = { .context="https", .peertype="client", .pkctype="x509pem" }; 1213 msv_ctxt_t ctx = msv_ctxt_init(NULL); 1214 char cert_pem_buf[10 * 1024]; 1215 size_t len = sizeof (cert_pem_buf); 1216 1217 rv = 0; 1218 if (gnutls_x509_crt_export(cert.x509[0], GNUTLS_X509_FMT_PEM, cert_pem_buf, &len) >= 0) { 1219 /* FIXME : put together a name from the cert we received, instead of hard-coding this value: */ 1220 q.peername = mgs_x509_construct_uid(r, cert.x509[0]); 1221 q.pkcdata = cert_pem_buf; 1222 rv = msv_query_agent(ctx, q, &resp); 1223 if (rv == LIBMSV_ERROR_SUCCESS) { 1224 status = 0; 1225 } else if (rv == LIBMSV_ERROR_INVALID) { 1226 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1227 "GnuTLS: Monkeysphere validation failed: (message: %s)", resp->message); 1228 status = GNUTLS_CERT_INVALID; 1229 } else { 1230 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1231 "GnuTLS: Error communicating with the Monkeysphere Validation Agent: (%d) %s", rv, msv_strerror(ctx, rv)); 1232 status = GNUTLS_CERT_INVALID; 1233 rv = -1; 1234 } 1235 } else { 1236 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1237 "GnuTLS: Could not convert the client certificate to PEM format"); 1238 status = GNUTLS_CERT_INVALID; 1239 rv = GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; 1240 } 1241 msv_response_destroy(resp); 1242 msv_ctxt_destroy(ctx); 1243 } 1244 break; 1245 #endif 1246 default: 1247 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1248 "GnuTLS: Failed to Verify X.509 Peer: method '%s' is not supported", 1249 mgs_readable_cvm(ctxt->sc->client_verify_method)); 1250 } 1251 1252 } else { 1253 apr_time_ansi_put(&expiration_time, 1254 gnutls_openpgp_crt_get_expiration_time 1255 (cert.pgp)); 1256 1257 switch(ctxt->sc->client_verify_method) { 1258 case mgs_cvm_cartel: 1259 rv = gnutls_openpgp_crt_verify_ring(cert.pgp, 1260 ctxt->sc->pgp_list, 0, 1261 &status); 1262 break; 1263 #ifdef ENABLE_MSVA 1264 case mgs_cvm_msva: 1265 /* need to set status and rv */ 1266 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1267 "GnuTLS: OpenPGP verification via MSVA is not yet implemented"); 1268 rv = GNUTLS_E_UNIMPLEMENTED_FEATURE; 1269 break; 1270 #endif 1271 default: 1272 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1273 "GnuTLS: Failed to Verify OpenPGP Peer: method '%s' is not supported", 1274 mgs_readable_cvm(ctxt->sc->client_verify_method)); 1275 } 1276 } 1277 1278 if (rv < 0) { 1279 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1280 "GnuTLS: Failed to Verify Peer certificate: (%d) %s", 1281 rv, gnutls_strerror(rv)); 1282 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND) 1283 ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r, 1284 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?"); 1285 ret = HTTP_FORBIDDEN; 1286 goto exit; 1287 } 1288 1289 /* TODO: X509 CRL Verification. */ 1290 /* May add later if anyone needs it. 1291 */ 1292 /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */ 1293 1294 cur_time = apr_time_now(); 1295 1296 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 1297 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1298 "GnuTLS: Could not find Signer for Peer Certificate"); 1299 } 1300 1301 if (status & GNUTLS_CERT_SIGNER_NOT_CA) { 1302 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1303 "GnuTLS: Peer's Certificate signer is not a CA"); 1304 } 1305 1306 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 1307 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1308 "GnuTLS: Peer's Certificate is using insecure algorithms"); 1309 } 1310 1311 if (status & GNUTLS_CERT_EXPIRED 1312 || status & GNUTLS_CERT_NOT_ACTIVATED) { 1313 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1314 "GnuTLS: Peer's Certificate signer is expired or not yet activated"); 1315 } 1316 1317 if (status & GNUTLS_CERT_INVALID) { 1318 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1319 "GnuTLS: Peer Certificate is invalid."); 1320 } else if (status & GNUTLS_CERT_REVOKED) { 1321 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1322 "GnuTLS: Peer Certificate is revoked."); 1323 } 1324 1325 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 1326 mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_enabled); 1327 else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) 1328 mgs_add_common_pgpcert_vars(r, cert.pgp, 1, ctxt->sc->export_certificates_enabled); 1329 1330 { 1331 /* days remaining */ 1332 unsigned long remain = 1333 (apr_time_sec(expiration_time) - 1334 apr_time_sec(cur_time)) / 86400; 1335 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN", 1336 apr_psprintf(r->pool, "%lu", remain)); 1337 } 1338 1339 if (status == 0) { 1340 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", 1341 "SUCCESS"); 1342 ret = OK; 1343 } else { 1344 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", 1345 "FAILED"); 1346 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST) 1347 ret = OK; 1348 else 1349 ret = HTTP_FORBIDDEN; 1350 } 1351 1352 exit: 1353 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1354 int i; 1355 for (i = 0; i < ch_size; i++) { 1356 gnutls_x509_crt_deinit(cert.x509[i]); 1357 } 1358 } else if (gnutls_certificate_type_get(ctxt->session) == 1359 GNUTLS_CRT_OPENPGP) 1360 gnutls_openpgp_crt_deinit(cert.pgp); 1361 return ret; 1362 1363 1364 } 1365 1366 static const char* mgs_x509_leaf_oid_from_dn(apr_pool_t *pool, const char* oid, gnutls_x509_crt_t cert) { 1367 int rv=GNUTLS_E_SUCCESS, i; 1368 size_t sz=0, lastsz=0; 1369 char* data=NULL; 1370 1371 i = -1; 1372 while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 1373 i++; 1374 lastsz=sz; 1375 sz=0; 1376 rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i, 0, NULL, &sz); 1377 } 1378 if (i > 0) { 1379 data = apr_palloc(pool, lastsz); 1380 sz=lastsz; 1381 rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i-1, 0, data, &sz); 1382 if (rv == GNUTLS_E_SUCCESS) 1383 return data; 1384 } 1385 return NULL; 1386 } 1387 1388 static const char* mgs_x509_first_type_from_san(apr_pool_t *pool, gnutls_x509_subject_alt_name_t target, gnutls_x509_crt_t cert) { 1389 int rv=GNUTLS_E_SUCCESS; 1390 size_t sz; 1391 char* data=NULL; 1392 unsigned int i; 1393 gnutls_x509_subject_alt_name_t thistype; 1394 1395 i = 0; 1396 while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 1397 sz = 0; 1398 rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, NULL, &sz, &thistype, NULL); 1399 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && thistype == target) { 1400 data = apr_palloc(pool, sz); 1401 rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, data, &sz, &thistype, NULL); 1402 if (rv == target) 1403 return data; 1404 } 1405 i++; 1406 } 1407 return NULL; 1408 } 1409 1410 /* Create a string representing a candidate User ID from an X.509 1411 * certificate 1412 1413 * We need this for client certification because a client gives us a 1414 * certificate, but doesn't tell us (in any other way) who they are 1415 * trying to authenticate as. 1416 1417 * TODO: we might need another parallel for OpenPGP, but for that it's 1418 * much simpler: we can just assume that the first User ID marked as 1419 * "primary" (or the first User ID, period) is the identity the user 1420 * is trying to present as. 1421 1422 * one complaint might be "but the user wanted to be another identity, 1423 * which is also in the certificate (e.g. in a SubjectAltName)" 1424 * However, given that any user can regenerate their own X.509 1425 * certificate with their own public key content, they should just do 1426 * so, and not expect us to guess at their identity :) 1427 1428 * This function allocates it's response from the pool given it. When 1429 * that pool is reclaimed, the response will also be deallocated. 1430 1431 * FIXME: what about extracting a server-style cert 1432 * (e.g. https://imposter.example) from the DN or any sAN? 1433 1434 * FIXME: what if we want to call this outside the context of a 1435 * request? That complicates the logging. 1436 */ 1437 static const char* mgs_x509_construct_uid(request_rec *r, gnutls_x509_crt_t cert) { 1438 /* basic strategy, assuming humans are the users: we are going to 1439 * try to reconstruct a "conventional" User ID by pulling in a 1440 * name, comment, and e-mail address. 1441 */ 1442 apr_pool_t *pool = r->pool; 1443 const char *name=NULL, *comment=NULL, *email=NULL; 1444 const char *ret=NULL; 1445 /* subpool for temporary allocation: */ 1446 apr_pool_t *sp=NULL; 1447 1448 if (APR_SUCCESS != apr_pool_create(&sp, pool)) 1449 return NULL; /* i'm assuming that libapr would log this kind 1450 * of error on its own */ 1451 1452 /* Name 1453 1454 the name comes from the leaf commonName of the cert's Subject. 1455 1456 (MAYBE: should we look at trying to assemble a candidate from 1457 givenName, surName, suffix, etc? the "name" field 1458 appears to be case-insensitive, which seems problematic 1459 from what we expect; see: 1460 http://www.itu.int/rec/T-REC-X.520-200102-s/e ) 1461 1462 (MAYBE: should we try pulling a commonName or otherName or 1463 something from subjectAltName? see: 1464 https://tools.ietf.org/html/rfc5280#section-4.2.1.6 1465 GnuTLS does not support looking for Common Names in the 1466 SAN yet) 1467 */ 1468 name = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_COMMON_NAME, cert); 1469 1470 /* Comment 1471 1472 I am inclined to punt on this for now, as Comment has been so 1473 atrociously misused in OpenPGP. Perhaps if there is a 1474 pseudonym (OID 2.5.4.65, aka GNUTLS_OID_X520_PSEUDONYM) field 1475 in the subject or sAN? 1476 */ 1477 comment = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_PSEUDONYM, cert); 1478 1479 /* E-mail 1480 1481 This should be the the first rfc822Name from the sAN. 1482 1483 failing that, we'll take the leaf email in the certificate's 1484 subject; this is a deprecated use though. 1485 */ 1486 email = mgs_x509_first_type_from_san(sp, GNUTLS_SAN_RFC822NAME, cert); 1487 if (email == NULL) 1488 email = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_PKCS9_EMAIL, cert); 1489 1490 /* assemble all the parts: */ 1491 1492 /* must have at least a name or an e-mail. */ 1493 if (name == NULL && email == NULL) { 1494 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1495 "GnuTLS: Need either a name or an e-mail address to get a User ID from an X.509 certificate."); 1496 goto end; 1497 } 1498 if (name) { 1499 if (comment) { 1500 if (email) { 1501 ret = apr_psprintf(pool, "%s (%s) <%s>", name, comment, email); 1502 } else { 1503 ret = apr_psprintf(pool, "%s (%s)", name, comment); 1504 } 1505 } else { 1506 if (email) { 1507 ret = apr_psprintf(pool, "%s <%s>", name, email); 1508 } else { 1509 ret = apr_pstrdup(pool, name); 1510 } 1511 } 1512 } else { 1513 if (comment) { 1514 ret = apr_psprintf(pool, "(%s) <%s>", comment, email); 1515 } else { 1516 ret = apr_psprintf(pool, "<%s>", email); 1517 } 1518 } 1519 1520 end: 1521 apr_pool_destroy(sp); 1522 return ret; 1523 } 1524 1525 static int mgs_status_hook(request_rec *r, int flags) 934 1526 { 935 unsigned char sbuf[64]; /* buffer to hold serials */ 936 char buf[AP_IOBUFSIZE]; 937 const char *tmp; 938 char *tmp2; 939 size_t len; 940 int ret, i; 941 942 if (r == NULL) 943 return; 944 945 apr_table_t *env = r->subprocess_env; 946 947 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 948 if (export_certificates_enabled != 0) { 949 char cert_buf[10 * 1024]; 950 len = sizeof(cert_buf); 951 952 if (gnutls_x509_crt_export 953 (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) 954 apr_table_setn(env, 955 apr_pstrcat(r->pool, MGS_SIDE, 956 "_CERT", NULL), 957 apr_pstrmemdup(r->pool, cert_buf, 958 len)); 959 960 } 961 962 len = sizeof(buf); 963 gnutls_x509_crt_get_dn(cert, buf, &len); 964 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL), 965 apr_pstrmemdup(r->pool, buf, len)); 966 967 len = sizeof(buf); 968 gnutls_x509_crt_get_issuer_dn(cert, buf, &len); 969 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL), 970 apr_pstrmemdup(r->pool, buf, len)); 971 972 len = sizeof(sbuf); 973 gnutls_x509_crt_get_serial(cert, sbuf, &len); 974 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 975 apr_table_setn(env, 976 apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL), 977 apr_pstrdup(r->pool, tmp)); 978 979 ret = gnutls_x509_crt_get_version(cert); 980 if (ret > 0) 981 apr_table_setn(env, 982 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 983 NULL), apr_psprintf(r->pool, 984 "%u", ret)); 985 986 apr_table_setn(env, 987 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 988 "X.509"); 989 990 tmp = 991 mgs_time2sz(gnutls_x509_crt_get_expiration_time 992 (cert), buf, sizeof(buf)); 993 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 994 apr_pstrdup(r->pool, tmp)); 995 996 tmp = 997 mgs_time2sz(gnutls_x509_crt_get_activation_time 998 (cert), buf, sizeof(buf)); 999 apr_table_setn(env, 1000 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1001 apr_pstrdup(r->pool, tmp)); 1002 1003 ret = gnutls_x509_crt_get_signature_algorithm(cert); 1004 if (ret >= 0) { 1005 apr_table_setn(env, 1006 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", 1007 NULL), 1008 gnutls_sign_algorithm_get_name(ret)); 1009 } 1010 1011 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL); 1012 if (ret >= 0) { 1013 apr_table_setn(env, 1014 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1015 NULL), 1016 gnutls_pk_algorithm_get_name(ret)); 1017 } 1018 1019 /* export all the alternative names (DNS, RFC822 and URI) */ 1020 for (i = 0; !(ret < 0); i++) { 1021 len = 0; 1022 ret = gnutls_x509_crt_get_subject_alt_name(cert, i, 1023 NULL, &len, 1024 NULL); 1025 1026 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) { 1027 tmp2 = apr_palloc(r->pool, len + 1); 1028 1029 ret = 1030 gnutls_x509_crt_get_subject_alt_name(cert, i, 1031 tmp2, 1032 &len, 1033 NULL); 1034 tmp2[len] = 0; 1035 1036 if (ret == GNUTLS_SAN_DNSNAME) { 1037 apr_table_setn(env, 1038 apr_psprintf(r->pool, 1039 "%s_S_AN%u", 1040 MGS_SIDE, i), 1041 apr_psprintf(r->pool, 1042 "DNSNAME:%s", 1043 tmp2)); 1044 } else if (ret == GNUTLS_SAN_RFC822NAME) { 1045 apr_table_setn(env, 1046 apr_psprintf(r->pool, 1047 "%s_S_AN%u", 1048 MGS_SIDE, i), 1049 apr_psprintf(r->pool, 1050 "RFC822NAME:%s", 1051 tmp2)); 1052 } else if (ret == GNUTLS_SAN_URI) { 1053 apr_table_setn(env, 1054 apr_psprintf(r->pool, 1055 "%s_S_AN%u", 1056 MGS_SIDE, i), 1057 apr_psprintf(r->pool, 1058 "URI:%s", 1059 tmp2)); 1060 } else { 1061 apr_table_setn(env, 1062 apr_psprintf(r->pool, 1063 "%s_S_AN%u", 1064 MGS_SIDE, i), 1065 "UNSUPPORTED"); 1066 } 1067 } 1068 } 1069 } 1070 1071 static void 1072 mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, 1073 int side, int export_certificates_enabled) 1074 { 1075 unsigned char sbuf[64]; /* buffer to hold serials */ 1076 char buf[AP_IOBUFSIZE]; 1077 const char *tmp; 1078 size_t len; 1079 int ret; 1080 1081 if (r == NULL) 1082 return; 1083 1084 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1085 apr_table_t *env = r->subprocess_env; 1086