1*a1157835SDaniel Fojt /*
2*a1157835SDaniel Fojt * EAP peer method: EAP-TEAP PAC file processing
3*a1157835SDaniel Fojt * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
4*a1157835SDaniel Fojt *
5*a1157835SDaniel Fojt * This software may be distributed under the terms of the BSD license.
6*a1157835SDaniel Fojt * See README for more details.
7*a1157835SDaniel Fojt */
8*a1157835SDaniel Fojt
9*a1157835SDaniel Fojt #include "includes.h"
10*a1157835SDaniel Fojt
11*a1157835SDaniel Fojt #include "common.h"
12*a1157835SDaniel Fojt #include "eap_config.h"
13*a1157835SDaniel Fojt #include "eap_i.h"
14*a1157835SDaniel Fojt #include "eap_teap_pac.h"
15*a1157835SDaniel Fojt
16*a1157835SDaniel Fojt /* TODO: encrypt PAC-Key in the PAC file */
17*a1157835SDaniel Fojt
18*a1157835SDaniel Fojt
19*a1157835SDaniel Fojt /* Text data format */
20*a1157835SDaniel Fojt static const char *pac_file_hdr =
21*a1157835SDaniel Fojt "wpa_supplicant EAP-TEAP PAC file - version 1";
22*a1157835SDaniel Fojt
23*a1157835SDaniel Fojt /*
24*a1157835SDaniel Fojt * Binary data format
25*a1157835SDaniel Fojt * 4-octet magic value: 6A E4 92 1C
26*a1157835SDaniel Fojt * 2-octet version (big endian)
27*a1157835SDaniel Fojt * <version specific data>
28*a1157835SDaniel Fojt *
29*a1157835SDaniel Fojt * version=0:
30*a1157835SDaniel Fojt * Sequence of PAC entries:
31*a1157835SDaniel Fojt * 2-octet PAC-Type (big endian)
32*a1157835SDaniel Fojt * 32-octet PAC-Key
33*a1157835SDaniel Fojt * 2-octet PAC-Opaque length (big endian)
34*a1157835SDaniel Fojt * <variable len> PAC-Opaque data (length bytes)
35*a1157835SDaniel Fojt * 2-octet PAC-Info length (big endian)
36*a1157835SDaniel Fojt * <variable len> PAC-Info data (length bytes)
37*a1157835SDaniel Fojt */
38*a1157835SDaniel Fojt
39*a1157835SDaniel Fojt #define EAP_TEAP_PAC_BINARY_MAGIC 0x6ae4921c
40*a1157835SDaniel Fojt #define EAP_TEAP_PAC_BINARY_FORMAT_VERSION 0
41*a1157835SDaniel Fojt
42*a1157835SDaniel Fojt
43*a1157835SDaniel Fojt /**
44*a1157835SDaniel Fojt * eap_teap_free_pac - Free PAC data
45*a1157835SDaniel Fojt * @pac: Pointer to the PAC entry
46*a1157835SDaniel Fojt *
47*a1157835SDaniel Fojt * Note that the PAC entry must not be in a list since this function does not
48*a1157835SDaniel Fojt * remove the list links.
49*a1157835SDaniel Fojt */
eap_teap_free_pac(struct eap_teap_pac * pac)50*a1157835SDaniel Fojt void eap_teap_free_pac(struct eap_teap_pac *pac)
51*a1157835SDaniel Fojt {
52*a1157835SDaniel Fojt os_free(pac->pac_opaque);
53*a1157835SDaniel Fojt os_free(pac->pac_info);
54*a1157835SDaniel Fojt os_free(pac->a_id);
55*a1157835SDaniel Fojt os_free(pac->i_id);
56*a1157835SDaniel Fojt os_free(pac->a_id_info);
57*a1157835SDaniel Fojt os_free(pac);
58*a1157835SDaniel Fojt }
59*a1157835SDaniel Fojt
60*a1157835SDaniel Fojt
61*a1157835SDaniel Fojt /**
62*a1157835SDaniel Fojt * eap_teap_get_pac - Get a PAC entry based on A-ID
63*a1157835SDaniel Fojt * @pac_root: Pointer to root of the PAC list
64*a1157835SDaniel Fojt * @a_id: A-ID to search for
65*a1157835SDaniel Fojt * @a_id_len: Length of A-ID
66*a1157835SDaniel Fojt * @pac_type: PAC-Type to search for
67*a1157835SDaniel Fojt * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
68*a1157835SDaniel Fojt */
eap_teap_get_pac(struct eap_teap_pac * pac_root,const u8 * a_id,size_t a_id_len,u16 pac_type)69*a1157835SDaniel Fojt struct eap_teap_pac * eap_teap_get_pac(struct eap_teap_pac *pac_root,
70*a1157835SDaniel Fojt const u8 *a_id, size_t a_id_len,
71*a1157835SDaniel Fojt u16 pac_type)
72*a1157835SDaniel Fojt {
73*a1157835SDaniel Fojt struct eap_teap_pac *pac = pac_root;
74*a1157835SDaniel Fojt
75*a1157835SDaniel Fojt while (pac) {
76*a1157835SDaniel Fojt if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
77*a1157835SDaniel Fojt os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
78*a1157835SDaniel Fojt return pac;
79*a1157835SDaniel Fojt }
80*a1157835SDaniel Fojt pac = pac->next;
81*a1157835SDaniel Fojt }
82*a1157835SDaniel Fojt return NULL;
83*a1157835SDaniel Fojt }
84*a1157835SDaniel Fojt
85*a1157835SDaniel Fojt
eap_teap_remove_pac(struct eap_teap_pac ** pac_root,struct eap_teap_pac ** pac_current,const u8 * a_id,size_t a_id_len,u16 pac_type)86*a1157835SDaniel Fojt static void eap_teap_remove_pac(struct eap_teap_pac **pac_root,
87*a1157835SDaniel Fojt struct eap_teap_pac **pac_current,
88*a1157835SDaniel Fojt const u8 *a_id, size_t a_id_len, u16 pac_type)
89*a1157835SDaniel Fojt {
90*a1157835SDaniel Fojt struct eap_teap_pac *pac, *prev;
91*a1157835SDaniel Fojt
92*a1157835SDaniel Fojt pac = *pac_root;
93*a1157835SDaniel Fojt prev = NULL;
94*a1157835SDaniel Fojt
95*a1157835SDaniel Fojt while (pac) {
96*a1157835SDaniel Fojt if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
97*a1157835SDaniel Fojt os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
98*a1157835SDaniel Fojt if (!prev)
99*a1157835SDaniel Fojt *pac_root = pac->next;
100*a1157835SDaniel Fojt else
101*a1157835SDaniel Fojt prev->next = pac->next;
102*a1157835SDaniel Fojt if (*pac_current == pac)
103*a1157835SDaniel Fojt *pac_current = NULL;
104*a1157835SDaniel Fojt eap_teap_free_pac(pac);
105*a1157835SDaniel Fojt break;
106*a1157835SDaniel Fojt }
107*a1157835SDaniel Fojt prev = pac;
108*a1157835SDaniel Fojt pac = pac->next;
109*a1157835SDaniel Fojt }
110*a1157835SDaniel Fojt }
111*a1157835SDaniel Fojt
112*a1157835SDaniel Fojt
eap_teap_copy_buf(u8 ** dst,size_t * dst_len,const u8 * src,size_t src_len)113*a1157835SDaniel Fojt static int eap_teap_copy_buf(u8 **dst, size_t *dst_len,
114*a1157835SDaniel Fojt const u8 *src, size_t src_len)
115*a1157835SDaniel Fojt {
116*a1157835SDaniel Fojt if (src) {
117*a1157835SDaniel Fojt *dst = os_memdup(src, src_len);
118*a1157835SDaniel Fojt if (!(*dst))
119*a1157835SDaniel Fojt return -1;
120*a1157835SDaniel Fojt *dst_len = src_len;
121*a1157835SDaniel Fojt }
122*a1157835SDaniel Fojt return 0;
123*a1157835SDaniel Fojt }
124*a1157835SDaniel Fojt
125*a1157835SDaniel Fojt
126*a1157835SDaniel Fojt /**
127*a1157835SDaniel Fojt * eap_teap_add_pac - Add a copy of a PAC entry to a list
128*a1157835SDaniel Fojt * @pac_root: Pointer to PAC list root pointer
129*a1157835SDaniel Fojt * @pac_current: Pointer to the current PAC pointer
130*a1157835SDaniel Fojt * @entry: New entry to clone and add to the list
131*a1157835SDaniel Fojt * Returns: 0 on success, -1 on failure
132*a1157835SDaniel Fojt *
133*a1157835SDaniel Fojt * This function makes a clone of the given PAC entry and adds this copied
134*a1157835SDaniel Fojt * entry to the list (pac_root). If an old entry for the same A-ID is found,
135*a1157835SDaniel Fojt * it will be removed from the PAC list and in this case, pac_current entry
136*a1157835SDaniel Fojt * is set to %NULL if it was the removed entry.
137*a1157835SDaniel Fojt */
eap_teap_add_pac(struct eap_teap_pac ** pac_root,struct eap_teap_pac ** pac_current,struct eap_teap_pac * entry)138*a1157835SDaniel Fojt int eap_teap_add_pac(struct eap_teap_pac **pac_root,
139*a1157835SDaniel Fojt struct eap_teap_pac **pac_current,
140*a1157835SDaniel Fojt struct eap_teap_pac *entry)
141*a1157835SDaniel Fojt {
142*a1157835SDaniel Fojt struct eap_teap_pac *pac;
143*a1157835SDaniel Fojt
144*a1157835SDaniel Fojt if (!entry || !entry->a_id)
145*a1157835SDaniel Fojt return -1;
146*a1157835SDaniel Fojt
147*a1157835SDaniel Fojt /* Remove a possible old entry for the matching A-ID. */
148*a1157835SDaniel Fojt eap_teap_remove_pac(pac_root, pac_current,
149*a1157835SDaniel Fojt entry->a_id, entry->a_id_len, entry->pac_type);
150*a1157835SDaniel Fojt
151*a1157835SDaniel Fojt /* Allocate a new entry and add it to the list of PACs. */
152*a1157835SDaniel Fojt pac = os_zalloc(sizeof(*pac));
153*a1157835SDaniel Fojt if (!pac)
154*a1157835SDaniel Fojt return -1;
155*a1157835SDaniel Fojt
156*a1157835SDaniel Fojt pac->pac_type = entry->pac_type;
157*a1157835SDaniel Fojt os_memcpy(pac->pac_key, entry->pac_key, EAP_TEAP_PAC_KEY_LEN);
158*a1157835SDaniel Fojt if (eap_teap_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
159*a1157835SDaniel Fojt entry->pac_opaque, entry->pac_opaque_len) < 0 ||
160*a1157835SDaniel Fojt eap_teap_copy_buf(&pac->pac_info, &pac->pac_info_len,
161*a1157835SDaniel Fojt entry->pac_info, entry->pac_info_len) < 0 ||
162*a1157835SDaniel Fojt eap_teap_copy_buf(&pac->a_id, &pac->a_id_len,
163*a1157835SDaniel Fojt entry->a_id, entry->a_id_len) < 0 ||
164*a1157835SDaniel Fojt eap_teap_copy_buf(&pac->i_id, &pac->i_id_len,
165*a1157835SDaniel Fojt entry->i_id, entry->i_id_len) < 0 ||
166*a1157835SDaniel Fojt eap_teap_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
167*a1157835SDaniel Fojt entry->a_id_info, entry->a_id_info_len) < 0) {
168*a1157835SDaniel Fojt eap_teap_free_pac(pac);
169*a1157835SDaniel Fojt return -1;
170*a1157835SDaniel Fojt }
171*a1157835SDaniel Fojt
172*a1157835SDaniel Fojt pac->next = *pac_root;
173*a1157835SDaniel Fojt *pac_root = pac;
174*a1157835SDaniel Fojt
175*a1157835SDaniel Fojt return 0;
176*a1157835SDaniel Fojt }
177*a1157835SDaniel Fojt
178*a1157835SDaniel Fojt
179*a1157835SDaniel Fojt struct eap_teap_read_ctx {
180*a1157835SDaniel Fojt FILE *f;
181*a1157835SDaniel Fojt const char *pos;
182*a1157835SDaniel Fojt const char *end;
183*a1157835SDaniel Fojt int line;
184*a1157835SDaniel Fojt char *buf;
185*a1157835SDaniel Fojt size_t buf_len;
186*a1157835SDaniel Fojt };
187*a1157835SDaniel Fojt
eap_teap_read_line(struct eap_teap_read_ctx * rc,char ** value)188*a1157835SDaniel Fojt static int eap_teap_read_line(struct eap_teap_read_ctx *rc, char **value)
189*a1157835SDaniel Fojt {
190*a1157835SDaniel Fojt char *pos;
191*a1157835SDaniel Fojt
192*a1157835SDaniel Fojt rc->line++;
193*a1157835SDaniel Fojt if (rc->f) {
194*a1157835SDaniel Fojt if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
195*a1157835SDaniel Fojt return -1;
196*a1157835SDaniel Fojt } else {
197*a1157835SDaniel Fojt const char *l_end;
198*a1157835SDaniel Fojt size_t len;
199*a1157835SDaniel Fojt
200*a1157835SDaniel Fojt if (rc->pos >= rc->end)
201*a1157835SDaniel Fojt return -1;
202*a1157835SDaniel Fojt l_end = rc->pos;
203*a1157835SDaniel Fojt while (l_end < rc->end && *l_end != '\n')
204*a1157835SDaniel Fojt l_end++;
205*a1157835SDaniel Fojt len = l_end - rc->pos;
206*a1157835SDaniel Fojt if (len >= rc->buf_len)
207*a1157835SDaniel Fojt len = rc->buf_len - 1;
208*a1157835SDaniel Fojt os_memcpy(rc->buf, rc->pos, len);
209*a1157835SDaniel Fojt rc->buf[len] = '\0';
210*a1157835SDaniel Fojt rc->pos = l_end + 1;
211*a1157835SDaniel Fojt }
212*a1157835SDaniel Fojt
213*a1157835SDaniel Fojt rc->buf[rc->buf_len - 1] = '\0';
214*a1157835SDaniel Fojt pos = rc->buf;
215*a1157835SDaniel Fojt while (*pos != '\0') {
216*a1157835SDaniel Fojt if (*pos == '\n' || *pos == '\r') {
217*a1157835SDaniel Fojt *pos = '\0';
218*a1157835SDaniel Fojt break;
219*a1157835SDaniel Fojt }
220*a1157835SDaniel Fojt pos++;
221*a1157835SDaniel Fojt }
222*a1157835SDaniel Fojt
223*a1157835SDaniel Fojt pos = os_strchr(rc->buf, '=');
224*a1157835SDaniel Fojt if (pos)
225*a1157835SDaniel Fojt *pos++ = '\0';
226*a1157835SDaniel Fojt *value = pos;
227*a1157835SDaniel Fojt
228*a1157835SDaniel Fojt return 0;
229*a1157835SDaniel Fojt }
230*a1157835SDaniel Fojt
231*a1157835SDaniel Fojt
eap_teap_parse_hex(const char * value,size_t * len)232*a1157835SDaniel Fojt static u8 * eap_teap_parse_hex(const char *value, size_t *len)
233*a1157835SDaniel Fojt {
234*a1157835SDaniel Fojt int hlen;
235*a1157835SDaniel Fojt u8 *buf;
236*a1157835SDaniel Fojt
237*a1157835SDaniel Fojt if (!value)
238*a1157835SDaniel Fojt return NULL;
239*a1157835SDaniel Fojt hlen = os_strlen(value);
240*a1157835SDaniel Fojt if (hlen & 1)
241*a1157835SDaniel Fojt return NULL;
242*a1157835SDaniel Fojt *len = hlen / 2;
243*a1157835SDaniel Fojt buf = os_malloc(*len);
244*a1157835SDaniel Fojt if (!buf)
245*a1157835SDaniel Fojt return NULL;
246*a1157835SDaniel Fojt if (hexstr2bin(value, buf, *len)) {
247*a1157835SDaniel Fojt os_free(buf);
248*a1157835SDaniel Fojt return NULL;
249*a1157835SDaniel Fojt }
250*a1157835SDaniel Fojt return buf;
251*a1157835SDaniel Fojt }
252*a1157835SDaniel Fojt
253*a1157835SDaniel Fojt
eap_teap_init_pac_data(struct eap_sm * sm,const char * pac_file,struct eap_teap_read_ctx * rc)254*a1157835SDaniel Fojt static int eap_teap_init_pac_data(struct eap_sm *sm, const char *pac_file,
255*a1157835SDaniel Fojt struct eap_teap_read_ctx *rc)
256*a1157835SDaniel Fojt {
257*a1157835SDaniel Fojt os_memset(rc, 0, sizeof(*rc));
258*a1157835SDaniel Fojt
259*a1157835SDaniel Fojt rc->buf_len = 2048;
260*a1157835SDaniel Fojt rc->buf = os_malloc(rc->buf_len);
261*a1157835SDaniel Fojt if (!rc->buf)
262*a1157835SDaniel Fojt return -1;
263*a1157835SDaniel Fojt
264*a1157835SDaniel Fojt if (os_strncmp(pac_file, "blob://", 7) == 0) {
265*a1157835SDaniel Fojt const struct wpa_config_blob *blob;
266*a1157835SDaniel Fojt
267*a1157835SDaniel Fojt blob = eap_get_config_blob(sm, pac_file + 7);
268*a1157835SDaniel Fojt if (!blob) {
269*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
270*a1157835SDaniel Fojt "EAP-TEAP: No PAC blob '%s' - assume no PAC entries have been provisioned",
271*a1157835SDaniel Fojt pac_file + 7);
272*a1157835SDaniel Fojt os_free(rc->buf);
273*a1157835SDaniel Fojt return -1;
274*a1157835SDaniel Fojt }
275*a1157835SDaniel Fojt rc->pos = (char *) blob->data;
276*a1157835SDaniel Fojt rc->end = (char *) blob->data + blob->len;
277*a1157835SDaniel Fojt } else {
278*a1157835SDaniel Fojt rc->f = fopen(pac_file, "rb");
279*a1157835SDaniel Fojt if (!rc->f) {
280*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
281*a1157835SDaniel Fojt "EAP-TEAP: No PAC file '%s' - assume no PAC entries have been provisioned",
282*a1157835SDaniel Fojt pac_file);
283*a1157835SDaniel Fojt os_free(rc->buf);
284*a1157835SDaniel Fojt return -1;
285*a1157835SDaniel Fojt }
286*a1157835SDaniel Fojt }
287*a1157835SDaniel Fojt
288*a1157835SDaniel Fojt return 0;
289*a1157835SDaniel Fojt }
290*a1157835SDaniel Fojt
291*a1157835SDaniel Fojt
eap_teap_deinit_pac_data(struct eap_teap_read_ctx * rc)292*a1157835SDaniel Fojt static void eap_teap_deinit_pac_data(struct eap_teap_read_ctx *rc)
293*a1157835SDaniel Fojt {
294*a1157835SDaniel Fojt os_free(rc->buf);
295*a1157835SDaniel Fojt if (rc->f)
296*a1157835SDaniel Fojt fclose(rc->f);
297*a1157835SDaniel Fojt }
298*a1157835SDaniel Fojt
299*a1157835SDaniel Fojt
eap_teap_parse_start(struct eap_teap_pac ** pac)300*a1157835SDaniel Fojt static const char * eap_teap_parse_start(struct eap_teap_pac **pac)
301*a1157835SDaniel Fojt {
302*a1157835SDaniel Fojt if (*pac)
303*a1157835SDaniel Fojt return "START line without END";
304*a1157835SDaniel Fojt
305*a1157835SDaniel Fojt *pac = os_zalloc(sizeof(struct eap_teap_pac));
306*a1157835SDaniel Fojt if (!(*pac))
307*a1157835SDaniel Fojt return "No memory for PAC entry";
308*a1157835SDaniel Fojt (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
309*a1157835SDaniel Fojt return NULL;
310*a1157835SDaniel Fojt }
311*a1157835SDaniel Fojt
312*a1157835SDaniel Fojt
eap_teap_parse_end(struct eap_teap_pac ** pac_root,struct eap_teap_pac ** pac)313*a1157835SDaniel Fojt static const char * eap_teap_parse_end(struct eap_teap_pac **pac_root,
314*a1157835SDaniel Fojt struct eap_teap_pac **pac)
315*a1157835SDaniel Fojt {
316*a1157835SDaniel Fojt if (!(*pac))
317*a1157835SDaniel Fojt return "END line without START";
318*a1157835SDaniel Fojt if (*pac_root) {
319*a1157835SDaniel Fojt struct eap_teap_pac *end = *pac_root;
320*a1157835SDaniel Fojt
321*a1157835SDaniel Fojt while (end->next)
322*a1157835SDaniel Fojt end = end->next;
323*a1157835SDaniel Fojt end->next = *pac;
324*a1157835SDaniel Fojt } else
325*a1157835SDaniel Fojt *pac_root = *pac;
326*a1157835SDaniel Fojt
327*a1157835SDaniel Fojt *pac = NULL;
328*a1157835SDaniel Fojt return NULL;
329*a1157835SDaniel Fojt }
330*a1157835SDaniel Fojt
331*a1157835SDaniel Fojt
eap_teap_parse_pac_type(struct eap_teap_pac * pac,char * pos)332*a1157835SDaniel Fojt static const char * eap_teap_parse_pac_type(struct eap_teap_pac *pac,
333*a1157835SDaniel Fojt char *pos)
334*a1157835SDaniel Fojt {
335*a1157835SDaniel Fojt if (!pos)
336*a1157835SDaniel Fojt return "Cannot parse pac type";
337*a1157835SDaniel Fojt pac->pac_type = atoi(pos);
338*a1157835SDaniel Fojt if (pac->pac_type != PAC_TYPE_TUNNEL_PAC)
339*a1157835SDaniel Fojt return "Unrecognized PAC-Type";
340*a1157835SDaniel Fojt
341*a1157835SDaniel Fojt return NULL;
342*a1157835SDaniel Fojt }
343*a1157835SDaniel Fojt
344*a1157835SDaniel Fojt
eap_teap_parse_pac_key(struct eap_teap_pac * pac,char * pos)345*a1157835SDaniel Fojt static const char * eap_teap_parse_pac_key(struct eap_teap_pac *pac, char *pos)
346*a1157835SDaniel Fojt {
347*a1157835SDaniel Fojt u8 *key;
348*a1157835SDaniel Fojt size_t key_len;
349*a1157835SDaniel Fojt
350*a1157835SDaniel Fojt key = eap_teap_parse_hex(pos, &key_len);
351*a1157835SDaniel Fojt if (!key || key_len != EAP_TEAP_PAC_KEY_LEN) {
352*a1157835SDaniel Fojt os_free(key);
353*a1157835SDaniel Fojt return "Invalid PAC-Key";
354*a1157835SDaniel Fojt }
355*a1157835SDaniel Fojt
356*a1157835SDaniel Fojt os_memcpy(pac->pac_key, key, EAP_TEAP_PAC_KEY_LEN);
357*a1157835SDaniel Fojt os_free(key);
358*a1157835SDaniel Fojt
359*a1157835SDaniel Fojt return NULL;
360*a1157835SDaniel Fojt }
361*a1157835SDaniel Fojt
362*a1157835SDaniel Fojt
eap_teap_parse_pac_opaque(struct eap_teap_pac * pac,char * pos)363*a1157835SDaniel Fojt static const char * eap_teap_parse_pac_opaque(struct eap_teap_pac *pac,
364*a1157835SDaniel Fojt char *pos)
365*a1157835SDaniel Fojt {
366*a1157835SDaniel Fojt os_free(pac->pac_opaque);
367*a1157835SDaniel Fojt pac->pac_opaque = eap_teap_parse_hex(pos, &pac->pac_opaque_len);
368*a1157835SDaniel Fojt if (!pac->pac_opaque)
369*a1157835SDaniel Fojt return "Invalid PAC-Opaque";
370*a1157835SDaniel Fojt return NULL;
371*a1157835SDaniel Fojt }
372*a1157835SDaniel Fojt
373*a1157835SDaniel Fojt
eap_teap_parse_a_id(struct eap_teap_pac * pac,char * pos)374*a1157835SDaniel Fojt static const char * eap_teap_parse_a_id(struct eap_teap_pac *pac, char *pos)
375*a1157835SDaniel Fojt {
376*a1157835SDaniel Fojt os_free(pac->a_id);
377*a1157835SDaniel Fojt pac->a_id = eap_teap_parse_hex(pos, &pac->a_id_len);
378*a1157835SDaniel Fojt if (!pac->a_id)
379*a1157835SDaniel Fojt return "Invalid A-ID";
380*a1157835SDaniel Fojt return NULL;
381*a1157835SDaniel Fojt }
382*a1157835SDaniel Fojt
383*a1157835SDaniel Fojt
eap_teap_parse_i_id(struct eap_teap_pac * pac,char * pos)384*a1157835SDaniel Fojt static const char * eap_teap_parse_i_id(struct eap_teap_pac *pac, char *pos)
385*a1157835SDaniel Fojt {
386*a1157835SDaniel Fojt os_free(pac->i_id);
387*a1157835SDaniel Fojt pac->i_id = eap_teap_parse_hex(pos, &pac->i_id_len);
388*a1157835SDaniel Fojt if (!pac->i_id)
389*a1157835SDaniel Fojt return "Invalid I-ID";
390*a1157835SDaniel Fojt return NULL;
391*a1157835SDaniel Fojt }
392*a1157835SDaniel Fojt
393*a1157835SDaniel Fojt
eap_teap_parse_a_id_info(struct eap_teap_pac * pac,char * pos)394*a1157835SDaniel Fojt static const char * eap_teap_parse_a_id_info(struct eap_teap_pac *pac,
395*a1157835SDaniel Fojt char *pos)
396*a1157835SDaniel Fojt {
397*a1157835SDaniel Fojt os_free(pac->a_id_info);
398*a1157835SDaniel Fojt pac->a_id_info = eap_teap_parse_hex(pos, &pac->a_id_info_len);
399*a1157835SDaniel Fojt if (!pac->a_id_info)
400*a1157835SDaniel Fojt return "Invalid A-ID-Info";
401*a1157835SDaniel Fojt return NULL;
402*a1157835SDaniel Fojt }
403*a1157835SDaniel Fojt
404*a1157835SDaniel Fojt
405*a1157835SDaniel Fojt /**
406*a1157835SDaniel Fojt * eap_teap_load_pac - Load PAC entries (text format)
407*a1157835SDaniel Fojt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
408*a1157835SDaniel Fojt * @pac_root: Pointer to root of the PAC list (to be filled)
409*a1157835SDaniel Fojt * @pac_file: Name of the PAC file/blob to load
410*a1157835SDaniel Fojt * Returns: 0 on success, -1 on failure
411*a1157835SDaniel Fojt */
eap_teap_load_pac(struct eap_sm * sm,struct eap_teap_pac ** pac_root,const char * pac_file)412*a1157835SDaniel Fojt int eap_teap_load_pac(struct eap_sm *sm, struct eap_teap_pac **pac_root,
413*a1157835SDaniel Fojt const char *pac_file)
414*a1157835SDaniel Fojt {
415*a1157835SDaniel Fojt struct eap_teap_read_ctx rc;
416*a1157835SDaniel Fojt struct eap_teap_pac *pac = NULL;
417*a1157835SDaniel Fojt int count = 0;
418*a1157835SDaniel Fojt char *pos;
419*a1157835SDaniel Fojt const char *err = NULL;
420*a1157835SDaniel Fojt
421*a1157835SDaniel Fojt if (!pac_file)
422*a1157835SDaniel Fojt return -1;
423*a1157835SDaniel Fojt
424*a1157835SDaniel Fojt if (eap_teap_init_pac_data(sm, pac_file, &rc) < 0)
425*a1157835SDaniel Fojt return 0;
426*a1157835SDaniel Fojt
427*a1157835SDaniel Fojt if (eap_teap_read_line(&rc, &pos) < 0) {
428*a1157835SDaniel Fojt /* empty file - assume it is fine to overwrite */
429*a1157835SDaniel Fojt eap_teap_deinit_pac_data(&rc);
430*a1157835SDaniel Fojt return 0;
431*a1157835SDaniel Fojt }
432*a1157835SDaniel Fojt if (os_strcmp(pac_file_hdr, rc.buf) != 0)
433*a1157835SDaniel Fojt err = "Unrecognized header line";
434*a1157835SDaniel Fojt
435*a1157835SDaniel Fojt while (!err && eap_teap_read_line(&rc, &pos) == 0) {
436*a1157835SDaniel Fojt if (os_strcmp(rc.buf, "START") == 0)
437*a1157835SDaniel Fojt err = eap_teap_parse_start(&pac);
438*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "END") == 0) {
439*a1157835SDaniel Fojt err = eap_teap_parse_end(pac_root, &pac);
440*a1157835SDaniel Fojt count++;
441*a1157835SDaniel Fojt } else if (!pac)
442*a1157835SDaniel Fojt err = "Unexpected line outside START/END block";
443*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "PAC-Type") == 0)
444*a1157835SDaniel Fojt err = eap_teap_parse_pac_type(pac, pos);
445*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "PAC-Key") == 0)
446*a1157835SDaniel Fojt err = eap_teap_parse_pac_key(pac, pos);
447*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
448*a1157835SDaniel Fojt err = eap_teap_parse_pac_opaque(pac, pos);
449*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "A-ID") == 0)
450*a1157835SDaniel Fojt err = eap_teap_parse_a_id(pac, pos);
451*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "I-ID") == 0)
452*a1157835SDaniel Fojt err = eap_teap_parse_i_id(pac, pos);
453*a1157835SDaniel Fojt else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
454*a1157835SDaniel Fojt err = eap_teap_parse_a_id_info(pac, pos);
455*a1157835SDaniel Fojt }
456*a1157835SDaniel Fojt
457*a1157835SDaniel Fojt if (pac) {
458*a1157835SDaniel Fojt if (!err)
459*a1157835SDaniel Fojt err = "PAC block not terminated with END";
460*a1157835SDaniel Fojt eap_teap_free_pac(pac);
461*a1157835SDaniel Fojt }
462*a1157835SDaniel Fojt
463*a1157835SDaniel Fojt eap_teap_deinit_pac_data(&rc);
464*a1157835SDaniel Fojt
465*a1157835SDaniel Fojt if (err) {
466*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "EAP-TEAP: %s in '%s:%d'",
467*a1157835SDaniel Fojt err, pac_file, rc.line);
468*a1157835SDaniel Fojt return -1;
469*a1157835SDaniel Fojt }
470*a1157835SDaniel Fojt
471*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-TEAP: Read %d PAC entries from '%s'",
472*a1157835SDaniel Fojt count, pac_file);
473*a1157835SDaniel Fojt
474*a1157835SDaniel Fojt return 0;
475*a1157835SDaniel Fojt }
476*a1157835SDaniel Fojt
477*a1157835SDaniel Fojt
eap_teap_write(char ** buf,char ** pos,size_t * buf_len,const char * field,const u8 * data,size_t len,int txt)478*a1157835SDaniel Fojt static void eap_teap_write(char **buf, char **pos, size_t *buf_len,
479*a1157835SDaniel Fojt const char *field, const u8 *data,
480*a1157835SDaniel Fojt size_t len, int txt)
481*a1157835SDaniel Fojt {
482*a1157835SDaniel Fojt size_t i, need;
483*a1157835SDaniel Fojt int ret;
484*a1157835SDaniel Fojt char *end;
485*a1157835SDaniel Fojt
486*a1157835SDaniel Fojt if (!data || !buf || !(*buf) || !pos || !(*pos) || *pos < *buf)
487*a1157835SDaniel Fojt return;
488*a1157835SDaniel Fojt
489*a1157835SDaniel Fojt need = os_strlen(field) + len * 2 + 30;
490*a1157835SDaniel Fojt if (txt)
491*a1157835SDaniel Fojt need += os_strlen(field) + len + 20;
492*a1157835SDaniel Fojt
493*a1157835SDaniel Fojt if (*pos - *buf + need > *buf_len) {
494*a1157835SDaniel Fojt char *nbuf = os_realloc(*buf, *buf_len + need);
495*a1157835SDaniel Fojt
496*a1157835SDaniel Fojt if (!nbuf) {
497*a1157835SDaniel Fojt os_free(*buf);
498*a1157835SDaniel Fojt *buf = NULL;
499*a1157835SDaniel Fojt return;
500*a1157835SDaniel Fojt }
501*a1157835SDaniel Fojt *pos = nbuf + (*pos - *buf);
502*a1157835SDaniel Fojt *buf = nbuf;
503*a1157835SDaniel Fojt *buf_len += need;
504*a1157835SDaniel Fojt }
505*a1157835SDaniel Fojt end = *buf + *buf_len;
506*a1157835SDaniel Fojt
507*a1157835SDaniel Fojt ret = os_snprintf(*pos, end - *pos, "%s=", field);
508*a1157835SDaniel Fojt if (os_snprintf_error(end - *pos, ret))
509*a1157835SDaniel Fojt return;
510*a1157835SDaniel Fojt *pos += ret;
511*a1157835SDaniel Fojt *pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
512*a1157835SDaniel Fojt ret = os_snprintf(*pos, end - *pos, "\n");
513*a1157835SDaniel Fojt if (os_snprintf_error(end - *pos, ret))
514*a1157835SDaniel Fojt return;
515*a1157835SDaniel Fojt *pos += ret;
516*a1157835SDaniel Fojt
517*a1157835SDaniel Fojt if (txt) {
518*a1157835SDaniel Fojt ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
519*a1157835SDaniel Fojt if (os_snprintf_error(end - *pos, ret))
520*a1157835SDaniel Fojt return;
521*a1157835SDaniel Fojt *pos += ret;
522*a1157835SDaniel Fojt for (i = 0; i < len; i++) {
523*a1157835SDaniel Fojt ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
524*a1157835SDaniel Fojt if (os_snprintf_error(end - *pos, ret))
525*a1157835SDaniel Fojt return;
526*a1157835SDaniel Fojt *pos += ret;
527*a1157835SDaniel Fojt }
528*a1157835SDaniel Fojt ret = os_snprintf(*pos, end - *pos, "\n");
529*a1157835SDaniel Fojt if (os_snprintf_error(end - *pos, ret))
530*a1157835SDaniel Fojt return;
531*a1157835SDaniel Fojt *pos += ret;
532*a1157835SDaniel Fojt }
533*a1157835SDaniel Fojt }
534*a1157835SDaniel Fojt
535*a1157835SDaniel Fojt
eap_teap_write_pac(struct eap_sm * sm,const char * pac_file,char * buf,size_t len)536*a1157835SDaniel Fojt static int eap_teap_write_pac(struct eap_sm *sm, const char *pac_file,
537*a1157835SDaniel Fojt char *buf, size_t len)
538*a1157835SDaniel Fojt {
539*a1157835SDaniel Fojt if (os_strncmp(pac_file, "blob://", 7) == 0) {
540*a1157835SDaniel Fojt struct wpa_config_blob *blob;
541*a1157835SDaniel Fojt
542*a1157835SDaniel Fojt blob = os_zalloc(sizeof(*blob));
543*a1157835SDaniel Fojt if (!blob)
544*a1157835SDaniel Fojt return -1;
545*a1157835SDaniel Fojt blob->data = (u8 *) buf;
546*a1157835SDaniel Fojt blob->len = len;
547*a1157835SDaniel Fojt buf = NULL;
548*a1157835SDaniel Fojt blob->name = os_strdup(pac_file + 7);
549*a1157835SDaniel Fojt if (!blob->name) {
550*a1157835SDaniel Fojt os_free(blob);
551*a1157835SDaniel Fojt return -1;
552*a1157835SDaniel Fojt }
553*a1157835SDaniel Fojt eap_set_config_blob(sm, blob);
554*a1157835SDaniel Fojt } else {
555*a1157835SDaniel Fojt FILE *f;
556*a1157835SDaniel Fojt
557*a1157835SDaniel Fojt f = fopen(pac_file, "wb");
558*a1157835SDaniel Fojt if (!f) {
559*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
560*a1157835SDaniel Fojt "EAP-TEAP: Failed to open PAC file '%s' for writing",
561*a1157835SDaniel Fojt pac_file);
562*a1157835SDaniel Fojt return -1;
563*a1157835SDaniel Fojt }
564*a1157835SDaniel Fojt if (fwrite(buf, 1, len, f) != len) {
565*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
566*a1157835SDaniel Fojt "EAP-TEAP: Failed to write all PACs into '%s'",
567*a1157835SDaniel Fojt pac_file);
568*a1157835SDaniel Fojt fclose(f);
569*a1157835SDaniel Fojt return -1;
570*a1157835SDaniel Fojt }
571*a1157835SDaniel Fojt os_free(buf);
572*a1157835SDaniel Fojt fclose(f);
573*a1157835SDaniel Fojt }
574*a1157835SDaniel Fojt
575*a1157835SDaniel Fojt return 0;
576*a1157835SDaniel Fojt }
577*a1157835SDaniel Fojt
578*a1157835SDaniel Fojt
eap_teap_add_pac_data(struct eap_teap_pac * pac,char ** buf,char ** pos,size_t * buf_len)579*a1157835SDaniel Fojt static int eap_teap_add_pac_data(struct eap_teap_pac *pac, char **buf,
580*a1157835SDaniel Fojt char **pos, size_t *buf_len)
581*a1157835SDaniel Fojt {
582*a1157835SDaniel Fojt int ret;
583*a1157835SDaniel Fojt
584*a1157835SDaniel Fojt ret = os_snprintf(*pos, *buf + *buf_len - *pos,
585*a1157835SDaniel Fojt "START\nPAC-Type=%d\n", pac->pac_type);
586*a1157835SDaniel Fojt if (os_snprintf_error(*buf + *buf_len - *pos, ret))
587*a1157835SDaniel Fojt return -1;
588*a1157835SDaniel Fojt
589*a1157835SDaniel Fojt *pos += ret;
590*a1157835SDaniel Fojt eap_teap_write(buf, pos, buf_len, "PAC-Key",
591*a1157835SDaniel Fojt pac->pac_key, EAP_TEAP_PAC_KEY_LEN, 0);
592*a1157835SDaniel Fojt eap_teap_write(buf, pos, buf_len, "PAC-Opaque",
593*a1157835SDaniel Fojt pac->pac_opaque, pac->pac_opaque_len, 0);
594*a1157835SDaniel Fojt eap_teap_write(buf, pos, buf_len, "PAC-Info",
595*a1157835SDaniel Fojt pac->pac_info, pac->pac_info_len, 0);
596*a1157835SDaniel Fojt eap_teap_write(buf, pos, buf_len, "A-ID",
597*a1157835SDaniel Fojt pac->a_id, pac->a_id_len, 0);
598*a1157835SDaniel Fojt eap_teap_write(buf, pos, buf_len, "I-ID",
599*a1157835SDaniel Fojt pac->i_id, pac->i_id_len, 1);
600*a1157835SDaniel Fojt eap_teap_write(buf, pos, buf_len, "A-ID-Info",
601*a1157835SDaniel Fojt pac->a_id_info, pac->a_id_info_len, 1);
602*a1157835SDaniel Fojt if (!(*buf)) {
603*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-TEAP: No memory for PAC data");
604*a1157835SDaniel Fojt return -1;
605*a1157835SDaniel Fojt }
606*a1157835SDaniel Fojt ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
607*a1157835SDaniel Fojt if (os_snprintf_error(*buf + *buf_len - *pos, ret))
608*a1157835SDaniel Fojt return -1;
609*a1157835SDaniel Fojt *pos += ret;
610*a1157835SDaniel Fojt
611*a1157835SDaniel Fojt return 0;
612*a1157835SDaniel Fojt }
613*a1157835SDaniel Fojt
614*a1157835SDaniel Fojt
615*a1157835SDaniel Fojt /**
616*a1157835SDaniel Fojt * eap_teap_save_pac - Save PAC entries (text format)
617*a1157835SDaniel Fojt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
618*a1157835SDaniel Fojt * @pac_root: Root of the PAC list
619*a1157835SDaniel Fojt * @pac_file: Name of the PAC file/blob
620*a1157835SDaniel Fojt * Returns: 0 on success, -1 on failure
621*a1157835SDaniel Fojt */
eap_teap_save_pac(struct eap_sm * sm,struct eap_teap_pac * pac_root,const char * pac_file)622*a1157835SDaniel Fojt int eap_teap_save_pac(struct eap_sm *sm, struct eap_teap_pac *pac_root,
623*a1157835SDaniel Fojt const char *pac_file)
624*a1157835SDaniel Fojt {
625*a1157835SDaniel Fojt struct eap_teap_pac *pac;
626*a1157835SDaniel Fojt int ret, count = 0;
627*a1157835SDaniel Fojt char *buf, *pos;
628*a1157835SDaniel Fojt size_t buf_len;
629*a1157835SDaniel Fojt
630*a1157835SDaniel Fojt if (!pac_file)
631*a1157835SDaniel Fojt return -1;
632*a1157835SDaniel Fojt
633*a1157835SDaniel Fojt buf_len = 1024;
634*a1157835SDaniel Fojt pos = buf = os_malloc(buf_len);
635*a1157835SDaniel Fojt if (!buf)
636*a1157835SDaniel Fojt return -1;
637*a1157835SDaniel Fojt
638*a1157835SDaniel Fojt ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
639*a1157835SDaniel Fojt if (os_snprintf_error(buf + buf_len - pos, ret)) {
640*a1157835SDaniel Fojt os_free(buf);
641*a1157835SDaniel Fojt return -1;
642*a1157835SDaniel Fojt }
643*a1157835SDaniel Fojt pos += ret;
644*a1157835SDaniel Fojt
645*a1157835SDaniel Fojt pac = pac_root;
646*a1157835SDaniel Fojt while (pac) {
647*a1157835SDaniel Fojt if (eap_teap_add_pac_data(pac, &buf, &pos, &buf_len)) {
648*a1157835SDaniel Fojt os_free(buf);
649*a1157835SDaniel Fojt return -1;
650*a1157835SDaniel Fojt }
651*a1157835SDaniel Fojt count++;
652*a1157835SDaniel Fojt pac = pac->next;
653*a1157835SDaniel Fojt }
654*a1157835SDaniel Fojt
655*a1157835SDaniel Fojt if (eap_teap_write_pac(sm, pac_file, buf, pos - buf)) {
656*a1157835SDaniel Fojt os_free(buf);
657*a1157835SDaniel Fojt return -1;
658*a1157835SDaniel Fojt }
659*a1157835SDaniel Fojt
660*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-TEAP: Wrote %d PAC entries into '%s'",
661*a1157835SDaniel Fojt count, pac_file);
662*a1157835SDaniel Fojt
663*a1157835SDaniel Fojt return 0;
664*a1157835SDaniel Fojt }
665*a1157835SDaniel Fojt
666*a1157835SDaniel Fojt
667*a1157835SDaniel Fojt /**
668*a1157835SDaniel Fojt * eap_teap_pac_list_truncate - Truncate a PAC list to the given length
669*a1157835SDaniel Fojt * @pac_root: Root of the PAC list
670*a1157835SDaniel Fojt * @max_len: Maximum length of the list (>= 1)
671*a1157835SDaniel Fojt * Returns: Number of PAC entries removed
672*a1157835SDaniel Fojt */
eap_teap_pac_list_truncate(struct eap_teap_pac * pac_root,size_t max_len)673*a1157835SDaniel Fojt size_t eap_teap_pac_list_truncate(struct eap_teap_pac *pac_root,
674*a1157835SDaniel Fojt size_t max_len)
675*a1157835SDaniel Fojt {
676*a1157835SDaniel Fojt struct eap_teap_pac *pac, *prev;
677*a1157835SDaniel Fojt size_t count;
678*a1157835SDaniel Fojt
679*a1157835SDaniel Fojt pac = pac_root;
680*a1157835SDaniel Fojt prev = NULL;
681*a1157835SDaniel Fojt count = 0;
682*a1157835SDaniel Fojt
683*a1157835SDaniel Fojt while (pac) {
684*a1157835SDaniel Fojt count++;
685*a1157835SDaniel Fojt if (count > max_len)
686*a1157835SDaniel Fojt break;
687*a1157835SDaniel Fojt prev = pac;
688*a1157835SDaniel Fojt pac = pac->next;
689*a1157835SDaniel Fojt }
690*a1157835SDaniel Fojt
691*a1157835SDaniel Fojt if (count <= max_len || !prev)
692*a1157835SDaniel Fojt return 0;
693*a1157835SDaniel Fojt
694*a1157835SDaniel Fojt count = 0;
695*a1157835SDaniel Fojt prev->next = NULL;
696*a1157835SDaniel Fojt
697*a1157835SDaniel Fojt while (pac) {
698*a1157835SDaniel Fojt prev = pac;
699*a1157835SDaniel Fojt pac = pac->next;
700*a1157835SDaniel Fojt eap_teap_free_pac(prev);
701*a1157835SDaniel Fojt count++;
702*a1157835SDaniel Fojt }
703*a1157835SDaniel Fojt
704*a1157835SDaniel Fojt return count;
705*a1157835SDaniel Fojt }
706*a1157835SDaniel Fojt
707*a1157835SDaniel Fojt
eap_teap_pac_get_a_id(struct eap_teap_pac * pac)708*a1157835SDaniel Fojt static void eap_teap_pac_get_a_id(struct eap_teap_pac *pac)
709*a1157835SDaniel Fojt {
710*a1157835SDaniel Fojt u8 *pos, *end;
711*a1157835SDaniel Fojt u16 type, len;
712*a1157835SDaniel Fojt
713*a1157835SDaniel Fojt pos = pac->pac_info;
714*a1157835SDaniel Fojt end = pos + pac->pac_info_len;
715*a1157835SDaniel Fojt
716*a1157835SDaniel Fojt while (end - pos > 4) {
717*a1157835SDaniel Fojt type = WPA_GET_BE16(pos);
718*a1157835SDaniel Fojt pos += 2;
719*a1157835SDaniel Fojt len = WPA_GET_BE16(pos);
720*a1157835SDaniel Fojt pos += 2;
721*a1157835SDaniel Fojt if (len > (unsigned int) (end - pos))
722*a1157835SDaniel Fojt break;
723*a1157835SDaniel Fojt
724*a1157835SDaniel Fojt if (type == PAC_TYPE_A_ID) {
725*a1157835SDaniel Fojt os_free(pac->a_id);
726*a1157835SDaniel Fojt pac->a_id = os_memdup(pos, len);
727*a1157835SDaniel Fojt if (!pac->a_id)
728*a1157835SDaniel Fojt break;
729*a1157835SDaniel Fojt pac->a_id_len = len;
730*a1157835SDaniel Fojt }
731*a1157835SDaniel Fojt
732*a1157835SDaniel Fojt if (type == PAC_TYPE_A_ID_INFO) {
733*a1157835SDaniel Fojt os_free(pac->a_id_info);
734*a1157835SDaniel Fojt pac->a_id_info = os_memdup(pos, len);
735*a1157835SDaniel Fojt if (!pac->a_id_info)
736*a1157835SDaniel Fojt break;
737*a1157835SDaniel Fojt pac->a_id_info_len = len;
738*a1157835SDaniel Fojt }
739*a1157835SDaniel Fojt
740*a1157835SDaniel Fojt pos += len;
741*a1157835SDaniel Fojt }
742*a1157835SDaniel Fojt }
743*a1157835SDaniel Fojt
744*a1157835SDaniel Fojt
745*a1157835SDaniel Fojt /**
746*a1157835SDaniel Fojt * eap_teap_load_pac_bin - Load PAC entries (binary format)
747*a1157835SDaniel Fojt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
748*a1157835SDaniel Fojt * @pac_root: Pointer to root of the PAC list (to be filled)
749*a1157835SDaniel Fojt * @pac_file: Name of the PAC file/blob to load
750*a1157835SDaniel Fojt * Returns: 0 on success, -1 on failure
751*a1157835SDaniel Fojt */
eap_teap_load_pac_bin(struct eap_sm * sm,struct eap_teap_pac ** pac_root,const char * pac_file)752*a1157835SDaniel Fojt int eap_teap_load_pac_bin(struct eap_sm *sm, struct eap_teap_pac **pac_root,
753*a1157835SDaniel Fojt const char *pac_file)
754*a1157835SDaniel Fojt {
755*a1157835SDaniel Fojt const struct wpa_config_blob *blob = NULL;
756*a1157835SDaniel Fojt u8 *buf, *end, *pos;
757*a1157835SDaniel Fojt size_t len, count = 0;
758*a1157835SDaniel Fojt struct eap_teap_pac *pac, *prev;
759*a1157835SDaniel Fojt
760*a1157835SDaniel Fojt *pac_root = NULL;
761*a1157835SDaniel Fojt
762*a1157835SDaniel Fojt if (!pac_file)
763*a1157835SDaniel Fojt return -1;
764*a1157835SDaniel Fojt
765*a1157835SDaniel Fojt if (os_strncmp(pac_file, "blob://", 7) == 0) {
766*a1157835SDaniel Fojt blob = eap_get_config_blob(sm, pac_file + 7);
767*a1157835SDaniel Fojt if (!blob) {
768*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
769*a1157835SDaniel Fojt "EAP-TEAP: No PAC blob '%s' - assume no PAC entries have been provisioned",
770*a1157835SDaniel Fojt pac_file + 7);
771*a1157835SDaniel Fojt return 0;
772*a1157835SDaniel Fojt }
773*a1157835SDaniel Fojt buf = blob->data;
774*a1157835SDaniel Fojt len = blob->len;
775*a1157835SDaniel Fojt } else {
776*a1157835SDaniel Fojt buf = (u8 *) os_readfile(pac_file, &len);
777*a1157835SDaniel Fojt if (!buf) {
778*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
779*a1157835SDaniel Fojt "EAP-TEAP: No PAC file '%s' - assume no PAC entries have been provisioned",
780*a1157835SDaniel Fojt pac_file);
781*a1157835SDaniel Fojt return 0;
782*a1157835SDaniel Fojt }
783*a1157835SDaniel Fojt }
784*a1157835SDaniel Fojt
785*a1157835SDaniel Fojt if (len == 0) {
786*a1157835SDaniel Fojt if (!blob)
787*a1157835SDaniel Fojt os_free(buf);
788*a1157835SDaniel Fojt return 0;
789*a1157835SDaniel Fojt }
790*a1157835SDaniel Fojt
791*a1157835SDaniel Fojt if (len < 6 || WPA_GET_BE32(buf) != EAP_TEAP_PAC_BINARY_MAGIC ||
792*a1157835SDaniel Fojt WPA_GET_BE16(buf + 4) != EAP_TEAP_PAC_BINARY_FORMAT_VERSION) {
793*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "EAP-TEAP: Invalid PAC file '%s' (bin)",
794*a1157835SDaniel Fojt pac_file);
795*a1157835SDaniel Fojt if (!blob)
796*a1157835SDaniel Fojt os_free(buf);
797*a1157835SDaniel Fojt return -1;
798*a1157835SDaniel Fojt }
799*a1157835SDaniel Fojt
800*a1157835SDaniel Fojt pac = prev = NULL;
801*a1157835SDaniel Fojt pos = buf + 6;
802*a1157835SDaniel Fojt end = buf + len;
803*a1157835SDaniel Fojt while (pos < end) {
804*a1157835SDaniel Fojt u16 val;
805*a1157835SDaniel Fojt
806*a1157835SDaniel Fojt if (end - pos < 2 + EAP_TEAP_PAC_KEY_LEN + 2 + 2) {
807*a1157835SDaniel Fojt pac = NULL;
808*a1157835SDaniel Fojt goto parse_fail;
809*a1157835SDaniel Fojt }
810*a1157835SDaniel Fojt
811*a1157835SDaniel Fojt pac = os_zalloc(sizeof(*pac));
812*a1157835SDaniel Fojt if (!pac)
813*a1157835SDaniel Fojt goto parse_fail;
814*a1157835SDaniel Fojt
815*a1157835SDaniel Fojt pac->pac_type = WPA_GET_BE16(pos);
816*a1157835SDaniel Fojt pos += 2;
817*a1157835SDaniel Fojt os_memcpy(pac->pac_key, pos, EAP_TEAP_PAC_KEY_LEN);
818*a1157835SDaniel Fojt pos += EAP_TEAP_PAC_KEY_LEN;
819*a1157835SDaniel Fojt val = WPA_GET_BE16(pos);
820*a1157835SDaniel Fojt pos += 2;
821*a1157835SDaniel Fojt if (val > end - pos)
822*a1157835SDaniel Fojt goto parse_fail;
823*a1157835SDaniel Fojt pac->pac_opaque_len = val;
824*a1157835SDaniel Fojt pac->pac_opaque = os_memdup(pos, pac->pac_opaque_len);
825*a1157835SDaniel Fojt if (!pac->pac_opaque)
826*a1157835SDaniel Fojt goto parse_fail;
827*a1157835SDaniel Fojt pos += pac->pac_opaque_len;
828*a1157835SDaniel Fojt if (end - pos < 2)
829*a1157835SDaniel Fojt goto parse_fail;
830*a1157835SDaniel Fojt val = WPA_GET_BE16(pos);
831*a1157835SDaniel Fojt pos += 2;
832*a1157835SDaniel Fojt if (val > end - pos)
833*a1157835SDaniel Fojt goto parse_fail;
834*a1157835SDaniel Fojt pac->pac_info_len = val;
835*a1157835SDaniel Fojt pac->pac_info = os_memdup(pos, pac->pac_info_len);
836*a1157835SDaniel Fojt if (!pac->pac_info)
837*a1157835SDaniel Fojt goto parse_fail;
838*a1157835SDaniel Fojt pos += pac->pac_info_len;
839*a1157835SDaniel Fojt eap_teap_pac_get_a_id(pac);
840*a1157835SDaniel Fojt
841*a1157835SDaniel Fojt count++;
842*a1157835SDaniel Fojt if (prev)
843*a1157835SDaniel Fojt prev->next = pac;
844*a1157835SDaniel Fojt else
845*a1157835SDaniel Fojt *pac_root = pac;
846*a1157835SDaniel Fojt prev = pac;
847*a1157835SDaniel Fojt }
848*a1157835SDaniel Fojt
849*a1157835SDaniel Fojt if (!blob)
850*a1157835SDaniel Fojt os_free(buf);
851*a1157835SDaniel Fojt
852*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-TEAP: Read %lu PAC entries from '%s' (bin)",
853*a1157835SDaniel Fojt (unsigned long) count, pac_file);
854*a1157835SDaniel Fojt
855*a1157835SDaniel Fojt return 0;
856*a1157835SDaniel Fojt
857*a1157835SDaniel Fojt parse_fail:
858*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "EAP-TEAP: Failed to parse PAC file '%s' (bin)",
859*a1157835SDaniel Fojt pac_file);
860*a1157835SDaniel Fojt if (!blob)
861*a1157835SDaniel Fojt os_free(buf);
862*a1157835SDaniel Fojt if (pac)
863*a1157835SDaniel Fojt eap_teap_free_pac(pac);
864*a1157835SDaniel Fojt return -1;
865*a1157835SDaniel Fojt }
866*a1157835SDaniel Fojt
867*a1157835SDaniel Fojt
868*a1157835SDaniel Fojt /**
869*a1157835SDaniel Fojt * eap_teap_save_pac_bin - Save PAC entries (binary format)
870*a1157835SDaniel Fojt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
871*a1157835SDaniel Fojt * @pac_root: Root of the PAC list
872*a1157835SDaniel Fojt * @pac_file: Name of the PAC file/blob
873*a1157835SDaniel Fojt * Returns: 0 on success, -1 on failure
874*a1157835SDaniel Fojt */
eap_teap_save_pac_bin(struct eap_sm * sm,struct eap_teap_pac * pac_root,const char * pac_file)875*a1157835SDaniel Fojt int eap_teap_save_pac_bin(struct eap_sm *sm, struct eap_teap_pac *pac_root,
876*a1157835SDaniel Fojt const char *pac_file)
877*a1157835SDaniel Fojt {
878*a1157835SDaniel Fojt size_t len, count = 0;
879*a1157835SDaniel Fojt struct eap_teap_pac *pac;
880*a1157835SDaniel Fojt u8 *buf, *pos;
881*a1157835SDaniel Fojt
882*a1157835SDaniel Fojt len = 6;
883*a1157835SDaniel Fojt pac = pac_root;
884*a1157835SDaniel Fojt while (pac) {
885*a1157835SDaniel Fojt if (pac->pac_opaque_len > 65535 ||
886*a1157835SDaniel Fojt pac->pac_info_len > 65535)
887*a1157835SDaniel Fojt return -1;
888*a1157835SDaniel Fojt len += 2 + EAP_TEAP_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
889*a1157835SDaniel Fojt 2 + pac->pac_info_len;
890*a1157835SDaniel Fojt pac = pac->next;
891*a1157835SDaniel Fojt }
892*a1157835SDaniel Fojt
893*a1157835SDaniel Fojt buf = os_malloc(len);
894*a1157835SDaniel Fojt if (!buf)
895*a1157835SDaniel Fojt return -1;
896*a1157835SDaniel Fojt
897*a1157835SDaniel Fojt pos = buf;
898*a1157835SDaniel Fojt WPA_PUT_BE32(pos, EAP_TEAP_PAC_BINARY_MAGIC);
899*a1157835SDaniel Fojt pos += 4;
900*a1157835SDaniel Fojt WPA_PUT_BE16(pos, EAP_TEAP_PAC_BINARY_FORMAT_VERSION);
901*a1157835SDaniel Fojt pos += 2;
902*a1157835SDaniel Fojt
903*a1157835SDaniel Fojt pac = pac_root;
904*a1157835SDaniel Fojt while (pac) {
905*a1157835SDaniel Fojt WPA_PUT_BE16(pos, pac->pac_type);
906*a1157835SDaniel Fojt pos += 2;
907*a1157835SDaniel Fojt os_memcpy(pos, pac->pac_key, EAP_TEAP_PAC_KEY_LEN);
908*a1157835SDaniel Fojt pos += EAP_TEAP_PAC_KEY_LEN;
909*a1157835SDaniel Fojt WPA_PUT_BE16(pos, pac->pac_opaque_len);
910*a1157835SDaniel Fojt pos += 2;
911*a1157835SDaniel Fojt os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
912*a1157835SDaniel Fojt pos += pac->pac_opaque_len;
913*a1157835SDaniel Fojt WPA_PUT_BE16(pos, pac->pac_info_len);
914*a1157835SDaniel Fojt pos += 2;
915*a1157835SDaniel Fojt os_memcpy(pos, pac->pac_info, pac->pac_info_len);
916*a1157835SDaniel Fojt pos += pac->pac_info_len;
917*a1157835SDaniel Fojt
918*a1157835SDaniel Fojt pac = pac->next;
919*a1157835SDaniel Fojt count++;
920*a1157835SDaniel Fojt }
921*a1157835SDaniel Fojt
922*a1157835SDaniel Fojt if (eap_teap_write_pac(sm, pac_file, (char *) buf, len)) {
923*a1157835SDaniel Fojt os_free(buf);
924*a1157835SDaniel Fojt return -1;
925*a1157835SDaniel Fojt }
926*a1157835SDaniel Fojt
927*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-TEAP: Wrote %lu PAC entries into '%s' (bin)",
928*a1157835SDaniel Fojt (unsigned long) count, pac_file);
929*a1157835SDaniel Fojt
930*a1157835SDaniel Fojt return 0;
931*a1157835SDaniel Fojt }
932