]> granicus.if.org Git - apache/commitdiff
After some productive feedback and no negative feedback, introduce
authorWilliam A. Rowe Jr <wrowe@apache.org>
Sat, 14 Dec 2002 07:46:45 +0000 (07:46 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Sat, 14 Dec 2002 07:46:45 +0000 (07:46 +0000)
  SSLEngine upgrade so that we can begin and continue to support these
  facilities.  This makes it simpler to keep this effort (while we have
  no known clients that support Connection: upgrade at this time), and
  begin refactoring more of SSL into smaller and tighter (and then optional)
  components.

  Submitted by: Ryan Bloom
  Reviewed by: William Rowe, Joe Orton

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@97912 13f79535-47bb-0310-9956-ffa450edef68

modules/ssl/mod_ssl.h
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_io.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_util.c

index 15d71919cbe22682cd9d2984ad1368cf8d15ee08..8cfbc4f8bd670a4f56cc65be1e8d1304fb990ccd 100644 (file)
@@ -541,7 +541,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 *);
@@ -588,6 +588,7 @@ int          ssl_hook_UserCheck(request_rec *);
 int          ssl_hook_Access(request_rec *);
 int          ssl_hook_Fixup(request_rec *);
 int          ssl_hook_ReadReq(request_rec *);
+int          ssl_hook_Upgrade(request_rec *);
 
 /*  OpenSSL callbacks */
 RSA         *ssl_callback_TmpRSA(SSL *, int, int);
@@ -709,6 +710,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__ */
index 57fdc3e88bf98803a9bf5adedf87e795b7e68566..08c30fc83c4380fdf68a2c06d8f2a9802949c258 100644 (file)
@@ -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 "Argument must be On, Off, or Optional";
 }
 
 const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd,
index 7a2e74273e031fbe8224cf8eb3ae89efeec2ac34..99428bfa8b13459784068158bf7cd56739b8bd86 100644 (file)
@@ -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);
 
+#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;
         }
@@ -982,6 +984,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");
@@ -1010,7 +1015,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) "
index 041a59b6530042e069d48fb9205bc3fc2e789a6d..6aa585e2fca7aaf6cc820a90dd76539659120b67 100644 (file)
@@ -1181,6 +1181,89 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
     return APR_SUCCESS;
 }
 
+static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,
+                                         apr_bucket_brigade *bb)
+
+{
+#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
+#define UPGRADE_HEADER "Upgrade: TLS/1.0 HTTP/1.1"
+#define CONNECTION_HEADER "Connection: 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");
+
+    /* XXX: I don't think the requirement that the client sends exactly 
+     * "Connection: Upgrade" is correct; the only requirement here is 
+     * on the client to send a  Connection header including the "upgrade" 
+     * token.
+     */
+    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_input(ap_filter_t *f,
                                         apr_bucket_brigade *bb,
                                         ap_input_mode_t mode,
@@ -1393,6 +1476,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;
index d4d4c5ce6e2e32eb7d41497d4f55ca0913fd7944..bbc5707a19c63fcb5499f7b59a052a70533c9fd2 100644 (file)
@@ -223,6 +223,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");
@@ -1014,6 +1024,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
      */
index 9b208b404fa334551f93fae3d315e4d91a2a98fc..6b3ecabeaa2ff782251d4f1fb3e19064030d7e44 100644 (file)
@@ -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;