-- 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)