diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/http/http_protocol.c | 13 | ||||
-rw-r--r-- | modules/ssl/mod_ssl.c | 83 | ||||
-rw-r--r-- | modules/ssl/mod_ssl.h | 5 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_config.c | 19 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_init.c | 11 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_io.c | 84 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_kernel.c | 14 | ||||
-rw-r--r-- | modules/ssl/ssl_util.c | 2 |
8 files changed, 191 insertions, 40 deletions
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 6730df6dcf..09e087c88c 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -163,7 +163,12 @@ static const char * const status_lines[RESPONSE_CODES] = "422 Unprocessable Entity", "423 Locked", "424 Failed Dependency", -#define LEVEL_500 44 + /* This is a hack, but it is required for ap_index_of_response + * to work with 426. + */ + "425 No code", + "426 Upgrade Required", +#define LEVEL_500 46 "500 Internal Server Error", "501 Method Not Implemented", "502 Bad Gateway", @@ -2190,6 +2195,12 @@ static const char *get_canned_error_string(int status, return("<p>The method could not be performed on the resource\n" "because the requested action depended on another\n" "action and that other action failed.</p>\n"); + case HTTP_UPGRADE_REQUIRED: + return("<p>The requested resource can only be retrieved\n" + "using SSL. The server is willing to upgrade the current\n" + "connection to SSL, but your client doesn't support it.\n" + "Either upgrade your client, or try requesting the page\n" + "using https://\n"); case HTTP_INSUFFICIENT_STORAGE: return("<p>The method could not be performed on the resource\n" "because the server is unable to store the\n" diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 0365adfb3a..5805367f38 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -105,7 +105,7 @@ static const command_rec ssl_config_cmds[] = { /* * Per-server context configuration directives */ - SSL_CMD_SRV(Engine, FLAG, + SSL_CMD_SRV(Engine, TAKE1, "SSL switch for the protocol engine " "(`on', `off')") SSL_CMD_ALL(CipherSuite, TAKE1, @@ -274,7 +274,7 @@ int ssl_engine_disable(conn_rec *c) return 1; } -static int ssl_hook_pre_connection(conn_rec *c, void *csd) +int ssl_init_ssl_connection(conn_rec *c) { SSLSrvConfigRec *sc = mySrvConfig(c->base_server); SSL *ssl; @@ -283,40 +283,14 @@ static int ssl_hook_pre_connection(conn_rec *c, void *csd) modssl_ctx_t *mctx; /* - * Immediately stop processing if SSL is disabled for this connection + * Seed the Pseudo Random Number Generator (PRNG) */ - if (!(sc && (sc->enabled || - (sslconn && sslconn->is_proxy)))) - { - return DECLINED; - } + ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, ""); - /* - * Create SSL context - */ if (!sslconn) { sslconn = ssl_init_connection_ctx(c); } - if (sslconn->disabled) { - return DECLINED; - } - - /* - * Remember the connection information for - * later access inside callback functions - */ - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, - "Connection to child %ld established " - "(server %s, client %s)", c->id, sc->vhost_id, - c->remote_ip ? c->remote_ip : "unknown"); - - /* - * Seed the Pseudo Random Number Generator (PRNG) - */ - ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, ""); - mctx = sslconn->is_proxy ? sc->proxy : sc->server; /* @@ -368,6 +342,44 @@ static int ssl_hook_pre_connection(conn_rec *c, void *csd) return APR_SUCCESS; } +static int ssl_hook_pre_connection(conn_rec *c, void *csd) +{ + SSLSrvConfigRec *sc = mySrvConfig(c->base_server); + SSLConnRec *sslconn = myConnConfig(c); + + /* + * Immediately stop processing if SSL is disabled for this connection + */ + if (!(sc && (sc->enabled == TRUE || + (sslconn && sslconn->is_proxy)))) + { + return DECLINED; + } + + /* + * Create SSL context + */ + if (!sslconn) { + sslconn = ssl_init_connection_ctx(c); + } + + if (sslconn->disabled) { + return DECLINED; + } + + /* + * Remember the connection information for + * later access inside callback functions + */ + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, + "Connection to child %ld established " + "(server %s, client %s)", c->id, sc->vhost_id, + c->remote_ip ? c->remote_ip : "unknown"); + + return ssl_init_ssl_connection(c); +} + static apr_status_t ssl_abort(SSLFilterRec *filter, conn_rec *c) { SSLConnRec *sslconn = myConnConfig(c); @@ -572,6 +584,15 @@ static apr_port_t ssl_hook_default_port(const request_rec *r) return 443; } +static void ssl_hook_Insert_Filter(request_rec *r) +{ + SSLSrvConfigRec *sc = mySrvConfig(r->server); + + if (sc->enabled == UNSET) { + ap_add_output_filter("UPGRADE_FILTER", NULL, r, r->connection); + } +} + /* * the module registration phase */ @@ -592,6 +613,8 @@ static void ssl_register_hooks(apr_pool_t *p) ap_hook_access_checker(ssl_hook_Access, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_auth_checker (ssl_hook_Auth, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_post_read_request(ssl_hook_ReadReq, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_insert_filter (ssl_hook_Insert_Filter, NULL,NULL, APR_HOOK_MIDDLE); +/* ap_hook_handler (ssl_hook_Upgrade, NULL,NULL, APR_HOOK_MIDDLE); */ ssl_var_register(); diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index 5f8009d694..8c119971d1 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -549,7 +549,7 @@ const char *ssl_cmd_SSLMutex(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLRandomSeed(cmd_parms *, void *, const char *, const char *, const char *); -const char *ssl_cmd_SSLEngine(cmd_parms *, void *, int); +const char *ssl_cmd_SSLEngine(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *); @@ -601,6 +601,7 @@ int ssl_hook_Access(request_rec *); int ssl_hook_Fixup(request_rec *); int ssl_hook_ReadReq(request_rec *); int ssl_hook_Handler(request_rec *); +int ssl_hook_Upgrade(request_rec *); /* OpenSSL callbacks */ RSA *ssl_callback_TmpRSA(SSL *, int, int); @@ -722,6 +723,8 @@ ssl_algo_t ssl_util_algotypeof(X509 *, EVP_PKEY *); char *ssl_util_algotypestr(ssl_algo_t); char *ssl_util_ptxtsub(apr_pool_t *, const char *, const char *, char *); void ssl_util_thread_setup(apr_pool_t *); +int ssl_init_ssl_connection(conn_rec *c); + #define APR_SHM_MAXSIZE (64 * 1024 * 1024) #endif /* __MOD_SSL_H__ */ diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 1350e4fc56..0faab68289 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -205,7 +205,7 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc)); sc->mc = NULL; - sc->enabled = UNSET; + sc->enabled = FALSE; sc->proxy_enabled = UNSET; sc->vhost_id = NULL; /* set during module init */ sc->vhost_id_len = 0; /* set during module init */ @@ -581,13 +581,24 @@ const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd, return NULL; } -const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, int flag) +const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); - sc->enabled = flag ? TRUE : FALSE; + if (!strcasecmp(arg, "On")) { + sc->enabled = TRUE; + return NULL; + } + else if (!strcasecmp(arg, "Off")) { + sc->enabled = FALSE; + return NULL; + } + else if (!strcasecmp(arg, "Optional")) { + sc->enabled = UNSET; + return NULL; + } - return NULL; + return "Argument must be On, Off, or Optional"; } const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index bf63baf4c1..c6e69747af 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -247,11 +247,13 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, sc->vhost_id = ssl_util_vhostid(p, s); sc->vhost_id_len = strlen(sc->vhost_id); - /* Fix up stuff that may not have been set */ +#if 0 + /* If sc->enabled is UNSET, then SSL is optional on this vhost */ + /* Fix up stuff that may not have been set */ if (sc->enabled == UNSET) { sc->enabled = FALSE; } - +#endif if (sc->proxy_enabled == UNSET) { sc->proxy_enabled = FALSE; } @@ -981,6 +983,9 @@ void ssl_init_ConfigureServer(server_rec *s, apr_pool_t *ptemp, SSLSrvConfigRec *sc) { + /* A bit of a hack, but initialize the server if SSL is optional or + * not. + */ if (sc->enabled) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Configuring server for SSL protocol"); @@ -1009,7 +1014,7 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); - if (sc->enabled && (s->port == DEFAULT_HTTP_PORT)) { + if ((sc->enabled == TRUE) && (s->port == DEFAULT_HTTP_PORT)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, "Init: (%s) You configured HTTPS(%d) " diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index cdb6c965c6..8b39054198 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -577,6 +577,85 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, return APR_SUCCESS; } +static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f, + apr_bucket_brigade *bb) + +{ +#define SWITCH_STATUS_LINE "101 Switching Protocols" +#define UPGRADE_HEADER "Upgrade: TLS/1.0 HTTP/1.1" +#define CONNECTION_HEADER "Conenction: Upgrade" + const char *upgrade; + const char *connection; + apr_bucket_brigade *upgradebb; + request_rec *r = f->r; + SSLConnRec *sslconn; + SSL *ssl; + + /* Just remove the filter, if it doesn't work the first time, it won't + * work at all for this request. + */ + ap_remove_output_filter(f); + + /* No need to ensure that this is a server with optional SSL, the filter + * is only inserted if that is true. + */ + + upgrade = apr_table_get(r->headers_in, "Upgrade"); + if (upgrade == NULL) { + return ap_pass_brigade(f->next, bb); + } + connection = apr_table_get(r->headers_in, "Connection"); + + apr_table_unset(r->headers_out, "Upgrade"); + + if (strcmp(connection, "Upgrade") || strcmp(upgrade, "TLS/1.0")) { + return ap_pass_brigade(f->next, bb); + } + + if (r->method_number == M_OPTIONS) { + apr_bucket *b = NULL; + /* This is a mandatory SSL upgrade. */ + + upgradebb = apr_brigade_create(r->pool, f->c->bucket_alloc); + + ap_fputstrs(f->next, upgradebb, SWITCH_STATUS_LINE, CRLF, + UPGRADE_HEADER, CRLF, CONNECTION_HEADER, CRLF, CRLF, NULL); + + b = apr_bucket_flush_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(upgradebb, b); + + ap_pass_brigade(f->next, upgradebb); + } + else { + /* This is optional, and should be configurable, for now don't bother + * doing anything. + */ + return ap_pass_brigade(f->next, bb); + } + + ssl_init_ssl_connection(f->c); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Awaiting re-negotiation handshake"); + + sslconn = myConnConfig(f->c); + ssl = sslconn->ssl; + + SSL_set_state(ssl, SSL_ST_ACCEPT); + SSL_do_handshake(ssl); + + if (SSL_get_state(ssl) != SSL_ST_OK) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Re-negotiation handshake failed: " + "Not accepted by client!?"); + + return AP_FILTER_ERROR; + } + + return OK; + +} + static apr_status_t ssl_io_filter_Output(ap_filter_t *f, apr_bucket_brigade *bb) { @@ -943,6 +1022,11 @@ void ssl_io_filter_init(conn_rec *c, SSL *ssl) void ssl_io_filter_register(apr_pool_t *p) { + /* This filter MUST be after the HTTP_HEADER filter, but it also must be + * a resource-level filter so it has the request_rec. + */ + ap_register_output_filter ("UPGRADE_FILTER", ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5); + ap_register_input_filter (ssl_io_filter, ssl_io_filter_Input, NULL, AP_FTYPE_CONNECTION + 5); ap_register_output_filter (ssl_io_filter, ssl_io_filter_Output, NULL, AP_FTYPE_CONNECTION + 5); return; diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index c03832b31f..40850a5e69 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -322,6 +322,16 @@ int ssl_hook_Access(request_rec *r) * Support for SSLRequireSSL directive */ if (dc->bSSLRequired && !ssl) { + if (sc->enabled == UNSET) { + /* This vhost was configured for optional SSL, just tell the + * client that we need to upgrade. + */ + apr_table_setn(r->err_headers_out, "Upgrade", "TLS/1.0, HTTP/1.1"); + apr_table_setn(r->err_headers_out, "Connection", "Upgrade"); + + return HTTP_UPGRADE_REQUIRED; + } + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "access to %s failed, reason: %s", r->filename, "SSL connection required"); @@ -1110,6 +1120,10 @@ int ssl_hook_Fixup(request_rec *r) SSL *ssl; int i; + if (sc->enabled == UNSET) { + apr_table_setn(r->headers_out, "Upgrade", "TLS/1.0, HTTP/1.1"); + } + /* * Check to see if SSL is on */ diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c index 9b208b404f..6b3ecabeaa 100644 --- a/modules/ssl/ssl_util.c +++ b/modules/ssl/ssl_util.c @@ -84,7 +84,7 @@ char *ssl_util_vhostid(apr_pool_t *p, server_rec *s) port = s->port; else { sc = mySrvConfig(s); - if (sc->enabled) + if (sc->enabled == TRUE) port = DEFAULT_HTTPS_PORT; else port = DEFAULT_HTTP_PORT; |