else if (   (SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ  && BIO_should_retry(SSL_get_rbio(ssl))) || (SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE && BIO_should_retry(SSL_get_wbio(ssl)))) { ssl_log(srvr, SSL_LOG_TRACE, "SSL handshake I/O retry (server %s, client %s)", cpVHostID, conn->remote_ip != NULL ? conn->remote_ip : "unknown"); continue; }
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;                ap_set_callback_and_alarm(NULL, 0);                ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);                return;            }            else if ((ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) &&                     (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL)) {                /*                 * 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);                ap_set_callback_and_alarm(NULL, 0);                ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);                /* 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;                ap_set_callback_and_alarm(NULL, 0);                ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);                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;                ap_set_callback_and_alarm(NULL, 0);                ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);                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;                ap_set_callback_and_alarm(NULL, 0);                ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);                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;            ap_set_callback_and_alarm(NULL, 0);            ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);            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));            OPENSSL_free(cp);            X509_free(xs);        }        /*         * 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;            ap_set_callback_and_alarm(NULL, 0);            ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);            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     * (don't used under Win32, because     * there we use select())     */#ifndef WIN32    SSL_set_read_ahead(ssl, TRUE);#endif#ifdef SSL_VENDOR    /* Allow vendors to do more things on connection time... */    ap_hook_use("ap::mod_ssl::vendor::new_connection",                AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, conn);#endif    return;}