diff options
author | Doug Hogan <doug@cvs.openbsd.org> | 2015-07-09 07:47:03 +0000 |
---|---|---|
committer | Doug Hogan <doug@cvs.openbsd.org> | 2015-07-09 07:47:03 +0000 |
commit | cc9ea8c5f861008ced2e46c23d9f9b7e417830ab (patch) | |
tree | 775a7214d37acecbae54bce67724a7778405211e /regress | |
parent | ba00e732386adb595123b4589d9d904c5969650d (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/Makefile | 4 | ||||
-rw-r--r-- | regress/lib/libssl/unit/tls_ext_alpn.c | 444 |
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; +} |