Changeset 31645b2 in mod_gnutls for src/mod_gnutls.c


Ignore:
Timestamp:
Apr 21, 2005, 1:15:56 PM (15 years ago)
Author:
Paul Querna <chip@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, master, msva, upstream
Children:
e924ddd
Parents:
0475f1bc
Message:

working SNI. Not so working Client Cert support.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/mod_gnutls.c

    r0475f1bc r31645b2  
    1818#include "mod_gnutls.h"
    1919
     20extern server_rec *ap_server_conf;
     21
    2022#if APR_HAS_THREADS
    2123GCRY_THREAD_OPTION_PTHREAD_IMPL;
     
    98100        return ret;
    99101    }
    100 
     102    apr_file_close(fp);
    101103    ret.data[br] = '\0';
    102104    ret.size = br;
     
    128130
    129131
    130     if (!first_run) {
     132    {
    131133        gnutls_datum pdata;
    132134        apr_pool_t* tpool;
     
    195197            sc->cache_config = sc_base->cache_config;
    196198
    197             if (sc->cert_file != NULL && sc->key_file != NULL) {
    198 
    199                 rv = gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file,
    200                                                  sc->key_file,
    201                                                  GNUTLS_X509_FMT_PEM);
    202                 if (rv != 0) {
    203                     ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
    204                          "[GnuTLS] - Host '%s:%d' has an invalid key or certificate:"
    205                          "(%s,%s) (%d) %s",
    206                          s->server_hostname, s->port, sc->cert_file, sc->key_file,
    207                          rv, gnutls_strerror(rv));
    208                 }
    209                 else {
    210                     gnutls_certificate_set_rsa_export_params(sc->certs,
     199            gnutls_certificate_set_rsa_export_params(sc->certs,
    211200                                                     rsa_params);
    212                     gnutls_certificate_set_dh_params(sc->certs, dh_params);
    213                 }
    214             }
    215             else if (sc->enabled == GNUTLS_ENABLED_TRUE) {
     201            gnutls_certificate_set_dh_params(sc->certs, dh_params);
     202
     203            if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    216204                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
    217205                             "[GnuTLS] - Host '%s:%d' is missing a "
    218                              "Cert and Key File!",
     206                             "Certificate File!",
    219207                         s->server_hostname, s->port);
     208                exit(-1);
     209            }
     210           
     211            if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     212                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
     213                             "[GnuTLS] - Host '%s:%d' is missing a "
     214                             "Private Key File!",
     215                             s->server_hostname, s->port);
     216                exit(-1);
     217            }
     218            {
     219                int rv;
     220                int data_len = 255;
     221                char crt_name[255];
     222                for (rv = 0; rv < data_len; rv++) {
     223                    crt_name[rv] = '\0';
     224                }
     225                rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
     226                                                   GNUTLS_OID_X520_COMMON_NAME, 0, 0,
     227                                                   crt_name, &data_len);
     228               
     229            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     230                         s,
     231                         "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", crt_name, rv,
     232                         gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)),
     233                         (unsigned int)s, (unsigned int)sc);
    220234            }
    221235        }
    222     } /* first_run */
     236    }
    223237
    224238    ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
     
    274288}
    275289
    276 /* TODO: Complete support for Server Name Indication */
     290#define MAX_HOST_LEN 255
    277291static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret)
    278292{
    279     char* server_name;
    280     int server_type;
    281     int data_len = 256;
    282     mod_gnutls_handle_t *ctxt;   
     293    int rv;
     294    int sni_type;
     295    int data_len = MAX_HOST_LEN;
     296    char sni_name[MAX_HOST_LEN];
     297    char crt_name[MAX_HOST_LEN];
     298    mod_gnutls_handle_t *ctxt;
     299    mod_gnutls_srvconf_rec *tsc;
     300    server_rec* s;
     301   
    283302    ctxt = gnutls_transport_get_ptr(session);
     303   
     304    sni_type = gnutls_certificate_type_get(session);
     305    if (sni_type != GNUTLS_CRT_X509) {
     306        /* In theory, we could support OpenPGP Certificates. Theory != code. */
     307        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     308                     ctxt->c->base_server,
     309                     "GnuTLS: Only x509 Certificates are currently supported.");
     310        return -1;
     311    }
    284312
    285313    ret->type = GNUTLS_CRT_X509;
    286314    ret->ncerts = 1;
    287     server_name = apr_palloc(ctxt->c->pool, data_len);
    288     if (gnutls_server_name_get(ctxt->session, server_name, &data_len, &server_type, 0) == 0) {
    289         if (server_type == GNUTLS_NAME_DNS) {
    290             ap_log_error(APLOG_MARK, APLOG_INFO, 0,
     315    ret->deinit_all = 0;
     316   
     317    rv = gnutls_server_name_get(ctxt->session, sni_name,
     318                                &data_len, &sni_type, 0);
     319
     320    if (rv != 0) {
     321        goto use_default_crt;
     322    }
     323
     324    if (sni_type != GNUTLS_NAME_DNS) {
     325        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     326                     ctxt->c->base_server,
     327                     "GnuTLS: Unknown type '%d' for SNI: "
     328                     "'%s'", sni_type, sni_name);       
     329        goto use_default_crt;
     330    }
     331   
     332    /**
     333     * Code in the Core already sets up the c->base_server as the base
     334     * for this IP/Port combo.  Trust that the core did the 'right' thing.
     335     */
     336    for (s = ap_server_conf; s; s = s->next) {
     337       
     338        tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
     339                                                             &gnutls_module);
     340        if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
     341            continue;
     342        }
     343       
     344        data_len = MAX_HOST_LEN;
     345        rv = gnutls_x509_crt_get_dn_by_oid(tsc->cert_x509,
     346                                           GNUTLS_OID_X520_COMMON_NAME, 0, 0,
     347                                           crt_name, &data_len);
     348        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     349                     ctxt->c->base_server,
     350                     "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X", crt_name, rv,
     351                     gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)),
     352                     (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc);
     353
     354        if (rv != 0) {
     355            continue;
     356        }
     357           
     358        /* The CN can contain a * -- this will match those too. */
     359        if (ap_strcasecmp_match(sni_name, crt_name) == 0) {
     360            /* found a match */
     361            ret->cert.x509 = &tsc->cert_x509;
     362            ret->key.x509 = tsc->privkey_x509;
     363#if MOD_GNUTLS_DEBUG
     364            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    291365                         ctxt->c->base_server,
    292366                         "GnuTLS: Virtual Host: "
    293                          "%s", server_name);
     367                         "'%s' == '%s'", crt_name, sni_name);
     368#endif
     369            return 0;
    294370        }
    295371    }
    296372
     373   
     374    /**
     375     * If the client does not support the Server Name Indication, give the default
     376     * certificate for this server.
     377     */
     378use_default_crt:
     379    data_len = MAX_HOST_LEN;
     380    rv = gnutls_x509_crt_get_dn_by_oid(ctxt->sc->cert_x509,
     381                                  GNUTLS_OID_X520_COMMON_NAME, 0, 0,
     382                                  crt_name, &data_len);
     383       
     384    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     385                     ctxt->c->base_server,
     386                     "GnuTLS: x509 cn: %s/%d pk: %s", crt_name, rv,
     387                 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)));
     388   
     389    ret->cert.x509 = &ctxt->sc->cert_x509;
     390    ret->key.x509 = ctxt->sc->privkey_x509;
     391#if MOD_GNUTLS_DEBUG
     392    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     393                 ctxt->c->base_server,
     394                 "GnuTLS: Using Default Certificate.");
     395#endif
    297396    return 0;
    298397}
     
    331430    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs);
    332431
    333     gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE);
     432    gnutls_certificate_server_set_request(ctxt->session, sc->client_verify_mode);
    334433
    335434    mod_gnutls_cache_session_init(ctxt);
    336435
    337436    /* TODO: Finish Support for Server Name Indication */
    338     /* gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn); */
     437    gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn);
    339438    return ctxt;
    340439}
     
    413512}
    414513
     514static int load_datum_from_file(apr_pool_t* pool,
     515                                const char* file,
     516                                gnutls_datum_t* data)
     517{
     518    apr_file_t* fp;
     519    apr_finfo_t finfo;
     520    apr_status_t rv;
     521    apr_size_t br = 0;
     522   
     523    rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT,
     524                       pool);
     525    if (rv != APR_SUCCESS) {
     526        return rv;
     527    }
     528   
     529    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
     530   
     531    if (rv != APR_SUCCESS) {
     532        return rv;
     533    }
     534   
     535    data->data = apr_palloc(pool, finfo.size+1);
     536    rv = apr_file_read_full(fp, data->data, finfo.size, &br);
     537   
     538    if (rv != APR_SUCCESS) {
     539        return rv;
     540    }
     541    apr_file_close(fp);
     542   
     543    data->data[br] = '\0';
     544    data->size = br;
     545   
     546    return 0;
     547}
     548
    415549static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy,
    416550                                        const char *arg)
    417551{
     552    int ret;
     553    gnutls_datum_t data;
     554    const char* file;
     555    apr_pool_t* spool;
    418556    mod_gnutls_srvconf_rec *sc =
    419557        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
    420558                                                        module_config,
    421559                                                        &gnutls_module);
    422     sc->cert_file = ap_server_root_relative(parms->pool, arg);
     560    apr_pool_create(&spool, parms->pool);
     561   
     562    file = ap_server_root_relative(spool, arg);
     563
     564    if (load_datum_from_file(spool, file, &data) != 0) {
     565        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     566                            "Certificate '%s'", file);
     567    }
     568   
     569    gnutls_x509_crt_init(&sc->cert_x509);
     570    ret = gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM);
     571    if (ret != 0) {
     572        return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
     573                            "Certificate'%s': (%d) %s", file, ret,
     574                            gnutls_strerror(ret));
     575    }
     576   
     577    //apr_pool_destroy(spool);
    423578    return NULL;
    424579}
     
    427582                                       const char *arg)
    428583{
     584    int ret;
     585    gnutls_datum_t data;
     586    const char* file;
     587    apr_pool_t* spool;
    429588    mod_gnutls_srvconf_rec *sc =
    430589        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
    431590                                                        module_config,
    432591                                                        &gnutls_module);
    433    
    434     sc->key_file = ap_server_root_relative(parms->pool, arg);
     592    apr_pool_create(&spool, parms->pool);
     593   
     594    file = ap_server_root_relative(spool, arg);
     595   
     596    if (load_datum_from_file(spool, file, &data) != 0) {
     597        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     598                            "Private Key '%s'", file);
     599    }
     600   
     601    gnutls_x509_privkey_init(&sc->privkey_x509);
     602    ret = gnutls_x509_privkey_import(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM);
     603    if (ret != 0) {
     604        return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
     605                            "Private Key '%s': (%d) %s", file, ret,
     606                            gnutls_strerror(ret));
     607    }
     608    //apr_pool_destroy(spool);
    435609    return NULL;
    436610}
     
    472646}
    473647
     648static const char *gnutls_set_cache_timeout(cmd_parms * parms, void *dummy,
     649                                            const char *arg)
     650{
     651    int argint;
     652    mod_gnutls_srvconf_rec *sc =
     653    (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
     654                                                    module_config,
     655                                                    &gnutls_module);
     656   
     657    argint = atoi(arg);
     658   
     659    if (argint < 0) {
     660        return "GnuTLSCacheTimeout: Invalid argument";
     661    }
     662    else if (argint == 0) {
     663        sc->cache_timeout = 0;
     664    }
     665    else {
     666        sc->cache_timeout = apr_time_from_sec(argint);
     667    }
     668   
     669    return NULL;
     670}
     671
     672
     673static const char *gnutls_set_client_verify(cmd_parms * parms, void *dummy,
     674                                            const char *arg)
     675{
     676    gnutls_certificate_request_t mode;
     677
     678    if (strcasecmp("none", arg) == 0  || strcasecmp("ignore", arg) == 0) {
     679        mode = GNUTLS_CERT_IGNORE;
     680    }
     681    else if (strcasecmp("optional", arg) == 0 || strcasecmp("request", arg) == 0) {
     682        mode = GNUTLS_CERT_REQUEST;
     683    }
     684    else if (strcasecmp("optional", arg) == 0) {
     685        mode = GNUTLS_CERT_REQUIRE;
     686    }
     687    else {
     688        return "GnuTLSClientVerify: Invalid argument";
     689    }
     690   
     691    /* This was set from a directory context */
     692    if (parms->path) {
     693        mod_gnutls_dirconf_rec *dc = (mod_gnutls_dirconf_rec *)dummy;
     694        dc->client_verify_mode = mode;
     695    }
     696    else {
     697        mod_gnutls_srvconf_rec *sc =
     698        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
     699                                                        module_config,
     700                                                        &gnutls_module);       
     701        sc->client_verify_mode = mode;
     702    }
     703
     704    return NULL;
     705}
    474706static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy,
    475707                                      const char *arg)
     
    493725
    494726static const command_rec gnutls_cmds[] = {
     727    AP_INIT_TAKE1("GnuTLSClientVerify", gnutls_set_client_verify,
     728                  NULL,
     729                  RSRC_CONF|OR_AUTHCFG,
     730                  "Set Verification Requirements of the Client Certificate"),
    495731    AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file,
    496732                  NULL,
     
    501737                  RSRC_CONF,
    502738                  "SSL Server Certificate file"),
     739    AP_INIT_TAKE1("GnuTLSCacheTimeout", gnutls_set_cache_timeout,
     740                  NULL,
     741                  RSRC_CONF,
     742                  "Cache Timeout"),
    503743    AP_INIT_TAKE2("GnuTLSCache", gnutls_set_cache,
    504744                  NULL,
     
    518758 *                 "CA"),
    519759 */
     760
     761int mod_gnutls_hook_authz(request_rec *r)
     762{
     763    return OK;
     764#if 0
     765    mod_gnutls_handle_t *ctxt;
     766    mod_gnutls_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
     767                                                      &gnutls_module);
     768   
     769    ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
     770
     771    if (dc->client_verify_mode == -1 ||
     772        dc->client_verify_mode == GNUTLS_CERT_IGNORE ||
     773        ctxt->sc->client_verify_mode > dc->client_verify_mode) {
     774        return DECLINED;
     775    }
     776
     777    gnutls_certificate_server_set_request(ctxt->session, dc->client_verify_mode);
     778    if (mod_gnutls_rehandshake(ctxt) != 0) {
     779        return HTTP_FORBIDDEN;
     780    }
     781#endif   
     782}
    520783
    521784static void gnutls_hooks(apr_pool_t * p)
     
    538801    ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL,
    539802                       APR_HOOK_MIDDLE);
    540 
    541     ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_MIDDLE);
     803   
     804    ap_hook_auth_checker(mod_gnutls_hook_authz, NULL, NULL, APR_HOOK_MIDDLE);
     805   
     806    ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
    542807
    543808    /* TODO: HTTP Upgrade Filter */
     
    561826
    562827    gnutls_certificate_allocate_credentials(&sc->certs);
    563     sc->key_file = NULL;
    564     sc->cert_file = NULL;
    565     sc->cache_timeout = apr_time_from_sec(3600);
     828    sc->privkey_x509 = NULL;
     829    sc->cert_x509 = NULL;
     830    sc->cache_timeout = apr_time_from_sec(300);
    566831    sc->cache_type = mod_gnutls_cache_dbm;
    567832    sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
    568833
    569     /* TODO: Make this Configurable ! */
     834    /* TODO: Make this Configurable. But it isn't configurable in mod_ssl? */
    570835    sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile");
    571836    sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile");
    572837
     838    /* Finish SSL Client Certificate Support */
     839    sc->client_verify_mode = GNUTLS_CERT_IGNORE;
     840
    573841    /* TODO: Make this Configurable ! */
    574     /* meh. mod_ssl uses a flex based parser for this part.. sigh */
     842    /* mod_ssl uses a flex based parser for this part.. sigh */
    575843    i = 0;
    576844    sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC;
     
    617885}
    618886
    619 
     887void *gnutls_config_dir_create(apr_pool_t *p, char *dir)
     888{
     889    mod_gnutls_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
     890
     891    dc->client_verify_mode = -1;
     892   
     893    return dc;
     894}
    620895
    621896module AP_MODULE_DECLARE_DATA gnutls_module = {
    622897    STANDARD20_MODULE_STUFF,
    623     NULL,
     898    gnutls_config_dir_create,
    624899    NULL,
    625900    gnutls_config_server_create,
Note: See TracChangeset for help on using the changeset viewer.