diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 6cc924150..9463f58f9 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -370,15 +370,21 @@ int __must_check tls_connection_get_random(void *tls_ctx, * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_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 * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure * - * Exports keying material using the mechanism described in RFC 5705. + * Exports keying material using the mechanism described in RFC 5705. If + * context is %NULL, context is not provided; otherwise, context is provided + * (including the case of empty context with context_len == 0). */ int __must_check 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); /** diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index 73e80f3b7..ccd28842a 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -898,14 +898,23 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, - const char *label, u8 *out, size_t out_len) + const char *label, const u8 *context, + size_t context_len, u8 *out, size_t out_len) { if (conn == NULL || conn->session == NULL) return -1; +#if GNUTLS_VERSION_NUMBER >= 0x030404 + return gnutls_prf_rfc5705(conn->session, os_strlen(label), label, + context_len, (const char *) context, + out_len, (char *) out); +#else /* 3.4.4 */ + if (context) + return -1; return gnutls_prf(conn->session, os_strlen(label), label, 0 /* client_random first */, 0, NULL, out_len, (char *) out); +#endif /* 3.4.4 */ } diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 2876630aa..50a7b300d 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -452,8 +452,11 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, - const char *label, u8 *out, size_t out_len) + 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); } diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index 108e9aa2e..6d6fb0caf 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -94,7 +94,8 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn, int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, - const char *label, u8 *out, size_t out_len) + const char *label, const u8 *context, + size_t context_len, u8 *out, size_t out_len) { return -1; } diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index b8d055664..fc5551820 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -3908,11 +3908,13 @@ static int openssl_get_keyblock_size(SSL *ssl) int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, - const char *label, u8 *out, size_t out_len) + const char *label, const u8 *context, + size_t context_len, u8 *out, size_t out_len) { if (!conn || SSL_export_keying_material(conn->ssl, out, out_len, label, - os_strlen(label), NULL, 0, 0) != 1) + os_strlen(label), context, context_len, + context != NULL) != 1) return -1; return 0; } diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c index 39a24b330..41fc946bc 100644 --- a/src/crypto/tls_wolfssl.c +++ b/src/crypto/tls_wolfssl.c @@ -1973,8 +1973,11 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, - const char *label, u8 *out, size_t out_len) + const char *label, const u8 *context, + size_t context_len, u8 *out, size_t out_len) { + if (context) + return -1; if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0) return -1; return 0; diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 650bea6ad..8dcf7cc29 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -1084,6 +1084,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, "key derivation", label); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label, + NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (data->key_data) { diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c index cb747026c..ffea9d213 100644 --- a/src/eap_peer/eap_tls.c +++ b/src/eap_peer/eap_tls.c @@ -198,6 +198,7 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, eap_tls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label, + NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (data->key_data) { diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 1ee01a2da..cb94c452e 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -349,6 +349,8 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @label: Label string for deriving the keys, e.g., "client EAP encryption" + * @context: Optional extra upper-layer context (max len 2^16) + * @context_len: The length of the context value * @len: Length of the key material to generate (usually 64 for MSK) * Returns: Pointer to allocated key on success or %NULL on failure * @@ -357,9 +359,12 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) * different label to bind the key usage into the generated material. * * The caller is responsible for freeing the returned buffer. + * + * Note: To provide the RFC 5705 context, the context variable must be non-NULL. */ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len) + const char *label, const u8 *context, + size_t context_len, size_t len) { u8 *out; @@ -367,8 +372,8 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, if (out == NULL) return NULL; - if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out, - len)) { + if (tls_connection_export_key(data->ssl_ctx, data->conn, label, + context, context_len, out, len)) { os_free(out); return NULL; } @@ -409,7 +414,7 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, if (!id) return NULL; method_id = eap_peer_tls_derive_key( - sm, data, "EXPORTER_EAP_TLS_Method-Id", 64); + sm, data, "EXPORTER_EAP_TLS_Method-Id", NULL, 0, 64); if (!method_id) { os_free(id); return NULL; diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h index 306e6a98b..5f825294d 100644 --- a/src/eap_peer/eap_tls_common.h +++ b/src/eap_peer/eap_tls_common.h @@ -99,7 +99,8 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, struct eap_peer_config *config, u8 eap_type); void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len); + const char *label, const u8 *context, + size_t context_len, size_t len); u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, struct eap_ssl_data *data, u8 eap_type, size_t *len); diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index 5d267010e..1c8dbe2b4 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -271,6 +271,7 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm, eap_ttls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "ttls keying material", + NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (!data->key_data) { @@ -303,7 +304,8 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm, static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { - return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); + return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", + NULL, 0, len); } #endif /* CONFIG_FIPS */ diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index 3d334a0db..92c0e5ec9 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -331,7 +331,7 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) * phase 1 of PEAP (based on TLS). */ tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption", - EAP_TLS_KEY_LEN); + NULL, 0, EAP_TLS_KEY_LEN); if (tk == NULL) return -1; wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); @@ -1333,7 +1333,7 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) /* TODO: PEAPv1 - different label in some cases */ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "client EAP encryption", + "client EAP encryption", NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (eapKeyData) { os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN); @@ -1363,7 +1363,7 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len) /* TODO: PEAPv1 - different label in some cases */ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "client EAP encryption", + "client EAP encryption", NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (eapKeyData) { emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c index 13d234982..357e72a82 100644 --- a/src/eap_server/eap_server_tls.c +++ b/src/eap_server/eap_server_tls.c @@ -331,6 +331,7 @@ static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) else label = "client EAP encryption"; eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label, + NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (eapKeyData) { *len = EAP_TLS_KEY_LEN; @@ -359,6 +360,7 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) else label = "client EAP encryption"; eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label, + NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (eapKeyData) { emsk = os_malloc(EAP_EMSK_LEN); diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index 4ba7c2499..0eca0ff77 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -107,7 +107,8 @@ void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len) + const char *label, const u8 *context, + size_t context_len, size_t len) { u8 *out; @@ -115,8 +116,8 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, if (out == NULL) return NULL; - if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, out, - len)) { + if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, + context, context_len, out, len)) { os_free(out); return NULL; } @@ -157,7 +158,7 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm, if (!id) return NULL; method_id = eap_server_tls_derive_key( - sm, data, "EXPORTER_EAP_TLS_Method-Id", 64); + sm, data, "EXPORTER_EAP_TLS_Method-Id", NULL, 0, 64); if (!method_id) { os_free(id); return NULL; diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c index b14996b0b..52bff8afe 100644 --- a/src/eap_server/eap_server_ttls.c +++ b/src/eap_server/eap_server_ttls.c @@ -332,7 +332,7 @@ static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge", - len); + NULL, 0, len); } @@ -1268,7 +1268,7 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) return NULL; eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "ttls keying material", + "ttls keying material", NULL, 0, EAP_TLS_KEY_LEN); if (eapKeyData) { *len = EAP_TLS_KEY_LEN; @@ -1310,7 +1310,7 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) return NULL; eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "ttls keying material", + "ttls keying material", NULL, 0, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); if (eapKeyData) { emsk = os_malloc(EAP_EMSK_LEN); diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h index 31f6e72d7..0b04983ad 100644 --- a/src/eap_server/eap_tls_common.h +++ b/src/eap_server/eap_tls_common.h @@ -78,7 +78,8 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, int verify_peer, int eap_type); void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len); + const char *label, const u8 *context, + size_t context_len, size_t len); u8 * eap_server_tls_derive_session_id(struct eap_sm *sm, struct eap_ssl_data *data, u8 eap_type, size_t *len);