eap_fast_pac.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:37