Commit cd0e0009 authored by Doug MacEachern's avatar Doug MacEachern
Browse files

remove #if 0-ed ssl_hook_NewConnection code; was only left for reference,

no longer needed
remove #if 0-ed ssl_hook_TimeoutConnection code; ssl no longer talks directly
to the socket
PR:
Obtained from:
Submitted by:    madhu
Reviewed by:	 dougm


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90511 13f79535-47bb-0310-9956-ffa450edef68
parent 6f7b1c50
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -175,7 +175,6 @@
   ssl_var_unregister();
   ssl_ext_unregister();
 o We certainly need CRYPTO_set_locking_callback() now also under Unix!
 o Enable Timeout processing.
 o Do we need SSL_set_read_ahead()?
 o Enable use of MM, SHMCB and SHMHT.
 o Enable SSL extensions (ssl_engine_ext.c)
+1 −3
Original line number Diff line number Diff line
@@ -298,9 +298,7 @@ static int ssl_hook_pre_connection(conn_rec *c)
     * working some time before this happens.
     */
    ssl_util_setmodconfig(c->base_server, "ssl::handshake::timeout", (void *)FALSE);
#if 0 /* XXX */
    ap_set_callback_and_alarm(ssl_hook_TimeoutConnection, c->base_server->timeout);
#endif

    ssl_io_filter_init(c, ssl);

    return APR_SUCCESS;
+0 −312
Original line number Diff line number Diff line
@@ -63,318 +63,6 @@
                                            -- Unknown                */
#include "mod_ssl.h"

#if 0 /* XXX */

/*  _________________________________________________________________
**
**  SSL Engine Kernel
**  _________________________________________________________________
*/

/*
 *  Connect Handler:
 *  Connect SSL to the accepted socket
 *
 *  Usually we would need an Apache API hook which is triggered right after
 *  the socket is accepted for handling a new request. But Apache 1.3 doesn't
 *  provide such a hook, so we have to patch http_main.c and call this
 *  function directly.
 */
void ssl_hook_NewConnection(conn_rec *conn)
{
    server_rec *srvr;
    BUFF *fb;
    SSLSrvConfigRec *sc;
    ap_ctx *apctx;
    SSL *ssl;
    char *cp;
    char *cpVHostID;
    char *cpVHostMD5;
    X509 *xs;
    int rc;

    /*
     * Get context
     */
    srvr = conn->server;
    fb   = conn->client;
    sc   = mySrvConfig(srvr);

    /*
     * Create SSL context
     */
    ap_ctx_set(fb->ctx, "ssl", NULL);

    /*
     * Immediately stop processing if SSL
     * is disabled for this connection
     */
    if (sc == NULL || !sc->bEnabled)
        return;

    /*
     * Remember the connection information for
     * later access inside callback functions
     */
    cpVHostID = ssl_util_vhostid(conn->pool, srvr);
    ssl_log(srvr, SSL_LOG_INFO, "Connection to child %d established "
            "(server %s, client %s)", conn->child_num, cpVHostID, 
            conn->remote_ip != NULL ? conn->remote_ip : "unknown");

    /*
     * Seed the Pseudo Random Number Generator (PRNG)
     */
    ssl_rand_seed(srvr, conn->pool, SSL_RSCTX_CONNECT, "");

    /*
     * Create a new SSL connection with the configured server SSL context and
     * attach this to the socket. Additionally we register this attachment
     * so we can detach later.
     */
    if ((ssl = SSL_new(sc->pSSLCtx)) == NULL) {
        ssl_log(conn->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
                "Unable to create a new SSL connection from the SSL context");
        ap_ctx_set(fb->ctx, "ssl", NULL);
        ap_bsetflag(fb, B_EOF|B_EOUT, 1);
        conn->aborted = 1;
        return;
    }
    SSL_clear(ssl);
    cpVHostMD5 = ap_md5(conn->pool, (unsigned char *)cpVHostID);
    if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5, strlen(cpVHostMD5))) {
        ssl_log(conn->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
                "Unable to set session id context to `%s'", cpVHostMD5);
        ap_ctx_set(fb->ctx, "ssl", NULL);
        ap_bsetflag(fb, B_EOF|B_EOUT, 1);
        conn->aborted = 1;
        return;
    }
    SSL_set_app_data(ssl, conn);
    apctx = ap_ctx_new(conn->pool);
    ap_ctx_set(apctx, "ssl::request_rec", NULL);
    ap_ctx_set(apctx, "ssl::verify::depth", AP_CTX_NUM2PTR(0));
    SSL_set_app_data2(ssl, apctx);
    SSL_set_fd(ssl, fb->fd);
    ap_ctx_set(fb->ctx, "ssl", ssl);

    /*
     *  Configure callbacks for SSL connection
     */
    SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
    SSL_set_tmp_dh_callback(ssl,  ssl_callback_TmpDH);
    if (sc->nLogLevel >= SSL_LOG_DEBUG) {
        BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb);
        BIO_set_callback_arg(SSL_get_rbio(ssl), ssl);
    }

    /*
     * Predefine some client verification results
     */
    ap_ctx_set(fb->ctx, "ssl::client::dn", NULL);
    ap_ctx_set(fb->ctx, "ssl::verify::error", NULL);
    ap_ctx_set(fb->ctx, "ssl::verify::info", NULL);
    SSL_set_verify_result(ssl, X509_V_OK);

    /*
     * We have to manage a I/O timeout ourself, because Apache
     * does it the first time when reading the request, but we're
     * working some time before this happens.
     */
    ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);
    ap_set_callback_and_alarm(ssl_hook_TimeoutConnection, srvr->timeout);

    /*
     * Now enter the SSL Handshake Phase
     */
    while (!SSL_is_init_finished(ssl)) {

        if ((rc = SSL_accept(ssl)) <= 0) {

            if (SSL_get_error(ssl, rc) == SSL_ERROR_ZERO_RETURN) {
                /*
                 * The case where the connection was closed before any data
                 * was transferred. That's not a real error and can occur
                 * sporadically with some clients.
                 */
                ssl_log(srvr, SSL_LOG_INFO,
                        "SSL handshake stopped: connection was closed");
                SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
                SSL_smart_shutdown(ssl);
                SSL_free(ssl);
                ap_ctx_set(fb->ctx, "ssl", NULL);
                ap_bsetflag(fb, B_EOF|B_EOUT, 1);
                conn->aborted = 1;
                return;
            }
            else if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) {
                /*
                 * The case where OpenSSL has recognized a HTTP request:
                 * This means the client speaks plain HTTP on our HTTPS
                 * port. Hmmmm...  At least for this error we can be more friendly
                 * and try to provide him with a HTML error page. We have only one
                 * problem: OpenSSL has already read some bytes from the HTTP
                 * request. So we have to skip the request line manually and
                 * instead provide a faked one in order to continue the internal
                 * Apache processing.
                 *
                 */
                char ca[2];
                int rv;

                /* log the situation */
                ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR,
                        "SSL handshake failed: HTTP spoken on HTTPS port; "
                        "trying to send HTML error page");

                /* first: skip the remaining bytes of the request line */
                do {
                    do {
                        rv = read(fb->fd, ca, 1);
                    } while (rv == -1 && errno == EINTR);
                } while (rv > 0 && ca[0] != '\012' /*LF*/);

                /* second: fake the request line */
                fb->inbase = ap_palloc(fb->pool, fb->bufsiz);
                ap_cpystrn((char *)fb->inbase, "GET /mod_ssl:error:HTTP-request HTTP/1.0\r\n",
                           fb->bufsiz);
                fb->inptr = fb->inbase;
                fb->incnt = strlen((char *)fb->inptr);

                /* third: kick away the SSL stuff */
                SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                SSL_smart_shutdown(ssl);
                SSL_free(ssl);
                ap_ctx_set(fb->ctx, "ssl", NULL);

                /* finally: let Apache go on with processing */
                return;
            }
            else if (ap_ctx_get(ap_global_ctx, "ssl::handshake::timeout") == (void *)TRUE) {
                ssl_log(srvr, SSL_LOG_ERROR,
                        "SSL handshake timed out (client %s, server %s)",
                        conn->remote_ip != NULL ? conn->remote_ip : "unknown", cpVHostID);
                SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
                SSL_smart_shutdown(ssl);
                SSL_free(ssl);
                ap_ctx_set(fb->ctx, "ssl", NULL);
                ap_bsetflag(fb, B_EOF|B_EOUT, 1);
                conn->aborted = 1;
                return;
            }
            else if (SSL_get_error(ssl, rc) == SSL_ERROR_SYSCALL) {
                if (errno == EINTR)
                    continue;
                if (errno > 0)
                    ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
                            "SSL handshake interrupted by system "
                            "[Hint: Stop button pressed in browser?!]");
                else
                    ssl_log(srvr, SSL_LOG_INFO|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
                            "Spurious SSL handshake interrupt"
                            "[Hint: Usually just one of those OpenSSL confusions!?]");
                SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
                SSL_smart_shutdown(ssl);
                SSL_free(ssl);
                ap_ctx_set(fb->ctx, "ssl", NULL);
                ap_bsetflag(fb, B_EOF|B_EOUT, 1);
                conn->aborted = 1;
                return;
            }
            else {
                /*
                 * Ok, anything else is a fatal error
                 */
                ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
                        "SSL handshake failed (server %s, client %s)", cpVHostID, 
                        conn->remote_ip != NULL ? conn->remote_ip : "unknown");

                /*
                 * try to gracefully shutdown the connection:
                 * - send an own shutdown message (be gracefully)
                 * - don't wait for peer's shutdown message (deadloop)
                 * - kick away the SSL stuff immediately
                 * - block the socket, so Apache cannot operate any more
                 */
                SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
                SSL_smart_shutdown(ssl);
                SSL_free(ssl);
                ap_ctx_set(fb->ctx, "ssl", NULL);
                ap_bsetflag(fb, B_EOF|B_EOUT, 1);
                conn->aborted = 1;
                return;
            }
        }

        /*
         * Check for failed client authentication
         */
        if (   SSL_get_verify_result(ssl) != X509_V_OK
            || ap_ctx_get(fb->ctx, "ssl::verify::error") != NULL) {
            cp = (char *)ap_ctx_get(fb->ctx, "ssl::verify::error");
            ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR,
                    "SSL client authentication failed: %s", 
                    cp != NULL ? cp : "unknown reason");
            SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
            SSL_smart_shutdown(ssl);
            SSL_free(ssl);
            ap_ctx_set(fb->ctx, "ssl", NULL);
            ap_bsetflag(fb, B_EOF|B_EOUT, 1);
            conn->aborted = 1;
            return;
        }

        /*
         * Remember the peer certificate's DN
         */
        if ((xs = SSL_get_peer_certificate(ssl)) != NULL) {
            cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
            ap_ctx_set(fb->ctx, "ssl::client::dn", ap_pstrdup(conn->pool, cp));
            free(cp);
        }

        /*
         * Make really sure that when a peer certificate
         * is required we really got one... (be paranoid)
         */
        if (   sc->nVerifyClient == SSL_CVERIFY_REQUIRE
            && ap_ctx_get(fb->ctx, "ssl::client::dn") == NULL) {
            ssl_log(srvr, SSL_LOG_ERROR,
                    "No acceptable peer certificate available");
            SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
            SSL_smart_shutdown(ssl);
            SSL_free(ssl);
            ap_ctx_set(fb->ctx, "ssl", NULL);
            ap_bsetflag(fb, B_EOF|B_EOUT, 1);
            conn->aborted = 1;
            return;
        }
    }

    /*
     * Remove the timeout handling
     */
    ap_set_callback_and_alarm(NULL, 0);
    ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);

    /*
     * Improve I/O throughput by using
     * OpenSSL's read-ahead functionality
     */
    SSL_set_read_ahead(ssl, TRUE);
    return;
}

/*
 * Signal handler function for the SSL handshake phase
 */
void ssl_hook_TimeoutConnection(int sig)
{
    /* we just set a flag for the handshake processing loop */
    ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)TRUE);
    return;
}
#endif /* XXX */

/*
 *  Close the SSL part of the socket connection
 *  (called immediately _before_ the socket is closed)