$search
00001 /* 00002 * EAP peer method: EAP-FAST PAC file processing 00003 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 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 /* TODO: encrypt PAC-Key in the PAC file */ 00023 00024 00025 /* Text data format */ 00026 static const char *pac_file_hdr = 00027 "wpa_supplicant EAP-FAST PAC file - version 1"; 00028 00029 /* 00030 * Binary data format 00031 * 4-octet magic value: 6A E4 92 0C 00032 * 2-octet version (big endian) 00033 * <version specific data> 00034 * 00035 * version=0: 00036 * Sequence of PAC entries: 00037 * 2-octet PAC-Type (big endian) 00038 * 32-octet PAC-Key 00039 * 2-octet PAC-Opaque length (big endian) 00040 * <variable len> PAC-Opaque data (length bytes) 00041 * 2-octet PAC-Info length (big endian) 00042 * <variable len> PAC-Info data (length bytes) 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 /* Remove a possible old entry for the matching A-ID. */ 00155 eap_fast_remove_pac(pac_root, pac_current, 00156 entry->a_id, entry->a_id_len, entry->pac_type); 00157 00158 /* Allocate a new entry and add it to the list of PACs. */ 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 }