From eacb2fcb81dbb0aca7beab848a3205c216144760 Mon Sep 17 00:00:00 2001 From: KLuka Date: Thu, 6 Aug 2015 17:57:12 +0200 Subject: [PATCH] Disable secure client-initiated renegotiation * In case that this SSL feature is abused it is possible to overload the server. Other web servers disable this feature by default, but users are able to change it with configuration. This is not possible with shellinabox as this feature is not needed. * Solution was implemented similary as in Lighttpd web server. --- libhttp/httpconnection.c | 11 ++++++++++- libhttp/ssl.c | 17 ++++++++++++++++- libhttp/ssl.h | 6 +++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/libhttp/httpconnection.c b/libhttp/httpconnection.c index 12ea365..67cc644 100644 --- a/libhttp/httpconnection.c +++ b/libhttp/httpconnection.c @@ -88,7 +88,7 @@ static int httpPromoteToSSL(struct HttpConnection *http, const char *buf, int len) { if (http->ssl->enabled && !http->sslHndl) { - debug("Switching to SSL (replaying %d+%d bytes)", + debug("SSL: switching to SSL (replaying %d+%d bytes)", http->partialLength, len); if (http->partial && len > 0) { check(http->partial = realloc(http->partial, @@ -102,6 +102,8 @@ static int httpPromoteToSSL(struct HttpConnection *http, const char *buf, http->partial ? http->partialLength : len); if (http->sslHndl) { check(!rc); + // Reset renegotiations count for connections promoted to SSL. + http->ssl->renegotiationCount = 0; SSL_set_app_data(http->sslHndl, http); } free(http->partial); @@ -138,6 +140,13 @@ static ssize_t httpRead(struct HttpConnection *http, char *buf, ssize_t len) { break; } dcheck(!ERR_peek_error()); + + // Shutdown SSL connection, if client initiated renegotiation. + if (http->ssl->renegotiationCount > 1) { + debug("SSL: connection shutdown due to client initiated renegotiation!"); + rc = 0; + errno = EINVAL; + } } else { rc = NOINTR(read(http->fd, buf, len)); } diff --git a/libhttp/ssl.c b/libhttp/ssl.c index 28229cf..2564584 100644 --- a/libhttp/ssl.c +++ b/libhttp/ssl.c @@ -113,7 +113,9 @@ int (*SSL_CTX_check_private_key)(const SSL_CTX *); long (*SSL_CTX_ctrl)(SSL_CTX *, int, long, void *); void (*SSL_CTX_free)(SSL_CTX *); SSL_CTX * (*SSL_CTX_new)(SSL_METHOD *); -int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); +int (*SSL_CTX_set_cipher_list)(SSL_CTX *, const char *); +void (*SSL_CTX_set_info_callback)(SSL_CTX *, + void (*)(const SSL *, int, int)); int (*SSL_CTX_use_PrivateKey_file)(SSL_CTX *, const char *, int); int (*SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *, const unsigned char *, long); @@ -168,6 +170,7 @@ void initSSL(struct SSLSupport *ssl) { ssl->sslContext = NULL; ssl->sniCertificatePattern = NULL; ssl->generateMissing = 0; + ssl->renegotiationCount = 0; initTrie(&ssl->sniContexts, sslDestroyCachedContext, ssl); } @@ -292,6 +295,7 @@ static void loadSSL(void) { { { &SSL_CTX_free }, "SSL_CTX_free" }, { { &SSL_CTX_new }, "SSL_CTX_new" }, { { &SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" }, + { { &SSL_CTX_set_info_callback }, "SSL_CTX_set_info_callback" }, { { &SSL_CTX_use_PrivateKey_file }, "SSL_CTX_use_PrivateKey_file" }, { { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" }, { { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"}, @@ -602,6 +606,15 @@ static int sslSetCertificateFromFile(SSL_CTX *context, return rc; } +static void sslInfoCallback(const SSL *sslHndl, int type, int val) { + // Count the number of renegotiations for each SSL session. + if (type & SSL_CB_HANDSHAKE_START) { + struct HttpConnection *http = + (struct HttpConnection *) SSL_get_app_data(sslHndl); + http->ssl->renegotiationCount += 1; + } +} + static SSL_CTX *sslMakeContext(void) { SSL_CTX *context; @@ -657,6 +670,8 @@ static SSL_CTX *sslMakeContext(void) { "ECDHE-RSA-DES-CBC3-SHA:" "HIGH:MEDIUM:!RC4:!aNULL:!MD5")); + SSL_CTX_set_info_callback(context, sslInfoCallback); + debug("SSL: server context succesfully initialized..."); return context; } diff --git a/libhttp/ssl.h b/libhttp/ssl.h index cd93aae..0be3830 100644 --- a/libhttp/ssl.h +++ b/libhttp/ssl.h @@ -95,7 +95,9 @@ extern int (*x_SSL_CTX_check_private_key)(const SSL_CTX *); extern long (*x_SSL_CTX_ctrl)(SSL_CTX *, int, long, void *); extern void (*x_SSL_CTX_free)(SSL_CTX *); extern SSL_CTX*(*x_SSL_CTX_new)(SSL_METHOD *); -extern int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); +extern int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *, const char *); +extern void (*x_SSL_CTX_set_info_callback)(SSL_CTX *, + void (*)(const SSL *, int, int)); extern int (*x_SSL_CTX_use_PrivateKey_file)(SSL_CTX *, const char *, int); extern int (*x_SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *, const unsigned char *, long); @@ -141,6 +143,7 @@ extern void *(*x_SSL_COMP_get_compression_methods)(void); #define SSL_CTX_free x_SSL_CTX_free #define SSL_CTX_new x_SSL_CTX_new #define SSL_CTX_set_cipher_list x_SSL_CTX_set_cipher_list +#define SSL_CTX_set_info_callback x_SSL_CTX_set_info_callback #define SSL_CTX_use_PrivateKey_file x_SSL_CTX_use_PrivateKey_file #define SSL_CTX_use_PrivateKey_ASN1 x_SSL_CTX_use_PrivateKey_ASN1 #define SSL_CTX_use_certificate_file x_SSL_CTX_use_certificate_file @@ -198,6 +201,7 @@ struct SSLSupport { SSL_CTX *sslContext; char *sniCertificatePattern; int generateMissing; + int renegotiationCount; struct Trie sniContexts; };