[openssl-commits] [openssl] master update
Matt Caswell
matt at openssl.org
Wed Nov 2 14:03:05 UTC 2016
The branch master has been updated
via 8aefa08cfbc7db7cc10765ee9684090e37983f45 (commit)
via 02e22dd444c46728008a7c17e0758327f1c31e67 (commit)
via 542dd9c58712201a46a5519ee02e878792bbcb72 (commit)
via 045bd04706d2a798d5fb4b3ccf7fd56e6e09b082 (commit)
from ca0b75ade0e89d1d3782ed6b1a4ae0fab72251ec (commit)
- Log -----------------------------------------------------------------
commit 8aefa08cfbc7db7cc10765ee9684090e37983f45
Author: David Woodhouse <dwmw2 at infradead.org>
Date: Sun Oct 23 17:03:56 2016 +0100
Add documentation for DTLS_get_data_mtu()
Reviewed-by: Rich Salz <rsalz at openssl.org>
Reviewed-by: Matt Caswell <matt at openssl.org>
commit 02e22dd444c46728008a7c17e0758327f1c31e67
Author: David Woodhouse <David.Woodhouse at intel.com>
Date: Wed Oct 12 16:13:31 2016 +0100
Add test cases for DTLS_get_data_mtu()
Reviewed-by: Rich Salz <rsalz at openssl.org>
Reviewed-by: Matt Caswell <matt at openssl.org>
commit 542dd9c58712201a46a5519ee02e878792bbcb72
Author: David Woodhouse <David.Woodhouse at intel.com>
Date: Thu Oct 6 11:44:29 2016 +0100
Add unit test for ssl_cipher_get_overhead()
Reviewed-by: Rich Salz <rsalz at openssl.org>
Reviewed-by: Matt Caswell <matt at openssl.org>
commit 045bd04706d2a798d5fb4b3ccf7fd56e6e09b082
Author: David Woodhouse <David.Woodhouse at intel.com>
Date: Thu Oct 6 00:44:59 2016 +0100
Add DTLS_get_data_mtu() function
We add ssl_cipher_get_overhead() as an internal function, to avoid
having too much ciphersuite-specific knowledge in DTLS_get_data_mtu()
itself. It's going to need adjustment for TLSv1.3... but then again, so
is fairly much *all* of the SSL_CIPHER handling. This bit is in the noise.
Reviewed-by: Rich Salz <rsalz at openssl.org>
Reviewed-by: Matt Caswell <matt at openssl.org>
-----------------------------------------------------------------------
Summary of changes:
doc/man3/DTLS_get_data_mtu.pod | 36 ++++
include/openssl/ssl.h | 2 +
ssl/d1_lib.c | 36 ++++
ssl/ssl_ciph.c | 52 ++++++
ssl/ssl_locl.h | 3 +
test/build.info | 13 +-
test/cipher_overhead_test.c | 33 ++++
test/dtls_mtu_test.c | 190 +++++++++++++++++++++
.../{70-test_bad_dtls.t => 80-test_dtls_mtu.t} | 9 +-
.../{70-test_wpacket.t => 90-test_overhead.t} | 4 +-
util/libssl.num | 1 +
11 files changed, 372 insertions(+), 7 deletions(-)
create mode 100644 doc/man3/DTLS_get_data_mtu.pod
create mode 100644 test/cipher_overhead_test.c
create mode 100644 test/dtls_mtu_test.c
copy test/recipes/{70-test_bad_dtls.t => 80-test_dtls_mtu.t} (64%)
copy test/recipes/{70-test_wpacket.t => 90-test_overhead.t} (83%)
diff --git a/doc/man3/DTLS_get_data_mtu.pod b/doc/man3/DTLS_get_data_mtu.pod
new file mode 100644
index 0000000..ab71472
--- /dev/null
+++ b/doc/man3/DTLS_get_data_mtu.pod
@@ -0,0 +1,36 @@
+=pod
+
+=head1 NAME
+
+DTLS_get_data_mtu - Get maximum data payload size
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ size_t DTLS_get_data_mtu(const SSL *ssl);
+
+=head1 DESCRIPTION
+
+This function obtains the maximum data payload size for the established
+DTLS connection B<ssl>, based on the DTLS record MTU and the overhead
+of the DTLS record header, encryption and authentication currently in use.
+
+=head1 RETURN VALUES
+
+Returns the maximum data payload size on success, or 0 on failure.
+
+=head1 HISTORY
+
+This function was added in OpenSSL 1.1.1
+
+=head1 COPYRIGHT
+
+Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index f0aa306..7b40b37 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1630,6 +1630,8 @@ __owur const SSL_METHOD *DTLS_method(void); /* DTLS 1.0 and 1.2 */
__owur const SSL_METHOD *DTLS_server_method(void); /* DTLS 1.0 and 1.2 */
__owur const SSL_METHOD *DTLS_client_method(void); /* DTLS 1.0 and 1.2 */
+__owur size_t DTLS_get_data_mtu(const SSL *s);
+
__owur STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
__owur STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx);
__owur STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s);
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 112c699..e7a6650 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -1088,3 +1088,39 @@ unsigned int dtls1_min_mtu(SSL *s)
{
return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
}
+
+size_t DTLS_get_data_mtu(const SSL *s)
+{
+ size_t mac_overhead, int_overhead, blocksize, ext_overhead;
+ const SSL_CIPHER *ciph = SSL_get_current_cipher(s);
+ size_t mtu = s->d1->mtu;
+
+ if (ciph == NULL)
+ return 0;
+
+ if (!ssl_cipher_get_overhead(ciph, &mac_overhead, &int_overhead,
+ &blocksize, &ext_overhead))
+ return 0;
+
+ if (SSL_USE_ETM(s))
+ ext_overhead += mac_overhead;
+ else
+ int_overhead += mac_overhead;
+
+ /* Subtract external overhead (e.g. IV/nonce, separate MAC) */
+ if (ext_overhead + DTLS1_RT_HEADER_LENGTH >= mtu)
+ return 0;
+ mtu -= ext_overhead + DTLS1_RT_HEADER_LENGTH;
+
+ /* Round encrypted payload down to cipher block size (for CBC etc.)
+ * No check for overflow since 'mtu % blocksize' cannot exceed mtu. */
+ if (blocksize)
+ mtu -= (mtu % blocksize);
+
+ /* Subtract internal overhead (e.g. CBC padding len byte) */
+ if (int_overhead >= mtu)
+ return 0;
+ mtu -= int_overhead;
+
+ return mtu;
+}
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index adccbfc..acc1840 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1947,3 +1947,55 @@ int SSL_CIPHER_is_aead(const SSL_CIPHER *c)
{
return (c->algorithm_mac & SSL_AEAD) ? 1 : 0;
}
+
+int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
+ size_t *int_overhead, size_t *blocksize,
+ size_t *ext_overhead)
+{
+ size_t mac = 0, in = 0, blk = 0, out = 0;
+
+ /* Some hard-coded numbers for the CCM/Poly1305 MAC overhead
+ * because there are no handy #defines for those. */
+ if (c->algorithm_enc & SSL_AESGCM) {
+ out = EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+ } else if (c->algorithm_enc & (SSL_AES128CCM | SSL_AES256CCM)) {
+ out = EVP_CCM_TLS_EXPLICIT_IV_LEN + 16;
+ } else if (c->algorithm_enc & (SSL_AES128CCM8 | SSL_AES256CCM8)) {
+ out = EVP_CCM_TLS_EXPLICIT_IV_LEN + 8;
+ } else if (c->algorithm_enc & SSL_CHACHA20POLY1305) {
+ out = 16;
+ } else if (c->algorithm_mac & SSL_AEAD) {
+ /* We're supposed to have handled all the AEAD modes above */
+ return 0;
+ } else {
+ /* Non-AEAD modes. Calculate MAC/cipher overhead separately */
+ int digest_nid = SSL_CIPHER_get_digest_nid(c);
+ const EVP_MD *e_md = EVP_get_digestbynid(digest_nid);
+
+ if (e_md == NULL)
+ return 0;
+
+ mac = EVP_MD_size(e_md);
+ if (c->algorithm_enc != SSL_eNULL) {
+ int cipher_nid = SSL_CIPHER_get_cipher_nid(c);
+ const EVP_CIPHER *e_ciph = EVP_get_cipherbynid(cipher_nid);
+
+ /* If it wasn't AEAD or SSL_eNULL, we expect it to be a
+ known CBC cipher. */
+ if (e_ciph == NULL ||
+ EVP_CIPHER_mode(e_ciph) != EVP_CIPH_CBC_MODE)
+ return 0;
+
+ in = 1; /* padding length byte */
+ out = EVP_CIPHER_iv_length(e_ciph);
+ blk = EVP_CIPHER_block_size(e_ciph);
+ }
+ }
+
+ *mac_overhead = mac;
+ *int_overhead = in;
+ *blocksize = blk;
+ *ext_overhead = out;
+
+ return 1;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index d5a6fe2..1cf27b9 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1817,6 +1817,9 @@ __owur int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
const EVP_MD **md, int *mac_pkey_type,
int *mac_secret_size, SSL_COMP **comp,
int use_etm);
+__owur int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
+ size_t *int_overhead, size_t *blocksize,
+ size_t *ext_overhead);
__owur int ssl_cipher_get_cert_index(const SSL_CIPHER *c);
__owur const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl,
const unsigned char *ptr);
diff --git a/test/build.info b/test/build.info
index 013a0c6..5246969 100644
--- a/test/build.info
+++ b/test/build.info
@@ -275,11 +275,22 @@ IF[{- !$disabled{tests} -}]
INCLUDE[bio_enc_test]=../include
DEPEND[bio_enc_test]=../libcrypto
+ IF[{- !$disabled{psk} -}]
+ PROGRAMS_NO_INST=dtls_mtu_test
+ SOURCE[dtls_mtu_test]=dtls_mtu_test.c ssltestlib.c
+ INCLUDE[dtls_mtu_test]=.. ../include
+ DEPEND[dtls_mtu_test]=../libcrypto ../libssl
+ ENDIF
+
IF[{- $disabled{shared} -}]
- PROGRAMS_NO_INST=wpackettest
+ PROGRAMS_NO_INST=wpackettest cipher_overhead_test
SOURCE[wpackettest]=wpackettest.c testutil.c
INCLUDE[wpackettest]=../include
DEPEND[wpackettest]=../libcrypto ../libssl
+
+ SOURCE[cipher_overhead_test]=cipher_overhead_test.c
+ INCLUDE[cipher_overhead_test]=.. ../include
+ DEPEND[cipher_overhead_test]=../libcrypto ../libssl
ENDIF
ENDIF
diff --git a/test/cipher_overhead_test.c b/test/cipher_overhead_test.c
new file mode 100644
index 0000000..8c262b3
--- /dev/null
+++ b/test/cipher_overhead_test.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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
+ */
+
+#include <stdio.h>
+
+#include "../ssl/ssl_locl.h"
+
+int main(void)
+{
+ int i, n = ssl3_num_ciphers();
+ const SSL_CIPHER *ciph;
+ size_t mac, in, blk, ex;
+
+ for (i = 0; i < n; i++) {
+ ciph = ssl3_get_cipher(i);
+ if (!ciph->min_dtls)
+ continue;
+ if (!ssl_cipher_get_overhead(ciph, &mac, &in, &blk, &ex)) {
+ printf("Error getting overhead for %s\n", ciph->name);
+ exit(1);
+ } else {
+ printf("Cipher %s: %"OSSLzu" %"OSSLzu" %"OSSLzu" %"OSSLzu"\n",
+ ciph->name, mac, in, blk, ex);
+ }
+ }
+ exit(0);
+}
diff --git a/test/dtls_mtu_test.c b/test/dtls_mtu_test.c
new file mode 100644
index 0000000..df1013a
--- /dev/null
+++ b/test/dtls_mtu_test.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/dtls1.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "ssltestlib.h"
+
+/* for SSL_USE_ETM() */
+#include "../ssl/ssl_locl.h"
+
+static int debug = 0;
+
+static unsigned int clnt_psk_callback(SSL *ssl, const char *hint,
+ char *ident, unsigned int max_ident_len,
+ unsigned char *psk,
+ unsigned int max_psk_len)
+{
+ snprintf(ident, max_ident_len, "psk");
+
+ if (max_psk_len > 20)
+ max_psk_len = 20;
+ memset(psk, 0x5a, max_psk_len);
+
+ return max_psk_len;
+}
+
+static unsigned int srvr_psk_callback(SSL *ssl, const char *identity,
+ unsigned char *psk,
+ unsigned int max_psk_len)
+{
+ if (max_psk_len > 20)
+ max_psk_len = 20;
+ memset(psk, 0x5a, max_psk_len);
+ return max_psk_len;
+}
+
+static int mtu_test(SSL_CTX *ctx, const char *cs, int no_etm)
+{
+ SSL *srvr_ssl = NULL, *clnt_ssl = NULL;
+ BIO *sc_bio = NULL;
+ int i;
+ size_t s;
+ size_t mtus[30];
+ unsigned char buf[600];
+ int rv = 0;
+
+ memset(buf, 0x5a, sizeof(buf));
+
+ if (create_ssl_objects(ctx, ctx, &srvr_ssl, &clnt_ssl, NULL, NULL) != 1)
+ goto out;
+
+ if (no_etm)
+ SSL_set_options(srvr_ssl, SSL_OP_NO_ENCRYPT_THEN_MAC);
+
+ if (SSL_set_cipher_list(srvr_ssl, cs) != 1 ||
+ SSL_set_cipher_list(clnt_ssl, cs) != 1) {
+ ERR_print_errors_fp(stdout);
+ goto out;
+ }
+ sc_bio = SSL_get_rbio(srvr_ssl);
+
+ if (create_ssl_connection(clnt_ssl, srvr_ssl) != 1)
+ goto out;
+
+ if (debug)
+ printf("Channel established\n");
+
+ /* For record MTU values between 500 and 539, call DTLS_get_data_mtu()
+ * to query the payload MTU which will fit. */
+ for (i = 0; i < 30; i++) {
+ SSL_set_mtu(clnt_ssl, 500 + i);
+ mtus[i] = DTLS_get_data_mtu(clnt_ssl);
+ if (debug)
+ printf("%s%s payload MTU for record mtu %d = %"OSSLzu"\n",
+ cs, no_etm ? "-noEtM":"", 500 + i, mtus[i]);
+ if (mtus[i] == 0) {
+ fprintf(stderr,
+ "payload MTU failed with record MTU %d for %s\n",
+ 500 + i, cs);
+ goto out;
+ }
+ }
+
+ /* Now get out of the way */
+ SSL_set_mtu(clnt_ssl, 1000);
+
+ /* Now for all values in the range of payload MTUs, send
+ * a payload of that size and see what actual record size
+ * we end up with. */
+ for (s = mtus[0]; s <= mtus[29]; s++) {
+ size_t reclen;
+ if (SSL_write(clnt_ssl, buf, s) != (int)s) {
+ ERR_print_errors_fp(stdout);
+ goto out;
+ }
+ reclen = BIO_read(sc_bio, buf, sizeof(buf));
+ if (debug)
+ printf("record %"OSSLzu" for payload %"OSSLzu"\n", reclen, s);
+
+ for (i = 0; i < 30; i++) {
+ /* DTLS_get_data_mtu() with record MTU 500+i returned mtus[i] ... */
+
+ if (s <= mtus[i] && reclen > (size_t)(500 + i)) {
+ /* We sent a packet smaller than or equal to mtus[j] and
+ * that made a record *larger* than the record MTU 500+j! */
+ fprintf(stderr,
+ "%s: Payload MTU %"OSSLzu" reported for record MTU %d\n"
+ "but sending a payload of %"OSSLzu" made a record of %"OSSLzu"(too large)\n",
+ cs, mtus[i], 500 + i, s, reclen);
+ goto out;
+ }
+ if (s > mtus[i] && reclen <= (size_t)(500 + i)) {
+ /* We sent a *larger* packet than mtus[i] and that *still*
+ * fits within the record MTU 500+i, so DTLS_get_data_mtu()
+ * was overly pessimistic. */
+ fprintf(stderr,
+ "%s: Payload MTU %"OSSLzu" reported for record MTU %d\n"
+ "but sending a payload of %"OSSLzu" made a record of %"OSSLzu" (too small)\n",
+ cs, mtus[i], 500 + i, s, reclen);
+ goto out;
+ }
+ }
+ }
+ rv = 1;
+ if (SSL_USE_ETM(clnt_ssl))
+ rv = 2;
+ out:
+ SSL_free(clnt_ssl);
+ SSL_free(srvr_ssl);
+ return rv;
+}
+
+int main(void)
+{
+ SSL_CTX *ctx = SSL_CTX_new(DTLS_method());
+ STACK_OF(SSL_CIPHER) *ciphers;
+ int i, rv = 0;
+
+ SSL_CTX_set_psk_server_callback(ctx, srvr_psk_callback);
+ SSL_CTX_set_psk_client_callback(ctx, clnt_psk_callback);
+ SSL_CTX_set_security_level(ctx, 0);
+
+ /* We only care about iterating over each enc/mac; we don't
+ * want to repeat the test for each auth/kx variant.
+ * So keep life simple and only do (non-DH) PSK. */
+ if (!SSL_CTX_set_cipher_list(ctx, "PSK")) {
+ fprintf(stderr, "Failed to set PSK cipher list\n");
+ goto out;
+ }
+
+ ciphers = SSL_CTX_get_ciphers(ctx);
+ for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
+ const char *cipher_name = SSL_CIPHER_get_name(cipher);
+
+ /* As noted above, only one test for each enc/mac variant. */
+ if (strncmp(cipher_name, "PSK-", 4))
+ continue;
+
+ rv = mtu_test(ctx, cipher_name, 0);
+ if (!rv)
+ break;
+
+ printf("DTLS MTU test OK for %s\n", cipher_name);
+ if (rv == 1)
+ continue;
+
+ /* mtu_test() returns 2 if it used Encrypt-then-MAC */
+ rv = mtu_test(ctx, cipher_name, 1);
+ if (!rv)
+ break;
+
+ printf("DTLS MTU test OK for %s without Encrypt-then-MAC\n", cipher_name);
+ }
+ out:
+ SSL_CTX_free(ctx);
+
+ return !rv;
+}
diff --git a/test/recipes/70-test_bad_dtls.t b/test/recipes/80-test_dtls_mtu.t
similarity index 64%
copy from test/recipes/70-test_bad_dtls.t
copy to test/recipes/80-test_dtls_mtu.t
index a20db77..86d7de0 100644
--- a/test/recipes/70-test_bad_dtls.t
+++ b/test/recipes/80-test_dtls_mtu.t
@@ -10,11 +10,12 @@
use OpenSSL::Test;
use OpenSSL::Test::Utils;
-setup("test_bad_dtls");
+my $test_name = "test_dtls_mtu";
+setup($test_name);
-plan skip_all => "DTLSv1 is not supported by this OpenSSL build"
- if disabled("dtls1");
+plan skip_all => "$test_name needs DTLS and PSK support enabled"
+ if disabled("dtls1_2") || disabled("psk");
plan tests => 1;
-ok(run(test(["bad_dtls_test"])), "running bad_dtls_test");
+ok(run(test(["dtls_mtu_test"])), "running dtls_mtu_test");
diff --git a/test/recipes/70-test_wpacket.t b/test/recipes/90-test_overhead.t
similarity index 83%
copy from test/recipes/70-test_wpacket.t
copy to test/recipes/90-test_overhead.t
index 9170122..a9311bf 100644
--- a/test/recipes/70-test_wpacket.t
+++ b/test/recipes/90-test_overhead.t
@@ -10,11 +10,11 @@
use OpenSSL::Test;
use OpenSSL::Test::Utils;
-setup("test_wpacket");
+setup("test_overhead");
plan skip_all => "Only supported in no-shared builds"
if !disabled("shared");
plan tests => 1;
-ok(run(test(["wpackettest"])));
+ok(run(test(["cipher_overhead_test"])), "running cipher_overhead_test");
diff --git a/util/libssl.num b/util/libssl.num
index 7e00479..9f44b38 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -404,3 +404,4 @@ SSL_SESSION_get0_cipher 404 1_1_0 EXIST::FUNCTION:
SSL_SESSION_get0_id_context 405 1_1_0 EXIST::FUNCTION:
SSL_SESSION_set1_id 406 1_1_0 EXIST::FUNCTION:
SSL_CTX_set1_cert_store 407 1_1_1 EXIST::FUNCTION:
+DTLS_get_data_mtu 408 1_1_1 EXIST::FUNCTION:
More information about the openssl-commits
mailing list