summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorDoug Hogan <doug@cvs.openbsd.org>2017-08-11 05:06:35 +0000
committerDoug Hogan <doug@cvs.openbsd.org>2017-08-11 05:06:35 +0000
commita859899f94a0f58e05defaf2bdbf4c46a35c49bf (patch)
tree11de05fce285ef306b36250e2688963f1aa515ae /regress
parentdf7f015e20610f5f9a3025ee3f5917bfbb87c611 (diff)
Rewrite the ECPointFormats TLS extension handling using CBB/CBS and the
new extension framework. input + ok jsing@
Diffstat (limited to 'regress')
-rw-r--r--regress/lib/libssl/tlsext/tlsexttest.c471
1 files changed, 470 insertions, 1 deletions
diff --git a/regress/lib/libssl/tlsext/tlsexttest.c b/regress/lib/libssl/tlsext/tlsexttest.c
index 792ccfe706e..5a7a34c56c0 100644
--- a/regress/lib/libssl/tlsext/tlsexttest.c
+++ b/regress/lib/libssl/tlsext/tlsexttest.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tlsexttest.c,v 1.3 2017/07/24 17:42:14 jsing Exp $ */
+/* $OpenBSD: tlsexttest.c,v 1.4 2017/08/11 05:06:34 doug Exp $ */
/*
* Copyright (c) 2017 Joel Sing <jsing@openbsd.org>
*
@@ -33,6 +33,23 @@ hexdump(const unsigned char *buf, size_t len)
fprintf(stderr, "\n");
}
+static void
+compare_data(const uint8_t *recv, size_t recv_len, const uint8_t *expect,
+ size_t expect_len)
+{
+ fprintf(stderr, "received:\n");
+ hexdump(recv, recv_len);
+
+ fprintf(stderr, "test data:\n");
+ hexdump(expect, expect_len);
+}
+
+#define FAIL(msg, ...) \
+do { \
+ fprintf(stderr, "[%s:%d] FAIL: ", __FILE__, __LINE__); \
+ fprintf(stderr, msg, ##__VA_ARGS__); \
+} while(0)
+
/*
* Renegotiation Indication - RFC 5746.
*/
@@ -522,6 +539,455 @@ test_tlsext_sni_serverhello(void)
return (failure);
}
+/*
+ * ECPointFormats - RFC 4492 section 5.1.2 (Supported Point Formats).
+ *
+ * Examples are from the RFC. Both client and server have the same build and
+ * parse but the needs differ.
+ */
+
+static uint8_t tlsext_ecpf_hello_uncompressed_val[] = {
+ TLSEXT_ECPOINTFORMAT_uncompressed
+};
+static uint8_t tlsext_ecpf_hello_uncompressed[] = {
+ 0x01,
+ 0x00 /* TLSEXT_ECPOINTFORMAT_uncompressed */
+};
+
+static uint8_t tlsext_ecpf_hello_prime[] = {
+ 0x01,
+ 0x01 /* TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime */
+};
+
+static uint8_t tlsext_ecpf_hello_prefer_order_val[] = {
+ TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
+ TLSEXT_ECPOINTFORMAT_uncompressed,
+ TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
+};
+static uint8_t tlsext_ecpf_hello_prefer_order[] = {
+ 0x03,
+ 0x01, /* TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime */
+ 0x00, /* TLSEXT_ECPOINTFORMAT_uncompressed */
+ 0x02 /* TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 */
+};
+
+static int
+test_tlsext_ecpf_clienthello(void)
+{
+ uint8_t *data = NULL;
+ SSL_CTX *ssl_ctx = NULL;
+ SSL *ssl = NULL;
+ size_t dlen;
+ int failure, alert;
+ CBB cbb;
+ CBS cbs;
+
+ failure = 1;
+
+ CBB_init(&cbb, 0);
+
+ if ((ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL)
+ errx(1, "failed to create SSL_CTX");
+ if ((ssl = SSL_new(ssl_ctx)) == NULL)
+ errx(1, "failed to create SSL");
+
+ /*
+ * Default ciphers include EC so we need it by default.
+ */
+ if (!tlsext_ecpf_clienthello_needs(ssl)) {
+ FAIL("clienthello should need ECPointFormats for default "
+ "ciphers\n");
+ goto err;
+ }
+
+ /*
+ * Exclude EC cipher suites so we can test not including it.
+ */
+ if (!SSL_set_cipher_list(ssl, "ALL:!ECDHE:!ECDH")) {
+ FAIL("clienthello should be able to set cipher list\n");
+ goto err;
+ }
+ if (tlsext_ecpf_clienthello_needs(ssl)) {
+ FAIL("clienthello should not need ECPointFormats\n");
+ goto err;
+ }
+
+ /*
+ * Use libtls default for the rest of the testing
+ */
+ if (!SSL_set_cipher_list(ssl, "TLSv1.2+AEAD+ECDHE")) {
+ FAIL("clienthello should be able to set cipher list\n");
+ goto err;
+ }
+ if (!tlsext_ecpf_clienthello_needs(ssl)) {
+ FAIL("clienthello should need ECPointFormats\n");
+ goto err;
+ }
+
+ /*
+ * The default ECPointFormats should only have uncompressed
+ */
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ if (!tlsext_ecpf_clienthello_build(ssl, &cbb)) {
+ FAIL("clienthello failed to build ECPointFormats\n");
+ goto err;
+ }
+
+ if (!CBB_finish(&cbb, &data, &dlen))
+ errx(1, "failed to finish CBB");
+
+ if (dlen != sizeof(tlsext_ecpf_hello_uncompressed)) {
+ FAIL("got clienthello ECPointFormats with length %zu, "
+ "want length %zu\n", dlen,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ compare_data(data, dlen, tlsext_ecpf_hello_uncompressed,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ goto err;
+ }
+
+ if (memcmp(data, tlsext_ecpf_hello_uncompressed, dlen) != 0) {
+ FAIL("clienthello ECPointFormats differs:\n");
+ compare_data(data, dlen, tlsext_ecpf_hello_uncompressed,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ goto err;
+ }
+
+ /*
+ * Make sure we can parse the default.
+ */
+ CBB_cleanup(&cbb);
+ CBB_init(&cbb, 0);
+ free(data);
+ data = NULL;
+
+ SSL_SESSION_free(ssl->session);
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ CBS_init(&cbs, tlsext_ecpf_hello_uncompressed,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ if (!tlsext_ecpf_clienthello_parse(ssl, &cbs, &alert)) {
+ FAIL("failed to parse clienthello ECPointFormats\n");
+ goto err;
+ }
+
+ if (SSI(ssl)->tlsext_ecpointformatlist_length !=
+ sizeof(tlsext_ecpf_hello_uncompressed_val)) {
+ FAIL("no tlsext_ecpointformats from clienthello "
+ "ECPointFormats\n");
+ goto err;
+ }
+
+ if (memcmp(SSI(ssl)->tlsext_ecpointformatlist,
+ tlsext_ecpf_hello_uncompressed_val,
+ sizeof(tlsext_ecpf_hello_uncompressed_val)) != 0) {
+ FAIL("clienthello had an incorrect ECPointFormats entry\n");
+ goto err;
+ }
+
+ /*
+ * Test with a custom order.
+ */
+ CBB_cleanup(&cbb);
+ CBB_init(&cbb, 0);
+ free(data);
+ data = NULL;
+
+ SSL_SESSION_free(ssl->session);
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ if ((ssl->internal->tlsext_ecpointformatlist = malloc(sizeof(uint8_t) * 3)) == NULL) {
+ FAIL("client could not malloc\n");
+ goto err;
+ }
+ ssl->internal->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ ssl->internal->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_uncompressed;
+ ssl->internal->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+ ssl->internal->tlsext_ecpointformatlist_length = 3;
+
+ if (!tlsext_ecpf_clienthello_needs(ssl)) {
+ FAIL("clienthello should need ECPointFormats with a custom "
+ "format\n");
+ goto err;
+ }
+
+ if (!tlsext_ecpf_clienthello_build(ssl, &cbb)) {
+ FAIL("clienthello failed to build ECPointFormats\n");
+ goto err;
+ }
+
+ if (!CBB_finish(&cbb, &data, &dlen))
+ errx(1, "failed to finish CBB");
+
+ if (dlen != sizeof(tlsext_ecpf_hello_prefer_order)) {
+ FAIL("got clienthello ECPointFormats with length %zu, "
+ "want length %zu\n", dlen,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ compare_data(data, dlen, tlsext_ecpf_hello_prefer_order,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ goto err;
+ }
+
+ if (memcmp(data, tlsext_ecpf_hello_prefer_order, dlen) != 0) {
+ FAIL("clienthello ECPointFormats differs:\n");
+ compare_data(data, dlen, tlsext_ecpf_hello_prefer_order,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ goto err;
+ }
+
+ /*
+ * Make sure that we can parse this custom order.
+ */
+ CBB_cleanup(&cbb);
+ CBB_init(&cbb, 0);
+ free(data);
+ data = NULL;
+
+ SSL_SESSION_free(ssl->session);
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ /* Reset the custom list so we go back to the default uncompressed. */
+ free(ssl->internal->tlsext_ecpointformatlist);
+ ssl->internal->tlsext_ecpointformatlist = NULL;
+ ssl->internal->tlsext_ecpointformatlist_length = 0;
+
+ CBS_init(&cbs, tlsext_ecpf_hello_prefer_order,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ if (!tlsext_ecpf_clienthello_parse(ssl, &cbs, &alert)) {
+ FAIL("failed to parse clienthello ECPointFormats\n");
+ goto err;
+ }
+
+ if (SSI(ssl)->tlsext_ecpointformatlist_length !=
+ sizeof(tlsext_ecpf_hello_prefer_order_val)) {
+ FAIL("no tlsext_ecpointformats from clienthello "
+ "ECPointFormats\n");
+ goto err;
+ }
+
+ if (memcmp(SSI(ssl)->tlsext_ecpointformatlist,
+ tlsext_ecpf_hello_prefer_order_val,
+ sizeof(tlsext_ecpf_hello_prefer_order_val)) != 0) {
+ FAIL("clienthello had an incorrect ECPointFormats entry\n");
+ goto err;
+ }
+
+
+ failure = 0;
+
+ err:
+ CBB_cleanup(&cbb);
+ SSL_CTX_free(ssl_ctx);
+ SSL_free(ssl);
+ free(data);
+
+ return (failure);
+}
+
+
+static int
+test_tlsext_ecpf_serverhello(void)
+{
+ uint8_t *data = NULL;
+ SSL_CTX *ssl_ctx = NULL;
+ SSL *ssl = NULL;
+ size_t dlen;
+ int failure, alert;
+ CBB cbb;
+ CBS cbs;
+
+ failure = 1;
+
+ CBB_init(&cbb, 0);
+
+ if ((ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL)
+ errx(1, "failed to create SSL_CTX");
+ if ((ssl = SSL_new(ssl_ctx)) == NULL)
+ errx(1, "failed to create SSL");
+
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ /* Setup the state so we can call needs. */
+ if ((S3I(ssl)->hs.new_cipher =
+ ssl3_get_cipher_by_id(TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305))
+ == NULL) {
+ FAIL("serverhello cannot find cipher\n");
+ goto err;
+ }
+ if ((SSI(ssl)->tlsext_ecpointformatlist = malloc(sizeof(uint8_t)))
+ == NULL) {
+ FAIL("server could not malloc\n");
+ goto err;
+ }
+ SSI(ssl)->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ SSI(ssl)->tlsext_ecpointformatlist_length = 1;
+
+ if (!tlsext_ecpf_serverhello_needs(ssl)) {
+ FAIL("serverhello should need ECPointFormats now\n");
+ goto err;
+ }
+
+ /*
+ * The server will ignore the session list and use either a custom
+ * list or the default (uncompressed).
+ */
+ if (!tlsext_ecpf_serverhello_build(ssl, &cbb)) {
+ FAIL("serverhello failed to build ECPointFormats\n");
+ goto err;
+ }
+
+ if (!CBB_finish(&cbb, &data, &dlen))
+ errx(1, "failed to finish CBB");
+
+ if (dlen != sizeof(tlsext_ecpf_hello_uncompressed)) {
+ FAIL("got serverhello ECPointFormats with length %zu, "
+ "want length %zu\n", dlen,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ compare_data(data, dlen, tlsext_ecpf_hello_uncompressed,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ goto err;
+ }
+
+ if (memcmp(data, tlsext_ecpf_hello_uncompressed, dlen) != 0) {
+ FAIL("serverhello ECPointFormats differs:\n");
+ compare_data(data, dlen, tlsext_ecpf_hello_uncompressed,
+ sizeof(tlsext_ecpf_hello_uncompressed));
+ goto err;
+ }
+
+ /*
+ * Cannot parse a non-default list without at least uncompressed.
+ */
+ CBB_cleanup(&cbb);
+ CBB_init(&cbb, 0);
+ free(data);
+ data = NULL;
+
+ SSL_SESSION_free(ssl->session);
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ CBS_init(&cbs, tlsext_ecpf_hello_prime,
+ sizeof(tlsext_ecpf_hello_prime));
+ if (tlsext_ecpf_serverhello_parse(ssl, &cbs, &alert)) {
+ FAIL("must include uncompressed in serverhello ECPointFormats\n");
+ goto err;
+ }
+
+ /*
+ * Test with a custom order that replaces the default uncompressed.
+ */
+ CBB_cleanup(&cbb);
+ CBB_init(&cbb, 0);
+ free(data);
+ data = NULL;
+
+ SSL_SESSION_free(ssl->session);
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ /* Add a session list even though it will be ignored. */
+ if ((SSI(ssl)->tlsext_ecpointformatlist = malloc(sizeof(uint8_t)))
+ == NULL) {
+ FAIL("server could not malloc\n");
+ goto err;
+ }
+ SSI(ssl)->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+ SSI(ssl)->tlsext_ecpointformatlist_length = 1;
+
+ /* Replace the default list with a custom one. */
+ if ((ssl->internal->tlsext_ecpointformatlist = malloc(sizeof(uint8_t) * 3)) == NULL) {
+ FAIL("server could not malloc\n");
+ goto err;
+ }
+ ssl->internal->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ ssl->internal->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_uncompressed;
+ ssl->internal->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+ ssl->internal->tlsext_ecpointformatlist_length = 3;
+
+ if (!tlsext_ecpf_serverhello_needs(ssl)) {
+ FAIL("serverhello should need ECPointFormats\n");
+ goto err;
+ }
+
+ if (!tlsext_ecpf_serverhello_build(ssl, &cbb)) {
+ FAIL("serverhello failed to build ECPointFormats\n");
+ goto err;
+ }
+
+ if (!CBB_finish(&cbb, &data, &dlen))
+ errx(1, "failed to finish CBB");
+
+ if (dlen != sizeof(tlsext_ecpf_hello_prefer_order)) {
+ FAIL("got serverhello ECPointFormats with length %zu, "
+ "want length %zu\n", dlen,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ compare_data(data, dlen, tlsext_ecpf_hello_prefer_order,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ goto err;
+ }
+
+ if (memcmp(data, tlsext_ecpf_hello_prefer_order, dlen) != 0) {
+ FAIL("serverhello ECPointFormats differs:\n");
+ compare_data(data, dlen, tlsext_ecpf_hello_prefer_order,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ goto err;
+ }
+
+ /*
+ * Should be able to parse the custom list into a session list.
+ */
+ CBB_cleanup(&cbb);
+ CBB_init(&cbb, 0);
+ free(data);
+ data = NULL;
+
+ SSL_SESSION_free(ssl->session);
+ if ((ssl->session = SSL_SESSION_new()) == NULL)
+ errx(1, "failed to create session");
+
+ /* Reset back to the default (uncompressed) */
+ free(ssl->internal->tlsext_ecpointformatlist);
+ ssl->internal->tlsext_ecpointformatlist = NULL;
+ ssl->internal->tlsext_ecpointformatlist_length = 0;
+
+ CBS_init(&cbs, tlsext_ecpf_hello_prefer_order,
+ sizeof(tlsext_ecpf_hello_prefer_order));
+ if (!tlsext_ecpf_serverhello_parse(ssl, &cbs, &alert)) {
+ FAIL("failed to parse serverhello ECPointFormats\n");
+ goto err;
+ }
+
+ if (SSI(ssl)->tlsext_ecpointformatlist_length !=
+ sizeof(tlsext_ecpf_hello_prefer_order_val)) {
+ FAIL("no tlsext_ecpointformats from serverhello "
+ "ECPointFormats\n");
+ goto err;
+ }
+
+ if (memcmp(SSI(ssl)->tlsext_ecpointformatlist,
+ tlsext_ecpf_hello_prefer_order_val,
+ sizeof(tlsext_ecpf_hello_prefer_order_val)) != 0) {
+ FAIL("serverhello had an incorrect ECPointFormats entry\n");
+ goto err;
+ }
+
+ failure = 0;
+
+ err:
+ CBB_cleanup(&cbb);
+ SSL_CTX_free(ssl_ctx);
+ SSL_free(ssl);
+ free(data);
+
+ return (failure);
+}
+
int
main(int argc, char **argv)
{
@@ -535,5 +1001,8 @@ main(int argc, char **argv)
failed |= test_tlsext_sni_clienthello();
failed |= test_tlsext_sni_serverhello();
+ failed |= test_tlsext_ecpf_clienthello();
+ failed |= test_tlsext_ecpf_serverhello();
+
return (failed);
}