Changes in src/gnutls_hooks.c [d04f7da:f030883] in mod_gnutls


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    rd04f7da rf030883  
    4040#endif
    4141
     42#define IS_PROXY_STR(c) \
     43    ((c->is_proxy == GNUTLS_ENABLED_TRUE) ? "proxy " : "")
     44
    4245static gnutls_datum_t session_ticket_key = {NULL, 0};
    4346
     
    5053static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
    5154#endif
     55static int load_proxy_x509_credentials(server_rec *s);
    5256
    5357/* Pool Cleanup Function */
     
    147151    gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    148152
     153    /* Set x509 credentials */
     154    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    149155    /* Set Anon credentials */
    150     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    151         /* Set x509 credentials */
    152156    gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    153157
     
    171175
    172176static int cert_retrieve_fn(gnutls_session_t session,
    173                             const gnutls_datum_t * req_ca_rdn __attribute__((unused)),
    174                             int nreqs __attribute__((unused)),
    175                             const gnutls_pk_algorithm_t * pk_algos __attribute__((unused)),
    176                             int pk_algos_length __attribute__((unused)),
    177                             gnutls_pcert_st **pcerts,
    178                             unsigned int *pcert_length,
    179                             gnutls_privkey_t *privkey)
    180 {
    181     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    182 
    183     mgs_handle_t *ctxt;
     177                                                        const gnutls_datum_t * req_ca_rdn __attribute__((unused)), int nreqs __attribute__((unused)),
     178                                                        const gnutls_pk_algorithm_t * pk_algos __attribute__((unused)), int pk_algos_length __attribute__((unused)),
     179                                                        gnutls_retr2_st *ret) {
     180
     181
     182        _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     183
     184        mgs_handle_t *ctxt;
    184185
    185186    if (session == NULL) {
    186187                // ERROR INVALID SESSION
     188                ret->ncerts = 0;
     189                ret->deinit_all = 1;
    187190        return -1;
    188     }
    189 
     191        }
    190192    ctxt = gnutls_transport_get_ptr(session);
    191193
    192194    if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
    193195                // X509 CERTIFICATE
    194         *pcerts = ctxt->sc->certs_x509_chain;
    195         *pcert_length = ctxt->sc->certs_x509_chain_num;
    196         *privkey = ctxt->sc->privkey_x509;
     196                ret->cert_type = GNUTLS_CRT_X509;
     197                ret->key_type = GNUTLS_PRIVKEY_X509;
     198        ret->ncerts = ctxt->sc->certs_x509_chain_num;
     199        ret->deinit_all = 0;
     200        ret->cert.x509 = ctxt->sc->certs_x509_chain;
     201        ret->key.x509 = ctxt->sc->privkey_x509;
    197202        return 0;
    198203    } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) {
    199204                // OPENPGP CERTIFICATE
    200         *pcerts = ctxt->sc->cert_pgp;
    201         *pcert_length = 1;
    202         *privkey = ctxt->sc->privkey_pgp;
     205                ret->cert_type = GNUTLS_CRT_OPENPGP;
     206                ret->key_type = GNUTLS_PRIVKEY_OPENPGP;
     207        ret->ncerts = 1;
     208        ret->deinit_all = 0;
     209        ret->cert.pgp = ctxt->sc->cert_pgp;
     210        ret->key.pgp = ctxt->sc->privkey_pgp;
    203211        return 0;
    204212    } else {
    205213                // UNKNOWN CERTIFICATE
     214                ret->ncerts = 0;
     215                ret->deinit_all = 1;
    206216            return -1;
    207217        }
    208218}
     219
     220/* 2048-bit group parameters from SRP specification */
     221const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
     222        "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
     223        "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
     224        "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
     225        "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
     226        "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
     227        "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
     228        "-----END DH PARAMETERS-----\n";
    209229
    210230/* Read the common name or the alternative name of the certificate.
     
    306326    }
    307327
     328
    308329    s = base_server;
    309330    sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    310331
     332    gnutls_dh_params_init(&dh_params);
     333
     334    if (sc_base->dh_params == NULL) {
     335        gnutls_datum_t pdata = {
     336            (void *) static_dh_params,
     337            sizeof(static_dh_params)
     338        };
     339        rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, GNUTLS_X509_FMT_PEM);
     340        /* Generate DH Params
     341        int dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
     342                GNUTLS_SEC_PARAM_NORMAL);
     343        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     344            "GnuTLS: Generating DH Params of %i bits.  "
     345            "To avoid this use GnuTLSDHFile to specify DH Params for this host",
     346            dh_bits);
     347#if MOD_GNUTLS_DEBUG
     348            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     349                    "GnuTLS: Generated DH Params of %i bits",dh_bits);
     350#endif
     351        rv = gnutls_dh_params_generate2 (dh_params,dh_bits);
     352        */
     353        if (rv < 0) {
     354            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     355                    "GnuTLS: Unable to generate or load DH Params: (%d) %s",
     356                    rv, gnutls_strerror(rv));
     357            exit(rv);
     358        }
     359    } else {
     360        dh_params = sc_base->dh_params;
     361    }
    311362
    312363    rv = mgs_cache_post_config(p, s, sc_base);
     
    323374        sc->cache_config = sc_base->cache_config;
    324375        sc->cache_timeout = sc_base->cache_timeout;
    325 
    326         rv = mgs_load_files(p, s);
    327         if (rv != 0) {
    328             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    329                 "GnuTLS: Loading required files failed."
    330                 " Shutting Down.");
    331             exit(-1);
    332         }
    333376
    334377        /* defaults for unset values: */
     
    344387            sc->client_verify_method = mgs_cvm_cartel;
    345388
     389
    346390        /* Check if the priorities have been set */
    347391        if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     
    361405        }
    362406
    363         /* The call after this comment is a workaround for bug in
    364          * gnutls_certificate_set_retrieve_function2 that ignores
    365          * supported certificate types. Should be fixed in GnuTLS
    366          * 3.3.12.
    367          *
    368          * Details:
    369          * https://lists.gnupg.org/pipermail/gnutls-devel/2015-January/007377.html
    370          * Workaround from:
    371          * https://github.com/vanrein/tlspool/commit/4938102d3d1b086491d147e6c8e4e2a02825fc12 */
    372 #if GNUTLS_VERSION_NUMBER < 0x030312
    373         gnutls_certificate_set_retrieve_function(sc->certs, (void *) exit);
     407        gnutls_certificate_set_retrieve_function(sc->certs, cert_retrieve_fn);
     408
     409#ifdef ENABLE_SRP
     410        if (sc->srp_tpasswd_conf_file != NULL
     411                && sc->srp_tpasswd_file != NULL) {
     412            rv = gnutls_srp_set_server_credentials_file
     413                    (sc->srp_creds, sc->srp_tpasswd_file,
     414                    sc->srp_tpasswd_conf_file);
     415
     416            if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
     417                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
     418                        s,
     419                        "[GnuTLS] - Host '%s:%d' is missing a "
     420                        "SRP password or conf File!",
     421                        s->server_hostname, s->port);
     422                exit(-1);
     423            }
     424        }
    374425#endif
    375 
    376         gnutls_certificate_set_retrieve_function2(sc->certs, cert_retrieve_fn);
    377426
    378427        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
    379428            sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    380429                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    381                                                 "GnuTLS: Host '%s:%d' is missing a Certificate File!",
     430                                                "[GnuTLS] - Host '%s:%d' is missing a Certificate File!",
    382431                                                s->server_hostname, s->port);
    383432            exit(-1);
    384433        }
     434
    385435        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    386             ((sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
    387              (sc->cert_crt_pgp[0] != NULL && sc->privkey_pgp == NULL))) {
     436            ((sc->certs_x509_chain != NULL && sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
     437             (sc->cert_pgp != NULL && sc->privkey_pgp == NULL))) {
    388438                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    389                                                 "GnuTLS: Host '%s:%d' is missing a Private Key File!",
     439                                                "[GnuTLS] - Host '%s:%d' is missing a Private Key File!",
    390440                                                s->server_hostname, s->port);
    391441            exit(-1);
     
    395445            rv = -1;
    396446            if (sc->certs_x509_chain_num > 0) {
    397                 rv = read_crt_cn(s, p, sc->certs_x509_crt_chain[0], &sc->cert_cn);
     447                rv = read_crt_cn(s, p, sc->certs_x509_chain[0], &sc->cert_cn);
    398448            }
    399449            if (rv < 0 && sc->cert_pgp != NULL) {
    400                 rv = read_pgpcrt_cn(s, p, sc->cert_crt_pgp[0], &sc->cert_cn);
     450                rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
    401451                        }
    402452
    403453            if (rv < 0) {
    404454                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    405                                                         "GnuTLS: Cannot find a certificate for host '%s:%d'!",
     455                                                        "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
    406456                                                        s->server_hostname, s->port);
    407457                sc->cert_cn = NULL;
    408458                continue;
    409459            }
     460        }
     461
     462        if (sc->enabled == GNUTLS_ENABLED_TRUE
     463            && sc->proxy_enabled == GNUTLS_ENABLED_TRUE)
     464        {
     465            /* Check if the proxy priorities have been set */
     466            if (sc->proxy_priorities == NULL)
     467            {
     468                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     469                             "Host '%s:%d' is missing the "
     470                             "GnuTLSProxyPriorities directive!",
     471                             s->server_hostname, s->port);
     472                exit(-1);
     473            }
     474            /* Set up proxy credentials */
     475            load_proxy_x509_credentials(s);
    410476        }
    411477    }
     
    428494}
    429495
    430 void mgs_hook_child_init(apr_pool_t * p, server_rec *s) {
     496void mgs_hook_child_init(apr_pool_t * p, server_rec * s) {
    431497    apr_status_t rv = APR_SUCCESS;
    432     mgs_srvconf_rec *sc =
    433         (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
     498    mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
     499            &gnutls_module);
    434500
    435501    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    436     /* if we use PKCS #11 reinitialize it */
    437 
    438     if (mgs_pkcs11_reinit(s) < 0) {
    439             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
    440                     "GnuTLS: Failed to reinitialize PKCS #11");
    441             exit(-1);
    442     }
    443 
    444502    if (sc->cache_type != mgs_cache_none) {
    445503        rv = mgs_cache_child_init(p, s, sc);
    446504        if (rv != APR_SUCCESS) {
    447505            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    448                     "GnuTLS: Failed to run Cache Init");
     506                    "[GnuTLS] - Failed to run Cache Init");
    449507        }
    450508    }
     
    567625
    568626    if (tsc->certs_x509_chain_num > 0) {
    569         /* this check is there to warn administrator of any missing hostname
    570          * in the certificate. */
    571         ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_crt_chain[0], s->server_hostname);
     627        /* why are we doing this check? */
     628        ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_chain[0], s->server_hostname);
    572629        if (0 == ret)
    573             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    574                          "GnuTLS: the certificate doesn't match requested hostname "
     630            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     631                         "GnuTLS: Error checking certificate for hostname "
    575632                         "'%s'", s->server_hostname);
    576633    } else {
     
    583640#endif
    584641
    585 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) {
     642mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     643{
    586644    int rv;
    587645    unsigned int sni_type;
     
    634692
    635693        tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    636                 &gnutls_module);
     694                                                       &gnutls_module);
    637695
    638696        if (tsc->enabled != GNUTLS_ENABLED_TRUE) { continue; }
    639697
    640                                 if(check_server_aliases(x, s, tsc)) {
    641                                         return tsc;
    642                                 }
     698        if(check_server_aliases(x, s, tsc)) {
     699            return tsc;
     700        }
     701    }
    643702#endif
    644703    return NULL;
     704}
     705
     706/*
     707 * This function is intended as a cleanup handler for connections
     708 * using GnuTLS.
     709 *
     710 * @param data must point to the mgs_handle_t associated with the
     711 * connection
     712 */
     713static apr_status_t cleanup_gnutls_session(void *data)
     714{
     715    /* nothing to do */
     716    if (data == NULL)
     717        return APR_SUCCESS;
     718
     719    /* check if session needs closing */
     720    mgs_handle_t *ctxt = (mgs_handle_t *) data;
     721    if (ctxt->session != NULL)
     722    {
     723        int ret;
     724        /* Try A Clean Shutdown */
     725        do
     726            ret = gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
     727        while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
     728        if (ret != GNUTLS_E_SUCCESS)
     729            ap_log_cerror(APLOG_MARK, APLOG_INFO, ret, ctxt->c,
     730                          "%s: error while closing TLS %sconnection: %s (%d)",
     731                          __func__, IS_PROXY_STR(ctxt),
     732                          gnutls_strerror(ret), ret);
     733        else
     734            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, ret, ctxt->c,
     735                          "%s: TLS %sconnection closed.",
     736                          __func__, IS_PROXY_STR(ctxt));
     737        /* De-Initialize Session */
     738        gnutls_deinit(ctxt->session);
     739        ctxt->session = NULL;
     740    }
     741    return APR_SUCCESS;
    645742}
    646743
     
    657754    if (ctxt == NULL)
    658755    {
    659         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s: allocating connection memory", __func__);
    660756        ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
    661757        ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
     758        ctxt->is_proxy = GNUTLS_ENABLED_FALSE;
    662759    }
    663760    ctxt->enabled = GNUTLS_ENABLED_TRUE;
     
    674771
    675772    /* Initialize GnuTLS Library */
    676     int err = gnutls_init(&ctxt->session, GNUTLS_SERVER);
    677     if (err != GNUTLS_E_SUCCESS)
    678         ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c, "gnutls_init failed!");
    679     /* Initialize Session Tickets */
    680     if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) {
    681         err = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
     773    int err = 0;
     774    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
     775    {
     776        /* this is an outgoing proxy connection, client mode */
     777        err = gnutls_init(&ctxt->session, GNUTLS_CLIENT);
    682778        if (err != GNUTLS_E_SUCCESS)
    683             ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c, "gnutls_session_ticket_enable_server failed!");
     779            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     780                          "gnutls_init for proxy connection failed: %s (%d)",
     781                          gnutls_strerror(err), err);
     782        err = gnutls_session_ticket_enable_client(ctxt->session);
     783        if (err != GNUTLS_E_SUCCESS)
     784            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     785                          "gnutls_session_ticket_enable_client failed: %s (%d)",
     786                          gnutls_strerror(err), err);
     787        /* Try to close and deinit the session when the connection
     788         * pool is cleared. Note that mod_proxy might not close
     789         * connections immediately, if you need that, look at the
     790         * "proxy-nokeepalive" environment variable for
     791         * mod_proxy_http. */
     792        apr_pool_pre_cleanup_register(c->pool, ctxt, cleanup_gnutls_session);
     793    }
     794    else
     795    {
     796        /* incoming connection, server mode */
     797        err = gnutls_init(&ctxt->session, GNUTLS_SERVER);
     798        if (err != GNUTLS_E_SUCCESS)
     799            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     800                          "gnutls_init for server side failed: %s (%d)",
     801                          gnutls_strerror(err), err);
     802        /* Initialize Session Tickets */
     803        if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
     804        {
     805            err = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
     806            if (err != GNUTLS_E_SUCCESS)
     807                ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     808                              "gnutls_session_ticket_enable_server failed: %s (%d)",
     809                              gnutls_strerror(err), err);
     810        }
    684811    }
    685812
     
    691818    gnutls_handshake_set_post_client_hello_function(ctxt->session,
    692819            mgs_select_virtual_server_cb);
     820
     821    /* Set GnuTLS user pointer, so we can access the module session
     822     * context in GnuTLS callbacks */
     823    gnutls_session_set_ptr(ctxt->session, ctxt);
     824
     825    /* If mod_gnutls is the TLS server, mgs_select_virtual_server_cb
     826     * will load appropriate credentials during handshake. However,
     827     * when handling a proxy backend connection, mod_gnutls acts as
     828     * TLS client and credentials must be loaded here. */
     829    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
     830    {
     831        /* Set anonymous client credentials for proxy connections */
     832        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
     833                               ctxt->sc->anon_client_creds);
     834        /* Set x509 credentials */
     835        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE,
     836                               ctxt->sc->proxy_x509_creds);
     837        /* Load priorities from the server configuration */
     838        err = gnutls_priority_set(ctxt->session, ctxt->sc->proxy_priorities);
     839        if (err != GNUTLS_E_SUCCESS)
     840            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     841                          "%s: setting priorities for proxy connection "
     842                          "failed: %s (%d)",
     843                          __func__, gnutls_strerror(err), err);
     844    }
     845
    693846    /* Initialize Session Cache */
    694847    mgs_cache_session_init(ctxt);
     
    716869        ap_get_module_config(c->conn_config, &gnutls_module);
    717870
    718     if ((sc && (!sc->enabled || sc->proxy_enabled == GNUTLS_ENABLED_TRUE))
    719         || (ctxt && ctxt->enabled == GNUTLS_ENABLED_FALSE))
     871    if ((sc && (!sc->enabled)) || (ctxt && ctxt->enabled == GNUTLS_ENABLED_FALSE))
    720872    {
    721873        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s declined connection",
     
    804956
    805957    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    806         mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0, ctxt->sc->export_certificates_size);
    807     } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
    808         mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_crt_pgp[0], 0, ctxt->sc->export_certificates_size);
    809     }
     958                mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_chain[0], 0, ctxt->sc->export_certificates_size);
     959        } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
     960        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, ctxt->sc->export_certificates_size);
     961        }
    810962
    811963    return rv;
     
    15391691}
    15401692
     1693
     1694
     1695/*
     1696 * Callback to check the server certificate for proxy HTTPS
     1697 * connections, to be used with
     1698 * gnutls_certificate_set_verify_function.
     1699
     1700 * Returns: 0 if certificate check was successful (certificate
     1701 * trusted), non-zero otherwise (error during check or untrusted
     1702 * certificate).
     1703 */
     1704static int gtls_check_server_cert(gnutls_session_t session)
     1705{
     1706    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
     1707    unsigned int status;
     1708
     1709    /* Get peer hostname from a note left by mod_proxy */
     1710    const char *peer_hostname =
     1711        apr_table_get(ctxt->c->notes, "proxy-request-hostname");
     1712    if (peer_hostname == NULL)
     1713        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
     1714                      "%s: proxy-request-hostname is NULL, cannot check "
     1715                      "peer's hostname", __func__);
     1716
     1717    /* Verify certificate, including hostname match. Should
     1718     * peer_hostname be NULL for some reason, the name is not
     1719     * checked. */
     1720    int err = gnutls_certificate_verify_peers3(session, peer_hostname,
     1721                                               &status);
     1722    if (err != GNUTLS_E_SUCCESS)
     1723    {
     1724        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
     1725                      "%s: server certificate check failed: %s (%d)",
     1726                      __func__, gnutls_strerror(err), err);
     1727        return err;
     1728    }
     1729
     1730    gnutls_datum_t * out = gnutls_malloc(sizeof(gnutls_datum_t));
     1731    /* GNUTLS_CRT_X509: ATM, only X509 is supported for proxy certs
     1732     * 0: according to function API, the last argument should be 0 */
     1733    err = gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509,
     1734                                                       out, 0);
     1735    if (err != GNUTLS_E_SUCCESS)
     1736        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
     1737                      "%s: server verify print failed: %s (%d)",
     1738                      __func__, gnutls_strerror(err), err);
     1739    else
     1740    {
     1741        /* If the certificate is trusted, logging the result is just
     1742         * nice for debugging. But if the back end server provided an
     1743         * untrusted certificate, warn! */
     1744        int level = (status == 0 ? APLOG_DEBUG : APLOG_WARNING);
     1745        ap_log_cerror(APLOG_MARK, level, 0, ctxt->c,
     1746                      "%s: server certificate verify result: %s",
     1747                      __func__, out->data);
     1748    }
     1749
     1750    gnutls_free(out);
     1751    return status;
     1752}
     1753
     1754
     1755
     1756static apr_status_t load_proxy_x509_credentials(server_rec *s)
     1757{
     1758    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     1759        ap_get_module_config(s->module_config, &gnutls_module);
     1760
     1761    if (sc == NULL)
     1762        return APR_EGENERAL;
     1763
     1764    apr_status_t ret = APR_SUCCESS;
     1765    int err = GNUTLS_E_SUCCESS;
     1766
     1767    /* Function pool, gets destroyed before exit. */
     1768    apr_pool_t *pool;
     1769    ret = apr_pool_create(&pool, s->process->pool);
     1770    if (ret != APR_SUCCESS)
     1771    {
     1772        ap_log_error(APLOG_MARK, APLOG_ERR, ret, s,
     1773                     "%s: failed to allocate function memory pool.", __func__);
     1774        return ret;
     1775    }
     1776
     1777    /* load certificate and key for client auth, if configured */
     1778    if (sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
     1779    {
     1780        char* cert_file = ap_server_root_relative(pool,
     1781                                                  sc->proxy_x509_cert_file);
     1782        char* key_file = ap_server_root_relative(pool,
     1783                                                 sc->proxy_x509_key_file);
     1784        err = gnutls_certificate_set_x509_key_file(sc->proxy_x509_creds,
     1785                                                   cert_file,
     1786                                                   key_file,
     1787                                                   GNUTLS_X509_FMT_PEM);
     1788        if (err != GNUTLS_E_SUCCESS)
     1789        {
     1790            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1791                         "%s: loading proxy client credentials failed: %s (%d)",
     1792                         __func__, gnutls_strerror(err), err);
     1793            ret = APR_EGENERAL;
     1794        }
     1795    }
     1796    else if (!sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
     1797    {
     1798        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1799                     "%s: proxy key file not set!", __func__);
     1800        ret = APR_EGENERAL;
     1801    }
     1802    else if (!sc->proxy_x509_cert_file && sc->proxy_x509_key_file)
     1803    {
     1804        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1805                     "%s: proxy certificate file not set!", __func__);
     1806        ret = APR_EGENERAL;
     1807    }
     1808    else
     1809        /* if both key and cert are NULL, client auth is not used */
     1810        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     1811                     "%s: no client credentials for proxy", __func__);
     1812
     1813    /* must be set if the server certificate is to be checked */
     1814    if (sc->proxy_x509_ca_file)
     1815    {
     1816        /* initialize the trust list */
     1817        err = gnutls_x509_trust_list_init(&sc->proxy_x509_tl, 0);
     1818        if (err != GNUTLS_E_SUCCESS)
     1819        {
     1820            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1821                         "%s: gnutls_x509_trust_list_init failed: %s (%d)",
     1822                         __func__, gnutls_strerror(err), err);
     1823            ret = APR_EGENERAL;
     1824        }
     1825
     1826        char* ca_file = ap_server_root_relative(pool,
     1827                                                sc->proxy_x509_ca_file);
     1828        /* if no CRL is used, sc->proxy_x509_crl_file is NULL */
     1829        char* crl_file = NULL;
     1830        if (sc->proxy_x509_crl_file)
     1831            crl_file = ap_server_root_relative(pool,
     1832                                               sc->proxy_x509_crl_file);
     1833
     1834        /* returns number of loaded elements */
     1835        err = gnutls_x509_trust_list_add_trust_file(sc->proxy_x509_tl,
     1836                                                    ca_file,
     1837                                                    crl_file,
     1838                                                    GNUTLS_X509_FMT_PEM,
     1839                                                    0 /* tl_flags */,
     1840                                                    0 /* tl_vflags */);
     1841        if (err > 0)
     1842            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     1843                         "%s: proxy CA trust list: %d structures loaded",
     1844                         __func__, err);
     1845        else if (err == 0)
     1846            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1847                         "%s: proxy CA trust list is empty (%d)",
     1848                         __func__, err);
     1849        else /* err < 0 */
     1850        {
     1851            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     1852                         "%s: error loading proxy CA trust list: %s (%d)",
     1853                         __func__, gnutls_strerror(err), err);
     1854            ret = APR_EGENERAL;
     1855        }
     1856
     1857        /* attach trust list to credentials */
     1858        gnutls_certificate_set_trust_list(sc->proxy_x509_creds,
     1859                                          sc->proxy_x509_tl, 0);
     1860    }
     1861    else
     1862        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
     1863                     "%s: no CA trust list for proxy connections, "
     1864                     "TLS connections will fail!", __func__);
     1865
     1866    gnutls_certificate_set_verify_function(sc->proxy_x509_creds,
     1867                                           gtls_check_server_cert);
     1868    apr_pool_destroy(pool);
     1869    return ret;
     1870}
Note: See TracChangeset for help on using the changeset viewer.