📄 ssl_engine_kernel.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* _ _ * _ __ ___ ___ __| | ___ ___| | mod_ssl * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL * | | | | | | (_) | (_| | \__ \__ \ | * |_| |_| |_|\___/ \__,_|___|___/___/_| * |_____| * ssl_engine_kernel.c * The SSL engine kernel */ /* ``It took me fifteen years to discover I had no talent for programming, but I couldn't give it up because by that time I was too famous.'' -- Unknown */#include "ssl_private.h"static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);/* * Post Read Request Handler */int ssl_hook_ReadReq(request_rec *r){ SSLConnRec *sslconn = myConnConfig(r->connection); SSL *ssl; if (!sslconn) { return DECLINED; } if (sslconn->non_ssl_request) { const char *errmsg; char *thisurl; char *thisport = ""; int port = ap_get_server_port(r); if (!ap_is_default_port(port, r)) { thisport = apr_psprintf(r->pool, ":%u", port); } thisurl = ap_escape_html(r->pool, apr_psprintf(r->pool, "https://%s%s/", ap_get_server_name(r), thisport)); errmsg = apr_psprintf(r->pool, "Reason: You're speaking plain HTTP " "to an SSL-enabled server port.<br />\n" "Instead use the HTTPS scheme to access " "this URL, please.<br />\n" "<blockquote>Hint: " "<a href=\"%s\"><b>%s</b></a></blockquote>", thisurl, thisurl); apr_table_setn(r->notes, "error-notes", errmsg); /* Now that we have caught this error, forget it. we are done * with using SSL on this request. */ sslconn->non_ssl_request = 0; return HTTP_BAD_REQUEST; } /* * Get the SSL connection structure and perform the * delayed interlinking from SSL back to request_rec */ ssl = sslconn->ssl; if (!ssl) { return DECLINED; } SSL_set_app_data2(ssl, r); /* * Log information about incoming HTTPS requests */ if (r->server->loglevel >= APLOG_INFO && ap_is_initial_req(r)) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "%s HTTPS request received for child %ld (server %s)", (r->connection->keepalives <= 0 ? "Initial (No.1)" : apr_psprintf(r->pool, "Subsequent (No.%d)", r->connection->keepalives+1)), r->connection->id, ssl_util_vhostid(r->pool, r->server)); } /* SetEnvIf ssl-*-shutdown flags can only be per-server, * so they won't change across keepalive requests */ if (sslconn->shutdown_type == SSL_SHUTDOWN_TYPE_UNSET) { ssl_configure_env(r, sslconn); } return DECLINED;}/* * Move SetEnvIf information from request_rec to conn_rec/BUFF * to allow the close connection handler to use them. */static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn){ int i; const apr_array_header_t *arr = apr_table_elts(r->subprocess_env); const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts; sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; for (i = 0; i < arr->nelts; i++) { const char *key = elts[i].key; switch (*key) { case 's': /* being case-sensitive here. * and not checking for the -shutdown since these are the only * SetEnvIf "flags" we support */ if (!strncmp(key+1, "sl-", 3)) { key += 4; if (!strncmp(key, "unclean", 7)) { sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN; } else if (!strncmp(key, "accurate", 8)) { sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_ACCURATE; } return; /* should only ever be one ssl-*-shutdown */ } break; } }}/* * Access Handler */int ssl_hook_Access(request_rec *r){ SSLDirConfigRec *dc = myDirConfig(r); SSLSrvConfigRec *sc = mySrvConfig(r->server); SSLConnRec *sslconn = myConnConfig(r->connection); SSL *ssl = sslconn ? sslconn->ssl : NULL; SSL_CTX *ctx = NULL; apr_array_header_t *requires; ssl_require_t *ssl_requires; char *cp; int ok, i; BOOL renegotiate = FALSE, renegotiate_quick = FALSE; X509 *cert; X509 *peercert; X509_STORE *cert_store = NULL; X509_STORE_CTX cert_store_ctx; STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL; SSL_CIPHER *cipher = NULL; int depth, verify_old, verify, n; if (ssl) { ctx = SSL_get_SSL_CTX(ssl); } /* * Support for SSLRequireSSL directive */ if (dc->bSSLRequired && !ssl) { if (sc->enabled == SSL_ENABLED_OPTIONAL) { /* 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"); /* remember forbidden access for strict require option */ apr_table_setn(r->notes, "ssl-access-forbidden", "1"); return HTTP_FORBIDDEN; } /* * Check to see whether SSL is in use; if it's not, then no * further access control checks are relevant. (the test for * sc->enabled is probably strictly unnecessary) */ if (sc->enabled == SSL_ENABLED_FALSE || !ssl) { return DECLINED; } /* * Support for per-directory reconfigured SSL connection parameters. * * This is implemented by forcing an SSL renegotiation with the * reconfigured parameter suite. But Apache's internal API processing * makes our life very hard here, because when internal sub-requests occur * we nevertheless should avoid multiple unnecessary SSL handshakes (they * require extra network I/O and especially time to perform). * * But the optimization for filtering out the unnecessary handshakes isn't * obvious and trivial. Especially because while Apache is in its * sub-request processing the client could force additional handshakes, * too. And these take place perhaps without our notice. So the only * possibility is to explicitly _ask_ OpenSSL whether the renegotiation * has to be performed or not. It has to performed when some parameters * which were previously known (by us) are not those we've now * reconfigured (as known by OpenSSL) or (in optimized way) at least when * the reconfigured parameter suite is stronger (more restrictions) than * the currently active one. */ /* * Override of SSLCipherSuite * * We provide two options here: * * o The paranoid and default approach where we force a renegotiation when * the cipher suite changed in _any_ way (which is straight-forward but * often forces renegotiations too often and is perhaps not what the * user actually wanted). * * o The optimized and still secure way where we force a renegotiation * only if the currently active cipher is no longer contained in the * reconfigured/new cipher suite. Any other changes are not important * because it's the servers choice to select a cipher from the ones the * client supports. So as long as the current cipher is still in the new * cipher suite we're happy. Because we can assume we would have * selected it again even when other (better) ciphers exists now in the * new cipher suite. This approach is fine because the user explicitly * has to enable this via ``SSLOptions +OptRenegotiate''. So we do no * implicit optimizations. */ if (dc->szCipherSuite) { /* remember old state */ if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) { cipher = SSL_get_current_cipher(ssl); } else { cipher_list_old = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl); if (cipher_list_old) { cipher_list_old = sk_SSL_CIPHER_dup(cipher_list_old); } } /* configure new state */ if (!modssl_set_cipher_list(ssl, dc->szCipherSuite)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "Unable to reconfigure (per-directory) " "permitted SSL ciphers"); ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); if (cipher_list_old) { sk_SSL_CIPHER_free(cipher_list_old); } return HTTP_FORBIDDEN; } /* determine whether a renegotiation has to be forced */ cipher_list = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl); if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) { /* optimized way */ if ((!cipher && cipher_list) || (cipher && !cipher_list)) { renegotiate = TRUE; } else if (cipher && cipher_list && (sk_SSL_CIPHER_find(cipher_list, cipher) < 0)) { renegotiate = TRUE; } } else { /* paranoid way */ if ((!cipher_list_old && cipher_list) || (cipher_list_old && !cipher_list)) { renegotiate = TRUE; } else if (cipher_list_old && cipher_list) { for (n = 0; !renegotiate && (n < sk_SSL_CIPHER_num(cipher_list)); n++) { SSL_CIPHER *value = sk_SSL_CIPHER_value(cipher_list, n); if (sk_SSL_CIPHER_find(cipher_list_old, value) < 0) { renegotiate = TRUE; } } for (n = 0; !renegotiate && (n < sk_SSL_CIPHER_num(cipher_list_old)); n++) { SSL_CIPHER *value = sk_SSL_CIPHER_value(cipher_list_old, n); if (sk_SSL_CIPHER_find(cipher_list, value) < 0) { renegotiate = TRUE; } } } } /* cleanup */ if (cipher_list_old) { sk_SSL_CIPHER_free(cipher_list_old); } /* tracing */ if (renegotiate) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Reconfigured cipher suite will force renegotiation"); } } /* * override of SSLVerifyDepth * * The depth checks are handled by us manually inside the verify callback * function and not by OpenSSL internally (and our function is aware of * both the per-server and per-directory contexts). So we cannot ask * OpenSSL about the currently verify depth. Instead we remember it in our * ap_ctx attached to the SSL* of OpenSSL. We've to force the * renegotiation if the reconfigured/new verify depth is less than the * currently active/remembered verify depth (because this means more * restriction on the certificate chain). */ if (dc->nVerifyDepth != UNSET) { /* XXX: doesnt look like sslconn->verify_depth is actually used */ if (!(n = sslconn->verify_depth)) { sslconn->verify_depth = n = sc->server->auth.verify_depth; } /* determine whether a renegotiation has to be forced */ if (dc->nVerifyDepth < n) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -