123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- /*
- * EAP peer method: EAP-FAST PAC file processing
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
- #include "includes.h"
- #include "common.h"
- #include "eap_config.h"
- #include "eap_i.h"
- #include "eap_fast_pac.h"
- /* TODO: encrypt PAC-Key in the PAC file */
- /* Text data format */
- static const char *pac_file_hdr =
- "wpa_supplicant EAP-FAST PAC file - version 1";
- /*
- * Binary data format
- * 4-octet magic value: 6A E4 92 0C
- * 2-octet version (big endian)
- * <version specific data>
- *
- * version=0:
- * Sequence of PAC entries:
- * 2-octet PAC-Type (big endian)
- * 32-octet PAC-Key
- * 2-octet PAC-Opaque length (big endian)
- * <variable len> PAC-Opaque data (length bytes)
- * 2-octet PAC-Info length (big endian)
- * <variable len> PAC-Info data (length bytes)
- */
- #define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c
- #define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0
- /**
- * eap_fast_free_pac - Free PAC data
- * @pac: Pointer to the PAC entry
- *
- * Note that the PAC entry must not be in a list since this function does not
- * remove the list links.
- */
- void eap_fast_free_pac(struct eap_fast_pac *pac)
- {
- os_free(pac->pac_opaque);
- os_free(pac->pac_info);
- os_free(pac->a_id);
- os_free(pac->i_id);
- os_free(pac->a_id_info);
- os_free(pac);
- }
- /**
- * eap_fast_get_pac - Get a PAC entry based on A-ID
- * @pac_root: Pointer to root of the PAC list
- * @a_id: A-ID to search for
- * @a_id_len: Length of A-ID
- * @pac_type: PAC-Type to search for
- * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
- */
- struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
- const u8 *a_id, size_t a_id_len,
- u16 pac_type)
- {
- struct eap_fast_pac *pac = pac_root;
- while (pac) {
- if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
- os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
- return pac;
- }
- pac = pac->next;
- }
- return NULL;
- }
- static void eap_fast_remove_pac(struct eap_fast_pac **pac_root,
- struct eap_fast_pac **pac_current,
- const u8 *a_id, size_t a_id_len, u16 pac_type)
- {
- struct eap_fast_pac *pac, *prev;
- pac = *pac_root;
- prev = NULL;
- while (pac) {
- if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
- os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
- if (prev == NULL)
- *pac_root = pac->next;
- else
- prev->next = pac->next;
- if (*pac_current == pac)
- *pac_current = NULL;
- eap_fast_free_pac(pac);
- break;
- }
- prev = pac;
- pac = pac->next;
- }
- }
- static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
- const u8 *src, size_t src_len)
- {
- if (src) {
- *dst = os_malloc(src_len);
- if (*dst == NULL)
- return -1;
- os_memcpy(*dst, src, src_len);
- *dst_len = src_len;
- }
- return 0;
- }
- /**
- * eap_fast_add_pac - Add a copy of a PAC entry to a list
- * @pac_root: Pointer to PAC list root pointer
- * @pac_current: Pointer to the current PAC pointer
- * @entry: New entry to clone and add to the list
- * Returns: 0 on success, -1 on failure
- *
- * This function makes a clone of the given PAC entry and adds this copied
- * entry to the list (pac_root). If an old entry for the same A-ID is found,
- * it will be removed from the PAC list and in this case, pac_current entry
- * is set to %NULL if it was the removed entry.
- */
- int eap_fast_add_pac(struct eap_fast_pac **pac_root,
- struct eap_fast_pac **pac_current,
- struct eap_fast_pac *entry)
- {
- struct eap_fast_pac *pac;
- if (entry == NULL || entry->a_id == NULL)
- return -1;
- /* Remove a possible old entry for the matching A-ID. */
- eap_fast_remove_pac(pac_root, pac_current,
- entry->a_id, entry->a_id_len, entry->pac_type);
- /* Allocate a new entry and add it to the list of PACs. */
- pac = os_zalloc(sizeof(*pac));
- if (pac == NULL)
- return -1;
- pac->pac_type = entry->pac_type;
- os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
- if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
- entry->pac_opaque, entry->pac_opaque_len) < 0 ||
- eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len,
- entry->pac_info, entry->pac_info_len) < 0 ||
- eap_fast_copy_buf(&pac->a_id, &pac->a_id_len,
- entry->a_id, entry->a_id_len) < 0 ||
- eap_fast_copy_buf(&pac->i_id, &pac->i_id_len,
- entry->i_id, entry->i_id_len) < 0 ||
- eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
- entry->a_id_info, entry->a_id_info_len) < 0) {
- eap_fast_free_pac(pac);
- return -1;
- }
- pac->next = *pac_root;
- *pac_root = pac;
- return 0;
- }
- struct eap_fast_read_ctx {
- FILE *f;
- const char *pos;
- const char *end;
- int line;
- char *buf;
- size_t buf_len;
- };
- static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value)
- {
- char *pos;
- rc->line++;
- if (rc->f) {
- if (fgets(rc->buf, rc->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 >= rc->buf_len)
- len = rc->buf_len - 1;
- os_memcpy(rc->buf, rc->pos, len);
- rc->buf[len] = '\0';
- rc->pos = l_end + 1;
- }
- rc->buf[rc->buf_len - 1] = '\0';
- pos = rc->buf;
- while (*pos != '\0') {
- if (*pos == '\n' || *pos == '\r') {
- *pos = '\0';
- break;
- }
- pos++;
- }
- pos = os_strchr(rc->buf, '=');
- if (pos)
- *pos++ = '\0';
- *value = 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 = os_strlen(value);
- if (hlen & 1)
- return NULL;
- *len = hlen / 2;
- buf = os_malloc(*len);
- if (buf == NULL)
- return NULL;
- if (hexstr2bin(value, buf, *len)) {
- os_free(buf);
- return NULL;
- }
- return buf;
- }
- static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file,
- struct eap_fast_read_ctx *rc)
- {
- os_memset(rc, 0, sizeof(*rc));
- rc->buf_len = 2048;
- rc->buf = os_malloc(rc->buf_len);
- if (rc->buf == NULL)
- return -1;
- if (os_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);
- os_free(rc->buf);
- return -1;
- }
- rc->pos = (char *) blob->data;
- rc->end = (char *) blob->data + blob->len;
- } else {
- rc->f = fopen(pac_file, "rb");
- if (rc->f == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
- "assume no PAC entries have been "
- "provisioned", pac_file);
- os_free(rc->buf);
- return -1;
- }
- }
- return 0;
- }
- static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc)
- {
- os_free(rc->buf);
- if (rc->f)
- fclose(rc->f);
- }
- static const char * eap_fast_parse_start(struct eap_fast_pac **pac)
- {
- if (*pac)
- return "START line without END";
- *pac = os_zalloc(sizeof(struct eap_fast_pac));
- if (*pac == NULL)
- return "No memory for PAC entry";
- (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
- return NULL;
- }
- static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
- struct eap_fast_pac **pac)
- {
- if (*pac == NULL)
- return "END line without START";
- if (*pac_root) {
- struct eap_fast_pac *end = *pac_root;
- while (end->next)
- end = end->next;
- end->next = *pac;
- } else
- *pac_root = *pac;
- *pac = NULL;
- return NULL;
- }
- static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
- char *pos)
- {
- if (!pos)
- return "Cannot parse pac type";
- pac->pac_type = atoi(pos);
- if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
- pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
- pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION)
- return "Unrecognized PAC-Type";
- return NULL;
- }
- static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos)
- {
- u8 *key;
- size_t key_len;
- key = eap_fast_parse_hex(pos, &key_len);
- if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
- os_free(key);
- return "Invalid PAC-Key";
- }
- os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
- os_free(key);
- return NULL;
- }
- static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac,
- char *pos)
- {
- os_free(pac->pac_opaque);
- pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len);
- if (pac->pac_opaque == NULL)
- return "Invalid PAC-Opaque";
- return NULL;
- }
- static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos)
- {
- os_free(pac->a_id);
- pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
- if (pac->a_id == NULL)
- return "Invalid A-ID";
- return NULL;
- }
- static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos)
- {
- os_free(pac->i_id);
- pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
- if (pac->i_id == NULL)
- return "Invalid I-ID";
- return NULL;
- }
- static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac,
- char *pos)
- {
- os_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)
- return "Invalid A-ID-Info";
- return NULL;
- }
- /**
- * eap_fast_load_pac - Load PAC entries (text format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Pointer to root of the PAC list (to be filled)
- * @pac_file: Name of the PAC file/blob to load
- * Returns: 0 on success, -1 on failure
- */
- int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
- const char *pac_file)
- {
- struct eap_fast_read_ctx rc;
- struct eap_fast_pac *pac = NULL;
- int count = 0;
- char *pos;
- const char *err = NULL;
- if (pac_file == NULL)
- return -1;
- if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
- return 0;
- if (eap_fast_read_line(&rc, &pos) < 0) {
- /* empty file - assume it is fine to overwrite */
- eap_fast_deinit_pac_data(&rc);
- return 0;
- }
- if (os_strcmp(pac_file_hdr, rc.buf) != 0)
- err = "Unrecognized header line";
- while (!err && eap_fast_read_line(&rc, &pos) == 0) {
- if (os_strcmp(rc.buf, "START") == 0)
- err = eap_fast_parse_start(&pac);
- else if (os_strcmp(rc.buf, "END") == 0) {
- err = eap_fast_parse_end(pac_root, &pac);
- count++;
- } else if (!pac)
- err = "Unexpected line outside START/END block";
- else if (os_strcmp(rc.buf, "PAC-Type") == 0)
- err = eap_fast_parse_pac_type(pac, pos);
- else if (os_strcmp(rc.buf, "PAC-Key") == 0)
- err = eap_fast_parse_pac_key(pac, pos);
- else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
- err = eap_fast_parse_pac_opaque(pac, pos);
- else if (os_strcmp(rc.buf, "A-ID") == 0)
- err = eap_fast_parse_a_id(pac, pos);
- else if (os_strcmp(rc.buf, "I-ID") == 0)
- err = eap_fast_parse_i_id(pac, pos);
- else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
- err = eap_fast_parse_a_id_info(pac, pos);
- }
- if (pac) {
- err = "PAC block not terminated with END";
- eap_fast_free_pac(pac);
- }
- eap_fast_deinit_pac_data(&rc);
- if (err) {
- wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'",
- err, pac_file, rc.line);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'",
- count, pac_file);
- return 0;
- }
- static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
- const char *field, const u8 *data,
- size_t len, int txt)
- {
- size_t i, need;
- int ret;
- char *end;
- if (data == NULL || buf == NULL || *buf == NULL ||
- pos == NULL || *pos == NULL || *pos < *buf)
- return;
- need = os_strlen(field) + len * 2 + 30;
- if (txt)
- need += os_strlen(field) + len + 20;
- if (*pos - *buf + need > *buf_len) {
- char *nbuf = os_realloc(*buf, *buf_len + need);
- if (nbuf == NULL) {
- os_free(*buf);
- *buf = NULL;
- return;
- }
- *pos = nbuf + (*pos - *buf);
- *buf = nbuf;
- *buf_len += need;
- }
- end = *buf + *buf_len;
- ret = os_snprintf(*pos, end - *pos, "%s=", field);
- if (ret < 0 || ret >= end - *pos)
- return;
- *pos += ret;
- *pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
- ret = os_snprintf(*pos, end - *pos, "\n");
- if (ret < 0 || ret >= end - *pos)
- return;
- *pos += ret;
- if (txt) {
- ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
- if (ret < 0 || ret >= end - *pos)
- return;
- *pos += ret;
- for (i = 0; i < len; i++) {
- ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
- if (ret < 0 || ret >= end - *pos)
- return;
- *pos += ret;
- }
- ret = os_snprintf(*pos, end - *pos, "\n");
- if (ret < 0 || ret >= end - *pos)
- return;
- *pos += ret;
- }
- }
- static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file,
- char *buf, size_t len)
- {
- if (os_strncmp(pac_file, "blob://", 7) == 0) {
- struct wpa_config_blob *blob;
- blob = os_zalloc(sizeof(*blob));
- if (blob == NULL)
- return -1;
- blob->data = (u8 *) buf;
- blob->len = len;
- buf = NULL;
- blob->name = os_strdup(pac_file + 7);
- if (blob->name == NULL) {
- os_free(blob);
- return -1;
- }
- eap_set_config_blob(sm, blob);
- } else {
- FILE *f;
- f = fopen(pac_file, "wb");
- if (f == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
- "file '%s' for writing", pac_file);
- return -1;
- }
- if (fwrite(buf, 1, len, f) != len) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all "
- "PACs into '%s'", pac_file);
- fclose(f);
- return -1;
- }
- os_free(buf);
- fclose(f);
- }
- return 0;
- }
- static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
- char **pos, size_t *buf_len)
- {
- int ret;
- ret = os_snprintf(*pos, *buf + *buf_len - *pos,
- "START\nPAC-Type=%d\n", pac->pac_type);
- if (ret < 0 || ret >= *buf + *buf_len - *pos)
- 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)
- return -1;
- *pos += ret;
- return 0;
- }
- /**
- * eap_fast_save_pac - Save PAC entries (text format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Root of the PAC list
- * @pac_file: Name of the PAC file/blob
- * Returns: 0 on success, -1 on failure
- */
- int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
- const char *pac_file)
- {
- struct eap_fast_pac *pac;
- int ret, count = 0;
- 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 = pac_root;
- while (pac) {
- if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) {
- os_free(buf);
- return -1;
- }
- count++;
- pac = pac->next;
- }
- if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) {
- os_free(buf);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'",
- count, pac_file);
- return 0;
- }
- /**
- * eap_fast_pac_list_truncate - Truncate a PAC list to the given length
- * @pac_root: Root of the PAC list
- * @max_len: Maximum length of the list (>= 1)
- * Returns: Number of PAC entries removed
- */
- size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
- size_t max_len)
- {
- struct eap_fast_pac *pac, *prev;
- size_t count;
- pac = pac_root;
- prev = NULL;
- count = 0;
- while (pac) {
- count++;
- if (count > max_len)
- break;
- prev = pac;
- pac = pac->next;
- }
- if (count <= max_len || prev == NULL)
- return 0;
- count = 0;
- prev->next = NULL;
- while (pac) {
- prev = pac;
- pac = pac->next;
- eap_fast_free_pac(prev);
- count++;
- }
- return count;
- }
- static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
- {
- u8 *pos, *end;
- u16 type, len;
- pos = pac->pac_info;
- end = pos + pac->pac_info_len;
- while (pos + 4 < end) {
- type = WPA_GET_BE16(pos);
- pos += 2;
- len = WPA_GET_BE16(pos);
- pos += 2;
- if (pos + len > end)
- break;
- if (type == PAC_TYPE_A_ID) {
- os_free(pac->a_id);
- pac->a_id = os_malloc(len);
- if (pac->a_id == NULL)
- break;
- os_memcpy(pac->a_id, pos, len);
- pac->a_id_len = len;
- }
- if (type == PAC_TYPE_A_ID_INFO) {
- os_free(pac->a_id_info);
- pac->a_id_info = os_malloc(len);
- if (pac->a_id_info == NULL)
- break;
- os_memcpy(pac->a_id_info, pos, len);
- pac->a_id_info_len = len;
- }
- pos += len;
- }
- }
- /**
- * eap_fast_load_pac_bin - Load PAC entries (binary format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Pointer to root of the PAC list (to be filled)
- * @pac_file: Name of the PAC file/blob to load
- * Returns: 0 on success, -1 on failure
- */
- int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
- const char *pac_file)
- {
- const struct wpa_config_blob *blob = NULL;
- u8 *buf, *end, *pos;
- size_t len, count = 0;
- struct eap_fast_pac *pac, *prev;
- *pac_root = NULL;
- if (pac_file == NULL)
- return -1;
- if (os_strncmp(pac_file, "blob://", 7) == 0) {
- 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;
- }
- buf = blob->data;
- len = blob->len;
- } else {
- buf = (u8 *) os_readfile(pac_file, &len);
- if (buf == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
- "assume no PAC entries have been "
- "provisioned", pac_file);
- return 0;
- }
- }
- if (len == 0) {
- if (blob == NULL)
- os_free(buf);
- return 0;
- }
- if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC ||
- WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) {
- wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)",
- pac_file);
- if (blob == NULL)
- os_free(buf);
- return -1;
- }
- pac = prev = NULL;
- pos = buf + 6;
- end = buf + len;
- while (pos < end) {
- if (end - pos < 2 + 32 + 2 + 2)
- goto parse_fail;
- pac = os_zalloc(sizeof(*pac));
- if (pac == NULL)
- goto parse_fail;
- pac->pac_type = WPA_GET_BE16(pos);
- pos += 2;
- os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
- pos += EAP_FAST_PAC_KEY_LEN;
- pac->pac_opaque_len = WPA_GET_BE16(pos);
- pos += 2;
- if (pos + pac->pac_opaque_len + 2 > end)
- goto parse_fail;
- pac->pac_opaque = os_malloc(pac->pac_opaque_len);
- if (pac->pac_opaque == NULL)
- goto parse_fail;
- os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
- pos += pac->pac_opaque_len;
- pac->pac_info_len = WPA_GET_BE16(pos);
- pos += 2;
- if (pos + pac->pac_info_len > end)
- goto parse_fail;
- pac->pac_info = os_malloc(pac->pac_info_len);
- if (pac->pac_info == NULL)
- goto parse_fail;
- os_memcpy(pac->pac_info, pos, pac->pac_info_len);
- pos += pac->pac_info_len;
- eap_fast_pac_get_a_id(pac);
- count++;
- if (prev)
- prev->next = pac;
- else
- *pac_root = pac;
- prev = pac;
- }
- if (blob == NULL)
- os_free(buf);
- wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)",
- (unsigned long) count, pac_file);
- return 0;
- parse_fail:
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)",
- pac_file);
- if (blob == NULL)
- os_free(buf);
- if (pac)
- eap_fast_free_pac(pac);
- return -1;
- }
- /**
- * eap_fast_save_pac_bin - Save PAC entries (binary format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Root of the PAC list
- * @pac_file: Name of the PAC file/blob
- * Returns: 0 on success, -1 on failure
- */
- int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
- const char *pac_file)
- {
- size_t len, count = 0;
- struct eap_fast_pac *pac;
- u8 *buf, *pos;
- len = 6;
- pac = pac_root;
- while (pac) {
- if (pac->pac_opaque_len > 65535 ||
- pac->pac_info_len > 65535)
- return -1;
- len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
- 2 + pac->pac_info_len;
- pac = pac->next;
- }
- buf = os_malloc(len);
- if (buf == NULL)
- return -1;
- pos = buf;
- WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC);
- pos += 4;
- WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION);
- pos += 2;
- pac = pac_root;
- while (pac) {
- WPA_PUT_BE16(pos, pac->pac_type);
- pos += 2;
- os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN);
- pos += EAP_FAST_PAC_KEY_LEN;
- WPA_PUT_BE16(pos, pac->pac_opaque_len);
- pos += 2;
- os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
- pos += pac->pac_opaque_len;
- WPA_PUT_BE16(pos, pac->pac_info_len);
- pos += 2;
- os_memcpy(pos, pac->pac_info, pac->pac_info_len);
- pos += pac->pac_info_len;
- pac = pac->next;
- count++;
- }
- if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) {
- os_free(buf);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' "
- "(bin)", (unsigned long) count, pac_file);
- return 0;
- }
|