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