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.
This commit is contained in:
KLuka 2015-08-06 17:57:12 +02:00
parent f0437832d3
commit eacb2fcb81
3 changed files with 31 additions and 3 deletions

View file

@ -88,7 +88,7 @@
static int httpPromoteToSSL(struct HttpConnection *http, const char *buf, static int httpPromoteToSSL(struct HttpConnection *http, const char *buf,
int len) { int len) {
if (http->ssl->enabled && !http->sslHndl) { 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); http->partialLength, len);
if (http->partial && len > 0) { if (http->partial && len > 0) {
check(http->partial = realloc(http->partial, check(http->partial = realloc(http->partial,
@ -102,6 +102,8 @@ static int httpPromoteToSSL(struct HttpConnection *http, const char *buf,
http->partial ? http->partialLength : len); http->partial ? http->partialLength : len);
if (http->sslHndl) { if (http->sslHndl) {
check(!rc); check(!rc);
// Reset renegotiations count for connections promoted to SSL.
http->ssl->renegotiationCount = 0;
SSL_set_app_data(http->sslHndl, http); SSL_set_app_data(http->sslHndl, http);
} }
free(http->partial); free(http->partial);
@ -138,6 +140,13 @@ static ssize_t httpRead(struct HttpConnection *http, char *buf, ssize_t len) {
break; break;
} }
dcheck(!ERR_peek_error()); 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 { } else {
rc = NOINTR(read(http->fd, buf, len)); rc = NOINTR(read(http->fd, buf, len));
} }

View file

@ -113,7 +113,9 @@ int (*SSL_CTX_check_private_key)(const SSL_CTX *);
long (*SSL_CTX_ctrl)(SSL_CTX *, int, long, void *); long (*SSL_CTX_ctrl)(SSL_CTX *, int, long, void *);
void (*SSL_CTX_free)(SSL_CTX *); void (*SSL_CTX_free)(SSL_CTX *);
SSL_CTX * (*SSL_CTX_new)(SSL_METHOD *); 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_file)(SSL_CTX *, const char *, int);
int (*SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *, int (*SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *,
const unsigned char *, long); const unsigned char *, long);
@ -168,6 +170,7 @@ void initSSL(struct SSLSupport *ssl) {
ssl->sslContext = NULL; ssl->sslContext = NULL;
ssl->sniCertificatePattern = NULL; ssl->sniCertificatePattern = NULL;
ssl->generateMissing = 0; ssl->generateMissing = 0;
ssl->renegotiationCount = 0;
initTrie(&ssl->sniContexts, sslDestroyCachedContext, ssl); initTrie(&ssl->sniContexts, sslDestroyCachedContext, ssl);
} }
@ -292,6 +295,7 @@ static void loadSSL(void) {
{ { &SSL_CTX_free }, "SSL_CTX_free" }, { { &SSL_CTX_free }, "SSL_CTX_free" },
{ { &SSL_CTX_new }, "SSL_CTX_new" }, { { &SSL_CTX_new }, "SSL_CTX_new" },
{ { &SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" }, { { &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_file }, "SSL_CTX_use_PrivateKey_file" },
{ { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" }, { { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" },
{ { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"}, { { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"},
@ -602,6 +606,15 @@ static int sslSetCertificateFromFile(SSL_CTX *context,
return rc; 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) { static SSL_CTX *sslMakeContext(void) {
SSL_CTX *context; SSL_CTX *context;
@ -657,6 +670,8 @@ static SSL_CTX *sslMakeContext(void) {
"ECDHE-RSA-DES-CBC3-SHA:" "ECDHE-RSA-DES-CBC3-SHA:"
"HIGH:MEDIUM:!RC4:!aNULL:!MD5")); "HIGH:MEDIUM:!RC4:!aNULL:!MD5"));
SSL_CTX_set_info_callback(context, sslInfoCallback);
debug("SSL: server context succesfully initialized..."); debug("SSL: server context succesfully initialized...");
return context; return context;
} }

View file

@ -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 long (*x_SSL_CTX_ctrl)(SSL_CTX *, int, long, void *);
extern void (*x_SSL_CTX_free)(SSL_CTX *); extern void (*x_SSL_CTX_free)(SSL_CTX *);
extern SSL_CTX*(*x_SSL_CTX_new)(SSL_METHOD *); 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_file)(SSL_CTX *, const char *, int);
extern int (*x_SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *, extern int (*x_SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *,
const unsigned char *, long); 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_free x_SSL_CTX_free
#define SSL_CTX_new x_SSL_CTX_new #define SSL_CTX_new x_SSL_CTX_new
#define SSL_CTX_set_cipher_list x_SSL_CTX_set_cipher_list #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_file x_SSL_CTX_use_PrivateKey_file
#define SSL_CTX_use_PrivateKey_ASN1 x_SSL_CTX_use_PrivateKey_ASN1 #define SSL_CTX_use_PrivateKey_ASN1 x_SSL_CTX_use_PrivateKey_ASN1
#define SSL_CTX_use_certificate_file x_SSL_CTX_use_certificate_file #define SSL_CTX_use_certificate_file x_SSL_CTX_use_certificate_file
@ -198,6 +201,7 @@ struct SSLSupport {
SSL_CTX *sslContext; SSL_CTX *sslContext;
char *sniCertificatePattern; char *sniCertificatePattern;
int generateMissing; int generateMissing;
int renegotiationCount;
struct Trie sniContexts; struct Trie sniContexts;
}; };