diff options
| -rw-r--r-- | include/mod_gnutls.h.in | 9 | ||||
| -rw-r--r-- | src/gnutls_io.c | 21 | ||||
| -rw-r--r-- | src/mod_gnutls.c | 259 |
3 files changed, 209 insertions, 80 deletions
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in index 6eff460..62cae02 100644 --- a/include/mod_gnutls.h.in +++ b/include/mod_gnutls.h.in | |||
| @@ -71,12 +71,13 @@ typedef enum | |||
| 71 | 71 | ||
| 72 | typedef struct | 72 | typedef struct |
| 73 | { | 73 | { |
| 74 | gnutls_certificate_request_t client_verify_mode; | 74 | int client_verify_mode; |
| 75 | } mod_gnutls_dirconf_rec; | 75 | } mod_gnutls_dirconf_rec; |
| 76 | 76 | ||
| 77 | typedef struct | 77 | typedef struct |
| 78 | { | 78 | { |
| 79 | gnutls_certificate_credentials_t certs; | 79 | gnutls_certificate_credentials_t certs; |
| 80 | char* cert_cn; | ||
| 80 | gnutls_x509_crt_t cert_x509; | 81 | gnutls_x509_crt_t cert_x509; |
| 81 | gnutls_x509_privkey_t privkey_x509; | 82 | gnutls_x509_privkey_t privkey_x509; |
| 82 | int enabled; | 83 | int enabled; |
| @@ -91,7 +92,7 @@ typedef struct | |||
| 91 | const char* cache_config; | 92 | const char* cache_config; |
| 92 | const char* rsa_params_file; | 93 | const char* rsa_params_file; |
| 93 | const char* dh_params_file; | 94 | const char* dh_params_file; |
| 94 | gnutls_certificate_request_t client_verify_mode; | 95 | int client_verify_mode; |
| 95 | } mod_gnutls_srvconf_rec; | 96 | } mod_gnutls_srvconf_rec; |
| 96 | 97 | ||
| 97 | typedef struct { | 98 | typedef struct { |
| @@ -179,6 +180,10 @@ ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr, | |||
| 179 | const void *buffer, size_t len); | 180 | const void *buffer, size_t len); |
| 180 | 181 | ||
| 181 | 182 | ||
| 183 | int mod_gnutls_rehandshake(mod_gnutls_handle_t * ctxt); | ||
| 184 | |||
| 185 | |||
| 186 | |||
| 182 | /** | 187 | /** |
| 183 | * Init the Cache after Configuration is done | 188 | * Init the Cache after Configuration is done |
| 184 | */ | 189 | */ |
diff --git a/src/gnutls_io.c b/src/gnutls_io.c index f081284..5e0c4ef 100644 --- a/src/gnutls_io.c +++ b/src/gnutls_io.c | |||
| @@ -358,12 +358,14 @@ static int gnutls_do_handshake(mod_gnutls_handle_t * ctxt) | |||
| 358 | int ret; | 358 | int ret; |
| 359 | int errcode; | 359 | int errcode; |
| 360 | if (ctxt->status != 0) { | 360 | if (ctxt->status != 0) { |
| 361 | return 0; | 361 | return -1; |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | tryagain: | 364 | tryagain: |
| 365 | 365 | do { | |
| 366 | ret = gnutls_handshake(ctxt->session); | 366 | ret = gnutls_handshake(ctxt->session); |
| 367 | } while (ret == GNUTLS_E_AGAIN); | ||
| 368 | |||
| 367 | if (ret < 0) { | 369 | if (ret < 0) { |
| 368 | if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED | 370 | if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED |
| 369 | || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { | 371 | || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { |
| @@ -392,7 +394,7 @@ tryagain: | |||
| 392 | else { | 394 | else { |
| 393 | /* all done with the handshake */ | 395 | /* all done with the handshake */ |
| 394 | ctxt->status = 1; | 396 | ctxt->status = 1; |
| 395 | return ret; | 397 | return 0; |
| 396 | } | 398 | } |
| 397 | } | 399 | } |
| 398 | 400 | ||
| @@ -411,14 +413,9 @@ int mod_gnutls_rehandshake(mod_gnutls_handle_t * ctxt) | |||
| 411 | 413 | ||
| 412 | ctxt->status = 0; | 414 | ctxt->status = 0; |
| 413 | 415 | ||
| 414 | gnutls_do_handshake(ctxt); | 416 | rv = gnutls_do_handshake(ctxt); |
| 415 | 417 | ||
| 416 | if (ctxt->status == 1) { | 418 | return rv; |
| 417 | return 0; | ||
| 418 | } | ||
| 419 | else { | ||
| 420 | return -1; | ||
| 421 | } | ||
| 422 | } | 419 | } |
| 423 | 420 | ||
| 424 | 421 | ||
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index be150a9..cb81a26 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include "mod_gnutls.h" | 18 | #include "mod_gnutls.h" |
| 19 | #include "http_vhost.h" | ||
| 19 | 20 | ||
| 20 | extern server_rec *ap_server_conf; | 21 | extern server_rec *ap_server_conf; |
| 21 | 22 | ||
| @@ -111,6 +112,7 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 111 | server_rec * base_server) | 112 | server_rec * base_server) |
| 112 | { | 113 | { |
| 113 | int rv; | 114 | int rv; |
| 115 | int data_len; | ||
| 114 | server_rec *s; | 116 | server_rec *s; |
| 115 | gnutls_dh_params_t dh_params; | 117 | gnutls_dh_params_t dh_params; |
| 116 | gnutls_rsa_params_t rsa_params; | 118 | gnutls_rsa_params_t rsa_params; |
| @@ -215,23 +217,26 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 215 | s->server_hostname, s->port); | 217 | s->server_hostname, s->port); |
| 216 | exit(-1); | 218 | exit(-1); |
| 217 | } | 219 | } |
| 218 | { | 220 | |
| 219 | int rv; | 221 | rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, |
| 220 | int data_len = 255; | 222 | GNUTLS_OID_X520_COMMON_NAME, 0, 0, |
| 221 | char crt_name[255]; | 223 | NULL, &data_len); |
| 222 | for (rv = 0; rv < data_len; rv++) { | 224 | |
| 223 | crt_name[rv] = '\0'; | 225 | if (data_len < 1) { |
| 224 | } | 226 | sc->enabled = GNUTLS_ENABLED_FALSE; |
| 225 | rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, | 227 | sc->cert_cn = NULL; |
| 226 | GNUTLS_OID_X520_COMMON_NAME, 0, 0, | 228 | continue; |
| 227 | crt_name, &data_len); | 229 | } |
| 228 | 230 | ||
| 231 | sc->cert_cn = apr_palloc(p, data_len); | ||
| 232 | rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, | ||
| 233 | GNUTLS_OID_X520_COMMON_NAME, 0, 0, | ||
| 234 | sc->cert_cn, &data_len); | ||
| 229 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, | 235 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, |
| 230 | s, | 236 | s, |
| 231 | "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", crt_name, rv, | 237 | "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", sc->cert_cn, rv, |
| 232 | gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)), | 238 | gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)), |
| 233 | (unsigned int)s, (unsigned int)sc); | 239 | (unsigned int)s, (unsigned int)sc); |
| 234 | } | ||
| 235 | } | 240 | } |
| 236 | } | 241 | } |
| 237 | 242 | ||
| @@ -287,17 +292,69 @@ static apr_port_t mod_gnutls_hook_default_port(const request_rec * r) | |||
| 287 | return 443; | 292 | return 443; |
| 288 | } | 293 | } |
| 289 | 294 | ||
| 295 | static void mod_gnutls_changed_servers(mod_gnutls_handle_t *ctxt) | ||
| 296 | { | ||
| 297 | gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs); | ||
| 298 | gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode); | ||
| 299 | } | ||
| 300 | |||
| 290 | #define MAX_HOST_LEN 255 | 301 | #define MAX_HOST_LEN 255 |
| 302 | |||
| 303 | #if USING_2_1_RECENT | ||
| 304 | typedef struct | ||
| 305 | { | ||
| 306 | mod_gnutls_handle_t *ctxt; | ||
| 307 | gnutls_retr_st* ret; | ||
| 308 | const char* sni_name; | ||
| 309 | } vhost_cb_rec; | ||
| 310 | |||
| 311 | int vhost_cb (void* baton, conn_rec* conn, server_rec* s) | ||
| 312 | { | ||
| 313 | mod_gnutls_srvconf_rec *tsc; | ||
| 314 | vhost_cb_rec* x = baton; | ||
| 315 | |||
| 316 | tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, | ||
| 317 | &gnutls_module); | ||
| 318 | |||
| 319 | if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { | ||
| 320 | return 0; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* The CN can contain a * -- this will match those too. */ | ||
| 324 | if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { | ||
| 325 | /* found a match */ | ||
| 326 | x->ret->cert.x509 = &tsc->cert_x509; | ||
| 327 | x->ret->key.x509 = tsc->privkey_x509; | ||
| 328 | #if MOD_GNUTLS_DEBUG | ||
| 329 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, | ||
| 330 | x->ctxt->c->base_server, | ||
| 331 | "GnuTLS: Virtual Host CB: " | ||
| 332 | "'%s' == '%s'", tsc->cert_cn, x->sni_name); | ||
| 333 | #endif | ||
| 334 | /* Because we actually change the server used here, we need to reset | ||
| 335 | * things like ClientVerify. | ||
| 336 | */ | ||
| 337 | x->ctxt->sc = tsc; | ||
| 338 | mod_gnutls_changed_servers(x->ctxt); | ||
| 339 | return 1; | ||
| 340 | } | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | #endif | ||
| 344 | |||
| 291 | static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) | 345 | static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) |
| 292 | { | 346 | { |
| 293 | int rv; | 347 | int rv; |
| 294 | int sni_type; | 348 | int sni_type; |
| 295 | int data_len = MAX_HOST_LEN; | 349 | int data_len = MAX_HOST_LEN; |
| 296 | char sni_name[MAX_HOST_LEN]; | 350 | char sni_name[MAX_HOST_LEN]; |
| 297 | char crt_name[MAX_HOST_LEN]; | ||
| 298 | mod_gnutls_handle_t *ctxt; | 351 | mod_gnutls_handle_t *ctxt; |
| 299 | mod_gnutls_srvconf_rec *tsc; | 352 | #if USING_2_1_RECENT |
| 353 | vhost_cb_rec cbx; | ||
| 354 | #else | ||
| 300 | server_rec* s; | 355 | server_rec* s; |
| 356 | mod_gnutls_srvconf_rec *tsc; | ||
| 357 | #endif | ||
| 301 | 358 | ||
| 302 | ctxt = gnutls_transport_get_ptr(session); | 359 | ctxt = gnutls_transport_get_ptr(session); |
| 303 | 360 | ||
| @@ -333,6 +390,16 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) | |||
| 333 | * Code in the Core already sets up the c->base_server as the base | 390 | * 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. | 391 | * for this IP/Port combo. Trust that the core did the 'right' thing. |
| 335 | */ | 392 | */ |
| 393 | #if USING_2_1_RECENT | ||
| 394 | cbx.ctxt = ctxt; | ||
| 395 | cbx.ret = ret; | ||
| 396 | cbx.sni_name = sni_name; | ||
| 397 | |||
| 398 | rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); | ||
| 399 | if (rv == 1) { | ||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | #else | ||
| 336 | for (s = ap_server_conf; s; s = s->next) { | 403 | for (s = ap_server_conf; s; s = s->next) { |
| 337 | 404 | ||
| 338 | tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, | 405 | tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, |
| @@ -340,23 +407,15 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) | |||
| 340 | if (tsc->enabled != GNUTLS_ENABLED_TRUE) { | 407 | if (tsc->enabled != GNUTLS_ENABLED_TRUE) { |
| 341 | continue; | 408 | continue; |
| 342 | } | 409 | } |
| 343 | 410 | #if MOD_GNUTLS_DEBUG | |
| 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, | 411 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, |
| 349 | ctxt->c->base_server, | 412 | 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, | 413 | "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", tsc->cert_cn, rv, |
| 351 | gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)), | 414 | 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); | 415 | (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc); |
| 353 | 416 | #endif | |
| 354 | if (rv != 0) { | ||
| 355 | continue; | ||
| 356 | } | ||
| 357 | |||
| 358 | /* The CN can contain a * -- this will match those too. */ | 417 | /* The CN can contain a * -- this will match those too. */ |
| 359 | if (ap_strcasecmp_match(sni_name, crt_name) == 0) { | 418 | if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) { |
| 360 | /* found a match */ | 419 | /* found a match */ |
| 361 | ret->cert.x509 = &tsc->cert_x509; | 420 | ret->cert.x509 = &tsc->cert_x509; |
| 362 | ret->key.x509 = tsc->privkey_x509; | 421 | ret->key.x509 = tsc->privkey_x509; |
| @@ -364,28 +423,20 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) | |||
| 364 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, | 423 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, |
| 365 | ctxt->c->base_server, | 424 | ctxt->c->base_server, |
| 366 | "GnuTLS: Virtual Host: " | 425 | "GnuTLS: Virtual Host: " |
| 367 | "'%s' == '%s'", crt_name, sni_name); | 426 | "'%s' == '%s'", tsc->cert_cn, sni_name); |
| 368 | #endif | 427 | #endif |
| 428 | ctxt->sc = tsc; | ||
| 429 | mod_gnutls_changed_servers(ctxt); | ||
| 369 | return 0; | 430 | return 0; |
| 370 | } | 431 | } |
| 371 | } | 432 | } |
| 372 | 433 | #endif | |
| 373 | 434 | ||
| 374 | /** | 435 | /** |
| 375 | * If the client does not support the Server Name Indication, give the default | 436 | * If the client does not support the Server Name Indication, give the default |
| 376 | * certificate for this server. | 437 | * certificate for this server. |
| 377 | */ | 438 | */ |
| 378 | use_default_crt: | 439 | use_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; | 440 | ret->cert.x509 = &ctxt->sc->cert_x509; |
| 390 | ret->key.x509 = ctxt->sc->privkey_x509; | 441 | ret->key.x509 = ctxt->sc->privkey_x509; |
| 391 | #if MOD_GNUTLS_DEBUG | 442 | #if MOD_GNUTLS_DEBUG |
| @@ -427,14 +478,11 @@ static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c) | |||
| 427 | gnutls_mac_set_priority(ctxt->session, sc->macs); | 478 | gnutls_mac_set_priority(ctxt->session, sc->macs); |
| 428 | gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types); | 479 | gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types); |
| 429 | 480 | ||
| 430 | gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs); | ||
| 431 | |||
| 432 | gnutls_certificate_server_set_request(ctxt->session, sc->client_verify_mode); | ||
| 433 | |||
| 434 | mod_gnutls_cache_session_init(ctxt); | 481 | mod_gnutls_cache_session_init(ctxt); |
| 435 | 482 | ||
| 436 | /* TODO: Finish Support for Server Name Indication */ | ||
| 437 | gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn); | 483 | gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn); |
| 484 | |||
| 485 | mod_gnutls_changed_servers(ctxt); | ||
| 438 | return ctxt; | 486 | return ctxt; |
| 439 | } | 487 | } |
| 440 | 488 | ||
| @@ -574,7 +622,7 @@ static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy, | |||
| 574 | gnutls_strerror(ret)); | 622 | gnutls_strerror(ret)); |
| 575 | } | 623 | } |
| 576 | 624 | ||
| 577 | //apr_pool_destroy(spool); | 625 | apr_pool_destroy(spool); |
| 578 | return NULL; | 626 | return NULL; |
| 579 | } | 627 | } |
| 580 | 628 | ||
| @@ -605,7 +653,7 @@ static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, | |||
| 605 | "Private Key '%s': (%d) %s", file, ret, | 653 | "Private Key '%s': (%d) %s", file, ret, |
| 606 | gnutls_strerror(ret)); | 654 | gnutls_strerror(ret)); |
| 607 | } | 655 | } |
| 608 | //apr_pool_destroy(spool); | 656 | apr_pool_destroy(spool); |
| 609 | return NULL; | 657 | return NULL; |
| 610 | } | 658 | } |
| 611 | 659 | ||
| @@ -673,15 +721,15 @@ static const char *gnutls_set_cache_timeout(cmd_parms * parms, void *dummy, | |||
| 673 | static const char *gnutls_set_client_verify(cmd_parms * parms, void *dummy, | 721 | static const char *gnutls_set_client_verify(cmd_parms * parms, void *dummy, |
| 674 | const char *arg) | 722 | const char *arg) |
| 675 | { | 723 | { |
| 676 | gnutls_certificate_request_t mode; | 724 | int mode; |
| 677 | 725 | ||
| 678 | if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { | 726 | if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { |
| 679 | mode = GNUTLS_CERT_IGNORE; | 727 | mode = GNUTLS_CERT_IGNORE; |
| 680 | } | 728 | } |
| 681 | else if (strcasecmp("optional", arg) == 0 || strcasecmp("request", arg) == 0) { | 729 | else if (strcasecmp("optional", arg) == 0 || strcasecmp("request", arg) == 0) { |
| 682 | mode = GNUTLS_CERT_REQUEST; | 730 | mode = GNUTLS_CERT_REQUEST; |
| 683 | } | 731 | } |
| 684 | else if (strcasecmp("optional", arg) == 0) { | 732 | else if (strcasecmp("require", arg) == 0) { |
| 685 | mode = GNUTLS_CERT_REQUIRE; | 733 | mode = GNUTLS_CERT_REQUIRE; |
| 686 | } | 734 | } |
| 687 | else { | 735 | else { |
| @@ -703,6 +751,29 @@ static const char *gnutls_set_client_verify(cmd_parms * parms, void *dummy, | |||
| 703 | 751 | ||
| 704 | return NULL; | 752 | return NULL; |
| 705 | } | 753 | } |
| 754 | |||
| 755 | static const char *gnutls_set_client_ca_file(cmd_parms * parms, void *dummy, | ||
| 756 | const char *arg) | ||
| 757 | { | ||
| 758 | int rv; | ||
| 759 | const char* file; | ||
| 760 | mod_gnutls_srvconf_rec *sc = | ||
| 761 | (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> | ||
| 762 | module_config, | ||
| 763 | &gnutls_module); | ||
| 764 | file = ap_server_root_relative(parms->pool, arg); | ||
| 765 | rv = gnutls_certificate_set_x509_trust_file(sc->certs, | ||
| 766 | file, GNUTLS_X509_FMT_PEM); | ||
| 767 | |||
| 768 | if (rv < 0) { | ||
| 769 | return apr_psprintf(parms->pool, "GnuTLS: Failed to load " | ||
| 770 | "Client CA File '%s': (%d) %s", file, rv, | ||
| 771 | gnutls_strerror(rv)); | ||
| 772 | } | ||
| 773 | return NULL; | ||
| 774 | } | ||
| 775 | |||
| 776 | |||
| 706 | static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy, | 777 | static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy, |
| 707 | const char *arg) | 778 | const char *arg) |
| 708 | { | 779 | { |
| @@ -728,6 +799,10 @@ static const command_rec gnutls_cmds[] = { | |||
| 728 | NULL, | 799 | NULL, |
| 729 | RSRC_CONF|OR_AUTHCFG, | 800 | RSRC_CONF|OR_AUTHCFG, |
| 730 | "Set Verification Requirements of the Client Certificate"), | 801 | "Set Verification Requirements of the Client Certificate"), |
| 802 | AP_INIT_TAKE1("GnuTLSClientCAFile", gnutls_set_client_ca_file, | ||
| 803 | NULL, | ||
| 804 | RSRC_CONF, | ||
| 805 | "Set the CA File for Client Certificates"), | ||
| 731 | AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file, | 806 | AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file, |
| 732 | NULL, | 807 | NULL, |
| 733 | RSRC_CONF, | 808 | RSRC_CONF, |
| @@ -751,34 +826,86 @@ static const command_rec gnutls_cmds[] = { | |||
| 751 | {NULL} | 826 | {NULL} |
| 752 | }; | 827 | }; |
| 753 | 828 | ||
| 754 | /* TODO: CACertificateFile & Client Authentication | ||
| 755 | * AP_INIT_TAKE1("GnuTLSCACertificateFile", ap_set_server_string_slot, | ||
| 756 | * (void *) APR_OFFSETOF(gnutls_srvconf_rec, key_file), NULL, | ||
| 757 | * RSRC_CONF, | ||
| 758 | * "CA"), | ||
| 759 | */ | ||
| 760 | |||
| 761 | int mod_gnutls_hook_authz(request_rec *r) | 829 | int mod_gnutls_hook_authz(request_rec *r) |
| 762 | { | 830 | { |
| 763 | return OK; | 831 | int rv; |
| 764 | #if 0 | 832 | int status; |
| 765 | mod_gnutls_handle_t *ctxt; | 833 | mod_gnutls_handle_t *ctxt; |
| 766 | mod_gnutls_dirconf_rec *dc = ap_get_module_config(r->per_dir_config, | 834 | mod_gnutls_dirconf_rec *dc = ap_get_module_config(r->per_dir_config, |
| 767 | &gnutls_module); | 835 | &gnutls_module); |
| 768 | 836 | ||
| 769 | ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module); | 837 | ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module); |
| 770 | 838 | ||
| 771 | if (dc->client_verify_mode == -1 || | 839 | if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { |
| 772 | dc->client_verify_mode == GNUTLS_CERT_IGNORE || | 840 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
| 773 | ctxt->sc->client_verify_mode > dc->client_verify_mode) { | 841 | "GnuTLS: Ignoring Client Certificate!"); |
| 774 | return DECLINED; | 842 | return DECLINED; |
| 775 | } | 843 | } |
| 776 | 844 | ||
| 777 | gnutls_certificate_server_set_request(ctxt->session, dc->client_verify_mode); | 845 | if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { |
| 778 | if (mod_gnutls_rehandshake(ctxt) != 0) { | 846 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
| 847 | "GnuTLS: Attempting to rehandshake with peer. %d %d", | ||
| 848 | ctxt->sc->client_verify_mode, dc->client_verify_mode); | ||
| 849 | |||
| 850 | gnutls_certificate_server_set_request(ctxt->session, | ||
| 851 | dc->client_verify_mode); | ||
| 852 | |||
| 853 | if (mod_gnutls_rehandshake(ctxt) != 0) { | ||
| 854 | return HTTP_FORBIDDEN; | ||
| 855 | } | ||
| 856 | } | ||
| 857 | else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) { | ||
| 858 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 859 | "GnuTLS: Peer is set to IGNORE"); | ||
| 860 | return DECLINED; | ||
| 861 | } | ||
| 862 | |||
| 863 | rv = gnutls_certificate_verify_peers2(ctxt->session, &status); | ||
| 864 | |||
| 865 | if (rv < 0) { | ||
| 866 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 867 | "GnuTLS: Failed to Verify Peer: (%d) %s", | ||
| 868 | rv, gnutls_strerror(rv)); | ||
| 869 | return HTTP_FORBIDDEN; | ||
| 870 | } | ||
| 871 | |||
| 872 | if (status < 0) { | ||
| 873 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 874 | "GnuTLS: Peer Status is invalid."); | ||
| 875 | return HTTP_FORBIDDEN; | ||
| 876 | } | ||
| 877 | |||
| 878 | if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { | ||
| 879 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 880 | "GnuTLS: Could not find Signer for Peer Certificate"); | ||
| 881 | } | ||
| 882 | |||
| 883 | if (status & GNUTLS_CERT_SIGNER_NOT_CA) { | ||
| 884 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 885 | "GnuTLS: Could not find CA for Peer Certificate"); | ||
| 886 | } | ||
| 887 | |||
| 888 | if (status & GNUTLS_CERT_INVALID) { | ||
| 889 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 890 | "GnuTLS: Peer Certificate is invalid."); | ||
| 891 | return HTTP_FORBIDDEN; | ||
| 892 | } | ||
| 893 | else if (status & GNUTLS_CERT_REVOKED) { | ||
| 894 | ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, | ||
| 895 | "GnuTLS: Peer Certificate is revoked."); | ||
| 779 | return HTTP_FORBIDDEN; | 896 | return HTTP_FORBIDDEN; |
| 780 | } | 897 | } |
| 781 | #endif | 898 | |
| 899 | /* TODO: OpenPGP Certificates */ | ||
| 900 | if (gnutls_certificate_type_get(ctxt->session) != GNUTLS_CRT_X509) { | ||
| 901 | ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, | ||
| 902 | "GnuTLS: Only x509 is supported for client certificates"); | ||
| 903 | return HTTP_FORBIDDEN; | ||
| 904 | } | ||
| 905 | /* TODO: Further Verification. */ | ||
| 906 | ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, | ||
| 907 | "GnuTLS: Verified Peer."); | ||
| 908 | return OK; | ||
| 782 | } | 909 | } |
| 783 | 910 | ||
| 784 | static void gnutls_hooks(apr_pool_t * p) | 911 | static void gnutls_hooks(apr_pool_t * p) |
| @@ -801,8 +928,8 @@ static void gnutls_hooks(apr_pool_t * p) | |||
| 801 | ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL, | 928 | ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL, |
| 802 | APR_HOOK_MIDDLE); | 929 | APR_HOOK_MIDDLE); |
| 803 | 930 | ||
| 804 | ap_hook_auth_checker(mod_gnutls_hook_authz, NULL, NULL, APR_HOOK_MIDDLE); | 931 | ap_hook_access_checker(mod_gnutls_hook_authz, NULL, NULL, APR_HOOK_REALLY_FIRST); |
| 805 | 932 | ||
| 806 | ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST); | 933 | ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST); |
| 807 | 934 | ||
| 808 | /* TODO: HTTP Upgrade Filter */ | 935 | /* TODO: HTTP Upgrade Filter */ |
