?? eap_fast.c
字號(hào):
*pos += snprintf(*pos, *buf + *buf_len - *pos, "%s=", field); for (i = 0; i < len; i++) { *pos += snprintf(*pos, *buf + *buf_len - *pos, "%02x", data[i]); } *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n"); if (txt) { *pos += snprintf(*pos, *buf + *buf_len - *pos, "%s-txt=", field); for (i = 0; i < len; i++) { *pos += snprintf(*pos, *buf + *buf_len - *pos, "%c", data[i]); } *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n"); }}static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data, const char *pac_file){ FILE *f; struct eap_fast_pac *pac; int count = 0; char *buf, *pos; size_t buf_len; if (pac_file == NULL) return -1; buf_len = 1024; pos = buf = malloc(buf_len); if (buf == NULL) return -1; pos += snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr); pac = data->pac; while (pac) { pos += snprintf(pos, buf + buf_len - pos, "START\n"); 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); pos += snprintf(pos, buf + buf_len - pos, "END\n"); count++; pac = pac->next; if (buf == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC " "data"); return -1; } } if (strncmp(pac_file, "blob://", 7) == 0) { struct wpa_config_blob *blob; blob = malloc(sizeof(*blob)); if (blob == NULL) { free(buf); return -1; } memset(blob, 0, sizeof(*blob)); blob->data = (u8 *) buf; blob->len = pos - buf; buf = NULL; blob->name = strdup(pac_file + 7); if (blob->name == NULL) { wpa_config_free_blob(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); free(buf); return -1; } fprintf(f, "%s", buf); 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 = malloc(sizeof(*data)); if (data == NULL) return NULL; memset(data, 0, sizeof(*data)); data->fast_version = EAP_FAST_VERSION; if (config && config->phase1) { if (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; u8 method, *methods = NULL, *_methods; size_t num_methods = 0; start = buf = strdup(config->phase2); if (buf == NULL) { eap_fast_deinit(sm, data); return NULL; } while (start && *start != '\0') { pos = strstr(start, "auth="); if (pos == NULL) break; if (start != pos && *(pos - 1) != ' ') { start = pos + 5; continue; } start = pos + 5; pos = strchr(start, ' '); if (pos) *pos++ = '\0'; method = eap_get_phase2_type(start); if (method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported " "Phase2 method '%s'", start); } else { num_methods++; _methods = realloc(methods, num_methods); if (_methods == NULL) { free(methods); free(buf); eap_fast_deinit(sm, data); return NULL; } methods = _methods; methods[num_methods - 1] = method; } start = pos; } 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", data->phase2_types, data->num_phase2_types); data->phase2_type = 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); free(data->phase2_types); free(data->key_block_a); 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); } 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 = 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"); 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_sm *sm, 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); wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos); wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types", data->phase2_types, data->num_phase2_types); *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types; *resp = malloc(*resp_len); if (*resp == NULL) return -1; resp_hdr = (struct eap_hdr *) (*resp); resp_hdr->code = EAP_CODE_RESPONSE; resp_hdr->identifier = hdr->identifier; resp_hdr->length = host_to_be16(*resp_len); pos = (u8 *) (resp_hdr + 1); *pos++ = EAP_TYPE_NAK; memcpy(pos, data->phase2_types, data->num_phase2_types); return 0;}static int eap_fast_derive_msk(struct eap_sm *sm, struct eap_fast_data *data){ u8 isk[32]; u8 imck[60]; if (data->key_block_a == NULL) return -1; memset(isk, 0, sizeof(isk)); sha1_t_prf(data->key_block_a->session_key_seed, sizeof(data->key_block_a->session_key_seed), "Inner Methods Compound Keys", isk, sizeof(isk), imck, sizeof(imck)); sha1_t_prf(imck, 40, "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); 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)) { 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 = malloc(seed_len); if (seed == NULL) return -1; memcpy(seed, server_random, server_random_len); 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)); 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; u8 *out; int block_size; if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) return NULL; block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn); if (block_size < 0) return NULL; out = malloc(block_size + 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.server_random, keys.server_random_len); 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)) { free(rnd); free(out); return NULL; } free(rnd); memmove(out, out + block_size, len); return out;}static void eap_fast_derive_key_auth(struct eap_sm *sm, struct eap_fast_data *data){ free(data->key_block_a); data->key_block_a = (struct eap_fast_key_block_auth *) eap_fast_derive_key(sm, &data->ssl, "key expansion", sizeof(*data->key_block_a)); if (data->key_block_a == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " "session_key_seed"); return; } wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed", data->key_block_a->session_key_seed, sizeof(data->key_block_a->session_key_seed));}static void eap_fast_derive_key_provisioning(struct eap_sm *sm, struct eap_fast_data *data){ 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; } wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed", data->key_block_p->session_key_seed, sizeof(data->key_block_p->session_key_seed)); 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, u8 **resp, size_t *resp_len){ size_t len = be_to_host16(hdr->length); u8 *pos; struct eap_method_ret iret; if (len <= sizeof(struct eap_hdr)) { wpa_printf(MSG_INFO, "EAP-FAST: too short " "Phase 2 request (len=%lu)", (unsigned long) len);
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -