Changeset 4addf74 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Aug 22, 2015, 3:30:24 PM (5 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, upstream
Children:
71e9a5c, 89f863f
Parents:
ae29683 (diff), a1c4c2d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Imported Upstream version 0.7

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    rae29683 r4addf74  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2008 Nikos Mavrogiannopoulos
     3 *  Copyright 2008, 2014 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
     5 *  Copyright 2013-2014 Daniel Kahn Gillmor
     6 *  Copyright 2015 Thomas Klute
    57 *
    68 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2729#endif
    2830
     31#ifdef APLOG_USE_MODULE
     32APLOG_USE_MODULE(gnutls);
     33#endif
     34
    2935#if !USING_2_1_RECENT
    3036extern server_rec *ap_server_conf;
     
    3541#endif
    3642
     43#define IS_PROXY_STR(c) \
     44    ((c->is_proxy == GNUTLS_ENABLED_TRUE) ? "proxy " : "")
     45
    3746static gnutls_datum_t session_ticket_key = {NULL, 0};
    3847
    3948static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    4049/* 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);
     50static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size);
     51static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, size_t export_cert_size);
     52static int mgs_status_hook(request_rec *r, int flags);
     53#ifdef ENABLE_MSVA
    4354static 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);
     55#endif
     56static int load_proxy_x509_credentials(server_rec *s);
    4557
    4658/* Pool Cleanup Function */
    47 apr_status_t mgs_cleanup_pre_config(void *data) {
     59apr_status_t mgs_cleanup_pre_config(void *data __attribute__((unused))) {
    4860        /* Free all session data */
    4961    gnutls_free(session_ticket_key.data);
     
    7890
    7991/* Pre-Configuration HOOK: Runs First */
    80 int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp) {
     92int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp __attribute__((unused))) {
    8193
    8294/* Maintainer Logging */
     
    140152    gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    141153
     154    /* Set x509 credentials */
     155    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    142156    /* Set Anon credentials */
    143     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    144         /* Set x509 credentials */
    145157    gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    146158
     
    164176
    165177static 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 
    173         mgs_handle_t *ctxt;
     178                            const gnutls_datum_t * req_ca_rdn __attribute__((unused)),
     179                            int nreqs __attribute__((unused)),
     180                            const gnutls_pk_algorithm_t * pk_algos __attribute__((unused)),
     181                            int pk_algos_length __attribute__((unused)),
     182                            gnutls_pcert_st **pcerts,
     183                            unsigned int *pcert_length,
     184                            gnutls_privkey_t *privkey)
     185{
     186    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     187
     188    mgs_handle_t *ctxt;
    174189
    175190    if (session == NULL) {
    176191                // ERROR INVALID SESSION
    177                 ret->ncerts = 0;
    178                 ret->deinit_all = 1;
    179192        return -1;
    180         }
     193    }
     194
    181195    ctxt = gnutls_transport_get_ptr(session);
    182196
    183197    if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
    184198                // 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;
     199        *pcerts = ctxt->sc->certs_x509_chain;
     200        *pcert_length = ctxt->sc->certs_x509_chain_num;
     201        *privkey = ctxt->sc->privkey_x509;
    191202        return 0;
    192203    } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) {
    193204                // 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;
     205        *pcerts = ctxt->sc->cert_pgp;
     206        *pcert_length = 1;
     207        *privkey = ctxt->sc->privkey_pgp;
    200208        return 0;
    201209    } else {
    202210                // UNKNOWN CERTIFICATE
    203                 ret->ncerts = 0;
    204                 ret->deinit_all = 1;
    205211            return -1;
    206212        }
    207213}
    208 
    209 /* 2048-bit group parameters from SRP specification */
    210 const 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";
    218214
    219215/* Read the common name or the alternative name of the certificate.
     
    298294}
    299295
    300 int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * base_server) {
     296int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog __attribute__((unused)), apr_pool_t * ptemp __attribute__((unused)), server_rec * base_server) {
    301297
    302298    int rv;
     
    315311    }
    316312
    317 
    318313    s = base_server;
    319314    sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    320315
    321     gnutls_dh_params_init(&dh_params);
    322 
    323     if (sc_base->dh_params == NULL) {
    324         gnutls_datum_t pdata = {
    325             (void *) static_dh_params,
    326             sizeof(static_dh_params)
    327         };
    328         rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, GNUTLS_X509_FMT_PEM);
    329         /* Generate DH Params
    330         int dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
    331                 GNUTLS_SEC_PARAM_NORMAL);
    332         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    333             "GnuTLS: Generating DH Params of %i bits.  "
    334             "To avoid this use GnuTLSDHFile to specify DH Params for this host",
    335             dh_bits);
    336 #if MOD_GNUTLS_DEBUG
    337             ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    338                     "GnuTLS: Generated DH Params of %i bits",dh_bits);
    339 #endif
    340         rv = gnutls_dh_params_generate2 (dh_params,dh_bits);
    341         */
    342         if (rv < 0) {
    343             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    344                     "GnuTLS: Unable to generate or load DH Params: (%d) %s",
    345                     rv, gnutls_strerror(rv));
    346             exit(rv);
    347         }
    348     } else {
    349         dh_params = sc_base->dh_params;
    350     }
    351316
    352317    rv = mgs_cache_post_config(p, s, sc_base);
     
    358323    }
    359324
     325    /* Load additional PKCS #11 module, if requested */
     326    if (sc_base->p11_module != NULL)
     327    {
     328        rv = gnutls_pkcs11_add_provider(sc_base->p11_module, NULL);
     329        if (rv != GNUTLS_E_SUCCESS)
     330            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     331                         "GnuTLS: Loading PKCS #11 provider module %s "
     332                         "failed: %s (%d).",
     333                         sc_base->p11_module, gnutls_strerror(rv), rv);
     334    }
     335
    360336    for (s = base_server; s; s = s->next) {
    361337        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
     
    364340        sc->cache_timeout = sc_base->cache_timeout;
    365341
     342        rv = mgs_load_files(p, s);
     343        if (rv != 0) {
     344            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     345                "GnuTLS: Loading required files failed."
     346                " Shutting Down.");
     347            exit(-1);
     348        }
     349
    366350        /* defaults for unset values: */
    367351        if (sc->enabled == GNUTLS_ENABLED_UNSET)
     
    369353        if (sc->tickets == GNUTLS_ENABLED_UNSET)
    370354            sc->tickets = GNUTLS_ENABLED_TRUE;
    371         if (sc->export_certificates_enabled == GNUTLS_ENABLED_UNSET)
    372             sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
     355        if (sc->export_certificates_size < 0)
     356            sc->export_certificates_size = 0;
    373357        if (sc->client_verify_mode ==  -1)
    374358            sc->client_verify_mode = GNUTLS_CERT_IGNORE;
    375359        if (sc->client_verify_method ==  mgs_cvm_unset)
    376360            sc->client_verify_method = mgs_cvm_cartel;
    377 
    378361
    379362        /* Check if the priorities have been set */
     
    394377        }
    395378
    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         }
     379        /* The call after this comment is a workaround for bug in
     380         * gnutls_certificate_set_retrieve_function2 that ignores
     381         * supported certificate types. Should be fixed in GnuTLS
     382         * 3.3.12.
     383         *
     384         * Details:
     385         * https://lists.gnupg.org/pipermail/gnutls-devel/2015-January/007377.html
     386         * Workaround from:
     387         * https://github.com/vanrein/tlspool/commit/4938102d3d1b086491d147e6c8e4e2a02825fc12 */
     388#if GNUTLS_VERSION_NUMBER < 0x030312
     389        gnutls_certificate_set_retrieve_function(sc->certs, (void *) exit);
    414390#endif
     391
     392        gnutls_certificate_set_retrieve_function2(sc->certs, cert_retrieve_fn);
    415393
    416394        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
    417395            sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    418396                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    419                                                 "[GnuTLS] - Host '%s:%d' is missing a Certificate File!",
     397                                                "GnuTLS: Host '%s:%d' is missing a Certificate File!",
    420398                                                s->server_hostname, s->port);
    421399            exit(-1);
    422400        }
    423 
    424401        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))) {
     402            ((sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
     403             (sc->cert_crt_pgp[0] != NULL && sc->privkey_pgp == NULL))) {
    427404                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    428                                                 "[GnuTLS] - Host '%s:%d' is missing a Private Key File!",
     405                                                "GnuTLS: Host '%s:%d' is missing a Private Key File!",
    429406                                                s->server_hostname, s->port);
    430407            exit(-1);
     
    434411            rv = -1;
    435412            if (sc->certs_x509_chain_num > 0) {
    436                 rv = read_crt_cn(s, p, sc->certs_x509_chain[0], &sc->cert_cn);
     413                rv = read_crt_cn(s, p, sc->certs_x509_crt_chain[0], &sc->cert_cn);
    437414            }
    438415            if (rv < 0 && sc->cert_pgp != NULL) {
    439                 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
     416                rv = read_pgpcrt_cn(s, p, sc->cert_crt_pgp[0], &sc->cert_cn);
    440417                        }
    441418
    442419            if (rv < 0) {
    443420                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    444                                                         "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
     421                                                        "GnuTLS: Cannot find a certificate for host '%s:%d'!",
    445422                                                        s->server_hostname, s->port);
    446423                sc->cert_cn = NULL;
    447424                continue;
    448425            }
     426        }
     427
     428        if (sc->enabled == GNUTLS_ENABLED_TRUE
     429            && sc->proxy_enabled == GNUTLS_ENABLED_TRUE
     430            && load_proxy_x509_credentials(s) != APR_SUCCESS)
     431        {
     432            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     433                         "%s: loading proxy credentials for host "
     434                         "'%s:%d' failed, exiting!",
     435                         __func__, s->server_hostname, s->port);
     436            exit(-1);
    449437        }
    450438    }
     
    467455}
    468456
    469 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) {
     457void mgs_hook_child_init(apr_pool_t * p, server_rec *s) {
    470458    apr_status_t rv = APR_SUCCESS;
    471     mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
    472             &gnutls_module);
     459    mgs_srvconf_rec *sc =
     460        (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    473461
    474462    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     463    /* if we use PKCS #11 reinitialize it */
     464
     465    if (mgs_pkcs11_reinit(s) < 0) {
     466            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
     467                    "GnuTLS: Failed to reinitialize PKCS #11");
     468            exit(-1);
     469    }
     470
    475471    if (sc->cache_type != mgs_cache_none) {
    476472        rv = mgs_cache_child_init(p, s, sc);
    477473        if (rv != APR_SUCCESS) {
    478474            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    479                     "[GnuTLS] - Failed to run Cache Init");
     475                    "GnuTLS: Failed to run Cache Init");
    480476        }
    481477    }
     
    584580}
    585581
    586 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) {
     582static int vhost_cb(void *baton, conn_rec * conn __attribute__((unused)), server_rec * s) {
    587583    mgs_srvconf_rec *tsc;
    588584    vhost_cb_rec *x = baton;
     
    598594
    599595    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);
     596        /* this check is there to warn administrator of any missing hostname
     597         * in the certificate. */
     598        ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_crt_chain[0], s->server_hostname);
    602599        if (0 == ret)
    603             ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    604                          "GnuTLS: Error checking certificate for hostname "
     600            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     601                         "GnuTLS: the certificate doesn't match requested hostname "
    605602                         "'%s'", s->server_hostname);
    606603    } else {
     
    613610#endif
    614611
    615 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) {
     612mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     613{
    616614    int rv;
    617615    unsigned int sni_type;
     
    664662
    665663        tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    666                 &gnutls_module);
     664                                                       &gnutls_module);
    667665
    668666        if (tsc->enabled != GNUTLS_ENABLED_TRUE) { continue; }
    669667
    670                                 if(check_server_aliases(x, s, tsc)) {
    671                                         return tsc;
    672                                 }
     668        if(check_server_aliases(x, s, tsc)) {
     669            return tsc;
     670        }
     671    }
    673672#endif
    674673    return NULL;
    675674}
    676675
    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);
     676/*
     677 * This function is intended as a cleanup handler for connections
     678 * using GnuTLS.
     679 *
     680 * @param data must point to the mgs_handle_t associated with the
     681 * connection
     682 */
     683static apr_status_t cleanup_gnutls_session(void *data)
     684{
     685    /* nothing to do */
     686    if (data == NULL)
     687        return APR_SUCCESS;
     688
     689    /* check if session needs closing */
     690    mgs_handle_t *ctxt = (mgs_handle_t *) data;
     691    if (ctxt->session != NULL)
     692    {
     693        int ret;
     694        /* Try A Clean Shutdown */
     695        do
     696            ret = gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
     697        while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
     698        if (ret != GNUTLS_E_SUCCESS)
     699            ap_log_cerror(APLOG_MARK, APLOG_INFO, ret, ctxt->c,
     700                          "%s: error while closing TLS %sconnection: %s (%d)",
     701                          __func__, IS_PROXY_STR(ctxt),
     702                          gnutls_strerror(ret), ret);
     703        else
     704            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, ret, ctxt->c,
     705                          "%s: TLS %sconnection closed.",
     706                          __func__, IS_PROXY_STR(ctxt));
     707        /* De-Initialize Session */
     708        gnutls_deinit(ctxt->session);
     709        ctxt->session = NULL;
     710    }
     711    return APR_SUCCESS;
     712}
     713
     714static void create_gnutls_handle(conn_rec * c)
     715{
     716    /* Get mod_gnutls server configuration */
     717    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     718            ap_get_module_config(c->base_server->module_config, &gnutls_module);
    682719
    683720    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    684     ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
     721
     722    /* Get connection specific configuration */
     723    mgs_handle_t *ctxt = (mgs_handle_t *) ap_get_module_config(c->conn_config, &gnutls_module);
     724    if (ctxt == NULL)
     725    {
     726        ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
     727        ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
     728        ctxt->is_proxy = GNUTLS_ENABLED_FALSE;
     729    }
     730    ctxt->enabled = GNUTLS_ENABLED_TRUE;
    685731    ctxt->c = c;
    686732    ctxt->sc = sc;
     
    693739    ctxt->output_blen = 0;
    694740    ctxt->output_length = 0;
     741
    695742    /* 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);
     743    int err = 0;
     744    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
     745    {
     746        /* this is an outgoing proxy connection, client mode */
     747        err = gnutls_init(&ctxt->session, GNUTLS_CLIENT);
     748        if (err != GNUTLS_E_SUCCESS)
     749            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     750                          "gnutls_init for proxy connection failed: %s (%d)",
     751                          gnutls_strerror(err), err);
     752        err = gnutls_session_ticket_enable_client(ctxt->session);
     753        if (err != GNUTLS_E_SUCCESS)
     754            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     755                          "gnutls_session_ticket_enable_client failed: %s (%d)",
     756                          gnutls_strerror(err), err);
     757        /* Try to close and deinit the session when the connection
     758         * pool is cleared. Note that mod_proxy might not close
     759         * connections immediately, if you need that, look at the
     760         * "proxy-nokeepalive" environment variable for
     761         * mod_proxy_http. */
     762        apr_pool_pre_cleanup_register(c->pool, ctxt, cleanup_gnutls_session);
     763    }
     764    else
     765    {
     766        /* incoming connection, server mode */
     767        err = gnutls_init(&ctxt->session, GNUTLS_SERVER);
     768        if (err != GNUTLS_E_SUCCESS)
     769            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     770                          "gnutls_init for server side failed: %s (%d)",
     771                          gnutls_strerror(err), err);
     772        /* Initialize Session Tickets */
     773        if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
     774        {
     775            err = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
     776            if (err != GNUTLS_E_SUCCESS)
     777                ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     778                              "gnutls_session_ticket_enable_server failed: %s (%d)",
     779                              gnutls_strerror(err), err);
     780        }
    700781    }
    701782
    702783    /* Set Default Priority */
    703         gnutls_priority_set_direct (ctxt->session, "NORMAL", NULL);
     784        err = gnutls_priority_set_direct(ctxt->session, "NORMAL", NULL);
     785    if (err != GNUTLS_E_SUCCESS)
     786        ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c, "gnutls_priority_set_direct failed!");
    704787    /* Set Handshake function */
    705788    gnutls_handshake_set_post_client_hello_function(ctxt->session,
    706789            mgs_select_virtual_server_cb);
     790
     791    /* Set GnuTLS user pointer, so we can access the module session
     792     * context in GnuTLS callbacks */
     793    gnutls_session_set_ptr(ctxt->session, ctxt);
     794
     795    /* If mod_gnutls is the TLS server, mgs_select_virtual_server_cb
     796     * will load appropriate credentials during handshake. However,
     797     * when handling a proxy backend connection, mod_gnutls acts as
     798     * TLS client and credentials must be loaded here. */
     799    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
     800    {
     801        /* Set anonymous client credentials for proxy connections */
     802        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
     803                               ctxt->sc->anon_client_creds);
     804        /* Set x509 credentials */
     805        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE,
     806                               ctxt->sc->proxy_x509_creds);
     807        /* Load priorities from the server configuration */
     808        err = gnutls_priority_set(ctxt->session, ctxt->sc->proxy_priorities);
     809        if (err != GNUTLS_E_SUCCESS)
     810            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     811                          "%s: setting priorities for proxy connection "
     812                          "failed: %s (%d)",
     813                          __func__, gnutls_strerror(err), err);
     814    }
     815
    707816    /* Initialize Session Cache */
    708817    mgs_cache_session_init(ctxt);
    709818
    710     /* Set this config for this connection */
    711     ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
    712819    /* Set pull, push & ptr functions */
    713820    gnutls_transport_set_pull_function(ctxt->session,
     
    723830}
    724831
    725 int mgs_hook_pre_connection(conn_rec * c, void *csd) {
    726     mgs_srvconf_rec *sc;
    727 
     832int mgs_hook_pre_connection(conn_rec * c, void *csd __attribute__((unused)))
     833{
    728834    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    729835
    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)) {
     836    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     837        ap_get_module_config(c->base_server->module_config, &gnutls_module);
     838    mgs_handle_t *ctxt = (mgs_handle_t *)
     839        ap_get_module_config(c->conn_config, &gnutls_module);
     840
     841    if ((sc && (!sc->enabled)) || (ctxt && ctxt->enabled == GNUTLS_ENABLED_FALSE))
     842    {
     843        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s declined connection",
     844                      __func__);
    734845        return DECLINED;
    735846    }
     
    753864    apr_table_t *env = r->subprocess_env;
    754865
    755     ctxt =
    756             ap_get_module_config(r->connection->conn_config,
    757             &gnutls_module);
    758 
    759     if (!ctxt || ctxt->session == NULL) {
     866    ctxt = ap_get_module_config(r->connection->conn_config,
     867                                &gnutls_module);
     868
     869    if (!ctxt || ctxt->enabled != GNUTLS_ENABLED_TRUE || ctxt->session == NULL)
     870    {
     871        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "request declined in %s", __func__);
    760872        return DECLINED;
    761873    }
     
    814926
    815927    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         }
     928        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0, ctxt->sc->export_certificates_size);
     929    } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
     930        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_crt_pgp[0], 0, ctxt->sc->export_certificates_size);
     931    }
    820932
    821933    return rv;
     
    872984        }
    873985        rv = mgs_cert_verify(r, ctxt);
    874         if (rv != DECLINED &&
    875                 (rv != HTTP_FORBIDDEN ||
    876                 dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
     986        if (rv != DECLINED
     987            && (rv != HTTP_FORBIDDEN
     988                || dc->client_verify_mode == GNUTLS_CERT_REQUIRE
     989                || (dc->client_verify_mode == -1
     990                    && ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUIRE)))
     991        {
    877992            return rv;
    878993        }
     
    8901005/* @param side is either 0 for SERVER or 1 for CLIENT
    8911006 *
    892  * @param export_full_cert (boolean) export the PEM-encoded
    893  * certificate in full as an environment variable.
     1007 * @param export_cert_size (int) maximum size for environment variable
     1008 * to use for the PEM-encoded certificate (0 means do not export)
    8941009 */
    895 #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) {
     1010#define MGS_SIDE(suffix) ((side==0) ? "SSL_SERVER" suffix : "SSL_CLIENT" suffix)
     1011
     1012static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size) {
    8981013    unsigned char sbuf[64]; /* buffer to hold serials */
    8991014    char buf[AP_IOBUFSIZE];
     
    9091024
    9101025    _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");
     1026    if (export_cert_size > 0) {
     1027        len = 0;
     1028        ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, NULL, &len);
     1029        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
     1030            if (len >= export_cert_size) {
     1031                apr_table_setn(env, MGS_SIDE("_CERT"), "GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED");
     1032                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1033                              "GnuTLS: Failed to export too-large X.509 certificate to environment");
     1034            } else {
     1035                char* cert_buf = apr_palloc(r->pool, len + 1);
     1036                if (cert_buf != NULL && gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) {
     1037                    cert_buf[len] = 0;
     1038                    apr_table_setn(env, MGS_SIDE("_CERT"), cert_buf);
     1039                } else {
     1040                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
     1041                                  "GnuTLS: failed to export X.509 certificate");
     1042                }
     1043            }
     1044        } else {
     1045            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
     1046                          "GnuTLS: dazed and confused about X.509 certificate size");
     1047        }
    9211048    }
    9221049
    9231050    len = sizeof (buf);
    9241051    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));
     1052    apr_table_setn(env, MGS_SIDE("_S_DN"), apr_pstrmemdup(r->pool, buf, len));
    9271053
    9281054    len = sizeof (buf);
    9291055    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));
     1056    apr_table_setn(env, MGS_SIDE("_I_DN"), apr_pstrmemdup(r->pool, buf, len));
    9321057
    9331058    len = sizeof (sbuf);
    9341059    gnutls_x509_crt_get_serial(cert, sbuf, &len);
    9351060    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));
     1061    apr_table_setn(env, MGS_SIDE("_M_SERIAL"), apr_pstrdup(r->pool, tmp));
    9391062
    9401063    ret = gnutls_x509_crt_get_version(cert);
    9411064    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");
     1065        apr_table_setn(env, MGS_SIDE("_M_VERSION"),
     1066                       apr_psprintf(r->pool, "%u", ret));
     1067
     1068    apr_table_setn(env, MGS_SIDE("_CERT_TYPE"), "X.509");
    9501069
    9511070    tmp =
    9521071            mgs_time2sz(gnutls_x509_crt_get_expiration_time
    9531072            (cert), buf, sizeof (buf));
    954     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    955             apr_pstrdup(r->pool, tmp));
     1073    apr_table_setn(env, MGS_SIDE("_V_END"), apr_pstrdup(r->pool, tmp));
    9561074
    9571075    tmp =
    9581076            mgs_time2sz(gnutls_x509_crt_get_activation_time
    9591077            (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));
     1078    apr_table_setn(env, MGS_SIDE("_V_START"), apr_pstrdup(r->pool, tmp));
    9631079
    9641080    ret = gnutls_x509_crt_get_signature_algorithm(cert);
    9651081    if (ret >= 0) {
    966         apr_table_setn(env,
    967                 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
    968                 NULL),
     1082        apr_table_setn(env, MGS_SIDE("_A_SIG"),
    9691083                gnutls_sign_algorithm_get_name(ret));
    9701084    }
     
    9721086    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
    9731087    if (ret >= 0) {
    974         apr_table_setn(env,
    975                 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    976                 NULL),
     1088        apr_table_setn(env, MGS_SIDE("_A_KEY"),
    9771089                gnutls_pk_algorithm_get_name(ret));
    9781090    }
     
    9801092    /* export all the alternative names (DNS, RFC822 and URI) */
    9811093    for (i = 0; !(ret < 0); i++) {
     1094        const char *san, *sanlabel;
    9821095        len = 0;
    9831096        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
     
    9951108            tmp2[len] = 0;
    9961109
     1110            sanlabel = apr_psprintf(r->pool, "%s%u", MGS_SIDE("_S_AN"), i);
    9971111            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));
     1112                san = apr_psprintf(r->pool, "DNSNAME:%s", tmp2);
    10051113            } 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));
     1114                san = apr_psprintf(r->pool, "RFC822NAME:%s", tmp2);
    10131115            } 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));
     1116                san = apr_psprintf(r->pool, "URI:%s", tmp2);
    10211117            } else {
    1022                 apr_table_setn(env,
    1023                         apr_psprintf(r->pool,
    1024                         "%s_S_AN%u",
    1025                         MGS_SIDE, i),
    1026                         "UNSUPPORTED");
     1118                san = "UNSUPPORTED";
    10271119            }
     1120            apr_table_setn(env, sanlabel, san);
    10281121        }
    10291122    }
     
    10331126/* @param side 0: server, 1: client
    10341127 *
    1035  * @param export_full_cert (boolean) export the PEM-encoded
    1036  * certificate in full as an environment variable.
     1128 * @param export_cert_size (int) maximum size for environment variable
     1129 * to use for the PEM-encoded certificate (0 means do not export)
    10371130 */
    1038 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, int export_full_cert) {
     1131static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, size_t export_cert_size) {
    10391132
    10401133        unsigned char sbuf[64]; /* buffer to hold serials */
     
    10501143    apr_table_t *env = r->subprocess_env;
    10511144
    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");
     1145    if (export_cert_size > 0) {
     1146        len = 0;
     1147        ret = gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, NULL, &len);
     1148        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
     1149            if (len >= export_cert_size) {
     1150                apr_table_setn(env, MGS_SIDE("_CERT"),
     1151                               "GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED");
     1152                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1153                              "GnuTLS: Failed to export too-large OpenPGP certificate to environment");
     1154            } else {
     1155                char* cert_buf = apr_palloc(r->pool, len + 1);
     1156                if (cert_buf != NULL && gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) {
     1157                    cert_buf[len] = 0;
     1158                    apr_table_setn(env, MGS_SIDE("_CERT"), cert_buf);
     1159                } else {
     1160                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
     1161                                  "GnuTLS: failed to export OpenPGP certificate");
     1162                }
     1163            }
     1164        } else {
     1165            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
     1166                          "GnuTLS: dazed and confused about OpenPGP certificate size");
     1167        }
    10621168    }
    10631169
    10641170    len = sizeof (buf);
    10651171    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));
     1172    apr_table_setn(env, MGS_SIDE("_NAME"), apr_pstrmemdup(r->pool, buf, len));
    10681173
    10691174    len = sizeof (sbuf);
    10701175    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
    10711176    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));
     1177    apr_table_setn(env, MGS_SIDE("_FINGERPRINT"), apr_pstrdup(r->pool, tmp));
    10751178
    10761179    ret = gnutls_openpgp_crt_get_version(cert);
    10771180    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");
     1181        apr_table_setn(env, MGS_SIDE("_M_VERSION"),
     1182                       apr_psprintf(r->pool, "%u", ret));
     1183
     1184    apr_table_setn(env, MGS_SIDE("_CERT_TYPE"), "OPENPGP");
    10861185
    10871186    tmp =
    10881187            mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
    10891188            (cert), buf, sizeof (buf));
    1090     apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    1091             apr_pstrdup(r->pool, tmp));
     1189    apr_table_setn(env, MGS_SIDE("_V_END"), apr_pstrdup(r->pool, tmp));
    10921190
    10931191    tmp =
    10941192            mgs_time2sz(gnutls_openpgp_crt_get_creation_time
    10951193            (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));
     1194    apr_table_setn(env, MGS_SIDE("_V_START"), apr_pstrdup(r->pool, tmp));
    10991195
    11001196    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
    11011197    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));
     1198        apr_table_setn(env, MGS_SIDE("_A_KEY"), gnutls_pk_algorithm_get_name(ret));
    11061199    }
    11071200
     
    13241417
    13251418    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);
     1419        mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_size);
    13271420    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);
     1421        mgs_add_common_pgpcert_vars(r, cert.pgp, 1, ctxt->sc->export_certificates_size);
    13291422
    13301423    {
     
    13521445exit:
    13531446    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1354         int i;
     1447        unsigned int i;
    13551448        for (i = 0; i < ch_size; i++) {
    13561449            gnutls_x509_crt_deinit(cert.x509[i]);
     
    13641457}
    13651458
     1459#ifdef ENABLE_MSVA
     1460/* this section of code is used only when trying to talk to the MSVA */
    13661461static const char* mgs_x509_leaf_oid_from_dn(apr_pool_t *pool, const char* oid, gnutls_x509_crt_t cert) {
    13671462    int rv=GNUTLS_E_SUCCESS, i;
     
    14001495            data = apr_palloc(pool, sz);
    14011496            rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, data, &sz, &thistype, NULL);
    1402             if (rv == target)
     1497            if (rv >=0 && (thistype == target))
    14031498                return data;
    14041499        }
     
    14071502    return NULL;
    14081503}
     1504
    14091505
    14101506/* Create a string representing a candidate User ID from an X.509
     
    15221618    return ret;
    15231619}
    1524 
    1525 static int mgs_status_hook(request_rec *r, int flags)
     1620#endif /* ENABLE_MSVA */
     1621
     1622static int mgs_status_hook(request_rec *r, int flags __attribute__((unused)))
    15261623{
    15271624    mgs_srvconf_rec *sc;
     
    15641661}
    15651662
     1663
     1664
     1665/*
     1666 * Callback to check the server certificate for proxy HTTPS
     1667 * connections, to be used with
     1668 * gnutls_certificate_set_verify_function.
     1669
     1670 * Returns: 0 if certificate check was successful (certificate
     1671 * trusted), non-zero otherwise (error during check or untrusted
     1672 * certificate).
     1673 */
     1674static int gtls_check_server_cert(gnutls_session_t session)
     1675{
     1676    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
     1677    unsigned int status;
     1678
     1679    /* Get peer hostname from a note left by mod_proxy */
     1680    const char *peer_hostname =
     1681        apr_table_get(ctxt->c->notes, "proxy-request-hostname");
     1682    if (peer_hostname == NULL)
     1683        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
     1684                      "%s: proxy-request-hostname is NULL, cannot check "
     1685                      "peer's hostname", __func__);
     1686
     1687    /* Verify certificate, including hostname match. Should
     1688     * peer_hostname be NULL for some reason, the name is not
     1689     * checked. */
     1690    int err = gnutls_certificate_verify_peers3(session, peer_hostname,
     1691                                               &status);
     1692    if (err != GNUTLS_E_SUCCESS)
     1693    {
     1694        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
     1695                      "%s: server certificate check failed: %s (%d)",
     1696                      __func__, gnutls_strerror(err), err);
     1697        return err;
     1698    }
     1699
     1700    gnutls_datum_t * out = gnutls_malloc(sizeof(gnutls_datum_t));
     1701    /* GNUTLS_CRT_X509: ATM, only X509 is supported for proxy certs
     1702     * 0: according to function API, the last argument should be 0 */
     1703    err = gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509,
     1704                                                       out, 0);
     1705    if (err != GNUTLS_E_SUCCESS)
     1706        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
     1707                      "%s: server verify print failed: %s (%d)",
     1708                      __func__, gnutls_strerror(err), err);
     1709    else
     1710    {
     1711        /* If the certificate is trusted, logging the result is just
     1712         * nice for debugging. But if the back end server provided an
     1713         * untrusted certificate, warn! */
     1714        int level = (status == 0 ? APLOG_DEBUG : APLOG_WARNING);
     1715        ap_log_cerror(APLOG_MARK, level, 0, ctxt->c,
     1716                      "%s: server certificate verify result: %s",
     1717                      __func__, out->data);
     1718    }
     1719
     1720    gnutls_free(out);
     1721    return status;
     1722}
     1723
     1724
     1725
     1726static apr_status_t load_proxy_x509_credentials(server_rec *s)
     1727{
     1728    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     1729        ap_get_module_config(s->module_config, &gnutls_module);
     1730
     1731    if (sc == NULL)
     1732        return APR_EGENERAL;
     1733
     1734    apr_status_t ret = APR_SUCCESS;
     1735    int err = GNUTLS_E_SUCCESS;
     1736
     1737    /* Function pool, gets destroyed before exit. */
     1738    apr_pool_t *pool;
     1739    ret = apr_pool_create(&pool, s->process->pool);
     1740    if (ret != APR_SUCCESS)
     1741    {
     1742        ap_log_error(APLOG_MARK, APLOG_ERR, ret, s,
     1743                     "%s: failed to allocate function memory pool.", __func__);
     1744        return ret;
     1745    }
     1746
     1747    /* allocate credentials structures */
     1748    err = gnutls_certificate_allocate_credentials(&sc->proxy_x509_creds);
     1749    if (err != GNUTLS_E_SUCCESS)
     1750    {
     1751        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1752                     "%s: Failed to initialize proxy credentials: (%d) %s",
     1753                     __func__, err, gnutls_strerror(err));
     1754        return APR_EGENERAL;
     1755    }
     1756    err = gnutls_anon_allocate_client_credentials(&sc->anon_client_creds);
     1757    if (err != GNUTLS_E_SUCCESS)
     1758    {
     1759        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1760                     "%s: Failed to initialize anon credentials for proxy: "
     1761                     "(%d) %s", __func__, err, gnutls_strerror(err));
     1762        return APR_EGENERAL;
     1763    }
     1764
     1765    /* Check if the proxy priorities have been set, fail immediately
     1766     * if not */
     1767    if (sc->proxy_priorities_str == NULL)
     1768    {
     1769        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     1770                     "Host '%s:%d' is missing the GnuTLSProxyPriorities "
     1771                     "directive!",
     1772                     s->server_hostname, s->port);
     1773        return APR_EGENERAL;
     1774    }
     1775    /* parse proxy priorities */
     1776    const char *err_pos = NULL;
     1777    err = gnutls_priority_init(&sc->proxy_priorities,
     1778                               sc->proxy_priorities_str, &err_pos);
     1779    if (err != GNUTLS_E_SUCCESS)
     1780    {
     1781        if (ret == GNUTLS_E_INVALID_REQUEST)
     1782            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1783                         "%s: Syntax error parsing proxy priorities "
     1784                         "string at: %s",
     1785                         __func__, err_pos);
     1786        else
     1787            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1788                         "Error setting proxy priorities: %s (%d)",
     1789                         gnutls_strerror(err), err);
     1790        ret = APR_EGENERAL;
     1791    }
     1792
     1793    /* load certificate and key for client auth, if configured */
     1794    if (sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
     1795    {
     1796        char* cert_file = ap_server_root_relative(pool,
     1797                                                  sc->proxy_x509_cert_file);
     1798        char* key_file = ap_server_root_relative(pool,
     1799                                                 sc->proxy_x509_key_file);
     1800        err = gnutls_certificate_set_x509_key_file(sc->proxy_x509_creds,
     1801                                                   cert_file,
     1802                                                   key_file,
     1803                                                   GNUTLS_X509_FMT_PEM);
     1804        if (err != GNUTLS_E_SUCCESS)
     1805        {
     1806            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1807                         "%s: loading proxy client credentials failed: %s (%d)",
     1808                         __func__, gnutls_strerror(err), err);
     1809            ret = APR_EGENERAL;
     1810        }
     1811    }
     1812    else if (!sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
     1813    {
     1814        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1815                     "%s: proxy key file not set!", __func__);
     1816        ret = APR_EGENERAL;
     1817    }
     1818    else if (!sc->proxy_x509_cert_file && sc->proxy_x509_key_file)
     1819    {
     1820        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1821                     "%s: proxy certificate file not set!", __func__);
     1822        ret = APR_EGENERAL;
     1823    }
     1824    else
     1825        /* if both key and cert are NULL, client auth is not used */
     1826        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     1827                     "%s: no client credentials for proxy", __func__);
     1828
     1829    /* must be set if the server certificate is to be checked */
     1830    if (sc->proxy_x509_ca_file)
     1831    {
     1832        /* initialize the trust list */
     1833        err = gnutls_x509_trust_list_init(&sc->proxy_x509_tl, 0);
     1834        if (err != GNUTLS_E_SUCCESS)
     1835        {
     1836            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1837                         "%s: gnutls_x509_trust_list_init failed: %s (%d)",
     1838                         __func__, gnutls_strerror(err), err);
     1839            ret = APR_EGENERAL;
     1840        }
     1841
     1842        char* ca_file = ap_server_root_relative(pool,
     1843                                                sc->proxy_x509_ca_file);
     1844        /* if no CRL is used, sc->proxy_x509_crl_file is NULL */
     1845        char* crl_file = NULL;
     1846        if (sc->proxy_x509_crl_file)
     1847            crl_file = ap_server_root_relative(pool,
     1848                                               sc->proxy_x509_crl_file);
     1849
     1850        /* returns number of loaded elements */
     1851        err = gnutls_x509_trust_list_add_trust_file(sc->proxy_x509_tl,
     1852                                                    ca_file,
     1853                                                    crl_file,
     1854                                                    GNUTLS_X509_FMT_PEM,
     1855                                                    0 /* tl_flags */,
     1856                                                    0 /* tl_vflags */);
     1857        if (err > 0)
     1858            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     1859                         "%s: proxy CA trust list: %d structures loaded",
     1860                         __func__, err);
     1861        else if (err == 0)
     1862            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1863                         "%s: proxy CA trust list is empty (%d)",
     1864                         __func__, err);
     1865        else /* err < 0 */
     1866        {
     1867            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1868                         "%s: error loading proxy CA trust list: %s (%d)",
     1869                         __func__, gnutls_strerror(err), err);
     1870            ret = APR_EGENERAL;
     1871        }
     1872
     1873        /* attach trust list to credentials */
     1874        gnutls_certificate_set_trust_list(sc->proxy_x509_creds,
     1875                                          sc->proxy_x509_tl, 0);
     1876    }
     1877    else
     1878        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1879                     "%s: no CA trust list for proxy connections, "
     1880                     "TLS connections will fail!", __func__);
     1881
     1882    gnutls_certificate_set_verify_function(sc->proxy_x509_creds,
     1883                                           gtls_check_server_cert);
     1884    apr_pool_destroy(pool);
     1885    return ret;
     1886}
Note: See TracChangeset for help on using the changeset viewer.