xref: /freebsd/contrib/wpa/src/eap_peer/eap_teap_pac.c (revision c5c3ba6b43cac20dc9432eac15758d41cb2b8b1f)
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