?? eap_fast.c
字號(hào):
/* * WPA Supplicant / EAP-FAST (draft-cam-winget-eap-fast-00.txt) * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include "common.h"#include "eap_i.h"#include "eap_tls_common.h"#include "wpa_supplicant.h"#include "config_ssid.h"#include "tls.h"#include "eap_tlv.h"#include "sha1.h"#include "config.h"/* TODO: * - encrypt PAC-Key in the PAC file * - test session resumption and enable it if it interoperates * - password change (pending mschapv2 packet; replay decrypted packet) */#define EAP_FAST_VERSION 1#define EAP_FAST_KEY_LEN 64#define EAP_FAST_PAC_KEY_LEN 32#define TLS_EXT_PAC_OPAQUE 35static const char *pac_file_hdr = "wpa_supplicant EAP-FAST PAC file - version 1";static void eap_fast_deinit(struct eap_sm *sm, void *priv);#define PAC_TYPE_PAC_KEY 1#define PAC_TYPE_PAC_OPAQUE 2#define PAC_TYPE_CRED_LIFETIME 3#define PAC_TYPE_A_ID 4#define PAC_TYPE_I_ID 5#define PAC_TYPE_SERVER_PROTECTED_DATA 6#define PAC_TYPE_A_ID_INFO 7#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8#define PAC_TYPE_PAC_INFO 9struct pac_tlv_hdr { u16 type; u16 len;};/* draft-cam-winget-eap-fast-02.txt: * 6.2 EAP-FAST Authentication Phase 1: Key Derivations */struct eap_fast_key_block_auth { /* Extra key material after TLS key_block */ u8 session_key_seed[40];};/* draft-cam-winget-eap-fast-provisioning-01.txt: * 3.4 Key Derivations Used in the EAP-FAST Provisioning Exchange */struct eap_fast_key_block_provisioning { /* Extra key material after TLS key_block */ u8 session_key_seed[40]; u8 server_challenge[16]; u8 client_challenge[16];};struct eap_fast_pac { struct eap_fast_pac *next; u8 pac_key[EAP_FAST_PAC_KEY_LEN]; u8 *pac_opaque; size_t pac_opaque_len; u8 *pac_info; size_t pac_info_len; u8 *a_id; size_t a_id_len; u8 *i_id; size_t i_id_len; u8 *a_id_info; size_t a_id_info_len;};struct eap_fast_data { struct eap_ssl_data ssl; int fast_version; const struct eap_method *phase2_method; void *phase2_priv; int phase2_success; u8 phase2_type; u8 *phase2_types; size_t num_phase2_types; int resuming; /* starting a resumed session */ struct eap_fast_key_block_auth *key_block_a; struct eap_fast_key_block_provisioning *key_block_p; int provisioning_allowed; /* is PAC provisioning allowed */ int provisioning; /* doing PAC provisioning (not the normal auth) */ u8 key_data[EAP_FAST_KEY_LEN]; int success; struct eap_fast_pac *pac; struct eap_fast_pac *current_pac; int tls_master_secret_set;};static void eap_fast_free_pac(struct eap_fast_pac *pac){ free(pac->pac_opaque); free(pac->pac_info); free(pac->a_id); free(pac->i_id); free(pac->a_id_info); free(pac);}static struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_data *data, const u8 *a_id, size_t a_id_len){ struct eap_fast_pac *pac = data->pac; while (pac) { if (pac->a_id_len == a_id_len && memcmp(pac->a_id, a_id, a_id_len) == 0) { return pac; } pac = pac->next; } return NULL;}static int eap_fast_add_pac(struct eap_fast_data *data, struct eap_fast_pac *entry){ struct eap_fast_pac *pac, *prev; if (entry == NULL || entry->a_id == NULL) return -1; /* Remove a possible old entry for the matching A-ID. */ pac = data->pac; prev = NULL; while (pac) { if (pac->a_id_len == entry->a_id_len && memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) { if (prev == NULL) { data->pac = pac->next; } else { prev->next = pac->next; } if (data->current_pac == pac) data->current_pac = NULL; eap_fast_free_pac(pac); break; } prev = pac; pac = pac->next; } /* Allocate a new entry and add it to the list of PACs. */ pac = malloc(sizeof(*pac)); if (pac == NULL) return -1; memset(pac, 0, sizeof(*pac)); memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN); if (entry->pac_opaque) { pac->pac_opaque = malloc(entry->pac_opaque_len); if (pac->pac_opaque == NULL) { eap_fast_free_pac(pac); return -1; } memcpy(pac->pac_opaque, entry->pac_opaque, entry->pac_opaque_len); pac->pac_opaque_len = entry->pac_opaque_len; } if (entry->pac_info) { pac->pac_info = malloc(entry->pac_info_len); if (pac->pac_info == NULL) { eap_fast_free_pac(pac); return -1; } memcpy(pac->pac_info, entry->pac_info, entry->pac_info_len); pac->pac_info_len = entry->pac_info_len; } if (entry->a_id) { pac->a_id = malloc(entry->a_id_len); if (pac->a_id == NULL) { eap_fast_free_pac(pac); return -1; } memcpy(pac->a_id, entry->a_id, entry->a_id_len); pac->a_id_len = entry->a_id_len; } if (entry->i_id) { pac->i_id = malloc(entry->i_id_len); if (pac->i_id == NULL) { eap_fast_free_pac(pac); return -1; } memcpy(pac->i_id, entry->i_id, entry->i_id_len); pac->i_id_len = entry->i_id_len; } if (entry->a_id_info) { pac->a_id_info = malloc(entry->a_id_info_len); if (pac->a_id_info == NULL) { eap_fast_free_pac(pac); return -1; } memcpy(pac->a_id_info, entry->a_id_info, entry->a_id_info_len); pac->a_id_info_len = entry->a_id_info_len; } pac->next = data->pac; data->pac = pac; return 0;}struct eap_fast_read_ctx { FILE *f; const char *pos; const char *end;};static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf, size_t buf_len){ char *pos; if (rc->f) { if (fgets(buf, buf_len, rc->f) == NULL) return -1; } else { const char *l_end; size_t len; if (rc->pos >= rc->end) return -1; l_end = rc->pos; while (l_end < rc->end && *l_end != '\n') l_end++; len = l_end - rc->pos; if (len >= buf_len) len = buf_len - 1; memcpy(buf, rc->pos, len); buf[len] = '\0'; rc->pos = l_end + 1; } buf[buf_len - 1] = '\0'; pos = buf; while (*pos != '\0') { if (*pos == '\n' || *pos == '\r') { *pos = '\0'; break; } pos++; } return 0;}static u8 * eap_fast_parse_hex(const char *value, size_t *len){ int hlen; u8 *buf; if (value == NULL) return NULL; hlen = strlen(value); if (hlen & 1) return NULL; *len = hlen / 2; buf = malloc(*len); if (buf == NULL) return NULL; if (hexstr2bin(value, buf, *len)) { free(buf); return NULL; } return buf;}static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data, const char *pac_file){ struct eap_fast_read_ctx rc; struct eap_fast_pac *pac = NULL; int count = 0; char *buf, *pos; const int buf_len = 2048; int ret = 0, line = 0; if (pac_file == NULL) return -1; memset(&rc, 0, sizeof(rc)); if (strncmp(pac_file, "blob://", 7) == 0) { const struct wpa_config_blob *blob; blob = eap_get_config_blob(sm, pac_file + 7); if (blob == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - " "assume no PAC entries have been " "provisioned", pac_file + 7); return 0; } rc.pos = (char *) blob->data; rc.end = (char *) blob->data + blob->len; } else { rc.f = fopen(pac_file, "r"); if (rc.f == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - " "assume no PAC entries have been " "provisioned", pac_file); return 0; } } buf = malloc(buf_len); if (buf == NULL) { return -1; } line++; if (eap_fast_read_line(&rc, buf, buf_len) < 0 || strcmp(pac_file_hdr, buf) != 0) { wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in " "PAC file '%s'", pac_file); free(buf); if (rc.f) fclose(rc.f); return -1; } while (eap_fast_read_line(&rc, buf, buf_len) == 0) { line++; pos = strchr(buf, '='); if (pos) { *pos++ = '\0'; } if (strcmp(buf, "START") == 0) { if (pac) { wpa_printf(MSG_INFO, "EAP-FAST: START line " "without END in '%s:%d'", pac_file, line); ret = -1; break; } pac = malloc(sizeof(*pac)); if (pac == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: No memory for " "PAC entry"); ret = -1; break; } memset(pac, 0, sizeof(*pac)); } else if (strcmp(buf, "END") == 0) { if (pac == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: END line " "without START in '%s:%d'", pac_file, line); ret = -1; break; } pac->next = data->pac; data->pac = pac; pac = NULL; count++; } else if (pac && strcmp(buf, "PAC-Key") == 0) { u8 *key; size_t key_len; key = eap_fast_parse_hex(pos, &key_len); if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid " "PAC-Key '%s:%d'", pac_file, line); ret = -1; free(key); break; } memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN); free(key); } else if (pac && strcmp(buf, "PAC-Opaque") == 0) { free(pac->pac_opaque); pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len); if (pac->pac_opaque == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid " "PAC-Opaque '%s:%d'", pac_file, line); ret = -1; break; } } else if (pac && strcmp(buf, "A-ID") == 0) { free(pac->a_id); pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len); if (pac->a_id == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid " "A-ID '%s:%d'", pac_file, line); ret = -1; break; } } else if (pac && strcmp(buf, "I-ID") == 0) { free(pac->i_id); pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len); if (pac->i_id == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid " "I-ID '%s:%d'", pac_file, line); ret = -1; break; } } else if (pac && strcmp(buf, "A-ID-Info") == 0) { free(pac->a_id_info); pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len); if (pac->a_id_info == NULL) { wpa_printf(MSG_INFO, "EAP-FAST: Invalid " "A-ID-Info '%s:%d'", pac_file, line); ret = -1; break; } } } if (pac) { wpa_printf(MSG_INFO, "EAP-FAST: PAC block not terminated with " "END in '%s'", pac_file); eap_fast_free_pac(pac); ret = -1; } free(buf); if (rc.f) fclose(rc.f); if (ret == 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: read %d PAC entries from " "'%s'", count, pac_file); } return ret;}static void eap_fast_write(char **buf, char **pos, size_t *buf_len, const char *field, const u8 *data, size_t len, int txt){ int i; size_t need; if (data == NULL || *buf == NULL) return; need = strlen(field) + len * 2 + 30; if (txt) need += strlen(field) + len + 20; if (*pos - *buf + need > *buf_len) { char *nbuf = realloc(*buf, *buf_len + need); if (nbuf == NULL) { free(*buf); *buf = NULL; return; } *buf = nbuf; *buf_len += need; }
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -