* all of the potential response status-lines (a sparse table).
* A future version should dynamically generate the apr_table_t at startup.
*/
-#define RESPONSE_CODES 55
+#define RESPONSE_CODES 57
#define HTTP_CONTINUE 100
#define HTTP_SWITCHING_PROTOCOLS 101
#define HTTP_UNPROCESSABLE_ENTITY 422
#define HTTP_LOCKED 423
#define HTTP_FAILED_DEPENDENCY 424
+#define HTTP_UPGRADE_REQUIRED 426
#define HTTP_INTERNAL_SERVER_ERROR 500
#define HTTP_NOT_IMPLEMENTED 501
#define HTTP_BAD_GATEWAY 502
"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",
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"
/*
* 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,
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;
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;
/*
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);
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
*/
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();
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 *);
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);
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__ */
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 */
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,
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;
}
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");
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) "
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)
{
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;
* 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");
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
*/
port = s->port;
else {
sc = mySrvConfig(s);
- if (sc->enabled)
+ if (sc->enabled == TRUE)
port = DEFAULT_HTTPS_PORT;
else
port = DEFAULT_HTTP_PORT;
}
}
-static perchild_process_connection(conn_rec *c)
+static int perchild_process_connection(conn_rec *c)
{
ap_filter_t *f;
apr_bucket_brigade *bb;
struct iovec iov[2];
int ret, dp;
apr_os_sock_t sd;
- apr_socket_t *unix_sd = NULL;
apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans);
apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc);
apr_bucket *bucket;
h.p = r->pool;
h.headers = apr_pstrcat(h.p, r->the_request, CRLF, "Host: ", r->hostname,
CRLF, NULL);
-/* XXX This REALLY needs to be uncommented, but it is causing problems.
apr_table_do((int (*) (void *, const char *, const char *))
- perchild_header_field, (void *) &h, r->headers_in, NULL); */
+ perchild_header_field, (void *) &h, r->headers_in, NULL);
h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL);
iov[0].iov_base = h.headers;
for (i = curr_child_num; i < max_this_time; i++, curr_child_num++) {
- int uid = 0, gid = 0;
-
if (i > num_daemons) {
return "Trying to use more child ID's than NumServers. Increase "
"NumServers in your config file.";