From 10e3b663a1750bc234861ed33ad78e8088b5cb47 Mon Sep 17 00:00:00 2001 From: beck <> Date: Thu, 24 Jan 2019 02:56:41 +0000 Subject: Add server side of versions, keyshare, and client and server of cookie extensions for tls1.3. versions is currently defanged to ignore its result until tls13 server side wired in full, so that server side code still works today when we only support tls 1.2 ok bcook@ tb@ jsing@ --- src/lib/libssl/s3_lib.c | 6 +- src/lib/libssl/ssl_locl.h | 5 +- src/lib/libssl/ssl_tlsext.c | 308 ++++++++++++++++++-- src/lib/libssl/ssl_tlsext.h | 10 +- src/regress/lib/libssl/tlsext/tlsexttest.c | 441 ++++++++++++++++++++++++++++- 5 files changed, 742 insertions(+), 28 deletions(-) diff --git a/src/lib/libssl/s3_lib.c b/src/lib/libssl/s3_lib.c index 36142f0415..6e4e8eb1d3 100644 --- a/src/lib/libssl/s3_lib.c +++ b/src/lib/libssl/s3_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: s3_lib.c,v 1.181 2019/01/24 01:50:41 beck Exp $ */ +/* $OpenBSD: s3_lib.c,v 1.182 2019/01/24 02:56:41 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1569,6 +1569,7 @@ ssl3_free(SSL *s) freezero(S3I(s)->hs_tls13.x25519_private, X25519_KEY_LENGTH); freezero(S3I(s)->hs_tls13.x25519_public, X25519_KEY_LENGTH); freezero(S3I(s)->hs_tls13.x25519_peer_public, X25519_KEY_LENGTH); + freezero(S3I(s)->hs_tls13.cookie, S3I(s)->hs_tls13.cookie_len); sk_X509_NAME_pop_free(S3I(s)->tmp.ca_names, X509_NAME_free); @@ -1605,6 +1606,9 @@ ssl3_clear(SSL *s) freezero(S3I(s)->hs_tls13.x25519_private, X25519_KEY_LENGTH); freezero(S3I(s)->hs_tls13.x25519_public, X25519_KEY_LENGTH); freezero(S3I(s)->hs_tls13.x25519_peer_public, X25519_KEY_LENGTH); + freezero(S3I(s)->hs_tls13.cookie, S3I(s)->hs_tls13.cookie_len); + S3I(s)->hs_tls13.cookie = NULL; + S3I(s)->hs_tls13.cookie_len = 0; S3I(s)->hs.extensions_seen = 0; diff --git a/src/lib/libssl/ssl_locl.h b/src/lib/libssl/ssl_locl.h index 5d560f5935..90aca26625 100644 --- a/src/lib/libssl/ssl_locl.h +++ b/src/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.232 2019/01/24 01:50:41 beck Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.233 2019/01/24 02:56:41 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -448,6 +448,9 @@ typedef struct ssl_handshake_tls13_st { uint8_t *x25519_peer_public; struct tls13_secrets *secrets; + + uint8_t *cookie; + size_t cookie_len; } SSL_HANDSHAKE_TLS13; typedef struct ssl_ctx_internal_st { diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c index 35c764f646..20acb43ccf 100644 --- a/src/lib/libssl/ssl_tlsext.c +++ b/src/lib/libssl/ssl_tlsext.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_tlsext.c,v 1.35 2019/01/24 01:50:41 beck Exp $ */ +/* $OpenBSD: ssl_tlsext.c,v 1.36 2019/01/24 02:56:41 beck Exp $ */ /* * Copyright (c) 2016, 2017, 2019 Joel Sing * Copyright (c) 2017 Doug Hogan @@ -1273,7 +1273,7 @@ tlsext_keyshare_client_build(SSL *s, CBB *cbb) return 1; -err: + err: freezero(public_key, X25519_KEY_LENGTH); freezero(private_key, X25519_KEY_LENGTH); @@ -1283,24 +1283,105 @@ err: int tlsext_keyshare_server_parse(SSL *s, CBS *cbs, int *alert) { - /* XXX we accept this but currently ignore it */ - if (!CBS_skip(cbs, CBS_len(cbs))) { - *alert = TLS1_AD_INTERNAL_ERROR; - return 0; + CBS client_shares; + CBS key_exchange; + uint16_t group; + size_t out_len; + int ret = 0; + + if (!CBS_get_u16_length_prefixed(cbs, &client_shares)) + goto err; + + if (CBS_len(cbs) != 0) + goto err; + + while (CBS_len(&client_shares) > 0) { + + /* Unpack client share. */ + if (!CBS_get_u16(&client_shares, &group)) + goto err; + + if (!CBS_get_u16_length_prefixed(&client_shares, &key_exchange)) + goto err; + + /* + * Skip this client share if not X25519 + * XXX support other groups later. + * XXX enforce group can only appear once. + */ + if (S3I(s)->hs_tls13.x25519_peer_public != NULL || + group != tls1_ec_nid2curve_id(NID_X25519)) + continue; + + if (CBS_len(&key_exchange) != X25519_KEY_LENGTH) + goto err; + + if (!CBS_stow(&key_exchange, &S3I(s)->hs_tls13.x25519_peer_public, + &out_len)) + goto err; + + ret = 1; } - return 1; + return ret; + + err: + *alert = SSL_AD_DECODE_ERROR; + return 0; } int tlsext_keyshare_server_needs(SSL *s) { - return (!SSL_IS_DTLS(s) && s->version >= TLS1_3_VERSION); + size_t idx; + + if (SSL_IS_DTLS(s) || s->version < TLS1_3_VERSION) + return 0; + if (tls_extension_find(TLSEXT_TYPE_key_share, &idx) == NULL) + return 0; + /* XXX move seen check to a function */ + return ((S3I(s)->hs.extensions_seen & (1 << idx)) != 0); } int tlsext_keyshare_server_build(SSL *s, CBB *cbb) { + uint8_t *public_key = NULL, *private_key = NULL; + CBB key_exchange; + + /* XXX deduplicate with client code */ + + /* X25519 */ + if (S3I(s)->hs_tls13.x25519_peer_public == NULL) + return 0; + + /* Generate X25519 key pair. */ + if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + if ((private_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + X25519_keypair(public_key, private_key); + + /* Add the group and serialize the public key. */ + if (!CBB_add_u16(cbb, tls1_ec_nid2curve_id(NID_X25519))) + goto err; + if (!CBB_add_u16_length_prefixed(cbb, &key_exchange)) + goto err; + if (!CBB_add_bytes(&key_exchange, public_key, X25519_KEY_LENGTH)) + goto err; + + if (!CBB_flush(cbb)) + goto err; + + S3I(s)->hs_tls13.x25519_public = public_key; + S3I(s)->hs_tls13.x25519_private = private_key; + + return 1; + + err: + freezero(public_key, X25519_KEY_LENGTH); + freezero(private_key, X25519_KEY_LENGTH); + return 0; } @@ -1321,8 +1402,10 @@ tlsext_keyshare_client_parse(SSL *s, CBS *cbs, int *alert) if (!CBS_get_u16_length_prefixed(cbs, &key_exchange)) goto err; + if (CBS_len(&key_exchange) != X25519_KEY_LENGTH) goto err; + if (!CBS_stow(&key_exchange, &S3I(s)->hs_tls13.x25519_peer_public, &out_len)) goto err; @@ -1340,11 +1423,9 @@ tlsext_keyshare_client_parse(SSL *s, CBS *cbs, int *alert) int tlsext_versions_client_needs(SSL *s) { - /* XXX once this gets initialized when we get tls13_client.c */ - if (S3I(s)->hs_tls13.max_version == 0) + if (SSL_IS_DTLS(s)) return 0; - return (!SSL_IS_DTLS(s) && S3I(s)->hs_tls13.max_version >= - TLS1_3_VERSION); + return (S3I(s)->hs_tls13.max_version >= TLS1_3_VERSION); } int @@ -1378,13 +1459,48 @@ tlsext_versions_client_build(SSL *s, CBB *cbb) int tlsext_versions_server_parse(SSL *s, CBS *cbs, int *alert) { - /* XXX we accept this but currently ignore it */ - if (!CBS_skip(cbs, CBS_len(cbs))) { - *alert = TLS1_AD_INTERNAL_ERROR; - return 0; + CBS versions; + uint16_t version; + uint16_t max, min; + uint16_t matched_version = 0; + + max = S3I(s)->hs_tls13.max_version; + min = S3I(s)->hs_tls13.min_version; + + if (!CBS_get_u8_length_prefixed(cbs, &versions)) + goto err; + + while (CBS_len(&versions) > 0) { + if (!CBS_get_u16(&versions, &version)) + goto err; + /* + * XXX What is below implements client preference, and + * ignores any server preference entirely. + */ + if (matched_version == 0 && version >= min && version <= max) + matched_version = version; } - return 1; + /* + * XXX if we haven't mached a version we should + * fail - but we currently need to succeed to + * ignore this before the server code for 1.3 + * is set up and initialized. + */ + if (max == 0) + return 1; /* XXX */ + + if (matched_version != 0) { + s->version = matched_version; + return 1; + } + + *alert = SSL_AD_PROTOCOL_VERSION; + return 0; + +err: + *alert = SSL_AD_DECODE_ERROR; + return 0; } int @@ -1396,7 +1512,11 @@ tlsext_versions_server_needs(SSL *s) int tlsext_versions_server_build(SSL *s, CBB *cbb) { - return 0; + if (!CBB_add_u16(cbb, TLS1_3_VERSION)) + return 0; + /* XXX set 1.2 in legacy version? */ + + return 1; } int @@ -1409,12 +1529,147 @@ tlsext_versions_client_parse(SSL *s, CBS *cbs, int *alert) return 0; } + if (selected_version < TLS1_3_VERSION) { + *alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + /* XXX test between min and max once initialization code goes in */ S3I(s)->hs_tls13.server_version = selected_version; return 1; } + +/* + * Cookie - RFC 8446 section 4.2.2. + */ + +int +tlsext_cookie_client_needs(SSL *s) +{ + if (SSL_IS_DTLS(s)) + return 0; + if (S3I(s)->hs_tls13.max_version < TLS1_3_VERSION) + return 0; + return (S3I(s)->hs_tls13.cookie_len > 0 && + S3I(s)->hs_tls13.cookie != NULL); +} + +int +tlsext_cookie_client_build(SSL *s, CBB *cbb) +{ + CBB cookie; + + if (!CBB_add_u16_length_prefixed(cbb, &cookie)) + return 0; + + if (!CBB_add_bytes(&cookie, S3I(s)->hs_tls13.cookie, + S3I(s)->hs_tls13.cookie_len)) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +tlsext_cookie_server_parse(SSL *s, CBS *cbs, int *alert) +{ + CBS cookie; + + if (!CBS_get_u16_length_prefixed(cbs, &cookie)) + goto err; + + if (CBS_len(&cookie) != S3I(s)->hs_tls13.cookie_len) + goto err; + + /* + * Check provided cookie value against what server previously + * sent - client *MUST* send the same cookie with new CR after + * a cookie is sent by the server with an HRR. + */ + if (!CBS_mem_equal(&cookie, S3I(s)->hs_tls13.cookie, + S3I(s)->hs_tls13.cookie_len)) { + /* XXX special cookie mismatch alert? */ + *alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + return 1; + + err: + *alert = SSL_AD_DECODE_ERROR; + return 0; +} + +int +tlsext_cookie_server_needs(SSL *s) +{ + + if (SSL_IS_DTLS(s)) + return 0; + if (S3I(s)->hs_tls13.max_version < TLS1_3_VERSION) + return 0; + /* + * Server needs to set cookie value in tls13 handshake + * in order to send one, should only be sent with HRR. + */ + return (S3I(s)->hs_tls13.cookie_len > 0 && + S3I(s)->hs_tls13.cookie != NULL); +} + +int +tlsext_cookie_server_build(SSL *s, CBB *cbb) +{ + CBB cookie; + + /* XXX deduplicate with client code */ + + if (!CBB_add_u16_length_prefixed(cbb, &cookie)) + return 0; + + if (!CBB_add_bytes(&cookie, S3I(s)->hs_tls13.cookie, + S3I(s)->hs_tls13.cookie_len)) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +tlsext_cookie_client_parse(SSL *s, CBS *cbs, int *alert) +{ + CBS cookie; + + /* + * XXX This currently assumes we will not get a second + * HRR from a server with a cookie to process after accepting + * one from the server in the same handshake + */ + if (S3I(s)->hs_tls13.cookie != NULL || + S3I(s)->hs_tls13.cookie_len != 0) { + *alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + if (!CBS_get_u16_length_prefixed(cbs, &cookie)) + goto err; + + if (!CBS_stow(&cookie, &S3I(s)->hs_tls13.cookie, + &S3I(s)->hs_tls13.cookie_len)) + goto err; + + return 1; + + err: + *alert = SSL_AD_DECODE_ERROR; + return 0; +} + struct tls_extension_funcs { int (*needs)(SSL *s); int (*build)(SSL *s, CBB *cbb); @@ -1572,6 +1827,20 @@ static struct tls_extension tls_extensions[] = { .parse = tlsext_alpn_client_parse, }, }, + { + .type = TLSEXT_TYPE_cookie, + .messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_HRR, + .client = { + .needs = tlsext_cookie_client_needs, + .build = tlsext_cookie_client_build, + .parse = tlsext_cookie_server_parse, + }, + .server = { + .needs = tlsext_cookie_server_needs, + .build = tlsext_cookie_server_build, + .parse = tlsext_cookie_client_parse, + }, + }, #ifndef OPENSSL_NO_SRTP { .type = TLSEXT_TYPE_use_srtp, @@ -1595,7 +1864,7 @@ static struct tls_extension tls_extensions[] = { /* Ensure that extensions fit in a uint32_t bitmask. */ CTASSERT(N_TLS_EXTENSIONS <= (sizeof(uint32_t) * 8)); -static struct tls_extension * +struct tls_extension * tls_extension_find(uint16_t type, size_t *tls_extensions_idx) { size_t i; @@ -1719,6 +1988,7 @@ tlsext_parse(SSL *s, CBS *cbs, int *alert, int is_server, uint16_t msg_type) } /* Check for duplicate known extensions. */ + /* XXX move seen check to a function */ if ((S3I(s)->hs.extensions_seen & (1 << idx)) != 0) return 0; S3I(s)->hs.extensions_seen |= (1 << idx); diff --git a/src/lib/libssl/ssl_tlsext.h b/src/lib/libssl/ssl_tlsext.h index e82be579d0..2f90a03ee9 100644 --- a/src/lib/libssl/ssl_tlsext.h +++ b/src/lib/libssl/ssl_tlsext.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_tlsext.h,v 1.19 2019/01/23 18:24:40 beck Exp $ */ +/* $OpenBSD: ssl_tlsext.h,v 1.20 2019/01/24 02:56:41 beck Exp $ */ /* * Copyright (c) 2016, 2017 Joel Sing * Copyright (c) 2017 Doug Hogan @@ -101,6 +101,13 @@ int tlsext_keyshare_server_needs(SSL *s); int tlsext_keyshare_server_build(SSL *s, CBB *cbb); int tlsext_keyshare_server_parse(SSL *s, CBS *cbs, int *alert); +int tlsext_cookie_client_needs(SSL *s); +int tlsext_cookie_client_build(SSL *s, CBB *cbb); +int tlsext_cookie_client_parse(SSL *s, CBS *cbs, int *alert); +int tlsext_cookie_server_needs(SSL *s); +int tlsext_cookie_server_build(SSL *s, CBB *cbb); +int tlsext_cookie_server_parse(SSL *s, CBS *cbs, int *alert); + #ifndef OPENSSL_NO_SRTP int tlsext_srtp_client_needs(SSL *s); int tlsext_srtp_client_build(SSL *s, CBB *cbb); @@ -116,6 +123,7 @@ int tlsext_client_parse(SSL *s, CBS *cbs, int *alert, uint16_t msg_type); int tlsext_server_build(SSL *s, CBB *cbb, uint16_t msg_type); int tlsext_server_parse(SSL *s, CBS *cbs, int *alert, uint16_t msg_type); +struct tls_extension *tls_extension_find(uint16_t, size_t *); __END_HIDDEN_DECLS #endif diff --git a/src/regress/lib/libssl/tlsext/tlsexttest.c b/src/regress/lib/libssl/tlsext/tlsexttest.c index 05b18b5b05..d9b048dbfc 100644 --- a/src/regress/lib/libssl/tlsext/tlsexttest.c +++ b/src/regress/lib/libssl/tlsext/tlsexttest.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tlsexttest.c,v 1.26 2019/01/24 00:07:58 beck Exp $ */ +/* $OpenBSD: tlsexttest.c,v 1.27 2019/01/24 02:56:41 beck Exp $ */ /* * Copyright (c) 2017 Joel Sing * Copyright (c) 2017 Doug Hogan @@ -2929,11 +2929,15 @@ test_tlsext_serverhello_build(void) return (failure); } -static unsigned char tlsext_versions_client[] = { +const unsigned char tlsext_versions_client[] = { 0x08, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, }; +const unsigned char tlsext_versions_server[] = { + 0x03, 0x04, +}; + static int test_tlsext_versions_client(void) { @@ -3001,12 +3005,12 @@ test_tlsext_versions_client(void) if (dlen != sizeof(tlsext_versions_client)) { FAIL("got versions with length %zu, " - "want length %zu\n", dlen, (size_t) sizeof(tlsext_versions_client)); + "want length %zu\n", dlen, sizeof(tlsext_versions_client)); failure = 1; goto done; } - CBS_init(&cbs, tlsext_versions_client, sizeof(tlsext_versions_client)); + CBS_init(&cbs, data, dlen); if (!tlsext_versions_server_parse(ssl, &cbs, &alert)) { FAIL("failed to parse client versions\n"); failure = 1; @@ -3026,7 +3030,82 @@ test_tlsext_versions_client(void) return (failure); } -static unsigned char tlsext_keyshare_client[] = { + +static int +test_tlsext_versions_server(void) +{ + unsigned char *data = NULL; + SSL_CTX *ssl_ctx = NULL; + SSL *ssl = NULL; + int failure = 0; + size_t dlen; + int alert; + CBB cbb; + CBS cbs; + + 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"); + + ssl->version = TLS1_2_VERSION; + + if (tlsext_versions_server_needs(ssl)) { + FAIL("server should not need versions\n"); + failure = 1; + goto done; + } + + ssl->version = TLS1_3_VERSION; + + if (!tlsext_versions_server_needs(ssl)) { + FAIL("server should need versions\n"); + failure = 1; + goto done; + } + + if (!tlsext_versions_server_build(ssl, &cbb)) { + FAIL("server should have built versions\n"); + failure = 1; + goto done; + } + + if (!CBB_finish(&cbb, &data, &dlen)) { + FAIL("failed to finish CBB"); + failure = 1; + goto done; + } + + if (dlen != sizeof(tlsext_versions_server)) { + FAIL("got versions with length %zu, " + "want length %zu\n", dlen, sizeof(tlsext_versions_server)); + failure = 1; + goto done; + } + + CBS_init(&cbs, data, dlen); + if (!tlsext_versions_client_parse(ssl, &cbs, &alert)) { + FAIL("failed to parse client versions\n"); + failure = 1; + goto done; + } + if (CBS_len(&cbs) != 0) { + FAIL("extension data remaining"); + failure = 1; + goto done; + } + done: + CBB_cleanup(&cbb); + SSL_CTX_free(ssl_ctx); + SSL_free(ssl); + free(data); + + return (failure); +} + +const unsigned char tlsext_keyshare_client[] = { 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xba, 0x83, 0x2e, 0x4a, 0x18, 0xbe, 0x96, 0xd2, 0x71, 0x70, 0x18, 0x04, 0xf9, 0x9d, 0x76, 0x98, 0xef, 0xe8, @@ -3034,6 +3113,14 @@ static unsigned char tlsext_keyshare_client[] = { 0xad, 0x5b, 0xa4, 0xe9, 0x8b, 0x6b, }; +const unsigned char tlsext_keyshare_server[] = { + 0x00, 0x1d, 0x00, 0x20, 0xe5, 0xe8, 0x5a, 0xb9, + 0x7e, 0x12, 0x62, 0xe3, 0xd8, 0x7f, 0x6e, 0x3c, + 0xec, 0xa6, 0x8b, 0x99, 0x45, 0x77, 0x8e, 0x11, + 0xb3, 0xb9, 0x12, 0xb6, 0xbe, 0x35, 0xca, 0x51, + 0x76, 0x1e, 0xe8, 0x22 +}; + static int test_tlsext_keyshare_client(void) { @@ -3095,17 +3182,22 @@ test_tlsext_keyshare_client(void) goto done; } - CBS_init(&cbs, tlsext_keyshare_client, sizeof(tlsext_keyshare_client)); + (ssl)->version = TLS1_3_VERSION; + CBS_init(&cbs, data, dlen); + if (!tlsext_keyshare_server_parse(ssl, &cbs, &alert)) { FAIL("failed to parse client keyshare\n"); failure = 1; goto done; } + if (CBS_len(&cbs) != 0) { FAIL("extension data remaining"); failure = 1; goto done; } + + done: CBB_cleanup(&cbb); SSL_CTX_free(ssl_ctx); @@ -3115,6 +3207,338 @@ test_tlsext_keyshare_client(void) return (failure); } +static int +test_tlsext_keyshare_server(void) +{ + unsigned char *data = NULL; + SSL_CTX *ssl_ctx = NULL; + SSL *ssl = NULL; + int failure = 0; + size_t dlen, idx; + int alert; + CBB cbb; + CBS cbs; + uint8_t bogokey[] = { + 0xe5, 0xe8, 0x5a, 0xb9, 0x7e, 0x12, 0x62, 0xe3, + 0xd8, 0x7f, 0x6e, 0x3c, 0xec, 0xa6, 0x8b, 0x99, + 0x45, 0x77, 0x8e, 0x11, 0xb3, 0xb9, 0x12, 0xb6, + 0xbe, 0x35, 0xca, 0x51, 0x76, 0x1e, 0xe8, 0x22 + }; + + 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"); + + (ssl)->version = 0; + if (tlsext_keyshare_server_needs(ssl)) { + FAIL("server should not need keyshare\n"); + failure = 1; + goto done; + } + + (ssl)->version = TLS1_2_VERSION; + if (tlsext_keyshare_server_needs(ssl)) { + FAIL("server should not need keyshare\n"); + failure = 1; + goto done; + } + + ssl->version = TLS1_3_VERSION; + if (tlsext_keyshare_server_needs(ssl)) { + FAIL("client should not need keyshare\n"); + failure = 1; + goto done; + } + + if (tls_extension_find(TLSEXT_TYPE_key_share, &idx) == NULL) + FAIL("Can't find keyshare extension"); + S3I(ssl)->hs.extensions_seen |= (1 << idx); + + if (!tlsext_keyshare_server_needs(ssl)) { + FAIL("server should need keyshare"); + failure = 1; + goto done; + } + + if (tlsext_keyshare_server_build(ssl, &cbb)) { + FAIL("server should not have built a keyshare response"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.x25519_peer_public = bogokey; + if (!tlsext_keyshare_server_build(ssl, &cbb)) { + FAIL("server should be able to build a keyshare response"); + failure = 1; + goto done; + } + S3I(ssl)->hs_tls13.x25519_peer_public = NULL; + + if (!CBB_finish(&cbb, &data, &dlen)) { + FAIL("failed to finish CBB"); + failure = 1; + goto done; + } + + if (dlen != sizeof(tlsext_keyshare_server)) { + FAIL("got server keyshare with length %zu, " + "want length %zu\n", dlen, sizeof(tlsext_keyshare_server)); + failure = 1; + goto done; + } + + CBS_init(&cbs, data, dlen); + + if (!tlsext_keyshare_client_parse(ssl, &cbs, &alert)) { + FAIL("failed to parse server keyshare\n"); + failure = 1; + goto done; + } + + if (CBS_len(&cbs) != 0) { + FAIL("extension data remaining"); + failure = 1; + goto done; + } + +done: + CBB_cleanup(&cbb); + SSL_CTX_free(ssl_ctx); + SSL_free(ssl); + free(data); + + return (failure); +} + +/* One day I hope to be the only Muppet in this codebase */ +const uint8_t cookie[] = "\n" + " .---. .---. \n" + " : : o : me want cookie! \n" + " _..-: o : :-.._ / \n" + " .-'' ' `---' `---' ' ``-. \n" + " .' ' ' ' . ' . ' ' `. \n" + " : '.---.,,.,...,.,.,.,..---. ' ; \n" + " `. ' `. .' ' .' \n" + " `. '`. .' ' .' \n" + " `. `-._ _.-' ' .' .----. \n" + " `. ' ''--...--'' . ' .' .' o `. \n" + " .'`-._' ' . ' _.-'`. : o : \n" + " jgs .' ```--.....--''' ' `:_ o : \n" + " .' ' ' ' ' ; `.;';';';' \n" + " ; ' ' ' . ; .' ; ; ; \n" + " ; ' ' ' ' .' .-' \n" + " ' ' ' ' ' ' _.-' \n"; + +static int +test_tlsext_cookie_client(void) +{ + unsigned char *data = NULL; + SSL_CTX *ssl_ctx = NULL; + SSL *ssl = NULL; + int failure = 0; + size_t dlen; + int alert; + CBB cbb; + CBS cbs; + + 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"); + + S3I(ssl)->hs_tls13.max_version = 0; + if (tlsext_cookie_client_needs(ssl)) { + FAIL("client should not need cookie\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_2_VERSION; + if (tlsext_cookie_client_needs(ssl)) { + FAIL("client should not need cookie\n"); + failure = 1; + goto done; + } + + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + if (tlsext_cookie_client_needs(ssl)) { + FAIL("client should not need cookie\n"); + failure = 1; + goto done; + } + + /* Normally would be set by receiving a server cookie in an HRR */ + S3I(ssl)->hs_tls13.cookie = strdup(cookie); + S3I(ssl)->hs_tls13.cookie_len = strlen(cookie); + + if (!tlsext_cookie_client_needs(ssl)) { + FAIL("client should need cookie"); + failure = 1; + goto done; + } + + if (!tlsext_cookie_client_build(ssl, &cbb)) { + FAIL("client should have built a cookie response"); + failure = 1; + goto done; + } + + if (!CBB_finish(&cbb, &data, &dlen)) { + FAIL("failed to finish CBB"); + failure = 1; + goto done; + } + + if (dlen != strlen(cookie) + sizeof(uint16_t)) { + FAIL("got cookie with length %zu, " + "want length %zu\n", dlen, strlen(cookie) + + sizeof(uint16_t)); + failure = 1; + goto done; + } + + CBS_init(&cbs, data, dlen); + + /* Checks cookie against what's in the hs_tls13 */ + if (!tlsext_cookie_server_parse(ssl, &cbs, &alert)) { + FAIL("failed to parse client cookie\n"); + failure = 1; + goto done; + } + + if (CBS_len(&cbs) != 0) { + FAIL("extension data remaining"); + failure = 1; + goto done; + } + + done: + CBB_cleanup(&cbb); + SSL_CTX_free(ssl_ctx); + SSL_free(ssl); + free(data); + + return (failure); +} + +static int +test_tlsext_cookie_server(void) +{ + unsigned char *data = NULL; + SSL_CTX *ssl_ctx = NULL; + SSL *ssl = NULL; + int failure = 0; + size_t dlen; + int alert; + CBB cbb; + CBS cbs; + + 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"); + + S3I(ssl)->hs_tls13.max_version = 0; + if (tlsext_cookie_server_needs(ssl)) { + FAIL("server should not need cookie\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_2_VERSION; + if (tlsext_cookie_server_needs(ssl)) { + FAIL("server should not need cookie\n"); + failure = 1; + goto done; + } + + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + if (tlsext_cookie_server_needs(ssl)) { + FAIL("server should not need cookie\n"); + failure = 1; + goto done; + } + + /* Normally would be set by server before sending HRR */ + S3I(ssl)->hs_tls13.cookie = strdup(cookie); + S3I(ssl)->hs_tls13.cookie_len = strlen(cookie); + + if (!tlsext_cookie_server_needs(ssl)) { + FAIL("server should need cookie"); + failure = 1; + goto done; + } + + if (!tlsext_cookie_server_build(ssl, &cbb)) { + FAIL("server have built a cookie response"); + failure = 1; + goto done; + } + + if (!CBB_finish(&cbb, &data, &dlen)) { + FAIL("failed to finish CBB"); + failure = 1; + goto done; + } + + if (dlen != strlen(cookie) + sizeof(uint16_t)) { + FAIL("got cookie with length %zu, " + "want length %zu\n", dlen, strlen(cookie) + + sizeof(uint16_t)); + failure = 1; + goto done; + } + + CBS_init(&cbs, data, dlen); + + if (tlsext_cookie_client_parse(ssl, &cbs, &alert)) { + FAIL("client should not have parsed server cookie\n"); + failure = 1; + goto done; + } + + freezero(S3I(ssl)->hs_tls13.cookie, S3I(ssl)->hs_tls13.cookie_len); + S3I(ssl)->hs_tls13.cookie = NULL; + S3I(ssl)->hs_tls13.cookie_len = 0; + + if (!tlsext_cookie_client_parse(ssl, &cbs, &alert)) { + FAIL("failed to parse server cookie\n"); + failure = 1; + goto done; + } + + if (memcmp(cookie, S3I(ssl)->hs_tls13.cookie, + S3I(ssl)->hs_tls13.cookie_len) != 0) { + FAIL("parsed server cookie does not match sent cookie\n"); + failure = 1; + goto done; + } + + if (CBS_len(&cbs) != 0) { + FAIL("extension data remaining"); + failure = 1; + goto done; + } + +done: + CBB_cleanup(&cbb); + SSL_CTX_free(ssl_ctx); + SSL_free(ssl); + free(data); + + return (failure); +} + + int main(int argc, char **argv) { @@ -3148,8 +3572,13 @@ main(int argc, char **argv) failed |= test_tlsext_sessionticket_server(); failed |= test_tlsext_versions_client(); + failed |= test_tlsext_versions_server(); failed |= test_tlsext_keyshare_client(); + failed |= test_tlsext_keyshare_server(); + + failed |= test_tlsext_cookie_client(); + failed |= test_tlsext_cookie_server(); #ifndef OPENSSL_NO_SRTP failed |= test_tlsext_srtp_client(); -- cgit v1.2.3-55-g6feb