diff options
| author | 2005-04-21 17:15:56 +0000 | |
|---|---|---|
| committer | 2005-04-21 17:15:56 +0000 | |
| commit | 31645b2ad4f81c5ce3ca8ee9a671f24fb35715cd (patch) | |
| tree | bde214555fb7612674bf4f3cbcf72db37f096b2f | |
| parent | 0475f1bc49d07ab75f33899e6c0d1b32f884c68b (diff) | |
working SNI. Not so working Client Cert support.
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | include/mod_gnutls.h.in | 17 | ||||
| -rw-r--r-- | src/gnutls_io.c | 54 | ||||
| -rw-r--r-- | src/mod_gnutls.c | 363 |
4 files changed, 362 insertions, 74 deletions
diff --git a/configure.ac b/configure.ac index b504eca..a16da41 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | AC_INIT(mod_gnutls, 0.1.1) | 1 | AC_INIT(mod_gnutls, 0.2.0) |
| 2 | OOO_CONFIG_NICE(config.nice) | 2 | OOO_CONFIG_NICE(config.nice) |
| 3 | MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION | 3 | MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION |
| 4 | AC_PREREQ(2.53) | 4 | AC_PREREQ(2.53) |
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in index d9b989e..6eff460 100644 --- a/include/mod_gnutls.h.in +++ b/include/mod_gnutls.h.in | |||
| @@ -27,14 +27,15 @@ | |||
| 27 | #include "apr_tables.h" | 27 | #include "apr_tables.h" |
| 28 | #include "ap_release.h" | 28 | #include "ap_release.h" |
| 29 | 29 | ||
| 30 | #include <gcrypt.h> | ||
| 31 | #include <gnutls/gnutls.h> | ||
| 32 | #include <gnutls/x509.h> | ||
| 33 | |||
| 30 | #ifndef __mod_gnutls_h_inc | 34 | #ifndef __mod_gnutls_h_inc |
| 31 | #define __mod_gnutls_h_inc | 35 | #define __mod_gnutls_h_inc |
| 32 | 36 | ||
| 33 | #define HAVE_APR_MEMCACHE @have_apr_memcache@ | 37 | #define HAVE_APR_MEMCACHE @have_apr_memcache@ |
| 34 | 38 | ||
| 35 | #include <gcrypt.h> | ||
| 36 | #include <gnutls/gnutls.h> | ||
| 37 | |||
| 38 | module AP_MODULE_DECLARE_DATA gnutls_module; | 39 | module AP_MODULE_DECLARE_DATA gnutls_module; |
| 39 | 40 | ||
| 40 | #define GNUTLS_OUTPUT_FILTER_NAME "gnutls_output_filter" | 41 | #define GNUTLS_OUTPUT_FILTER_NAME "gnutls_output_filter" |
| @@ -70,9 +71,14 @@ typedef enum | |||
| 70 | 71 | ||
| 71 | typedef struct | 72 | typedef struct |
| 72 | { | 73 | { |
| 74 | gnutls_certificate_request_t client_verify_mode; | ||
| 75 | } mod_gnutls_dirconf_rec; | ||
| 76 | |||
| 77 | typedef struct | ||
| 78 | { | ||
| 73 | gnutls_certificate_credentials_t certs; | 79 | gnutls_certificate_credentials_t certs; |
| 74 | char *key_file; | 80 | gnutls_x509_crt_t cert_x509; |
| 75 | char *cert_file; | 81 | gnutls_x509_privkey_t privkey_x509; |
| 76 | int enabled; | 82 | int enabled; |
| 77 | int ciphers[16]; | 83 | int ciphers[16]; |
| 78 | int key_exchange[16]; | 84 | int key_exchange[16]; |
| @@ -85,6 +91,7 @@ typedef struct | |||
| 85 | const char* cache_config; | 91 | const char* cache_config; |
| 86 | const char* rsa_params_file; | 92 | const char* rsa_params_file; |
| 87 | const char* dh_params_file; | 93 | const char* dh_params_file; |
| 94 | gnutls_certificate_request_t client_verify_mode; | ||
| 88 | } mod_gnutls_srvconf_rec; | 95 | } mod_gnutls_srvconf_rec; |
| 89 | 96 | ||
| 90 | typedef struct { | 97 | typedef struct { |
diff --git a/src/gnutls_io.c b/src/gnutls_io.c index f761f96..f081284 100644 --- a/src/gnutls_io.c +++ b/src/gnutls_io.c | |||
| @@ -353,13 +353,12 @@ static apr_status_t gnutls_io_input_getline(mod_gnutls_handle_t * ctxt, | |||
| 353 | return APR_SUCCESS; | 353 | return APR_SUCCESS; |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | 356 | static int gnutls_do_handshake(mod_gnutls_handle_t * ctxt) | |
| 357 | static void gnutls_do_handshake(mod_gnutls_handle_t * ctxt) | ||
| 358 | { | 357 | { |
| 359 | int ret; | 358 | int ret; |
| 360 | int errcode; | 359 | int errcode; |
| 361 | if (ctxt->status != 0) { | 360 | if (ctxt->status != 0) { |
| 362 | return; | 361 | return 0; |
| 363 | } | 362 | } |
| 364 | 363 | ||
| 365 | tryagain: | 364 | tryagain: |
| @@ -388,11 +387,37 @@ tryagain: | |||
| 388 | gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, | 387 | gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, |
| 389 | gnutls_error_to_alert(ret, NULL)); | 388 | gnutls_error_to_alert(ret, NULL)); |
| 390 | gnutls_deinit(ctxt->session); | 389 | gnutls_deinit(ctxt->session); |
| 391 | return; | 390 | return ret; |
| 392 | } | 391 | } |
| 393 | else { | 392 | else { |
| 393 | /* all done with the handshake */ | ||
| 394 | ctxt->status = 1; | 394 | ctxt->status = 1; |
| 395 | return; /* all done with the handshake */ | 395 | return ret; |
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | int mod_gnutls_rehandshake(mod_gnutls_handle_t * ctxt) | ||
| 400 | { | ||
| 401 | int rv; | ||
| 402 | |||
| 403 | rv = gnutls_rehandshake(ctxt->session); | ||
| 404 | |||
| 405 | if (rv != 0) { | ||
| 406 | /* the client did not want to rehandshake. goodbye */ | ||
| 407 | ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server, | ||
| 408 | "GnuTLS: Client Refused Rehandshake request."); | ||
| 409 | return -1; | ||
| 410 | } | ||
| 411 | |||
| 412 | ctxt->status = 0; | ||
| 413 | |||
| 414 | gnutls_do_handshake(ctxt); | ||
| 415 | |||
| 416 | if (ctxt->status == 1) { | ||
| 417 | return 0; | ||
| 418 | } | ||
| 419 | else { | ||
| 420 | return -1; | ||
| 396 | } | 421 | } |
| 397 | } | 422 | } |
| 398 | 423 | ||
| @@ -414,26 +439,7 @@ apr_status_t mod_gnutls_filter_input(ap_filter_t* f, | |||
| 414 | } | 439 | } |
| 415 | 440 | ||
| 416 | if (ctxt->status == 0) { | 441 | if (ctxt->status == 0) { |
| 417 | char* server_name; | ||
| 418 | int server_type; | ||
| 419 | int data_len = 256; | ||
| 420 | |||
| 421 | gnutls_do_handshake(ctxt); | 442 | gnutls_do_handshake(ctxt); |
| 422 | |||
| 423 | /** | ||
| 424 | * Due to issues inside the GnuTLS API, we cannot currently do TLS 1.1 | ||
| 425 | * Server Name Indication. | ||
| 426 | */ | ||
| 427 | server_name = apr_palloc(ctxt->c->pool, data_len); | ||
| 428 | if (gnutls_server_name_get(ctxt->session, server_name, &data_len, &server_type, 0) == 0) { | ||
| 429 | if (server_type == GNUTLS_NAME_DNS) { | ||
| 430 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, | ||
| 431 | ctxt->c->base_server, | ||
| 432 | "GnuTLS: TLS 1.1 Server Name: " | ||
| 433 | "%s", server_name); | ||
| 434 | |||
| 435 | } | ||
| 436 | } | ||
| 437 | } | 443 | } |
| 438 | 444 | ||
| 439 | if (ctxt->status < 0) { | 445 | if (ctxt->status < 0) { |
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index 71076ef..be150a9 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | #include "mod_gnutls.h" | 18 | #include "mod_gnutls.h" |
| 19 | 19 | ||
| 20 | extern server_rec *ap_server_conf; | ||
| 21 | |||
| 20 | #if APR_HAS_THREADS | 22 | #if APR_HAS_THREADS |
| 21 | GCRY_THREAD_OPTION_PTHREAD_IMPL; | 23 | GCRY_THREAD_OPTION_PTHREAD_IMPL; |
| 22 | #endif | 24 | #endif |
| @@ -97,7 +99,7 @@ static gnutls_datum load_params(const char* file, server_rec* s, | |||
| 97 | "GnuTLS failed to read params file at: %s", file); | 99 | "GnuTLS failed to read params file at: %s", file); |
| 98 | return ret; | 100 | return ret; |
| 99 | } | 101 | } |
| 100 | 102 | apr_file_close(fp); | |
| 101 | ret.data[br] = '\0'; | 103 | ret.data[br] = '\0'; |
| 102 | ret.size = br; | 104 | ret.size = br; |
| 103 | 105 | ||
| @@ -127,7 +129,7 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 127 | } | 129 | } |
| 128 | 130 | ||
| 129 | 131 | ||
| 130 | if (!first_run) { | 132 | { |
| 131 | gnutls_datum pdata; | 133 | gnutls_datum pdata; |
| 132 | apr_pool_t* tpool; | 134 | apr_pool_t* tpool; |
| 133 | s = base_server; | 135 | s = base_server; |
| @@ -194,32 +196,44 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, | |||
| 194 | sc->cache_type = sc_base->cache_type; | 196 | sc->cache_type = sc_base->cache_type; |
| 195 | sc->cache_config = sc_base->cache_config; | 197 | sc->cache_config = sc_base->cache_config; |
| 196 | 198 | ||
| 197 | if (sc->cert_file != NULL && sc->key_file != NULL) { | 199 | gnutls_certificate_set_rsa_export_params(sc->certs, |
| 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, | ||
| 211 | rsa_params); | 200 | rsa_params); |
| 212 | gnutls_certificate_set_dh_params(sc->certs, dh_params); | 201 | gnutls_certificate_set_dh_params(sc->certs, dh_params); |
| 213 | } | 202 | |
| 214 | } | 203 | if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) { |
| 215 | else if (sc->enabled == GNUTLS_ENABLED_TRUE) { | ||
| 216 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, | 204 | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, |
| 217 | "[GnuTLS] - Host '%s:%d' is missing a " | 205 | "[GnuTLS] - Host '%s:%d' is missing a " |
| 218 | "Cert and Key File!", | 206 | "Certificate File!", |
| 219 | s->server_hostname, s->port); | 207 | 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); | ||
| 220 | } | 234 | } |
| 221 | } | 235 | } |
| 222 | } /* first_run */ | 236 | } |
| 223 | 237 | ||
| 224 | ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); | 238 | ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); |
| 225 | 239 | ||
| @@ -273,27 +287,112 @@ static apr_port_t mod_gnutls_hook_default_port(const request_rec * r) | |||
| 273 | return 443; | 287 | return 443; |
| 274 | } | 288 | } |
| 275 | 289 | ||
| 276 | /* TODO: Complete support for Server Name Indication */ | 290 | #define MAX_HOST_LEN 255 |
| 277 | static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) | 291 | static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) |
| 278 | { | 292 | { |
| 279 | char* server_name; | 293 | int rv; |
| 280 | int server_type; | 294 | int sni_type; |
| 281 | int data_len = 256; | 295 | int data_len = MAX_HOST_LEN; |
| 282 | mod_gnutls_handle_t *ctxt; | 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 | |||
| 283 | ctxt = gnutls_transport_get_ptr(session); | 302 | 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 | } | ||
| 284 | 312 | ||
| 285 | ret->type = GNUTLS_CRT_X509; | 313 | ret->type = GNUTLS_CRT_X509; |
| 286 | ret->ncerts = 1; | 314 | ret->ncerts = 1; |
| 287 | server_name = apr_palloc(ctxt->c->pool, data_len); | 315 | ret->deinit_all = 0; |
| 288 | if (gnutls_server_name_get(ctxt->session, server_name, &data_len, &server_type, 0) == 0) { | 316 | |
| 289 | if (server_type == GNUTLS_NAME_DNS) { | 317 | rv = gnutls_server_name_get(ctxt->session, sni_name, |
| 290 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, | 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, | ||
| 291 | ctxt->c->base_server, | 365 | ctxt->c->base_server, |
| 292 | "GnuTLS: Virtual Host: " | 366 | "GnuTLS: Virtual Host: " |
| 293 | "%s", server_name); | 367 | "'%s' == '%s'", crt_name, sni_name); |
| 368 | #endif | ||
| 369 | return 0; | ||
| 294 | } | 370 | } |
| 295 | } | 371 | } |
| 296 | 372 | ||
| 373 | |||
| 374 | /** | ||
| 375 | * If the client does not support the Server Name Indication, give the default | ||
| 376 | * certificate for this server. | ||
| 377 | */ | ||
| 378 | 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; | ||
| 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 | ||
| 297 | return 0; | 396 | return 0; |
| 298 | } | 397 | } |
| 299 | 398 | ||
| @@ -330,12 +429,12 @@ static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c) | |||
| 330 | 429 | ||
| 331 | gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs); | 430 | gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs); |
| 332 | 431 | ||
| 333 | gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE); | 432 | gnutls_certificate_server_set_request(ctxt->session, sc->client_verify_mode); |
| 334 | 433 | ||
| 335 | mod_gnutls_cache_session_init(ctxt); | 434 | mod_gnutls_cache_session_init(ctxt); |
| 336 | 435 | ||
| 337 | /* TODO: Finish Support for Server Name Indication */ | 436 | /* 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); |
| 339 | return ctxt; | 438 | return ctxt; |
| 340 | } | 439 | } |
| 341 | 440 | ||
| @@ -412,26 +511,101 @@ static int mod_gnutls_hook_fixups(request_rec *r) | |||
| 412 | return OK; | 511 | return OK; |
| 413 | } | 512 | } |
| 414 | 513 | ||
| 514 | static 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 | |||
| 415 | static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy, | 549 | static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy, |
| 416 | const char *arg) | 550 | const char *arg) |
| 417 | { | 551 | { |
| 552 | int ret; | ||
| 553 | gnutls_datum_t data; | ||
| 554 | const char* file; | ||
| 555 | apr_pool_t* spool; | ||
| 418 | mod_gnutls_srvconf_rec *sc = | 556 | mod_gnutls_srvconf_rec *sc = |
| 419 | (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> | 557 | (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> |
| 420 | module_config, | 558 | module_config, |
| 421 | &gnutls_module); | 559 | &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); | ||
| 423 | return NULL; | 578 | return NULL; |
| 424 | } | 579 | } |
| 425 | 580 | ||
| 426 | static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, | 581 | static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, |
| 427 | const char *arg) | 582 | const char *arg) |
| 428 | { | 583 | { |
| 584 | int ret; | ||
| 585 | gnutls_datum_t data; | ||
| 586 | const char* file; | ||
| 587 | apr_pool_t* spool; | ||
| 429 | mod_gnutls_srvconf_rec *sc = | 588 | mod_gnutls_srvconf_rec *sc = |
| 430 | (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> | 589 | (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> |
| 431 | module_config, | 590 | module_config, |
| 432 | &gnutls_module); | 591 | &gnutls_module); |
| 592 | apr_pool_create(&spool, parms->pool); | ||
| 433 | 593 | ||
| 434 | sc->key_file = ap_server_root_relative(parms->pool, arg); | 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); | ||
| 435 | return NULL; | 609 | return NULL; |
| 436 | } | 610 | } |
| 437 | 611 | ||
| @@ -471,6 +645,64 @@ static const char *gnutls_set_cache(cmd_parms * parms, void *dummy, | |||
| 471 | return NULL; | 645 | return NULL; |
| 472 | } | 646 | } |
| 473 | 647 | ||
| 648 | static 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 | |||
| 673 | static 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 | } | ||
| 474 | static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy, | 706 | static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy, |
| 475 | const char *arg) | 707 | const char *arg) |
| 476 | { | 708 | { |
| @@ -492,6 +724,10 @@ static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy, | |||
| 492 | } | 724 | } |
| 493 | 725 | ||
| 494 | static const command_rec gnutls_cmds[] = { | 726 | static 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"), | ||
| 495 | AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file, | 731 | AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file, |
| 496 | NULL, | 732 | NULL, |
| 497 | RSRC_CONF, | 733 | RSRC_CONF, |
| @@ -500,6 +736,10 @@ static const command_rec gnutls_cmds[] = { | |||
| 500 | NULL, | 736 | NULL, |
| 501 | RSRC_CONF, | 737 | RSRC_CONF, |
| 502 | "SSL Server Certificate file"), | 738 | "SSL Server Certificate file"), |
| 739 | AP_INIT_TAKE1("GnuTLSCacheTimeout", gnutls_set_cache_timeout, | ||
| 740 | NULL, | ||
| 741 | RSRC_CONF, | ||
| 742 | "Cache Timeout"), | ||
| 503 | AP_INIT_TAKE2("GnuTLSCache", gnutls_set_cache, | 743 | AP_INIT_TAKE2("GnuTLSCache", gnutls_set_cache, |
| 504 | NULL, | 744 | NULL, |
| 505 | RSRC_CONF, | 745 | RSRC_CONF, |
| @@ -518,6 +758,29 @@ static const command_rec gnutls_cmds[] = { | |||
| 518 | * "CA"), | 758 | * "CA"), |
| 519 | */ | 759 | */ |
| 520 | 760 | ||
| 761 | int 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 | } | ||
| 783 | |||
| 521 | static void gnutls_hooks(apr_pool_t * p) | 784 | static void gnutls_hooks(apr_pool_t * p) |
| 522 | { | 785 | { |
| 523 | ap_hook_pre_connection(mod_gnutls_hook_pre_connection, NULL, NULL, | 786 | ap_hook_pre_connection(mod_gnutls_hook_pre_connection, NULL, NULL, |
| @@ -537,8 +800,10 @@ static void gnutls_hooks(apr_pool_t * p) | |||
| 537 | APR_HOOK_MIDDLE); | 800 | APR_HOOK_MIDDLE); |
| 538 | ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL, | 801 | ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL, |
| 539 | APR_HOOK_MIDDLE); | 802 | APR_HOOK_MIDDLE); |
| 540 | 803 | ||
| 541 | ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_MIDDLE); | 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); | ||
| 542 | 807 | ||
| 543 | /* TODO: HTTP Upgrade Filter */ | 808 | /* TODO: HTTP Upgrade Filter */ |
| 544 | /* ap_register_output_filter ("UPGRADE_FILTER", | 809 | /* ap_register_output_filter ("UPGRADE_FILTER", |
| @@ -560,18 +825,21 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) | |||
| 560 | sc->enabled = GNUTLS_ENABLED_FALSE; | 825 | sc->enabled = GNUTLS_ENABLED_FALSE; |
| 561 | 826 | ||
| 562 | gnutls_certificate_allocate_credentials(&sc->certs); | 827 | gnutls_certificate_allocate_credentials(&sc->certs); |
| 563 | sc->key_file = NULL; | 828 | sc->privkey_x509 = NULL; |
| 564 | sc->cert_file = NULL; | 829 | sc->cert_x509 = NULL; |
| 565 | sc->cache_timeout = apr_time_from_sec(3600); | 830 | sc->cache_timeout = apr_time_from_sec(300); |
| 566 | sc->cache_type = mod_gnutls_cache_dbm; | 831 | sc->cache_type = mod_gnutls_cache_dbm; |
| 567 | sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); | 832 | sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); |
| 568 | 833 | ||
| 569 | /* TODO: Make this Configurable ! */ | 834 | /* TODO: Make this Configurable. But it isn't configurable in mod_ssl? */ |
| 570 | sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile"); | 835 | sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile"); |
| 571 | sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile"); | 836 | sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile"); |
| 572 | 837 | ||
| 838 | /* Finish SSL Client Certificate Support */ | ||
| 839 | sc->client_verify_mode = GNUTLS_CERT_IGNORE; | ||
| 840 | |||
| 573 | /* TODO: Make this Configurable ! */ | 841 | /* 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 */ |
| 575 | i = 0; | 843 | i = 0; |
| 576 | sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC; | 844 | sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC; |
| 577 | sc->ciphers[i++] = GNUTLS_CIPHER_AES_128_CBC; | 845 | sc->ciphers[i++] = GNUTLS_CIPHER_AES_128_CBC; |
| @@ -616,11 +884,18 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) | |||
| 616 | return sc; | 884 | return sc; |
| 617 | } | 885 | } |
| 618 | 886 | ||
| 887 | void *gnutls_config_dir_create(apr_pool_t *p, char *dir) | ||
| 888 | { | ||
| 889 | mod_gnutls_dirconf_rec *dc = apr_palloc(p, sizeof(*dc)); | ||
| 619 | 890 | ||
| 891 | dc->client_verify_mode = -1; | ||
| 892 | |||
| 893 | return dc; | ||
| 894 | } | ||
| 620 | 895 | ||
| 621 | module AP_MODULE_DECLARE_DATA gnutls_module = { | 896 | module AP_MODULE_DECLARE_DATA gnutls_module = { |
| 622 | STANDARD20_MODULE_STUFF, | 897 | STANDARD20_MODULE_STUFF, |
| 623 | NULL, | 898 | gnutls_config_dir_create, |
| 624 | NULL, | 899 | NULL, |
| 625 | gnutls_config_server_create, | 900 | gnutls_config_server_create, |
| 626 | NULL, | 901 | NULL, |
