[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