📄 ssl_engine_io.c
字号:
} offset += tmplen; tmplen = buflen - offset; } if (pos) { char *value; int length; apr_size_t bytes = pos - buf; bytes += 1; value = buf + bytes; length = *len - bytes; char_buffer_write(&inctx->cbuf, value, length); *len = bytes; } return APR_SUCCESS;}static apr_status_t ssl_filter_write(ap_filter_t *f, const char *data, apr_size_t len){ ssl_filter_ctx_t *filter_ctx = f->ctx; bio_filter_out_ctx_t *outctx; int res; /* write SSL */ if (filter_ctx->pssl == NULL) { return APR_EGENERAL; } outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr; res = SSL_write(filter_ctx->pssl, (unsigned char *)data, len); if (res < 0) { int ssl_err = SSL_get_error(filter_ctx->pssl, res); conn_rec *c = (conn_rec*)SSL_get_app_data(outctx->filter_ctx->pssl); if (ssl_err == SSL_ERROR_WANT_WRITE) { /* * If OpenSSL wants to write more, and we were nonblocking, * report as an EAGAIN. Otherwise loop, pushing more * data at the network filter. * * (This is usually the case when the client forces an SSL * renegotation which is handled implicitly by OpenSSL.) */ outctx->rc = APR_EAGAIN; } else if (ssl_err == SSL_ERROR_SYSCALL) { ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, "SSL output filter write failed."); } else /* if (ssl_err == SSL_ERROR_SSL) */ { /* * Log SSL errors */ ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, "SSL library error %d writing data", ssl_err); ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); } if (outctx->rc == APR_SUCCESS) { outctx->rc = APR_EGENERAL; } } else if ((apr_size_t)res != len) { conn_rec *c = f->c; char *reason = "reason unknown"; /* XXX: probably a better way to determine this */ if (SSL_total_renegotiations(filter_ctx->pssl)) { reason = "likely due to failed renegotiation"; } ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, "failed to write %" APR_SSIZE_T_FMT " of %" APR_SIZE_T_FMT " bytes (%s)", len - (apr_size_t)res, len, reason); outctx->rc = APR_EGENERAL; } return outctx->rc;}/* Just use a simple request. Any request will work for this, because * we use a flag in the conn_rec->conn_vector now. The fake request just * gets the request back to the Apache core so that a response can be sent. * * To avoid calling back for more data from the socket, use an HTTP/0.9 * request, and tack on an EOS bucket. */#define HTTP_ON_HTTPS_PORT \ "GET /" CRLF#define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \ apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \ sizeof(HTTP_ON_HTTPS_PORT) - 1, \ alloc)static void ssl_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f){ bio_filter_in_ctx_t *inctx = f->ctx; SSL_free(inctx->ssl); sslconn->ssl = NULL; inctx->ssl = NULL; inctx->filter_ctx->pssl = NULL;}static apr_status_t ssl_io_filter_error(ap_filter_t *f, apr_bucket_brigade *bb, apr_status_t status){ SSLConnRec *sslconn = myConnConfig(f->c); apr_bucket *bucket; switch (status) { case HTTP_BAD_REQUEST: /* log the situation */ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c, "SSL handshake failed: HTTP spoken on HTTPS port; " "trying to send HTML error page"); ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, f->c->base_server); sslconn->non_ssl_request = 1; ssl_io_filter_disable(sslconn, f); /* fake the request line */ bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); break; default: return status; } APR_BRIGADE_INSERT_TAIL(bb, bucket); bucket = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bucket); return APR_SUCCESS;}static const char ssl_io_filter[] = "SSL/TLS Filter";static const char ssl_io_buffer[] = "SSL/TLS Buffer";/* * Close the SSL part of the socket connection * (called immediately _before_ the socket is closed) * or called with */static apr_status_t ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx, conn_rec *c, int abortive){ SSL *ssl = filter_ctx->pssl; const char *type = ""; SSLConnRec *sslconn = myConnConfig(c); int shutdown_type; if (!ssl) { return APR_SUCCESS; } /* * Now close the SSL layer of the connection. We've to take * the TLSv1 standard into account here: * * | 7.2.1. Closure alerts * | * | The client and the server must share knowledge that the connection is * | ending in order to avoid a truncation attack. Either party may * | initiate the exchange of closing messages. * | * | close_notify * | This message notifies the recipient that the sender will not send * | any more messages on this connection. The session becomes * | unresumable if any connection is terminated without proper * | close_notify messages with level equal to warning. * | * | Either party may initiate a close by sending a close_notify alert. * | Any data received after a closure alert is ignored. * | * | Each party is required to send a close_notify alert before closing * | the write side of the connection. It is required that the other party * | respond with a close_notify alert of its own and close down the * | connection immediately, discarding any pending writes. It is not * | required for the initiator of the close to wait for the responding * | close_notify alert before closing the read side of the connection. * * This means we've to send a close notify message, but haven't to wait * for the close notify of the client. Actually we cannot wait for the * close notify of the client because some clients (including Netscape * 4.x) don't send one, so we would hang. */ /* * exchange close notify messages, but allow the user * to force the type of handshake via SetEnvIf directive */ if (abortive) { shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN; type = "abortive"; } else switch (sslconn->shutdown_type) { case SSL_SHUTDOWN_TYPE_UNCLEAN: /* perform no close notify handshake at all (violates the SSL/TLS standard!) */ shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN; type = "unclean"; break; case SSL_SHUTDOWN_TYPE_ACCURATE: /* send close notify and wait for clients close notify (standard compliant, but usually causes connection hangs) */ shutdown_type = 0; type = "accurate"; break; default: /* * case SSL_SHUTDOWN_TYPE_UNSET: * case SSL_SHUTDOWN_TYPE_STANDARD: */ /* send close notify, but don't wait for clients close notify (standard compliant and safe, so it's the DEFAULT!) */ shutdown_type = SSL_RECEIVED_SHUTDOWN; type = "standard"; break; } SSL_set_shutdown(ssl, shutdown_type); SSL_smart_shutdown(ssl); /* and finally log the fact that we've closed the connection */ if (c->base_server->loglevel >= APLOG_INFO) { ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "Connection closed to child %ld with %s shutdown " "(server %s)", c->id, type, ssl_util_vhostid(c->pool, c->base_server)); } /* deallocate the SSL connection */ if (sslconn->client_cert) { X509_free(sslconn->client_cert); sslconn->client_cert = NULL; } SSL_free(ssl); sslconn->ssl = NULL; filter_ctx->pssl = NULL; /* so filters know we've been shutdown */ if (abortive) { /* prevent any further I/O */ c->aborted = 1; } return APR_SUCCESS;}static apr_status_t ssl_io_filter_cleanup(void *data){ ssl_filter_ctx_t *filter_ctx = data; if (filter_ctx->pssl) { conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl); SSLConnRec *sslconn = myConnConfig(c); SSL_free(filter_ctx->pssl); sslconn->ssl = filter_ctx->pssl = NULL; } return APR_SUCCESS;}/* * The hook is NOT registered with ap_hook_process_connection. Instead, it is * called manually from the churn () before it tries to read any data. * There is some problem if I accept conn_rec *. Still investigating.. * Adv. if conn_rec * can be accepted is we can hook this function using the * ap_hook_process_connection hook. */static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx){ conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl); SSLConnRec *sslconn = myConnConfig(c); SSLSrvConfigRec *sc = mySrvConfig(c->base_server); X509 *cert; int n; int ssl_err; long verify_result; if (SSL_is_init_finished(filter_ctx->pssl)) { return APR_SUCCESS; } if (sslconn->is_proxy) { if ((n = SSL_connect(filter_ctx->pssl)) <= 0) { ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "SSL Proxy connect failed"); ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); /* ensure that the SSL structures etc are freed, etc: */ ssl_filter_io_shutdown(filter_ctx, c, 1); return HTTP_BAD_GATEWAY; } return APR_SUCCESS; } if ((n = SSL_accept(filter_ctx->pssl)) <= 0) { bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *) (filter_ctx->pbioRead->ptr); bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *) (filter_ctx->pbioWrite->ptr); apr_status_t rc = inctx->rc ? inctx->rc : outctx->rc ; ssl_err = SSL_get_error(filter_ctx->pssl, n); if (ssl_err == 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. */ ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c, "SSL handshake stopped: connection was closed"); } else if (ssl_err == SSL_ERROR_WANT_READ) { /* * This is in addition to what was present earlier. It is * borrowed from openssl_state_machine.c [mod_tls]. * TBD. */ outctx->rc = APR_EAGAIN; return SSL_ERROR_WANT_READ; } else if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && 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. * ssl_io_filter_error will disable the ssl filters when it * sees this status code. */ return HTTP_BAD_REQUEST; } else if (ssl_err == SSL_ERROR_SYSCALL) { ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c, "SSL handshake interrupted by system " "[Hint: Stop button pressed in browser?!]"); } else /* if (ssl_err == SSL_ERROR_SSL) */ { /* * Log SSL errors and any unexpected conditions. */ ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c, "SSL library error %d in handshake " "(server %s)", ssl_err, ssl_util_vhostid(c->pool, c->base_server)); ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); } if (inctx->rc == APR_SUCCESS) { inctx->rc = APR_EGENERAL; } return ssl_filter_io_shutdown(filter_ctx, c, 1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -