Browse code

tls: new parameter 'renegotiation' to enable/disable client renegotiation

- default is 0 (renegotiation disabled), to protect against SSL
renegotiation attack
- can be enabled by setting it to 1

Daniel-Constantin Mierla authored on 17/12/2011 21:22:04
Showing 5 changed files
... ...
@@ -591,6 +591,40 @@ static int set_verification(tls_domain_t* d)
591 591
 }
592 592
 
593 593
 
594
+/* This callback function is executed when libssl processes the SSL
595
+ * handshake and does SSL record layer stuff. It's used to trap
596
+ * client-initiated renegotiations.
597
+ */
598
+
599
+static void sr_ssl_ctx_info_callback(const SSL *ssl, int event, int ret)
600
+{
601
+	struct tls_extra_data* data = 0;
602
+	int tls_dbg;
603
+
604
+	if (event & SSL_CB_HANDSHAKE_START) {
605
+		tls_dbg = cfg_get(tls, tls_cfg, debug);
606
+		LOG(tls_dbg, "SSL handshake started\n");
607
+		if(data==0)
608
+			data = (struct tls_extra_data*)SSL_get_app_data(ssl);
609
+		if(data->flags & F_TLS_CON_HANDSHAKED) {
610
+			LOG(tls_dbg, "SSL renegotiation initiated by client\n");
611
+			data->flags |= F_TLS_CON_RENEGOTIATION;
612
+		}
613
+	}
614
+	if (event & SSL_CB_HANDSHAKE_DONE) {
615
+		tls_dbg = cfg_get(tls, tls_cfg, debug);
616
+		if(data==0)
617
+			data = (struct tls_extra_data*)SSL_get_app_data(ssl);
618
+		LOG(tls_dbg, "SSL handshake done\n");
619
+		/* CVE-2009-3555 - disable renegotiation */
620
+		if (ssl->s3) {
621
+			LOG(tls_dbg, "SSL disable renegotiation\n");
622
+			ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
623
+		}
624
+		data->flags |= F_TLS_CON_HANDSHAKED;
625
+	}
626
+}
627
+
594 628
 /**
595 629
  * @brief Configure generic SSL parameters 
596 630
  * @param d domain
... ...
@@ -635,6 +669,8 @@ static int set_ssl_options(tls_domain_t* d)
635 669
 #endif
636 670
 	for(i = 0; i < procs_no; i++) {
637 671
 		SSL_CTX_set_options(d->ctx[i], options);
672
+		if(sr_tls_renegotiation==0)
673
+			SSL_CTX_set_info_callback(d->ctx[i], sr_ssl_ctx_info_callback);
638 674
 	}
639 675
 	return 0;
640 676
 }
... ...
@@ -175,6 +175,8 @@ tls_domains_cfg_t** tls_domains_cfg = NULL;
175 175
 gen_lock_t* tls_domains_cfg_lock = NULL;
176 176
 
177 177
 
178
+int sr_tls_renegotiation = 0;
179
+
178 180
 /*
179 181
  * Exported functions
180 182
  */
... ...
@@ -218,6 +220,7 @@ static param_export_t params[] = {
218 220
 	{"tls_force_run",       PARAM_INT,    &default_tls_cfg.force_run},
219 221
 	{"low_mem_threshold1",  PARAM_INT,    &default_tls_cfg.low_mem_threshold1},
220 222
 	{"low_mem_threshold2",  PARAM_INT,    &default_tls_cfg.low_mem_threshold2},
223
+	{"renegotiation",       PARAM_INT,    &sr_tls_renegotiation},
221 224
 	{0, 0, 0}
222 225
 };
223 226
 
... ...
@@ -53,4 +53,6 @@ extern tls_domain_t srv_defaults;
53 53
 
54 54
 extern str tls_domains_cfg_file;
55 55
 
56
+extern int sr_tls_renegotiation;
57
+
56 58
 #endif /* _TLS_MOD_H */
... ...
@@ -209,6 +209,10 @@ static int tls_complete_init(struct tcp_connection* c)
209 209
 #endif
210 210
 	SSL_set_bio(data->ssl, data->rwbio, data->rwbio);
211 211
 	c->extra_data = data;
212
+
213
+	/* link the extra data struct inside ssl connection*/
214
+	SSL_set_app_data(data->ssl, data);
215
+
212 216
 	return 0;
213 217
 
214 218
  error:
... ...
@@ -908,6 +912,7 @@ int tls_read_f(struct tcp_connection* c, int* flags)
908 912
 	int n, flush_flags;
909 913
 	char* err_src;
910 914
 	int x;
915
+	int tls_dbg;
911 916
 	
912 917
 	TLS_RD_TRACE("(%p, %p (%d)) start (%s -> %s:%d*)\n",
913 918
 					c, flags, *flags,
... ...
@@ -1092,15 +1097,26 @@ continue_ssl_read:
1092 1097
 			 *  In the later case, this whole function should be called again
1093 1098
 			 *  once there is more output space (set RD_CONN_REPEAT_READ).
1094 1099
 			 */
1095
-			if (unlikely(n <= 0)) {
1096
-				ssl_error = SSL_get_error(ssl, n);
1097
-				err_src = "TLS read:";
1098
-				/*  errors handled below, outside the lock */
1100
+
1101
+			if (unlikely(tls_c->flags & F_TLS_CON_RENEGOTIATION)) {
1102
+				/* Fix CVE-2009-3555 - disable renegotiation if started by client
1103
+				 * - simulate SSL EOF to force close connection*/
1104
+				tls_dbg = cfg_get(tls, tls_cfg, debug);
1105
+				LOG(tls_dbg, "Reading on a renegotiation of connection (n:%d) (%d)\n",
1106
+						n, SSL_get_error(ssl, n));
1107
+				err_src = "TLS R-N read:";
1108
+				ssl_error = SSL_ERROR_ZERO_RETURN;
1099 1109
 			} else {
1100
-				ssl_error = SSL_ERROR_NONE;
1101
-				r->pos += n;
1102
-				ssl_read += n;
1103
-				bytes_free -=n;
1110
+				if (unlikely(n <= 0)) {
1111
+					ssl_error = SSL_get_error(ssl, n);
1112
+					err_src = "TLS read:";
1113
+					/*  errors handled below, outside the lock */
1114
+				} else {
1115
+					ssl_error = SSL_ERROR_NONE;
1116
+					r->pos += n;
1117
+					ssl_read += n;
1118
+					bytes_free -=n;
1119
+				}
1104 1120
 			}
1105 1121
 			TLS_RD_TRACE("(%p, %p) SSL_read() => %d (err=%d) ssl_read=%d"
1106 1122
 							" *flags=%d tls_c->flags=%d\n",
... ...
@@ -49,7 +49,9 @@ struct tls_rd_buf {
49 49
 };
50 50
 
51 51
 /* tls conn flags */
52
-#define F_TLS_CON_WR_WANTS_RD 1 /* write wants read */
52
+#define F_TLS_CON_WR_WANTS_RD    1 /* write wants read */
53
+#define F_TLS_CON_HANDSHAKED     2 /* connection is handshaked */
54
+#define F_TLS_CON_RENEGOTIATION  4 /* renegotiation by clinet */
53 55
 
54 56
 struct tls_extra_data {
55 57
 	tls_domains_cfg_t* cfg; /* Configuration used for this connection */