summaryrefslogtreecommitdiff
path: root/src/lib/libssl/ssl_lib.c
diff options
context:
space:
mode:
authorjsing <>2015-02-22 15:54:27 +0000
committerjsing <>2015-02-22 15:54:27 +0000
commit78601da9335579c01a88b356a8323117f14ec379 (patch)
tree38ba794e823ec25b4428f85632c6cdd2573912da /src/lib/libssl/ssl_lib.c
parent9ca594bf596db20fe3bf5a6e78e6df39cf9e10cd (diff)
downloadopenbsd-78601da9335579c01a88b356a8323117f14ec379.tar.gz
openbsd-78601da9335579c01a88b356a8323117f14ec379.tar.bz2
openbsd-78601da9335579c01a88b356a8323117f14ec379.zip
Reluctantly add server-side support for TLS_FALLBACK_SCSV.
This allows for clients that willingly choose to perform a downgrade and attempt to establish a second connection at a lower protocol after the previous attempt unexpectedly failed, to be notified and have the second connection aborted, if the server does in fact support a higher protocol. TLS has perfectly good version negotiation and client-side fallback is dangerous. Despite this, in order to maintain maximum compatability with broken web servers, most mainstream browsers implement this. Furthermore, TLS_FALLBACK_SCSV only works if both the client and server support it and there is effectively no way to tell if this is the case, unless you control both ends. Unfortunately, various auditors and vulnerability scanners (including certain online assessment websites) consider the presence of a not yet standardised feature to be important for security, even if the clients do not perform client-side downgrade or the server only supports current TLS protocols. Diff is loosely based on OpenSSL with some inspiration from BoringSSL. Discussed with beck@ and miod@. ok bcook@
Diffstat (limited to 'src/lib/libssl/ssl_lib.c')
-rw-r--r--src/lib/libssl/ssl_lib.c62
1 files changed, 58 insertions, 4 deletions
diff --git a/src/lib/libssl/ssl_lib.c b/src/lib/libssl/ssl_lib.c
index 58835931d2..d7b5283501 100644
--- a/src/lib/libssl/ssl_lib.c
+++ b/src/lib/libssl/ssl_lib.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_lib.c,v 1.100 2015/02/22 15:29:39 jsing Exp $ */ 1/* $OpenBSD: ssl_lib.c,v 1.101 2015/02/22 15:54:27 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -1419,7 +1419,9 @@ ssl_bytes_to_cipher_list(SSL *s, unsigned char *p, int num,
1419 const SSL_CIPHER *c; 1419 const SSL_CIPHER *c;
1420 STACK_OF(SSL_CIPHER) *sk; 1420 STACK_OF(SSL_CIPHER) *sk;
1421 int i; 1421 int i;
1422 unsigned long cipher_id;
1422 uint16_t cipher_value; 1423 uint16_t cipher_value;
1424 uint16_t max_version;
1423 1425
1424 if (s->s3) 1426 if (s->s3)
1425 s->s3->send_connection_binding = 0; 1427 s->s3->send_connection_binding = 0;
@@ -1440,10 +1442,13 @@ ssl_bytes_to_cipher_list(SSL *s, unsigned char *p, int num,
1440 1442
1441 for (i = 0; i < num; i += SSL3_CIPHER_VALUE_SIZE) { 1443 for (i = 0; i < num; i += SSL3_CIPHER_VALUE_SIZE) {
1442 n2s(p, cipher_value); 1444 n2s(p, cipher_value);
1445 cipher_id = SSL3_CK_ID | cipher_value;
1443 1446
1444 /* Check for SCSV */ 1447 if (s->s3 != NULL && cipher_id == SSL3_CK_SCSV) {
1445 if (s->s3 && (SSL3_CK_ID | cipher_value) == SSL3_CK_SCSV) { 1448 /*
1446 /* SCSV is fatal if renegotiating. */ 1449 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV is fatal if
1450 * renegotiating.
1451 */
1447 if (s->renegotiate) { 1452 if (s->renegotiate) {
1448 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, 1453 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
1449 SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); 1454 SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
@@ -1456,6 +1461,25 @@ ssl_bytes_to_cipher_list(SSL *s, unsigned char *p, int num,
1456 continue; 1461 continue;
1457 } 1462 }
1458 1463
1464 if (cipher_id == SSL3_CK_FALLBACK_SCSV) {
1465 /*
1466 * TLS_FALLBACK_SCSV indicates that the client
1467 * previously tried a higher protocol version.
1468 * Fail if the current version is an unexpected
1469 * downgrade.
1470 */
1471 max_version = ssl_max_server_version(s);
1472 if (max_version == 0 || s->version < max_version) {
1473 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
1474 SSL_R_INAPPROPRIATE_FALLBACK);
1475 if (s->s3 != NULL)
1476 ssl3_send_alert(s, SSL3_AL_FATAL,
1477 SSL_AD_INAPPROPRIATE_FALLBACK);
1478 goto err;
1479 }
1480 continue;
1481 }
1482
1459 if ((c = ssl3_get_cipher_by_value(cipher_value)) != NULL) { 1483 if ((c = ssl3_get_cipher_by_value(cipher_value)) != NULL) {
1460 if (!sk_SSL_CIPHER_push(sk, c)) { 1484 if (!sk_SSL_CIPHER_push(sk, c)) {
1461 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, 1485 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
@@ -2543,6 +2567,36 @@ SSL_get_version(const SSL *s)
2543 return ssl_version_string(s->version); 2567 return ssl_version_string(s->version);
2544} 2568}
2545 2569
2570uint16_t
2571ssl_max_server_version(SSL *s)
2572{
2573 uint16_t max_version;
2574
2575 /*
2576 * The SSL method will be changed during version negotiation, as such
2577 * we want to use the SSL method from the context.
2578 */
2579 max_version = s->ctx->method->version;
2580
2581 if (SSL_IS_DTLS(s))
2582 return (DTLS1_VERSION);
2583
2584 if ((s->options & SSL_OP_NO_TLSv1_2) == 0 &&
2585 max_version >= TLS1_2_VERSION)
2586 return (TLS1_2_VERSION);
2587 if ((s->options & SSL_OP_NO_TLSv1_1) == 0 &&
2588 max_version >= TLS1_1_VERSION)
2589 return (TLS1_1_VERSION);
2590 if ((s->options & SSL_OP_NO_TLSv1) == 0 &&
2591 max_version >= TLS1_VERSION)
2592 return (TLS1_VERSION);
2593 if ((s->options & SSL_OP_NO_SSLv3) == 0 &&
2594 max_version >= SSL3_VERSION)
2595 return (SSL3_VERSION);
2596
2597 return (0);
2598}
2599
2546SSL * 2600SSL *
2547SSL_dup(SSL *s) 2601SSL_dup(SSL *s)
2548{ 2602{