From 8581de7dc1af6d6443642f67c0fcc2846467021c Mon Sep 17 00:00:00 2001
From: Anders Kaseorg <andersk@mit.edu>
Date: Sat, 18 Oct 2014 19:48:07 -0400
Subject: [PATCH] Allow specifying ssl_protocols as a blacklist (ticket #642).

This allows the administrator to specify a minimum SSL/TLS version
without also specifying a maximum.  For example, instead of
  ssl_protocols TLSv1.0 TLSv1.1 TLSv1.2;
one can now write
  ssl_protocols all -SSLv2 -SSLv3;
which will not need to be updated when future versions of TLS become
supported.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 src/event/ngx_event_openssl.c            | 10 +++++-----
 src/event/ngx_event_openssl.h            |  7 +++++++
 src/http/modules/ngx_http_proxy_module.c |  6 ++++++
 src/http/modules/ngx_http_ssl_module.c   |  6 ++++++
 src/http/modules/ngx_http_uwsgi_module.c |  6 ++++++
 src/mail/ngx_mail_ssl_module.c           |  6 ++++++
 6 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 975a8e0..dc21850 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -249,22 +249,22 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
 
-    if (!(protocols & NGX_SSL_SSLv2)) {
+    if (!(protocols & NGX_SSL_SSLv2) || (protocols & NGX_SSL_NO_SSLv2)) {
         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
     }
-    if (!(protocols & NGX_SSL_SSLv3)) {
+    if (!(protocols & NGX_SSL_SSLv3) || (protocols & NGX_SSL_NO_SSLv3)) {
         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
     }
-    if (!(protocols & NGX_SSL_TLSv1)) {
+    if (!(protocols & NGX_SSL_TLSv1) || (protocols & NGX_SSL_NO_TLSv1)) {
         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
     }
 #ifdef SSL_OP_NO_TLSv1_1
-    if (!(protocols & NGX_SSL_TLSv1_1)) {
+    if (!(protocols & NGX_SSL_TLSv1_1) || (protocols & NGX_SSL_NO_TLSv1_1)) {
         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
     }
 #endif
 #ifdef SSL_OP_NO_TLSv1_2
-    if (!(protocols & NGX_SSL_TLSv1_2)) {
+    if (!(protocols & NGX_SSL_TLSv1_2) || (protocols & NGX_SSL_NO_TLSv1_2)) {
         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
     }
 #endif
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 4086940..b1a7ba0 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -113,6 +113,13 @@ typedef struct {
 #define NGX_SSL_TLSv1_1  0x0010
 #define NGX_SSL_TLSv1_2  0x0020
 
+#define NGX_SSL_ALL      (NGX_SSL_SSLv2 | NGX_SSL_SSLv3 | NGX_SSL_TLSv1 | NGX_SSL_TLSv1_1 | NGX_SSL_TLSv1_2)
+
+#define NGX_SSL_NO_SSLv2    (NGX_SSL_SSLv2 << 16)
+#define NGX_SSL_NO_SSLv3    (NGX_SSL_SSLv3 << 16)
+#define NGX_SSL_NO_TLSv1    (NGX_SSL_TLSv1 << 16)
+#define NGX_SSL_NO_TLSv1_1  (NGX_SSL_TLSv1_1 << 16)
+#define NGX_SSL_NO_TLSv1_2  (NGX_SSL_TLSv1_2 << 16)
 
 #define NGX_SSL_BUFFER   1
 #define NGX_SSL_CLIENT   2
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 9a85973..4f91590 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -203,6 +203,12 @@ static ngx_conf_bitmask_t  ngx_http_proxy_ssl_protocols[] = {
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("all"), NGX_SSL_ALL },
+    { ngx_string("-SSLv2"), NGX_SSL_NO_SSLv2 },
+    { ngx_string("-SSLv3"), NGX_SSL_NO_SSLv3 },
+    { ngx_string("-TLSv1"), NGX_SSL_NO_TLSv1 },
+    { ngx_string("-TLSv1.1"), NGX_SSL_NO_TLSv1_1 },
+    { ngx_string("-TLSv1.2"), NGX_SSL_NO_TLSv1_2 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 4c69091..9173049 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -57,6 +57,12 @@ static ngx_conf_bitmask_t  ngx_http_ssl_protocols[] = {
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("all"), NGX_SSL_ALL },
+    { ngx_string("-SSLv2"), NGX_SSL_NO_SSLv2 },
+    { ngx_string("-SSLv3"), NGX_SSL_NO_SSLv3 },
+    { ngx_string("-TLSv1"), NGX_SSL_NO_TLSv1 },
+    { ngx_string("-TLSv1.1"), NGX_SSL_NO_TLSv1_1 },
+    { ngx_string("-TLSv1.2"), NGX_SSL_NO_TLSv1_2 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 151d76c..c47bc1d 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -108,6 +108,12 @@ static ngx_conf_bitmask_t  ngx_http_uwsgi_ssl_protocols[] = {
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("all"), NGX_SSL_ALL },
+    { ngx_string("-SSLv2"), NGX_SSL_NO_SSLv2 },
+    { ngx_string("-SSLv3"), NGX_SSL_NO_SSLv3 },
+    { ngx_string("-TLSv1"), NGX_SSL_NO_TLSv1 },
+    { ngx_string("-TLSv1.1"), NGX_SSL_NO_TLSv1_1 },
+    { ngx_string("-TLSv1.2"), NGX_SSL_NO_TLSv1_2 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index f864d99..125ad2a 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -42,6 +42,12 @@ static ngx_conf_bitmask_t  ngx_mail_ssl_protocols[] = {
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("all"), NGX_SSL_ALL },
+    { ngx_string("-SSLv2"), NGX_SSL_NO_SSLv2 },
+    { ngx_string("-SSLv3"), NGX_SSL_NO_SSLv3 },
+    { ngx_string("-TLSv1"), NGX_SSL_NO_TLSv1 },
+    { ngx_string("-TLSv1.1"), NGX_SSL_NO_TLSv1_1 },
+    { ngx_string("-TLSv1.2"), NGX_SSL_NO_TLSv1_2 },
     { ngx_null_string, 0 }
 };
 
-- 
2.1.2

