Changes between 1.1.1a and 1.1.1b [xx XXX xxxx]
+ *) Fix a bug in the computation of the endpoint-pair shared secret used
+ by DTLS over SCTP. This breaks interoperability with older versions
+ of OpenSSL like OpenSSL 1.1.0 and OpenSSL 1.0.2. There is a runtime
+ switch SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG (off by default) enabling
+ interoperability with such broken implementations. However, enabling
+ this switch breaks interoperability with correct implementations.
+
*) Move strictness check from EVP_PKEY_asn1_new() to EVP_PKEY_asn1_add0().
[Richard Levitte]
#endif
OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
OPT_ENABLE_PHA,
+ OPT_SCTP_LABEL_BUG,
OPT_R_ENUM
} OPTION_CHOICE;
#endif
#ifndef OPENSSL_NO_SCTP
{"sctp", OPT_SCTP, '-', "Use SCTP"},
+ {"sctp_label_bug", OPT_SCTP_LABEL_BUG, '-', "Enable SCTP label length bug"},
#endif
#ifndef OPENSSL_NO_SSL_TRACE
{"trace", OPT_TRACE, '-', "Show trace output of protocol messages"},
#endif
char *psksessf = NULL;
int enable_pha = 0;
+#ifndef OPENSSL_NO_SCTP
+ int sctp_label_bug = 0;
+#endif
FD_ZERO(&readfds);
FD_ZERO(&writefds);
case OPT_SCTP:
#ifndef OPENSSL_NO_SCTP
protocol = IPPROTO_SCTP;
+#endif
+ break;
+ case OPT_SCTP_LABEL_BUG:
+#ifndef OPENSSL_NO_SCTP
+ sctp_label_bug = 1;
#endif
break;
case OPT_TIMEOUT:
}
}
+#ifndef OPENSSL_NO_SCTP
+ if (protocol == IPPROTO_SCTP && sctp_label_bug == 1)
+ SSL_CTX_set_mode(ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG);
+#endif
+
if (min_version != 0
&& SSL_CTX_set_min_proto_version(ctx, min_version) == 0)
goto end;
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA,
- OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY,
+ OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY, OPT_SCTP_LABEL_BUG,
OPT_R_ENUM,
OPT_S_ENUM,
OPT_V_ENUM,
#endif
#ifndef OPENSSL_NO_SCTP
{"sctp", OPT_SCTP, '-', "Use SCTP"},
+ {"sctp_label_bug", OPT_SCTP_LABEL_BUG, '-', "Enable SCTP label length bug"},
#endif
#ifndef OPENSSL_NO_DH
{"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"},
const char *keylog_file = NULL;
int max_early_data = -1, recv_max_early_data = -1;
char *psksessf = NULL;
+#ifndef OPENSSL_NO_SCTP
+ int sctp_label_bug = 0;
+#endif
/* Init of few remaining global variables */
local_argc = argc;
case OPT_SCTP:
#ifndef OPENSSL_NO_SCTP
protocol = IPPROTO_SCTP;
+#endif
+ break;
+ case OPT_SCTP_LABEL_BUG:
+#ifndef OPENSSL_NO_SCTP
+ sctp_label_bug = 1;
#endif
break;
case OPT_TIMEOUT:
goto end;
}
}
+
+#ifndef OPENSSL_NO_SCTP
+ if (protocol == IPPROTO_SCTP && sctp_label_bug == 1)
+ SSL_CTX_set_mode(ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG);
+#endif
+
if (min_version != 0
&& SSL_CTX_set_min_proto_version(ctx, min_version) == 0)
goto end;
[B<-dtls1>]
[B<-dtls1_2>]
[B<-sctp>]
+[B<-sctp_label_bug>]
[B<-fallback_scsv>]
[B<-async>]
[B<-max_send_frag>]
conjunction with B<-dtls>, B<-dtls1> or B<-dtls1_2>. This option is only
available where OpenSSL has support for SCTP enabled.
+=item B<-sctp_label_bug>
+
+Use the incorrect behaviour of older OpenSSL implementations when computing
+endpoint-pair shared secrets for DTLS/SCTP. This allows communication with
+older broken implementations but breaks interoperability with correct
+implementations. Must be used in conjunction with B<-sctp>. This option is only
+available where OpenSSL has support for SCTP enabled.
+
=item B<-fallback_scsv>
Send TLS_FALLBACK_SCSV in the ClientHello.
[B<-dtls1>]
[B<-dtls1_2>]
[B<-sctp>]
+[B<-sctp_label_bug>]
[B<-no_dhe>]
[B<-nextprotoneg val>]
[B<-use_srtp val>]
conjunction with B<-dtls>, B<-dtls1> or B<-dtls1_2>. This option is only
available where OpenSSL has support for SCTP enabled.
+=item B<-sctp_label_bug>
+
+Use the incorrect behaviour of older OpenSSL implementations when computing
+endpoint-pair shared secrets for DTLS/SCTP. This allows communication with
+older broken implementations but breaks interoperability with correct
+implementations. Must be used in conjunction with B<-sctp>. This option is only
+available where OpenSSL has support for SCTP enabled.
+
=item B<-no_dhe>
If this option is set then no DH parameters will be loaded effectively
SSL_ERROR_WANT_ASYNC with this mode set if an asynchronous capable engine is
used to perform cryptographic operations. See L<SSL_get_error(3)>.
+=item SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG
+
+Older versions of OpenSSL had a bug in the computation of the label length
+used for computing the endpoint-pair shared secret. The bug was that the
+terminating zero was included in the length of the label. Setting this option
+enables this behaviour to allow interoperability with such broken
+implementations. Please note that setting this option breaks interoperability
+with correct implementations. This option only applies to DTLS over SCTP.
+
=back
All modes are off by default except for SSL_MODE_AUTO_RETRY which is on by
*/
# define SSL_MODE_ASYNC 0x00000100U
+/*
+ * When using DTLS/SCTP, include the terminating zero in the label
+ * used for computing the endpoint-pair shared secret. Required for
+ * interoperability with implementations having this bug like these
+ * older version of OpenSSL:
+ * - OpenSSL 1.0.0 series
+ * - OpenSSL 1.0.1 series
+ * - OpenSSL 1.0.2 series
+ * - OpenSSL 1.1.0 series
+ * - OpenSSL 1.1.1 and 1.1.1a
+ */
+# define SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG 0x00000400U
+
/* Cert related flags */
/*
* Many implementations ignore some aspects of the TLS standards such as
if (SSL_IS_DTLS(s) && s->hit) {
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+ size_t labellen;
/*
* Add new shared key for SCTP-Auth, will be ignored if
memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
sizeof(DTLS1_SCTP_AUTH_LABEL));
+ /* Don't include the terminating zero. */
+ labellen = sizeof(labelbuffer) - 1;
+ if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+ labellen += 1;
+
if (SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey),
labelbuffer,
- sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+ labellen, NULL, 0, 0) <= 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
ERR_R_INTERNAL_ERROR);
goto err;
if (SSL_IS_DTLS(s)) {
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+ size_t labellen;
/*
* Add new shared key for SCTP-Auth, will be ignored if no SCTP
memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
sizeof(DTLS1_SCTP_AUTH_LABEL));
+ /* Don't include the terminating zero. */
+ labellen = sizeof(labelbuffer) - 1;
+ if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+ labellen += 1;
+
if (SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
- sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+ labellen, NULL, 0, 0) <= 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK,
ERR_R_INTERNAL_ERROR);
if (SSL_IS_DTLS(s) && s->hit) {
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+ size_t labellen;
/*
* Add new shared key for SCTP-Auth, will be ignored if no
memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
sizeof(DTLS1_SCTP_AUTH_LABEL));
+ /* Don't include the terminating zero. */
+ labellen = sizeof(labelbuffer) - 1;
+ if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+ labellen += 1;
+
if (SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
- sizeof(labelbuffer), NULL, 0,
+ labellen, NULL, 0,
0) <= 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_OSSL_STATEM_SERVER_POST_WORK,
if (SSL_IS_DTLS(s)) {
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+ size_t labellen;
/*
* Add new shared key for SCTP-Auth, will be ignored if no SCTP
* used.
memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
sizeof(DTLS1_SCTP_AUTH_LABEL));
+ /* Don't include the terminating zero. */
+ labellen = sizeof(labelbuffer) - 1;
+ if (s->mode & SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG)
+ labellen += 1;
+
if (SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
- sizeof(labelbuffer), NULL, 0,
+ labellen, NULL, 0,
0) <= 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE,
#include "handshake_helper.h"
#include "testutil.h"
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+#include <netinet/sctp.h>
+#endif
+
HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void)
{
HANDSHAKE_RESULT *ret;
#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
static int set_sock_as_sctp(int sock)
{
+ struct sctp_assocparams assocparams;
+ struct sctp_rtoinfo rto_info;
+ BIO *tmpbio;
+
+ /*
+ * To allow tests to fail fast (within a second or so), reduce the
+ * retransmission timeouts and the number of retransmissions.
+ */
+ memset(&rto_info, 0, sizeof(struct sctp_rtoinfo));
+ rto_info.srto_initial = 100;
+ rto_info.srto_max = 200;
+ rto_info.srto_min = 50;
+ (void)setsockopt(sock, IPPROTO_SCTP, SCTP_RTOINFO,
+ (const void *)&rto_info, sizeof(struct sctp_rtoinfo));
+ memset(&assocparams, 0, sizeof(struct sctp_assocparams));
+ assocparams.sasoc_asocmaxrxt = 2;
+ (void)setsockopt(sock, IPPROTO_SCTP, SCTP_ASSOCINFO,
+ (const void *)&assocparams,
+ sizeof(struct sctp_assocparams));
+
/*
* For SCTP we have to set various options on the socket prior to
* connecting. This is done automatically by BIO_new_dgram_sctp().
* We don't actually need the created BIO though so we free it again
* immediately.
*/
- BIO *tmpbio = BIO_new_dgram_sctp(sock, BIO_NOCLOSE);
+ tmpbio = BIO_new_dgram_sctp(sock, BIO_NOCLOSE);
if (tmpbio == NULL)
return 0;
return NULL;
}
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+ if (test_ctx->enable_client_sctp_label_bug)
+ SSL_CTX_set_mode(client_ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG);
+ if (test_ctx->enable_server_sctp_label_bug)
+ SSL_CTX_set_mode(server_ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG);
+#endif
+
/* Setup SSL and buffers; additional configuration happens below. */
if (!create_peer(&server, server_ctx)) {
TEST_note("creating server context");
# We hard-code the number of tests to double-check that the globbing above
# finds all files as expected.
-plan tests => 28; # = scalar @conf_srcs
+plan tests => 29; # = scalar @conf_srcs
# Some test results depend on the configuration of enabled protocols. We only
# verify generated sources in the default configuration.
"24-padding.conf" => disabled("tls1_3"),
"25-cipher.conf" => disabled("ec") || disabled("tls1_2"),
"26-tls13_client_auth.conf" => disabled("tls1_3"),
+ "29-dtls-sctp-label-bug.conf" => disabled("sctp") || disabled("sock"),
);
foreach my $conf (@conf_files) {
--- /dev/null
+# Generated with generate_ssl_tests.pl
+
+num_tests = 4
+
+test-0 = 0-SCTPLabelBug-good1
+test-1 = 1-SCTPLabelBug-good2
+test-2 = 2-SCTPLabelBug-bad1
+test-3 = 3-SCTPLabelBug-bad2
+# ===========================================================
+
+[0-SCTPLabelBug-good1]
+ssl_conf = 0-SCTPLabelBug-good1-ssl
+
+[0-SCTPLabelBug-good1-ssl]
+server = 0-SCTPLabelBug-good1-server
+client = 0-SCTPLabelBug-good1-client
+
+[0-SCTPLabelBug-good1-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-SCTPLabelBug-good1-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+EnableClientSCTPLabelBug = No
+EnableServerSCTPLabelBug = No
+ExpectedResult = Success
+Method = DTLS
+UseSCTP = Yes
+
+
+# ===========================================================
+
+[1-SCTPLabelBug-good2]
+ssl_conf = 1-SCTPLabelBug-good2-ssl
+
+[1-SCTPLabelBug-good2-ssl]
+server = 1-SCTPLabelBug-good2-server
+client = 1-SCTPLabelBug-good2-client
+
+[1-SCTPLabelBug-good2-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-SCTPLabelBug-good2-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-1]
+EnableClientSCTPLabelBug = Yes
+EnableServerSCTPLabelBug = Yes
+ExpectedResult = Success
+Method = DTLS
+UseSCTP = Yes
+
+
+# ===========================================================
+
+[2-SCTPLabelBug-bad1]
+ssl_conf = 2-SCTPLabelBug-bad1-ssl
+
+[2-SCTPLabelBug-bad1-ssl]
+server = 2-SCTPLabelBug-bad1-server
+client = 2-SCTPLabelBug-bad1-client
+
+[2-SCTPLabelBug-bad1-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-SCTPLabelBug-bad1-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+EnableClientSCTPLabelBug = Yes
+EnableServerSCTPLabelBug = No
+ExpectedResult = ClientFail
+Method = DTLS
+UseSCTP = Yes
+
+
+# ===========================================================
+
+[3-SCTPLabelBug-bad2]
+ssl_conf = 3-SCTPLabelBug-bad2-ssl
+
+[3-SCTPLabelBug-bad2-ssl]
+server = 3-SCTPLabelBug-bad2-server
+client = 3-SCTPLabelBug-bad2-client
+
+[3-SCTPLabelBug-bad2-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-SCTPLabelBug-bad2-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-3]
+EnableClientSCTPLabelBug = No
+EnableServerSCTPLabelBug = Yes
+ExpectedResult = ClientFail
+Method = DTLS
+UseSCTP = Yes
+
+
--- /dev/null
+# -*- mode: perl; -*-
+# Copyright 2019-2019 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+
+## Test SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG handling
+
+use strict;
+use warnings;
+
+package ssltests;
+use OpenSSL::Test::Utils;
+
+our @tests = (
+ {
+ name => "SCTPLabelBug-good1",
+ server => {},
+ client => {},
+ test => {
+ "Method" => "DTLS",
+ "UseSCTP" => "Yes",
+ "EnableClientSCTPLabelBug" => "No",
+ "EnableServerSCTPLabelBug" => "No",
+ "ExpectedResult" => "Success"
+ }
+ },
+ {
+ name => "SCTPLabelBug-good2",
+ server => {},
+ client => {},
+ test => {
+ "Method" => "DTLS",
+ "UseSCTP" => "Yes",
+ "EnableClientSCTPLabelBug" => "Yes",
+ "EnableServerSCTPLabelBug" => "Yes",
+ "ExpectedResult" => "Success"
+ }
+ },
+ {
+ name => "SCTPLabelBug-bad1",
+ server => {},
+ client => {},
+ test => {
+ "Method" => "DTLS",
+ "UseSCTP" => "Yes",
+ "EnableClientSCTPLabelBug" => "Yes",
+ "EnableServerSCTPLabelBug" => "No",
+ "ExpectedResult" => "ClientFail"
+ }
+ },
+ {
+ name => "SCTPLabelBug-bad2",
+ server => {},
+ client => {},
+ test => {
+ "Method" => "DTLS",
+ "UseSCTP" => "Yes",
+ "EnableClientSCTPLabelBug" => "No",
+ "EnableServerSCTPLabelBug" => "Yes",
+ "ExpectedResult" => "ClientFail"
+ }
+ },
+);
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, resumption_expected)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_SERVER_CONF, server, broken_session_ticket)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, use_sctp)
+IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, enable_client_sctp_label_bug)
+IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, enable_server_sctp_label_bug)
/* CertStatus */
{ "ExpectedClientSignType", &parse_expected_client_sign_type },
{ "ExpectedClientCANames", &parse_expected_client_ca_names },
{ "UseSCTP", &parse_test_use_sctp },
+ { "EnableClientSCTPLabelBug", &parse_test_enable_client_sctp_label_bug },
+ { "EnableServerSCTPLabelBug", &parse_test_enable_server_sctp_label_bug },
{ "ExpectedCipher", &parse_test_expected_cipher },
{ "ExpectedSessionTicketAppData", &parse_test_expected_session_ticket_app_data },
};
STACK_OF(X509_NAME) *expected_client_ca_names;
/* Whether to use SCTP for the transport */
int use_sctp;
+ /* Enable SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG on client side */
+ int enable_client_sctp_label_bug;
+ /* Enable SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG on server side */
+ int enable_server_sctp_label_bug;
/* Whether to expect a session id from the server */
ssl_session_id_t session_id_expected;
char *expected_cipher;