00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "includes.h"
00016
00017 #include "common.h"
00018 #include "eap_config.h"
00019 #include "eap_i.h"
00020 #include "eap_fast_pac.h"
00021
00022
00023
00024
00025
00026 static const char *pac_file_hdr =
00027 "wpa_supplicant EAP-FAST PAC file - version 1";
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c
00046 #define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0
00047
00048
00056 void eap_fast_free_pac(struct eap_fast_pac *pac)
00057 {
00058 os_free(pac->pac_opaque);
00059 os_free(pac->pac_info);
00060 os_free(pac->a_id);
00061 os_free(pac->i_id);
00062 os_free(pac->a_id_info);
00063 os_free(pac);
00064 }
00065
00066
00075 struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
00076 const u8 *a_id, size_t a_id_len,
00077 u16 pac_type)
00078 {
00079 struct eap_fast_pac *pac = pac_root;
00080
00081 while (pac) {
00082 if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
00083 os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
00084 return pac;
00085 }
00086 pac = pac->next;
00087 }
00088 return NULL;
00089 }
00090
00091
00092 static void eap_fast_remove_pac(struct eap_fast_pac **pac_root,
00093 struct eap_fast_pac **pac_current,
00094 const u8 *a_id, size_t a_id_len, u16 pac_type)
00095 {
00096 struct eap_fast_pac *pac, *prev;
00097
00098 pac = *pac_root;
00099 prev = NULL;
00100
00101 while (pac) {
00102 if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
00103 os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
00104 if (prev == NULL)
00105 *pac_root = pac->next;
00106 else
00107 prev->next = pac->next;
00108 if (*pac_current == pac)
00109 *pac_current = NULL;
00110 eap_fast_free_pac(pac);
00111 break;
00112 }
00113 prev = pac;
00114 pac = pac->next;
00115 }
00116 }
00117
00118
00119 static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
00120 const u8 *src, size_t src_len)
00121 {
00122 if (src) {
00123 *dst = os_malloc(src_len);
00124 if (*dst == NULL)
00125 return -1;
00126 os_memcpy(*dst, src, src_len);
00127 *dst_len = src_len;
00128 }
00129 return 0;
00130 }
00131
00132
00145 int eap_fast_add_pac(struct eap_fast_pac **pac_root,
00146 struct eap_fast_pac **pac_current,
00147 struct eap_fast_pac *entry)
00148 {
00149 struct eap_fast_pac *pac;
00150
00151 if (entry == NULL || entry->a_id == NULL)
00152 return -1;
00153
00154
00155 eap_fast_remove_pac(pac_root, pac_current,
00156 entry->a_id, entry->a_id_len, entry->pac_type);
00157
00158
00159 pac = os_zalloc(sizeof(*pac));
00160 if (pac == NULL)
00161 return -1;
00162
00163 pac->pac_type = entry->pac_type;
00164 os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
00165 if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
00166 entry->pac_opaque, entry->pac_opaque_len) < 0 ||
00167 eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len,
00168 entry->pac_info, entry->pac_info_len) < 0 ||
00169 eap_fast_copy_buf(&pac->a_id, &pac->a_id_len,
00170 entry->a_id, entry->a_id_len) < 0 ||
00171 eap_fast_copy_buf(&pac->i_id, &pac->i_id_len,
00172 entry->i_id, entry->i_id_len) < 0 ||
00173 eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
00174 entry->a_id_info, entry->a_id_info_len) < 0) {
00175 eap_fast_free_pac(pac);
00176 return -1;
00177 }
00178
00179 pac->next = *pac_root;
00180 *pac_root = pac;
00181
00182 return 0;
00183 }
00184
00185
00186 struct eap_fast_read_ctx {
00187 FILE *f;
00188 const char *pos;
00189 const char *end;
00190 int line;
00191 char *buf;
00192 size_t buf_len;
00193 };
00194
00195 static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value)
00196 {
00197 char *pos;
00198
00199 rc->line++;
00200 if (rc->f) {
00201 if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
00202 return -1;
00203 } else {
00204 const char *l_end;
00205 size_t len;
00206 if (rc->pos >= rc->end)
00207 return -1;
00208 l_end = rc->pos;
00209 while (l_end < rc->end && *l_end != '\n')
00210 l_end++;
00211 len = l_end - rc->pos;
00212 if (len >= rc->buf_len)
00213 len = rc->buf_len - 1;
00214 os_memcpy(rc->buf, rc->pos, len);
00215 rc->buf[len] = '\0';
00216 rc->pos = l_end + 1;
00217 }
00218
00219 rc->buf[rc->buf_len - 1] = '\0';
00220 pos = rc->buf;
00221 while (*pos != '\0') {
00222 if (*pos == '\n' || *pos == '\r') {
00223 *pos = '\0';
00224 break;
00225 }
00226 pos++;
00227 }
00228
00229 pos = os_strchr(rc->buf, '=');
00230 if (pos)
00231 *pos++ = '\0';
00232 *value = pos;
00233
00234 return 0;
00235 }
00236
00237
00238 static u8 * eap_fast_parse_hex(const char *value, size_t *len)
00239 {
00240 int hlen;
00241 u8 *buf;
00242
00243 if (value == NULL)
00244 return NULL;
00245 hlen = os_strlen(value);
00246 if (hlen & 1)
00247 return NULL;
00248 *len = hlen / 2;
00249 buf = os_malloc(*len);
00250 if (buf == NULL)
00251 return NULL;
00252 if (hexstr2bin(value, buf, *len)) {
00253 os_free(buf);
00254 return NULL;
00255 }
00256 return buf;
00257 }
00258
00259
00260 static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file,
00261 struct eap_fast_read_ctx *rc)
00262 {
00263 os_memset(rc, 0, sizeof(*rc));
00264
00265 rc->buf_len = 2048;
00266 rc->buf = os_malloc(rc->buf_len);
00267 if (rc->buf == NULL)
00268 return -1;
00269
00270 if (os_strncmp(pac_file, "blob://", 7) == 0) {
00271 const struct wpa_config_blob *blob;
00272 blob = eap_get_config_blob(sm, pac_file + 7);
00273 if (blob == NULL) {
00274 wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
00275 "assume no PAC entries have been "
00276 "provisioned", pac_file + 7);
00277 os_free(rc->buf);
00278 return -1;
00279 }
00280 rc->pos = (char *) blob->data;
00281 rc->end = (char *) blob->data + blob->len;
00282 } else {
00283 rc->f = fopen(pac_file, "rb");
00284 if (rc->f == NULL) {
00285 wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
00286 "assume no PAC entries have been "
00287 "provisioned", pac_file);
00288 os_free(rc->buf);
00289 return -1;
00290 }
00291 }
00292
00293 return 0;
00294 }
00295
00296
00297 static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc)
00298 {
00299 os_free(rc->buf);
00300 if (rc->f)
00301 fclose(rc->f);
00302 }
00303
00304
00305 static const char * eap_fast_parse_start(struct eap_fast_pac **pac)
00306 {
00307 if (*pac)
00308 return "START line without END";
00309
00310 *pac = os_zalloc(sizeof(struct eap_fast_pac));
00311 if (*pac == NULL)
00312 return "No memory for PAC entry";
00313 (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
00314 return NULL;
00315 }
00316
00317
00318 static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
00319 struct eap_fast_pac **pac)
00320 {
00321 if (*pac == NULL)
00322 return "END line without START";
00323 if (*pac_root) {
00324 struct eap_fast_pac *end = *pac_root;
00325 while (end->next)
00326 end = end->next;
00327 end->next = *pac;
00328 } else
00329 *pac_root = *pac;
00330
00331 *pac = NULL;
00332 return NULL;
00333 }
00334
00335
00336 static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
00337 char *pos)
00338 {
00339 pac->pac_type = atoi(pos);
00340 if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
00341 pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
00342 pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION)
00343 return "Unrecognized PAC-Type";
00344
00345 return NULL;
00346 }
00347
00348
00349 static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos)
00350 {
00351 u8 *key;
00352 size_t key_len;
00353
00354 key = eap_fast_parse_hex(pos, &key_len);
00355 if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
00356 os_free(key);
00357 return "Invalid PAC-Key";
00358 }
00359
00360 os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
00361 os_free(key);
00362
00363 return NULL;
00364 }
00365
00366
00367 static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac,
00368 char *pos)
00369 {
00370 os_free(pac->pac_opaque);
00371 pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len);
00372 if (pac->pac_opaque == NULL)
00373 return "Invalid PAC-Opaque";
00374 return NULL;
00375 }
00376
00377
00378 static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos)
00379 {
00380 os_free(pac->a_id);
00381 pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
00382 if (pac->a_id == NULL)
00383 return "Invalid A-ID";
00384 return NULL;
00385 }
00386
00387
00388 static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos)
00389 {
00390 os_free(pac->i_id);
00391 pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
00392 if (pac->i_id == NULL)
00393 return "Invalid I-ID";
00394 return NULL;
00395 }
00396
00397
00398 static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac,
00399 char *pos)
00400 {
00401 os_free(pac->a_id_info);
00402 pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len);
00403 if (pac->a_id_info == NULL)
00404 return "Invalid A-ID-Info";
00405 return NULL;
00406 }
00407
00408
00416 int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
00417 const char *pac_file)
00418 {
00419 struct eap_fast_read_ctx rc;
00420 struct eap_fast_pac *pac = NULL;
00421 int count = 0;
00422 char *pos;
00423 const char *err = NULL;
00424
00425 if (pac_file == NULL)
00426 return -1;
00427
00428 if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
00429 return 0;
00430
00431 if (eap_fast_read_line(&rc, &pos) < 0 ||
00432 os_strcmp(pac_file_hdr, rc.buf) != 0)
00433 err = "Unrecognized header line";
00434
00435 while (!err && eap_fast_read_line(&rc, &pos) == 0) {
00436 if (os_strcmp(rc.buf, "START") == 0)
00437 err = eap_fast_parse_start(&pac);
00438 else if (os_strcmp(rc.buf, "END") == 0) {
00439 err = eap_fast_parse_end(pac_root, &pac);
00440 count++;
00441 } else if (!pac)
00442 err = "Unexpected line outside START/END block";
00443 else if (os_strcmp(rc.buf, "PAC-Type") == 0)
00444 err = eap_fast_parse_pac_type(pac, pos);
00445 else if (os_strcmp(rc.buf, "PAC-Key") == 0)
00446 err = eap_fast_parse_pac_key(pac, pos);
00447 else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
00448 err = eap_fast_parse_pac_opaque(pac, pos);
00449 else if (os_strcmp(rc.buf, "A-ID") == 0)
00450 err = eap_fast_parse_a_id(pac, pos);
00451 else if (os_strcmp(rc.buf, "I-ID") == 0)
00452 err = eap_fast_parse_i_id(pac, pos);
00453 else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
00454 err = eap_fast_parse_a_id_info(pac, pos);
00455 }
00456
00457 if (pac) {
00458 err = "PAC block not terminated with END";
00459 eap_fast_free_pac(pac);
00460 }
00461
00462 eap_fast_deinit_pac_data(&rc);
00463
00464 if (err) {
00465 wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'",
00466 err, pac_file, rc.line);
00467 return -1;
00468 }
00469
00470 wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'",
00471 count, pac_file);
00472
00473 return 0;
00474 }
00475
00476
00477 static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
00478 const char *field, const u8 *data,
00479 size_t len, int txt)
00480 {
00481 size_t i, need;
00482 int ret;
00483 char *end;
00484
00485 if (data == NULL || buf == NULL || *buf == NULL ||
00486 pos == NULL || *pos == NULL || *pos < *buf)
00487 return;
00488
00489 need = os_strlen(field) + len * 2 + 30;
00490 if (txt)
00491 need += os_strlen(field) + len + 20;
00492
00493 if (*pos - *buf + need > *buf_len) {
00494 char *nbuf = os_realloc(*buf, *buf_len + need);
00495 if (nbuf == NULL) {
00496 os_free(*buf);
00497 *buf = NULL;
00498 return;
00499 }
00500 *buf = nbuf;
00501 *buf_len += need;
00502 }
00503 end = *buf + *buf_len;
00504
00505 ret = os_snprintf(*pos, end - *pos, "%s=", field);
00506 if (ret < 0 || ret >= end - *pos)
00507 return;
00508 *pos += ret;
00509 *pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
00510 ret = os_snprintf(*pos, end - *pos, "\n");
00511 if (ret < 0 || ret >= end - *pos)
00512 return;
00513 *pos += ret;
00514
00515 if (txt) {
00516 ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
00517 if (ret < 0 || ret >= end - *pos)
00518 return;
00519 *pos += ret;
00520 for (i = 0; i < len; i++) {
00521 ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
00522 if (ret < 0 || ret >= end - *pos)
00523 return;
00524 *pos += ret;
00525 }
00526 ret = os_snprintf(*pos, end - *pos, "\n");
00527 if (ret < 0 || ret >= end - *pos)
00528 return;
00529 *pos += ret;
00530 }
00531 }
00532
00533
00534 static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file,
00535 char *buf, size_t len)
00536 {
00537 if (os_strncmp(pac_file, "blob://", 7) == 0) {
00538 struct wpa_config_blob *blob;
00539 blob = os_zalloc(sizeof(*blob));
00540 if (blob == NULL)
00541 return -1;
00542 blob->data = (u8 *) buf;
00543 blob->len = len;
00544 buf = NULL;
00545 blob->name = os_strdup(pac_file + 7);
00546 if (blob->name == NULL) {
00547 os_free(blob);
00548 return -1;
00549 }
00550 eap_set_config_blob(sm, blob);
00551 } else {
00552 FILE *f;
00553 f = fopen(pac_file, "wb");
00554 if (f == NULL) {
00555 wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
00556 "file '%s' for writing", pac_file);
00557 return -1;
00558 }
00559 if (fwrite(buf, 1, len, f) != len) {
00560 wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all "
00561 "PACs into '%s'", pac_file);
00562 fclose(f);
00563 return -1;
00564 }
00565 os_free(buf);
00566 fclose(f);
00567 }
00568
00569 return 0;
00570 }
00571
00572
00573 static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
00574 char **pos, size_t *buf_len)
00575 {
00576 int ret;
00577
00578 ret = os_snprintf(*pos, *buf + *buf_len - *pos,
00579 "START\nPAC-Type=%d\n", pac->pac_type);
00580 if (ret < 0 || ret >= *buf + *buf_len - *pos)
00581 return -1;
00582
00583 *pos += ret;
00584 eap_fast_write(buf, pos, buf_len, "PAC-Key",
00585 pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0);
00586 eap_fast_write(buf, pos, buf_len, "PAC-Opaque",
00587 pac->pac_opaque, pac->pac_opaque_len, 0);
00588 eap_fast_write(buf, pos, buf_len, "PAC-Info",
00589 pac->pac_info, pac->pac_info_len, 0);
00590 eap_fast_write(buf, pos, buf_len, "A-ID",
00591 pac->a_id, pac->a_id_len, 0);
00592 eap_fast_write(buf, pos, buf_len, "I-ID",
00593 pac->i_id, pac->i_id_len, 1);
00594 eap_fast_write(buf, pos, buf_len, "A-ID-Info",
00595 pac->a_id_info, pac->a_id_info_len, 1);
00596 if (*buf == NULL) {
00597 wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
00598 "data");
00599 return -1;
00600 }
00601 ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
00602 if (ret < 0 || ret >= *buf + *buf_len - *pos)
00603 return -1;
00604 *pos += ret;
00605
00606 return 0;
00607 }
00608
00609
00617 int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
00618 const char *pac_file)
00619 {
00620 struct eap_fast_pac *pac;
00621 int ret, count = 0;
00622 char *buf, *pos;
00623 size_t buf_len;
00624
00625 if (pac_file == NULL)
00626 return -1;
00627
00628 buf_len = 1024;
00629 pos = buf = os_malloc(buf_len);
00630 if (buf == NULL)
00631 return -1;
00632
00633 ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
00634 if (ret < 0 || ret >= buf + buf_len - pos) {
00635 os_free(buf);
00636 return -1;
00637 }
00638 pos += ret;
00639
00640 pac = pac_root;
00641 while (pac) {
00642 if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) {
00643 os_free(buf);
00644 return -1;
00645 }
00646 count++;
00647 pac = pac->next;
00648 }
00649
00650 if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) {
00651 os_free(buf);
00652 return -1;
00653 }
00654
00655 wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'",
00656 count, pac_file);
00657
00658 return 0;
00659 }
00660
00661
00668 size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
00669 size_t max_len)
00670 {
00671 struct eap_fast_pac *pac, *prev;
00672 size_t count;
00673
00674 pac = pac_root;
00675 prev = NULL;
00676 count = 0;
00677
00678 while (pac) {
00679 count++;
00680 if (count > max_len)
00681 break;
00682 prev = pac;
00683 pac = pac->next;
00684 }
00685
00686 if (count <= max_len || prev == NULL)
00687 return 0;
00688
00689 count = 0;
00690 prev->next = NULL;
00691
00692 while (pac) {
00693 prev = pac;
00694 pac = pac->next;
00695 eap_fast_free_pac(prev);
00696 count++;
00697 }
00698
00699 return count;
00700 }
00701
00702
00703 static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
00704 {
00705 u8 *pos, *end;
00706 u16 type, len;
00707
00708 pos = pac->pac_info;
00709 end = pos + pac->pac_info_len;
00710
00711 while (pos + 4 < end) {
00712 type = WPA_GET_BE16(pos);
00713 pos += 2;
00714 len = WPA_GET_BE16(pos);
00715 pos += 2;
00716 if (pos + len > end)
00717 break;
00718
00719 if (type == PAC_TYPE_A_ID) {
00720 os_free(pac->a_id);
00721 pac->a_id = os_malloc(len);
00722 if (pac->a_id == NULL)
00723 break;
00724 os_memcpy(pac->a_id, pos, len);
00725 pac->a_id_len = len;
00726 }
00727
00728 if (type == PAC_TYPE_A_ID_INFO) {
00729 os_free(pac->a_id_info);
00730 pac->a_id_info = os_malloc(len);
00731 if (pac->a_id_info == NULL)
00732 break;
00733 os_memcpy(pac->a_id_info, pos, len);
00734 pac->a_id_info_len = len;
00735 }
00736
00737 pos += len;
00738 }
00739 }
00740
00741
00749 int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
00750 const char *pac_file)
00751 {
00752 const struct wpa_config_blob *blob = NULL;
00753 u8 *buf, *end, *pos;
00754 size_t len, count = 0;
00755 struct eap_fast_pac *pac, *prev;
00756
00757 *pac_root = NULL;
00758
00759 if (pac_file == NULL)
00760 return -1;
00761
00762 if (os_strncmp(pac_file, "blob://", 7) == 0) {
00763 blob = eap_get_config_blob(sm, pac_file + 7);
00764 if (blob == NULL) {
00765 wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
00766 "assume no PAC entries have been "
00767 "provisioned", pac_file + 7);
00768 return 0;
00769 }
00770 buf = blob->data;
00771 len = blob->len;
00772 } else {
00773 buf = (u8 *) os_readfile(pac_file, &len);
00774 if (buf == NULL) {
00775 wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
00776 "assume no PAC entries have been "
00777 "provisioned", pac_file);
00778 return 0;
00779 }
00780 }
00781
00782 if (len == 0) {
00783 if (blob == NULL)
00784 os_free(buf);
00785 return 0;
00786 }
00787
00788 if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC ||
00789 WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) {
00790 wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)",
00791 pac_file);
00792 if (blob == NULL)
00793 os_free(buf);
00794 return -1;
00795 }
00796
00797 pac = prev = NULL;
00798 pos = buf + 6;
00799 end = buf + len;
00800 while (pos < end) {
00801 if (end - pos < 2 + 32 + 2 + 2)
00802 goto parse_fail;
00803
00804 pac = os_zalloc(sizeof(*pac));
00805 if (pac == NULL)
00806 goto parse_fail;
00807
00808 pac->pac_type = WPA_GET_BE16(pos);
00809 pos += 2;
00810 os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
00811 pos += EAP_FAST_PAC_KEY_LEN;
00812 pac->pac_opaque_len = WPA_GET_BE16(pos);
00813 pos += 2;
00814 if (pos + pac->pac_opaque_len + 2 > end)
00815 goto parse_fail;
00816 pac->pac_opaque = os_malloc(pac->pac_opaque_len);
00817 if (pac->pac_opaque == NULL)
00818 goto parse_fail;
00819 os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
00820 pos += pac->pac_opaque_len;
00821 pac->pac_info_len = WPA_GET_BE16(pos);
00822 pos += 2;
00823 if (pos + pac->pac_info_len > end)
00824 goto parse_fail;
00825 pac->pac_info = os_malloc(pac->pac_info_len);
00826 if (pac->pac_info == NULL)
00827 goto parse_fail;
00828 os_memcpy(pac->pac_info, pos, pac->pac_info_len);
00829 pos += pac->pac_info_len;
00830 eap_fast_pac_get_a_id(pac);
00831
00832 count++;
00833 if (prev)
00834 prev->next = pac;
00835 else
00836 *pac_root = pac;
00837 prev = pac;
00838 }
00839
00840 if (blob == NULL)
00841 os_free(buf);
00842
00843 wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)",
00844 (unsigned long) count, pac_file);
00845
00846 return 0;
00847
00848 parse_fail:
00849 wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)",
00850 pac_file);
00851 if (blob == NULL)
00852 os_free(buf);
00853 if (pac)
00854 eap_fast_free_pac(pac);
00855 return -1;
00856 }
00857
00858
00866 int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
00867 const char *pac_file)
00868 {
00869 size_t len, count = 0;
00870 struct eap_fast_pac *pac;
00871 u8 *buf, *pos;
00872
00873 len = 6;
00874 pac = pac_root;
00875 while (pac) {
00876 if (pac->pac_opaque_len > 65535 ||
00877 pac->pac_info_len > 65535)
00878 return -1;
00879 len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
00880 2 + pac->pac_info_len;
00881 pac = pac->next;
00882 }
00883
00884 buf = os_malloc(len);
00885 if (buf == NULL)
00886 return -1;
00887
00888 pos = buf;
00889 WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC);
00890 pos += 4;
00891 WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION);
00892 pos += 2;
00893
00894 pac = pac_root;
00895 while (pac) {
00896 WPA_PUT_BE16(pos, pac->pac_type);
00897 pos += 2;
00898 os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN);
00899 pos += EAP_FAST_PAC_KEY_LEN;
00900 WPA_PUT_BE16(pos, pac->pac_opaque_len);
00901 pos += 2;
00902 os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
00903 pos += pac->pac_opaque_len;
00904 WPA_PUT_BE16(pos, pac->pac_info_len);
00905 pos += 2;
00906 os_memcpy(pos, pac->pac_info, pac->pac_info_len);
00907 pos += pac->pac_info_len;
00908
00909 pac = pac->next;
00910 count++;
00911 }
00912
00913 if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) {
00914 os_free(buf);
00915 return -1;
00916 }
00917
00918 wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' "
00919 "(bin)", (unsigned long) count, pac_file);
00920
00921 return 0;
00922 }