1  /*
2   * EAP peer method: EAP-GPSK (RFC 5433)
3   * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
4   *
5   * This software may be distributed under the terms of the BSD license.
6   * See README for more details.
7   */
8  
9  #include "includes.h"
10  
11  #include "common.h"
12  #include "crypto/random.h"
13  #include "eap_peer/eap_i.h"
14  #include "eap_common/eap_gpsk_common.h"
15  
16  struct eap_gpsk_data {
17  	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
18  	u8 rand_server[EAP_GPSK_RAND_LEN];
19  	u8 rand_peer[EAP_GPSK_RAND_LEN];
20  	u8 msk[EAP_MSK_LEN];
21  	u8 emsk[EAP_EMSK_LEN];
22  	u8 sk[EAP_GPSK_MAX_SK_LEN];
23  	size_t sk_len;
24  	u8 pk[EAP_GPSK_MAX_PK_LEN];
25  	size_t pk_len;
26  	u8 session_id[128];
27  	size_t id_len;
28  	u8 *id_peer;
29  	size_t id_peer_len;
30  	u8 *id_server;
31  	size_t id_server_len;
32  	int vendor; /* CSuite/Specifier */
33  	int specifier; /* CSuite/Specifier */
34  	u8 *psk;
35  	size_t psk_len;
36  	u16 forced_cipher; /* force cipher or 0 to allow all supported */
37  };
38  
39  
40  static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
41  					    u8 identifier,
42  					    const u8 *csuite_list,
43  					    size_t csuite_list_len);
44  static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
45  					    u8 identifier);
46  
47  
48  #ifndef CONFIG_NO_STDOUT_DEBUG
eap_gpsk_state_txt(int state)49  static const char * eap_gpsk_state_txt(int state)
50  {
51  	switch (state) {
52  	case GPSK_1:
53  		return "GPSK-1";
54  	case GPSK_3:
55  		return "GPSK-3";
56  	case SUCCESS:
57  		return "SUCCESS";
58  	case FAILURE:
59  		return "FAILURE";
60  	default:
61  		return "?";
62  	}
63  }
64  #endif /* CONFIG_NO_STDOUT_DEBUG */
65  
66  
eap_gpsk_state(struct eap_gpsk_data * data,int state)67  static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
68  {
69  	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
70  		   eap_gpsk_state_txt(data->state),
71  		   eap_gpsk_state_txt(state));
72  	data->state = state;
73  }
74  
75  
76  static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
77  
78  
eap_gpsk_init(struct eap_sm * sm)79  static void * eap_gpsk_init(struct eap_sm *sm)
80  {
81  	struct eap_gpsk_data *data;
82  	const u8 *identity, *password;
83  	size_t identity_len, password_len;
84  	const char *phase1;
85  
86  	password = eap_get_config_password(sm, &password_len);
87  	if (password == NULL) {
88  		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
89  		return NULL;
90  	}
91  
92  	data = os_zalloc(sizeof(*data));
93  	if (data == NULL)
94  		return NULL;
95  	data->state = GPSK_1;
96  
97  	identity = eap_get_config_identity(sm, &identity_len);
98  	if (identity) {
99  		data->id_peer = os_memdup(identity, identity_len);
100  		if (data->id_peer == NULL) {
101  			eap_gpsk_deinit(sm, data);
102  			return NULL;
103  		}
104  		data->id_peer_len = identity_len;
105  	}
106  
107  	phase1 = eap_get_config_phase1(sm);
108  	if (phase1) {
109  		const char *pos;
110  
111  		pos = os_strstr(phase1, "cipher=");
112  		if (pos) {
113  			data->forced_cipher = atoi(pos + 7);
114  			wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
115  				   data->forced_cipher);
116  		}
117  	}
118  
119  	data->psk = os_memdup(password, password_len);
120  	if (data->psk == NULL) {
121  		eap_gpsk_deinit(sm, data);
122  		return NULL;
123  	}
124  	data->psk_len = password_len;
125  
126  	return data;
127  }
128  
129  
eap_gpsk_deinit(struct eap_sm * sm,void * priv)130  static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
131  {
132  	struct eap_gpsk_data *data = priv;
133  	os_free(data->id_server);
134  	os_free(data->id_peer);
135  	if (data->psk) {
136  		os_memset(data->psk, 0, data->psk_len);
137  		os_free(data->psk);
138  	}
139  	bin_clear_free(data, sizeof(*data));
140  }
141  
142  
eap_gpsk_process_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)143  static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
144  					     const u8 *pos, const u8 *end)
145  {
146  	u16 alen;
147  
148  	if (end - pos < 2) {
149  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
150  		return NULL;
151  	}
152  	alen = WPA_GET_BE16(pos);
153  	pos += 2;
154  	if (end - pos < alen) {
155  		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
156  		return NULL;
157  	}
158  	os_free(data->id_server);
159  	data->id_server = os_memdup(pos, alen);
160  	if (data->id_server == NULL) {
161  		wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
162  		return NULL;
163  	}
164  	data->id_server_len = alen;
165  	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
166  			  data->id_server, data->id_server_len);
167  	pos += alen;
168  
169  	return pos;
170  }
171  
172  
eap_gpsk_process_rand_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)173  static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
174  					       const u8 *pos, const u8 *end)
175  {
176  	if (pos == NULL)
177  		return NULL;
178  
179  	if (end - pos < EAP_GPSK_RAND_LEN) {
180  		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
181  		return NULL;
182  	}
183  	os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
184  	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
185  		    data->rand_server, EAP_GPSK_RAND_LEN);
186  	pos += EAP_GPSK_RAND_LEN;
187  
188  	return pos;
189  }
190  
191  
eap_gpsk_select_csuite(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 * csuite_list,size_t csuite_list_len)192  static int eap_gpsk_select_csuite(struct eap_sm *sm,
193  				  struct eap_gpsk_data *data,
194  				  const u8 *csuite_list,
195  				  size_t csuite_list_len)
196  {
197  	struct eap_gpsk_csuite *csuite;
198  	int i, count;
199  
200  	count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
201  	data->vendor = EAP_GPSK_VENDOR_IETF;
202  	data->specifier = EAP_GPSK_CIPHER_RESERVED;
203  	csuite = (struct eap_gpsk_csuite *) csuite_list;
204  	for (i = 0; i < count; i++) {
205  		int vendor, specifier;
206  		vendor = WPA_GET_BE32(csuite->vendor);
207  		specifier = WPA_GET_BE16(csuite->specifier);
208  		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
209  			   i, vendor, specifier);
210  		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
211  		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
212  		    eap_gpsk_supported_ciphersuite(vendor, specifier) &&
213  		    (!data->forced_cipher || data->forced_cipher == specifier))
214  		{
215  			data->vendor = vendor;
216  			data->specifier = specifier;
217  		}
218  		csuite++;
219  	}
220  	if (data->vendor == EAP_GPSK_VENDOR_IETF &&
221  	    data->specifier == EAP_GPSK_CIPHER_RESERVED) {
222  		wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
223  			"ciphersuite found");
224  		return -1;
225  	}
226  	wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
227  		   data->vendor, data->specifier);
228  
229  	return 0;
230  }
231  
232  
eap_gpsk_process_csuite_list(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 ** list,size_t * list_len,const u8 * pos,const u8 * end)233  static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
234  					       struct eap_gpsk_data *data,
235  					       const u8 **list,
236  					       size_t *list_len,
237  					       const u8 *pos, const u8 *end)
238  {
239  	size_t len;
240  
241  	if (pos == NULL)
242  		return NULL;
243  
244  	if (end - pos < 2) {
245  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
246  		return NULL;
247  	}
248  	len = WPA_GET_BE16(pos);
249  	pos += 2;
250  	if (len > (size_t) (end - pos)) {
251  		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
252  		return NULL;
253  	}
254  	if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
255  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
256  			   (unsigned long) len);
257  		return NULL;
258  	}
259  
260  	if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
261  		return NULL;
262  
263  	*list = pos;
264  	*list_len = len;
265  	pos += len;
266  
267  	return pos;
268  }
269  
270  
eap_gpsk_process_gpsk_1(struct eap_sm * sm,struct eap_gpsk_data * data,struct eap_method_ret * ret,u8 identifier,const u8 * payload,size_t payload_len)271  static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
272  					       struct eap_gpsk_data *data,
273  					       struct eap_method_ret *ret,
274  					       u8 identifier,
275  					       const u8 *payload,
276  					       size_t payload_len)
277  {
278  	size_t csuite_list_len;
279  	const u8 *csuite_list, *pos, *end;
280  	struct wpabuf *resp;
281  
282  	if (data->state != GPSK_1) {
283  		ret->ignore = true;
284  		return NULL;
285  	}
286  
287  	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
288  
289  	end = payload + payload_len;
290  
291  	pos = eap_gpsk_process_id_server(data, payload, end);
292  	pos = eap_gpsk_process_rand_server(data, pos, end);
293  	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
294  					   &csuite_list_len, pos, end);
295  	if (pos == NULL) {
296  		ret->methodState = METHOD_DONE;
297  		eap_gpsk_state(data, FAILURE);
298  		return NULL;
299  	}
300  
301  	resp = eap_gpsk_send_gpsk_2(data, identifier,
302  				    csuite_list, csuite_list_len);
303  	if (resp == NULL)
304  		return NULL;
305  
306  	eap_gpsk_state(data, GPSK_3);
307  
308  	return resp;
309  }
310  
311  
eap_gpsk_send_gpsk_2(struct eap_gpsk_data * data,u8 identifier,const u8 * csuite_list,size_t csuite_list_len)312  static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
313  					    u8 identifier,
314  					    const u8 *csuite_list,
315  					    size_t csuite_list_len)
316  {
317  	struct wpabuf *resp;
318  	size_t len, miclen;
319  	u8 *rpos, *start;
320  	struct eap_gpsk_csuite *csuite;
321  
322  	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
323  
324  	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
325  	len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
326  		2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
327  		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
328  
329  	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
330  			     EAP_CODE_RESPONSE, identifier);
331  	if (resp == NULL)
332  		return NULL;
333  
334  	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
335  	start = wpabuf_put(resp, 0);
336  
337  	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
338  			  data->id_peer, data->id_peer_len);
339  	wpabuf_put_be16(resp, data->id_peer_len);
340  	wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
341  
342  	wpabuf_put_be16(resp, data->id_server_len);
343  	wpabuf_put_data(resp, data->id_server, data->id_server_len);
344  
345  	if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
346  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
347  			   "for RAND_Peer");
348  		eap_gpsk_state(data, FAILURE);
349  		wpabuf_free(resp);
350  		return NULL;
351  	}
352  	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
353  		    data->rand_peer, EAP_GPSK_RAND_LEN);
354  	wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
355  	wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
356  
357  	wpabuf_put_be16(resp, csuite_list_len);
358  	wpabuf_put_data(resp, csuite_list, csuite_list_len);
359  
360  	csuite = wpabuf_put(resp, sizeof(*csuite));
361  	WPA_PUT_BE32(csuite->vendor, data->vendor);
362  	WPA_PUT_BE16(csuite->specifier, data->specifier);
363  
364  	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
365  				 data->vendor, data->specifier,
366  				 data->rand_peer, data->rand_server,
367  				 data->id_peer, data->id_peer_len,
368  				 data->id_server, data->id_server_len,
369  				 data->msk, data->emsk,
370  				 data->sk, &data->sk_len,
371  				 data->pk, &data->pk_len) < 0) {
372  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
373  		eap_gpsk_state(data, FAILURE);
374  		wpabuf_free(resp);
375  		return NULL;
376  	}
377  
378  	if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
379  				       data->vendor, data->specifier,
380  				       data->rand_peer, data->rand_server,
381  				       data->id_peer, data->id_peer_len,
382  				       data->id_server, data->id_server_len,
383  				       EAP_TYPE_GPSK,
384  				       data->session_id, &data->id_len) < 0) {
385  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
386  		eap_gpsk_state(data, FAILURE);
387  		wpabuf_free(resp);
388  		return NULL;
389  	}
390  	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
391  		    data->session_id, data->id_len);
392  
393  	/* No PD_Payload_1 */
394  	wpabuf_put_be16(resp, 0);
395  
396  	rpos = wpabuf_put(resp, miclen);
397  	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
398  				 data->specifier, start, rpos - start, rpos) <
399  	    0) {
400  		eap_gpsk_state(data, FAILURE);
401  		wpabuf_free(resp);
402  		return NULL;
403  	}
404  
405  	return resp;
406  }
407  
408  
eap_gpsk_validate_rand(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)409  static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
410  					 const u8 *pos, const u8 *end)
411  {
412  	if (end - pos < EAP_GPSK_RAND_LEN) {
413  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
414  			   "RAND_Peer");
415  		return NULL;
416  	}
417  	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
418  		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
419  			   "GPSK-3 did not match");
420  		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
421  			    data->rand_peer, EAP_GPSK_RAND_LEN);
422  		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
423  			    pos, EAP_GPSK_RAND_LEN);
424  		return NULL;
425  	}
426  	pos += EAP_GPSK_RAND_LEN;
427  
428  	if (end - pos < EAP_GPSK_RAND_LEN) {
429  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
430  			   "RAND_Server");
431  		return NULL;
432  	}
433  	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
434  		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
435  			   "GPSK-3 did not match");
436  		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
437  			    data->rand_server, EAP_GPSK_RAND_LEN);
438  		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
439  			    pos, EAP_GPSK_RAND_LEN);
440  		return NULL;
441  	}
442  	pos += EAP_GPSK_RAND_LEN;
443  
444  	return pos;
445  }
446  
447  
eap_gpsk_validate_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)448  static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
449  					      const u8 *pos, const u8 *end)
450  {
451  	size_t len;
452  
453  	if (pos == NULL)
454  		return NULL;
455  
456  	if (end - pos < (int) 2) {
457  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
458  			   "length(ID_Server)");
459  		return NULL;
460  	}
461  
462  	len = WPA_GET_BE16(pos);
463  	pos += 2;
464  
465  	if (end - pos < (int) len) {
466  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
467  			   "ID_Server");
468  		return NULL;
469  	}
470  
471  	if (len != data->id_server_len ||
472  	    os_memcmp(pos, data->id_server, len) != 0) {
473  		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
474  			   "the one used in GPSK-1");
475  		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
476  				  data->id_server, data->id_server_len);
477  		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
478  				  pos, len);
479  		return NULL;
480  	}
481  
482  	pos += len;
483  
484  	return pos;
485  }
486  
487  
eap_gpsk_validate_csuite(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)488  static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
489  					   const u8 *pos, const u8 *end)
490  {
491  	int vendor, specifier;
492  	const struct eap_gpsk_csuite *csuite;
493  
494  	if (pos == NULL)
495  		return NULL;
496  
497  	if (end - pos < (int) sizeof(*csuite)) {
498  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
499  			   "CSuite_Sel");
500  		return NULL;
501  	}
502  	csuite = (const struct eap_gpsk_csuite *) pos;
503  	vendor = WPA_GET_BE32(csuite->vendor);
504  	specifier = WPA_GET_BE16(csuite->specifier);
505  	pos += sizeof(*csuite);
506  	if (vendor != data->vendor || specifier != data->specifier) {
507  		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
508  			   "match with the one sent in GPSK-2 (%d:%d)",
509  			   vendor, specifier, data->vendor, data->specifier);
510  		return NULL;
511  	}
512  
513  	return pos;
514  }
515  
516  
eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)517  static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
518  						 const u8 *pos, const u8 *end)
519  {
520  	u16 alen;
521  
522  	if (pos == NULL)
523  		return NULL;
524  
525  	if (end - pos < 2) {
526  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
527  			   "PD_Payload_2 length");
528  		return NULL;
529  	}
530  	alen = WPA_GET_BE16(pos);
531  	pos += 2;
532  	if (end - pos < alen) {
533  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
534  			   "%d-octet PD_Payload_2", alen);
535  		return NULL;
536  	}
537  	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
538  	pos += alen;
539  
540  	return pos;
541  }
542  
543  
eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data * data,const u8 * payload,const u8 * pos,const u8 * end)544  static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
545  					       const u8 *payload,
546  					       const u8 *pos, const u8 *end)
547  {
548  	size_t miclen;
549  	u8 mic[EAP_GPSK_MAX_MIC_LEN];
550  
551  	if (pos == NULL)
552  		return NULL;
553  
554  	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
555  	if (end - pos < (int) miclen) {
556  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
557  			   "(left=%lu miclen=%lu)",
558  			   (unsigned long) (end - pos),
559  			   (unsigned long) miclen);
560  		return NULL;
561  	}
562  	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
563  				 data->specifier, payload, pos - payload, mic)
564  	    < 0) {
565  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
566  		return NULL;
567  	}
568  	if (os_memcmp_const(mic, pos, miclen) != 0) {
569  		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
570  		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
571  		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
572  		return NULL;
573  	}
574  	pos += miclen;
575  
576  	return pos;
577  }
578  
579  
eap_gpsk_process_gpsk_3(struct eap_sm * sm,struct eap_gpsk_data * data,struct eap_method_ret * ret,u8 identifier,const u8 * payload,size_t payload_len)580  static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
581  					       struct eap_gpsk_data *data,
582  					       struct eap_method_ret *ret,
583  					       u8 identifier,
584  					       const u8 *payload,
585  					       size_t payload_len)
586  {
587  	struct wpabuf *resp;
588  	const u8 *pos, *end;
589  
590  	if (data->state != GPSK_3) {
591  		ret->ignore = true;
592  		return NULL;
593  	}
594  
595  	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
596  
597  	end = payload + payload_len;
598  
599  	pos = eap_gpsk_validate_rand(data, payload, end);
600  	pos = eap_gpsk_validate_id_server(data, pos, end);
601  	pos = eap_gpsk_validate_csuite(data, pos, end);
602  	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
603  	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
604  
605  	if (pos == NULL) {
606  		eap_gpsk_state(data, FAILURE);
607  		return NULL;
608  	}
609  	if (pos != end) {
610  		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
611  			   "data in the end of GPSK-2",
612  			   (unsigned long) (end - pos));
613  	}
614  
615  	resp = eap_gpsk_send_gpsk_4(data, identifier);
616  	if (resp == NULL)
617  		return NULL;
618  
619  	eap_gpsk_state(data, SUCCESS);
620  	ret->methodState = METHOD_DONE;
621  	ret->decision = DECISION_UNCOND_SUCC;
622  
623  	return resp;
624  }
625  
626  
eap_gpsk_send_gpsk_4(struct eap_gpsk_data * data,u8 identifier)627  static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
628  					    u8 identifier)
629  {
630  	struct wpabuf *resp;
631  	u8 *rpos, *start;
632  	size_t mlen;
633  
634  	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
635  
636  	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
637  
638  	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
639  			     EAP_CODE_RESPONSE, identifier);
640  	if (resp == NULL)
641  		return NULL;
642  
643  	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
644  	start = wpabuf_put(resp, 0);
645  
646  	/* No PD_Payload_3 */
647  	wpabuf_put_be16(resp, 0);
648  
649  	rpos = wpabuf_put(resp, mlen);
650  	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
651  				 data->specifier, start, rpos - start, rpos) <
652  	    0) {
653  		eap_gpsk_state(data, FAILURE);
654  		wpabuf_free(resp);
655  		return NULL;
656  	}
657  
658  	return resp;
659  }
660  
661  
eap_gpsk_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)662  static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
663  					struct eap_method_ret *ret,
664  					const struct wpabuf *reqData)
665  {
666  	struct eap_gpsk_data *data = priv;
667  	struct wpabuf *resp;
668  	const u8 *pos;
669  	size_t len;
670  	u8 opcode, id;
671  
672  	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
673  	if (pos == NULL || len < 1) {
674  		ret->ignore = true;
675  		return NULL;
676  	}
677  
678  	id = eap_get_id(reqData);
679  	opcode = *pos++;
680  	len--;
681  	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
682  
683  	ret->ignore = false;
684  	ret->methodState = METHOD_MAY_CONT;
685  	ret->decision = DECISION_FAIL;
686  	ret->allowNotifications = false;
687  
688  	switch (opcode) {
689  	case EAP_GPSK_OPCODE_GPSK_1:
690  		resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
691  		break;
692  	case EAP_GPSK_OPCODE_GPSK_3:
693  		resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
694  		break;
695  	default:
696  		wpa_printf(MSG_DEBUG,
697  			   "EAP-GPSK: Ignoring message with unknown opcode %d",
698  			   opcode);
699  		ret->ignore = true;
700  		return NULL;
701  	}
702  
703  	return resp;
704  }
705  
706  
eap_gpsk_isKeyAvailable(struct eap_sm * sm,void * priv)707  static bool eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
708  {
709  	struct eap_gpsk_data *data = priv;
710  	return data->state == SUCCESS;
711  }
712  
713  
eap_gpsk_getKey(struct eap_sm * sm,void * priv,size_t * len)714  static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
715  {
716  	struct eap_gpsk_data *data = priv;
717  	u8 *key;
718  
719  	if (data->state != SUCCESS)
720  		return NULL;
721  
722  	key = os_memdup(data->msk, EAP_MSK_LEN);
723  	if (key == NULL)
724  		return NULL;
725  	*len = EAP_MSK_LEN;
726  
727  	return key;
728  }
729  
730  
eap_gpsk_get_emsk(struct eap_sm * sm,void * priv,size_t * len)731  static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
732  {
733  	struct eap_gpsk_data *data = priv;
734  	u8 *key;
735  
736  	if (data->state != SUCCESS)
737  		return NULL;
738  
739  	key = os_memdup(data->emsk, EAP_EMSK_LEN);
740  	if (key == NULL)
741  		return NULL;
742  	*len = EAP_EMSK_LEN;
743  
744  	return key;
745  }
746  
747  
eap_gpsk_get_session_id(struct eap_sm * sm,void * priv,size_t * len)748  static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
749  {
750  	struct eap_gpsk_data *data = priv;
751  	u8 *sid;
752  
753  	if (data->state != SUCCESS)
754  		return NULL;
755  
756  	sid = os_memdup(data->session_id, data->id_len);
757  	if (sid == NULL)
758  		return NULL;
759  	*len = data->id_len;
760  
761  	return sid;
762  }
763  
764  
eap_peer_gpsk_register(void)765  int eap_peer_gpsk_register(void)
766  {
767  	struct eap_method *eap;
768  
769  	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
770  				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
771  	if (eap == NULL)
772  		return -1;
773  
774  	eap->init = eap_gpsk_init;
775  	eap->deinit = eap_gpsk_deinit;
776  	eap->process = eap_gpsk_process;
777  	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
778  	eap->getKey = eap_gpsk_getKey;
779  	eap->get_emsk = eap_gpsk_get_emsk;
780  	eap->getSessionId = eap_gpsk_get_session_id;
781  
782  	return eap_peer_method_register(eap);
783  }
784