diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 50a7b300d..8095b43bd 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -1,6 +1,6 @@ /* * TLS interface functions and an internal TLS implementation - * Copyright (c) 2004-2011, Jouni Malinen + * Copyright (c) 2004-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -412,7 +412,8 @@ static int tls_get_keyblock_size(struct tls_connection *conn) static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, + const char *label, const u8 *context, + size_t context_len, int server_random_first, int skip_keyblock, u8 *out, size_t out_len) { int ret = -1, skip = 0; @@ -431,15 +432,15 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - ret = tlsv1_client_prf(conn->client, label, - server_random_first, + ret = tlsv1_client_prf(conn->client, label, context, + context_len, server_random_first, _out, skip + out_len); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { - ret = tlsv1_server_prf(conn->server, label, - server_random_first, + ret = tlsv1_server_prf(conn->server, label, context, + context_len, server_random_first, _out, skip + out_len); } #endif /* CONFIG_TLS_INTERNAL_SERVER */ @@ -455,17 +456,16 @@ int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, const char *label, const u8 *context, size_t context_len, u8 *out, size_t out_len) { - if (context) - return -1; - return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len); + return tls_connection_prf(tls_ctx, conn, label, context, context_len, + 0, 0, out, out_len); } int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, u8 *out, size_t out_len) { - return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out, - out_len); + return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0, + 1, 1, out, out_len); } diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index 76e19746b..a147a54a3 100644 --- a/src/tls/tlsv1_client.c +++ b/src/tls/tlsv1_client.c @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2015, Jouni Malinen + * Copyright (c) 2006-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -514,6 +514,8 @@ int tlsv1_client_established(struct tlsv1_client *conn) * tlsv1_client_prf - Use TLS-PRF to derive keying material * @conn: TLSv1 client connection data from tlsv1_client_init() * @label: Label (e.g., description of the key) for PRF + * @context: Optional extra upper-layer context (max len 2^16) + * @context_len: The length of the context value * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random * @out: Buffer for output data from TLS-PRF @@ -521,13 +523,26 @@ int tlsv1_client_established(struct tlsv1_client *conn) * Returns: 0 on success, -1 on failure */ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, + const u8 *context, size_t context_len, int server_random_first, u8 *out, size_t out_len) { - u8 seed[2 * TLS_RANDOM_LEN]; + u8 *seed, *pos; + size_t seed_len = 2 * TLS_RANDOM_LEN; + int res; if (conn->state != ESTABLISHED) return -1; + if (context_len > 65535) + return -1; + + if (context) + seed_len += 2 + context_len; + + seed = os_malloc(seed_len); + if (!seed) + return -1; + if (server_random_first) { os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, @@ -538,9 +553,18 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, TLS_RANDOM_LEN); } - return tls_prf(conn->rl.tls_version, - conn->master_secret, TLS_MASTER_SECRET_LEN, - label, seed, 2 * TLS_RANDOM_LEN, out, out_len); + if (context) { + pos = seed + 2 * TLS_RANDOM_LEN; + WPA_PUT_BE16(pos, context_len); + pos += 2; + os_memcpy(pos, context, context_len); + } + + res = tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, + label, seed, seed_len, out, out_len); + os_free(seed); + return res; } diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h index 40fa6c7fb..7fcc256f1 100644 --- a/src/tls/tlsv1_client.h +++ b/src/tls/tlsv1_client.h @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -19,6 +19,7 @@ struct tlsv1_client * tlsv1_client_init(void); void tlsv1_client_deinit(struct tlsv1_client *conn); int tlsv1_client_established(struct tlsv1_client *conn); int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, + const u8 *context, size_t context_len, int server_random_first, u8 *out, size_t out_len); u8 * tlsv1_client_handshake(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c index 4759509e5..12dcc859a 100644 --- a/src/tls/tlsv1_server.c +++ b/src/tls/tlsv1_server.c @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2014, Jouni Malinen + * Copyright (c) 2006-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -462,6 +462,8 @@ int tlsv1_server_established(struct tlsv1_server *conn) * tlsv1_server_prf - Use TLS-PRF to derive keying material * @conn: TLSv1 server connection data from tlsv1_server_init() * @label: Label (e.g., description of the key) for PRF + * @context: Optional extra upper-layer context (max len 2^16) + * @context_len: The length of the context value * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random * @out: Buffer for output data from TLS-PRF @@ -469,13 +471,26 @@ int tlsv1_server_established(struct tlsv1_server *conn) * Returns: 0 on success, -1 on failure */ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, + const u8 *context, size_t context_len, int server_random_first, u8 *out, size_t out_len) { - u8 seed[2 * TLS_RANDOM_LEN]; + u8 *seed, *pos; + size_t seed_len = 2 * TLS_RANDOM_LEN; + int res; if (conn->state != ESTABLISHED) return -1; + if (context_len > 65535) + return -1; + + if (context) + seed_len += 2 + context_len; + + seed = os_malloc(seed_len); + if (!seed) + return -1; + if (server_random_first) { os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, @@ -486,9 +501,18 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, TLS_RANDOM_LEN); } - return tls_prf(conn->rl.tls_version, - conn->master_secret, TLS_MASTER_SECRET_LEN, - label, seed, 2 * TLS_RANDOM_LEN, out, out_len); + if (context) { + pos = seed + 2 * TLS_RANDOM_LEN; + WPA_PUT_BE16(pos, context_len); + pos += 2; + os_memcpy(pos, context, context_len); + } + + res = tls_prf(conn->rl.tls_version, + conn->master_secret, TLS_MASTER_SECRET_LEN, + label, seed, seed_len, out, out_len); + os_free(seed); + return res; } diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h index c3fd37eb0..c9c0875ca 100644 --- a/src/tls/tlsv1_server.h +++ b/src/tls/tlsv1_server.h @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -19,6 +19,7 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred); void tlsv1_server_deinit(struct tlsv1_server *conn); int tlsv1_server_established(struct tlsv1_server *conn); int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, + const u8 *context, size_t context_len, int server_random_first, u8 *out, size_t out_len); u8 * tlsv1_server_handshake(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, size_t *out_len);