diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c | 1876 |
1 files changed, 0 insertions, 1876 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c deleted file mode 100644 index 60133f7c..00000000 --- a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c +++ /dev/null @@ -1,1876 +0,0 @@ -/* 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 "mod_ssl.h" - -static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); - -/* Perform a speculative (and non-blocking) read from the connection - * filters for the given request, to determine whether there is any - * pending data to read. Return non-zero if there is, else zero. */ -static int has_buffered_data(request_rec *r) -{ - apr_bucket_brigade *bb; - apr_off_t len; - apr_status_t rv; - int result; - - bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); - - rv = ap_get_brigade(r->connection->input_filters, bb, AP_MODE_SPECULATIVE, - APR_NONBLOCK_READ, 1); - result = rv == APR_SUCCESS - && apr_brigade_length(bb, 1, &len) == APR_SUCCESS - && len > 0; - - apr_brigade_destroy(bb); - - return result; -} - -/* - * 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) { - 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) { - 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) { - renegotiate = TRUE; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "Reduced client verification depth will force " - "renegotiation"); - } - } - - /* - * override of SSLVerifyClient - * - * We force a renegotiation if the reconfigured/new verify type is - * 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 - * handshake. - */ - if (dc->nVerifyClient != SSL_CVERIFY_UNSET) { - /* remember old state */ - verify_old = SSL_get_verify_mode(ssl); - /* configure new state */ - verify = SSL_VERIFY_NONE; - - if (dc->nVerifyClient == SSL_CVERIFY_REQUIRE) { - verify |= SSL_VERIFY_PEER_STRICT; - } - - if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) || - (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA)) - { - verify |= SSL_VERIFY_PEER; - } - - modssl_set_verify(ssl, verify, ssl_callback_SSLVerify); - SSL_set_verify_result(ssl, X509_V_OK); - - /* determine whether we've to force a renegotiation */ - if (!renegotiate && verify != verify_old) { - if (((verify_old == SSL_VERIFY_NONE) && - (verify != SSL_VERIFY_NONE)) || - - (!(verify_old & SSL_VERIFY_PEER) && - (verify & SSL_VERIFY_PEER)) || - - (!(verify_old & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) && - (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) - { - renegotiate = TRUE; - /* optimization */ - - if ((dc->nOptions & SSL_OPT_OPTRENEGOTIATE) && - (verify_old == SSL_VERIFY_NONE) && - ((peercert = SSL_get_peer_certificate(ssl)) != NULL)) - { - renegotiate_quick = TRUE; - X509_free(peercert); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "Changed client verification type will force " - "%srenegotiation", - renegotiate_quick ? "quick " : ""); - } - } - } - - /* - * 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. - */ - -#ifdef HAVE_SSL_SET_CERT_STORE - /* - * 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 ... - */ -#define MODSSL_CFG_NE(f) \ - (dc->f && (!sc->f || (sc->f && strNE(dc->f, sc->f)))) - -#define MODSSL_CFG_CA(f) \ - (dc->f ? dc->f : sc->f) - - if (MODSSL_CFG_NE(szCACertificateFile) || - MODSSL_CFG_NE(szCACertificatePath)) - { - STACK_OF(X509_NAME) *ca_list; - const char *ca_file = MODSSL_CFG_CA(szCACertificateFile); - const char *ca_path = MODSSL_CFG_CA(szCACertificatePath); - - cert_store = X509_STORE_new(); - - if (!X509_STORE_load_locations(cert_store, ca_file, ca_path)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Unable to reconfigure verify locations " - "for client authentication"); - ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); - - X509_STORE_free(cert_store); - - return HTTP_FORBIDDEN; - } - - /* SSL_free will free cert_store */ - SSL_set_cert_store(ssl, cert_store); - - if (!(ca_list = ssl_init_FindCAList(r->server, r->pool, - ca_file, ca_path))) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Unable to determine list of available " - "CA certificates for client authentication"); - - return HTTP_FORBIDDEN; - } - - SSL_set_client_CA_list(ssl, ca_list); - renegotiate = TRUE; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "Changed client verification locations will force " - "renegotiation"); - } -#endif /* HAVE_SSL_SET_CERT_STORE */ - - /* If a renegotiation is now required for this location, and the - * request includes a message body (and the client has not - * requested a "100 Continue" response), then the client will be - * streaming the request body over the wire already. In that - * case, it is not possible to stop and perform a new SSL - * handshake immediately; once the SSL library moves to the - * "accept" state, it will reject the SSL packets which the client - * is sending for the request body. - * - * To allow authentication to complete in this auth hook, the - * solution used here is to fill a (bounded) buffer with the - * request body, and then to reinject that request body later. - */ - if (renegotiate && !renegotiate_quick - && (apr_table_get(r->headers_in, "transfer-encoding") - || (apr_table_get(r->headers_in, "content-length") - && strcmp(apr_table_get(r->headers_in, "content-length"), "0"))) - && !r->expecting_100) { - int rv; - - /* Fill the I/O buffer with the request body if possible. */ - rv = ssl_io_buffer_fill(r); - - if (rv) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "could not buffer message body to allow " - "SSL renegotiation to proceed"); - return rv; - } - } - - /* - * now do the renegotiation if anything was actually reconfigured - */ - if (renegotiate) { - /* - * 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. - */ - ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, - "Requesting connection re-negotiation"); - - if (renegotiate_quick) { - STACK_OF(X509) *cert_stack; - - /* perform just a manual re-verification of the peer */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "Performing quick renegotiation: " - "just re-verifying the peer"); - - cert_stack = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl); - - cert = SSL_get_peer_certificate(ssl); - - if (!cert_stack && cert) { - /* 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. - */ - cert_stack = sk_new_null(); - sk_X509_push(cert_stack, MODSSL_PCHAR_CAST cert); - } - - if (!cert_stack || (sk_X509_num(cert_stack) == 0)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Cannot find peer certificate chain"); - - return HTTP_FORBIDDEN; - } - - if (!(cert_store || - (cert_store = SSL_CTX_get_cert_store(ctx)))) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Cannot find certificate storage"); - - return HTTP_FORBIDDEN; - } - - if (!cert) { - cert = sk_X509_value(cert_stack, 0); - } - - X509_STORE_CTX_init(&cert_store_ctx, cert_store, cert, cert_stack); - depth = SSL_get_verify_depth(ssl); - - if (depth >= 0) { - X509_STORE_CTX_set_depth(&cert_store_ctx, depth); - } - - X509_STORE_CTX_set_ex_data(&cert_store_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx(), - (char *)ssl); - - if (!modssl_X509_verify_cert(&cert_store_ctx)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Re-negotiation verification step failed"); - ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); - } - - SSL_set_verify_result(ssl, cert_store_ctx.error); - X509_STORE_CTX_cleanup(&cert_store_ctx); - - if (cert_stack != SSL_get_peer_cert_chain(ssl)) { - /* we created this ourselves, so free it */ - sk_X509_pop_free(cert_stack, X509_free); - } - } - else { - request_rec *id = r->main ? r->main : r; - - /* Additional mitigation for CVE-2009-3555: At this point, - * before renegotiating, an (entire) request has been read - * from the connection. An attacker may have sent further - * data to "prefix" any subsequent request by the victim's - * client after the renegotiation; this data may already - * have been read and buffered. Forcing a connection - * closure after the response ensures such data will be - * discarded. Legimately pipelined HTTP requests will be - * retried anyway with this approach. */ - if (has_buffered_data(r)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "insecure SSL re-negotiation required, but " - "a pipelined request is present; keepalive " - "disabled"); - r->connection->keepalive = AP_CONN_CLOSE; - } - - /* Perform a full renegotiation. */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "Performing full renegotiation: complete handshake " - "protocol (%s support secure renegotiation)", -#if defined(SSL_get_secure_renegotiation_support) - SSL_get_secure_renegotiation_support(ssl) ? - "client does" : "client does not" -#else - "server does not" -#endif - ); - - SSL_set_session_id_context(ssl, - (unsigned char *)&id, - sizeof(id)); - - /* Toggle the renegotiation state to allow the new - * handshake to proceed. */ - sslconn->reneg_state = RENEG_ALLOW; - - SSL_renegotiate(ssl); - SSL_do_handshake(ssl); - - if (SSL_get_state(ssl) != SSL_ST_OK) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Re-negotiation request failed"); - ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); - - r->connection->aborted = 1; - return HTTP_FORBIDDEN; - } - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, - "Awaiting re-negotiation handshake"); - - SSL_set_state(ssl, SSL_ST_ACCEPT); - SSL_do_handshake(ssl); - - sslconn->reneg_state = RENEG_REJECT; - - if (SSL_get_state(ssl) != SSL_ST_OK) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Re-negotiation handshake failed: " - "Not accepted by client!?"); - - r->connection->aborted = 1; - return HTTP_FORBIDDEN; - } - } - - /* - * Remember the peer certificate's DN - */ - if ((cert = SSL_get_peer_certificate(ssl))) { - if (sslconn->client_cert) { - X509_free(sslconn->client_cert); - } - sslconn->client_cert = cert; - sslconn->client_dn = NULL; - } - - /* - * Finally check for acceptable renegotiation results - */ - if (dc->nVerifyClient != SSL_CVERIFY_NONE) { - BOOL do_verify = (dc->nVerifyClient == SSL_CVERIFY_REQUIRE); - - if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Re-negotiation handshake failed: " - "Client verification failed"); - - return HTTP_FORBIDDEN; - } - - if (do_verify) { - if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Re-negotiation handshake failed: " - "Client certificate missing"); - - return HTTP_FORBIDDEN; - } - - X509_free(peercert); - } - } - - /* - * Also check that SSLCipherSuite has been enforced as expected. - */ - if (cipher_list) { - cipher = SSL_get_current_cipher(ssl); - if (sk_SSL_CIPHER_find(cipher_list, cipher) < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "SSL cipher suite not renegotiated: " - "access to %s denied using cipher %s", - r->filename, - SSL_CIPHER_get_name(cipher)); - return HTTP_FORBIDDEN; - } - } - } - - /* If we're trying to have the user name set from a client - * certificate then we need to set it here. This should be safe as - * the user name probably isn't important from an auth checking point - * of view as the certificate supplied acts in that capacity. - * However, if FakeAuth is being used then this isn't the case so - * we need to postpone setting the username until later. - */ - if ((dc->nOptions & SSL_OPT_FAKEBASICAUTH) == 0 && dc->szUserName) { - char *val = ssl_var_lookup(r->pool, r->server, r->connection, - r, (char *)dc->szUserName); - if (val && val[0]) - r->user = val; - } - - /* - * Check SSLRequire boolean expressions - */ - requires = dc->aRequirement; - ssl_requires = (ssl_require_t *)requires->elts; - - for (i = 0; i < requires->nelts; i++) { - ssl_require_t *req = &ssl_requires[i]; - ok = ssl_expr_exec(r, req->mpExpr); - - if (ok < 0) { - cp = apr_psprintf(r->pool, - "Failed to execute " - "SSL requirement expression: %s", - ssl_expr_get_error()); - - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "access to %s failed, reason: %s", - r->filename, cp); - - /* remember forbidden access for strict require option */ - apr_table_setn(r->notes, "ssl-access-forbidden", "1"); - - return HTTP_FORBIDDEN; - } - - if (ok != 1) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, - "Access to %s denied for %s " - "(requirement expression not fulfilled)", - r->filename, r->connection->remote_ip); - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, - "Failed expression: %s", req->cpExpr); - - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "access to %s failed, reason: %s", - r->filename, - "SSL requirement expression not fulfilled " - "(see SSL logfile for more details)"); - - /* remember forbidden access for strict require option */ - apr_table_setn(r->notes, "ssl-access-forbidden", "1"); - - return HTTP_FORBIDDEN; - } - } - - /* - * 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 - * deny access. - */ - - return DECLINED; -} - -/* - * 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. - */ -int ssl_hook_UserCheck(request_rec *r) -{ - SSLConnRec *sslconn = myConnConfig(r->connection); - SSLSrvConfigRec *sc = mySrvConfig(r->server); - SSLDirConfigRec *dc = myDirConfig(r); - char *clientdn; - const char *auth_line, *username, *password; - - /* - * Additionally forbid access (again) - * when strict require option is used. - */ - if ((dc->nOptions & SSL_OPT_STRICTREQUIRE) && - (apr_table_get(r->notes, "ssl-access-forbidden"))) - { - return HTTP_FORBIDDEN; - } - - /* - * We decline when we are in a subrequest. The Authorization header - * would already be present if it was added in the main request. - */ - if (!ap_is_initial_req(r)) { - return DECLINED; - } - - /* - * 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 - * password. - */ - if ((auth_line = apr_table_get(r->headers_in, "Authorization"))) { - if (strcEQ(ap_getword(r->pool, &auth_line, ' '), "Basic")) { - while ((*auth_line == ' ') || (*auth_line == '\t')) { - auth_line++; - } - - auth_line = ap_pbase64decode(r->pool, auth_line); - username = ap_getword_nulls(r->pool, &auth_line, ':'); - password = auth_line; - - if ((username[0] == '/') && strEQ(password, "password")) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Encountered FakeBasicAuth spoof: %s", username); - return HTTP_FORBIDDEN; - } - } - } - - /* - * We decline operation in various situations... - * - SSLOptions +FakeBasicAuth not configured - * - r->user already authenticated - * - ssl not enabled - * - client did not present a certificate - */ - if (!(sc->enabled && sslconn && sslconn->ssl && sslconn->client_cert) || - !(dc->nOptions & SSL_OPT_FAKEBASICAUTH) || r->user) - { - return DECLINED; - } - - if (!sslconn->client_dn) { - X509_NAME *name = X509_get_subject_name(sslconn->client_cert); - char *cp = X509_NAME_oneline(name, NULL, 0); - sslconn->client_dn = apr_pstrdup(r->connection->pool, cp); - modssl_free(cp); - } - - clientdn = (char *)sslconn->client_dn; - - /* - * 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" ;-) - */ - auth_line = apr_pstrcat(r->pool, "Basic ", - ap_pbase64encode(r->pool, - apr_pstrcat(r->pool, clientdn, - ":password", NULL)), - NULL); - apr_table_set(r->headers_in, "Authorization", auth_line); - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, - "Faking HTTP Basic Auth header: \"Authorization: %s\"", - auth_line); - - return DECLINED; -} - -/* authorization phase */ -int ssl_hook_Auth(request_rec *r) -{ - SSLDirConfigRec *dc = myDirConfig(r); - - /* - * Additionally forbid access (again) - * when strict require option is used. - */ - if ((dc->nOptions & SSL_OPT_STRICTREQUIRE) && - (apr_table_get(r->notes, "ssl-access-forbidden"))) - { - return HTTP_FORBIDDEN; - } - - return DECLINED; -} - -/* - * Fixup Handler - */ - -static const char *ssl_hook_Fixup_vars[] = { - "SSL_VERSION_INTERFACE", - "SSL_VERSION_LIBRARY", - "SSL_PROTOCOL", - "SSL_SECURE_RENEG", - "SSL_CIPHER", - "SSL_CIPHER_EXPORT", - "SSL_CIPHER_USEKEYSIZE", - "SSL_CIPHER_ALGKEYSIZE", - "SSL_CLIENT_VERIFY", - "SSL_CLIENT_M_VERSION", - "SSL_CLIENT_M_SERIAL", - "SSL_CLIENT_V_START", - "SSL_CLIENT_V_END", - "SSL_CLIENT_S_DN", - "SSL_CLIENT_S_DN_C", - "SSL_CLIENT_S_DN_ST", - "SSL_CLIENT_S_DN_L", - "SSL_CLIENT_S_DN_O", - "SSL_CLIENT_S_DN_OU", - "SSL_CLIENT_S_DN_CN", - "SSL_CLIENT_S_DN_T", - "SSL_CLIENT_S_DN_I", - "SSL_CLIENT_S_DN_G", - "SSL_CLIENT_S_DN_S", - "SSL_CLIENT_S_DN_D", - "SSL_CLIENT_S_DN_UID", - "SSL_CLIENT_S_DN_Email", - "SSL_CLIENT_I_DN", - "SSL_CLIENT_I_DN_C", - "SSL_CLIENT_I_DN_ST", - "SSL_CLIENT_I_DN_L", - "SSL_CLIENT_I_DN_O", - "SSL_CLIENT_I_DN_OU", - "SSL_CLIENT_I_DN_CN", - "SSL_CLIENT_I_DN_T", - "SSL_CLIENT_I_DN_I", - "SSL_CLIENT_I_DN_G", - "SSL_CLIENT_I_DN_S", - "SSL_CLIENT_I_DN_D", - "SSL_CLIENT_I_DN_UID", - "SSL_CLIENT_I_DN_Email", - "SSL_CLIENT_A_KEY", - "SSL_CLIENT_A_SIG", - "SSL_SERVER_M_VERSION", - "SSL_SERVER_M_SERIAL", - "SSL_SERVER_V_START", - "SSL_SERVER_V_END", - "SSL_SERVER_S_DN", - "SSL_SERVER_S_DN_C", - "SSL_SERVER_S_DN_ST", - "SSL_SERVER_S_DN_L", - "SSL_SERVER_S_DN_O", - "SSL_SERVER_S_DN_OU", - "SSL_SERVER_S_DN_CN", - "SSL_SERVER_S_DN_T", - "SSL_SERVER_S_DN_I", - "SSL_SERVER_S_DN_G", - "SSL_SERVER_S_DN_S", - "SSL_SERVER_S_DN_D", - "SSL_SERVER_S_DN_UID", - "SSL_SERVER_S_DN_Email", - "SSL_SERVER_I_DN", - "SSL_SERVER_I_DN_C", - "SSL_SERVER_I_DN_ST", - "SSL_SERVER_I_DN_L", - "SSL_SERVER_I_DN_O", - "SSL_SERVER_I_DN_OU", - "SSL_SERVER_I_DN_CN", - "SSL_SERVER_I_DN_T", - "SSL_SERVER_I_DN_I", - "SSL_SERVER_I_DN_G", - "SSL_SERVER_I_DN_S", - "SSL_SERVER_I_DN_D", - "SSL_SERVER_I_DN_UID", - "SSL_SERVER_I_DN_Email", - "SSL_SERVER_A_KEY", - "SSL_SERVER_A_SIG", - "SSL_SESSION_ID", - NULL -}; - -int ssl_hook_Fixup(request_rec *r) -{ - SSLConnRec *sslconn = myConnConfig(r->connection); - SSLSrvConfigRec *sc = mySrvConfig(r->server); - SSLDirConfigRec *dc = myDirConfig(r); - apr_table_t *env = r->subprocess_env; - char *var, *val = ""; - STACK_OF(X509) *peer_certs; - SSL *ssl; - int i; - - /* - * Check to see if SSL is on - */ - if (!(sc->enabled && sslconn && (ssl = sslconn->ssl))) { - return DECLINED; - } - - /* - * Annotate the SSI/CGI environment with standard SSL information - */ - /* the always present HTTPS (=HTTP over SSL) flag! */ - apr_table_setn(env, "HTTPS", "on"); - - /* standard SSL environment variables */ - if (dc->nOptions & SSL_OPT_STDENVVARS) { - for (i = 0; ssl_hook_Fixup_vars[i]; i++) { - var = (char *)ssl_hook_Fixup_vars[i]; - val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); - if (!strIsEmpty(val)) { - apr_table_setn(env, var, val); - } - } - } - - /* - * On-demand bloat up the SSI/CGI environment with certificate data - */ - if (dc->nOptions & SSL_OPT_EXPORTCERTDATA) { - val = ssl_var_lookup(r->pool, r->server, r->connection, - r, "SSL_SERVER_CERT"); - - apr_table_setn(env, "SSL_SERVER_CERT", val); - - val = ssl_var_lookup(r->pool, r->server, r->connection, - r, "SSL_CLIENT_CERT"); - - apr_table_setn(env, "SSL_CLIENT_CERT", val); - - if ((peer_certs = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl))) { - for (i = 0; i < sk_X509_num(peer_certs); i++) { - var = apr_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i); - val = ssl_var_lookup(r->pool, r->server, r->connection, - r, var); - if (val) { - apr_table_setn(env, var, val); - } - } - } - } - - -#ifdef SSL_get_secure_renegotiation_support - apr_table_setn(r->notes, "ssl-secure-reneg", - SSL_get_secure_renegotiation_support(ssl) ? "1" : "0"); -#endif - - return DECLINED; -} - -/* _________________________________________________________________ -** -** 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 - * on the fly. - * - * So we generated 512 and 1024 bit temporary keys on startup - * which we now just hand out on demand.... - */ - -RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen) -{ - conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); - SSLModConfigRec *mc = myModConfig(c->base_server); - int idx; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, - "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? - */ - - switch (keylen) { - case 512: - idx = SSL_TMP_KEY_RSA_512; - break; - - case 1024: - default: - idx = SSL_TMP_KEY_RSA_1024; - } - - return (RSA *)mc->pTmpKeys[idx]; -} - -/* - * Hand out the already generated DH parameters... - */ -DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen) -{ - conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); - SSLModConfigRec *mc = myModConfig(c->base_server); - int idx; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, - "handing out temporary %d bit DH key", keylen); - - switch (keylen) { - case 512: - idx = SSL_TMP_KEY_DH_512; - break; - - case 1024: - default: - idx = SSL_TMP_KEY_DH_1024; - } - - return (DH *)mc->pTmpKeys[idx]; -} - -/* - * This OpenSSL callback function is called when OpenSSL - * does client authentication and verifies the certificate chain. - */ -int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx) -{ - /* Get Apache context back through OpenSSL context */ - SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl); - server_rec *s = conn->base_server; - request_rec *r = (request_rec *)SSL_get_app_data2(ssl); - - SSLSrvConfigRec *sc = mySrvConfig(s); - SSLDirConfigRec *dc = r ? myDirConfig(r) : NULL; - SSLConnRec *sslconn = myConnConfig(conn); - modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); - - /* Get verify ingredients */ - int errnum = X509_STORE_CTX_get_error(ctx); - int errdepth = X509_STORE_CTX_get_error_depth(ctx); - int depth, verify; - - /* - * Log verification information - */ - if (s->loglevel >= APLOG_DEBUG) { - X509 *cert = X509_STORE_CTX_get_current_cert(ctx); - char *sname = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - char *iname = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Certificate Verification: " - "depth: %d, subject: %s, issuer: %s", - errdepth, - sname ? sname : "-unknown-", - iname ? iname : "-unknown-"); - - if (sname) { - modssl_free(sname); - } - - if (iname) { - modssl_free(iname); - } - } - - /* - * Check for optionally acceptable non-verifiable issuer situation - */ - if (dc && (dc->nVerifyClient != SSL_CVERIFY_UNSET)) { - verify = dc->nVerifyClient; - } - else { - verify = mctx->auth.verify_mode; - } - - if (verify == SSL_CVERIFY_NONE) { - /* - * 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") - */ - return TRUE; - } - - if (ssl_verify_error_is_optional(errnum) && - (verify == SSL_CVERIFY_OPTIONAL_NO_CA)) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Certificate Verification: Verifiable Issuer is " - "configured as optional, therefore we're accepting " - "the certificate"); - - sslconn->verify_info = "GENEROUS"; - ok = TRUE; - } - - /* - * Additionally perform CRL-based revocation checks - */ - if (ok) { - if (!(ok = ssl_callback_SSLVerify_CRL(ok, ctx, conn))) { - errnum = X509_STORE_CTX_get_error(ctx); - } - } - - /* - * If we already know it's not ok, log the real reason - */ - if (!ok) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Certificate Verification: Error (%d): %s", - errnum, X509_verify_cert_error_string(errnum)); - - if (sslconn->client_cert) { - X509_free(sslconn->client_cert); - sslconn->client_cert = NULL; - } - sslconn->client_dn = NULL; - sslconn->verify_error = X509_verify_cert_error_string(errnum); - } - - /* - * Finally check the depth of the certificate verification - */ - if (dc && (dc->nVerifyDepth != UNSET)) { - depth = dc->nVerifyDepth; - } - else { - depth = mctx->auth.verify_depth; - } - - if (errdepth > depth) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Certificate Verification: Certificate Chain too long " - "(chain has %d certificates, but maximum allowed are " - "only %d)", - errdepth, depth); - - errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG; - sslconn->verify_error = X509_verify_cert_error_string(errnum); - - ok = FALSE; - } - - /* - * And finally signal OpenSSL the (perhaps changed) state - */ - return ok; -} - -int ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, conn_rec *c) -{ - server_rec *s = c->base_server; - SSLSrvConfigRec *sc = mySrvConfig(s); - SSLConnRec *sslconn = myConnConfig(c); - modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); - X509_OBJECT obj; - X509_NAME *subject, *issuer; - X509 *cert; - X509_CRL *crl; - EVP_PKEY *pubkey; - int i, n, rc; - - /* - * Unless a revocation store for CRLs was created we - * cannot do any CRL-based verification, of course. - */ - if (!mctx->crl) { - return ok; - } - - /* - * Determine certificate ingredients in advance - */ - cert = X509_STORE_CTX_get_current_cert(ctx); - subject = X509_get_subject_name(cert); - issuer = X509_get_issuer_name(cert); - - /* - * 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 - * project): - * - * 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 - * well, of course. - */ - - /* - * Try to retrieve a CRL corresponding to the _subject_ of - * the current certificate in order to verify it's integrity. - */ - memset((char *)&obj, 0, sizeof(obj)); - rc = SSL_X509_STORE_lookup(mctx->crl, - X509_LU_CRL, subject, &obj); - crl = obj.data.crl; - - if ((rc > 0) && crl) { - /* - * Log information about CRL - * (A little bit complicated because of ASN.1 and BIOs...) - */ - if (s->loglevel >= APLOG_DEBUG) { - char buff[512]; /* should be plenty */ - BIO *bio = BIO_new(BIO_s_mem()); - - BIO_printf(bio, "CA CRL: Issuer: "); - X509_NAME_print(bio, issuer, 0); - - BIO_printf(bio, ", lastUpdate: "); - ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl)); - - BIO_printf(bio, ", nextUpdate: "); - ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl)); - - n = BIO_read(bio, buff, sizeof(buff) - 1); - buff[n] = '\0'; - - BIO_free(bio); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, buff); - } - - /* - * Verify the signature on this CRL - */ - pubkey = X509_get_pubkey(cert); - rc = X509_CRL_verify(crl, pubkey); -#ifdef OPENSSL_VERSION_NUMBER - /* Only refcounted in OpenSSL */ - if (pubkey) - EVP_PKEY_free(pubkey); -#endif - if (rc <= 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "Invalid signature on CRL"); - - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); - X509_OBJECT_free_contents(&obj); - return FALSE; - } - - /* - * Check date of CRL to make sure it's not expired - */ - i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); - - if (i == 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "Found CRL has invalid nextUpdate field"); - - X509_STORE_CTX_set_error(ctx, - X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); - X509_OBJECT_free_contents(&obj); - - return FALSE; - } - - if (i < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "Found CRL is expired - " - "revoking all certificates until you get updated CRL"); - - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); - X509_OBJECT_free_contents(&obj); - - return FALSE; - } - - X509_OBJECT_free_contents(&obj); - } - - /* - * Try to retrieve a CRL corresponding to the _issuer_ of - * the current certificate in order to check for revocation. - */ - memset((char *)&obj, 0, sizeof(obj)); - rc = SSL_X509_STORE_lookup(mctx->crl, - X509_LU_CRL, issuer, &obj); - - crl = obj.data.crl; - if ((rc > 0) && crl) { - /* - * Check if the current certificate is revoked by this CRL - */ - n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); - - for (i = 0; i < n; i++) { - X509_REVOKED *revoked = - sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); - - ASN1_INTEGER *sn = X509_REVOKED_get_serialNumber(revoked); - - if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) { - if (s->loglevel >= APLOG_DEBUG) { - char *cp = X509_NAME_oneline(issuer, NULL, 0); - long serial = ASN1_INTEGER_get(sn); - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Certificate with serial %ld (0x%lX) " - "revoked per CRL from issuer %s", - serial, serial, cp); - modssl_free(cp); - } - - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); - X509_OBJECT_free_contents(&obj); - - return FALSE; - } - } - - X509_OBJECT_free_contents(&obj); - } - - return ok; -} - -#define SSLPROXY_CERT_CB_LOG_FMT \ - "Proxy client certificate callback: (%s) " - -static void modssl_proxy_info_log(server_rec *s, - X509_INFO *info, - const char *msg) -{ - SSLSrvConfigRec *sc = mySrvConfig(s); - char name_buf[256]; - X509_NAME *name; - char *dn; - - if (s->loglevel < APLOG_DEBUG) { - return; - } - - name = X509_get_subject_name(info->x509); - dn = X509_NAME_oneline(name, name_buf, sizeof(name_buf)); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - SSLPROXY_CERT_CB_LOG_FMT "%s, sending %s", - sc->vhost_id, msg, dn ? dn : "-uknown-"); -} - -/* - * caller will decrement the cert and key reference - * so we need to increment here to prevent them from - * being freed. - */ -#define modssl_set_cert_info(info, cert, pkey) \ - *cert = info->x509; \ - X509_reference_inc(*cert); \ - *pkey = info->x_pkey->dec_pkey; \ - EVP_PKEY_reference_inc(*pkey) - -int ssl_callback_proxy_cert(SSL *ssl, MODSSL_CLIENT_CERT_CB_ARG_TYPE **x509, EVP_PKEY **pkey) -{ - conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); - server_rec *s = c->base_server; - SSLSrvConfigRec *sc = mySrvConfig(s); - X509_NAME *ca_name, *issuer; - X509_INFO *info; - STACK_OF(X509_NAME) *ca_list; - STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs; - int i, j; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - SSLPROXY_CERT_CB_LOG_FMT "entered", - sc->vhost_id); - - if (!certs || (sk_X509_INFO_num(certs) <= 0)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - SSLPROXY_CERT_CB_LOG_FMT - "downstream server wanted client certificate " - "but none are configured", sc->vhost_id); - return FALSE; - } - - ca_list = SSL_get_client_CA_list(ssl); - - if (!ca_list || (sk_X509_NAME_num(ca_list) <= 0)) { - /* - * downstream server didn't send us a list of acceptable CA certs, - * so we send the first client cert in the list. - */ - info = sk_X509_INFO_value(certs, 0); - - modssl_proxy_info_log(s, info, "no acceptable CA list"); - - modssl_set_cert_info(info, x509, pkey); - - return TRUE; - } - - for (i = 0; i < sk_X509_NAME_num(ca_list); i++) { - ca_name = sk_X509_NAME_value(ca_list, i); - - for (j = 0; j < sk_X509_INFO_num(certs); j++) { - info = sk_X509_INFO_value(certs, j); - issuer = X509_get_issuer_name(info->x509); - - if (X509_NAME_cmp(issuer, ca_name) == 0) { - modssl_proxy_info_log(s, info, "found acceptable cert"); - - modssl_set_cert_info(info, x509, pkey); - - return TRUE; - } - } - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - SSLPROXY_CERT_CB_LOG_FMT - "no client certificate found!?", sc->vhost_id); - - return FALSE; -} - -static void ssl_session_log(server_rec *s, - const char *request, - unsigned char *id, - unsigned int idlen, - const char *status, - const char *result, - long timeout) -{ - char buf[SSL_SESSION_ID_STRING_LEN]; - char timeout_str[56] = {'\0'}; - - if (s->loglevel < APLOG_DEBUG) { - return; - } - - if (timeout) { - apr_snprintf(timeout_str, sizeof(timeout_str), - "timeout=%lds ", (timeout - time(NULL))); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Inter-Process Session Cache: " - "request=%s status=%s id=%s %s(session %s)", - request, status, - SSL_SESSION_id2sz(id, idlen, buf, sizeof(buf)), - timeout_str, result); -} - -/* - * 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. - */ -int ssl_callback_NewSessionCacheEntry(SSL *ssl, SSL_SESSION *session) -{ - /* Get Apache context back through OpenSSL context */ - conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl); - server_rec *s = conn->base_server; - SSLSrvConfigRec *sc = mySrvConfig(s); - long timeout = sc->session_cache_timeout; - BOOL rc; - unsigned char *id; - unsigned int idlen; - - /* - * Set the timeout also for the internal OpenSSL cache, because this way - * our inter-process cache is consulted only when it's really necessary. - */ - SSL_set_timeout(session, timeout); - - /* - * Store the SSL_SESSION in the inter-process cache with the - * same expire time, so it expires automatically there, too. - */ - id = SSL_SESSION_get_session_id(session); - idlen = SSL_SESSION_get_session_id_length(session); - - timeout += modssl_session_get_time(session); - - rc = ssl_scache_store(s, id, idlen, timeout, session); - - ssl_session_log(s, "SET", id, idlen, - rc == TRUE ? "OK" : "BAD", - "caching", timeout); - - /* - * return 0 which means to OpenSSL that the session is still - * valid and was not freed by us with SSL_SESSION_free(). - */ - return 0; -} - -/* - * 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. - */ -SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *ssl, - unsigned char *id, - int idlen, int *do_copy) -{ - /* Get Apache context back through OpenSSL context */ - conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl); - server_rec *s = conn->base_server; - SSL_SESSION *session; - - /* - * Try to retrieve the SSL_SESSION from the inter-process cache - */ - session = ssl_scache_retrieve(s, id, idlen); - - ssl_session_log(s, "GET", id, idlen, - session ? "FOUND" : "MISSED", - session ? "reuse" : "renewal", 0); - - /* - * 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. - */ - *do_copy = 0; - - return session; -} - -/* - * 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 - * disk-cache, too. - */ -void ssl_callback_DelSessionCacheEntry(SSL_CTX *ctx, - SSL_SESSION *session) -{ - server_rec *s; - SSLSrvConfigRec *sc; - unsigned char *id; - unsigned int idlen; - - /* - * Get Apache context back through OpenSSL context - */ - if (!(s = (server_rec *)SSL_CTX_get_app_data(ctx))) { - return; /* on server shutdown Apache is already gone */ - } - - sc = mySrvConfig(s); - - /* - * Remove the SSL_SESSION from the inter-process cache - */ - id = SSL_SESSION_get_session_id(session); - idlen = SSL_SESSION_get_session_id_length(session); - - ssl_scache_remove(s, id, idlen); - - ssl_session_log(s, "REM", id, idlen, - "OK", "dead", 0); - - return; -} - -/* Dump debugginfo trace to the log file. */ -static void log_tracing_state(MODSSL_INFO_CB_ARG_TYPE ssl, conn_rec *c, - server_rec *s, int where, int rc) -{ - /* - * create the various trace messages - */ - if (where & SSL_CB_HANDSHAKE_START) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Handshake: start", SSL_LIBRARY_NAME); - } - else if (where & SSL_CB_HANDSHAKE_DONE) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Handshake: done", SSL_LIBRARY_NAME); - } - else if (where & SSL_CB_LOOP) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Loop: %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - } - else if (where & SSL_CB_READ) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Read: %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - } - else if (where & SSL_CB_WRITE) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Write: %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - } - else if (where & SSL_CB_ALERT) { - char *str = (where & SSL_CB_READ) ? "read" : "write"; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Alert: %s:%s:%s", - SSL_LIBRARY_NAME, str, - SSL_alert_type_string_long(rc), - SSL_alert_desc_string_long(rc)); - } - else if (where & SSL_CB_EXIT) { - if (rc == 0) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Exit: failed in %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - } - else if (rc < 0) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: Exit: error in %s", - SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); - } - } - - /* - * 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. - */ - if (where & SSL_CB_HANDSHAKE_DONE) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Connection: Client IP: %s, Protocol: %s, " - "Cipher: %s (%s/%s bits)", - ssl_var_lookup(NULL, s, c, NULL, "REMOTE_ADDR"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_PROTOCOL"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_USEKEYSIZE"), - ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_ALGKEYSIZE")); - } -} - -/* - * This callback function is executed while OpenSSL processes the SSL - * handshake and does SSL record layer stuff. It's used to trap - * client-initiated renegotiations, and for dumping everything to the - * log. - */ -void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc) -{ - conn_rec *c; - server_rec *s; - SSLConnRec *scr; - - /* Retrieve the conn_rec and the associated SSLConnRec. */ - if ((c = (conn_rec *)SSL_get_app_data((SSL *)ssl)) == NULL) { - return; - } - - if ((scr = myConnConfig(c)) == NULL) { - return; - } - - /* If the reneg state is to reject renegotiations, check the SSL - * state machine and move to ABORT if a Client Hello is being - * read. */ - if ((where & SSL_CB_ACCEPT_LOOP) && scr->reneg_state == RENEG_REJECT) { - int state = SSL_get_state((SSL *)ssl); - - if (state == SSL3_ST_SR_CLNT_HELLO_A - || state == SSL23_ST_SR_CLNT_HELLO_A) { - scr->reneg_state = RENEG_ABORT; - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, - "rejecting client initiated renegotiation"); - } - } - /* If the first handshake is complete, change state to reject any - * subsequent client-initated renegotiation. */ - else if ((where & SSL_CB_HANDSHAKE_DONE) && scr->reneg_state == RENEG_INIT) { - scr->reneg_state = RENEG_REJECT; - } - - s = c->base_server; - if (s && s->loglevel >= APLOG_DEBUG) { - log_tracing_state(ssl, c, s, where, rc); - } -} |