📄 ssl_engine_kernel.c
字号:
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; /* do a full renegotiation */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Performing full renegotiation: " "complete handshake protocol"); SSL_set_session_id_context(ssl, (unsigned char *)&id, sizeof(id)); 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"); r->connection->aborted = 1; return HTTP_FORBIDDEN; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Awaiting re-negotiation handshake"); /* XXX: Should replace SSL_set_state with SSL_renegotiate(ssl); * However, this causes failures in perl-framework currently, * perhaps pre-test if we have already negotiated? */ SSL_set_state(ssl, SSL_ST_ACCEPT); SSL_do_handshake(ssl); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -