u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len) { struct tls_keys keys; u8 *random; u8 *out; if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) return NULL; out = malloc(len); random = malloc(keys.client_random_len + keys.server_random_len); if (out == NULL || random == NULL) { free(out); free(random); return NULL; } memcpy(random, keys.client_random, keys.client_random_len); memcpy(random + keys.client_random_len, keys.server_random, keys.server_random_len); if (tls_prf(keys.master_key, keys.master_key_len, label, random, keys.client_random_len + keys.server_random_len, out, len)) { free(random); free(out); return NULL; } free(random); return out; }
static int eap_ttls_v1_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { struct tls_keys keys; u8 *rnd; os_free(data->key_data); data->key_data = NULL; os_memset(&keys, 0, sizeof(keys)); if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || keys.client_random == NULL || keys.server_random == NULL || keys.inner_secret == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " "client random, or server random to derive keying " "material"); return -1; } rnd = os_malloc(keys.client_random_len + keys.server_random_len); data->key_data = os_malloc(EAP_TLS_KEY_LEN); if (rnd == NULL || data->key_data == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); os_free(rnd); os_free(data->key_data); data->key_data = NULL; return -1; } 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(keys.inner_secret, keys.inner_secret_len, "ttls v1 keying material", rnd, keys.client_random_len + keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); os_free(rnd); os_free(data->key_data); data->key_data = NULL; return -1; } wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", rnd, keys.client_random_len + keys.server_random_len); wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", keys.inner_secret, keys.inner_secret_len); os_free(rnd); wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", data->key_data, EAP_TLS_KEY_LEN); return 0; }
static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, struct eap_ttls_data *data, size_t len) { struct tls_keys keys; u8 *challenge, *rnd; if (data->ttls_version == 0) { return eap_tls_derive_key(sm, &data->ssl, "ttls challenge", len); } os_memset(&keys, 0, sizeof(keys)); if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || keys.client_random == NULL || keys.server_random == NULL || keys.inner_secret == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " "client random, or server random to derive " "implicit challenge"); return NULL; } rnd = os_malloc(keys.client_random_len + keys.server_random_len); challenge = os_malloc(len); if (rnd == NULL || challenge == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " "challenge derivation"); os_free(rnd); os_free(challenge); return NULL; } os_memcpy(rnd, keys.server_random, keys.server_random_len); os_memcpy(rnd + keys.server_random_len, keys.client_random, keys.client_random_len); if (tls_prf(keys.inner_secret, keys.inner_secret_len, "inner application challenge", rnd, keys.client_random_len + keys.server_random_len, challenge, len)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " "challenge"); os_free(rnd); os_free(challenge); return NULL; } os_free(rnd); wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", challenge, len); return challenge; }
u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, const char *label, size_t len) { struct tls_keys keys; u8 *rnd = NULL, *out; int block_size; block_size = tls_connection_get_keyblock_size(ssl_ctx, conn); if (block_size < 0) return NULL; out = os_malloc(block_size + len); if (out == NULL) return NULL; if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len) == 0) { os_memmove(out, out + block_size, len); return out; } if (tls_connection_get_keys(ssl_ctx, conn, &keys)) goto fail; rnd = os_malloc(keys.client_random_len + keys.server_random_len); if (rnd == NULL) goto fail; os_memcpy(rnd, keys.server_random, keys.server_random_len); os_memcpy(rnd + keys.server_random_len, keys.client_random, keys.client_random_len); wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " "expansion", keys.master_key, keys.master_key_len); if (tls_prf(keys.master_key, keys.master_key_len, label, rnd, keys.client_random_len + keys.server_random_len, out, block_size + len)) goto fail; os_free(rnd); os_memmove(out, out + block_size, len); return out; fail: os_free(rnd); os_free(out); return NULL; }
u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, const char *label, size_t len) { struct tls_keys keys; 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(sm->ssl_ctx, data->conn, label, 0, out, len) == 0) return out; /* * 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(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(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; }
u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len) { struct tls_keys keys; u8 *rnd; u8 *out; if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) return NULL; if (keys.eap_tls_prf && strcmp(label, "client EAP encryption") == 0) { if (len > keys.eap_tls_prf_len) return NULL; out = malloc(len); if (out == NULL) return NULL; memcpy(out, keys.eap_tls_prf, len); return out; } if (keys.client_random == NULL || keys.server_random == NULL || keys.master_key == NULL) return NULL; out = malloc(len); rnd = malloc(keys.client_random_len + keys.server_random_len); if (out == NULL || rnd == NULL) { free(out); free(rnd); return NULL; } memcpy(rnd, keys.client_random, keys.client_random_len); memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); if (tls_prf(keys.master_key, keys.master_key_len, label, rnd, keys.client_random_len + keys.server_random_len, out, len)) { free(rnd); free(out); return NULL; } free(rnd); return out; }
u8 * eap_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 = 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 = malloc(keys.client_random_len + keys.server_random_len); if (rnd == NULL) goto fail; memcpy(rnd, keys.client_random, keys.client_random_len); memcpy(rnd + keys.client_random_len, keys.server_random, keys.server_random_len); if (tls_prf(keys.master_key, keys.master_key_len, label, rnd, keys.client_random_len + keys.server_random_len, out, len)) goto fail; free(rnd); return out; fail: free(out); free(rnd); return NULL; }
/** * 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 * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure */ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { u8 seed[2 * TLS_RANDOM_LEN]; if (conn->state != ESTABLISHED) return -1; if (server_random_first) { os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); } else { os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); } return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, 2 * TLS_RANDOM_LEN, out, out_len); }
static int tls_write_server_finished(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_server = NULL; crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); conn->verify.sha1_server = NULL; return -1; } conn->verify.md5_server = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_server == NULL || crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_server = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_server = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); pos += TLS_VERIFY_DATA_LEN; WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; *msgpos = pos; return 0; }
static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " "Finished", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " "type 0x%x", pos[0]); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } len = WPA_GET_BE24(pos + 1); pos += 4; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " "(len=%lu > left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (len != TLS_VERIFY_DATA_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " "in Finished: %lu (expected %d)", (unsigned long) len, TLS_VERIFY_DATA_LEN); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_client = NULL; crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); conn->verify.sha1_client = NULL; return -1; } conn->verify.md5_client = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_client == NULL || crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_client = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_client = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data, TLS_VERIFY_DATA_LEN); if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); *in_len = end - in_data; if (conn->use_session_ticket) { /* Abbreviated handshake using session ticket; RFC 4507 */ wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed " "successfully"); conn->state = ESTABLISHED; } else { /* Full handshake */ conn->state = SERVER_CHANGE_CIPHER_SPEC; } return 0; }
int tls_derive_keys(struct tlsv1_client *conn, const u8 *pre_master_secret, size_t pre_master_secret_len) { u8 seed[2 * TLS_RANDOM_LEN]; u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; u8 *pos; size_t key_block_len; if (pre_master_secret) { wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", pre_master_secret, pre_master_secret_len); os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); if (tls_prf(pre_master_secret, pre_master_secret_len, "master secret", seed, 2 * TLS_RANDOM_LEN, conn->master_secret, TLS_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " "master_secret"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", conn->master_secret, TLS_MASTER_SECRET_LEN); } os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + conn->rl.iv_size); if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "key expansion", seed, 2 * TLS_RANDOM_LEN, key_block, key_block_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", key_block, key_block_len); pos = key_block; /* client_write_MAC_secret */ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* server_write_MAC_secret */ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* client_write_key */ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* server_write_key */ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* client_write_IV */ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; /* server_write_IV */ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; return 0; }
static int test_eap_fast(void) { /* RFC 4851, Appendix B.1 */ const u8 pac_key[] = { 0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09, 0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B, 0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA, 0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14 }; const u8 seed[] = { 0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A, 0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3, 0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93, 0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A, 0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A, 0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F, 0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A, 0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00 }; const u8 master_secret[] = { 0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02, 0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64, 0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77, 0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29, 0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27, 0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2 }; const u8 key_block[] = { 0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74, 0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35, 0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B, 0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57, 0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70, 0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB, 0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF, 0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44, 0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29, 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05, 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96, 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84, 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98, 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71 }; const u8 sks[] = { 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05, 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96, 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84, 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98, 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71 }; const u8 isk[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const u8 imck[] = { 0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9, 0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80, 0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96, 0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1, 0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5, 0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9, 0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8, 0x15, 0xEC, 0x57, 0x7B }; const u8 msk[] = { 0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED, 0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33, 0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51, 0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9, 0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A, 0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49, 0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59, 0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3 }; const u8 emsk[] = { 0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B, 0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55, 0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D, 0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9, 0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54, 0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A, 0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44, 0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9 }; /* RFC 4851, Appendix B.2 */ u8 tlv[] = { 0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00, 0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8, 0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14, 0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62, 0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58, 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF, 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC, 0x05, 0xC5, 0x5B, 0xB7 }; const u8 compound_mac[] = { 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF, 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC, 0x05, 0xC5, 0x5B, 0xB7 }; u8 buf[512]; const u8 *simck, *cmk; int errors = 0; printf("EAP-FAST test cases\n"); printf("- T-PRF (SHA1) test case / master_secret\n"); sha1_t_prf(pac_key, sizeof(pac_key), "PAC to master secret label hash", seed, sizeof(seed), buf, sizeof(master_secret)); if (memcmp(master_secret, buf, sizeof(master_secret)) != 0) { printf("T-PRF test - FAILED!\n"); errors++; } printf("- PRF (TLS, SHA1/MD5) test case / key_block\n"); if (tls_prf(master_secret, sizeof(master_secret), "key expansion", seed, sizeof(seed), buf, sizeof(key_block)) || memcmp(key_block, buf, sizeof(key_block)) != 0) { printf("PRF test - FAILED!\n"); errors++; } printf("- T-PRF (SHA1) test case / IMCK\n"); sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys", isk, sizeof(isk), buf, sizeof(imck)); if (memcmp(imck, buf, sizeof(imck)) != 0) { printf("T-PRF test - FAILED!\n"); errors++; } simck = imck; cmk = imck + 40; printf("- T-PRF (SHA1) test case / MSK\n"); sha1_t_prf(simck, 40, "Session Key Generating Function", (u8 *) "", 0, buf, sizeof(msk)); if (memcmp(msk, buf, sizeof(msk)) != 0) { printf("T-PRF test - FAILED!\n"); errors++; } printf("- T-PRF (SHA1) test case / EMSK\n"); sha1_t_prf(simck, 40, "Extended Session Key Generating Function", (u8 *) "", 0, buf, sizeof(msk)); if (memcmp(emsk, buf, sizeof(emsk)) != 0) { printf("T-PRF test - FAILED!\n"); errors++; } printf("- Compound MAC test case\n"); memset(tlv + sizeof(tlv) - 20, 0, 20); hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20); if (memcmp(tlv + sizeof(tlv) - 20, compound_mac, sizeof(compound_mac)) != 0) { printf("Compound MAC test - FAILED!\n"); errors++; } return errors; }
int tls_derive_keys(struct tlsv1_client *conn, const u8 *pre_master_secret, size_t pre_master_secret_len) { u8 seed[2 * TLS_RANDOM_LEN]; u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; u8 *pos; size_t key_block_len; if (pre_master_secret) { wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", pre_master_secret, pre_master_secret_len); os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); if (tls_prf(conn->rl.tls_version, pre_master_secret, pre_master_secret_len, "master secret", seed, 2 * TLS_RANDOM_LEN, conn->master_secret, TLS_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " "master_secret"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", conn->master_secret, TLS_MASTER_SECRET_LEN); } os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len); if (conn->rl.tls_version == TLS_VERSION_1) key_block_len += 2 * conn->rl.iv_size; if (tls_prf(conn->rl.tls_version, conn->master_secret, TLS_MASTER_SECRET_LEN, "key expansion", seed, 2 * TLS_RANDOM_LEN, key_block, key_block_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", key_block, key_block_len); pos = key_block; /* client_write_MAC_secret */ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* server_write_MAC_secret */ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* client_write_key */ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* server_write_key */ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; if (conn->rl.tls_version == TLS_VERSION_1) { /* client_write_IV */ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; /* server_write_IV */ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; } else { /* * Use IV field to set the mask value for TLS v1.1. A fixed * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block * Cipher option 2a. */ os_memset(conn->rl.write_iv, 0, conn->rl.iv_size); } return 0; }
static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " "Finished", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " "type 0x%x", pos[0]); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } len = WPA_GET_BE24(pos + 1); pos += 4; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " "(len=%lu > left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (len != TLS_VERIFY_DATA_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " "in Finished: %lu (expected %d)", (unsigned long) len, TLS_VERIFY_DATA_LEN); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_server == NULL || crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.sha256_server = NULL; return -1; } conn->verify.sha256_server = NULL; } else { #endif /* CONFIG_TLSV12 */ hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_server = NULL; crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); conn->verify.sha1_server = NULL; return -1; } conn->verify.md5_server = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_server == NULL || crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_server = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_server = NULL; hlen = MD5_MAC_LEN + SHA1_MAC_LEN; #ifdef CONFIG_TLSV12 } #endif /* CONFIG_TLSV12 */ if (tls_prf(conn->rl.tls_version, conn->master_secret, TLS_MASTER_SECRET_LEN, "server finished", hash, hlen, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); *in_len = end - in_data; conn->state = (conn->session_resumed || conn->use_session_ticket) ? CHANGE_CIPHER_SPEC : ACK_FINISHED; return 0; }
static int tls_write_client_finished(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *hs_start; size_t rlen, hlen; u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_client = NULL; crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); conn->verify.sha1_client = NULL; return -1; } conn->verify.md5_client = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_client == NULL || crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_client = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_client = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); /* Handshake */ pos = hs_start = verify_data; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; /* uint24 length */ WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); pos += 3; pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, *msgpos, end - *msgpos, hs_start, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *msgpos += rlen; return 0; }