From ae085f866c992c5aafe0d0322dddfa4f932c16bc Mon Sep 17 00:00:00 2001 From: beck <> Date: Fri, 18 Jan 2019 12:09:52 +0000 Subject: Add client side of supported versions and keyshare extensions with basic regress ok jsing@ --- src/lib/libssl/s3_lib.c | 7 +- src/lib/libssl/ssl_locl.h | 20 ++- src/lib/libssl/ssl_tlsext.c | 223 ++++++++++++++++++++++++++++- src/lib/libssl/ssl_tlsext.h | 16 ++- src/regress/lib/libssl/tlsext/tlsexttest.c | 193 ++++++++++++++++++++++++- 5 files changed, 454 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/libssl/s3_lib.c b/src/lib/libssl/s3_lib.c index 091713d12a..0761c5b5ce 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.176 2018/11/08 22:28:52 jsing Exp $ */ +/* $OpenBSD: s3_lib.c,v 1.177 2019/01/18 12:09:52 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1627,6 +1627,11 @@ ssl3_clear(SSL *s) s->internal->packet_length = 0; s->version = TLS1_VERSION; + + tls13_secrets_destroy(S3I(s)->hs_tls13.secrets); + 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); } static long diff --git a/src/lib/libssl/ssl_locl.h b/src/lib/libssl/ssl_locl.h index 94bb76eca3..1653b2ab96 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.225 2018/11/21 15:13:29 jsing Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.226 2019/01/18 12:09:52 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -162,6 +162,7 @@ #include "bytestring.h" #include "ssl_sigalgs.h" +#include "tls13_internal.h" __BEGIN_HIDDEN_DECLS @@ -430,6 +431,22 @@ typedef struct ssl_handshake_st { unsigned char *key_block; } SSL_HANDSHAKE; +typedef struct ssl_handshake_tls13_st { + uint16_t min_version; + uint16_t max_version; + uint16_t version; + + /* Version proposed by peer server. */ + uint16_t server_version; + + /* X25519 key share. */ + uint8_t *x25519_public; + uint8_t *x25519_private; + uint8_t *x25519_peer_public; + + struct tls13_secrets *secrets; +} SSL_HANDSHAKE_TLS13; + typedef struct ssl_ctx_internal_st { uint16_t min_version; uint16_t max_version; @@ -803,6 +820,7 @@ typedef struct ssl3_state_internal_st { int in_read_app_data; SSL_HANDSHAKE hs; + SSL_HANDSHAKE_TLS13 hs_tls13; struct { int new_mac_secret_size; diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c index da34a79f7d..91b3b7d958 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.28 2019/01/18 03:39:27 beck Exp $ */ +/* $OpenBSD: ssl_tlsext.c,v 1.29 2019/01/18 12:09:52 beck Exp $ */ /* * Copyright (c) 2016, 2017 Joel Sing * Copyright (c) 2017 Doug Hogan @@ -16,6 +16,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include "ssl_locl.h" @@ -1193,6 +1194,196 @@ tlsext_srtp_client_parse(SSL *s, CBS *cbs, int *alert) #endif /* OPENSSL_NO_SRTP */ +/* + * TLSv1.3 Key Share - RFC 8446 section 4.2.8. + */ +int +tlsext_keyshare_client_needs(SSL *s) +{ + /* XXX once this gets initialized when we get tls13_client.c */ + if (S3I(s)->hs_tls13.max_version == 0) + return 0; + return (!SSL_IS_DTLS(s) && S3I(s)->hs_tls13.max_version >= + TLS1_3_VERSION); +} + +int +tlsext_keyshare_client_build(SSL *s, CBB *cbb) +{ + uint8_t *public_key = NULL, *private_key = NULL; + CBB client_shares, key_exchange; + + /* Generate and provide key shares. */ + if (!CBB_add_u16_length_prefixed(cbb, &client_shares)) + return 0; + + /* XXX - other groups. */ + + /* 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(&client_shares, tls1_ec_nid2curve_id(NID_X25519))) + goto err; + if (!CBB_add_u16_length_prefixed(&client_shares, &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; +} + +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; + } + + return 1; +} + +int +tlsext_keyshare_server_needs(SSL *s) +{ + return (!SSL_IS_DTLS(s) && s->version >= TLS1_3_VERSION); +} + +int +tlsext_keyshare_server_build(SSL *s, CBB *cbb) +{ + return 0; +} + +int +tlsext_keyshare_client_parse(SSL *s, CBS *cbs, int *alert) +{ + CBS key_exchange; + uint16_t group; + size_t out_len; + + /* Unpack server share. */ + if (!CBS_get_u16(cbs, &group)) + goto err; + + /* Handle other groups and verify that they're valid. */ + if (group != tls1_ec_nid2curve_id(NID_X25519)) + goto err; + + 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; + + return 1; + + err: + *alert = SSL_AD_DECODE_ERROR; + return 0; +} + +/* + * Supported Versions - RFC 8446 section 4.2.1. + */ +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) + return 0; + return (!SSL_IS_DTLS(s) && S3I(s)->hs_tls13.max_version >= + TLS1_3_VERSION); +} + +int +tlsext_versions_client_build(SSL *s, CBB *cbb) +{ + uint16_t version; + CBB versions; + uint16_t max, min; + + max = S3I(s)->hs_tls13.max_version; + min = S3I(s)->hs_tls13.min_version; + + if (min < TLS1_VERSION) + return 0; + + if (!CBB_add_u8_length_prefixed(cbb, &versions)) + return 0; + + /* XXX - fix, but contiguous for now... */ + for (version = max; version >= min; version--) { + if (!CBB_add_u16(&versions, version)) + return 0; + } + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +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; + } + + return 1; +} + +int +tlsext_versions_server_needs(SSL *s) +{ + return (!SSL_IS_DTLS(s) && s->version >= TLS1_3_VERSION); +} + +int +tlsext_versions_server_build(SSL *s, CBB *cbb) +{ + return 0; +} + +int +tlsext_versions_client_parse(SSL *s, CBS *cbs, int *alert) +{ + uint16_t selected_version; + + if (!CBS_get_u16(cbs, &selected_version)) { + *alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* XXX test between min and max once initialization code goes in */ + S3I(s)->hs_tls13.server_version = selected_version; + + return 1; +} + struct tls_extension_funcs { int (*needs)(SSL *s); int (*build)(SSL *s, CBB *cbb); @@ -1207,6 +1398,36 @@ struct tls_extension { }; static struct tls_extension tls_extensions[] = { + { + .type = TLSEXT_TYPE_supported_versions, + .messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH | + SSL_TLSEXT_MSG_HRR, + .client = { + .needs = tlsext_versions_client_needs, + .build = tlsext_versions_client_build, + .parse = tlsext_versions_server_parse, + }, + .server = { + .needs = tlsext_versions_server_needs, + .build = tlsext_versions_server_build, + .parse = tlsext_versions_client_parse, + }, + }, + { + .type = TLSEXT_TYPE_key_share, + .messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH | + SSL_TLSEXT_MSG_HRR, + .client = { + .needs = tlsext_keyshare_client_needs, + .build = tlsext_keyshare_client_build, + .parse = tlsext_keyshare_server_parse, + }, + .server = { + .needs = tlsext_keyshare_server_needs, + .build = tlsext_keyshare_server_build, + .parse = tlsext_keyshare_client_parse, + }, + }, { .type = TLSEXT_TYPE_server_name, .messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_EE, diff --git a/src/lib/libssl/ssl_tlsext.h b/src/lib/libssl/ssl_tlsext.h index e5c1628c98..8f5aaa89dc 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.15 2019/01/18 00:54:42 jsing Exp $ */ +/* $OpenBSD: ssl_tlsext.h,v 1.16 2019/01/18 12:09:52 beck Exp $ */ /* * Copyright (c) 2016, 2017 Joel Sing * Copyright (c) 2017 Doug Hogan @@ -86,6 +86,20 @@ int tlsext_sessionticket_server_needs(SSL *s); int tlsext_sessionticket_server_build(SSL *s, CBB *cbb); int tlsext_sessionticket_server_parse(SSL *s, CBS *cbs, int *alert); +int tlsext_versions_client_needs(SSL *s); +int tlsext_versions_client_build(SSL *s, CBB *cbb); +int tlsext_versions_client_parse(SSL *s, CBS *cbs, int *alert); +int tlsext_versions_server_needs(SSL *s); +int tlsext_versions_server_build(SSL *s, CBB *cbb); +int tlsext_versions_server_parse(SSL *s, CBS *cbs, int *alert); + +int tlsext_keyshare_client_needs(SSL *s); +int tlsext_keyshare_client_build(SSL *s, CBB *cbb); +int tlsext_keyshare_client_parse(SSL *s, CBS *cbs, int *alert); +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); + #ifndef OPENSSL_NO_SRTP int tlsext_srtp_client_needs(SSL *s); int tlsext_srtp_client_build(SSL *s, CBB *cbb); diff --git a/src/regress/lib/libssl/tlsext/tlsexttest.c b/src/regress/lib/libssl/tlsext/tlsexttest.c index 04403118af..7a9f7d9be7 100644 --- a/src/regress/lib/libssl/tlsext/tlsexttest.c +++ b/src/regress/lib/libssl/tlsext/tlsexttest.c @@ -1,7 +1,8 @@ -/* $OpenBSD: tlsexttest.c,v 1.21 2019/01/18 00:55:15 jsing Exp $ */ +/* $OpenBSD: tlsexttest.c,v 1.22 2019/01/18 12:09:52 beck Exp $ */ /* * Copyright (c) 2017 Joel Sing * Copyright (c) 2017 Doug Hogan + * Copyright (c) 2019 Bob Beck * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2934,6 +2935,192 @@ test_tlsext_serverhello_build(void) return (failure); } +static unsigned char tlsext_versions_client[] = { + 0x08, 0x03, 0x04, 0x03, 0x03, 0x03, + 0x02, 0x03, 0x01, +}; + +static int +test_tlsext_versions_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_versions_client_needs(ssl)) { + FAIL("client should not need versions\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_2_VERSION; + + if (tlsext_versions_client_needs(ssl)) { + FAIL("client should not need versions\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + + if (!tlsext_versions_client_needs(ssl)) { + FAIL("client should need versions\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + S3I(ssl)->hs_tls13.min_version = 0; + if (tlsext_versions_client_build(ssl, &cbb)) { + FAIL("client should not have built versions\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + S3I(ssl)->hs_tls13.min_version = TLS1_VERSION; + if (!tlsext_versions_client_build(ssl, &cbb)) { + FAIL("client 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_client)) { + FAIL("got versions with length %zu, " + "want length %zu\n", dlen, (size_t) sizeof(tlsext_versions_client)); + failure = 1; + goto done; + } + + CBS_init(&cbs, tlsext_versions_client, sizeof(tlsext_versions_client)); + if (!tlsext_versions_server_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); +} + +static 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, + 0x4f, 0x8b, 0x85, 0x41, 0xa4, 0xd9, 0x61, 0x57, + 0xad, 0x5b, 0xa4, 0xe9, 0x8b, 0x6b, +}; + +static int +test_tlsext_keyshare_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_keyshare_client_needs(ssl)) { + FAIL("client should not need keyshare\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_2_VERSION; + if (tlsext_keyshare_client_needs(ssl)) { + FAIL("client should not need keyshare\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + if (!tlsext_keyshare_client_needs(ssl)) { + FAIL("client should need keyshare\n"); + failure = 1; + goto done; + } + + S3I(ssl)->hs_tls13.max_version = TLS1_3_VERSION; + if (!tlsext_keyshare_client_build(ssl, &cbb)) { + FAIL("client should have built keyshare\n"); + failure = 1; + goto done; + } + + if (!CBB_finish(&cbb, &data, &dlen)) { + FAIL("failed to finish CBB"); + failure = 1; + goto done; + } + + if (dlen != sizeof(tlsext_keyshare_client)) { + FAIL("got client sigalgs with length %zu, " + "want length %zu\n", dlen, (size_t) sizeof(tlsext_keyshare_client)); + failure = 1; + goto done; + } + + CBS_init(&cbs, tlsext_keyshare_client, sizeof(tlsext_keyshare_client)); + 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); + SSL_free(ssl); + free(data); + + return (failure); +} + int main(int argc, char **argv) { @@ -2966,6 +3153,10 @@ main(int argc, char **argv) failed |= test_tlsext_sessionticket_client(); failed |= test_tlsext_sessionticket_server(); + failed |= test_tlsext_versions_client(); + + failed |= test_tlsext_keyshare_client(); + #ifndef OPENSSL_NO_SRTP failed |= test_tlsext_srtp_client(); failed |= test_tlsext_srtp_server(); -- cgit v1.2.3-55-g6feb