Changeset ae29683 in mod_gnutls


Ignore:
Timestamp:
Feb 21, 2014, 12:15:56 AM (9 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
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.
Message:

Imported Upstream version 0.6

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).
    318
    419** Version 0.5.9 (2010-09-24)
     20- GnuTLSCache none is now an allowed option.
    521- Corrected behavior in Keep-Alive connections (do not
    622  terminate the connection prematurely)
    7 
    823- The GnuTLSCache variable now can be given the specific
    924  option "gdbm" instead of "dbm". "dbm" will use the berkeley
     
    1328** Version 0.5.8 (2010-08-18)
    1429- Session tickets are enabled by default.
    15 
    1630- Fixes some segmentation faults noticed in some
    1731  configurations.
     
    2135  my system had issues after reaching a limit of entries.
    2236  SDBM seems stable so force it.
    23 
    2437- Optimizations in session caching.
    25 
    2638- Added support for session tickets. This allows a
    2739  server to avoid using a session cache and still support
     
    2941  session data during handshake. New option
    3042  GnuTLSSessionTickets [on|off]
    31 
    3243- Depend on gnutls 2.10.0 to force support for safe
    3344  renegotiation.
     
    3647- Corrected issue with firefox and long POST data (by
    3748  handling EINTR and EAGAIN errors in read).
    38 
    3949- Added support for chained client certificates
    40 
    4150- Corrected more issues related to double frees
    4251http://issues.outoforder.cc/view.php?id=102
    4352
    4453** Version 0.5.5 (2009-06-13)
    45 
    4654- Removed limits on CA certificate loading. Reported by
    4755  Sander Marechal and Jack Bates.
    48 
    4956- Do not allow sending empty TLS packets even when instructed to.
    5057  This had the side effect of clients closing connection.
    5158
    5259** Version 0.5.4 (2009-01-04)
    53 
    5460- mod_gnutls.h: modified definition to extern to avoid compilation
    5561  errors in darwin.
    56 
    5762- Added patch to fix issue with mod_proxy. Investigation and patch by Alain
    5863  Knaff.
    59 
    6064- libgnutls detection uses pkg-config.
    6165
    6266** Version 0.5.3 (2008-10-16)
    63 
    6467- Corrected bug to allow having an OpenPGP-only web site.
    65 
    6668- Increased Max handshake tries due to interrupted system calls.
    6769
    6870** Version 0.5.2 (2008-06-29)
    69 
    7071- Depend on gnutls 2.4 which has openpgp support in main library.
    7172
    7273** Version 0.5.1 (2008-03-05)
    73 
    7474- Added --disable-srp configure option
    75 
    7675- Better check for memcache (patch by Guillaume Rousse)
    77 
    7876- Corrected possible memory leak in DBM support for resuming sessions.
    7977
    8078** Version 0.5.0-alpha (2008-01-24)
    81 
    8279- Added support for OpenPGP keys. The new directives are:
    8380  GnuTLSPGPKeyringFile, GnuTLSPGPCertificateFile, GnuTLSPGPKeyFile
    8481
    8582** Version 0.4.2 (2007-12-10)
    86 
    8783- Added support for sending a certificate chain.
    88 
    8984- Corrected bug which did not allow the TLS session cache to be used.
    90 
    9185- Do not allow resuming sessions on different servers.
    9286
    9387** Version 0.4.1 (2007-12-03)
    94 
    9588- Added support for subject alternative names in certificates.
    9689Only one per certificate is supported.
    97 
    9890- New enviroment variables: SSL_CLIENT_M_VERSION, SSL_CLIENT_S_SAN%,
    9991SSL_CLIENT_S_TYPE, SSL_SERVER_M_VERSION, SSL_SERVER_S_SAN%, SSL_SERVER_S_TYPE
    100 
    10192- The compatibility mode can now be enabled explicitely with the
    10293%COMPAT keyword at the GnuTLSPriorities string. It is no longer the default.
    103 
    10494- Check for GnuTLSPriorities directive. This corrects a segfault. Thanks
    10595to David Hrbáč.
    106 
    10796- Better handling of GnuTLSDHFile and GnuTLSRSAFile.
    108 
    10997- No longer default paths for RSA and DH parameter files.
  • Makefile.am

    r180e49f rae29683  
    33EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \
    44                m4/libgnutls.m4 m4/apr_memcache.m4 \
    5                 m4/apache_test.m4 m4/lua.m4 \
     5                m4/apache_test.m4 \
    66                include/mod_gnutls.h.in \
    77                README README.ENV NEWS \
     
    1010SUBDIRS = src
    1111ACLOCAL_AMFLAGS = -I m4
     12TESTS = run_tests.sh
  • NOTICE

    r180e49f rae29683  
    11This 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/).
    36
    4 This product includes software developed by
    5 Paul Querna (http://www.outoforder.cc/).
    6 
    7 This product includes software developed by
    8 The Apache Software Foundation (http://www.apache.org/).
    9 
  • README

    r180e49f rae29683  
    99     I. ABOUT
    1010    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
    1517
    1618
     
    4244II.   AUTHORS
    4345
    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>
    4649
     50III.  MAINTAINERS
    4751
     52      Dash Shendy <neuromancer at dash.za.net>
     53      Execute `autoreconf -v -i -f` to Auto-generate files
    4854
    49 III.  LICENSE
     55IV.   LICENSE
    5056
    5157      Apache License, Version 2.0 (see the LICENSE file for details)
    5258
     59V.    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)
    5365
    5466
    55 IV.   STATUS
     67VI.   INSTALLATION
    5668
    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 cache
    60       * Supports DBM as a local SSL session cache
    61       * Support for server name indication (SNI), RFC3546
    62       * Support for client certificates
    63       * Support for secure remote password (SRP), RFC5054
     69      * 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
    6476
    65 
    66 
    67 V.    BASIC CONFIGURATION
     77VII.  BASIC CONFIGURATION
    6878
    6979      LoadModule gnutls_module modules/mod_gnutls.so
     
    151161
    152162
    153 VI.   CREATE OPENPGP CREDENTIALS FOR THE SERVER
     163IX.   CREATE OPENPGP CREDENTIALS FOR THE SERVER
    154164
    155165      mod_gnutls currently cannot read encrypted OpenPGP credentials.  That is,
  • configure.ac

    r180e49f rae29683  
    11dnl
    2 AC_INIT(mod_gnutls, 0.5.10)
     2AC_INIT(mod_gnutls, 0.6)
    33OOO_CONFIG_NICE(config.nice)
    44MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
     
    2020AC_PROG_LIBTOOL
    2121
     22AC_CONFIG_MACRO_DIR([m4])
     23
    2224AP_VERSION=2.0.40
    2325CHECK_APACHE(,$AP_VERSION,
     
    2628)
    2729
    28 dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`"
    29 dnl AC_SUBST(LIBTOOL)
     30PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.12.6])
    3031
    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 ]]))
     32LIBGNUTLS_VERSION=`pkg-config --modversion gnutls`
    4033
    4134AC_ARG_ENABLE(srp,
     
    4841        SRP_CFLAGS="-DENABLE_SRP=1"
    4942fi
     43
    5044AC_MSG_CHECKING([whether to enable SRP functionality])
    5145AC_MSG_RESULT($use_srp)
    5246
    53 dnl CHECK_LUA()
     47AC_ARG_ENABLE(msva,
     48       AS_HELP_STRING([--enable-msva],
     49               [enable Monkeysphere client certificate verification]),
     50       use_msva=$enableval, use_msva=no)
     51
     52MSVA_CFLAGS=""
     53if 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"
     59fi
     60
     61AC_MSG_CHECKING([whether to enable MSVA functionality])
     62AC_MSG_RESULT($use_msva)
    5463
    5564have_apr_memcache=0
     
    5766AC_SUBST(have_apr_memcache)
    5867
    59 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
     68MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${MSVA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
    6069MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}"
    6170
     
    7382echo "   * GnuTLS Library version:      ${LIBGNUTLS_VERSION}"
    7483echo "   * SRP Authentication:          ${use_srp}"
     84echo "   * MSVA Client Verification:    ${use_msva}"
    7585echo ""
    7686echo "---"
  • include/mod_gnutls.h.in

    r180e49f rae29683  
    1616 */
    1717
     18/* Apache Runtime Headers */
    1819#include "httpd.h"
    1920#include "http_config.h"
     
    2728#include "apr_tables.h"
    2829#include "ap_release.h"
    29 
     30#include "apr_fnmatch.h"
     31/* GnuTLS Library Headers */
    3032#include <gnutls/gnutls.h>
     33#if GNUTLS_VERSION_MAJOR == 2
    3134#include <gnutls/extra.h>
     35#endif
    3236#include <gnutls/openpgp.h>
    3337#include <gnutls/x509.h>
     
    4044extern module AP_MODULE_DECLARE_DATA gnutls_module;
    4145
     46/* IO Filter names */
    4247#define GNUTLS_OUTPUT_FILTER_NAME "gnutls_output_filter"
    4348#define GNUTLS_INPUT_FILTER_NAME "gnutls_input_filter"
    44 
     49/* GnuTLS Constants */
    4550#define GNUTLS_ENABLED_FALSE 0
    4651#define GNUTLS_ENABLED_TRUE  1
    47 
     52#define GNUTLS_ENABLED_UNSET  2
     53/* Current module version */
    4854#define MOD_GNUTLS_VERSION "@MOD_GNUTLS_VERSION@"
    4955
     56/* Module Debug Mode */
    5057#define MOD_GNUTLS_DEBUG @OOO_MAINTAIN@
    5158
    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 */
    5463#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
    6067#endif
    6168
    62 typedef enum
    63 {
     69/* mod_gnutls Cache Types */
     70typedef enum {
     71        /* No Cache */
    6472    mgs_cache_none,
     73        /* Use Old Berkley DB */
    6574    mgs_cache_dbm,
     75        /* Use Gnu's version of Berkley DB */
    6676    mgs_cache_gdbm,
    6777#if HAVE_APR_MEMCACHE
    68     mgs_cache_memcache
     78        /* Use Memcache */
     79    mgs_cache_memcache,
    6980#endif
     81    mgs_cache_unset
    7082} mgs_cache_e;
    7183
    72 typedef struct
    73 {
     84typedef 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 */
     92typedef struct {
    7493    int client_verify_mode;
    7594    const char* lua_bytecode;
     
    7897
    7998
    80 /* The maximum number of certificates to send in a chain
    81  */
     99/* The maximum number of certificates to send in a chain */
    82100#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 */
     105typedef struct {
     106        /* x509 Certificate Structure */
    86107    gnutls_certificate_credentials_t certs;
     108        /* SRP Certificate Structure*/
    87109    gnutls_srp_server_credentials_t srp_creds;
     110        /* Annonymous Certificate Structure */
    88111    gnutls_anon_server_credentials_t anon_creds;
     112        /* Current x509 Certificate CN [Common Name] */
    89113    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 */
    92119    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 */
    94123    gnutls_openpgp_privkey_t privkey_pgp;
     124        /* Number of Certificates in Chain */
     125    unsigned int certs_x509_chain_num;
     126        /* Is the module enabled? */
    95127    int enabled;
    96     /* whether to send the PEM encoded certificates
    97      * to CGIs
    98      */
     128    /* Export full certificates to CGI environment: */
    99129    int export_certificates_enabled;
     130        /* GnuTLS Priorities */
    100131    gnutls_priority_t priorities;
    101     gnutls_rsa_params_t rsa_params;
     132        /* GnuTLS DH Parameters */
    102133    gnutls_dh_params_t dh_params;
     134        /* Cache timeout value */
    103135    int cache_timeout;
     136        /* Chose Cache Type */
    104137    mgs_cache_e cache_type;
    105138    const char* cache_config;
    106139    const char* srp_tpasswd_file;
    107140    const char* srp_tpasswd_conf_file;
     141        /* A list of CA Certificates */
    108142    gnutls_x509_crt_t *ca_list;
     143        /* OpenPGP Key Ring */
    109144    gnutls_openpgp_keyring_t pgp_list;
     145        /* CA Certificate list size */
    110146    unsigned int ca_list_size;
     147        /* Client Certificate Verification Mode */
    111148    int client_verify_mode;
     149        /* Client Certificate Verification Method */
     150    mgs_client_verification_method_e client_verify_method;
     151        /* Last Cache timestamp */
    112152    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;
    114159} mgs_srvconf_rec;
    115160
     161/* Character Buffer */
    116162typedef struct {
    117163    int length;
     
    119165} mgs_char_buffer_t;
    120166
    121 typedef struct
    122 {
     167/* GnuTLS Handle */
     168typedef struct {
     169        /* Server configuration record */
    123170    mgs_srvconf_rec *sc;
     171        /* Connection record */
    124172    conn_rec* c;
     173        /* GnuTLS Session handle */
    125174    gnutls_session_t session;
    126 
     175        /* module input status */
    127176    apr_status_t input_rc;
     177        /* Input filter */
    128178    ap_filter_t *input_filter;
     179        /* Input Bucket Brigade */
    129180    apr_bucket_brigade *input_bb;
     181        /* Input Read Type */
    130182    apr_read_type_e input_block;
     183        /* Input Mode */
    131184    ap_input_mode_t input_mode;
     185        /* Input Character Buffer */
    132186    mgs_char_buffer_t input_cbuf;
     187        /* Input Character Array */
    133188    char input_buffer[AP_IOBUFSIZE];
    134 
     189        /* module Output status */
    135190    apr_status_t output_rc;
     191        /* Output filter */
    136192    ap_filter_t *output_filter;
     193        /* Output Bucket Brigade */
    137194    apr_bucket_brigade *output_bb;
     195        /* Output character array */
    138196    char output_buffer[AP_IOBUFSIZE];
     197        /* Output buffer length */
    139198    apr_size_t output_blen;
     199        /* Output length */
    140200    apr_size_t output_length;
    141 
     201        /* General Status */
    142202    int status;
    143     int non_https;
    144203} mgs_handle_t;
    145204
     205
     206
    146207/** Functions in gnutls_io.c **/
    147208
    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 */
     210apr_status_t apr_signal_block(int signum);
     211
     212 /* Proxy Support */
     213/* An optional function which returns non-zero if the given connection
     214is using SSL/TLS. */
     215APR_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. */
     219APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
     220APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
     221int ssl_is_https(conn_rec *c);
     222int ssl_proxy_enable(conn_rec *c);
     223int ssl_engine_disable(conn_rec *c);
     224const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy,
     225    const char *arg);
     226apr_status_t mgs_cleanup_pre_config(void *data);
    152227
    153228/**
     
    180255
    181256/**
    182  * mgs_transport_read is called from GnuTLS to provide encrypted 
     257 * mgs_transport_read is called from GnuTLS to provide encrypted
    183258 * data from the client.
    184259 *
     
    192267
    193268/**
    194  * mgs_transport_write is called from GnuTLS to 
     269 * mgs_transport_write is called from GnuTLS to
    195270 * write data to the client.
    196271 *
     
    211286 * Init the Cache after Configuration is done
    212287 */
    213 int mgs_cache_post_config(apr_pool_t *p, server_rec *s, 
     288int mgs_cache_post_config(apr_pool_t *p, server_rec *s,
    214289                                 mgs_srvconf_rec *sc);
    215290/**
    216291 * Init the Cache inside each Process
    217292 */
    218 int mgs_cache_child_init(apr_pool_t *p, server_rec *s, 
     293int mgs_cache_child_init(apr_pool_t *p, server_rec *s,
    219294                                mgs_srvconf_rec *sc);
    220295/**
     
    225300#define GNUTLS_SESSION_ID_STRING_LEN \
    226301    ((GNUTLS_MAX_SESSION_ID + 1) * 2)
    227    
     302
    228303/**
    229304 * Convert a SSL Session ID into a Null Terminated Hex Encoded String
     
    253328const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
    254329                                        const char *arg);
    255 const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
    256                                         const char *arg);
    257330const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
    258331                                        const char *arg);
     
    275348const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
    276349                                  const char *arg);
     350
     351const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy,
     352                                         const char *arg);
    277353
    278354const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
     
    290366const char *mgs_set_tickets(cmd_parms * parms, void *dummy,
    291367                            const char *arg);
    292                            
    293 const char *mgs_set_require_section(cmd_parms *cmd, 
     368
     369const char *mgs_set_require_section(cmd_parms *cmd,
    294370                                    void *mconfig, const char *arg);
    295371void *mgs_config_server_create(apr_pool_t * p, server_rec * s);
     372void *mgs_config_server_merge(apr_pool_t *p, void *BASE, void *ADD);
    296373
    297374void *mgs_config_dir_merge(apr_pool_t *p, void *basev, void *addv);
     
    299376void *mgs_config_dir_create(apr_pool_t *p, char *dir);
    300377
    301 const char *mgs_set_require_bytecode(cmd_parms *cmd, 
     378const char *mgs_set_require_bytecode(cmd_parms *cmd,
    302379                                    void *mconfig, const char *arg);
    303380
     
    325402int mgs_hook_authz(request_rec *r);
    326403
    327 int mgs_authz_lua(request_rec* r);
    328 
    329404#endif /*  __mod_gnutls_h_inc */
  • src/Makefile.am

    r180e49f rae29683  
    11CLEANFILES = .libs/libmod_gnutls *~
    22
    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}
     3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c
     4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
     5libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS}
    76
    87lib_LTLIBRARIES = libmod_gnutls.la
     
    1110        @if test ! -L mod_gnutls.so ; then ln -s .libs/libmod_gnutls.so mod_gnutls.so ; fi
    1211
    13 clean: 
     12clean:
    1413        rm -f mod_gnutls.so
    15         rm -f *.o *.lo *.la 
     14        rm -f *.o *.lo *.la
    1615        rm -fr .libs
    1716
     
    2322        @echo ""
    2423        @echo "   Please read the documentation at            "
    25         @echo "   http://www.outoforder.cc/ for   "
     24        @echo "   http://modgnutls.sourceforge.net/?p=docs for   "
    2625        @echo "   details on configuration of this module     "
    2726        @echo ""
  • src/gnutls_cache.c

    r180e49f rae29683  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Portions Copyright 2008 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    3435#endif
    3536
    36 /* it seems the default has some strange errors. Use SDBM 
     37/* it seems the default has some strange errors. Use SDBM
    3738 */
    3839#define MC_TAG "mod_gnutls:"
     
    4546
    4647char *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}
    6160
    6261/* Name the Session ID as:
     
    6564 */
    6665static 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;
    8381}
    8482
    8583#define CTIME "%b %d %k:%M:%S %Y %Z"
    86 char *mgs_time2sz(time_t in_time, char *str, int strsize)
    87 {
    88         apr_time_exp_t vtm;
    89         apr_size_t ret_size;
    90         apr_time_t t;
    91 
    92 
    93         apr_time_ansi_put(&t, in_time);
    94         apr_time_exp_gmt(&vtm, t);
    95         apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
    96 
    97         return str;
     84
     85char *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;
    9896}
    9997
    10098#if HAVE_APR_MEMCACHE
     99
    101100/* Name the Session ID as:
    102101 * server:port.SessionID
    103102 * to disallow resuming sessions on different servers
    104103 */
    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);
     104static 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);
    117115}
    118116
     
    126124
    127125static 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;
    207204}
    208205
    209206static 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
     233static 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) {
    255250#if MOD_GNUTLS_DEBUG
    256                 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    257                              ctxt->c->base_server,
    258                              "[gnutls_cache] error fetching key '%s' ",
    259                              strkey);
     251        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     252                ctxt->c->base_server,
     253                "[gnutls_cache] error fetching key '%s' ",
     254                strkey);
    260255#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
     272static 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
     296static const char *db_type(mgs_srvconf_rec * sc) {
     297    if (sc->cache_type == mgs_cache_gdbm)
     298        return "gdbm";
     299    else
     300        return "db";
    308301}
    309302
    310303#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    311304
    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;
     305static 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
     371static 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;
    430421}
    431422
    432423static 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
     483static 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;
    528517}
    529518
    530519static 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 */
    554542#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    }
    562556#endif
    563557
    564         return rv;
     558    return rv;
    565559}
    566560
    567561int 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;
    575576}
    576577
    577578int 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    }
    584584#if HAVE_APR_MEMCACHE
    585         else if (sc->cache_type == mgs_cache_memcache) {
    586                 return mc_cache_child_init(p, s, sc);
    587         }
     585    else if (sc->cache_type == mgs_cache_memcache) {
     586        return mc_cache_child_init(p, s, sc);
     587    }
    588588#endif
    589         return 0;
     589    return 0;
    590590}
    591591
    592592#include <assert.h>
    593593
    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         }
     594int 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    }
    606605#if HAVE_APR_MEMCACHE
    607         else if (ctxt->sc->cache_type == mgs_cache_memcache) {
    608                 gnutls_db_set_retrieve_function(ctxt->session,
    609                                                 mc_cache_fetch);
    610                 gnutls_db_set_remove_function(ctxt->session,
    611                                               mc_cache_delete);
    612                 gnutls_db_set_store_function(ctxt->session,
    613                                              mc_cache_store);
    614                 gnutls_db_set_ptr(ctxt->session, ctxt);
    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    }
    616615#endif
    617616
    618         return 0;
    619 }
     617    return 0;
     618}
  • src/gnutls_config.c

    r180e49f rae29683  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2007 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2021
    2122static 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
     55const 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
     98const 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
     127const 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);
    33158        }
    34159
    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
     171const 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
     211const 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
     252const 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
     270const 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
     282const 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
     297const 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
     339const 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
     365const 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
     384const 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
     416const 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
     478const 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
     518const 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
     535const 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
     552const 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
     566const char *mgs_set_priorities(cmd_parms * parms, void *dummy, const char *arg) {
     567
    58568        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
     587static 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    }
    329608#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;
    358619#endif
    359620
    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
     645void *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
     654void *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
     704void *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
     714void *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  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2007 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2021#include "http_vhost.h"
    2122#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>
    2827#endif
    2928
     
    3635#endif
    3736
    38 static int mpm_is_threaded;
    39 static gnutls_datum session_ticket_key = { NULL, 0 };
     37static gnutls_datum_t session_ticket_key = {NULL, 0};
    4038
    4139static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    4240/* 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 
     41static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert);
     42static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert);
     43static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
     44static int mgs_status_hook(request_rec *r, int flags);
     45
     46/* Pool Cleanup Function */
     47apr_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 */
    6058#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 
     59static void gnutls_debug_log_all(int level, const char *str) {
     60    apr_file_printf(debug_log_fp, "<%d> %s", level, str);
     61}
    6662#define _gnutls_log apr_file_printf
    6763#else
    68 # define _gnutls_log(...)
     64#define _gnutls_log(...)
    6965#endif
    7066
    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 
     67static 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 */
     80int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp) {
     81
     82/* Maintainer Logging */
    7783#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
     122static 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
     165static 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
    81170
    82171        _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    83172
    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;
    96180        }
    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;
    108206        }
    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 credentials
    153          */
    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_SRP
    162         if (ctxt->sc->srp_tpasswd_conf_file != NULL
    163             && ctxt->sc->srp_tpasswd_file != NULL) {
    164                 gnutls_credentials_set(session, GNUTLS_CRD_SRP,
    165                                        ctxt->sc->srp_creds);
    166         }
    167 #endif
    168 
    169         /* update the priorities - to avoid negotiating a ciphersuite that is not
    170          * enabled on this virtual server. Note that here we ignore the version
    171          * 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 from
    179          * 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 != NULL
    186                    && 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;
    228207}
    229208
    230209/* 2048-bit group parameters from SRP specification */
    231210const 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";
    239218
    240219/* Read the common name or the alternative name of the certificate.
     
    243222 * Returns negative on error.
    244223 */
    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;
     224static 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
     275static 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
     300int 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
     469void 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
     491const 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
     509apr_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
     531typedef 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 */
     545int 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;
    292580                        }
    293581                }
    294582        }
    295 
    296583        return rv;
    297584}
    298585
    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                 }
     586static 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}
    448613#endif
    449614
    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 
     615mgs_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;
    552621#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;
    580626#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    }
    637648
    638649    /**
     
    641652     */
    642653#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
     677static 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
     725int 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
     741int 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);
    650819        }
    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
     824int 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) {
    660867#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");
    669870#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;
    920882}
    921883
     
    926888 */
    927889
    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.
    929894 */
    930895#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
     897static 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 */
     1038static 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 */
     1111static 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
     1352exit:
     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
     1366static 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
     1388static 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 */
     1437static 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
     1520end:
     1521    apr_pool_destroy(sp);
     1522    return ret;
     1523}
     1524
     1525static int mgs_status_hook(request_rec *r, int flags)
    9341526{
    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