Add compression tests

Check whether we negotiate compression in various scenarios.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2814)
diff --git a/test/handshake_helper.c b/test/handshake_helper.c
index 88f6aec..99b6ad1 100644
--- a/test/handshake_helper.c
+++ b/test/handshake_helper.c
@@ -1207,6 +1207,9 @@
         ret->session_ticket = SSL_TEST_SESSION_TICKET_NO;
     else
         ret->session_ticket = SSL_TEST_SESSION_TICKET_YES;
+    ret->compression = (SSL_get_current_compression(client.ssl) == NULL)
+                       ? SSL_TEST_COMPRESSION_NO
+                       : SSL_TEST_COMPRESSION_YES;
     ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call;
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
diff --git a/test/handshake_helper.h b/test/handshake_helper.h
index bdbeabb..a9dd5c9 100644
--- a/test/handshake_helper.h
+++ b/test/handshake_helper.h
@@ -34,6 +34,7 @@
     ssl_servername_t servername;
     /* Session ticket status */
     ssl_session_ticket_t session_ticket;
+    ssl_compression_t compression;
     /* Was this called on the second context? */
     int session_ticket_do_not_call;
     char *client_npn_negotiated;
diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t
index f94a7d8..5f44334 100644
--- a/test/recipes/80-test_ssl_new.t
+++ b/test/recipes/80-test_ssl_new.t
@@ -29,7 +29,7 @@
 
 # We hard-code the number of tests to double-check that the globbing above
 # finds all files as expected.
-plan tests => 21;  # = scalar @conf_srcs
+plan tests => 22;  # = scalar @conf_srcs
 
 # Some test results depend on the configuration of enabled protocols. We only
 # verify generated sources in the default configuration.
@@ -63,6 +63,7 @@
   "18-dtls-renegotiate.conf" => disabled("dtls1_2"),
   "19-mac-then-encrypt.conf" => !$is_default_tls,
   "20-cert-select.conf" => !$is_default_tls || $no_dh || $no_dsa,
+  "22-compression.conf" => !$is_default_tls,
 );
 
 # Add your test here if it should be skipped for some compile-time
@@ -87,6 +88,7 @@
   "19-mac-then-encrypt.conf" => $no_pre_tls1_3,
   "20-cert-select.conf" => disabled("tls1_2") || $no_ec,
   "21-key-update.conf" => disabled("tls1_3"),
+  "22-compression.conf" => disabled("zlib") || $no_tls,
 );
 
 foreach my $conf (@conf_files) {
diff --git a/test/ssl-tests/22-compression.conf b/test/ssl-tests/22-compression.conf
new file mode 100644
index 0000000..999b008
--- /dev/null
+++ b/test/ssl-tests/22-compression.conf
@@ -0,0 +1,112 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 4
+
+test-0 = 0-tlsv1_2-both-compress
+test-1 = 1-tlsv1_2-client-compress
+test-2 = 2-tlsv1_2-server-compress
+test-3 = 3-tlsv1_2-neither-compress
+# ===========================================================
+
+[0-tlsv1_2-both-compress]
+ssl_conf = 0-tlsv1_2-both-compress-ssl
+
+[0-tlsv1_2-both-compress-ssl]
+server = 0-tlsv1_2-both-compress-server
+client = 0-tlsv1_2-both-compress-client
+
+[0-tlsv1_2-both-compress-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+Options = Compression
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-tlsv1_2-both-compress-client]
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+Options = Compression
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+CompressionExpected = Yes
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[1-tlsv1_2-client-compress]
+ssl_conf = 1-tlsv1_2-client-compress-ssl
+
+[1-tlsv1_2-client-compress-ssl]
+server = 1-tlsv1_2-client-compress-server
+client = 1-tlsv1_2-client-compress-client
+
+[1-tlsv1_2-client-compress-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-tlsv1_2-client-compress-client]
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+Options = Compression
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-1]
+CompressionExpected = No
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[2-tlsv1_2-server-compress]
+ssl_conf = 2-tlsv1_2-server-compress-ssl
+
+[2-tlsv1_2-server-compress-ssl]
+server = 2-tlsv1_2-server-compress-server
+client = 2-tlsv1_2-server-compress-client
+
+[2-tlsv1_2-server-compress-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+Options = Compression
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-tlsv1_2-server-compress-client]
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+CompressionExpected = No
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[3-tlsv1_2-neither-compress]
+ssl_conf = 3-tlsv1_2-neither-compress-ssl
+
+[3-tlsv1_2-neither-compress-ssl]
+server = 3-tlsv1_2-neither-compress-server
+client = 3-tlsv1_2-neither-compress-client
+
+[3-tlsv1_2-neither-compress-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-tlsv1_2-neither-compress-client]
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-3]
+CompressionExpected = No
+ExpectedResult = Success
+
+
diff --git a/test/ssl-tests/22-compression.conf.in b/test/ssl-tests/22-compression.conf.in
new file mode 100644
index 0000000..8d4d823
--- /dev/null
+++ b/test/ssl-tests/22-compression.conf.in
@@ -0,0 +1,127 @@
+# -*- mode: perl; -*-
+# Copyright 2016-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
+
+
+## Test Compression
+
+use strict;
+use warnings;
+
+package ssltests;
+use OpenSSL::Test::Utils;
+
+our @tests = ();
+
+our @tests_tls1_3 = (
+    {
+        name => "tlsv1_3-both-compress",
+        server => {
+            "Options" => "Compression"
+        },
+        client => {
+            "Options" => "Compression"
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "tlsv1_3-client-compress",
+        server => {
+        },
+        client => {
+            "Options" => "Compression"
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "tlsv1_3-server-compress",
+        server => {
+            "Options" => "Compression"
+        },
+        client => {
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "tlsv1_3-neither-compress",
+        server => {
+        },
+        client => {
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+);
+our @tests_tls1_2 = (
+    {
+        name => "tlsv1_2-both-compress",
+        server => {
+            "Options" => "Compression"
+        },
+        client => {
+            "Options" => "Compression",
+            "MaxProtocol" => "TLSv1.2"
+        },
+        test => {
+            "CompressionExpected" => "Yes",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "tlsv1_2-client-compress",
+        server => {
+        },
+        client => {
+            "Options" => "Compression",
+            "MaxProtocol" => "TLSv1.2"
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "tlsv1_2-server-compress",
+        server => {
+            "Options" => "Compression"
+        },
+        client => {
+            "MaxProtocol" => "TLSv1.2"
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "tlsv1_2-neither-compress",
+        server => {
+        },
+        client => {
+            "MaxProtocol" => "TLSv1.2"
+        },
+        test => {
+            "CompressionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+);
+
+push @tests, @tests_tls1_3 unless disabled("tls1_3");
+push @tests, @tests_tls1_2 unless alldisabled(("tls1_2", "tls1_1", "tls1",
+                                               "ssl3"));
diff --git a/test/ssl_test.c b/test/ssl_test.c
index 752de63..f5dfa97 100644
--- a/test/ssl_test.c
+++ b/test/ssl_test.c
@@ -146,6 +146,16 @@
     return 1;
 }
 
+static int check_compression(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
+{
+    if (result->compression != test_ctx->compression_expected) {
+        fprintf(stderr, "Client CompressionExpected mismatch, expected %s, got %s\n.",
+                ssl_compression_name(test_ctx->compression_expected),
+                ssl_compression_name(result->compression));
+        return 0;
+    }
+    return 1;
+}
 #ifndef OPENSSL_NO_NEXTPROTONEG
 static int check_npn(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
 {
@@ -259,6 +269,7 @@
         ret &= check_protocol(result, test_ctx);
         ret &= check_servername(result, test_ctx);
         ret &= check_session_ticket(result, test_ctx);
+        ret &= check_compression(result, test_ctx);
         ret &= (result->session_ticket_do_not_call == 0);
 #ifndef OPENSSL_NO_NEXTPROTONEG
         ret &= check_npn(result, test_ctx);
diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c
index f9e74d1..e746dbd 100644
--- a/test/ssl_test_ctx.c
+++ b/test/ssl_test_ctx.c
@@ -286,6 +286,29 @@
                      server);
 }
 
+/* CompressionExpected */
+
+static const test_enum ssl_compression[] = {
+    {"Yes", SSL_TEST_COMPRESSION_YES},
+    {"No", SSL_TEST_COMPRESSION_NO},
+};
+
+__owur static int parse_compression(SSL_TEST_CTX *test_ctx, const char *value)
+{
+    int ret_value;
+    if (!parse_enum(ssl_compression, OSSL_NELEM(ssl_compression),
+                    &ret_value, value)) {
+        return 0;
+    }
+    test_ctx->compression_expected = ret_value;
+    return 1;
+}
+
+const char *ssl_compression_name(ssl_compression_t comp)
+{
+    return enum_name(ssl_compression, OSSL_NELEM(ssl_compression), comp);
+}
+
 /* Method */
 
 static const test_enum ssl_test_methods[] = {
@@ -541,6 +564,7 @@
     { "ExpectedProtocol", &parse_protocol },
     { "ExpectedServerName", &parse_expected_servername },
     { "SessionTicketExpected", &parse_session_ticket },
+    { "CompressionExpected", &parse_compression },
     { "Method", &parse_test_method },
     { "ExpectedNPNProtocol", &parse_test_expected_npn_protocol },
     { "ExpectedALPNProtocol", &parse_test_expected_alpn_protocol },
diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h
index 499e314..418a4f2 100644
--- a/test/ssl_test_ctx.h
+++ b/test/ssl_test_ctx.h
@@ -52,6 +52,11 @@
 } ssl_session_ticket_t;
 
 typedef enum {
+    SSL_TEST_COMPRESSION_NO = 0, /* Default */
+    SSL_TEST_COMPRESSION_YES
+} ssl_compression_t;
+
+typedef enum {
     SSL_TEST_METHOD_TLS = 0, /* Default */
     SSL_TEST_METHOD_DTLS
 } ssl_test_method_t;
@@ -163,6 +168,7 @@
      */
     ssl_servername_t expected_servername;
     ssl_session_ticket_t session_ticket_expected;
+    ssl_compression_t compression_expected;
     /* The expected NPN/ALPN protocol to negotiate. */
     char *expected_npn_protocol;
     char *expected_alpn_protocol;
@@ -192,6 +198,7 @@
 const char *ssl_servername_callback_name(ssl_servername_callback_t
                                          servername_callback);
 const char *ssl_session_ticket_name(ssl_session_ticket_t server);
+const char *ssl_compression_name(ssl_compression_t server);
 const char *ssl_test_method_name(ssl_test_method_t method);
 const char *ssl_handshake_mode_name(ssl_handshake_mode_t mode);
 const char *ssl_ct_validation_name(ssl_ct_validation_t mode);
diff --git a/test/ssl_test_ctx_test.c b/test/ssl_test_ctx_test.c
index 36d17a7..5c1e427 100644
--- a/test/ssl_test_ctx_test.c
+++ b/test/ssl_test_ctx_test.c
@@ -173,6 +173,12 @@
                 ssl_session_ticket_name(ctx2->session_ticket_expected));
         return 0;
     }
+    if (ctx->compression_expected != ctx2->compression_expected) {
+        fprintf(stderr, "ComrpessionExpected mismatch: %s vs %s.\n",
+                ssl_compression_name(ctx->compression_expected),
+                ssl_compression_name(ctx2->compression_expected));
+        return 0;
+    }
     if (!strings_equal("ExpectedNPNProtocol", ctx->expected_npn_protocol,
                        ctx2->expected_npn_protocol))
         return 0;
@@ -250,6 +256,7 @@
     fixture.expected_ctx->expected_protocol = TLS1_1_VERSION;
     fixture.expected_ctx->expected_servername = SSL_TEST_SERVERNAME_SERVER2;
     fixture.expected_ctx->session_ticket_expected = SSL_TEST_SESSION_TICKET_YES;
+    fixture.expected_ctx->compression_expected = SSL_TEST_COMPRESSION_NO;
     fixture.expected_ctx->resumption_expected = 1;
 
     fixture.expected_ctx->extra.client.verify_callback =
@@ -284,6 +291,7 @@
     "ssltest_unknown_servername",
     "ssltest_unknown_servername_callback",
     "ssltest_unknown_session_ticket_expected",
+    "ssltest_unknown_compression_expected",
     "ssltest_unknown_method",
     "ssltest_unknown_handshake_mode",
     "ssltest_unknown_resumption_expected",
diff --git a/test/ssl_test_ctx_test.conf b/test/ssl_test_ctx_test.conf
index a062d75..86d40e5 100644
--- a/test/ssl_test_ctx_test.conf
+++ b/test/ssl_test_ctx_test.conf
@@ -72,6 +72,9 @@
 [ssltest_unknown_session_ticket_expected]
 SessionTicketExpected = Foo
 
+[ssltest_unknown_compression_expected]
+CompressionExpected = Foo
+
 [ssltest_unknown_method]
 Method = TLS2