ssl_engine_kernel.c revision bb8b22a3708a815a8fcd0c8d5c8de46c25240cc1
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * Unless required by applicable law or agreed to in writing, software
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * distributed under the License is distributed on an "AS IS" BASIS,
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * See the License for the specific language governing permissions and
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * limitations under the License.
3568de757bac0b47256647504c186d17ca272f85rbb * _ __ ___ ___ __| | ___ ___| | mod_ssl
3568de757bac0b47256647504c186d17ca272f85rbb * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
3568de757bac0b47256647504c186d17ca272f85rbb * | | | | | | (_) | (_| | \__ \__ \ |
3568de757bac0b47256647504c186d17ca272f85rbb * |_| |_| |_|\___/ \__,_|___|___/___/_|
3568de757bac0b47256647504c186d17ca272f85rbb * The SSL engine kernel
3568de757bac0b47256647504c186d17ca272f85rbb /* ``It took me fifteen years to discover
3568de757bac0b47256647504c186d17ca272f85rbb I had no talent for programming, but
3568de757bac0b47256647504c186d17ca272f85rbb I couldn't give it up because by that
3568de757bac0b47256647504c186d17ca272f85rbb time I was too famous.''
3568de757bac0b47256647504c186d17ca272f85rbb -- Unknown */
3568de757bac0b47256647504c186d17ca272f85rbbstatic void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
3568de757bac0b47256647504c186d17ca272f85rbbstatic int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s);
3568de757bac0b47256647504c186d17ca272f85rbb#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
3568de757bac0b47256647504c186d17ca272f85rbb/* Perform an upgrade-to-TLS for the given request, per RFC 2817. */
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02028)
3568de757bac0b47256647504c186d17ca272f85rbb "upgrading connection to TLS");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = ap_fputs(conn->output_filters, bb, SWITCH_STATUS_LINE CRLF
98fb535f829e2a95aabd82420931f476661fa8e3jorton ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02029)
db12cd62083041bf90945eeb90cc40fbd2340797trawick "failed to send 101 interim response for connection "
db12cd62083041bf90945eeb90cc40fbd2340797trawick "upgrade");
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* Perform initial SSL handshake. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02030)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "TLS upgrade handshake failed: not accepted by client!?");
f0e395a55abfcad3d2bd7c63470003b08a93d567nd/* Perform a speculative (and non-blocking) read from the connection
f0e395a55abfcad3d2bd7c63470003b08a93d567nd * filters for the given request, to determine whether there is any
f0e395a55abfcad3d2bd7c63470003b08a93d567nd * pending data to read. Return non-zero if there is, else zero. */
7cd5419264796cfeaf8215383cf0f89130a81fectrawick bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick rv = ap_get_brigade(r->connection->input_filters, bb, AP_MODE_SPECULATIVE,
3568de757bac0b47256647504c186d17ca272f85rbb * Post Read Request Handler
3568de757bac0b47256647504c186d17ca272f85rbb const char *upgrade;
3568de757bac0b47256647504c186d17ca272f85rbb const char *servername;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* Perform TLS upgrade here if "SSLEngine optional" is configured,
3568de757bac0b47256647504c186d17ca272f85rbb * SSL is not already set up for this connection, and the client
fc1efab92032301e317f07e1b3a00082d9d71f3frbb * has sent a suitable Upgrade header. */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (sc->enabled == SSL_ENABLED_OPTIONAL && !myConnConfig(r->connection)
24b534291150023e6b68eca89ddd33e475ccddc0wrowe && (upgrade = apr_table_get(r->headers_in, "Upgrade")) != NULL
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (sslconn->non_ssl_request == NON_SSL_SET_ERROR_MSG) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "Reason: You're speaking plain HTTP to an SSL-enabled "
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "server port.<br />\n Instead use the HTTPS scheme to "
3568de757bac0b47256647504c186d17ca272f85rbb "access this URL, please.<br />\n");
3568de757bac0b47256647504c186d17ca272f85rbb /* Now that we have caught this error, forget it. we are done
3568de757bac0b47256647504c186d17ca272f85rbb * with using SSL on this request.
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * Get the SSL connection structure and perform the
3568de757bac0b47256647504c186d17ca272f85rbb * delayed interlinking from SSL back to request_rec
3568de757bac0b47256647504c186d17ca272f85rbb * Perform SNI checks only on the initial request. In particular,
3568de757bac0b47256647504c186d17ca272f85rbb * if these checks detect a problem, the checks shouldn't return an
3568de757bac0b47256647504c186d17ca272f85rbb * error again when processing an ErrorDocument redirect for the
3568de757bac0b47256647504c186d17ca272f85rbb * original problem.
3568de757bac0b47256647504c186d17ca272f85rbb if (r->proxyreq != PROXYREQ_PROXY && ap_is_initial_req(r)) {
3568de757bac0b47256647504c186d17ca272f85rbb if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
3568de757bac0b47256647504c186d17ca272f85rbb * The SNI extension supplied a hostname. So don't accept requests
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * with either no hostname or a different hostname as this could
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * cause us to end up in a different virtual host as the one that
3568de757bac0b47256647504c186d17ca272f85rbb * was used for the handshake causing different SSL parameters to
239f998fbee5ac5b114b965bb76e217cce0003edstoddard * be applied as SSLProtocol, SSLCACertificateFile/Path and
78ae889ffe0fdfab72f56c6993b0f302cb48da55rbb * SSLCADNRequestFile/Path cannot be renegotiated (SSLCA* due
3568de757bac0b47256647504c186d17ca272f85rbb * to current limitations in OpenSSL, see
6653a33e820463abd4f81915b7a1eba0f602e200brianp * http://mail-archives.apache.org/mod_mbox/httpd-dev/200806.mbox/%3C48592955.2090303@velox.ch%3E
6653a33e820463abd4f81915b7a1eba0f602e200brianp * http://mail-archives.apache.org/mod_mbox/httpd-dev/201312.mbox/%3CCAKQ1sVNpOrdiBm-UPw1hEdSN7YQXRRjeaT-MCWbW_7mN%3DuFiOw%40mail.gmail.com%3E
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02031)
6653a33e820463abd4f81915b7a1eba0f602e200brianp "Hostname %s provided via SNI, but no hostname"
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool);
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02032)
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin "Hostname %s provided via SNI and hostname %s provided"
ca53a74f4012a45cbad48e940eddf27d866981f9dougm else if (((sc->strict_sni_vhost_check == SSL_ENABLED_TRUE)
ca53a74f4012a45cbad48e940eddf27d866981f9dougm || (mySrvConfig(sslconn->server))->strict_sni_vhost_check
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin * We are using a name based configuration here, but no hostname was
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin * provided via SNI. Don't allow that if are requested to do strict
dd028aa8111afb6534fece555e8c2d408894671etrawick * checking. Check whether this strict checking was set up either in the
dd028aa8111afb6534fece555e8c2d408894671etrawick * server config we used for handshaking or in our current server.
6653a33e820463abd4f81915b7a1eba0f602e200brianp * This should avoid insecure configuration by accident.
6653a33e820463abd4f81915b7a1eba0f602e200brianp ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02033)
6653a33e820463abd4f81915b7a1eba0f602e200brianp "No hostname was provided via SNI for a name based"
6653a33e820463abd4f81915b7a1eba0f602e200brianp " virtual host");
6653a33e820463abd4f81915b7a1eba0f602e200brianp "Reason: The client software did not provide a "
6653a33e820463abd4f81915b7a1eba0f602e200brianp "hostname using Server Name Indication (SNI), "
6653a33e820463abd4f81915b7a1eba0f602e200brianp "which is required to access this server.<br />\n");
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick * Log information about incoming HTTPS requests
239f998fbee5ac5b114b965bb76e217cce0003edstoddard ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02034)
3568de757bac0b47256647504c186d17ca272f85rbb "%s HTTPS request received for child %ld (server %s)",
3568de757bac0b47256647504c186d17ca272f85rbb "Initial (No.1)" :
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* SetEnvIf ssl-*-shutdown flags can only be per-server,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * so they won't change across keepalive requests
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton if (sslconn->shutdown_type == SSL_SHUTDOWN_TYPE_UNSET) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * Move SetEnvIf information from request_rec to conn_rec/BUFF
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * to allow the close connection handler to use them.
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluemstatic void ssl_configure_env(request_rec *r, SSLConnRec *sslconn)
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem const apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem switch (*key) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* being case-sensitive here.
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * and not checking for the -shutdown since these are the only
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * SetEnvIf "flags" we support
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_ACCURATE;
3568de757bac0b47256647504c186d17ca272f85rbb return; /* should only ever be one ssl-*-shutdown */
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick * Access Handler
397df70abe0bdd78a84fb6c38c02641bcfeadceasf server_rec *handshakeserver = sslconn ? sslconn->server : NULL;
3cbd177a6c885562f9ad0cf11695f044489c881dgregames STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * Support for SSLRequireSSL directive
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard /* This vhost was configured for optional SSL, just tell the
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * client that we need to upgrade.
7cd5419264796cfeaf8215383cf0f89130a81fectrawick apr_table_setn(r->err_headers_out, "Upgrade", "TLS/1.0, HTTP/1.1");
7cd5419264796cfeaf8215383cf0f89130a81fectrawick apr_table_setn(r->err_headers_out, "Connection", "Upgrade");
7cd5419264796cfeaf8215383cf0f89130a81fectrawick ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02219)
7cd5419264796cfeaf8215383cf0f89130a81fectrawick "access to %s failed, reason: %s",
7cd5419264796cfeaf8215383cf0f89130a81fectrawick /* remember forbidden access for strict require option */
7cd5419264796cfeaf8215383cf0f89130a81fectrawick apr_table_setn(r->notes, "ssl-access-forbidden", "1");
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * Check to see whether SSL is in use; if it's not, then no
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * further access control checks are relevant. (the test for
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * sc->enabled is probably strictly unnecessary)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * Support for per-directory reconfigured SSL connection parameters
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * We do not force any renegotiation if the user is already authenticated
3568de757bac0b47256647504c186d17ca272f85rbb * Support for per-directory reconfigured SSL connection parameters.
74fd6d9aeadb9022086259c5c1ae00bc0dda9c9astoddard * This is implemented by forcing an SSL renegotiation with the
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp * reconfigured parameter suite. But Apache's internal API processing
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp * makes our life very hard here, because when internal sub-requests occur
3568de757bac0b47256647504c186d17ca272f85rbb * we nevertheless should avoid multiple unnecessary SSL handshakes (they
3568de757bac0b47256647504c186d17ca272f85rbb * require extra network I/O and especially time to perform).
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * But the optimization for filtering out the unnecessary handshakes isn't
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * obvious and trivial. Especially because while Apache is in its
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * sub-request processing the client could force additional handshakes,
b5ffe4f30780fb159db08bd9f628980d2a092711sf * too. And these take place perhaps without our notice. So the only
b5ffe4f30780fb159db08bd9f628980d2a092711sf * possibility is to explicitly _ask_ OpenSSL whether the renegotiation
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * has to be performed or not. It has to performed when some parameters
1ce78cf71b5baaf2c1ab48e818cb1f2397df5010trawick * which were previously known (by us) are not those we've now
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * reconfigured (as known by OpenSSL) or (in optimized way) at least when
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * the reconfigured parameter suite is stronger (more restrictions) than
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * the currently active one.
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * Override of SSLCipherSuite
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * We provide two options here:
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * o The paranoid and default approach where we force a renegotiation when
dd028aa8111afb6534fece555e8c2d408894671etrawick * the cipher suite changed in _any_ way (which is straight-forward but
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * often forces renegotiations too often and is perhaps not what the
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * user actually wanted).
3568de757bac0b47256647504c186d17ca272f85rbb * o The optimized and still secure way where we force a renegotiation
3568de757bac0b47256647504c186d17ca272f85rbb * only if the currently active cipher is no longer contained in the
3568de757bac0b47256647504c186d17ca272f85rbb * reconfigured/new cipher suite. Any other changes are not important
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * because it's the servers choice to select a cipher from the ones the
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * client supports. So as long as the current cipher is still in the new
f714f1a7002928d785e53e70349700a7f595fee3trawick * cipher suite we're happy. Because we can assume we would have
f714f1a7002928d785e53e70349700a7f595fee3trawick * selected it again even when other (better) ciphers exists now in the
3568de757bac0b47256647504c186d17ca272f85rbb * new cipher suite. This approach is fine because the user explicitly
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard * has to enable this via ``SSLOptions +OptRenegotiate''. So we do no
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh * implicit optimizations.
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh if (dc->szCipherSuite || (r->server != handshakeserver)) {
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh /* remember old state */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard cipher_list_old = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard cipher_list_old = sk_SSL_CIPHER_dup(cipher_list_old);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* configure new state */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if ((dc->szCipherSuite || sc->server->auth.cipher_suite) &&
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02253)
3568de757bac0b47256647504c186d17ca272f85rbb "Unable to reconfigure (per-directory) "
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard "permitted SSL ciphers");
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim /* determine whether a renegotiation has to be forced */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard cipher_list = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* optimized way */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* paranoid way */
3568de757bac0b47256647504c186d17ca272f85rbb for (n = 0;
3568de757bac0b47256647504c186d17ca272f85rbb SSL_CIPHER *value = sk_SSL_CIPHER_value(cipher_list, n);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz !renegotiate && (n < sk_SSL_CIPHER_num(cipher_list_old));
fe6baec9bbcd36f932b71a355120cd7b5a685d6cfielding SSL_CIPHER *value = sk_SSL_CIPHER_value(cipher_list_old, n);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* cleanup */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* tracing */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02220)
8e9734d1a4af74c141e2a0f880bb51bb061fa03atrawick "Reconfigured cipher suite will force renegotiation");
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick * override of SSLVerifyDepth
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * The depth checks are handled by us manually inside the verify callback
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe * function and not by OpenSSL internally (and our function is aware of
0f113d7123e8bd3e3e2e9b6373461a1a773bfccatrawick * both the per-server and per-directory contexts). So we cannot ask
0f113d7123e8bd3e3e2e9b6373461a1a773bfccatrawick * OpenSSL about the currently verify depth. Instead we remember it in our
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * SSLConnRec attached to the SSL* of OpenSSL. We've to force the
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * renegotiation if the reconfigured/new verify depth is less than the
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * currently active/remembered verify depth (because this means more
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * restriction on the certificate chain).
3568de757bac0b47256647504c186d17ca272f85rbb (mySrvConfig(handshakeserver))->server->auth.verify_depth;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* determine the new depth */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz sslconn->verify_depth = (dc->nVerifyDepth != UNSET) ?
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02254)
3568de757bac0b47256647504c186d17ca272f85rbb "Reduced client verification depth will force "
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "renegotiation");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * override of SSLVerifyClient
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * We force a renegotiation if the reconfigured/new verify type is
f886987cd0bd4220c14043c4d9be77ec22902e73trawick * stronger than the currently active verify type.
f886987cd0bd4220c14043c4d9be77ec22902e73trawick * The order is: none << optional_no_ca << optional << require
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * Additionally the following optimization is possible here: When the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * currently active verify type is "none" but a client certificate is
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * already known/present, it's enough to manually force a client
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * verification but at least skip the I/O-intensive renegotiation
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * handshake.
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick (sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* remember old state */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* configure new state */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE)) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) ||
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) ||
e8f95a682820a599fe41b22977010636be5c2717jim (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL) ||
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* determine whether we've to force a renegotiation */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* optimization */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ((peercert = SSL_get_peer_certificate(ssl)) != NULL))
36c8049de63c446926139936c3d195330a0539cetrawick ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02255)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "Changed client verification type will force "
e8f95a682820a599fe41b22977010636be5c2717jim "%srenegotiation",
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* If we're handling a request for a vhost other than the default one,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * then we need to make sure that client authentication is properly
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * enforced. For clients supplying an SNI extension, the peer
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * certificate verification has happened in the handshake already
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * (and r->server == handshakeserver). For non-SNI requests,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * an additional check is needed here. If client authentication
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * is configured as mandatory, then we can only proceed if the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * CA list doesn't have to be changed (OpenSSL doesn't provide
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * an option to change the list for an existing session).
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick SSLSrvConfigRec *hssc = mySrvConfig(handshakeserver);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02256)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "Non-default virtual host with SSLVerify set to "
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "'require' and VirtualHost-specific CA certificate "
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "list is only available to clients with TLS server "
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "name indication (SNI) support");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* let it pass, possibly with an "incorrect" peer cert,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * so make sure the SSL_CLIENT_VERIFY environment variable
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * will indicate partial success only, later on.
f886987cd0bd4220c14043c4d9be77ec22902e73trawick /* If a renegotiation is now required for this location, and the
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * request includes a message body (and the client has not
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * requested a "100 Continue" response), then the client will be
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * streaming the request body over the wire already. In that
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * case, it is not possible to stop and perform a new SSL
3568de757bac0b47256647504c186d17ca272f85rbb * handshake immediately; once the SSL library moves to the
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp * "accept" state, it will reject the SSL packets which the client
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp * is sending for the request body.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * To allow authentication to complete in this auth hook, the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * solution used here is to fill a (bounded) buffer with the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * request body, and then to reinject that request body later.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick && (apr_table_get(r->headers_in, "transfer-encoding")
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick && strcmp(apr_table_get(r->headers_in, "content-length"), "0")))
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE :
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* Fill the I/O buffer with the request body if possible. */
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick /* If the reneg buffer size is set to zero, just fail. */
f886987cd0bd4220c14043c4d9be77ec22902e73trawick ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02257)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "could not buffer message body to allow "
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe "SSL renegotiation to proceed");
e8f95a682820a599fe41b22977010636be5c2717jim * now do the renegotiation if anything was actually reconfigured
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * Now we force the SSL renegotiation by sending the Hello Request
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * message to the client. Here we have to do a workaround: Actually
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * OpenSSL returns immediately after sending the Hello Request (the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * intent AFAIK is because the SSL/TLS protocol says it's not a must
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * that the client replies to a Hello Request). But because we insist
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * on a reply (anything else is an error for us) we have to go to the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * ACCEPT state manually. Using SSL_set_accept_state() doesn't work
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * here because it resets too much of the connection. So we set the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * state explicitly and continue the handshake manually.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02221)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "Requesting connection re-negotiation");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* perform just a manual re-verification of the peer */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02258)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "Performing quick renegotiation: "
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "just re-verifying the peer");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick cert_stack = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* client cert is in the session cache, but there is
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * no chain, since ssl3_get_client_certificate()
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * sk_X509_shift-ed the peer cert out of the chain.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * we put it back here for the purpose of quick_renegotiation.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02222)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick "Cannot find peer certificate chain");
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02223)
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm "Cannot find certificate storage");
e8f95a682820a599fe41b22977010636be5c2717jim X509_STORE_CTX_init(&cert_store_ctx, cert_store, cert, cert_stack);
44d2e75323651320b480d8bc2f098448a08de4fcwrowe if (depth >= 0) {
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02224)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "Re-negotiation verification step failed");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server);
f886987cd0bd4220c14043c4d9be77ec22902e73trawick /* we created this ourselves, so free it */
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe /* Additional mitigation for CVE-2009-3555: At this point,
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe * before renegotiating, an (entire) request has been read
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe * from the connection. An attacker may have sent further
3568de757bac0b47256647504c186d17ca272f85rbb * data to "prefix" any subsequent request by the victim's
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * client after the renegotiation; this data may already
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * have been read and buffered. Forcing a connection
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * closure after the response ensures such data will be
3568de757bac0b47256647504c186d17ca272f85rbb * discarded. Legimately pipelined HTTP requests will be
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * retried anyway with this approach. */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02259)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "insecure SSL re-negotiation required, but "
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "a pipelined request is present; keepalive "
3568de757bac0b47256647504c186d17ca272f85rbb "disabled");
e8f95a682820a599fe41b22977010636be5c2717jim reneg_support = SSL_get_secure_renegotiation_support(ssl) ?
98fb535f829e2a95aabd82420931f476661fa8e3jorton /* Perform a full renegotiation. */
98fb535f829e2a95aabd82420931f476661fa8e3jorton ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02260)
3568de757bac0b47256647504c186d17ca272f85rbb "Performing full renegotiation: complete handshake "
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "protocol (%s support secure renegotiation)",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (unsigned char *)&id,
85c5af648e9f414bd4f157490766d2fd5515a9f5rpluem /* Toggle the renegotiation state to allow the new
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe * handshake to proceed. */
85c5af648e9f414bd4f157490766d2fd5515a9f5rpluem ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02225)
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe "Re-negotiation request failed");
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02226)
3568de757bac0b47256647504c186d17ca272f85rbb "Awaiting re-negotiation handshake");
3568de757bac0b47256647504c186d17ca272f85rbb /* XXX: Should replace setting state with SSL_renegotiate(ssl);
3568de757bac0b47256647504c186d17ca272f85rbb * However, this causes failures in perl-framework currently,
3568de757bac0b47256647504c186d17ca272f85rbb * perhaps pre-test if we have already negotiated?
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02261)
3568de757bac0b47256647504c186d17ca272f85rbb "Re-negotiation handshake failed: "
3568de757bac0b47256647504c186d17ca272f85rbb "Not accepted by client!?");
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe * Remember the peer certificate's DN
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Finally check for acceptable renegotiation results
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz (sc->server->auth.verify_mode != SSL_CVERIFY_NONE)) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz BOOL do_verify = ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE));
3568de757bac0b47256647504c186d17ca272f85rbb if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02262)
3568de757bac0b47256647504c186d17ca272f85rbb "Re-negotiation handshake failed: "
return HTTP_FORBIDDEN;
if (do_verify) {
return HTTP_FORBIDDEN;
if (cipher_list) {
r->filename,
return HTTP_FORBIDDEN;
const char *errstring;
if (ok < 0) {
return HTTP_FORBIDDEN;
r->filename,
return HTTP_FORBIDDEN;
return DECLINED;
char *user;
return HTTP_FORBIDDEN;
if (!ap_is_initial_req(r)) {
return DECLINED;
auth_line++;
return HTTP_FORBIDDEN;
return DECLINED;
APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02434) "Failed to set FakeBasicAuth username to '%s', did not exist in certificate", dc->szUserName);
return DECLINED;
NULL);
return DECLINED;
return HTTP_FORBIDDEN;
return DECLINED;
static const char *ssl_hook_Fixup_vars[] = {
#ifdef HAVE_SRP
#ifdef HAVE_TLSEXT
const char *servername;
&& !r->main) {
if (!(((sc->enabled == SSL_ENABLED_TRUE) || (sc->enabled == SSL_ENABLED_OPTIONAL)) && sslconn && (ssl = sslconn->ssl))) {
return DECLINED;
#ifdef HAVE_TLSEXT
for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
r, var);
if (val) {
return DECLINED;
const char *require_line,
const void *parsed)
if (ssl)
return AUTHZ_GRANTED;
return AUTHZ_DENIED;
const char *require_line,
const void **parsed)
return NULL;
const char *require_line,
const void *parsed)
if (!ssl)
return AUTHZ_DENIED;
if (xs) {
return AUTHZ_GRANTED;
return AUTHZ_DENIED;
const char *require_line,
const void **parsed)
return NULL;
int type;
#ifdef SSL_CERT_SET_SERVER
* (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h).
return TRUE;
* s3_both.c:ssl_verify_alarm_type() maps to SSL_AD_CERTIFICATE_UNKNOWN,
#ifndef OPENSSL_NO_OCSP
if (!ok) {
if (!ok) {
return ok;
#define SSLPROXY_CERT_CB_LOG_FMT \
const char *msg)
return FALSE;
return TRUE;
return TRUE;
if (ca_cert_chains) {
return TRUE;
return FALSE;
const char *request,
unsigned char *id,
unsigned int idlen,
const char *status,
const char *result,
long timeout)
if (!APLOGdebug(s)) {
if (timeout) {
unsigned char *id;
unsigned int idlen;
#ifdef OPENSSL_NO_SSL_INTERN
+ timeout),
unsigned char *id,
*do_copy = 0;
return session;
server_rec *s;
unsigned char *id;
unsigned int idlen;
#ifdef OPENSSL_NO_SSL_INTERN
if (rc == 0) {
else if (rc < 0) {
conn_rec *c;
server_rec *s;
s = mySrvFromConn(c);
if (s && APLOGdebug(s)) {
#ifdef HAVE_TLSEXT
const char *servername =
if (servername) {
(void *)servername)) {
return SSL_TLSEXT_ERR_OK;
return SSL_TLSEXT_ERR_NOACK;
* (adapted from vhost.c:matches_aliases())
if (!found) {
if (names) {
if (!name[i])
if (!found) {
if (names) {
if (!name[i])
unsigned char *sid_ctx =
if (APLOGtrace4(s)) {
#ifdef HAVE_TLS_SESSION_TICKETS
unsigned char *keyname,
unsigned char *iv,
int mode)
* see s3_srvr.c:ssl3_send_newsession_ticket()
else if (mode == 0) {
* see t1_lib.c:tls_decrypt_ticket()
#ifdef HAVE_TLS_NPN
int num_protos;
unsigned int size;
unsigned char *data;
unsigned char *start;
*size_out = 0;
return SSL_TLSEXT_ERR_OK;
size = 0;
for (i = 0; i < num_protos; ++i) {
if (size == 0) {
return SSL_TLSEXT_ERR_OK;
for (i = 0; i < num_protos; ++i) {
++start;
return SSL_TLSEXT_ERR_OK;
#ifdef HAVE_SRP
SRP_user_pwd *u;
return SSL3_AL_FATAL;
return SSL3_AL_FATAL;
return SSL_ERROR_NONE;