summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorDoug Hogan <doug@cvs.openbsd.org>2015-07-09 07:47:03 +0000
committerDoug Hogan <doug@cvs.openbsd.org>2015-07-09 07:47:03 +0000
commitcc9ea8c5f861008ced2e46c23d9f9b7e417830ab (patch)
tree775a7214d37acecbae54bce67724a7778405211e /regress
parentba00e732386adb595123b4589d9d904c5969650d (diff)
Add tests for parsing TLS extension ALPN (RFC 7301).
The current libssl code does not pass these tests yet.
Diffstat (limited to 'regress')
-rw-r--r--regress/lib/libssl/unit/Makefile4
-rw-r--r--regress/lib/libssl/unit/tls_ext_alpn.c444
2 files changed, 446 insertions, 2 deletions
diff --git a/regress/lib/libssl/unit/Makefile b/regress/lib/libssl/unit/Makefile
index c0146159003..8e8b633e1d5 100644
--- a/regress/lib/libssl/unit/Makefile
+++ b/regress/lib/libssl/unit/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.1 2015/06/27 23:35:52 doug Exp $
+# $OpenBSD: Makefile,v 1.2 2015/07/09 07:47:02 doug Exp $
-TEST_CASES+= cipher_list
+TEST_CASES+= cipher_list tls_ext_alpn
REGRESS_TARGETS= all_tests
diff --git a/regress/lib/libssl/unit/tls_ext_alpn.c b/regress/lib/libssl/unit/tls_ext_alpn.c
new file mode 100644
index 00000000000..d792272bf8c
--- /dev/null
+++ b/regress/lib/libssl/unit/tls_ext_alpn.c
@@ -0,0 +1,444 @@
+/* $OpenBSD: tls_ext_alpn.c,v 1.1 2015/07/09 07:47:02 doug Exp $ */
+/*
+ * Copyright (c) 2015 Doug Hogan <doug@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Test TLS extension Application-Layer Protocol Negotiation (RFC 7301).
+ */
+#include <stdio.h>
+#include <openssl/ssl.h>
+
+#include "tests.h"
+
+extern int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
+ unsigned char *d, int n, int *al);
+extern int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p,
+ unsigned char *d, int n, int *al);
+
+/*
+ * In the ProtocolNameList, ProtocolNames must not include empty strings and
+ * byte strings must not be truncated.
+ *
+ * This uses some of the IANA approved protocol names from:
+ * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+ */
+
+/* Valid for client and server since it only has one name. */
+static uint8_t proto_single[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0f, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x0b, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x09, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31
+};
+
+/* Valid for client, but NOT server. Server must have exactly one name. */
+static uint8_t proto_multiple1[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x19, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x15, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x13, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31,
+ /* opaque ProtocolName<1..2^8-1> -- 'stun.nat' */
+ 0x09, /* len */
+ 0x73, 0x74, 0x75, 0x6e, 0x2e, 0x74, 0x75, 0x72, 0x6e
+};
+
+/* Valid for client, but NOT server. Server must have exactly one name. */
+static uint8_t proto_multiple2[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x1c, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x18, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x16, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31,
+ /* opaque ProtocolName<1..2^8-1> -- 'h2' */
+ 0x02, /* len */
+ 0x68, 0x32,
+ /* opaque ProtocolName<1..2^8-1> -- 'stun.nat' */
+ 0x09, /* len */
+ 0x73, 0x74, 0x75, 0x6e, 0x2e, 0x74, 0x75, 0x72, 0x6e
+};
+
+/* Valid for client, but NOT server. Server must have exactly one name. */
+static uint8_t proto_multiple3[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x20, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x1c, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x1a, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31,
+ /* opaque ProtocolName<1..2^8-1> -- 'h2' */
+ 0x02, /* len */
+ 0x68, 0x32,
+ /* opaque ProtocolName<1..2^8-1> -- 'stun.nat' */
+ 0x09, /* len */
+ 0x73, 0x74, 0x75, 0x6e, 0x2e, 0x74, 0x75, 0x72, 0x6e,
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+
+static uint8_t proto_empty[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions. */
+ 0x00, 0x00, /* none present. */
+};
+
+/* Invalid for both client and server. Length is wrong. */
+static uint8_t proto_invalid_len1[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x04, /* XXX len too large */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len2[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x02, /* XXX len too small */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len3[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x03, /* XXX len too small */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len4[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x06, /* XXX len too large */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len5[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x01, 0x08, /* XXX len too large */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len6[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x05, /* XXX len too small */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len7[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x06, /* XXX len too small */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+static uint8_t proto_invalid_len8[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0b, /* XXX len too large */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ 0x03, /* len */
+ 0x68, 0x32, 0x63
+};
+
+/* Invalid for client and server since it is missing data. */
+static uint8_t proto_invalid_missing1[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x06, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x04, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'h2c' */
+ /* XXX missing */
+};
+static uint8_t proto_invalid_missing2[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x00, /* XXX missing name list */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+};
+static uint8_t proto_invalid_missing3[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x02, /* XXX size is sufficient but missing data for name list */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+};
+static uint8_t proto_invalid_missing4[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x0a, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ /* XXX missing */
+};
+static uint8_t proto_invalid_missing5[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x1c, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x18, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x16, /* len of all names */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31,
+ /* opaque ProtocolName<1..2^8-1> -- 'h2' */
+ 0x02, /* len */
+ 0x68, 0x32,
+ /* XXX missing name */
+};
+static uint8_t proto_invalid_missing6[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x07, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x03, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x01, /* XXX len must be at least 2 */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x00, /* XXX len cannot be 0 */
+};
+static uint8_t proto_invalid_missing7[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x07, /* len */
+ /* ExtensionType extension_type */
+ 0x00, 0x10, /* ALPN */
+ /* opaque extension_data<0..2^16-1> */
+ 0x00, 0x03, /* len */
+ /* ProtocolName protocol_name_list<2..2^16-1> -- ALPN names */
+ 0x00, 0x02, /* XXX len is at least 2 but not correct. */
+ /* opaque ProtocolName<1..2^8-1> -- 'http/1.1' */
+ 0x00, /* XXX len cannot be 0 */
+};
+static uint8_t proto_invalid_missing8[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x00, 0x01, /* len */
+ /* ExtensionType extension_type */
+ 0x00, /* XXX need a 2 byte type */
+};
+static uint8_t proto_invalid_missing9[] = {
+ /* Extension extensions<0..2^16-1> -- All TLS extensions */
+ 0x0a, /* XXX need a 2 byte len */
+};
+
+
+#define CHECK_BOTH(c_val,s_val,proto) do { \
+ { \
+ unsigned char *p = proto; \
+ int al; \
+ CHECK(c_val == ssl_parse_clienthello_tlsext(s, &p, \
+ proto, sizeof(proto), &al)); \
+ p = proto; \
+ CHECK(s_val == ssl_parse_serverhello_tlsext(s, &p, \
+ proto, sizeof(proto), &al)); \
+ } \
+} while (0)
+
+static int dummy_alpn_cb(SSL *ssl, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in, unsigned int inlen,
+ void *arg);
+
+static int
+check_valid_alpn(SSL *s)
+{
+ const uint8_t str[] = {
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 /* http/1.1 */
+ };
+
+ /* Setup in order to test ALPN. */
+ CHECK(! SSL_set_alpn_protos(s, str, 9));
+ SSL_CTX_set_alpn_select_cb(s->ctx, dummy_alpn_cb, NULL);
+
+ /* Prerequisites to test these. */
+ CHECK(s->alpn_client_proto_list != NULL);
+ CHECK(s->ctx->alpn_select_cb != NULL);
+ CHECK(s->s3->tmp.finish_md_len == 0);
+
+ CHECK_BOTH(1, 1, proto_single);
+ CHECK_BOTH(1, 1, proto_empty);
+
+ /* Multiple protocol names are only valid for client */
+ CHECK_BOTH(1, 0, proto_multiple1);
+ CHECK_BOTH(1, 0, proto_multiple2);
+ CHECK_BOTH(1, 0, proto_multiple3);
+
+ return 1;
+}
+
+/*
+ * Some of the IANA approved IDs from:
+ * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+ */
+static int
+check_invalid_alpn(SSL *s)
+{
+ const uint8_t str[] = {
+ 0x08, /* len */
+ 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 /* http/1.1 */
+ };
+
+ /* Setup in order to test ALPN. */
+ CHECK(! SSL_set_alpn_protos(s, str, 9));
+ SSL_CTX_set_alpn_select_cb(s->ctx, dummy_alpn_cb, NULL);
+
+ /* Prerequisites to test these. */
+ CHECK(s->alpn_client_proto_list != NULL);
+ CHECK(s->ctx->alpn_select_cb != NULL);
+ CHECK(s->s3->tmp.finish_md_len == 0);
+
+ /* None of these are valid for client or server */
+ CHECK_BOTH(0, 0, proto_invalid_len1);
+ CHECK_BOTH(0, 0, proto_invalid_len2);
+ CHECK_BOTH(0, 0, proto_invalid_len3);
+ CHECK_BOTH(0, 0, proto_invalid_len4);
+ CHECK_BOTH(0, 0, proto_invalid_len5);
+ CHECK_BOTH(0, 0, proto_invalid_len6);
+ CHECK_BOTH(0, 0, proto_invalid_len7);
+ CHECK_BOTH(0, 0, proto_invalid_len8);
+ CHECK_BOTH(0, 0, proto_invalid_missing1);
+ CHECK_BOTH(0, 0, proto_invalid_missing2);
+ CHECK_BOTH(0, 0, proto_invalid_missing3);
+ CHECK_BOTH(0, 0, proto_invalid_missing4);
+ CHECK_BOTH(0, 0, proto_invalid_missing5);
+ CHECK_BOTH(0, 0, proto_invalid_missing6);
+ CHECK_BOTH(0, 0, proto_invalid_missing7);
+ CHECK_BOTH(0, 0, proto_invalid_missing8);
+ CHECK_BOTH(0, 0, proto_invalid_missing9);
+
+ return 1;
+}
+
+int
+dummy_alpn_cb(SSL *ssl __attribute__((unused)), const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in, unsigned int inlen,
+ void *arg __attribute__((unused)))
+{
+ *out = in;
+ *outlen = (unsigned char)inlen;
+
+ return 0;
+}
+
+int
+main(void)
+{
+ SSL_CTX *ctx = NULL;
+ SSL *s = NULL;
+ int rv = 1;
+
+ SSL_library_init();
+
+ CHECK_GOTO((ctx = SSL_CTX_new(TLSv1_2_client_method())) != NULL);
+ CHECK_GOTO((s = SSL_new(ctx)) != NULL);
+
+ if (!check_valid_alpn(s))
+ goto err;
+ if (!check_invalid_alpn(s))
+ goto err;
+
+ rv = 0;
+
+err:
+ SSL_CTX_free(ctx);
+ SSL_free(s);
+
+ if (!rv)
+ printf("PASS %s\n", __FILE__);
+ return rv;
+}