tests/stub_ETag.cc \
EventLoop.cc \
event.cc \
+ FadingCounter.cc \
fatal.h \
tests/stub_fatal.cc \
fd.h \
store_rebuild.h \
tests/stub_store_rebuild.cc \
tests/stub_store_stats.cc \
+ FadingCounter.cc \
fatal.h \
tests/stub_fatal.cc \
fd.h \
ETag.cc \
EventLoop.cc \
event.cc \
+ FadingCounter.cc \
fatal.h \
fatal.cc \
fd.h \
rbuf.init(4096, 65536);
}
+Ssl::ClientBio::ClientBio(const int anFd):
+ Bio(anFd),
+ holdRead_(false),
+ holdWrite_(false),
+ helloState(atHelloNone),
+ abortReason(nullptr)
+{
+ renegotiations.configure(10*1000);
+}
+
bool
Ssl::ClientBio::isClientHello(int state)
{
Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret)
{
Ssl::Bio::stateChanged(ssl, where, ret);
+ // detect client-initiated renegotiations DoS (CVE-2011-1473)
+ if (where & SSL_CB_HANDSHAKE_START) {
+ const int reneg = renegotiations.count(1);
+
+ if (abortReason)
+ return; // already decided and informed the admin
+
+ if (reneg > RenegotiationsLimit) {
+ abortReason = "renegotiate requests flood";
+ debugs(83, DBG_IMPORTANT, "Terminating TLS connection [from " << fd_table[fd_].ipaddr << "] due to " << abortReason << ". This connection received " <<
+ reneg << " renegotiate requests in the last " <<
+ RenegotiationsWindow << " seconds (and " <<
+ renegotiations.remembered() << " requests total).");
+ }
+ }
}
int
Ssl::ClientBio::write(const char *buf, int size, BIO *table)
{
+ if (abortReason) {
+ debugs(83, 3, "BIO on FD " << fd_ << " is aborted");
+ BIO_clear_retry_flags(table);
+ return -1;
+ }
+
if (holdWrite_) {
BIO_set_retry_write(table);
return 0;
int
Ssl::ClientBio::read(char *buf, int size, BIO *table)
{
+ if (abortReason) {
+ debugs(83, 3, "BIO on FD " << fd_ << " is aborted");
+ BIO_clear_retry_flags(table);
+ return -1;
+ }
+
if (helloState < atHelloReceived) {
int bytes = readAndBuffer(buf, size, table, "TLS client Hello");
if (bytes <= 0)
#ifndef SQUID_SSL_BIO_H
#define SQUID_SSL_BIO_H
+#include "FadingCounter.h"
#include "fd.h"
#include "SBuf.h"
public:
/// The ssl hello message read states
typedef enum {atHelloNone = 0, atHelloStarted, atHelloReceived} HelloReadState;
- explicit ClientBio(const int anFd): Bio(anFd), holdRead_(false), holdWrite_(false), helloState(atHelloNone) {}
+ explicit ClientBio(const int anFd);
/// The ClientBio version of the Ssl::Bio::stateChanged method
/// When the client hello message retrieved, fill the
private:
/// True if the SSL state corresponds to a hello message
bool isClientHello(int state);
+
+ /// approximate size of a time window for computing client-initiated renegotiation rate (in seconds)
+ static const time_t RenegotiationsWindow = 10;
+
+ /// the maximum tolerated number of client-initiated renegotiations in RenegotiationsWindow
+ static const int RenegotiationsLimit = 5;
+
/// The futures retrieved from client SSL hello message
Bio::sslFeatures features;
bool holdRead_; ///< The read hold state of the bio.
bool holdWrite_; ///< The write hold state of the bio.
HelloReadState helloState; ///< The SSL hello read state
+ FadingCounter renegotiations; ///< client requested renegotiations limit control
+
+ /// why we should terminate the connection during next TLS operation (or nil)
+ const char *abortReason;
};
/// BIO node to handle socket IO for squid server side
return dh;
}
-#if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
-static void
-ssl_info_cb(const SSL *ssl, int where, int ret)
-{
- (void)ret;
- if ((where & SSL_CB_HANDSHAKE_DONE) != 0) {
- // disable renegotiation (CVE-2009-3555)
- ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
- }
-}
-#endif
-
static bool
configureSslEECDH(SSL_CTX *sslContext, const char *curve)
{
int ssl_error;
SSL_CTX_set_options(sslContext, port.sslOptions);
-#if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
- SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
-#endif
-
if (port.sslContextSessionId)
SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)port.sslContextSessionId, strlen(port.sslContextSessionId));
SSL_CTX_set_options(sslContext, Ssl::parse_options(options));
-#if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
- SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
-#endif
-
if (cipher) {
debugs(83, 5, "Using chiper suite " << cipher << ".");