📄 eap_fast.c
字号:
const char *pac_file){ FILE *f; struct eap_fast_pac *pac; int count = 0, ret; char *buf, *pos; size_t buf_len; if (pac_file == NULL) return -1; buf_len = 1024; pos = buf = os_malloc(buf_len); if (buf == NULL) return -1; ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr); if (ret < 0 || ret >= buf + buf_len - pos) { os_free(buf); return -1; } pos += ret; pac = data->pac; while (pac) { ret = os_snprintf(pos, buf + buf_len - pos, "START\n"); if (ret < 0 || ret >= buf + buf_len - pos) { os_free(buf); return -1; } pos += ret; eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0); eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque", pac->pac_opaque, pac->pac_opaque_len, 0); eap_fast_write(&buf, &pos, &buf_len, "PAC-Info", pac->pac_info, pac->pac_info_len, 0); eap_fast_write(&buf, &pos, &buf_len, "A-ID", pac->a_id, pac->a_id_len, 0); eap_fast_write(&buf, &pos, &buf_len, "I-ID", pac->i_id, pac->i_id_len, 1); eap_fast_write(&buf, &pos, &buf_len, "A-ID-Info", pac->a_id_info, pac->a_id_info_len, 1); if (buf == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC " "data"); return -1; } ret = os_snprintf(pos, buf + buf_len - pos, "END\n"); if (ret < 0 || ret >= buf + buf_len - pos) { os_free(buf); return -1; } pos += ret; count++; pac = pac->next; } if (os_strncmp(pac_file, "blob://", 7) == 0) { struct wpa_config_blob *blob; blob = os_zalloc(sizeof(*blob)); if (blob == NULL) { os_free(buf); return -1; } blob->data = (u8 *) buf; blob->len = pos - buf; buf = NULL; blob->name = os_strdup(pac_file + 7); if (blob->name == NULL) { os_free(blob->data); os_free(blob); return -1; } eap_set_config_blob(sm, blob); } else { f = fopen(pac_file, "w"); if (f == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC " "file '%s' for writing", pac_file); os_free(buf); return -1; } fprintf(f, "%s", buf); os_free(buf); fclose(f); } wpa_printf(MSG_DEBUG, "EAP-FAST: wrote %d PAC entries into '%s'", count, pac_file); return 0;}static void * eap_fast_init(struct eap_sm *sm){ struct eap_fast_data *data; struct wpa_ssid *config = eap_get_config(sm); data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->fast_version = EAP_FAST_VERSION; if (config && config->phase1) { if (os_strstr(config->phase1, "fast_provisioning=1")) { data->provisioning_allowed = 1; wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC " "provisioning is allowed"); } } if (config && config->phase2) { char *start, *pos, *buf; struct eap_method_type *methods = NULL, *_methods; u8 method; size_t num_methods = 0; start = buf = os_strdup(config->phase2); if (buf == NULL) { eap_fast_deinit(sm, data); return NULL; } while (start && *start != '\0') { int vendor; pos = os_strstr(start, "auth="); if (pos == NULL) break; if (start != pos && *(pos - 1) != ' ') { start = pos + 5; continue; } start = pos + 5; pos = os_strchr(start, ' '); if (pos) *pos++ = '\0'; method = eap_get_phase2_type(start, &vendor); if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported " "Phase2 method '%s'", start); } else { num_methods++; _methods = os_realloc( methods, num_methods * sizeof(*methods)); if (_methods == NULL) { os_free(methods); os_free(buf); eap_fast_deinit(sm, data); return NULL; } methods = _methods; methods[num_methods - 1].vendor = vendor; methods[num_methods - 1].method = method; } start = pos; } os_free(buf); data->phase2_types = methods; data->num_phase2_types = num_methods; } if (data->phase2_types == NULL) { data->phase2_types = eap_get_phase2_types(config, &data->num_phase2_types); } if (data->phase2_types == NULL) { wpa_printf(MSG_ERROR, "EAP-FAST: No Phase2 method available"); eap_fast_deinit(sm, data); return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 EAP types", (u8 *) data->phase2_types, data->num_phase2_types * sizeof(struct eap_method_type)); data->phase2_type.vendor = EAP_VENDOR_IETF; data->phase2_type.method = EAP_TYPE_NONE; if (eap_tls_ssl_init(sm, &data->ssl, config)) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL."); eap_fast_deinit(sm, data); return NULL; } /* The local RADIUS server in a Cisco AP does not seem to like empty * fragments before data, so disable that workaround for CBC. * TODO: consider making this configurable */ tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn); if (eap_fast_load_pac(sm, data, config->pac_file) < 0) { eap_fast_deinit(sm, data); return NULL; } if (data->pac == NULL && !data->provisioning_allowed) { wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and " "provisioning disabled"); eap_fast_deinit(sm, data); return NULL; } return data;}static void eap_fast_deinit(struct eap_sm *sm, void *priv){ struct eap_fast_data *data = priv; struct eap_fast_pac *pac, *prev; if (data == NULL) return; if (data->phase2_priv && data->phase2_method) data->phase2_method->deinit(sm, data->phase2_priv); os_free(data->phase2_types); os_free(data->key_block_p); eap_tls_ssl_deinit(sm, &data->ssl); pac = data->pac; prev = NULL; while (pac) { prev = pac; pac = pac->next; eap_fast_free_pac(prev); } os_free(data);}static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data, int id, const u8 *plain, size_t plain_len, u8 **out_data, size_t *out_len){ int res; u8 *pos; struct eap_hdr *resp; /* TODO: add support for fragmentation, if needed. This will need to * add TLS Message Length field, if the frame is fragmented. */ resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit); if (resp == NULL) return 0; resp->code = EAP_CODE_RESPONSE; resp->identifier = id; pos = (u8 *) (resp + 1); *pos++ = EAP_TYPE_FAST; *pos++ = data->fast_version; res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, plain, plain_len, pos, data->ssl.tls_out_limit); if (res < 0) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 " "data"); os_free(resp); return 0; } *out_len = sizeof(struct eap_hdr) + 2 + res; resp->length = host_to_be16(*out_len); *out_data = (u8 *) resp; return 0;}static int eap_fast_phase2_nak(struct eap_fast_data *data, struct eap_hdr *hdr, u8 **resp, size_t *resp_len){ struct eap_hdr *resp_hdr; u8 *pos = (u8 *) (hdr + 1); size_t i; /* TODO: add support for expanded Nak */ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos); wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types", (u8 *) data->phase2_types, data->num_phase2_types * sizeof(struct eap_method_type)); *resp_len = sizeof(struct eap_hdr) + 1; *resp = os_malloc(*resp_len + data->num_phase2_types); if (*resp == NULL) return -1; resp_hdr = (struct eap_hdr *) (*resp); resp_hdr->code = EAP_CODE_RESPONSE; resp_hdr->identifier = hdr->identifier; pos = (u8 *) (resp_hdr + 1); *pos++ = EAP_TYPE_NAK; for (i = 0; i < data->num_phase2_types; i++) { if (data->phase2_types[i].vendor == EAP_VENDOR_IETF && data->phase2_types[i].method < 256) { (*resp_len)++; *pos++ = data->phase2_types[i].method; } } resp_hdr->length = host_to_be16(*resp_len); return 0;}static int eap_fast_derive_msk(struct eap_fast_data *data){ /* Derive EAP Master Session Keys (section 5.4) */ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, "Session Key Generating Function", (u8 *) "", 0, data->key_data, EAP_FAST_KEY_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)", data->key_data, EAP_FAST_KEY_LEN); sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, "Extended Session Key Generating Function", (u8 *) "", 0, data->emsk, EAP_EMSK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)", data->emsk, EAP_EMSK_LEN); data->success = 1; return 0;}static int eap_fast_set_tls_master_secret(struct eap_sm *sm, struct eap_fast_data *data, const u8 *tls, size_t tls_len){ struct tls_keys keys; u8 master_secret[48], *seed; const u8 *server_random; size_t seed_len, server_random_len; if (data->tls_master_secret_set || !data->current_pac || tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || keys.client_random == NULL) { return 0; } wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random", keys.client_random, keys.client_random_len); /* TLS master secret is needed before TLS library has processed this * message which includes both ServerHello and an encrypted handshake * message, so we need to parse server_random from this message before * passing it to TLS library. * * Example TLS packet header: * (16 03 01 00 2a 02 00 00 26 03 01 <32 bytes server_random>) * Content Type: Handshake: 0x16 * Version: TLS 1.0 (0x0301) * Lenghth: 42 (0x002a) * Handshake Type: Server Hello: 0x02 * Length: 38 (0x000026) * Version TLS 1.0 (0x0301) * Random: 32 bytes */ if (tls_len < 43 || tls[0] != 0x16 || tls[1] != 0x03 || tls[2] != 0x01 || tls[5] != 0x02 || tls[9] != 0x03 || tls[10] != 0x01) { wpa_hexdump(MSG_DEBUG, "EAP-FAST: unrecognized TLS " "ServerHello", tls, tls_len); return -1; } server_random = tls + 11; server_random_len = 32; wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random", server_random, server_random_len); seed_len = keys.client_random_len + server_random_len; seed = os_malloc(seed_len); if (seed == NULL) return -1; os_memcpy(seed, server_random, server_random_len); os_memcpy(seed + server_random_len, keys.client_random, keys.client_random_len); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len); wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key", data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN); /* master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", * server_random + client_random, 48) */ sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN, "PAC to master secret label hash", seed, seed_len, master_secret, sizeof(master_secret)); os_free(seed); wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret", master_secret, sizeof(master_secret)); data->tls_master_secret_set = 1; return tls_connection_set_master_key(sm->ssl_ctx, data->ssl.conn, master_secret, sizeof(master_secret));}static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len){ struct tls_keys keys; u8 *rnd = NULL, *out; int block_size; block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn); if (block_size < 0) return NULL; out = os_malloc(block_size + len); if (out == NULL) return NULL; if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out, block_size + len) == 0) { os_memmove(out, out + block_size, len); return out; } if (tls_connection_get_keys(sm->ssl_ctx, data->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;}static void eap_fast_derive_key_auth(struct eap_sm *sm, struct eap_fast_data *data){ u8 *sks; /* draft-cam-winget-eap-fast-05.txt: * 5.1 EAP-FAST Authentication Phase 1: Key Derivations * Extra key material after TLS key_block: session_ket_seed[40] */ sks = eap_fast_derive_key(sm, &data->ssl, "key expansion", EAP_FAST_SKS_LEN); if (sks == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " "session_key_seed"); return; } /* * draft-cam-winget-eap-fast-05.txt, 5.2: * S-IMCK[0] = session_key_seed */ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", sks, EAP_FAST_SKS_LEN); data->simck_idx = 0; os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN); os_free(sks);}static void eap_fast_derive_key_provisioning(struct eap_sm *sm, struct eap_fast_data *data){ os_free(data->key_block_p); data->key_block_p = (struct eap_fast_key_block_provisioning *) eap_fast_derive_key(sm, &data->ssl, "key expansion", sizeof(*data->key_block_p)); if (data->key_block_p == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block"); return; } /* * draft-cam-winget-eap-fast-05.txt, 5.2: * S-IMCK[0] = session_key_seed */ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", data->key_block_p->session_key_seed, sizeof(data->key_block_p->session_key_seed)); data->simck_idx = 0; os_memcpy(data->simck, data->key_block_p->session_key_seed, EAP_FAST_SIMCK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge", data->key_block_p->server_challenge, sizeof(data->key_block_p->server_challenge)); wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge", data->key_block_p->client_challenge, sizeof(data->key_block_p->client_challenge));}static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data){ if (data->current_pac) { eap_fast_derive_key_auth(sm, data); } else { eap_fast_derive_key_provisioning(sm, data); }}static int eap_fast_phase2_request(struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret, struct eap_hdr *hdr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -