Changes in / [ae29683:180e49f] in mod_gnutls


Ignore:
Files:
21 added
104 deleted
11 edited

Legend:

Unmodified
Added
Removed
  • Makefile.am

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

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

    rae29683 r180e49f  
    99     I. ABOUT
    1010    II. AUTHORS
    11    III. MAINTAINERS
    12     IV. LICENSE
    13      V. PREREQUISITES
    14     VI. INSTALLATION
    15    VII. BASIC CONFIGURATION
    16   VIII. CREATE OPENPGP CREDENTIALS FOR THE SERVER
     11   III. LICENSE
     12    IV. STATUS
     13     V. BASIC CONFIGURATION
     14    VI. CREATE OPENPGP CREDENTIALS FOR THE SERVER
    1715
    1816
     
    4442II.   AUTHORS
    4543
    46       Paul Querna <chip at force-elite.com>
    47       Nikos Mavrogiannopoulos <nmav at gnutls.org>
    48       Dash Shendy <neuromancer at dash.za.net>
     44      Paul Querna <chip force-elite.com>
     45      Nikos Mavrogiannopoulos <nmav gnutls.org>
    4946
    50 III.  MAINTAINERS
    5147
    52       Dash Shendy <neuromancer at dash.za.net>
    53       Execute `autoreconf -v -i -f` to Auto-generate files
    5448
    55 IV.   LICENSE
     49III.  LICENSE
    5650
    5751      Apache License, Version 2.0 (see the LICENSE file for details)
    5852
    59 V.    PREREQUISITES
    60 
    61       * GnuTLS          >= 2.12.6 <http://www.gnu.org/software/gnutls/>
    62       * Apache HTTPD    >= 2.0.42 <http://httpd.apache.org/>
    63       *                 >= 2.1.5-dev
    64       * ARP Memcache    >= 0.7.0 (Optinal)
    6553
    6654
    67 VI.   INSTALLATION
     55IV.   STATUS
    6856
    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
     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
    7664
    77 VII.  BASIC CONFIGURATION
     65
     66
     67V.    BASIC CONFIGURATION
    7868
    7969      LoadModule gnutls_module modules/mod_gnutls.so
     
    161151
    162152
    163 IX.   CREATE OPENPGP CREDENTIALS FOR THE SERVER
     153VI.   CREATE OPENPGP CREDENTIALS FOR THE SERVER
    164154
    165155      mod_gnutls currently cannot read encrypted OpenPGP credentials.  That is,
  • configure.ac

    rae29683 r180e49f  
    11dnl
    2 AC_INIT(mod_gnutls, 0.6)
     2AC_INIT(mod_gnutls, 0.5.10)
    33OOO_CONFIG_NICE(config.nice)
    44MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
     
    2020AC_PROG_LIBTOOL
    2121
    22 AC_CONFIG_MACRO_DIR([m4])
    23 
    2422AP_VERSION=2.0.40
    2523CHECK_APACHE(,$AP_VERSION,
     
    2826)
    2927
    30 PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.12.6])
     28dnl LIBTOOL="`${APR_CONFIG} --apr-libtool`"
     29dnl AC_SUBST(LIBTOOL)
    3130
    32 LIBGNUTLS_VERSION=`pkg-config --modversion gnutls`
     31dnl Depend on 2.10.0 due to safe renegotiation addition.
     32MIN_TLS_VERSION=2.10.0
     33AM_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]]))
    3340
    3441AC_ARG_ENABLE(srp,
     
    4148        SRP_CFLAGS="-DENABLE_SRP=1"
    4249fi
    43 
    4450AC_MSG_CHECKING([whether to enable SRP functionality])
    4551AC_MSG_RESULT($use_srp)
    4652
    47 AC_ARG_ENABLE(msva,
    48        AS_HELP_STRING([--enable-msva],
    49                [enable Monkeysphere client certificate verification]),
    50        use_msva=$enableval, use_msva=no)
    51 
    52 MSVA_CFLAGS=""
    53 if test "$use_msva" != "no"; then
    54         AC_CHECK_HEADERS([msv/msv.h], [],
    55                          [AC_MSG_ERROR([*** No libmsv headers found!])])
    56         AC_SEARCH_LIBS([msv_query_agent], [msv], [],
    57                          [AC_MSG_ERROR([*** No libmsv found with msv_query_agent!])])
    58         MSVA_CFLAGS="-DENABLE_MSVA=1"
    59 fi
    60 
    61 AC_MSG_CHECKING([whether to enable MSVA functionality])
    62 AC_MSG_RESULT($use_msva)
     53dnl CHECK_LUA()
    6354
    6455have_apr_memcache=0
     
    6657AC_SUBST(have_apr_memcache)
    6758
    68 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${MSVA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
     59MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES}"
    6960MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}"
    7061
     
    8273echo "   * GnuTLS Library version:      ${LIBGNUTLS_VERSION}"
    8374echo "   * SRP Authentication:          ${use_srp}"
    84 echo "   * MSVA Client Verification:    ${use_msva}"
    8575echo ""
    8676echo "---"
  • include/mod_gnutls.h.in

    rae29683 r180e49f  
    1616 */
    1717
    18 /* Apache Runtime Headers */
    1918#include "httpd.h"
    2019#include "http_config.h"
     
    2827#include "apr_tables.h"
    2928#include "ap_release.h"
    30 #include "apr_fnmatch.h"
    31 /* GnuTLS Library Headers */
     29
    3230#include <gnutls/gnutls.h>
    33 #if GNUTLS_VERSION_MAJOR == 2
    3431#include <gnutls/extra.h>
    35 #endif
    3632#include <gnutls/openpgp.h>
    3733#include <gnutls/x509.h>
     
    4440extern module AP_MODULE_DECLARE_DATA gnutls_module;
    4541
    46 /* IO Filter names */
    4742#define GNUTLS_OUTPUT_FILTER_NAME "gnutls_output_filter"
    4843#define GNUTLS_INPUT_FILTER_NAME "gnutls_input_filter"
    49 /* GnuTLS Constants */
     44
    5045#define GNUTLS_ENABLED_FALSE 0
    5146#define GNUTLS_ENABLED_TRUE  1
    52 #define GNUTLS_ENABLED_UNSET  2
    53 /* Current module version */
     47
    5448#define MOD_GNUTLS_VERSION "@MOD_GNUTLS_VERSION@"
    5549
    56 /* Module Debug Mode */
    5750#define MOD_GNUTLS_DEBUG @OOO_MAINTAIN@
    5851
    59 /*
    60  * Recent Versions of 2.1 renamed several hooks.
    61  * This allows us to compile on 2.0.xx
    62  */
     52/* Recent Versions of 2.1 renamed several hooks. This allows us to
     53   compile on 2.0.xx  */
    6354#if AP_SERVER_MINORVERSION_NUMBER >= 2 || (AP_SERVER_MINORVERSION_NUMBER == 1 && AP_SERVER_PATCHLEVEL_NUMBER >= 3)
    64         #define USING_2_1_RECENT 1
    65 #else
    66         #define USING_2_1_RECENT 0
     55#define USING_2_1_RECENT 1
     56#endif
     57
     58#ifndef USING_2_1_RECENT
     59#define USING_2_1_RECENT 0
    6760#endif
    6861
    69 /* mod_gnutls Cache Types */
    70 typedef enum {
    71         /* No Cache */
     62typedef enum
     63{
    7264    mgs_cache_none,
    73         /* Use Old Berkley DB */
    7465    mgs_cache_dbm,
    75         /* Use Gnu's version of Berkley DB */
    7666    mgs_cache_gdbm,
    7767#if HAVE_APR_MEMCACHE
    78         /* Use Memcache */
    79     mgs_cache_memcache,
     68    mgs_cache_memcache
    8069#endif
    81     mgs_cache_unset
    8270} mgs_cache_e;
    8371
    84 typedef enum {
    85     mgs_cvm_unset,
    86     mgs_cvm_cartel,
    87     mgs_cvm_msva
    88 } mgs_client_verification_method_e;
    89 
    90 
    91 /* Directory Configuration Record */
    92 typedef struct {
     72typedef struct
     73{
    9374    int client_verify_mode;
    9475    const char* lua_bytecode;
     
    9778
    9879
    99 /* The maximum number of certificates to send in a chain */
     80/* The maximum number of certificates to send in a chain
     81 */
    10082#define MAX_CHAIN_SIZE 8
    101 /* The maximum number of SANs to read from a x509 certificate */
    102 #define MAX_CERT_SAN 5
    103 
    104 /* Server Configuration Record */
    105 typedef struct {
    106         /* x509 Certificate Structure */
     83
     84typedef struct
     85{
    10786    gnutls_certificate_credentials_t certs;
    108         /* SRP Certificate Structure*/
    10987    gnutls_srp_server_credentials_t srp_creds;
    110         /* Annonymous Certificate Structure */
    11188    gnutls_anon_server_credentials_t anon_creds;
    112         /* Current x509 Certificate CN [Common Name] */
    11389    char* cert_cn;
    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 */
     90    gnutls_x509_crt_t certs_x509[MAX_CHAIN_SIZE]; /* A certificate chain */
     91    unsigned int certs_x509_num;
    11992    gnutls_x509_privkey_t privkey_x509;
    120         /* OpenPGP Certificate */
    121     gnutls_openpgp_crt_t cert_pgp;
    122         /* OpenPGP Certificate Private Key */
     93    gnutls_openpgp_crt_t cert_pgp; /* A certificate chain */
    12394    gnutls_openpgp_privkey_t privkey_pgp;
    124         /* Number of Certificates in Chain */
    125     unsigned int certs_x509_chain_num;
    126         /* Is the module enabled? */
    12795    int enabled;
    128     /* Export full certificates to CGI environment: */
     96    /* whether to send the PEM encoded certificates
     97     * to CGIs
     98     */
    12999    int export_certificates_enabled;
    130         /* GnuTLS Priorities */
    131100    gnutls_priority_t priorities;
    132         /* GnuTLS DH Parameters */
     101    gnutls_rsa_params_t rsa_params;
    133102    gnutls_dh_params_t dh_params;
    134         /* Cache timeout value */
    135103    int cache_timeout;
    136         /* Chose Cache Type */
    137104    mgs_cache_e cache_type;
    138105    const char* cache_config;
    139106    const char* srp_tpasswd_file;
    140107    const char* srp_tpasswd_conf_file;
    141         /* A list of CA Certificates */
    142108    gnutls_x509_crt_t *ca_list;
    143         /* OpenPGP Key Ring */
    144109    gnutls_openpgp_keyring_t pgp_list;
    145         /* CA Certificate list size */
    146110    unsigned int ca_list_size;
    147         /* Client Certificate Verification Mode */
    148111    int client_verify_mode;
    149         /* Client Certificate Verification Method */
    150     mgs_client_verification_method_e client_verify_method;
    151         /* Last Cache timestamp */
    152112    apr_time_t last_cache_check;
    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;
     113    int tickets; /* whether session tickets are allowed */
    159114} mgs_srvconf_rec;
    160115
    161 /* Character Buffer */
    162116typedef struct {
    163117    int length;
     
    165119} mgs_char_buffer_t;
    166120
    167 /* GnuTLS Handle */
    168 typedef struct {
    169         /* Server configuration record */
     121typedef struct
     122{
    170123    mgs_srvconf_rec *sc;
    171         /* Connection record */
    172124    conn_rec* c;
    173         /* GnuTLS Session handle */
    174125    gnutls_session_t session;
    175         /* module input status */
     126
    176127    apr_status_t input_rc;
    177         /* Input filter */
    178128    ap_filter_t *input_filter;
    179         /* Input Bucket Brigade */
    180129    apr_bucket_brigade *input_bb;
    181         /* Input Read Type */
    182130    apr_read_type_e input_block;
    183         /* Input Mode */
    184131    ap_input_mode_t input_mode;
    185         /* Input Character Buffer */
    186132    mgs_char_buffer_t input_cbuf;
    187         /* Input Character Array */
    188133    char input_buffer[AP_IOBUFSIZE];
    189         /* module Output status */
     134
    190135    apr_status_t output_rc;
    191         /* Output filter */
    192136    ap_filter_t *output_filter;
    193         /* Output Bucket Brigade */
    194137    apr_bucket_brigade *output_bb;
    195         /* Output character array */
    196138    char output_buffer[AP_IOBUFSIZE];
    197         /* Output buffer length */
    198139    apr_size_t output_blen;
    199         /* Output length */
    200140    apr_size_t output_length;
    201         /* General Status */
     141
    202142    int status;
     143    int non_https;
    203144} mgs_handle_t;
    204145
    205 
    206 
    207146/** Functions in gnutls_io.c **/
    208147
    209 /* apr_signal_block() for blocking SIGPIPE */
    210 apr_status_t apr_signal_block(int signum);
    211 
    212  /* Proxy Support */
    213 /* An optional function which returns non-zero if the given connection
    214 is using SSL/TLS. */
    215 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
    216 /* The ssl_proxy_enable() and ssl_engine_disable() optional functions
    217  * are used by mod_proxy to enable use of SSL for outgoing
    218  * connections. */
    219 APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
    220 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
    221 int ssl_is_https(conn_rec *c);
    222 int ssl_proxy_enable(conn_rec *c);
    223 int ssl_engine_disable(conn_rec *c);
    224 const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy,
    225     const char *arg);
    226 apr_status_t mgs_cleanup_pre_config(void *data);
     148/**
     149 * write_flush will flush data
     150 */
     151static ssize_t write_flush(mgs_handle_t * ctxt);
    227152
    228153/**
     
    255180
    256181/**
    257  * mgs_transport_read is called from GnuTLS to provide encrypted
     182 * mgs_transport_read is called from GnuTLS to provide encrypted 
    258183 * data from the client.
    259184 *
     
    267192
    268193/**
    269  * mgs_transport_write is called from GnuTLS to
     194 * mgs_transport_write is called from GnuTLS to 
    270195 * write data to the client.
    271196 *
     
    286211 * Init the Cache after Configuration is done
    287212 */
    288 int mgs_cache_post_config(apr_pool_t *p, server_rec *s,
     213int mgs_cache_post_config(apr_pool_t *p, server_rec *s, 
    289214                                 mgs_srvconf_rec *sc);
    290215/**
    291216 * Init the Cache inside each Process
    292217 */
    293 int mgs_cache_child_init(apr_pool_t *p, server_rec *s,
     218int mgs_cache_child_init(apr_pool_t *p, server_rec *s, 
    294219                                mgs_srvconf_rec *sc);
    295220/**
     
    300225#define GNUTLS_SESSION_ID_STRING_LEN \
    301226    ((GNUTLS_MAX_SESSION_ID + 1) * 2)
    302 
     227   
    303228/**
    304229 * Convert a SSL Session ID into a Null Terminated Hex Encoded String
     
    328253const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
    329254                                        const char *arg);
     255const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
     256                                        const char *arg);
    330257const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
    331258                                        const char *arg);
     
    348275const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
    349276                                  const char *arg);
    350 
    351 const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy,
    352                                          const char *arg);
    353277
    354278const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
     
    366290const char *mgs_set_tickets(cmd_parms * parms, void *dummy,
    367291                            const char *arg);
    368 
    369 const char *mgs_set_require_section(cmd_parms *cmd,
     292                           
     293const char *mgs_set_require_section(cmd_parms *cmd, 
    370294                                    void *mconfig, const char *arg);
    371295void *mgs_config_server_create(apr_pool_t * p, server_rec * s);
    372 void *mgs_config_server_merge(apr_pool_t *p, void *BASE, void *ADD);
    373296
    374297void *mgs_config_dir_merge(apr_pool_t *p, void *basev, void *addv);
     
    376299void *mgs_config_dir_create(apr_pool_t *p, char *dir);
    377300
    378 const char *mgs_set_require_bytecode(cmd_parms *cmd,
     301const char *mgs_set_require_bytecode(cmd_parms *cmd, 
    379302                                    void *mconfig, const char *arg);
    380303
     
    402325int mgs_hook_authz(request_rec *r);
    403326
     327int mgs_authz_lua(request_rec* r);
     328
    404329#endif /*  __mod_gnutls_h_inc */
  • src/Makefile.am

    rae29683 r180e49f  
    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 libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
    5 libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS}
     3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c
     4#gnutls_lua.c
     5libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} ${LUA_CFLAGS}
     6libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS} ${LUA_LIBS}
    67
    78lib_LTLIBRARIES = libmod_gnutls.la
     
    1011        @if test ! -L mod_gnutls.so ; then ln -s .libs/libmod_gnutls.so mod_gnutls.so ; fi
    1112
    12 clean:
     13clean: 
    1314        rm -f mod_gnutls.so
    14         rm -f *.o *.lo *.la
     15        rm -f *.o *.lo *.la 
    1516        rm -fr .libs
    1617
     
    2223        @echo ""
    2324        @echo "   Please read the documentation at            "
    24         @echo "   http://modgnutls.sourceforge.net/?p=docs for   "
     25        @echo "   http://www.outoforder.cc/ for   "
    2526        @echo "   details on configuration of this module     "
    2627        @echo ""
  • src/gnutls_cache.c

    rae29683 r180e49f  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2008 Nikos Mavrogiannopoulos
    4  *  Copyright 2011 Dash Shendy
     3 *  Portions Copyright 2008 Nikos Mavrogiannopoulos
    54 *
    65 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    3534#endif
    3635
    37 /* it seems the default has some strange errors. Use SDBM
     36/* it seems the default has some strange errors. Use SDBM 
    3837 */
    3938#define MC_TAG "mod_gnutls:"
     
    4645
    4746char *mgs_session_id2sz(unsigned char *id, int idlen,
    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 }
     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
    6061
    6162/* Name the Session ID as:
     
    6465 */
    6566static int mgs_session_id2dbm(conn_rec * c, unsigned char *id, int idlen,
    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;
     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;
    8183}
    8284
    8385#define CTIME "%b %d %k:%M:%S %Y %Z"
    84 
    85 char *mgs_time2sz(time_t in_time, char *str, int strsize) {
    86     apr_time_exp_t vtm;
    87     apr_size_t ret_size;
    88     apr_time_t t;
    89 
    90 
    91     apr_time_ansi_put(&t, in_time);
    92     apr_time_exp_gmt(&vtm, t);
    93     apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
    94 
    95     return str;
     86char *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;
    9698}
    9799
    98100#if HAVE_APR_MEMCACHE
    99 
    100101/* Name the Session ID as:
    101102 * server:port.SessionID
    102103 * to disallow resuming sessions on different servers
    103104 */
    104 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) {
    105     char buf[STR_SESSION_LEN];
    106     char *sz;
    107 
    108     sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
    109     if (sz == NULL)
    110         return NULL;
    111 
    112     return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
    113             c->base_server->server_hostname,
    114             c->base_server->port, sz);
     105static 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);
    115117}
    116118
     
    124126
    125127static int mc_cache_child_init(apr_pool_t * p, server_rec * s,
    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;
     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;
    204207}
    205208
    206209static int mc_cache_store(void *baton, gnutls_datum_t key,
    207         gnutls_datum_t data) {
    208     apr_status_t rv = APR_SUCCESS;
    209     mgs_handle_t *ctxt = baton;
    210     char *strkey = NULL;
    211     apr_uint32_t timeout;
    212 
    213     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    214     if (!strkey)
    215         return -1;
    216 
    217     timeout = apr_time_sec(ctxt->sc->cache_timeout);
    218 
    219     rv = apr_memcache_set(mc, strkey, (char *) data.data, data.size, timeout,
    220             0);
    221 
    222     if (rv != APR_SUCCESS) {
    223         ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
    224                 ctxt->c->base_server,
    225                 "[gnutls_cache] error setting key '%s' "
    226                 "with %d bytes of data", strkey, data.size);
    227         return -1;
    228     }
    229 
    230     return 0;
    231 }
    232 
    233 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) {
    234     apr_status_t rv = APR_SUCCESS;
    235     mgs_handle_t *ctxt = baton;
    236     char *strkey = NULL;
    237     char *value;
    238     apr_size_t value_len;
    239     gnutls_datum_t data = {NULL, 0};
    240 
    241     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    242     if (!strkey) {
    243         return data;
    244     }
    245 
    246     rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
    247             &value, &value_len, NULL);
    248 
    249     if (rv != APR_SUCCESS) {
     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
     237static 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) {
    250255#if MOD_GNUTLS_DEBUG
    251         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    252                 ctxt->c->base_server,
    253                 "[gnutls_cache] error fetching key '%s' ",
    254                 strkey);
     256                ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     257                             ctxt->c->base_server,
     258                             "[gnutls_cache] error fetching key '%s' ",
     259                             strkey);
    255260#endif
    256         data.size = 0;
    257         data.data = NULL;
    258         return data;
    259     }
    260 
    261     /* TODO: Eliminate this memcpy. gnutls-- */
    262     data.data = gnutls_malloc(value_len);
    263     if (data.data == NULL)
    264         return data;
    265 
    266     data.size = value_len;
    267     memcpy(data.data, value, value_len);
    268 
    269     return data;
    270 }
    271 
    272 static int mc_cache_delete(void *baton, gnutls_datum_t key) {
    273     apr_status_t rv = APR_SUCCESS;
    274     mgs_handle_t *ctxt = baton;
    275     char *strkey = NULL;
    276 
    277     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    278     if (!strkey)
    279         return -1;
    280 
    281     rv = apr_memcache_delete(mc, strkey, 0);
    282 
    283     if (rv != APR_SUCCESS) {
    284         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    285                 ctxt->c->base_server,
    286                 "[gnutls_cache] error deleting key '%s' ",
    287                 strkey);
    288         return -1;
    289     }
    290 
    291     return 0;
    292 }
    293 
    294 #endif  /* have_apr_memcache */
    295 
    296 static const char *db_type(mgs_srvconf_rec * sc) {
    297     if (sc->cache_type == mgs_cache_gdbm)
    298         return "gdbm";
    299     else
    300         return "db";
     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
     277static 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
     302const char *db_type(mgs_srvconf_rec * sc)
     303{
     304        if (sc->cache_type == mgs_cache_gdbm)
     305                return "gdbm";
     306        else
     307                return "db";
    301308}
    302309
    303310#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    304311
    305 static void dbm_cache_expire(mgs_handle_t * ctxt) {
    306     apr_status_t rv;
    307     apr_dbm_t *dbm;
    308     apr_datum_t dbmkey;
    309     apr_datum_t dbmval;
    310     apr_time_t now;
    311     apr_time_t dtime;
    312     apr_pool_t *spool;
    313     int total, deleted;
    314 
    315     now = apr_time_now();
    316 
    317     if (now - ctxt->sc->last_cache_check <
    318             (ctxt->sc->cache_timeout) / 2)
    319         return;
    320 
    321     ctxt->sc->last_cache_check = now;
    322 
    323     apr_pool_create(&spool, ctxt->c->pool);
    324 
    325     total = 0;
    326     deleted = 0;
    327 
    328     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    329             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    330             SSL_DBM_FILE_MODE, spool);
    331     if (rv != APR_SUCCESS) {
    332         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    333                 ctxt->c->base_server,
    334                 "[gnutls_cache] error opening cache searcher '%s'",
    335                 ctxt->sc->cache_config);
    336         apr_pool_destroy(spool);
    337         return;
    338     }
    339 
    340     apr_dbm_firstkey(dbm, &dbmkey);
    341     while (dbmkey.dptr != NULL) {
    342         apr_dbm_fetch(dbm, dbmkey, &dbmval);
    343         if (dbmval.dptr != NULL
    344                 && dbmval.dsize >= sizeof (apr_time_t)) {
    345             memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t));
    346 
    347             if (now >= dtime) {
    348                 apr_dbm_delete(dbm, dbmkey);
    349                 deleted++;
    350             }
    351             apr_dbm_freedatum(dbm, dbmval);
    352         } else {
    353             apr_dbm_delete(dbm, dbmkey);
    354             deleted++;
    355         }
    356         total++;
    357         apr_dbm_nextkey(dbm, &dbmkey);
    358     }
    359     apr_dbm_close(dbm);
    360 
    361     ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    362             ctxt->c->base_server,
    363             "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d",
    364             ctxt->sc->cache_config, deleted, total - deleted);
    365 
    366     apr_pool_destroy(spool);
    367 
    368     return;
    369 }
    370 
    371 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) {
    372     gnutls_datum_t data = {NULL, 0};
    373     apr_dbm_t *dbm;
    374     apr_datum_t dbmkey;
    375     apr_datum_t dbmval;
    376     mgs_handle_t *ctxt = baton;
    377     apr_status_t rv;
    378 
    379     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    380         return data;
    381 
    382     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    383             ctxt->sc->cache_config, APR_DBM_READONLY,
    384             SSL_DBM_FILE_MODE, ctxt->c->pool);
    385     if (rv != APR_SUCCESS) {
    386         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    387                 ctxt->c->base_server,
    388                 "[gnutls_cache] error opening cache '%s'",
    389                 ctxt->sc->cache_config);
    390         return data;
    391     }
    392 
    393     rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
    394 
    395     if (rv != APR_SUCCESS) {
    396         apr_dbm_close(dbm);
    397         return data;
    398     }
    399 
    400     if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t)) {
    401         apr_dbm_freedatum(dbm, dbmval);
    402         apr_dbm_close(dbm);
    403         return data;
    404     }
    405 
    406     data.size = dbmval.dsize - sizeof (apr_time_t);
    407 
    408     data.data = gnutls_malloc(data.size);
    409     if (data.data == NULL) {
    410         apr_dbm_freedatum(dbm, dbmval);
    411         apr_dbm_close(dbm);
    412         return data;
    413     }
    414 
    415     memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
    416 
    417     apr_dbm_freedatum(dbm, dbmval);
    418     apr_dbm_close(dbm);
    419 
    420     return data;
     312static 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
     379static 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;
    421430}
    422431
    423432static int dbm_cache_store(void *baton, gnutls_datum_t key,
    424         gnutls_datum_t data) {
    425     apr_dbm_t *dbm;
    426     apr_datum_t dbmkey;
    427     apr_datum_t dbmval;
    428     mgs_handle_t *ctxt = baton;
    429     apr_status_t rv;
    430     apr_time_t expiry;
    431     apr_pool_t *spool;
    432 
    433     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    434         return -1;
    435 
    436     /* we expire dbm only on every store
    437      */
    438     dbm_cache_expire(ctxt);
    439 
    440     apr_pool_create(&spool, ctxt->c->pool);
    441 
    442     /* create DBM value */
    443     dbmval.dsize = data.size + sizeof (apr_time_t);
    444     dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
    445 
    446     expiry = apr_time_now() + ctxt->sc->cache_timeout;
    447 
    448     memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t));
    449     memcpy((char *) dbmval.dptr + sizeof (apr_time_t),
    450             data.data, data.size);
    451 
    452     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    453             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    454             SSL_DBM_FILE_MODE, ctxt->c->pool);
    455     if (rv != APR_SUCCESS) {
    456         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    457                 ctxt->c->base_server,
    458                 "[gnutls_cache] error opening cache '%s'",
    459                 ctxt->sc->cache_config);
    460         apr_pool_destroy(spool);
    461         return -1;
    462     }
    463 
    464     rv = apr_dbm_store(dbm, dbmkey, dbmval);
    465 
    466     if (rv != APR_SUCCESS) {
    467         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    468                 ctxt->c->base_server,
    469                 "[gnutls_cache] error storing in cache '%s'",
    470                 ctxt->sc->cache_config);
    471         apr_dbm_close(dbm);
    472         apr_pool_destroy(spool);
    473         return -1;
    474     }
    475 
    476     apr_dbm_close(dbm);
    477 
    478     apr_pool_destroy(spool);
    479 
    480     return 0;
    481 }
    482 
    483 static int dbm_cache_delete(void *baton, gnutls_datum_t key) {
    484     apr_dbm_t *dbm;
    485     apr_datum_t dbmkey;
    486     mgs_handle_t *ctxt = baton;
    487     apr_status_t rv;
    488 
    489     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    490         return -1;
    491 
    492     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    493             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    494             SSL_DBM_FILE_MODE, ctxt->c->pool);
    495     if (rv != APR_SUCCESS) {
    496         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    497                 ctxt->c->base_server,
    498                 "[gnutls_cache] error opening cache '%s'",
    499                 ctxt->sc->cache_config);
    500         return -1;
    501     }
    502 
    503     rv = apr_dbm_delete(dbm, dbmkey);
    504 
    505     if (rv != APR_SUCCESS) {
    506         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    507                 ctxt->c->base_server,
    508                 "[gnutls_cache] error deleting from cache '%s'",
    509                 ctxt->sc->cache_config);
    510         apr_dbm_close(dbm);
    511         return -1;
    512     }
    513 
    514     apr_dbm_close(dbm);
    515 
    516     return 0;
     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
     493static 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;
    517528}
    518529
    519530static int dbm_cache_post_config(apr_pool_t * p, server_rec * s,
    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 */
     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 */
    542554#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    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     }
     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        }
    556562#endif
    557563
    558     return rv;
     564        return rv;
    559565}
    560566
    561567int mgs_cache_post_config(apr_pool_t * p, server_rec * s,
    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;
     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;
    576575}
    577576
    578577int mgs_cache_child_init(apr_pool_t * p, server_rec * s,
    579         mgs_srvconf_rec * sc) {
    580     if (sc->cache_type == mgs_cache_dbm
    581             || sc->cache_type == mgs_cache_gdbm) {
    582         return 0;
    583     }
     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        }
    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     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     }
     594int 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        }
    605606#if HAVE_APR_MEMCACHE
    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     }
     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        }
    615616#endif
    616617
    617     return 0;
    618 }
     618        return 0;
     619}
  • src/gnutls_config.c

    rae29683 r180e49f  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2008 Nikos Mavrogiannopoulos
    4  *  Copyright 2011 Dash Shendy
     3 *  Copyright 2007 Nikos Mavrogiannopoulos
    54 *
    65 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2120
    2221static int load_datum_from_file(apr_pool_t * pool,
    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;
     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;
     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;
    5353}
    5454
    5555const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
    56         const char *arg) {
    57     int ret;
    58     gnutls_datum_t data;
    59     const char *file;
    60     apr_pool_t *spool;
    61     mgs_srvconf_rec *sc =
    62             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    63             module_config,
    64             &gnutls_module);
    65 
    66     apr_pool_create(&spool, parms->pool);
    67 
    68     file = ap_server_root_relative(spool, arg);
    69 
    70     if (load_datum_from_file(spool, file, &data) != 0) {
    71         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    72                 "DH params '%s'", file);
    73     }
    74 
    75     ret = gnutls_dh_params_init(&sc->dh_params);
    76     if (ret < 0) {
    77         return apr_psprintf(parms->pool,
    78                 "GnuTLS: Failed to initialize"
    79                 ": (%d) %s", ret,
    80                 gnutls_strerror(ret));
    81     }
    82 
    83     ret =
    84             gnutls_dh_params_import_pkcs3(sc->dh_params, &data,
    85             GNUTLS_X509_FMT_PEM);
    86     if (ret < 0) {
    87         return apr_psprintf(parms->pool,
    88                 "GnuTLS: Failed to Import "
    89                 "DH params '%s': (%d) %s", file, ret,
    90                 gnutls_strerror(ret));
    91     }
    92 
    93     apr_pool_destroy(spool);
    94 
    95     return NULL;
    96 }
    97 
    98 const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, const char *arg) {
    99 
    100     int ret;
    101     gnutls_datum_t data;
    102     const char *file;
    103     apr_pool_t *spool;
    104 
    105     mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module);
    106     apr_pool_create(&spool, parms->pool);
    107 
    108     file = ap_server_root_relative(spool, arg);
    109 
    110     if (load_datum_from_file(spool, file, &data) != 0) {
    111                 apr_pool_destroy(spool);
    112         return apr_psprintf(parms->pool, "GnuTLS: Error Reading Certificate '%s'", file);
    113     }
    114 
    115     sc->certs_x509_chain_num = MAX_CHAIN_SIZE;
    116     ret = gnutls_x509_crt_list_import(sc->certs_x509_chain, &sc->certs_x509_chain_num, &data, GNUTLS_X509_FMT_PEM, 0);
    117     if (ret < 0) {
    118                 apr_pool_destroy(spool);
    119         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import Certificate '%s': (%d) %s", file, ret, gnutls_strerror(ret));
    120     }
    121 
    122         apr_pool_destroy(spool);
    123     return NULL;
    124 
    125 }
    126 
    127 const char *mgs_set_key_file(cmd_parms * parms, void *dummy, const char *arg) {
    128 
    129     int ret;
    130     gnutls_datum_t data;
    131     const char *file;
    132     apr_pool_t *spool;
    133     const char *out;
    134 
    135         mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module);
    136 
    137         apr_pool_create(&spool, parms->pool);
    138 
    139     file = ap_server_root_relative(spool, arg);
    140 
    141     if (load_datum_from_file(spool, file, &data) != 0) {
    142         out = apr_psprintf(parms->pool, "GnuTLS: Error Reading Private Key '%s'", file);
    143                 apr_pool_destroy(spool);
    144         return out;
    145     }
    146 
    147     ret = gnutls_x509_privkey_init(&sc->privkey_x509);
    148 
    149     if (ret < 0) {
    150                 apr_pool_destroy(spool);
    151         return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize: (%d) %s", ret, gnutls_strerror(ret));
    152     }
    153 
    154     ret = gnutls_x509_privkey_import(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM);
    155 
    156     if (ret < 0) {
    157         ret = gnutls_x509_privkey_import_pkcs8(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM, NULL, GNUTLS_PKCS_PLAIN);
    158         }
    159 
    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;
     56                            const char *arg)
     57{
     58        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
     99const 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
     143const 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
     179const 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;
    169227}
    170228
    171229const 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;
     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;
    209268}
    210269
    211270const 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;
     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;
    250310}
    251311
    252312const 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;
     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;
    265326}
    266327
     
    269330
    270331const 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;
     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;
    280342}
    281343
    282344const 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;
     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;
    293356}
    294357
     
    296359
    297360const 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     }
     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        }
    316380#if HAVE_APR_MEMCACHE
    317     else if (strcasecmp("memcache", type) == 0) {
    318         sc->cache_type = mgs_cache_memcache;
    319     }
     381        else if (strcasecmp("memcache", type) == 0) {
     382                sc->cache_type = mgs_cache_memcache;
     383        }
    320384#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;
     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;
    337401}
    338402
    339403const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy,
    340         const char *arg) {
    341     int argint;
    342     const char *err;
    343     mgs_srvconf_rec *sc =
    344             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    345             module_config,
    346             &gnutls_module);
    347 
    348     if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
    349         return err;
    350     }
    351 
    352     argint = atoi(arg);
    353 
    354     if (argint < 0) {
    355         return "GnuTLSCacheTimeout: Invalid argument";
    356     } else if (argint == 0) {
    357         sc->cache_timeout = 0;
    358     } else {
    359         sc->cache_timeout = apr_time_from_sec(argint);
    360     }
    361 
    362     return NULL;
    363 }
    364 
    365 const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy,
    366         const char *arg) {
    367     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)ap_get_module_config(parms->server->module_config, &gnutls_module);
    368 
    369     if (strcasecmp("cartel", arg) == 0) {
    370         sc->client_verify_method = mgs_cvm_cartel;
    371     } else if (strcasecmp("msva", arg) == 0) {
    372 #ifdef ENABLE_MSVA
    373         sc->client_verify_method = mgs_cvm_msva;
    374 #else
    375         return "GnuTLSClientVerifyMethod: msva is not supported";
     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
     425const 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
     457const 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
     520const 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
     561const 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
     579const 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
     600const 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
     623void *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;
    376653#endif
    377     } else {
    378         return "GnuTLSClientVerifyMethod: Invalid argument";
    379     }
    380 
    381     return NULL;
    382 }
    383 
    384 const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
    385         const char *arg) {
    386     int mode;
    387 
    388     if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
    389         mode = GNUTLS_CERT_IGNORE;
    390     } else if (strcasecmp("optional", arg) == 0
    391             || strcasecmp("request", arg) == 0) {
    392         mode = GNUTLS_CERT_REQUEST;
    393     } else if (strcasecmp("require", arg) == 0) {
    394         mode = GNUTLS_CERT_REQUIRE;
    395     } else {
    396         return "GnuTLSClientVerify: Invalid argument";
    397     }
    398 
    399     /* This was set from a directory context */
    400     if (parms->path) {
    401         mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
    402         dc->client_verify_mode = mode;
    403     } else {
    404         mgs_srvconf_rec *sc =
    405                 (mgs_srvconf_rec *)
    406                 ap_get_module_config(parms->server->module_config,
    407                 &gnutls_module);
    408         sc->client_verify_mode = mode;
    409     }
    410 
    411     return NULL;
    412 }
    413 
    414 #define INIT_CA_SIZE 128
    415 
    416 const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
    417         const char *arg) {
    418     int rv;
    419     const char *file;
    420     apr_pool_t *spool;
    421     gnutls_datum_t data;
    422 
    423     mgs_srvconf_rec *sc =
    424             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    425             module_config,
    426             &gnutls_module);
    427     apr_pool_create(&spool, parms->pool);
    428 
    429     file = ap_server_root_relative(spool, arg);
    430 
    431     if (load_datum_from_file(spool, file, &data) != 0) {
    432         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    433                 "Client CA File '%s'", file);
    434     }
    435 
    436     sc->ca_list_size = INIT_CA_SIZE;
    437     sc->ca_list = malloc(sc->ca_list_size * sizeof (*sc->ca_list));
    438     if (sc->ca_list == NULL) {
    439         return apr_psprintf(parms->pool,
    440                 "mod_gnutls: Memory allocation error");
    441     }
    442 
    443     rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
    444             &data, GNUTLS_X509_FMT_PEM,
    445             GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
    446     if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) {
    447         return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    448                 "Client CA File '%s': (%d) %s", file,
    449                 rv, gnutls_strerror(rv));
    450     }
    451 
    452     if (INIT_CA_SIZE < sc->ca_list_size) {
    453         sc->ca_list =
    454                 realloc(sc->ca_list,
    455                 sc->ca_list_size * sizeof (*sc->ca_list));
    456         if (sc->ca_list == NULL) {
    457             return apr_psprintf(parms->pool,
    458                     "mod_gnutls: Memory allocation error");
    459         }
    460 
    461         /* re-read */
    462         rv = gnutls_x509_crt_list_import(sc->ca_list,
    463                 &sc->ca_list_size, &data,
    464                 GNUTLS_X509_FMT_PEM, 0);
    465 
    466         if (rv < 0) {
    467             return apr_psprintf(parms->pool,
    468                     "GnuTLS: Failed to load "
    469                     "Client CA File '%s': (%d) %s",
    470                     file, rv, gnutls_strerror(rv));
    471         }
    472     }
    473 
    474     apr_pool_destroy(spool);
    475     return NULL;
    476 }
    477 
    478 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
    479         const char *arg) {
    480     int rv;
    481     const char *file;
    482     apr_pool_t *spool;
    483     gnutls_datum_t data;
    484 
    485     mgs_srvconf_rec *sc =
    486             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    487             module_config,
    488             &gnutls_module);
    489     apr_pool_create(&spool, parms->pool);
    490 
    491     file = ap_server_root_relative(spool, arg);
    492 
    493     if (load_datum_from_file(spool, file, &data) != 0) {
    494         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    495                 "Keyring File '%s'", file);
    496     }
    497 
    498     rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
    499     if (rv < 0) {
    500         return apr_psprintf(parms->pool,
    501                 "GnuTLS: Failed to initialize"
    502                 "keyring: (%d) %s", rv,
    503                 gnutls_strerror(rv));
    504     }
    505 
    506     rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
    507             GNUTLS_OPENPGP_FMT_BASE64);
    508     if (rv < 0) {
    509         return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    510                 "Keyring File '%s': (%d) %s", file, rv,
    511                 gnutls_strerror(rv));
    512     }
    513 
    514     apr_pool_destroy(spool);
    515     return NULL;
    516 }
    517 
    518 const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy,
    519         const char *arg) {
    520 
    521     mgs_srvconf_rec *sc =(mgs_srvconf_rec *)
    522             ap_get_module_config(parms->server->module_config, &gnutls_module);
    523 
    524     if (!strcasecmp(arg, "On")) {
    525         sc->proxy_enabled = GNUTLS_ENABLED_TRUE;
    526     } else if (!strcasecmp(arg, "Off")) {
    527         sc->proxy_enabled = GNUTLS_ENABLED_FALSE;
    528     } else {
    529         return "SSLProxyEngine must be set to 'On' or 'Off'";
    530     }
    531 
    532     return NULL;
    533 }
    534 
    535 const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
    536         const char *arg) {
    537     mgs_srvconf_rec *sc =
    538             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    539             module_config,
    540             &gnutls_module);
    541     if (!strcasecmp(arg, "On")) {
    542         sc->enabled = GNUTLS_ENABLED_TRUE;
    543     } else if (!strcasecmp(arg, "Off")) {
    544         sc->enabled = GNUTLS_ENABLED_FALSE;
    545     } else {
    546         return "GnuTLSEnable must be set to 'On' or 'Off'";
    547     }
    548 
    549     return NULL;
    550 }
    551 
    552 const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy, const char *arg) {
    553     mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module);
    554     if (!strcasecmp(arg, "On")) {
    555         sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
    556     } else if (!strcasecmp(arg, "Off")) {
    557         sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
    558     } else {
    559         return
    560         "GnuTLSExportCertificates must be set to 'On' or 'Off'";
    561     }
    562 
    563     return NULL;
    564 }
    565 
    566 const char *mgs_set_priorities(cmd_parms * parms, void *dummy, const char *arg) {
    567 
    568         int ret;
    569     const char *err;
    570 
    571     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    572                                                   ap_get_module_config(parms->server->module_config, &gnutls_module);
    573 
    574     ret = gnutls_priority_init(&sc->priorities, arg, &err);
    575 
    576     if (ret < 0) {
    577         if (ret == GNUTLS_E_INVALID_REQUEST) {
    578             return apr_psprintf(parms->pool,
    579                                                                 "GnuTLS: Syntax error parsing priorities string at: %s", err);
    580                 }
    581         return "Error setting priorities";
    582     }
    583 
    584     return NULL;
    585 }
    586 
    587 static mgs_srvconf_rec *_mgs_config_server_create(apr_pool_t * p, char** err) {
    588     mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof (*sc));
    589     int ret;
    590 
    591     sc->enabled = GNUTLS_ENABLED_UNSET;
    592 
    593     ret = gnutls_certificate_allocate_credentials(&sc->certs);
    594     if (ret < 0) {
    595         *err = apr_psprintf(p, "GnuTLS: Failed to initialize"
    596                             ": (%d) %s", ret,
    597                             gnutls_strerror(ret));
    598         return NULL;
    599     }
    600 
    601     ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
    602     if (ret < 0) {
    603         *err = apr_psprintf(p, "GnuTLS: Failed to initialize"
    604                             ": (%d) %s", ret,
    605                             gnutls_strerror(ret));
    606         return NULL;
    607     }
    608 #ifdef ENABLE_SRP
    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;
    619 #endif
    620 
    621     sc->privkey_x509 = NULL;
    622         /* Initialize all Certificate Chains */
    623     /* FIXME: how do we indicate that this is unset for a merge? (that
    624      * is, how can a subordinate server override the chain by setting
    625      * an empty one?  what would that even look like in the
    626      * configuration?) */
    627         sc->certs_x509_chain = malloc(MAX_CHAIN_SIZE * sizeof (*sc->certs_x509_chain));
    628     sc->certs_x509_chain_num = 0;
    629     sc->cache_timeout = -1; /* -1 means "unset" */
    630     sc->cache_type = mgs_cache_unset;
    631     sc->cache_config = NULL;
    632     sc->tickets = GNUTLS_ENABLED_UNSET;
    633     sc->priorities = NULL;
    634     sc->dh_params = NULL;
    635     sc->proxy_enabled = GNUTLS_ENABLED_UNSET;
    636     sc->export_certificates_enabled = GNUTLS_ENABLED_UNSET;
    637     sc->client_verify_method = mgs_cvm_unset;
    638 
    639 /* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */
    640     sc->client_verify_mode = -1;
    641 
    642     return sc;
    643 }
    644 
    645 void *mgs_config_server_create(apr_pool_t * p, server_rec * s) {
    646     char *err = NULL;
    647     mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err);
    648     if (sc) return sc; else return err;
    649 }
    650 
    651 #define gnutls_srvconf_merge(t, unset) sc->t = (add->t == unset) ? base->t : add->t
    652 #define gnutls_srvconf_assign(t) sc->t = add->t
    653 
    654 void *mgs_config_server_merge(apr_pool_t *p, void *BASE, void *ADD) {
    655     int i;
    656     char *err = NULL;
    657     mgs_srvconf_rec *base = (mgs_srvconf_rec *)BASE;
    658     mgs_srvconf_rec *add = (mgs_srvconf_rec *)ADD;
    659     mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err);
    660     if (NULL == sc) return err;
    661 
    662     gnutls_srvconf_merge(enabled, GNUTLS_ENABLED_UNSET);
    663     gnutls_srvconf_merge(tickets, GNUTLS_ENABLED_UNSET);
    664     gnutls_srvconf_merge(proxy_enabled, GNUTLS_ENABLED_UNSET);
    665     gnutls_srvconf_merge(export_certificates_enabled, GNUTLS_ENABLED_UNSET);
    666     gnutls_srvconf_merge(client_verify_method, mgs_cvm_unset);
    667     gnutls_srvconf_merge(client_verify_mode, -1);
    668     gnutls_srvconf_merge(srp_tpasswd_file, NULL);
    669     gnutls_srvconf_merge(srp_tpasswd_conf_file, NULL);
    670     gnutls_srvconf_merge(privkey_x509, NULL);
    671     gnutls_srvconf_merge(priorities, NULL);
    672     gnutls_srvconf_merge(dh_params, NULL);
    673 
    674     /* FIXME: the following items are pre-allocated, and should be
    675      * properly disposed of before assigning in order to avoid leaks;
    676      * so at the moment, we can't actually have them in the config.
    677      * what happens during de-allocation?
    678 
    679      * This is probably leaky.
    680      */
    681     gnutls_srvconf_assign(certs);
    682     gnutls_srvconf_assign(anon_creds);
    683     gnutls_srvconf_assign(srp_creds);
    684     gnutls_srvconf_assign(certs_x509_chain);
    685     gnutls_srvconf_assign(certs_x509_chain_num);
    686 
    687     /* how do these get transferred cleanly before the data from ADD
    688      * goes away? */
    689     gnutls_srvconf_assign(cert_cn);
    690     for (i = 0; i < MAX_CERT_SAN; i++)
    691         gnutls_srvconf_assign(cert_san[i]);
    692     gnutls_srvconf_assign(ca_list);
    693     gnutls_srvconf_assign(ca_list_size);
    694     gnutls_srvconf_assign(cert_pgp);
    695     gnutls_srvconf_assign(pgp_list);
    696     gnutls_srvconf_assign(privkey_pgp);
    697 
    698     return sc;
    699 }
    700 
    701 #undef gnutls_srvconf_merge
    702 #undef gnutls_srvconf_assign
    703 
    704 void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv) {
    705     mgs_dirconf_rec *new;
    706     /*    mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
    707     mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
    708 
    709     new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof (mgs_dirconf_rec));
    710     new->client_verify_mode = add->client_verify_mode;
    711     return new;
    712 }
    713 
    714 void *mgs_config_dir_create(apr_pool_t * p, char *dir) {
    715     mgs_dirconf_rec *dc = apr_palloc(p, sizeof (*dc));
    716     dc->client_verify_mode = -1;
    717     return dc;
    718 }
    719 
     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
     668void *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
     682void *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}
  • src/gnutls_hooks.c

    rae29683 r180e49f  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2008 Nikos Mavrogiannopoulos
    4  *  Copyright 2011 Dash Shendy
     3 *  Copyright 2007 Nikos Mavrogiannopoulos
    54 *
    65 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2120#include "http_vhost.h"
    2221#include "ap_mpm.h"
    23 #include "mod_status.h"
    24 
    25 #ifdef ENABLE_MSVA
    26 #include <msv/msv.h>
     22
     23#if APR_HAS_THREADS
     24# if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11
     25#include <gcrypt.h>
     26GCRY_THREAD_OPTION_PTHREAD_IMPL;
     27# endif
    2728#endif
    2829
     
    3536#endif
    3637
    37 static gnutls_datum_t session_ticket_key = {NULL, 0};
     38static int mpm_is_threaded;
     39static gnutls_datum session_ticket_key = { NULL, 0 };
    3840
    3941static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    4042/* use side==0 for server and side==1 for client */
    41 static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert);
    42 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert);
    43 static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
    44 static int mgs_status_hook(request_rec *r, int flags);
    45 
    46 /* Pool Cleanup Function */
    47 apr_status_t mgs_cleanup_pre_config(void *data) {
    48         /* Free all session data */
    49     gnutls_free(session_ticket_key.data);
    50     session_ticket_key.data = NULL;
    51     session_ticket_key.size = 0;
    52         /* Deinitialize GnuTLS Library */
    53     gnutls_global_deinit();
    54     return APR_SUCCESS;
    55 }
    56 
    57 /* Logging Function for Maintainers */
     43static void mgs_add_common_cert_vars(request_rec * r,
     44                                     gnutls_x509_crt_t cert, int side,
     45                                     int export_certificates_enabled);
     46static void mgs_add_common_pgpcert_vars(request_rec * r,
     47                                        gnutls_openpgp_crt_t cert,
     48                                        int side,
     49                                        int export_certificates_enabled);
     50
     51static 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
    5860#if MOD_GNUTLS_DEBUG
    59 static void gnutls_debug_log_all(int level, const char *str) {
    60     apr_file_printf(debug_log_fp, "<%d> %s", level, str);
    61 }
     61static 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
    6266#define _gnutls_log apr_file_printf
    6367#else
    64 #define _gnutls_log(...)
    65 #endif
    66 
    67 static const char* mgs_readable_cvm(mgs_client_verification_method_e m) {
    68     switch(m) {
    69     case mgs_cvm_unset:
    70         return "unset";
    71     case mgs_cvm_cartel:
    72         return "cartel";
    73     case mgs_cvm_msva:
    74         return "msva";
    75     }
    76     return "unknown";
    77 }
    78 
    79 /* Pre-Configuration HOOK: Runs First */
    80 int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp) {
    81 
    82 /* Maintainer Logging */
     68# define _gnutls_log(...)
     69#endif
     70
     71int
     72mgs_hook_pre_config(apr_pool_t * pconf,
     73                    apr_pool_t * plog, apr_pool_t * ptemp)
     74{
     75        int ret;
     76
    8377#if MOD_GNUTLS_DEBUG
    84     apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pconf);
    85     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    86     gnutls_global_set_log_level(9);
    87     gnutls_global_set_log_function(gnutls_debug_log_all);
    88     _gnutls_log(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
    89 #endif
    90 
    91     int ret;
    92 
    93         /* Check for required GnuTLS Library Version */
    94     if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
    95                 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_check_version() failed. Required: "
    96                                         "gnutls-%s Found: gnutls-%s", LIBGNUTLS_VERSION, gnutls_check_version(NULL));
    97         return DONE;
    98     }
    99 
    100         /* Initialize GnuTLS Library */
    101     ret = gnutls_global_init();
    102     if (ret < 0) {
    103                 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_global_init: %s", gnutls_strerror(ret));
    104                 return DONE;
    105     }
    106 
    107         /* Generate a Session Key */
    108     ret = gnutls_session_ticket_key_generate(&session_ticket_key);
    109     if (ret < 0) {
    110                 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_session_ticket_key_generate: %s", gnutls_strerror(ret));
    111                 return DONE;
    112     }
    113 
    114     AP_OPTIONAL_HOOK(status_hook, mgs_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
    115 
    116         /* Register a pool clean-up function */
    117     apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, apr_pool_cleanup_null);
    118 
    119     return OK;
    120 }
    121 
    122 static int mgs_select_virtual_server_cb(gnutls_session_t session) {
    123 
    124     mgs_handle_t *ctxt = NULL;
    125     mgs_srvconf_rec *tsc = NULL;
    126     int ret = 0;
    127 
    128     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    129 
    130     ctxt = gnutls_transport_get_ptr(session);
    131 
    132     /* find the virtual server */
    133     tsc = mgs_find_sni_server(session);
    134 
    135     if (tsc != NULL) {
    136         // Found a TLS vhost based on the SNI from the client; use it instead.
    137         ctxt->sc = tsc;
    138         }
    139 
    140     gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    141 
    142     /* Set Anon credentials */
    143     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    144         /* Set x509 credentials */
    145     gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
     78        apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
     79                      APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
     80                      pconf);
     81
     82        _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     83
     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);
     96        }
     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;
     108        }
     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
     131static 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);
    146160
    147161#ifdef ENABLE_SRP
    148         /* Set SRP credentials */
    149     if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
    150         gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
    151     }
    152 #endif
    153 
    154     /* update the priorities - to avoid negotiating a ciphersuite that is not
    155      * enabled on this virtual server. Note that here we ignore the version
    156      * negotiation.
    157      */
    158 
    159     ret = gnutls_priority_set(session, ctxt->sc->priorities);
    160     /* actually it shouldn't fail since we have checked at startup */
    161     return ret;
    162 
    163 }
    164 
    165 static int cert_retrieve_fn(gnutls_session_t session,
    166                                                         const gnutls_datum_t * req_ca_rdn, int nreqs,
    167                                                         const gnutls_pk_algorithm_t * pk_algos, int pk_algos_length,
    168                                                         gnutls_retr2_st *ret) {
    169 
    170 
    171         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    172 
     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
     195static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
     196{
    173197        mgs_handle_t *ctxt;
    174198
    175     if (session == NULL) {
    176                 // ERROR INVALID SESSION
    177                 ret->ncerts = 0;
    178                 ret->deinit_all = 1;
    179         return -1;
    180         }
    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;
    206         }
     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;
    207228}
    208229
    209230/* 2048-bit group parameters from SRP specification */
    210231const char static_dh_params[] = "-----BEGIN 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";
     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";
    218239
    219240/* Read the common name or the alternative name of the certificate.
     
    222243 * Returns negative on error.
    223244 */
    224 static int read_crt_cn(server_rec * s, apr_pool_t * p, gnutls_x509_crt_t cert, char **cert_cn) {
    225 
    226     int rv = 0, i;
    227     size_t data_len;
    228 
    229 
    230     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    231     *cert_cn = NULL;
    232 
    233     data_len = 0;
    234     rv = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &data_len);
    235 
    236     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    237         *cert_cn = apr_palloc(p, data_len);
    238         rv = gnutls_x509_crt_get_dn_by_oid(cert,
    239                 GNUTLS_OID_X520_COMMON_NAME,
    240                 0, 0, *cert_cn,
    241                 &data_len);
    242     } else { /* No CN return subject alternative name */
    243         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    244                 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    245                 s->server_hostname, s->port);
    246         rv = 0;
    247         /* read subject alternative name */
    248         for (i = 0; !(rv < 0); i++) {
    249             data_len = 0;
    250             rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
    251                     NULL,
    252                     &data_len,
    253                     NULL);
    254 
    255             if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
    256                     && data_len > 1) {
    257                 /* FIXME: not very efficient. What if we have several alt names
    258                  * before DNSName?
    259                  */
    260                 *cert_cn = apr_palloc(p, data_len + 1);
    261 
    262                 rv = gnutls_x509_crt_get_subject_alt_name
    263                         (cert, i, *cert_cn, &data_len, NULL);
    264                 (*cert_cn)[data_len] = 0;
    265 
    266                 if (rv == GNUTLS_SAN_DNSNAME)
    267                     break;
    268             }
    269         }
    270     }
    271 
    272     return rv;
     245static 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;
     292                        }
     293                }
     294        }
     295
     296        return rv;
    273297}
    274298
    275299static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
    276         gnutls_openpgp_crt_t cert, char **cert_cn) {
    277     int rv = 0;
    278     size_t data_len;
    279 
    280 
    281     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    282     *cert_cn = NULL;
    283 
    284     data_len = 0;
    285     rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
    286 
    287     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    288         *cert_cn = apr_palloc(p, data_len);
    289         rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
    290                 &data_len);
    291     } else { /* No CN return subject alternative name */
    292         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    293                 "No name found in PGP certificate for '%s:%d'.",
    294                 s->server_hostname, s->port);
    295     }
    296 
    297     return rv;
    298 }
    299 
    300 int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * base_server) {
    301 
    302     int rv;
    303     server_rec *s;
    304     gnutls_dh_params_t dh_params = NULL;
    305     mgs_srvconf_rec *sc;
    306     mgs_srvconf_rec *sc_base;
    307     void *data = NULL;
    308     const char *userdata_key = "mgs_init";
    309 
    310     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    311 
    312     apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
    313     if (data == NULL) {
    314         apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, base_server->process->pool);
    315     }
    316 
    317 
    318     s = base_server;
    319     sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    320 
    321     gnutls_dh_params_init(&dh_params);
    322 
    323     if (sc_base->dh_params == NULL) {
    324         gnutls_datum_t pdata = {
    325             (void *) static_dh_params,
    326             sizeof(static_dh_params)
    327         };
    328         rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, GNUTLS_X509_FMT_PEM);
    329         /* Generate DH Params
    330         int dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
    331                 GNUTLS_SEC_PARAM_NORMAL);
    332         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    333             "GnuTLS: Generating DH Params of %i bits.  "
    334             "To avoid this use GnuTLSDHFile to specify DH Params for this host",
    335             dh_bits);
     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
     326int
     327mgs_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                }
     448#endif
     449
     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
     496void 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
     512const 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
     531apr_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
     552#if USING_2_1_RECENT
     553typedef struct {
     554        mgs_handle_t *ctxt;
     555        mgs_srvconf_rec *sc;
     556        const char *sni_name;
     557} vhost_cb_rec;
     558
     559static 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 */
    336575#if MOD_GNUTLS_DEBUG
    337             ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    338                     "GnuTLS: Generated DH Params of %i bits",dh_bits);
    339 #endif
    340         rv = gnutls_dh_params_generate2 (dh_params,dh_bits);
    341         */
    342         if (rv < 0) {
    343             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    344                     "GnuTLS: Unable to generate or load DH Params: (%d) %s",
    345                     rv, gnutls_strerror(rv));
    346             exit(rv);
    347         }
    348     } else {
    349         dh_params = sc_base->dh_params;
    350     }
    351 
    352     rv = mgs_cache_post_config(p, s, sc_base);
    353     if (rv != 0) {
    354         ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    355                 "GnuTLS: Post Config for GnuTLSCache Failed."
    356                 " Shutting Down.");
    357         exit(-1);
    358     }
    359 
    360     for (s = base_server; s; s = s->next) {
    361         sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    362         sc->cache_type = sc_base->cache_type;
    363         sc->cache_config = sc_base->cache_config;
    364         sc->cache_timeout = sc_base->cache_timeout;
    365 
    366         /* defaults for unset values: */
    367         if (sc->enabled == GNUTLS_ENABLED_UNSET)
    368             sc->enabled = GNUTLS_ENABLED_FALSE;
    369         if (sc->tickets == GNUTLS_ENABLED_UNSET)
    370             sc->tickets = GNUTLS_ENABLED_TRUE;
    371         if (sc->export_certificates_enabled == GNUTLS_ENABLED_UNSET)
    372             sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
    373         if (sc->client_verify_mode ==  -1)
    374             sc->client_verify_mode = GNUTLS_CERT_IGNORE;
    375         if (sc->client_verify_method ==  mgs_cvm_unset)
    376             sc->client_verify_method = mgs_cvm_cartel;
    377 
    378 
    379         /* Check if the priorities have been set */
    380         if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    381             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    382                     "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
    383                     s->server_hostname, s->port);
    384             exit(-1);
    385         }
    386 
    387         /* Check if DH params have been set per host */
    388         if (sc->dh_params != NULL) {
    389             gnutls_certificate_set_dh_params(sc->certs, sc->dh_params);
    390             gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params);
    391         } else if (dh_params) {
    392             gnutls_certificate_set_dh_params(sc->certs, dh_params);
    393             gnutls_anon_set_server_dh_params(sc->anon_creds, dh_params);
    394         }
    395 
    396         gnutls_certificate_set_retrieve_function(sc->certs, cert_retrieve_fn);
    397 
    398 #ifdef ENABLE_SRP
    399         if (sc->srp_tpasswd_conf_file != NULL
    400                 && sc->srp_tpasswd_file != NULL) {
    401             rv = gnutls_srp_set_server_credentials_file
    402                     (sc->srp_creds, sc->srp_tpasswd_file,
    403                     sc->srp_tpasswd_conf_file);
    404 
    405             if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
    406                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
    407                         s,
    408                         "[GnuTLS] - Host '%s:%d' is missing a "
    409                         "SRP password or conf File!",
    410                         s->server_hostname, s->port);
    411                 exit(-1);
    412             }
    413         }
    414 #endif
    415 
    416         if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
    417             sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    418                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    419                                                 "[GnuTLS] - Host '%s:%d' is missing a Certificate File!",
    420                                                 s->server_hostname, s->port);
    421             exit(-1);
    422         }
    423 
    424         if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    425             ((sc->certs_x509_chain != NULL && sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
    426              (sc->cert_pgp != NULL && sc->privkey_pgp == NULL))) {
    427                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    428                                                 "[GnuTLS] - Host '%s:%d' is missing a Private Key File!",
    429                                                 s->server_hostname, s->port);
    430             exit(-1);
    431         }
    432 
    433         if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    434             rv = -1;
    435             if (sc->certs_x509_chain_num > 0) {
    436                 rv = read_crt_cn(s, p, sc->certs_x509_chain[0], &sc->cert_cn);
    437             }
    438             if (rv < 0 && sc->cert_pgp != NULL) {
    439                 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
    440                         }
    441 
    442             if (rv < 0) {
    443                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    444                                                         "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
    445                                                         s->server_hostname, s->port);
    446                 sc->cert_cn = NULL;
    447                 continue;
    448             }
    449         }
    450     }
    451 
    452 
    453     ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
    454 
    455     {
    456         const char* libvers = gnutls_check_version(NULL);
    457         char* gnutls_version = NULL;
    458         if(libvers && (gnutls_version = apr_psprintf(p, "GnuTLS/%s", libvers))) {
    459             ap_add_version_component(p, gnutls_version);
    460         } else {
    461             // In case we could not create the above string go for the static version instead
    462             ap_add_version_component(p, "GnuTLS/" GNUTLS_VERSION "-static");
    463         }
    464     }
    465 
    466     return OK;
    467 }
    468 
    469 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) {
    470     apr_status_t rv = APR_SUCCESS;
    471     mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
    472             &gnutls_module);
    473 
    474     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    475     if (sc->cache_type != mgs_cache_none) {
    476         rv = mgs_cache_child_init(p, s, sc);
    477         if (rv != APR_SUCCESS) {
    478             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    479                     "[GnuTLS] - Failed to run Cache Init");
    480         }
    481     }
    482     /* Block SIGPIPE Signals */
    483     rv = apr_signal_block(SIGPIPE);
    484     if(rv != APR_SUCCESS) {
    485         /* error sending output */
    486         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    487                 "GnuTLS: Error Blocking SIGPIPE Signal!");
    488     }
    489 }
    490 
    491 const char *mgs_hook_http_scheme(const request_rec * r) {
    492     mgs_srvconf_rec *sc;
    493 
    494     if (r == NULL)
    495         return NULL;
    496 
    497     sc = (mgs_srvconf_rec *) ap_get_module_config(r->
    498             server->module_config,
    499             &gnutls_module);
    500 
    501     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    502     if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    503         return NULL;
    504     }
    505 
    506     return "https";
    507 }
    508 
    509 apr_port_t mgs_hook_default_port(const request_rec * r) {
    510     mgs_srvconf_rec *sc;
    511 
    512     if (r == NULL)
    513         return 0;
    514 
    515     sc = (mgs_srvconf_rec *) ap_get_module_config(r->
    516             server->module_config,
    517             &gnutls_module);
    518 
    519     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    520     if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    521         return 0;
    522     }
    523 
    524     return 443;
    525 }
    526 
    527 #define MAX_HOST_LEN 255
    528 
     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);
     580#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
     603mgs_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;
    529610#if USING_2_1_RECENT
    530 
    531 typedef struct {
    532     mgs_handle_t *ctxt;
    533     mgs_srvconf_rec *sc;
    534     const char *sni_name;
    535 } vhost_cb_rec;
    536 
    537 /**
    538  * Matches the current vhost's ServerAlias directives
    539  *
    540  * @param x vhost callback record
    541  * @param s server record
    542  * @return true if a match, false otherwise
    543  *
    544  */
    545 int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc) {
    546         apr_array_header_t *names;
    547         int i,rv = 0;
    548         char ** name;
    549 
    550         /* Check ServerName First! */
    551         if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) {
    552                 // We have a match, save this server configuration
    553                 x->sc = tsc;
    554                 rv = 1;
    555         /* Check any ServerAlias directives */
    556         } else if(s->names->nelts) {
    557                 names = s->names;
    558                 name = (char **)names->elts;
    559                 for (i = 0; i < names->nelts; ++i) {
    560                         if (!name[i]) { continue; }
    561                                 if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) {
    562                                         // We have a match, save this server configuration
    563                                         x->sc = tsc;
    564                                         rv = 1;
    565                         }
    566                 }
    567         /* Wild any ServerAlias Directives */
    568         } else if(s->wild_names->nelts) {
    569                 names = s->wild_names;
    570         name = (char **)names->elts;
    571                 for (i = 0; i < names->nelts; ++i) {
    572                         if (!name[i]) { continue; }
    573                                 if(apr_fnmatch(name[i], x->sni_name ,
    574                                                                 APR_FNM_CASE_BLIND|
    575                                                                 APR_FNM_PERIOD|
    576                                                                 APR_FNM_PATHNAME|
    577                                                                 APR_FNM_NOESCAPE) == APR_SUCCESS) {
    578                                 x->sc = tsc;
    579                                 rv = 1;
    580                         }
    581                 }
    582         }
    583         return rv;
    584 }
    585 
    586 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) {
    587     mgs_srvconf_rec *tsc;
    588     vhost_cb_rec *x = baton;
    589     int ret;
    590 
    591     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    592     tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    593             &gnutls_module);
    594 
    595     if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
    596         return 0;
    597     }
    598 
    599     if (tsc->certs_x509_chain_num > 0) {
    600         /* why are we doing this check? */
    601         ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_chain[0], s->server_hostname);
    602         if (0 == ret)
    603             ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    604                          "GnuTLS: Error checking certificate for hostname "
    605                          "'%s'", s->server_hostname);
    606     } else {
    607         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    608                      "GnuTLS: SNI request for '%s' but no X.509 certs available at all",
    609                      s->server_hostname);
    610     }
    611         return check_server_aliases(x, s, tsc);
    612 }
    613 #endif
    614 
    615 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) {
    616     int rv;
    617     unsigned int sni_type;
    618     size_t data_len = MAX_HOST_LEN;
    619     char sni_name[MAX_HOST_LEN];
    620     mgs_handle_t *ctxt;
    621 #if USING_2_1_RECENT
    622     vhost_cb_rec cbx;
     611        vhost_cb_rec cbx;
    623612#else
    624     server_rec *s;
    625     mgs_srvconf_rec *tsc;
    626 #endif
    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     }
     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        }
    648637
    649638    /**
     
    652641     */
    653642#if USING_2_1_RECENT
    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     }
     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;
     650        }
    662651#else
    663     for (s = ap_server_conf; s; s = s->next) {
    664 
    665         tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    666                 &gnutls_module);
    667 
    668         if (tsc->enabled != GNUTLS_ENABLED_TRUE) { continue; }
    669 
    670                                 if(check_server_aliases(x, s, tsc)) {
    671                                         return tsc;
    672                                 }
    673 #endif
    674     return NULL;
    675 }
    676 
    677 static void create_gnutls_handle(conn_rec * c) {
    678     mgs_handle_t *ctxt;
    679     /* Get mod_gnutls Configuration Record */
    680     mgs_srvconf_rec *sc =(mgs_srvconf_rec *)
    681             ap_get_module_config(c->base_server->module_config,&gnutls_module);
    682 
    683     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    684     ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
    685     ctxt->c = c;
    686     ctxt->sc = sc;
    687     ctxt->status = 0;
    688     ctxt->input_rc = APR_SUCCESS;
    689     ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
    690     ctxt->input_cbuf.length = 0;
    691     ctxt->output_rc = APR_SUCCESS;
    692     ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
    693     ctxt->output_blen = 0;
    694     ctxt->output_length = 0;
    695     /* Initialize GnuTLS Library */
    696     gnutls_init(&ctxt->session, GNUTLS_SERVER);
    697     /* Initialize Session Tickets */
    698     if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) {
    699         gnutls_session_ticket_enable_server(ctxt->session,&session_ticket_key);
    700     }
    701 
    702     /* Set Default Priority */
    703         gnutls_priority_set_direct (ctxt->session, "NORMAL", NULL);
    704     /* Set Handshake function */
    705     gnutls_handshake_set_post_client_hello_function(ctxt->session,
    706             mgs_select_virtual_server_cb);
    707     /* Initialize Session Cache */
    708     mgs_cache_session_init(ctxt);
    709 
    710     /* Set this config for this connection */
    711     ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
    712     /* Set pull, push & ptr functions */
    713     gnutls_transport_set_pull_function(ctxt->session,
    714             mgs_transport_read);
    715     gnutls_transport_set_push_function(ctxt->session,
    716             mgs_transport_write);
    717     gnutls_transport_set_ptr(ctxt->session, ctxt);
    718     /* Add IO filters */
    719     ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME,
    720             ctxt, NULL, c);
    721     ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
    722             ctxt, NULL, c);
    723 }
    724 
    725 int mgs_hook_pre_connection(conn_rec * c, void *csd) {
    726     mgs_srvconf_rec *sc;
    727 
    728     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    729 
    730     sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->module_config,
    731             &gnutls_module);
    732 
    733     if (sc && (!sc->enabled || sc->proxy_enabled == GNUTLS_ENABLED_TRUE)) {
    734         return DECLINED;
    735     }
    736 
    737     create_gnutls_handle(c);
    738     return OK;
    739 }
    740 
    741 int mgs_hook_fixups(request_rec * r) {
    742     unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
    743     char buf[AP_IOBUFSIZE];
    744     const char *tmp;
    745     size_t len;
    746     mgs_handle_t *ctxt;
    747     int rv = OK;
    748 
    749     if (r == NULL)
    750         return DECLINED;
    751 
    752     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    753     apr_table_t *env = r->subprocess_env;
    754 
    755     ctxt =
    756             ap_get_module_config(r->connection->conn_config,
    757             &gnutls_module);
    758 
    759     if (!ctxt || ctxt->session == NULL) {
    760         return DECLINED;
    761     }
    762 
    763     apr_table_setn(env, "HTTPS", "on");
    764 
    765     apr_table_setn(env, "SSL_VERSION_LIBRARY",
    766             "GnuTLS/" LIBGNUTLS_VERSION);
    767     apr_table_setn(env, "SSL_VERSION_INTERFACE",
    768             "mod_gnutls/" MOD_GNUTLS_VERSION);
    769 
    770     apr_table_setn(env, "SSL_PROTOCOL",
    771             gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
    772 
    773     /* should have been called SSL_CIPHERSUITE instead */
    774     apr_table_setn(env, "SSL_CIPHER",
    775             gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session),
    776                                          gnutls_cipher_get(ctxt->session),
    777                                          gnutls_mac_get(ctxt->session)));
    778 
    779     apr_table_setn(env, "SSL_COMPRESS_METHOD",
    780             gnutls_compression_get_name(gnutls_compression_get(ctxt->session)));
     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                }
     660#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);
     669#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
     687static const int protocol_priority[] = {
     688        GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
     689};
     690
     691
     692static 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
     734int 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
     776int 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)));
    781822
    782823#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);
    819         }
    820 
    821     return rv;
    822 }
    823 
    824 int mgs_hook_authz(request_rec * r) {
    825     int rv;
    826     mgs_handle_t *ctxt;
    827     mgs_dirconf_rec *dc;
    828 
    829     if (r == NULL)
    830         return DECLINED;
    831 
    832     dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
    833 
    834     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    835     ctxt =
    836             ap_get_module_config(r->connection->conn_config,
    837             &gnutls_module);
    838 
    839     if (!ctxt || ctxt->session == NULL) {
    840         return DECLINED;
    841     }
    842 
    843     if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
    844         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    845                 "GnuTLS: Directory set to Ignore Client Certificate!");
    846     } else {
    847         if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
    848             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    849                     "GnuTLS: Attempting to rehandshake with peer. %d %d",
    850                     ctxt->sc->client_verify_mode,
    851                     dc->client_verify_mode);
    852 
    853             /* If we already have a client certificate, there's no point in
    854              * re-handshaking... */
    855             rv = mgs_cert_verify(r, ctxt);
    856             if (rv != DECLINED && rv != HTTP_FORBIDDEN)
    857                 return rv;
    858 
    859             gnutls_certificate_server_set_request
    860                     (ctxt->session, dc->client_verify_mode);
    861 
    862             if (mgs_rehandshake(ctxt) != 0) {
    863                 return HTTP_FORBIDDEN;
    864             }
    865         } else if (ctxt->sc->client_verify_mode ==
    866                 GNUTLS_CERT_IGNORE) {
     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
     861int 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) {
    867905#if MOD_GNUTLS_DEBUG
    868             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    869                     "GnuTLS: Peer is set to IGNORE");
    870 #endif
    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;
     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;
    882920}
    883921
     
    888926 */
    889927
    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.
     928/* side is either 0 for SERVER or 1 for CLIENT
    894929 */
    895930#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
    896 
    897 static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, int export_full_cert) {
    898     unsigned char sbuf[64]; /* buffer to hold serials */
    899     char buf[AP_IOBUFSIZE];
    900     const char *tmp;
    901     char *tmp2;
    902     size_t len;
    903     int ret, i;
    904 
    905     if (r == NULL)
    906         return;
    907 
    908     apr_table_t *env = r->subprocess_env;
    909 
    910     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    911     if (export_full_cert != 0) {
    912         char cert_buf[10 * 1024];
    913         len = sizeof (cert_buf);
    914 
    915         if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
    916             apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
    917                            apr_pstrmemdup(r->pool, cert_buf, len));
    918         else
    919             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    920                           "GnuTLS: Failed to export X.509 certificate to environment");
    921     }
    922 
    923     len = sizeof (buf);
    924     gnutls_x509_crt_get_dn(cert, buf, &len);
    925     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
    926             apr_pstrmemdup(r->pool, buf, len));
    927 
    928     len = sizeof (buf);
    929     gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
    930     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
    931             apr_pstrmemdup(r->pool, buf, len));
    932 
    933     len = sizeof (sbuf);
    934     gnutls_x509_crt_get_serial(cert, sbuf, &len);
    935     tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
    936     apr_table_setn(env,
    937             apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
    938             apr_pstrdup(r->pool, tmp));
    939 
    940     ret = gnutls_x509_crt_get_version(cert);
    941     if (ret > 0)
    942         apr_table_setn(env,
    943             apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
    944             NULL), apr_psprintf(r->pool,
    945             "%u", ret));
    946 
    947     apr_table_setn(env,
    948             apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
    949             "X.509");
    950 
    951     tmp =
    952             mgs_time2sz(gnutls_x509_crt_get_expiration_time
    953             (cert), buf, sizeof (buf));
    954     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    955             apr_pstrdup(r->pool, tmp));
    956 
    957     tmp =
    958             mgs_time2sz(gnutls_x509_crt_get_activation_time
    959             (cert), buf, sizeof (buf));
    960     apr_table_setn(env,
    961             apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
    962             apr_pstrdup(r->pool, tmp));
    963 
    964     ret = gnutls_x509_crt_get_signature_algorithm(cert);
    965     if (ret >= 0) {
    966         apr_table_setn(env,
    967                 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
    968                 NULL),
    969                 gnutls_sign_algorithm_get_name(ret));
    970     }
    971 
    972     ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
    973     if (ret >= 0) {
    974         apr_table_setn(env,
    975                 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    976                 NULL),
    977                 gnutls_pk_algorithm_get_name(ret));
    978     }
    979 
    980     /* export all the alternative names (DNS, RFC822 and URI) */
    981     for (i = 0; !(ret < 0); i++) {
    982         len = 0;
    983         ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
    984                 NULL, &len,
    985                 NULL);
    986 
    987         if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
    988             tmp2 = apr_palloc(r->pool, len + 1);
    989 
    990             ret =
    991                     gnutls_x509_crt_get_subject_alt_name(cert, i,
    992                     tmp2,
    993                     &len,
    994                     NULL);
    995             tmp2[len] = 0;
    996 
    997             if (ret == GNUTLS_SAN_DNSNAME) {
    998                 apr_table_setn(env,
    999                         apr_psprintf(r->pool,
    1000                         "%s_S_AN%u",
    1001                         MGS_SIDE, i),
    1002                         apr_psprintf(r->pool,
    1003                         "DNSNAME:%s",
    1004                         tmp2));
    1005             } else if (ret == GNUTLS_SAN_RFC822NAME) {
    1006                 apr_table_setn(env,
    1007                         apr_psprintf(r->pool,
    1008                         "%s_S_AN%u",
    1009                         MGS_SIDE, i),
    1010                         apr_psprintf(r->pool,
    1011                         "RFC822NAME:%s",
    1012                         tmp2));
    1013             } else if (ret == GNUTLS_SAN_URI) {
    1014                 apr_table_setn(env,
    1015                         apr_psprintf(r->pool,
    1016                         "%s_S_AN%u",
    1017                         MGS_SIDE, i),
    1018                         apr_psprintf(r->pool,
    1019                         "URI:%s",
    1020                         tmp2));
    1021             } else {
    1022                 apr_table_setn(env,
    1023                         apr_psprintf(r->pool,
    1024                         "%s_S_AN%u",
    1025                         MGS_SIDE, i),
    1026                         "UNSUPPORTED");
    1027             }
    1028         }
    1029     }
    1030 }
    1031 
    1032 
    1033 /* @param side 0: server, 1: client
    1034  *
    1035  * @param export_full_cert (boolean) export the PEM-encoded
    1036  * certificate in full as an environment variable.
    1037  */
    1038 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert) {
    1039 
    1040         unsigned char sbuf[64]; /* buffer to hold serials */
    1041     char buf[AP_IOBUFSIZE];
    1042     const char *tmp;
    1043     size_t len;
    1044     int ret;
    1045 
    1046     if (r == NULL)
    1047         return;
    1048 
    1049     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1050     apr_table_t *env = r->subprocess_env;
    1051 
    1052     if (export_full_cert != 0) {
    1053         char cert_buf[10 * 1024];
    1054         len = sizeof (cert_buf);
    1055 
    1056         if (gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
    1057             apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
    1058                            apr_pstrmemdup(r->pool, cert_buf, len));
    1059         else
    1060             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1061                           "GnuTLS: Failed to export OpenPGP certificate to environment");
    1062     }
    1063 
    1064     len = sizeof (buf);
    1065     gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
    1066     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
    1067             apr_pstrmemdup(r->pool, buf, len));
    1068 
    1069     len = sizeof (sbuf);
    1070     gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
    1071     tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
    1072     apr_table_setn(env,
    1073             apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
    1074             NULL), apr_pstrdup(r->pool, tmp));
    1075 
    1076     ret = gnutls_openpgp_crt_get_version(cert);
    1077     if (ret > 0)
    1078         apr_table_setn(env,
    1079             apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
    1080             NULL), apr_psprintf(r->pool,
    1081             "%u", ret));
    1082 
    1083     apr_table_setn(env,
    1084             apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
    1085             "OPENPGP");
    1086 
    1087     tmp =
    1088             mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
    1089             (cert), buf, sizeof (buf));
    1090     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    1091             apr_pstrdup(r->pool, tmp));
    1092 
    1093     tmp =
    1094             mgs_time2sz(gnutls_openpgp_crt_get_creation_time
    1095             (cert), buf, sizeof (buf));
    1096     apr_table_setn(env,
    1097             apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
    1098             apr_pstrdup(r->pool, tmp));
    1099 
    1100     ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
    1101     if (ret >= 0) {
    1102         apr_table_setn(env,
    1103                 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    1104                 NULL),
    1105                 gnutls_pk_algorithm_get_name(ret));
    1106     }
     931static void
     932mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
     933                         int export_certificates_enabled)
     934{
     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
     1071static void
     1072mgs_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
     1087        if (export_certificates_enabled != 0) {
     1088                char cert_buf[10 * 1024];
     1089                len = sizeof(cert_buf);
     1090
     1091                if (gnutls_openpgp_crt_export
     1092                    (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
     1093                        apr_table_setn(env,
     1094                                       apr_pstrcat(r->pool, MGS_SIDE,
     1095                                                   "_CERT", NULL),
     1096                                       apr_pstrmemdup(r->pool, cert_buf,
     1097                                                      len));
     1098
     1099        }
     1100
     1101        len = sizeof(buf);
     1102        gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
     1103        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
     1104                       apr_pstrmemdup(r->pool, buf, len));
     1105
     1106        len = sizeof(sbuf);
     1107        gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
     1108        tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
     1109        apr_table_setn(env,
     1110                       apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
     1111                                   NULL), apr_pstrdup(r->pool, tmp));
     1112
     1113        ret = gnutls_openpgp_crt_get_version(cert);
     1114        if (ret > 0)
     1115                apr_table_setn(env,
     1116                               apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     1117                                           NULL), apr_psprintf(r->pool,
     1118                                                               "%u", ret));
     1119
     1120        apr_table_setn(env,
     1121                       apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     1122                       "OPENPGP");
     1123
     1124        tmp =
     1125            mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
     1126                        (cert), buf, sizeof(buf));
     1127        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     1128                       apr_pstrdup(r->pool, tmp));
     1129
     1130        tmp =
     1131            mgs_time2sz(gnutls_openpgp_crt_get_creation_time
     1132                        (cert), buf, sizeof(buf));
     1133        apr_table_setn(env,
     1134                       apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     1135                       apr_pstrdup(r->pool, tmp));
     1136
     1137        ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
     1138        if (ret >= 0) {
     1139                apr_table_setn(env,
     1140                               apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     1141                                           NULL),
     1142                               gnutls_pk_algorithm_get_name(ret));
     1143        }
    11071144
    11081145}
    11091146
    11101147/* TODO: Allow client sending a X.509 certificate chain */
    1111 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) {
    1112     const gnutls_datum_t *cert_list;
    1113     unsigned int cert_list_size, status;
    1114     int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
    1115     unsigned int ch_size = 0;
    1116 
    1117     union {
    1118         gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
    1119         gnutls_openpgp_crt_t pgp;
    1120     } cert;
    1121     apr_time_t expiration_time, cur_time;
    1122 
    1123     if (r == NULL || ctxt == NULL || ctxt->session == NULL)
    1124         return HTTP_FORBIDDEN;
    1125 
    1126     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1127     cert_list =
    1128             gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
    1129 
    1130     if (cert_list == NULL || cert_list_size == 0) {
    1131         /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
    1132          */
    1133         if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
    1134             return OK;
    1135 
    1136         /* no certificate provided by the client, but one was required. */
    1137         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1138                 "GnuTLS: Failed to Verify Peer: "
    1139                 "Client did not submit a certificate");
    1140         return HTTP_FORBIDDEN;
    1141     }
    1142 
    1143     if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1144         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1145                 "GnuTLS: A Chain of %d certificate(s) was provided for validation",
    1146                 cert_list_size);
    1147 
    1148         for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
    1149             gnutls_x509_crt_init(&cert.x509[ch_size]);
    1150             rv = gnutls_x509_crt_import(cert.x509[ch_size],
    1151                     &cert_list[ch_size],
    1152                     GNUTLS_X509_FMT_DER);
    1153             // When failure to import, leave the loop
    1154             if (rv != GNUTLS_E_SUCCESS) {
    1155                 if (ch_size < 1) {
    1156                     ap_log_rerror(APLOG_MARK,
    1157                             APLOG_INFO, 0, r,
    1158                             "GnuTLS: Failed to Verify Peer: "
    1159                             "Failed to import peer certificates.");
    1160                     ret = HTTP_FORBIDDEN;
    1161                     goto exit;
    1162                 }
    1163                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1164                         "GnuTLS: Failed to import some peer certificates. Using %d certificates",
    1165                         ch_size);
    1166                 rv = GNUTLS_E_SUCCESS;
    1167                 break;
    1168             }
    1169         }
    1170     } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
    1171         if (cert_list_size > 1) {
    1172             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1173                     "GnuTLS: Failed to Verify Peer: "
    1174                     "Chained Client Certificates are not supported.");
    1175             return HTTP_FORBIDDEN;
    1176         }
    1177 
    1178         gnutls_openpgp_crt_init(&cert.pgp);
    1179         rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
    1180                 GNUTLS_OPENPGP_FMT_RAW);
    1181 
    1182     } else
    1183         return HTTP_FORBIDDEN;
    1184 
    1185     if (rv < 0) {
    1186         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1187                 "GnuTLS: Failed to Verify Peer: "
    1188                 "Failed to import peer certificates.");
    1189         ret = HTTP_FORBIDDEN;
    1190         goto exit;
    1191     }
    1192 
    1193     if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1194         apr_time_ansi_put(&expiration_time,
    1195                 gnutls_x509_crt_get_expiration_time
    1196                 (cert.x509[0]));
    1197 
    1198         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1199                       "GnuTLS: Verifying list of %d certificate(s) via method '%s'",
    1200                       ch_size, mgs_readable_cvm(ctxt->sc->client_verify_method));
    1201         switch(ctxt->sc->client_verify_method) {
    1202         case mgs_cvm_cartel:
    1203             rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
    1204                                              ctxt->sc->ca_list,
    1205                                              ctxt->sc->ca_list_size,
    1206                                              NULL, 0, 0, &status);
    1207             break;
    1208 #ifdef ENABLE_MSVA
    1209         case mgs_cvm_msva:
    1210         {
    1211             struct msv_response* resp = NULL;
    1212             struct msv_query q = { .context="https", .peertype="client", .pkctype="x509pem" };
    1213             msv_ctxt_t ctx = msv_ctxt_init(NULL);
    1214             char cert_pem_buf[10 * 1024];
    1215             size_t len = sizeof (cert_pem_buf);
    1216 
    1217             rv = 0;
    1218             if (gnutls_x509_crt_export(cert.x509[0], GNUTLS_X509_FMT_PEM, cert_pem_buf, &len) >= 0) {
    1219                 /* FIXME : put together a name from the cert we received, instead of hard-coding this value: */
    1220                 q.peername = mgs_x509_construct_uid(r, cert.x509[0]);
    1221                 q.pkcdata = cert_pem_buf;
    1222                 rv = msv_query_agent(ctx, q, &resp);
    1223                 if (rv == LIBMSV_ERROR_SUCCESS) {
    1224                     status = 0;
    1225                 } else if (rv == LIBMSV_ERROR_INVALID) {
    1226                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1227                                   "GnuTLS: Monkeysphere validation failed: (message: %s)", resp->message);
    1228                     status = GNUTLS_CERT_INVALID;
    1229                 } else {
    1230                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1231                                   "GnuTLS: Error communicating with the Monkeysphere Validation Agent: (%d) %s", rv, msv_strerror(ctx, rv));
    1232                     status = GNUTLS_CERT_INVALID;
    1233                     rv = -1;
    1234                 }
    1235             } else {
    1236                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1237                               "GnuTLS: Could not convert the client certificate to PEM format");
    1238                 status = GNUTLS_CERT_INVALID;
    1239                 rv = GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
    1240             }
    1241             msv_response_destroy(resp);
    1242             msv_ctxt_destroy(ctx);
    1243         }
    1244             break;
    1245 #endif
    1246         default:
    1247             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1248                           "GnuTLS: Failed to Verify X.509 Peer: method '%s' is not supported",
    1249                           mgs_readable_cvm(ctxt->sc->client_verify_method));
    1250         }
    1251 
    1252     } else {
    1253         apr_time_ansi_put(&expiration_time,
    1254                 gnutls_openpgp_crt_get_expiration_time
    1255                 (cert.pgp));
    1256 
    1257         switch(ctxt->sc->client_verify_method) {
    1258         case mgs_cvm_cartel:
    1259             rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
    1260                                                 ctxt->sc->pgp_list, 0,
    1261                                                 &status);
    1262             break;
    1263 #ifdef ENABLE_MSVA
    1264         case mgs_cvm_msva:
    1265             /* need to set status and rv */
    1266             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1267                           "GnuTLS:  OpenPGP verification via MSVA is not yet implemented");
    1268             rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    1269             break;
    1270 #endif
    1271         default:
    1272             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1273                           "GnuTLS: Failed to Verify OpenPGP Peer: method '%s' is not supported",
    1274                           mgs_readable_cvm(ctxt->sc->client_verify_method));
    1275         }
    1276     }
    1277 
    1278     if (rv < 0) {
    1279         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1280                 "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
    1281                 rv, gnutls_strerror(rv));
    1282         if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
    1283             ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
    1284                 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
    1285         ret = HTTP_FORBIDDEN;
    1286         goto exit;
    1287     }
    1288 
    1289     /* TODO: X509 CRL Verification. */
    1290     /* May add later if anyone needs it.
    1291      */
    1292     /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
    1293 
    1294     cur_time = apr_time_now();
    1295 
    1296     if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
    1297         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1298                 "GnuTLS: Could not find Signer for Peer Certificate");
    1299     }
    1300 
    1301     if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
    1302         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1303                 "GnuTLS: Peer's Certificate signer is not a CA");
    1304     }
    1305 
    1306     if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
    1307         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1308                 "GnuTLS: Peer's Certificate is using insecure algorithms");
    1309     }
    1310 
    1311     if (status & GNUTLS_CERT_EXPIRED
    1312             || status & GNUTLS_CERT_NOT_ACTIVATED) {
    1313         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1314                 "GnuTLS: Peer's Certificate signer is expired or not yet activated");
    1315     }
    1316 
    1317     if (status & GNUTLS_CERT_INVALID) {
    1318         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1319                 "GnuTLS: Peer Certificate is invalid.");
    1320     } else if (status & GNUTLS_CERT_REVOKED) {
    1321         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1322                 "GnuTLS: Peer Certificate is revoked.");
    1323     }
    1324 
    1325     if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    1326         mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_enabled);
    1327     else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP)
    1328         mgs_add_common_pgpcert_vars(r, cert.pgp, 1, ctxt->sc->export_certificates_enabled);
    1329 
    1330     {
    1331         /* days remaining */
    1332         unsigned long remain =
    1333                 (apr_time_sec(expiration_time) -
    1334                 apr_time_sec(cur_time)) / 86400;
    1335         apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
    1336                 apr_psprintf(r->pool, "%lu", remain));
    1337     }
    1338 
    1339     if (status == 0) {
    1340         apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
    1341                 "SUCCESS");
    1342         ret = OK;
    1343     } else {
    1344         apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
    1345                 "FAILED");
    1346         if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
    1347             ret = OK;
    1348         else
    1349             ret = HTTP_FORBIDDEN;
    1350     }
    1351 
    1352 exit:
    1353     if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1354         int i;
    1355         for (i = 0; i < ch_size; i++) {
    1356             gnutls_x509_crt_deinit(cert.x509[i]);
    1357         }
    1358     } else if (gnutls_certificate_type_get(ctxt->session) ==
    1359             GNUTLS_CRT_OPENPGP)
    1360         gnutls_openpgp_crt_deinit(cert.pgp);
    1361     return ret;
    1362 
    1363 
    1364 }
    1365 
    1366 static const char* mgs_x509_leaf_oid_from_dn(apr_pool_t *pool, const char* oid, gnutls_x509_crt_t cert) {
    1367     int rv=GNUTLS_E_SUCCESS, i;
    1368     size_t sz=0, lastsz=0;
    1369     char* data=NULL;
    1370 
    1371     i = -1;
    1372     while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
    1373         i++;
    1374         lastsz=sz;
    1375         sz=0;
    1376         rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i, 0, NULL, &sz);
    1377     }
    1378     if (i > 0) {
    1379         data = apr_palloc(pool, lastsz);
    1380         sz=lastsz;
    1381         rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i-1, 0, data, &sz);
    1382         if (rv == GNUTLS_E_SUCCESS)
    1383             return data;
    1384     }
    1385     return NULL;
    1386 }
    1387 
    1388 static const char* mgs_x509_first_type_from_san(apr_pool_t *pool, gnutls_x509_subject_alt_name_t target, gnutls_x509_crt_t cert) {
    1389     int rv=GNUTLS_E_SUCCESS;
    1390     size_t sz;
    1391     char* data=NULL;
    1392     unsigned int i;
    1393     gnutls_x509_subject_alt_name_t thistype;
    1394 
    1395     i = 0;
    1396     while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
    1397         sz = 0;
    1398         rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, NULL, &sz, &thistype, NULL);
    1399         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && thistype == target) {
    1400             data = apr_palloc(pool, sz);
    1401             rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, data, &sz, &thistype, NULL);
    1402             if (rv == target)
    1403                 return data;
    1404         }
    1405         i++;
    1406     }
    1407     return NULL;
    1408 }
    1409 
    1410 /* Create a string representing a candidate User ID from an X.509
    1411  * certificate
    1412 
    1413  * We need this for client certification because a client gives us a
    1414  * certificate, but doesn't tell us (in any other way) who they are
    1415  * trying to authenticate as.
    1416 
    1417  * TODO: we might need another parallel for OpenPGP, but for that it's
    1418  * much simpler: we can just assume that the first User ID marked as
    1419  * "primary" (or the first User ID, period) is the identity the user
    1420  * is trying to present as.
    1421 
    1422  * one complaint might be "but the user wanted to be another identity,
    1423  * which is also in the certificate (e.g. in a SubjectAltName)"
    1424  * However, given that any user can regenerate their own X.509
    1425  * certificate with their own public key content, they should just do
    1426  * so, and not expect us to guess at their identity :)
    1427 
    1428  * This function allocates it's response from the pool given it.  When
    1429  * that pool is reclaimed, the response will also be deallocated.
    1430 
    1431  * FIXME: what about extracting a server-style cert
    1432  *        (e.g. https://imposter.example) from the DN or any sAN?
    1433 
    1434  * FIXME: what if we want to call this outside the context of a
    1435  *        request?  That complicates the logging.
    1436  */
    1437 static const char* mgs_x509_construct_uid(request_rec *r, gnutls_x509_crt_t cert) {
    1438     /* basic strategy, assuming humans are the users: we are going to
    1439      * try to reconstruct a "conventional" User ID by pulling in a
    1440      * name, comment, and e-mail address.
    1441      */
    1442     apr_pool_t *pool = r->pool;
    1443     const char *name=NULL, *comment=NULL, *email=NULL;
    1444     const char *ret=NULL;
    1445     /* subpool for temporary allocation: */
    1446     apr_pool_t *sp=NULL;
    1447 
    1448     if (APR_SUCCESS != apr_pool_create(&sp, pool))
    1449         return NULL; /* i'm assuming that libapr would log this kind
    1450                       * of error on its own */
    1451 
    1452      /* Name
    1453 
    1454      the name comes from the leaf commonName of the cert's Subject.
    1455 
    1456      (MAYBE: should we look at trying to assemble a candidate from
    1457              givenName, surName, suffix, etc?  the "name" field
    1458              appears to be case-insensitive, which seems problematic
    1459              from what we expect; see:
    1460              http://www.itu.int/rec/T-REC-X.520-200102-s/e )
    1461 
    1462      (MAYBE: should we try pulling a commonName or otherName or
    1463              something from subjectAltName? see:
    1464              https://tools.ietf.org/html/rfc5280#section-4.2.1.6
    1465              GnuTLS does not support looking for Common Names in the
    1466              SAN yet)
    1467      */
    1468     name = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_COMMON_NAME, cert);
    1469 
    1470     /* Comment
    1471 
    1472        I am inclined to punt on this for now, as Comment has been so
    1473        atrociously misused in OpenPGP.  Perhaps if there is a
    1474        pseudonym (OID 2.5.4.65, aka GNUTLS_OID_X520_PSEUDONYM) field
    1475        in the subject or sAN?
    1476     */
    1477     comment = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_PSEUDONYM, cert);
    1478 
    1479     /* E-mail
    1480 
    1481        This should be the the first rfc822Name from the sAN.
    1482 
    1483        failing that, we'll take the leaf email in the certificate's
    1484        subject; this is a deprecated use though.
    1485      */
    1486     email = mgs_x509_first_type_from_san(sp, GNUTLS_SAN_RFC822NAME, cert);
    1487     if (email == NULL)
    1488         email = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_PKCS9_EMAIL, cert);
    1489 
    1490     /* assemble all the parts: */
    1491 
    1492     /* must have at least a name or an e-mail. */
    1493     if (name == NULL && email == NULL) {
    1494         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1495                 "GnuTLS: Need either a name or an e-mail address to get a User ID from an X.509 certificate.");
    1496         goto end;
    1497     }
    1498     if (name) {
    1499         if (comment) {
    1500             if (email) {
    1501                 ret = apr_psprintf(pool, "%s (%s) <%s>", name, comment, email);
    1502             } else {
    1503                 ret = apr_psprintf(pool, "%s (%s)", name, comment);
    1504             }
    1505         } else {
    1506             if (email) {
    1507                 ret = apr_psprintf(pool, "%s <%s>", name, email);
    1508             } else {
    1509                 ret = apr_pstrdup(pool, name);
    1510             }
    1511         }
    1512     } else {
    1513         if (comment) {
    1514             ret = apr_psprintf(pool, "(%s) <%s>", comment, email);
    1515         } else {
    1516             ret = apr_psprintf(pool, "<%s>", email);
    1517         }
    1518     }
    1519 
    1520 end:
    1521     apr_pool_destroy(sp);
    1522     return ret;
    1523 }
    1524 
    1525 static int mgs_status_hook(request_rec *r, int flags)
    1526 {
    1527     mgs_srvconf_rec *sc;
    1528 
    1529     if (r == NULL)
    1530         return OK;
    1531 
    1532     sc = (mgs_srvconf_rec *) ap_get_module_config(r->server->module_config, &gnutls_module);
    1533 
    1534     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1535 
    1536     ap_rputs("<hr>\n", r);
    1537     ap_rputs("<h2>GnuTLS Information:</h2>\n<dl>\n", r);
    1538 
    1539     ap_rprintf(r, "<dt>GnuTLS version:</dt><dd>%s</dd>\n", gnutls_check_version(NULL));
    1540     ap_rputs("<dt>Built against:</dt><dd>" GNUTLS_VERSION "</dd>\n", r);
    1541     ap_rprintf(r, "<dt>using TLS:</dt><dd>%s</dd>\n", (sc->enabled == GNUTLS_ENABLED_FALSE ? "no" : "yes"));
    1542     if (sc->enabled != GNUTLS_ENABLED_FALSE) {
    1543         mgs_handle_t* ctxt;
    1544         ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
    1545         if (ctxt && ctxt->session != NULL) {
    1546 #if GNUTLS_VERSION_MAJOR < 3
    1547             ap_rprintf(r, "<dt>This TLS Session:</dt><dd>%s</dd>\n",
    1548                 gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session),
    1549                 gnutls_cipher_get(ctxt->session),
    1550                 gnutls_mac_get(ctxt->session)));
    1551 #else
    1552             char* z = NULL;
    1553             z = gnutls_session_get_desc(ctxt->session);
    1554             if (z) {
    1555                 ap_rprintf(r, "<dt>This TLS Session:</dt><dd>%s</dd>\n", z);
    1556                 gnutls_free(z);
    1557             }
    1558 #endif
    1559         }
    1560     }
    1561 
    1562     ap_rputs("</dl>\n", r);
    1563     return OK;
    1564 }
    1565 
     1148static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
     1149{
     1150        const gnutls_datum_t *cert_list;
     1151        unsigned int cert_list_size, status;
     1152        int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
     1153        unsigned int ch_size = 0;
     1154        union {
     1155                gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
     1156                gnutls_openpgp_crt_t pgp;
     1157        } cert;
     1158        apr_time_t expiration_time, cur_time;
     1159
     1160        if (r == NULL || ctxt == NULL || ctxt->session == NULL)
     1161                return HTTP_FORBIDDEN;
     1162
     1163        _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1164        cert_list =
     1165            gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
     1166
     1167        if (cert_list == NULL || cert_list_size == 0) {
     1168                /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
     1169                 */
     1170                if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1171                        return OK;