/** * eap_peer_tls_derive_key - Derive a key based on TLS session 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" * @len: Length of the key material to generate (usually 64 for MSK) * Returns: Pointer to allocated key on success or %NULL on failure * * This function uses TLS-PRF to generate pseudo-random data based on the TLS * session data (client/server random and master key). Each key type may use a * different label to bind the key usage into the generated material. * * The caller is responsible for freeing the returned buffer. */ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, const char *label, size_t len) { #ifndef CONFIG_FIPS struct tls_keys keys; #endif /* CONFIG_FIPS */ u8 *rnd = NULL, *out; out = os_malloc(len); if (out == NULL) return NULL; /* First, try to use TLS library function for PRF, if available. */ if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len) == 0) return out; #ifndef CONFIG_FIPS /* * TLS library did not support key generation, so get the needed TLS * session parameters and use an internal implementation of TLS PRF to * derive the key. */ if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys)) goto fail; if (keys.client_random == NULL || keys.server_random == NULL || keys.master_key == NULL) goto fail; rnd = os_malloc(keys.client_random_len + keys.server_random_len); if (rnd == NULL) goto fail; os_memcpy(rnd, keys.client_random, keys.client_random_len); os_memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, label, rnd, keys.client_random_len + keys.server_random_len, out, len)) goto fail; os_free(rnd); return out; fail: #endif /* CONFIG_FIPS */ os_free(out); os_free(rnd); return NULL; }
int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen) { #ifdef CONFIG_TLSV12 if (ver >= TLS_VERSION_1_2) { tls_prf_sha256(secret, secret_len, label, seed, seed_len, out, outlen); return 0; } #endif /* CONFIG_TLSV12 */ return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out, outlen); }
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len) { struct tls_keys keys; u8 *rnd = NULL, *out; out = os_malloc(len); if (out == NULL) return NULL; if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == 0) return out; if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) goto fail; if (keys.client_random == NULL || keys.server_random == NULL || keys.master_key == NULL) goto fail; rnd = os_malloc(keys.client_random_len + keys.server_random_len); if (rnd == NULL) goto fail; os_memcpy(rnd, keys.client_random, keys.client_random_len); os_memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, label, rnd, keys.client_random_len + keys.server_random_len, out, len)) goto fail; os_free(rnd); return out; fail: os_free(out); os_free(rnd); return NULL; }