diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2019-02-04 16:18:16 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2019-02-04 16:18:16 +0000 |
commit | 66dd949ade2bf91e71a63b26f5d4651f4aa86178 (patch) | |
tree | 1aafaea8c709b007f6b12bdd0d9bcaf29da3a08b | |
parent | c3c1288d3618ba568ef3e32ee7a56e449a1c9388 (diff) |
Implement parsing and processing of TLSv1.3 ServerHello messages.
ok tb@
-rw-r--r-- | lib/libssl/tls13_client.c | 179 | ||||
-rw-r--r-- | lib/libssl/tls13_handshake.c | 10 | ||||
-rw-r--r-- | lib/libssl/tls13_internal.h | 9 |
3 files changed, 187 insertions, 11 deletions
diff --git a/lib/libssl/tls13_client.c b/lib/libssl/tls13_client.c index 1a2529be6af..4d34cf99437 100644 --- a/lib/libssl/tls13_client.c +++ b/lib/libssl/tls13_client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_client.c,v 1.1 2019/01/21 13:45:57 jsing Exp $ */ +/* $OpenBSD: tls13_client.c,v 1.2 2019/02/04 16:18:15 jsing Exp $ */ /* * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org> * @@ -22,6 +22,7 @@ #include "bytestring.h" #include "ssl_tlsext.h" +#include "tls13_handshake.h" #include "tls13_internal.h" int @@ -137,3 +138,179 @@ tls13_client_hello_send(struct tls13_ctx *ctx) return 1; } + +/* + * HelloRetryRequest hash - RFC 8446 section 4.1.3. + */ +static const uint8_t tls13_hello_retry_request_hash[] = { + 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, + 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, + 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, + 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, +}; + +static int +tls13_server_hello_process(struct tls13_ctx *ctx, CBS *cbs) +{ + CBS server_random, session_id; + uint16_t cipher_suite, legacy_version; + uint8_t compression_method; + const SSL_CIPHER *cipher; + SSL *s = ctx->ssl; + int alert; + + if (!CBS_get_u16(cbs, &legacy_version)) + goto err; + if (!CBS_get_bytes(cbs, &server_random, SSL3_RANDOM_SIZE)) + goto err; + if (!CBS_get_u8_length_prefixed(cbs, &session_id)) + goto err; + if (!CBS_get_u16(cbs, &cipher_suite)) + goto err; + if (!CBS_get_u8(cbs, &compression_method)) + goto err; + + if (!tlsext_client_parse(s, cbs, &alert, SSL_TLSEXT_MSG_SH)) + goto err; + + if (CBS_len(cbs) != 0) + goto err; + + /* + * See if a supported versions extension was returned. If it was then + * the legacy version must be set to 0x0303 (RFC 8446 section 4.1.3). + * Otherwise, fallback to the legacy version, ensuring that it is both + * within range and not TLS 1.3 or greater (which must use the + * supported version extension. + */ + if (S3I(s)->hs_tls13.server_version != 0) { + if (legacy_version != TLS1_2_VERSION) { + /* XXX - alert. */ + goto err; + } + } else { + if (legacy_version < S3I(s)->hs_tls13.min_version || + legacy_version > S3I(s)->hs_tls13.max_version || + legacy_version > TLS1_2_VERSION) { + /* XXX - alert. */ + goto err; + } + S3I(s)->hs_tls13.server_version = legacy_version; + } + + /* XXX - session_id must match. */ + + /* + * Ensure that the cipher suite is one that we offered in the client + * hello and that it matches the TLS version selected. + */ + cipher = ssl3_get_cipher_by_value(cipher_suite); + if (cipher == NULL || + sk_SSL_CIPHER_find(ssl_get_ciphers_by_id(s), cipher) < 0) { + /* XXX - alert. */ + goto err; + } + if (S3I(s)->hs_tls13.server_version == TLS1_3_VERSION && + cipher->algorithm_ssl != SSL_TLSV1_3) { + /* XXX - alert. */ + goto err; + } + /* XXX - move this to hs_tls13? */ + S3I(s)->hs.new_cipher = cipher; + + if (compression_method != 0) { + /* XXX - alert. */ + goto err; + } + + if (CBS_mem_equal(&server_random, tls13_hello_retry_request_hash, + sizeof(tls13_hello_retry_request_hash))) + ctx->handshake_stage.hs_type |= WITH_HRR; + + return 1; + + err: + return 0; +} + +int +tls13_server_hello_recv(struct tls13_ctx *ctx) +{ + struct tls13_secrets *secrets; + struct tls13_secret context; + unsigned char buf[EVP_MAX_MD_SIZE]; + uint8_t *shared_key = NULL; + size_t hash_len; + SSL *s = ctx->ssl; + int ret = 0; + CBS cbs; + + if (!tls13_handshake_msg_content(ctx->hs_msg, &cbs)) + goto err; + + if (!tls13_server_hello_process(ctx, &cbs)) + goto err; + + if (S3I(s)->hs_tls13.server_version < TLS1_3_VERSION) { + /* XXX - switch back to legacy client. */ + } + + if (ctx->handshake_stage.hs_type & WITH_HRR) + return 1; + + /* XXX - handle other key share types. */ + if (S3I(s)->hs_tls13.x25519_peer_public == NULL) { + /* XXX - alert. */ + goto err; + } + if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + if (!X25519(shared_key, S3I(s)->hs_tls13.x25519_private, + S3I(s)->hs_tls13.x25519_peer_public)) + goto err; + + s->session->cipher = S3I(s)->hs.new_cipher; + s->session->ssl_version = S3I(s)->hs_tls13.server_version; + + if ((ctx->aead = tls13_cipher_aead(S3I(s)->hs.new_cipher)) == NULL) + goto err; + if ((ctx->hash = tls13_cipher_hash(S3I(s)->hs.new_cipher)) == NULL) + goto err; + + if ((secrets = tls13_secrets_create(ctx->hash, 0)) == NULL) + goto err; + S3I(ctx->ssl)->hs_tls13.secrets = secrets; + + /* XXX - pass in hash. */ + if (!tls1_handshake_hash_init(s)) + goto err; + if (!tls1_handshake_hash_value(s, buf, sizeof(buf), &hash_len)) + goto err; + context.data = buf; + context.len = hash_len; + + /* Early secrets. */ + if (!tls13_derive_early_secrets(secrets, secrets->zeros.data, + secrets->zeros.len, &context)) + goto err; + + /* Handshake secrets. */ + if (!tls13_derive_handshake_secrets(S3I(s)->hs_tls13.secrets, + shared_key, X25519_KEY_LENGTH, &context)) + goto err; + + tls13_record_layer_set_aead(ctx->rl, ctx->aead); + tls13_record_layer_set_hash(ctx->rl, ctx->hash); + + if (!tls13_record_layer_set_traffic_keys(ctx->rl, + &secrets->server_handshake_traffic, + &secrets->client_handshake_traffic)) + goto err; + + ctx->handshake_stage.hs_type |= NEGOTIATED; + ret = 1; + + err: + freezero(shared_key, X25519_KEY_LENGTH); + return ret; +} diff --git a/lib/libssl/tls13_handshake.c b/lib/libssl/tls13_handshake.c index f9cb3e5b476..b3c08ef39c1 100644 --- a/lib/libssl/tls13_handshake.c +++ b/lib/libssl/tls13_handshake.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_handshake.c,v 1.22 2019/01/23 23:29:56 tb Exp $ */ +/* $OpenBSD: tls13_handshake.c,v 1.23 2019/02/04 16:18:15 jsing Exp $ */ /* * Copyright (c) 2018-2019 Theo Buehler <tb@openbsd.org> * Copyright (c) 2019 Joel Sing <jsing@openbsd.org> @@ -467,14 +467,6 @@ tls13_client_key_update_recv(struct tls13_ctx *ctx) } int -tls13_server_hello_recv(struct tls13_ctx *ctx) -{ - ctx->handshake_stage.hs_type |= NEGOTIATED; - - return 0; -} - -int tls13_server_hello_send(struct tls13_ctx *ctx) { ctx->handshake_stage.hs_type |= NEGOTIATED; diff --git a/lib/libssl/tls13_internal.h b/lib/libssl/tls13_internal.h index 2738c40c4c1..4b23e74ae14 100644 --- a/lib/libssl/tls13_internal.h +++ b/lib/libssl/tls13_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_internal.h,v 1.15 2019/01/21 13:45:57 jsing Exp $ */ +/* $OpenBSD: tls13_internal.h,v 1.16 2019/02/04 16:18:15 jsing Exp $ */ /* * Copyright (c) 2018 Bob Beck <beck@openbsd.org> * Copyright (c) 2018 Theo Buehler <tb@openbsd.org> @@ -21,6 +21,7 @@ #define HEADER_TLS13_INTERNAL_H #include <openssl/evp.h> +#include <openssl/ssl.h> #include "bytestring.h" @@ -151,6 +152,9 @@ struct tls13_ctx { uint8_t mode; struct tls13_handshake_stage handshake_stage; + const EVP_AEAD *aead; + const EVP_MD *hash; + struct tls13_record_layer *rl; struct tls13_handshake_msg *hs_msg; }; @@ -158,6 +162,9 @@ struct tls13_ctx { struct tls13_ctx *tls13_ctx_new(int mode); void tls13_ctx_free(struct tls13_ctx *ctx); +const EVP_AEAD *tls13_cipher_aead(const SSL_CIPHER *cipher); +const EVP_MD *tls13_cipher_hash(const SSL_CIPHER *cipher); + /* * Legacy interfaces. */ |