apache2-mod_nss/mod_nss-CVE-2013-4566-NSSVerifyClient.diff
Wolfgang Rosenauer 1d3e419a19 Accepting request 222758 from home:draht:branches:mozilla:Factory
- mod_nss-cipherlist_update_for_tls12-doc.diff
  mod_nss-cipherlist_update_for_tls12.diff
  GCM mode and Camellia ciphers added to the supported ciphers list.
  The additional ciphers are: 
  rsa_aes_128_gcm_sha == TLS_RSA_WITH_AES_128_GCM_SHA256
  rsa_camellia_128_sha == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
  rsa_camellia_256_sha == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
  ecdh_ecdsa_aes_128_gcm_sha == TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
  ecdhe_ecdsa_aes_128_gcm_sha == TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  ecdh_rsa_aes_128_gcm_sha == TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
  ecdhe_rsa_aes_128_gcm_sha == TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  [bnc#863035]

- mod_nss-CVE-2013-4566-NSSVerifyClient.diff fixes CVE-2013-4566:
  If 'NSSVerifyClient none' is set in the server / vhost context
  (i.e. when server is configured to not request or require client
  certificate authentication on the initial connection), and client
  certificate authentication is expected to be required for a 
  specific directory via 'NSSVerifyClient require' setting, 
  mod_nss fails to properly require certificate authentication.
  Remote attacker can use this to access content of the restricted
  directories. [bnc#853039]

- glue documentation added to /etc/apache2/conf.d/mod_nss.conf:
  * simultaneaous usage of mod_ssl and mod_nss
  * SNI concurrency
  * SUSE framework for apache configuration, Listen directive
  * module initialization
- mod_nss-conf.patch obsoleted by scratch-version of nss.conf.in
  or mod_nss.conf, respectively. This also leads to the removal of

OBS-URL: https://build.opensuse.org/request/show/222758
OBS-URL: https://build.opensuse.org/package/show/mozilla:Factory/apache2-mod_nss?expand=0&rev=8
2014-02-20 21:12:44 +00:00

320 lines
13 KiB
Diff

This is CVE-2013-4566:
The flaw is in the NSSVerifyClient (which is equivalent to mod_ssl's
SSLVerifyClient) setting enforcement. If 'NSSVerifyClient none' is set
in the server / vhost context (i.e. when server is configured to not
request or require client certificate authentication on the initial
connection), and client certificate authentication is expected to be
required for a specific directory via 'NSSVerifyClient require'
setting, mod_nss fails to properly require certificate authentication.
Remote attacker can use this to access content of the restricted
directories.
Reported by Thomas Hoger <thoger@redhat.com>.
diff -rNU 150 ../mod_nss-1.0.8-o/nss_engine_kernel.c ./nss_engine_kernel.c
--- ../mod_nss-1.0.8-o/nss_engine_kernel.c 2013-11-29 16:09:37.000000000 +0100
+++ ./nss_engine_kernel.c 2013-11-29 16:12:20.000000000 +0100
@@ -133,301 +133,301 @@
/*
* Check to see if SSL protocol is enabled. If it's not then
* no further access control checks are relevant. The test for
* sc->enabled is probably strictly unnecessary
*/
if (!((sc->enabled == TRUE) || !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 NSSCipherSuite
*
* 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 ``NSSOptions +OptRenegotiate''. So we do no
* implicit optimizations.
*/
if (dc->szCipherSuite) {
/* remember old state */
for (i=0; i < ciphernum; i++) {
SSL_CipherPrefGet(ssl, ciphers_def[i].num, &ciphers_old[i]);
}
if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) {
int on, keySize, secretKeySize;
char *issuer, *subject;
SSL_SecurityStatus(ssl, &on, &cipher,
&keySize, &secretKeySize, &issuer,
&subject);
}
/* configure new state */
ciphers = strdup(dc->szCipherSuite);
if (nss_parse_ciphers(r->server, ciphers, ciphers_new) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
r->server,
"Unable to reconfigure (per-directory) "
"permitted SSL ciphers");
nss_log_nss_error(APLOG_MARK, APLOG_ERR, r->server);
free(ciphers);
return HTTP_FORBIDDEN;
}
free(ciphers);
/* Actually enable the selected ciphers. Also check to
see if the existing cipher is in the new list for
a possible optimization later. */
for (i=0; i<ciphernum;i++) {
if (cipher && !strcasecmp(cipher, ciphers_def[i].name)) {
if (ciphers_new[i] == PR_TRUE)
cipher_in_list = PR_TRUE;
}
SSL_CipherPrefSet(ssl, ciphers_def[i].num, ciphers_new[i]);
}
/* determine whether a renegotiation has to be forced */
if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) {
if (cipher_in_list != PR_TRUE)
renegotiate = TRUE;
}
else {
/* paranoid way */
for (i=0; i<ciphernum;i++) {
if (ciphers_new[i] != ciphers_old[i]) {
renegotiate = TRUE;
break;
}
}
}
/* tracing */
if (renegotiate) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Reconfigured cipher suite 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) {
PRInt32 on;
/* remember old state */
SSL_OptionGet(ssl, SSL_REQUIRE_CERTIFICATE, &on);
if (on == PR_TRUE) {
verify_old = SSL_CVERIFY_REQUIRE;
} else {
SSL_OptionGet(ssl, SSL_REQUEST_CERTIFICATE, &on);
if (on == PR_TRUE)
verify_old = SSL_CVERIFY_OPTIONAL;
else
verify_old = SSL_CVERIFY_NONE;
}
/* configure new state */
verify = dc->nVerifyClient;
if (verify == SSL_CVERIFY_REQUIRE) {
SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_TRUE);
- SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NO_ERROR);
+ SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
} else if (verify == SSL_CVERIFY_OPTIONAL) {
SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_TRUE);
SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
} else {
SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_FALSE);
SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
}
/* determine whether we've to force a renegotiation */
if (!renegotiate && verify != verify_old) {
if (((verify_old == SSL_CVERIFY_NONE) &&
(verify != SSL_CVERIFY_NONE)) ||
(!(verify_old & SSL_CVERIFY_OPTIONAL) &&
(verify & SSL_CVERIFY_OPTIONAL)) ||
(!(verify_old & SSL_CVERIFY_REQUIRE) &&
(verify & SSL_CVERIFY_REQUIRE)))
{
renegotiate = TRUE;
/* optimization */
if ((dc->nOptions & SSL_OPT_OPTRENEGOTIATE) &&
(verify_old == SSL_CVERIFY_NONE) &&
((peercert = SSL_PeerCertificate(ssl)) != NULL))
{
renegotiate_quick = TRUE;
CERT_DestroyCertificate(peercert);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
r->server,
"Changed client verification type will force "
"%srenegotiation",
renegotiate_quick ? "quick " : "");
}
}
}
/* 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 = nss_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) {
SECStatus rv;
CERTCertificate *peerCert;
void *pinArg;
/* 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");
peerCert = SSL_PeerCertificate(sslconn->ssl);
pinArg = SSL_RevealPinArg(sslconn->ssl);
rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(),
peerCert,
PR_TRUE,
certUsageSSLClient,
pinArg);
CERT_DestroyCertificate(peerCert);
if (rv != SECSuccess) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"Re-negotiation handshake failed: "
"Client verification failed");
return HTTP_FORBIDDEN;
}
/* The cert is ok, fall through to the check SSLRequires */
}
else {
int handshake_done = 0;
int result = 0;
/* do a full renegotiation */
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Performing full renegotiation: "
"complete handshake protocol");
/* Do NOT call SSL_ResetHandshake as this will tear down the
* existing connection.
*/
if (SSL_HandshakeCallback(ssl, HandshakeDone, (void *)&handshake_done) || SSL_ReHandshake(ssl, PR_TRUE)) {
int errCode = PR_GetError();
if (errCode == SEC_ERROR_INVALID_ARGS) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Re-negotation request failed: "
"trying to do client authentication on a non-SSL3 connection");
} else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Re-negotation request failed: "
"returned error %d", errCode);
}
r->connection->aborted = 1;
return HTTP_FORBIDDEN;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Awaiting re-negotiation handshake");