ssl_engine_kernel.c revision 766c20b0366e1d0e359e0d9a834669e19a4db3d9
2362N/A** _ __ ___ ___ __| | ___ ___| | mod_ssl 0N/A** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL 0N/A** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org 0N/A** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org 0N/A** The SSL engine kernel 0N/A/* ==================================================================== 0N/A * The Apache Software License, Version 1.1 0N/A * Copyright (c) 2000-2002 The Apache Software Foundation. All rights 0N/A * Redistribution and use in source and binary forms, with or without 0N/A * modification, are permitted provided that the following conditions 2362N/A * 1. Redistributions of source code must retain the above copyright 0N/A * notice, this list of conditions and the following disclaimer. 0N/A * 2. Redistributions in binary form must reproduce the above copyright 0N/A * notice, this list of conditions and the following disclaimer in 0N/A * the documentation and/or other materials provided with the 0N/A * 3. The end-user documentation included with the redistribution, 0N/A * if any, must include the following acknowledgment: 0N/A * "This product includes software developed by the 0N/A * Alternately, this acknowledgment may appear in the software itself, 0N/A * if and wherever such third-party acknowledgments normally appear. 0N/A * 4. The names "Apache" and "Apache Software Foundation" must 0N/A * not be used to endorse or promote products derived from this 0N/A * software without prior written permission. For written 0N/A * permission, please contact apache@apache.org. 0N/A * 5. Products derived from this software may not be called "Apache", 0N/A * nor may "Apache" appear in their name, without prior written 0N/A * permission of the Apache Software Foundation. 0N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 0N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 0N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 0N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 0N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 0N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 0N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 0N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 0N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 0N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 0N/A * ==================================================================== 0N/A /* ``It took me fifteen years to discover 0N/A I had no talent for programming, but 0N/A I couldn't give it up because by that 0N/A time I was too famous.'' 0N/A * Close the SSL part of the socket connection 0N/A * (called immediately _before_ the socket is closed) 0N/A/* XXX: perhaps ssl_abort() should call us or vice-versa 0N/A * lot of the same happening in both places 0N/A * Now close the SSL layer of the connection. We've to take 0N/A * the TLSv1 standard into account here: 0N/A * | 7.2.1. Closure alerts 0N/A * | The client and the server must share knowledge that the connection is 0N/A * | ending in order to avoid a truncation attack. Either party may 0N/A * | initiate the exchange of closing messages. 0N/A * | This message notifies the recipient that the sender will not send 0N/A * | any more messages on this connection. The session becomes 0N/A * | unresumable if any connection is terminated without proper 0N/A * | close_notify messages with level equal to warning. 0N/A * | Either party may initiate a close by sending a close_notify alert. 0N/A * | Any data received after a closure alert is ignored. 0N/A * | Each party is required to send a close_notify alert before closing 0N/A * | the write side of the connection. It is required that the other party 0N/A * | respond with a close_notify alert of its own and close down the 0N/A * | connection immediately, discarding any pending writes. It is not 0N/A * | required for the initiator of the close to wait for the responding 0N/A * | close_notify alert before closing the read side of the connection. 0N/A * This means we've to send a close notify message, but haven't to wait 0N/A * for the close notify of the client. Actually we cannot wait for the 0N/A * close notify of the client because some clients (including Netscape 0N/A * 4.x) don't send one, so we would hang. 0N/A * exchange close notify messages, but allow the user 0N/A * to force the type of handshake via SetEnvIf directive 0N/A /* send close notify, but don't wait for clients close notify 0N/A (standard compliant and safe, so it's the DEFAULT!) */ 0N/A /* perform no close notify handshake at all 0N/A /* send close notify and wait for clients close notify 0N/A (standard compliant, but usually causes connection hangs) */ 0N/A /* and finally log the fact that we've closed the connection */ 0N/A "Connection to child %ld closed with %s shutdown" 0N/A "(server %s, client %s)",
/* deallocate the SSL connection */ * Post Read Request Handler "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" "<a href=\"%s\"><b>%s</b></a></blockquote>",
/* Now that we have caught this error, forget it. we are done * with using SSL on this request. * Get the SSL connection structure and perform the * delayed interlinking from SSL back to request_rec * Move SetEnvIf information from request_rec to conn_rec/BUFF * to allow the close connection handler to use them. /* being case-sensitive here. * and not checking for the -shutdown since these are the only * SetEnvIf "flags" we support return;
/* should only ever be one ssl-*-shutdown */ * URL Translation Handler * Log information about incoming HTTPS requests "%s HTTPS request received for child %ld (server %s)",
/* SetEnvIf ssl-*-shutdown flags can only be per-server, * so they won't change across keepalive requests * Support for SSLRequireSSL directive "access to %s failed, reason: %s",
r->
filename,
"SSL connection required");
/* remember forbidden access for strict require option */ * Check to see if SSL protocol is on * 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 * o The optimized and still secure way where we force a renegotiation * only if the currently active cipher is no longer contained in the * 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. /* configure new state */ "Unable to reconfigure (per-directory) " "permitted SSL ciphers");
/* determine whether a renegotiation has to be forced */ "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 * restriction on the certificate chain). /* XXX: doesnt look like sslconn->verify_depth is actually used */ /* determine whether a renegotiation has to be forced */ "Reduced client verification depth will force " * override of SSLVerifyClient * stronger than the currently active verify type. * The order is: none << optional_no_ca << optional << require * Additionally the following optimization is possible here: When the * currently active verify type is "none" but a client certificate is * already known/present, it's enough to manually force a client * verification but at least skip the I/O-intensive renegotation /* configure new state */ /* determine whether we've to force a renegotiation */ "Changed client verification type will force " * override SSLCACertificateFile & SSLCACertificatePath * This is only enabled if the SSL_set_cert_store() function * is available in the ssl library. the 1.x based mod_ssl * used SSL_CTX_set_cert_store which is not thread safe. * check if per-dir and per-server config field are not the same. * if f is defined in per-dir and not defined in per-server * or f is defined in both but not the equal ... "Unable to reconfigure verify locations " "for client authentication");
/* SSL_free will free cert_store */ "Unable to determine list of available " "CA certificates for client authentication");
"Changed client verification locations will force " #
endif /* HAVE_SSL_SET_CERT_STORE */ * SSL renegotiations in conjunction with HTTP * requests using the POST method are not supported. * 1. When the client sends a HTTP/HTTPS request, Apache's core code * reads only the request line ("METHOD /path HTTP/x.y") and the * attached MIME headers ("Foo: bar") up to the terminating line ("CR * LF"). An attached request body (for instance the data of a POST * method) is _NOT_ read. Instead it is read by mod_cgi's content * handler and directly passed to the CGI script. * 2. mod_ssl supports per-directory re-configuration of SSL parameters. * This is implemented by performing an SSL renegotiation of the * re-configured parameters after the request is read, but before the * response is sent. In more detail: the renegotiation happens after the * request line and MIME headers were read, but _before_ the attached * request body is read. The reason simply is that in the HTTP protocol * usually there is no acknowledgment step between the headers and the * body (there is the 100-continue feature and the chunking facility * only), so Apache has no API hook for this step. * 3. the problem now occurs when the client sends a POST request for * URL /foo via HTTPS the server and the server has SSL parameters * re-configured on a per-URL basis for /foo. Then mod_ssl has to * perform an SSL renegotiation after the request was read and before * the response is sent. But the problem is the pending POST body data * in the receive buffer of SSL (which Apache still has not read - it's * pending until mod_cgi sucks it in). When mod_ssl now tries to perform * the renegotiation the pending data leads to an I/O error. * There are only two solutions: Either to simply state that POST * requests to URLs with SSL re-configurations are not allowed, or to * renegotiate really after the _complete_ request (i.e. including * the POST body) was read. Obviously the latter would be preferred, * but it cannot be done easily inside Apache, because as already * mentioned, there is no API step between the body reading and the body * processing. And even when we mod_ssl would hook directly into the * loop of mod_cgi, we wouldn't solve the problem for other handlers, of * course. So the only general solution is to suck in the pending data * of the request body from the OpenSSL BIO into the Apache BUFF. Then * the renegotiation can be done and after this step Apache can proceed * processing the request as before. * Solution Implementation: * We cannot simply suck in the data via an SSL_read-based loop because of * HTTP chunking. Instead we _have_ to use the Apache API for this step which * is aware of HTTP chunking. So the trick is to suck in the pending request * data via the Apache API (which uses Apache's BUFF code and in the * background mod_ssl's I/O glue code) and re-inject it later into the Apache * BUFF code again. This way the data flows twice through the Apache BUFF, of * course. But this way the solution doesn't depend on any Apache specifics * and is fully transparent to Apache modules. * !! BUT ALL THIS IS STILL NOT RE-IMPLEMENTED FOR APACHE 2.0 !! "SSL Re-negotiation in conjunction " "with POST method not supported!\n" "hint: try SSLOptions +OptRenegotiate");
* now do the renegotiation if anything was actually reconfigured * Now we force the SSL renegotation by sending the Hello Request * message to the client. Here we have to do a workaround: Actually * OpenSSL returns immediately after sending the Hello Request (the * intent AFAIK is because the SSL/TLS protocol says it's not a must * that the client replies to a Hello Request). But because we insist * on a reply (anything else is an error for us) we have to go to the * ACCEPT state manually. Using SSL_set_accept_state() doesn't work * here because it resets too much of the connection. So we set the * state explicitly and continue the handshake manually. "Requesting connection re-negotiation");
/* perform just a manual re-verification of the peer */ "Performing quick renegotiation: " "just re-verifying the peer");
/* client cert is in the session cache, but there is * no chain, since ssl3_get_client_certificate() * sk_X509_shift-ed the peer cert out of the chain. * we put it back here for the purpose of quick_renegotiation. "Cannot find peer certificate chain");
"Cannot find certificate storage");
"Re-negotiation verification step failed");
/* we created this ourselves, so free it */ /* do a full renegotiation */ "Performing full renegotiation: " "complete handshake protocol");
"Re-negotiation request failed");
"Awaiting re-negotiation handshake");
"Re-negotiation handshake failed: " "Not accepted by client!?");
* Remember the peer certificate's DN * Finally check for acceptable renegotiation results "Re-negotiation handshake failed: " "Client verification failed");
"Re-negotiation handshake failed: " "Client certificate missing");
* Check SSLRequire boolean expressions "SSL requirement expression: %s",
"access to %s failed, reason: %s",
/* remember forbidden access for strict require option */ "Access to %s denied for %s " "(requirement expression not fulfilled)",
"access to %s failed, reason: %s",
"SSL requirement expression not fulfilled " "(see SSL logfile for more details)");
/* remember forbidden access for strict require option */ * Else access is granted from our point of view (except vendor * handlers override). But we have to return DECLINED here instead * of OK, because mod_auth and other modules still might want to * Authentication Handler: * Fake a Basic authentication from the X509 client certificate. * This must be run fairly early on to prevent a real authentication from * occuring, in particular it must be run before anything else that * authenticates a user. This means that the Module statement for this * module should be LAST in the Configuration file. * Additionally forbid access (again) * when strict require option is used. * Make sure the user is not able to fake the client certificate * based authentication by just entering an X.509 Subject DN * ("/XX=YYY/XX=YYY/..") as the username and "password" as the * We decline operation in various situations... * - SSLOptions +FakeBasicAuth not configured * - r->user already authenticated * - client did not present a certificate * Fake a password - which one would be immaterial, as, it seems, an empty * password in the users file would match ALL incoming passwords, if only * we were using the standard crypt library routine. Unfortunately, OpenSSL * "fixes" a "bug" in crypt and thus prevents blank passwords from * working. (IMHO what they really fix is a bug in the users of the code * - failing to program correctly for shadow passwords). We need, * therefore, to provide a password. This password can be matched by * adding the string "xxj31ZMTZzkVA" as the password in the user file. * This is just the crypted variant of the word "password" ;-) "Faking HTTP Basic Auth header: \"Authorization: %s\"",
buf1);
/* authorization phase */ * Additionally forbid access (again) * when strict require option is used. * Check to see if SSL is on * Annotate the SSI/CGI environment with standard SSL information /* the always present HTTPS (=HTTP over SSL) flag! */ /* standard SSL environment variables */ * On-demand bloat up the SSI/CGI environment with certificate data /* _________________________________________________________________ ** OpenSSL Callback Functions ** _________________________________________________________________ * Handle out temporary RSA private keys on demand * The background of this as the TLSv1 standard explains it: * | D.1. Temporary RSA keys * | US Export restrictions limit RSA keys used for encryption to 512 * | bits, but do not place any limit on lengths of RSA keys used for * | signing operations. Certificates often need to be larger than 512 * | bits, since 512-bit RSA keys are not secure enough for high-value * | transactions or for applications requiring long-term security. Some * | certificates are also designated signing-only, in which case they * | cannot be used for key exchange. * | When the public key in the certificate cannot be used for encryption, * | the server signs a temporary RSA key, which is then exchanged. In * | exportable applications, the temporary RSA key should be the maximum * | allowable length (i.e., 512 bits). Because 512-bit RSA keys are * | relatively insecure, they should be changed often. For typical * | electronic commerce applications, it is suggested that keys be * | changed daily or every 500 transactions, and more often if possible. * | Note that while it is acceptable to use the same temporary key for * | multiple transactions, it must be signed each time it is used. * | RSA key generation is a time-consuming process. In many cases, a * | low-priority process can be assigned the task of key generation. * | Whenever a new key is completed, the existing temporary key can be * | replaced with the new one. * XXX: base on comment above, if thread support is enabled, * we should spawn a low-priority thread to generate new keys * So we generated 512 and 1024 bit temporary keys on startup * which we now just hand out on demand.... "handing out temporary %d bit RSA key",
keylen);
/* doesn't matter if export flag is on, * we won't be asked for keylen > 512 in that case. * if we are asked for a keylen > 1024, it is too expensive * to generate on the fly. * XXX: any reason not to generate 2048 bit keys at startup? * Hand out the already generated DH parameters... "handing out temporary %d bit DH key",
keylen);
* This OpenSSL callback function is called when OpenSSL * does client authentication and verifies the certificate chain. /* Get Apache context back through OpenSSL context */ /* Get verify ingredients */ * Log verification information "Certificate Verification: " "depth: %d, subject: %s, issuer: %s",
* Check for optionally acceptable non-verifiable issuer situation * SSLProxyVerify is either not configured or set to "none". * (this callback doesn't happen in the server context if SSLVerify * is not configured or set to "none") "Certificate Verification: Verifiable Issuer is " "configured as optional, therefore we're accepting " * Additionally perform CRL-based revocation checks * If we already know it's not ok, log the real reason "Certificate Verification: Error (%d): %s",
* Finally check the depth of the certificate verification "Certificate Verification: Certificate Chain too long " "(chain has %d certificates, but maximum allowed are " * And finally signal OpenSSL the (perhaps changed) state * Unless a revocation store for CRLs was created we * cannot do any CRL-based verification, of course. * Determine certificate ingredients in advance * OpenSSL provides the general mechanism to deal with CRLs but does not * use them automatically when verifying certificates, so we do it * explicitly here. We will check the CRL for the currently checked * certificate, if there is such a CRL in the store. * We come through this procedure for each certificate in the certificate * chain, starting with the root-CA's certificate. At each step we've to * both verify the signature on the CRL (to make sure it's a valid CRL) * and it's revocation list (to make sure the current certificate isn't * revoked). But because to check the signature on the CRL we need the * public key of the issuing CA certificate (which was already processed * one round before), we've a little problem. But we can both solve it and * at the same time optimize the processing by using the following * verification scheme (idea and code snippets borrowed from the GLOBUS * 1. We'll check the signature of a CRL in each step when we find a CRL * through the _subject_ name of the current certificate. This CRL * itself will be needed the first time in the next round, of course. * But we do the signature processing one round before this where the * public key of the CA is available. * 2. We'll check the revocation list of a CRL in each step when * we find a CRL through the _issuer_ name of the current certificate. * This CRLs signature was then already verified one round before. * This verification scheme allows a CA to revoke its own certificate as * Try to retrieve a CRL corresponding to the _subject_ of * the current certificate in order to verify it's integrity. * Log information about CRL * (A little bit complicated because of ASN.1 and BIOs...) char buff[
512];
/* should be plenty */ * Verify the signature on this CRL "Invalid signature on CRL");
* Check date of CRL to make sure it's not expired "Found CRL has invalid nextUpdate field");
"Found CRL is expired - " "revoking all certificates until you get updated CRL");
* Try to retrieve a CRL corresponding to the _issuer_ of * the current certificate in order to check for revocation. * Check if the current certificate is revoked by this CRL for (i = 0; i < n; i++) {
"Certificate with serial %ld (0x%lX) " "revoked per CRL from issuer %s",
"Proxy client certificate callback: (%s) " * caller will decrement the cert and key reference * so we need to increment here to prevent them from "downstream server wanted client certificate " * downstream server didn't send us a list of acceptable CA certs, * so we send the first client cert in the list. "Inter-Process Session Cache: " "request=%s status=%s id=%s %s(session %s)",
* This callback function is executed by OpenSSL whenever a new SSL_SESSION is * added to the internal OpenSSL session cache. We use this hook to spread the * SSL_SESSION also to the inter-process disk-cache to make share it with our * other Apache pre-forked server processes. /* Get Apache context back through OpenSSL context */ * Set the timeout also for the internal OpenSSL cache, because this way * our inter-process cache is consulted only when it's really necessary. * Store the SSL_SESSION in the inter-process cache with the * same expire time, so it expires automatically there, too. * return 0 which means to OpenSSL that the session is still * valid and was not freed by us with SSL_SESSION_free(). * This callback function is executed by OpenSSL whenever a * SSL_SESSION is looked up in the internal OpenSSL cache and it * was not found. We use this to lookup the SSL_SESSION in the * inter-process disk-cache where it was perhaps stored by one * of our other Apache pre-forked server processes. /* Get Apache context back through OpenSSL context */ * Try to retrieve the SSL_SESSION from the inter-process cache * Return NULL or the retrieved SSL_SESSION. But indicate (by * setting do_copy to 0) that the reference count on the * SSL_SESSION should not be incremented by the SSL library, * because we will no longer hold a reference to it ourself. * This callback function is executed by OpenSSL whenever a * SSL_SESSION is removed from the the internal OpenSSL cache. * We use this to remove the SSL_SESSION in the inter-process * Get Apache context back through OpenSSL context return;
/* on server shutdown Apache is already gone */ * Remove the SSL_SESSION from the inter-process cache * This callback function is executed while OpenSSL processes the * SSL handshake and does SSL record layer stuff. We use it to * trace OpenSSL's processing in out SSL logfile. * find corresponding server * create the various trace messages "%s: Exit: failed in %s",
* Because SSL renegotations can happen at any time (not only after * SSL_accept()), the best way to log the current connection details is * right after a finished handshake. "Connection: Client IP: %s, Protocol: %s, " "Cipher: %s (%s/%s bits)",