1206b73d0SCy Schubert /*
2206b73d0SCy Schubert * EAP-TEAP server (RFC 7170)
3206b73d0SCy Schubert * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
4206b73d0SCy Schubert *
5206b73d0SCy Schubert * This software may be distributed under the terms of the BSD license.
6206b73d0SCy Schubert * See README for more details.
7206b73d0SCy Schubert */
8206b73d0SCy Schubert
9206b73d0SCy Schubert #include "includes.h"
10206b73d0SCy Schubert
11206b73d0SCy Schubert #include "common.h"
12206b73d0SCy Schubert #include "crypto/aes_wrap.h"
13206b73d0SCy Schubert #include "crypto/tls.h"
14206b73d0SCy Schubert #include "crypto/random.h"
15206b73d0SCy Schubert #include "eap_common/eap_teap_common.h"
16206b73d0SCy Schubert #include "eap_i.h"
17206b73d0SCy Schubert #include "eap_tls_common.h"
18206b73d0SCy Schubert
19206b73d0SCy Schubert
20206b73d0SCy Schubert static void eap_teap_reset(struct eap_sm *sm, void *priv);
21206b73d0SCy Schubert
22206b73d0SCy Schubert
23206b73d0SCy Schubert /* Private PAC-Opaque TLV types */
24206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_PAD 0
25206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_KEY 1
26206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_LIFETIME 2
27206b73d0SCy Schubert #define PAC_OPAQUE_TYPE_IDENTITY 3
28206b73d0SCy Schubert
29206b73d0SCy Schubert struct eap_teap_data {
30206b73d0SCy Schubert struct eap_ssl_data ssl;
31206b73d0SCy Schubert enum {
32206b73d0SCy Schubert START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID,
33206b73d0SCy Schubert PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC,
34c1d255d3SCy Schubert FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE
35206b73d0SCy Schubert } state;
36206b73d0SCy Schubert
37206b73d0SCy Schubert u8 teap_version;
38206b73d0SCy Schubert u8 peer_version;
39206b73d0SCy Schubert u16 tls_cs;
40206b73d0SCy Schubert
41206b73d0SCy Schubert const struct eap_method *phase2_method;
42206b73d0SCy Schubert void *phase2_priv;
43206b73d0SCy Schubert
44206b73d0SCy Schubert u8 crypto_binding_nonce[32];
45206b73d0SCy Schubert int final_result;
46206b73d0SCy Schubert
47206b73d0SCy Schubert u8 simck_msk[EAP_TEAP_SIMCK_LEN];
48206b73d0SCy Schubert u8 cmk_msk[EAP_TEAP_CMK_LEN];
49206b73d0SCy Schubert u8 simck_emsk[EAP_TEAP_SIMCK_LEN];
50206b73d0SCy Schubert u8 cmk_emsk[EAP_TEAP_CMK_LEN];
51206b73d0SCy Schubert int simck_idx;
52206b73d0SCy Schubert int cmk_emsk_available;
53206b73d0SCy Schubert
54206b73d0SCy Schubert u8 pac_opaque_encr[16];
55206b73d0SCy Schubert u8 *srv_id;
56206b73d0SCy Schubert size_t srv_id_len;
57206b73d0SCy Schubert char *srv_id_info;
58206b73d0SCy Schubert
59c1d255d3SCy Schubert unsigned int basic_auth_not_done:1;
60c1d255d3SCy Schubert unsigned int inner_eap_not_done:1;
61206b73d0SCy Schubert int anon_provisioning;
62c1d255d3SCy Schubert int skipped_inner_auth;
63206b73d0SCy Schubert int send_new_pac; /* server triggered re-keying of Tunnel PAC */
64206b73d0SCy Schubert struct wpabuf *pending_phase2_resp;
65206b73d0SCy Schubert struct wpabuf *server_outer_tlvs;
66206b73d0SCy Schubert struct wpabuf *peer_outer_tlvs;
67c1d255d3SCy Schubert u8 *identity; /* from PAC-Opaque or client certificate */
68206b73d0SCy Schubert size_t identity_len;
69206b73d0SCy Schubert int eap_seq;
70206b73d0SCy Schubert int tnc_started;
71206b73d0SCy Schubert
72206b73d0SCy Schubert int pac_key_lifetime;
73206b73d0SCy Schubert int pac_key_refresh_time;
74206b73d0SCy Schubert
75206b73d0SCy Schubert enum teap_error_codes error_code;
76c1d255d3SCy Schubert enum teap_identity_types cur_id_type;
77*a90b9d01SCy Schubert
78*a90b9d01SCy Schubert bool check_crypto_binding;
79206b73d0SCy Schubert };
80206b73d0SCy Schubert
81206b73d0SCy Schubert
82206b73d0SCy Schubert static int eap_teap_process_phase2_start(struct eap_sm *sm,
83206b73d0SCy Schubert struct eap_teap_data *data);
84*a90b9d01SCy Schubert static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
85*a90b9d01SCy Schubert int vendor, enum eap_type eap_type);
86206b73d0SCy Schubert
87206b73d0SCy Schubert
eap_teap_state_txt(int state)88206b73d0SCy Schubert static const char * eap_teap_state_txt(int state)
89206b73d0SCy Schubert {
90206b73d0SCy Schubert switch (state) {
91206b73d0SCy Schubert case START:
92206b73d0SCy Schubert return "START";
93206b73d0SCy Schubert case PHASE1:
94206b73d0SCy Schubert return "PHASE1";
95206b73d0SCy Schubert case PHASE1B:
96206b73d0SCy Schubert return "PHASE1B";
97206b73d0SCy Schubert case PHASE2_START:
98206b73d0SCy Schubert return "PHASE2_START";
99206b73d0SCy Schubert case PHASE2_ID:
100206b73d0SCy Schubert return "PHASE2_ID";
101206b73d0SCy Schubert case PHASE2_BASIC_AUTH:
102206b73d0SCy Schubert return "PHASE2_BASIC_AUTH";
103206b73d0SCy Schubert case PHASE2_METHOD:
104206b73d0SCy Schubert return "PHASE2_METHOD";
105206b73d0SCy Schubert case CRYPTO_BINDING:
106206b73d0SCy Schubert return "CRYPTO_BINDING";
107206b73d0SCy Schubert case REQUEST_PAC:
108206b73d0SCy Schubert return "REQUEST_PAC";
109206b73d0SCy Schubert case FAILURE_SEND_RESULT:
110206b73d0SCy Schubert return "FAILURE_SEND_RESULT";
111c1d255d3SCy Schubert case SUCCESS_SEND_RESULT:
112c1d255d3SCy Schubert return "SUCCESS_SEND_RESULT";
113206b73d0SCy Schubert case SUCCESS:
114206b73d0SCy Schubert return "SUCCESS";
115206b73d0SCy Schubert case FAILURE:
116206b73d0SCy Schubert return "FAILURE";
117206b73d0SCy Schubert default:
118206b73d0SCy Schubert return "Unknown?!";
119206b73d0SCy Schubert }
120206b73d0SCy Schubert }
121206b73d0SCy Schubert
122206b73d0SCy Schubert
eap_teap_state(struct eap_teap_data * data,int state)123206b73d0SCy Schubert static void eap_teap_state(struct eap_teap_data *data, int state)
124206b73d0SCy Schubert {
125206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: %s -> %s",
126206b73d0SCy Schubert eap_teap_state_txt(data->state),
127206b73d0SCy Schubert eap_teap_state_txt(state));
128206b73d0SCy Schubert data->state = state;
129206b73d0SCy Schubert }
130206b73d0SCy Schubert
131206b73d0SCy Schubert
eap_teap_req_failure(struct eap_teap_data * data,enum teap_error_codes error)132c1d255d3SCy Schubert static enum eap_type eap_teap_req_failure(struct eap_teap_data *data,
133206b73d0SCy Schubert enum teap_error_codes error)
134206b73d0SCy Schubert {
135206b73d0SCy Schubert eap_teap_state(data, FAILURE_SEND_RESULT);
136206b73d0SCy Schubert return EAP_TYPE_NONE;
137206b73d0SCy Schubert }
138206b73d0SCy Schubert
139206b73d0SCy Schubert
eap_teap_session_ticket_cb(void * ctx,const u8 * ticket,size_t len,const u8 * client_random,const u8 * server_random,u8 * master_secret)140206b73d0SCy Schubert static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
141206b73d0SCy Schubert const u8 *client_random,
142206b73d0SCy Schubert const u8 *server_random,
143206b73d0SCy Schubert u8 *master_secret)
144206b73d0SCy Schubert {
145206b73d0SCy Schubert struct eap_teap_data *data = ctx;
146206b73d0SCy Schubert const u8 *pac_opaque;
147206b73d0SCy Schubert size_t pac_opaque_len;
148206b73d0SCy Schubert u8 *buf, *pos, *end, *pac_key = NULL;
149206b73d0SCy Schubert os_time_t lifetime = 0;
150206b73d0SCy Schubert struct os_time now;
151206b73d0SCy Schubert u8 *identity = NULL;
152206b73d0SCy Schubert size_t identity_len = 0;
153206b73d0SCy Schubert
154206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback");
155206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket (PAC-Opaque)",
156206b73d0SCy Schubert ticket, len);
157206b73d0SCy Schubert
158206b73d0SCy Schubert if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
159206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignore invalid SessionTicket");
160206b73d0SCy Schubert return 0;
161206b73d0SCy Schubert }
162206b73d0SCy Schubert
163206b73d0SCy Schubert pac_opaque_len = WPA_GET_BE16(ticket + 2);
164206b73d0SCy Schubert pac_opaque = ticket + 4;
165206b73d0SCy Schubert if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
166206b73d0SCy Schubert pac_opaque_len > len - 4) {
167206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
168206b73d0SCy Schubert "EAP-TEAP: Ignore invalid PAC-Opaque (len=%lu left=%lu)",
169206b73d0SCy Schubert (unsigned long) pac_opaque_len,
170206b73d0SCy Schubert (unsigned long) len);
171206b73d0SCy Schubert return 0;
172206b73d0SCy Schubert }
173206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Received PAC-Opaque",
174206b73d0SCy Schubert pac_opaque, pac_opaque_len);
175206b73d0SCy Schubert
176206b73d0SCy Schubert buf = os_malloc(pac_opaque_len - 8);
177206b73d0SCy Schubert if (!buf) {
178206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
179206b73d0SCy Schubert "EAP-TEAP: Failed to allocate memory for decrypting PAC-Opaque");
180206b73d0SCy Schubert return 0;
181206b73d0SCy Schubert }
182206b73d0SCy Schubert
183206b73d0SCy Schubert if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
184206b73d0SCy Schubert (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) {
185206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Failed to decrypt PAC-Opaque");
186206b73d0SCy Schubert os_free(buf);
187206b73d0SCy Schubert /*
188206b73d0SCy Schubert * This may have been caused by server changing the PAC-Opaque
189206b73d0SCy Schubert * encryption key, so just ignore this PAC-Opaque instead of
190206b73d0SCy Schubert * failing the authentication completely. Provisioning can now
191206b73d0SCy Schubert * be used to provision a new PAC.
192206b73d0SCy Schubert */
193206b73d0SCy Schubert return 0;
194206b73d0SCy Schubert }
195206b73d0SCy Schubert
196206b73d0SCy Schubert end = buf + pac_opaque_len - 8;
197206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Decrypted PAC-Opaque",
198206b73d0SCy Schubert buf, end - buf);
199206b73d0SCy Schubert
200206b73d0SCy Schubert pos = buf;
201206b73d0SCy Schubert while (end - pos > 1) {
202206b73d0SCy Schubert u8 id, elen;
203206b73d0SCy Schubert
204206b73d0SCy Schubert id = *pos++;
205206b73d0SCy Schubert elen = *pos++;
206206b73d0SCy Schubert if (elen > end - pos)
207206b73d0SCy Schubert break;
208206b73d0SCy Schubert
209206b73d0SCy Schubert switch (id) {
210206b73d0SCy Schubert case PAC_OPAQUE_TYPE_PAD:
211206b73d0SCy Schubert goto done;
212206b73d0SCy Schubert case PAC_OPAQUE_TYPE_KEY:
213206b73d0SCy Schubert if (elen != EAP_TEAP_PAC_KEY_LEN) {
214206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
215206b73d0SCy Schubert "EAP-TEAP: Invalid PAC-Key length %d",
216206b73d0SCy Schubert elen);
217206b73d0SCy Schubert os_free(buf);
218206b73d0SCy Schubert return -1;
219206b73d0SCy Schubert }
220206b73d0SCy Schubert pac_key = pos;
221206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG,
222206b73d0SCy Schubert "EAP-TEAP: PAC-Key from decrypted PAC-Opaque",
223206b73d0SCy Schubert pac_key, EAP_TEAP_PAC_KEY_LEN);
224206b73d0SCy Schubert break;
225206b73d0SCy Schubert case PAC_OPAQUE_TYPE_LIFETIME:
226206b73d0SCy Schubert if (elen != 4) {
227206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
228206b73d0SCy Schubert "EAP-TEAP: Invalid PAC-Key lifetime length %d",
229206b73d0SCy Schubert elen);
230206b73d0SCy Schubert os_free(buf);
231206b73d0SCy Schubert return -1;
232206b73d0SCy Schubert }
233206b73d0SCy Schubert lifetime = WPA_GET_BE32(pos);
234206b73d0SCy Schubert break;
235206b73d0SCy Schubert case PAC_OPAQUE_TYPE_IDENTITY:
236206b73d0SCy Schubert identity = pos;
237206b73d0SCy Schubert identity_len = elen;
238206b73d0SCy Schubert break;
239206b73d0SCy Schubert }
240206b73d0SCy Schubert
241206b73d0SCy Schubert pos += elen;
242206b73d0SCy Schubert }
243206b73d0SCy Schubert done:
244206b73d0SCy Schubert
245206b73d0SCy Schubert if (!pac_key) {
246206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
247206b73d0SCy Schubert "EAP-TEAP: No PAC-Key included in PAC-Opaque");
248206b73d0SCy Schubert os_free(buf);
249206b73d0SCy Schubert return -1;
250206b73d0SCy Schubert }
251206b73d0SCy Schubert
252206b73d0SCy Schubert if (identity) {
253206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG,
254206b73d0SCy Schubert "EAP-TEAP: Identity from PAC-Opaque",
255206b73d0SCy Schubert identity, identity_len);
256206b73d0SCy Schubert os_free(data->identity);
257206b73d0SCy Schubert data->identity = os_malloc(identity_len);
258206b73d0SCy Schubert if (data->identity) {
259206b73d0SCy Schubert os_memcpy(data->identity, identity, identity_len);
260206b73d0SCy Schubert data->identity_len = identity_len;
261206b73d0SCy Schubert }
262206b73d0SCy Schubert }
263206b73d0SCy Schubert
264206b73d0SCy Schubert if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
265206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
266206b73d0SCy Schubert "EAP-TEAP: PAC-Key not valid anymore (lifetime=%ld now=%ld)",
267206b73d0SCy Schubert lifetime, now.sec);
268206b73d0SCy Schubert data->send_new_pac = 2;
269206b73d0SCy Schubert /*
270206b73d0SCy Schubert * Allow PAC to be used to allow a PAC update with some level
271206b73d0SCy Schubert * of server authentication (i.e., do not fall back to full TLS
272206b73d0SCy Schubert * handshake since we cannot be sure that the peer would be
273206b73d0SCy Schubert * able to validate server certificate now). However, reject
274206b73d0SCy Schubert * the authentication since the PAC was not valid anymore. Peer
275206b73d0SCy Schubert * can connect again with the newly provisioned PAC after this.
276206b73d0SCy Schubert */
277206b73d0SCy Schubert } else if (lifetime - now.sec < data->pac_key_refresh_time) {
278206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
279206b73d0SCy Schubert "EAP-TEAP: PAC-Key soft timeout; send an update if authentication succeeds");
280206b73d0SCy Schubert data->send_new_pac = 1;
281206b73d0SCy Schubert }
282206b73d0SCy Schubert
283206b73d0SCy Schubert /* EAP-TEAP uses PAC-Key as the TLS master_secret */
284206b73d0SCy Schubert os_memcpy(master_secret, pac_key, EAP_TEAP_PAC_KEY_LEN);
285206b73d0SCy Schubert
286206b73d0SCy Schubert os_free(buf);
287206b73d0SCy Schubert
288206b73d0SCy Schubert return 1;
289206b73d0SCy Schubert }
290206b73d0SCy Schubert
291206b73d0SCy Schubert
eap_teap_derive_key_auth(struct eap_sm * sm,struct eap_teap_data * data)292206b73d0SCy Schubert static int eap_teap_derive_key_auth(struct eap_sm *sm,
293206b73d0SCy Schubert struct eap_teap_data *data)
294206b73d0SCy Schubert {
295206b73d0SCy Schubert int res;
296206b73d0SCy Schubert
297206b73d0SCy Schubert /* RFC 7170, Section 5.1 */
298c1d255d3SCy Schubert res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn,
299206b73d0SCy Schubert TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
300206b73d0SCy Schubert data->simck_msk, EAP_TEAP_SIMCK_LEN);
301206b73d0SCy Schubert if (res)
302206b73d0SCy Schubert return res;
303206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG,
304206b73d0SCy Schubert "EAP-TEAP: session_key_seed (S-IMCK[0])",
305206b73d0SCy Schubert data->simck_msk, EAP_TEAP_SIMCK_LEN);
306206b73d0SCy Schubert os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN);
307206b73d0SCy Schubert data->simck_idx = 0;
308206b73d0SCy Schubert return 0;
309206b73d0SCy Schubert }
310206b73d0SCy Schubert
311206b73d0SCy Schubert
eap_teap_update_icmk(struct eap_sm * sm,struct eap_teap_data * data)312206b73d0SCy Schubert static int eap_teap_update_icmk(struct eap_sm *sm, struct eap_teap_data *data)
313206b73d0SCy Schubert {
314206b73d0SCy Schubert u8 *msk = NULL, *emsk = NULL;
315206b73d0SCy Schubert size_t msk_len = 0, emsk_len = 0;
316206b73d0SCy Schubert int res;
317206b73d0SCy Schubert
318206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Deriving ICMK[%d] (S-IMCK and CMK)",
319206b73d0SCy Schubert data->simck_idx + 1);
320206b73d0SCy Schubert
321c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1)
322c1d255d3SCy Schubert return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
323c1d255d3SCy Schubert data->simck_msk,
324206b73d0SCy Schubert data->cmk_msk);
325206b73d0SCy Schubert
326206b73d0SCy Schubert if (!data->phase2_method || !data->phase2_priv) {
327206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available");
328206b73d0SCy Schubert return -1;
329206b73d0SCy Schubert }
330206b73d0SCy Schubert
331206b73d0SCy Schubert if (data->phase2_method->getKey) {
332206b73d0SCy Schubert msk = data->phase2_method->getKey(sm, data->phase2_priv,
333206b73d0SCy Schubert &msk_len);
334206b73d0SCy Schubert if (!msk) {
335206b73d0SCy Schubert wpa_printf(MSG_INFO,
336206b73d0SCy Schubert "EAP-TEAP: Could not fetch Phase 2 MSK");
337206b73d0SCy Schubert return -1;
338206b73d0SCy Schubert }
339206b73d0SCy Schubert }
340206b73d0SCy Schubert
341206b73d0SCy Schubert if (data->phase2_method->get_emsk) {
342206b73d0SCy Schubert emsk = data->phase2_method->get_emsk(sm, data->phase2_priv,
343206b73d0SCy Schubert &emsk_len);
344206b73d0SCy Schubert }
345206b73d0SCy Schubert
346c1d255d3SCy Schubert res = eap_teap_derive_imck(data->tls_cs,
347c1d255d3SCy Schubert data->simck_msk, data->simck_emsk,
348206b73d0SCy Schubert msk, msk_len, emsk, emsk_len,
349206b73d0SCy Schubert data->simck_msk, data->cmk_msk,
350206b73d0SCy Schubert data->simck_emsk, data->cmk_emsk);
351206b73d0SCy Schubert bin_clear_free(msk, msk_len);
352206b73d0SCy Schubert bin_clear_free(emsk, emsk_len);
353206b73d0SCy Schubert if (res == 0) {
354206b73d0SCy Schubert data->simck_idx++;
355206b73d0SCy Schubert if (emsk)
356206b73d0SCy Schubert data->cmk_emsk_available = 1;
357206b73d0SCy Schubert }
358206b73d0SCy Schubert return 0;
359206b73d0SCy Schubert }
360206b73d0SCy Schubert
361206b73d0SCy Schubert
eap_teap_init(struct eap_sm * sm)362206b73d0SCy Schubert static void * eap_teap_init(struct eap_sm *sm)
363206b73d0SCy Schubert {
364206b73d0SCy Schubert struct eap_teap_data *data;
365206b73d0SCy Schubert
366206b73d0SCy Schubert data = os_zalloc(sizeof(*data));
367206b73d0SCy Schubert if (!data)
368206b73d0SCy Schubert return NULL;
369206b73d0SCy Schubert data->teap_version = EAP_TEAP_VERSION;
370206b73d0SCy Schubert data->state = START;
371206b73d0SCy Schubert
372c1d255d3SCy Schubert if (eap_server_tls_ssl_init(sm, &data->ssl,
373c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 2 ? 2 : 0,
374c1d255d3SCy Schubert EAP_TYPE_TEAP)) {
375206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL.");
376206b73d0SCy Schubert eap_teap_reset(sm, data);
377206b73d0SCy Schubert return NULL;
378206b73d0SCy Schubert }
379206b73d0SCy Schubert
380206b73d0SCy Schubert /* TODO: Add anon-DH TLS cipher suites (and if one is negotiated,
381206b73d0SCy Schubert * enforce inner EAP with mutual authentication to be used) */
382206b73d0SCy Schubert
383c1d255d3SCy Schubert if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
384c1d255d3SCy Schubert data->ssl.conn,
385206b73d0SCy Schubert eap_teap_session_ticket_cb,
386206b73d0SCy Schubert data) < 0) {
387206b73d0SCy Schubert wpa_printf(MSG_INFO,
388206b73d0SCy Schubert "EAP-TEAP: Failed to set SessionTicket callback");
389206b73d0SCy Schubert eap_teap_reset(sm, data);
390206b73d0SCy Schubert return NULL;
391206b73d0SCy Schubert }
392206b73d0SCy Schubert
393c1d255d3SCy Schubert if (!sm->cfg->pac_opaque_encr_key) {
394206b73d0SCy Schubert wpa_printf(MSG_INFO,
395206b73d0SCy Schubert "EAP-TEAP: No PAC-Opaque encryption key configured");
396206b73d0SCy Schubert eap_teap_reset(sm, data);
397206b73d0SCy Schubert return NULL;
398206b73d0SCy Schubert }
399c1d255d3SCy Schubert os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
400206b73d0SCy Schubert sizeof(data->pac_opaque_encr));
401206b73d0SCy Schubert
402c1d255d3SCy Schubert if (!sm->cfg->eap_fast_a_id) {
403206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured");
404206b73d0SCy Schubert eap_teap_reset(sm, data);
405206b73d0SCy Schubert return NULL;
406206b73d0SCy Schubert }
407c1d255d3SCy Schubert data->srv_id = os_malloc(sm->cfg->eap_fast_a_id_len);
408206b73d0SCy Schubert if (!data->srv_id) {
409206b73d0SCy Schubert eap_teap_reset(sm, data);
410206b73d0SCy Schubert return NULL;
411206b73d0SCy Schubert }
412c1d255d3SCy Schubert os_memcpy(data->srv_id, sm->cfg->eap_fast_a_id,
413c1d255d3SCy Schubert sm->cfg->eap_fast_a_id_len);
414c1d255d3SCy Schubert data->srv_id_len = sm->cfg->eap_fast_a_id_len;
415206b73d0SCy Schubert
416c1d255d3SCy Schubert if (!sm->cfg->eap_fast_a_id_info) {
417206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID-Info configured");
418206b73d0SCy Schubert eap_teap_reset(sm, data);
419206b73d0SCy Schubert return NULL;
420206b73d0SCy Schubert }
421c1d255d3SCy Schubert data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
422206b73d0SCy Schubert if (!data->srv_id_info) {
423206b73d0SCy Schubert eap_teap_reset(sm, data);
424206b73d0SCy Schubert return NULL;
425206b73d0SCy Schubert }
426206b73d0SCy Schubert
427206b73d0SCy Schubert /* PAC-Key lifetime in seconds (hard limit) */
428c1d255d3SCy Schubert data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
429206b73d0SCy Schubert
430206b73d0SCy Schubert /*
431206b73d0SCy Schubert * PAC-Key refresh time in seconds (soft limit on remaining hard
432206b73d0SCy Schubert * limit). The server will generate a new PAC-Key when this number of
433206b73d0SCy Schubert * seconds (or fewer) of the lifetime remains.
434206b73d0SCy Schubert */
435c1d255d3SCy Schubert data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
436206b73d0SCy Schubert
437206b73d0SCy Schubert return data;
438206b73d0SCy Schubert }
439206b73d0SCy Schubert
440206b73d0SCy Schubert
eap_teap_reset(struct eap_sm * sm,void * priv)441206b73d0SCy Schubert static void eap_teap_reset(struct eap_sm *sm, void *priv)
442206b73d0SCy Schubert {
443206b73d0SCy Schubert struct eap_teap_data *data = priv;
444206b73d0SCy Schubert
445206b73d0SCy Schubert if (!data)
446206b73d0SCy Schubert return;
447206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method)
448206b73d0SCy Schubert data->phase2_method->reset(sm, data->phase2_priv);
449206b73d0SCy Schubert eap_server_tls_ssl_deinit(sm, &data->ssl);
450206b73d0SCy Schubert os_free(data->srv_id);
451206b73d0SCy Schubert os_free(data->srv_id_info);
452206b73d0SCy Schubert wpabuf_free(data->pending_phase2_resp);
453206b73d0SCy Schubert wpabuf_free(data->server_outer_tlvs);
454206b73d0SCy Schubert wpabuf_free(data->peer_outer_tlvs);
455206b73d0SCy Schubert os_free(data->identity);
456206b73d0SCy Schubert forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN);
457206b73d0SCy Schubert forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN);
458206b73d0SCy Schubert forced_memzero(data->cmk_msk, EAP_TEAP_CMK_LEN);
459206b73d0SCy Schubert forced_memzero(data->cmk_emsk, EAP_TEAP_CMK_LEN);
460206b73d0SCy Schubert forced_memzero(data->pac_opaque_encr, sizeof(data->pac_opaque_encr));
461206b73d0SCy Schubert bin_clear_free(data, sizeof(*data));
462206b73d0SCy Schubert }
463206b73d0SCy Schubert
464206b73d0SCy Schubert
eap_teap_build_start(struct eap_sm * sm,struct eap_teap_data * data,u8 id)465206b73d0SCy Schubert static struct wpabuf * eap_teap_build_start(struct eap_sm *sm,
466206b73d0SCy Schubert struct eap_teap_data *data, u8 id)
467206b73d0SCy Schubert {
468206b73d0SCy Schubert struct wpabuf *req;
469206b73d0SCy Schubert size_t outer_tlv_len = sizeof(struct teap_tlv_hdr) + data->srv_id_len;
470206b73d0SCy Schubert const u8 *start, *end;
471206b73d0SCy Schubert
472206b73d0SCy Schubert req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TEAP,
473206b73d0SCy Schubert 1 + 4 + outer_tlv_len, EAP_CODE_REQUEST, id);
474206b73d0SCy Schubert if (!req) {
475206b73d0SCy Schubert wpa_printf(MSG_ERROR,
476206b73d0SCy Schubert "EAP-TEAP: Failed to allocate memory for request");
477206b73d0SCy Schubert eap_teap_state(data, FAILURE);
478206b73d0SCy Schubert return NULL;
479206b73d0SCy Schubert }
480206b73d0SCy Schubert
481206b73d0SCy Schubert wpabuf_put_u8(req, EAP_TLS_FLAGS_START | EAP_TEAP_FLAGS_OUTER_TLV_LEN |
482206b73d0SCy Schubert data->teap_version);
483206b73d0SCy Schubert wpabuf_put_be32(req, outer_tlv_len);
484206b73d0SCy Schubert
485206b73d0SCy Schubert start = wpabuf_put(req, 0);
486206b73d0SCy Schubert
487206b73d0SCy Schubert /* RFC 7170, Section 4.2.2: Authority-ID TLV */
488206b73d0SCy Schubert eap_teap_put_tlv(req, TEAP_TLV_AUTHORITY_ID,
489206b73d0SCy Schubert data->srv_id, data->srv_id_len);
490206b73d0SCy Schubert
491206b73d0SCy Schubert end = wpabuf_put(req, 0);
492206b73d0SCy Schubert wpabuf_free(data->server_outer_tlvs);
493206b73d0SCy Schubert data->server_outer_tlvs = wpabuf_alloc_copy(start, end - start);
494206b73d0SCy Schubert if (!data->server_outer_tlvs) {
495206b73d0SCy Schubert eap_teap_state(data, FAILURE);
496206b73d0SCy Schubert return NULL;
497206b73d0SCy Schubert }
498206b73d0SCy Schubert
499206b73d0SCy Schubert eap_teap_state(data, PHASE1);
500206b73d0SCy Schubert
501206b73d0SCy Schubert return req;
502206b73d0SCy Schubert }
503206b73d0SCy Schubert
504206b73d0SCy Schubert
eap_teap_phase1_done(struct eap_sm * sm,struct eap_teap_data * data)505206b73d0SCy Schubert static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data)
506206b73d0SCy Schubert {
507206b73d0SCy Schubert char cipher[64];
508206b73d0SCy Schubert
509206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2");
510206b73d0SCy Schubert
511c1d255d3SCy Schubert if (!data->identity && sm->cfg->eap_teap_auth == 2) {
512c1d255d3SCy Schubert const char *subject;
513c1d255d3SCy Schubert
514c1d255d3SCy Schubert subject = tls_connection_get_peer_subject(data->ssl.conn);
515c1d255d3SCy Schubert if (subject) {
516c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
517c1d255d3SCy Schubert "EAP-TEAP: Peer subject from Phase 1 client certificate: '%s'",
518c1d255d3SCy Schubert subject);
519c1d255d3SCy Schubert data->identity = (u8 *) os_strdup(subject);
520c1d255d3SCy Schubert data->identity_len = os_strlen(subject);
521c1d255d3SCy Schubert }
522c1d255d3SCy Schubert }
523c1d255d3SCy Schubert
524206b73d0SCy Schubert data->tls_cs = tls_connection_get_cipher_suite(data->ssl.conn);
525206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
526206b73d0SCy Schubert data->tls_cs);
527206b73d0SCy Schubert
528c1d255d3SCy Schubert if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
529c1d255d3SCy Schubert cipher, sizeof(cipher)) < 0) {
530206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
531206b73d0SCy Schubert "EAP-TEAP: Failed to get cipher information");
532206b73d0SCy Schubert eap_teap_state(data, FAILURE);
533206b73d0SCy Schubert return -1;
534206b73d0SCy Schubert }
535206b73d0SCy Schubert data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
536206b73d0SCy Schubert
537206b73d0SCy Schubert if (data->anon_provisioning)
538206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Anonymous provisioning");
539206b73d0SCy Schubert
540206b73d0SCy Schubert if (eap_teap_derive_key_auth(sm, data) < 0) {
541206b73d0SCy Schubert eap_teap_state(data, FAILURE);
542206b73d0SCy Schubert return -1;
543206b73d0SCy Schubert }
544206b73d0SCy Schubert
545206b73d0SCy Schubert eap_teap_state(data, PHASE2_START);
546206b73d0SCy Schubert
547206b73d0SCy Schubert return 0;
548206b73d0SCy Schubert }
549206b73d0SCy Schubert
550206b73d0SCy Schubert
eap_teap_build_phase2_req(struct eap_sm * sm,struct eap_teap_data * data,u8 id)551206b73d0SCy Schubert static struct wpabuf * eap_teap_build_phase2_req(struct eap_sm *sm,
552206b73d0SCy Schubert struct eap_teap_data *data,
553206b73d0SCy Schubert u8 id)
554206b73d0SCy Schubert {
555c1d255d3SCy Schubert struct wpabuf *req, *id_tlv = NULL;
556206b73d0SCy Schubert
557c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1 ||
558c1d255d3SCy Schubert (data->phase2_priv && data->phase2_method &&
559c1d255d3SCy Schubert data->phase2_method->vendor == EAP_VENDOR_IETF &&
560c1d255d3SCy Schubert data->phase2_method->method == EAP_TYPE_IDENTITY)) {
561c1d255d3SCy Schubert switch (sm->cfg->eap_teap_id) {
562c1d255d3SCy Schubert case EAP_TEAP_ID_ALLOW_ANY:
563c1d255d3SCy Schubert break;
564c1d255d3SCy Schubert case EAP_TEAP_ID_REQUIRE_USER:
565c1d255d3SCy Schubert case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE:
566c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
567c1d255d3SCy Schubert id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
568c1d255d3SCy Schubert break;
569c1d255d3SCy Schubert case EAP_TEAP_ID_REQUIRE_MACHINE:
570c1d255d3SCy Schubert case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER:
571c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
572c1d255d3SCy Schubert id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
573c1d255d3SCy Schubert break;
574c1d255d3SCy Schubert case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE:
575c1d255d3SCy Schubert if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER)
576c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
577c1d255d3SCy Schubert else
578c1d255d3SCy Schubert data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
579c1d255d3SCy Schubert id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
580c1d255d3SCy Schubert break;
581c1d255d3SCy Schubert }
582c1d255d3SCy Schubert }
583c1d255d3SCy Schubert
584c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1) {
585206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth");
586c1d255d3SCy Schubert data->basic_auth_not_done = 1;
587206b73d0SCy Schubert req = wpabuf_alloc(sizeof(struct teap_tlv_hdr));
588c1d255d3SCy Schubert if (!req) {
589c1d255d3SCy Schubert wpabuf_free(id_tlv);
590206b73d0SCy Schubert return NULL;
591c1d255d3SCy Schubert }
592206b73d0SCy Schubert eap_teap_put_tlv_hdr(req, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ, 0);
593c1d255d3SCy Schubert return wpabuf_concat(req, id_tlv);
594206b73d0SCy Schubert }
595206b73d0SCy Schubert
596206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method");
597c1d255d3SCy Schubert data->inner_eap_not_done = 1;
598206b73d0SCy Schubert if (!data->phase2_priv) {
599206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
600206b73d0SCy Schubert "EAP-TEAP: Phase 2 method not initialized");
601c1d255d3SCy Schubert wpabuf_free(id_tlv);
602206b73d0SCy Schubert return NULL;
603206b73d0SCy Schubert }
604206b73d0SCy Schubert
605206b73d0SCy Schubert req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
606c1d255d3SCy Schubert if (!req) {
607c1d255d3SCy Schubert wpabuf_free(id_tlv);
608206b73d0SCy Schubert return NULL;
609c1d255d3SCy Schubert }
610206b73d0SCy Schubert
611206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-TEAP: Phase 2 EAP-Request", req);
612c1d255d3SCy Schubert
613c1d255d3SCy Schubert return wpabuf_concat(eap_teap_tlv_eap_payload(req), id_tlv);
614206b73d0SCy Schubert }
615206b73d0SCy Schubert
616206b73d0SCy Schubert
eap_teap_build_crypto_binding(struct eap_sm * sm,struct eap_teap_data * data)617206b73d0SCy Schubert static struct wpabuf * eap_teap_build_crypto_binding(
618206b73d0SCy Schubert struct eap_sm *sm, struct eap_teap_data *data)
619206b73d0SCy Schubert {
620206b73d0SCy Schubert struct wpabuf *buf;
621206b73d0SCy Schubert struct teap_tlv_result *result;
622206b73d0SCy Schubert struct teap_tlv_crypto_binding *cb;
623206b73d0SCy Schubert u8 subtype, flags;
624206b73d0SCy Schubert
625206b73d0SCy Schubert buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*cb));
626206b73d0SCy Schubert if (!buf)
627206b73d0SCy Schubert return NULL;
628206b73d0SCy Schubert
629206b73d0SCy Schubert if (data->send_new_pac || data->anon_provisioning ||
630c1d255d3SCy Schubert data->basic_auth_not_done || data->inner_eap_not_done ||
631c1d255d3SCy Schubert data->phase2_method || sm->cfg->eap_teap_separate_result)
632206b73d0SCy Schubert data->final_result = 0;
633206b73d0SCy Schubert else
634206b73d0SCy Schubert data->final_result = 1;
635206b73d0SCy Schubert
636c1d255d3SCy Schubert if (!data->final_result || data->eap_seq > 0 ||
637c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 1) {
638206b73d0SCy Schubert /* Intermediate-Result */
639206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
640206b73d0SCy Schubert "EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)");
641206b73d0SCy Schubert result = wpabuf_put(buf, sizeof(*result));
642206b73d0SCy Schubert result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
643206b73d0SCy Schubert TEAP_TLV_INTERMEDIATE_RESULT);
644206b73d0SCy Schubert result->length = host_to_be16(2);
645206b73d0SCy Schubert result->status = host_to_be16(TEAP_STATUS_SUCCESS);
646206b73d0SCy Schubert }
647206b73d0SCy Schubert
648206b73d0SCy Schubert if (data->final_result) {
649206b73d0SCy Schubert /* Result TLV */
650206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
651206b73d0SCy Schubert "EAP-TEAP: Add Result TLV (status=SUCCESS)");
652206b73d0SCy Schubert result = wpabuf_put(buf, sizeof(*result));
653206b73d0SCy Schubert result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
654206b73d0SCy Schubert TEAP_TLV_RESULT);
655206b73d0SCy Schubert result->length = host_to_be16(2);
656206b73d0SCy Schubert result->status = host_to_be16(TEAP_STATUS_SUCCESS);
657206b73d0SCy Schubert }
658206b73d0SCy Schubert
659206b73d0SCy Schubert /* Crypto-Binding TLV */
660206b73d0SCy Schubert cb = wpabuf_put(buf, sizeof(*cb));
661206b73d0SCy Schubert cb->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
662206b73d0SCy Schubert TEAP_TLV_CRYPTO_BINDING);
663206b73d0SCy Schubert cb->length = host_to_be16(sizeof(*cb) - sizeof(struct teap_tlv_hdr));
664206b73d0SCy Schubert cb->version = EAP_TEAP_VERSION;
665206b73d0SCy Schubert cb->received_version = data->peer_version;
666206b73d0SCy Schubert /* FIX: RFC 7170 is not clear on which Flags value to use when
667206b73d0SCy Schubert * Crypto-Binding TLV is used with Basic-Password-Auth */
668206b73d0SCy Schubert flags = data->cmk_emsk_available ?
669206b73d0SCy Schubert TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC :
670206b73d0SCy Schubert TEAP_CRYPTO_BINDING_MSK_CMAC;
671206b73d0SCy Schubert subtype = TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST;
672206b73d0SCy Schubert cb->subtype = (flags << 4) | subtype;
673206b73d0SCy Schubert if (random_get_bytes(cb->nonce, sizeof(cb->nonce)) < 0) {
674206b73d0SCy Schubert wpabuf_free(buf);
675206b73d0SCy Schubert return NULL;
676206b73d0SCy Schubert }
677206b73d0SCy Schubert
678206b73d0SCy Schubert /*
679206b73d0SCy Schubert * RFC 7170, Section 4.2.13:
680206b73d0SCy Schubert * The nonce in a request MUST have its least significant bit set to 0.
681206b73d0SCy Schubert */
682206b73d0SCy Schubert cb->nonce[sizeof(cb->nonce) - 1] &= ~0x01;
683206b73d0SCy Schubert
684206b73d0SCy Schubert os_memcpy(data->crypto_binding_nonce, cb->nonce, sizeof(cb->nonce));
685206b73d0SCy Schubert
686206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb, data->server_outer_tlvs,
687206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_msk,
688206b73d0SCy Schubert cb->msk_compound_mac) < 0) {
689206b73d0SCy Schubert wpabuf_free(buf);
690206b73d0SCy Schubert return NULL;
691206b73d0SCy Schubert }
692206b73d0SCy Schubert
693206b73d0SCy Schubert if (data->cmk_emsk_available &&
694206b73d0SCy Schubert eap_teap_compound_mac(data->tls_cs, cb, data->server_outer_tlvs,
695206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_emsk,
696206b73d0SCy Schubert cb->emsk_compound_mac) < 0) {
697206b73d0SCy Schubert wpabuf_free(buf);
698206b73d0SCy Schubert return NULL;
699206b73d0SCy Schubert }
700206b73d0SCy Schubert
701206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
702206b73d0SCy Schubert "EAP-TEAP: Add Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
703206b73d0SCy Schubert cb->version, cb->received_version, flags, subtype);
704206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
705206b73d0SCy Schubert cb->nonce, sizeof(cb->nonce));
706206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
707206b73d0SCy Schubert cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac));
708206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
709206b73d0SCy Schubert cb->msk_compound_mac, sizeof(cb->msk_compound_mac));
710206b73d0SCy Schubert
711*a90b9d01SCy Schubert data->check_crypto_binding = true;
712*a90b9d01SCy Schubert
713206b73d0SCy Schubert return buf;
714206b73d0SCy Schubert }
715206b73d0SCy Schubert
716206b73d0SCy Schubert
eap_teap_build_pac(struct eap_sm * sm,struct eap_teap_data * data)717206b73d0SCy Schubert static struct wpabuf * eap_teap_build_pac(struct eap_sm *sm,
718206b73d0SCy Schubert struct eap_teap_data *data)
719206b73d0SCy Schubert {
720206b73d0SCy Schubert u8 pac_key[EAP_TEAP_PAC_KEY_LEN];
721206b73d0SCy Schubert u8 *pac_buf, *pac_opaque;
722206b73d0SCy Schubert struct wpabuf *buf;
723206b73d0SCy Schubert u8 *pos;
724206b73d0SCy Schubert size_t buf_len, srv_id_info_len, pac_len;
725206b73d0SCy Schubert struct teap_tlv_hdr *pac_tlv;
726206b73d0SCy Schubert struct pac_attr_hdr *pac_info;
727206b73d0SCy Schubert struct teap_tlv_result *result;
728206b73d0SCy Schubert struct os_time now;
729206b73d0SCy Schubert
730206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Build a new PAC");
731206b73d0SCy Schubert
732206b73d0SCy Schubert if (random_get_bytes(pac_key, EAP_TEAP_PAC_KEY_LEN) < 0 ||
733206b73d0SCy Schubert os_get_time(&now) < 0)
734206b73d0SCy Schubert return NULL;
735206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Generated PAC-Key",
736206b73d0SCy Schubert pac_key, EAP_TEAP_PAC_KEY_LEN);
737206b73d0SCy Schubert
738206b73d0SCy Schubert pac_len = (2 + EAP_TEAP_PAC_KEY_LEN) + (2 + 4) +
739206b73d0SCy Schubert (2 + sm->identity_len) + 8;
740206b73d0SCy Schubert pac_buf = os_malloc(pac_len);
741206b73d0SCy Schubert if (!pac_buf)
742206b73d0SCy Schubert return NULL;
743206b73d0SCy Schubert
744206b73d0SCy Schubert srv_id_info_len = os_strlen(data->srv_id_info);
745206b73d0SCy Schubert
746206b73d0SCy Schubert pos = pac_buf;
747206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_KEY;
748206b73d0SCy Schubert *pos++ = EAP_TEAP_PAC_KEY_LEN;
749206b73d0SCy Schubert os_memcpy(pos, pac_key, EAP_TEAP_PAC_KEY_LEN);
750206b73d0SCy Schubert pos += EAP_TEAP_PAC_KEY_LEN;
751206b73d0SCy Schubert
752206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Key lifetime: %u seconds",
753206b73d0SCy Schubert data->pac_key_lifetime);
754206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_LIFETIME;
755206b73d0SCy Schubert *pos++ = 4;
756206b73d0SCy Schubert WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime);
757206b73d0SCy Schubert pos += 4;
758206b73d0SCy Schubert
759206b73d0SCy Schubert if (sm->identity) {
760206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Opaque Identity",
761206b73d0SCy Schubert sm->identity, sm->identity_len);
762206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_IDENTITY;
763206b73d0SCy Schubert *pos++ = sm->identity_len;
764206b73d0SCy Schubert os_memcpy(pos, sm->identity, sm->identity_len);
765206b73d0SCy Schubert pos += sm->identity_len;
766206b73d0SCy Schubert }
767206b73d0SCy Schubert
768206b73d0SCy Schubert pac_len = pos - pac_buf;
769206b73d0SCy Schubert while (pac_len % 8) {
770206b73d0SCy Schubert *pos++ = PAC_OPAQUE_TYPE_PAD;
771206b73d0SCy Schubert pac_len++;
772206b73d0SCy Schubert }
773206b73d0SCy Schubert
774206b73d0SCy Schubert pac_opaque = os_malloc(pac_len + 8);
775206b73d0SCy Schubert if (!pac_opaque) {
776206b73d0SCy Schubert os_free(pac_buf);
777206b73d0SCy Schubert return NULL;
778206b73d0SCy Schubert }
779206b73d0SCy Schubert if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
780206b73d0SCy Schubert pac_len / 8, pac_buf, pac_opaque) < 0) {
781206b73d0SCy Schubert os_free(pac_buf);
782206b73d0SCy Schubert os_free(pac_opaque);
783206b73d0SCy Schubert return NULL;
784206b73d0SCy Schubert }
785206b73d0SCy Schubert os_free(pac_buf);
786206b73d0SCy Schubert
787206b73d0SCy Schubert pac_len += 8;
788206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pac_opaque, pac_len);
789206b73d0SCy Schubert
790206b73d0SCy Schubert buf_len = sizeof(*pac_tlv) +
791206b73d0SCy Schubert sizeof(struct pac_attr_hdr) + EAP_TEAP_PAC_KEY_LEN +
792206b73d0SCy Schubert sizeof(struct pac_attr_hdr) + pac_len +
793206b73d0SCy Schubert data->srv_id_len + srv_id_info_len + 100 + sizeof(*result);
794206b73d0SCy Schubert buf = wpabuf_alloc(buf_len);
795206b73d0SCy Schubert if (!buf) {
796206b73d0SCy Schubert os_free(pac_opaque);
797206b73d0SCy Schubert return NULL;
798206b73d0SCy Schubert }
799206b73d0SCy Schubert
800206b73d0SCy Schubert /* Result TLV */
801206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Result TLV (status=SUCCESS)");
802206b73d0SCy Schubert result = wpabuf_put(buf, sizeof(*result));
803206b73d0SCy Schubert WPA_PUT_BE16((u8 *) &result->tlv_type,
804206b73d0SCy Schubert TEAP_TLV_MANDATORY | TEAP_TLV_RESULT);
805206b73d0SCy Schubert WPA_PUT_BE16((u8 *) &result->length, 2);
806206b73d0SCy Schubert WPA_PUT_BE16((u8 *) &result->status, TEAP_STATUS_SUCCESS);
807206b73d0SCy Schubert
808206b73d0SCy Schubert /* PAC TLV */
809206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV");
810206b73d0SCy Schubert pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv));
811206b73d0SCy Schubert pac_tlv->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_PAC);
812206b73d0SCy Schubert
813206b73d0SCy Schubert /* PAC-Key */
814206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_TEAP_PAC_KEY_LEN);
815206b73d0SCy Schubert
816206b73d0SCy Schubert /* PAC-Opaque */
817206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
818206b73d0SCy Schubert os_free(pac_opaque);
819206b73d0SCy Schubert
820206b73d0SCy Schubert /* PAC-Info */
821206b73d0SCy Schubert pac_info = wpabuf_put(buf, sizeof(*pac_info));
822206b73d0SCy Schubert pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
823206b73d0SCy Schubert
824206b73d0SCy Schubert /* PAC-Lifetime (inside PAC-Info) */
825206b73d0SCy Schubert eap_teap_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
826206b73d0SCy Schubert wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime);
827206b73d0SCy Schubert
828206b73d0SCy Schubert /* A-ID (inside PAC-Info) */
829206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
830206b73d0SCy Schubert
831206b73d0SCy Schubert /* Note: headers may be misaligned after A-ID */
832206b73d0SCy Schubert
833206b73d0SCy Schubert if (sm->identity) {
834206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_I_ID, sm->identity,
835206b73d0SCy Schubert sm->identity_len);
836206b73d0SCy Schubert }
837206b73d0SCy Schubert
838206b73d0SCy Schubert /* A-ID-Info (inside PAC-Info) */
839206b73d0SCy Schubert eap_teap_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info,
840206b73d0SCy Schubert srv_id_info_len);
841206b73d0SCy Schubert
842206b73d0SCy Schubert /* PAC-Type (inside PAC-Info) */
843206b73d0SCy Schubert eap_teap_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
844206b73d0SCy Schubert wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
845206b73d0SCy Schubert
846206b73d0SCy Schubert /* Update PAC-Info and PAC TLV Length fields */
847206b73d0SCy Schubert pos = wpabuf_put(buf, 0);
848206b73d0SCy Schubert pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
849206b73d0SCy Schubert pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
850206b73d0SCy Schubert
851206b73d0SCy Schubert return buf;
852206b73d0SCy Schubert }
853206b73d0SCy Schubert
854206b73d0SCy Schubert
eap_teap_encrypt_phase2(struct eap_sm * sm,struct eap_teap_data * data,struct wpabuf * plain,int piggyback)855206b73d0SCy Schubert static int eap_teap_encrypt_phase2(struct eap_sm *sm,
856206b73d0SCy Schubert struct eap_teap_data *data,
857206b73d0SCy Schubert struct wpabuf *plain, int piggyback)
858206b73d0SCy Schubert {
859206b73d0SCy Schubert struct wpabuf *encr;
860206b73d0SCy Schubert
861206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Encrypting Phase 2 TLVs",
862206b73d0SCy Schubert plain);
863206b73d0SCy Schubert encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
864206b73d0SCy Schubert wpabuf_free(plain);
865206b73d0SCy Schubert
866206b73d0SCy Schubert if (!encr)
867206b73d0SCy Schubert return -1;
868206b73d0SCy Schubert
869206b73d0SCy Schubert if (data->ssl.tls_out && piggyback) {
870206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
871206b73d0SCy Schubert "EAP-TEAP: Piggyback Phase 2 data (len=%d) with last Phase 1 Message (len=%d used=%d)",
872206b73d0SCy Schubert (int) wpabuf_len(encr),
873206b73d0SCy Schubert (int) wpabuf_len(data->ssl.tls_out),
874206b73d0SCy Schubert (int) data->ssl.tls_out_pos);
875206b73d0SCy Schubert if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
876206b73d0SCy Schubert wpa_printf(MSG_WARNING,
877206b73d0SCy Schubert "EAP-TEAP: Failed to resize output buffer");
878206b73d0SCy Schubert wpabuf_free(encr);
879206b73d0SCy Schubert return -1;
880206b73d0SCy Schubert }
881206b73d0SCy Schubert wpabuf_put_buf(data->ssl.tls_out, encr);
882206b73d0SCy Schubert wpabuf_free(encr);
883206b73d0SCy Schubert } else {
884206b73d0SCy Schubert wpabuf_free(data->ssl.tls_out);
885206b73d0SCy Schubert data->ssl.tls_out_pos = 0;
886206b73d0SCy Schubert data->ssl.tls_out = encr;
887206b73d0SCy Schubert }
888206b73d0SCy Schubert
889206b73d0SCy Schubert return 0;
890206b73d0SCy Schubert }
891206b73d0SCy Schubert
892206b73d0SCy Schubert
eap_teap_buildReq(struct eap_sm * sm,void * priv,u8 id)893206b73d0SCy Schubert static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id)
894206b73d0SCy Schubert {
895206b73d0SCy Schubert struct eap_teap_data *data = priv;
896206b73d0SCy Schubert struct wpabuf *req = NULL;
897206b73d0SCy Schubert int piggyback = 0;
898*a90b9d01SCy Schubert bool move_to_method = true;
899206b73d0SCy Schubert
900206b73d0SCy Schubert if (data->ssl.state == FRAG_ACK) {
901206b73d0SCy Schubert return eap_server_tls_build_ack(id, EAP_TYPE_TEAP,
902206b73d0SCy Schubert data->teap_version);
903206b73d0SCy Schubert }
904206b73d0SCy Schubert
905206b73d0SCy Schubert if (data->ssl.state == WAIT_FRAG_ACK) {
906206b73d0SCy Schubert return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TEAP,
907206b73d0SCy Schubert data->teap_version, id);
908206b73d0SCy Schubert }
909206b73d0SCy Schubert
910206b73d0SCy Schubert switch (data->state) {
911206b73d0SCy Schubert case START:
912206b73d0SCy Schubert return eap_teap_build_start(sm, data, id);
913206b73d0SCy Schubert case PHASE1B:
914c1d255d3SCy Schubert if (tls_connection_established(sm->cfg->ssl_ctx,
915c1d255d3SCy Schubert data->ssl.conn)) {
916206b73d0SCy Schubert if (eap_teap_phase1_done(sm, data) < 0)
917206b73d0SCy Schubert return NULL;
918206b73d0SCy Schubert if (data->state == PHASE2_START) {
919206b73d0SCy Schubert int res;
920206b73d0SCy Schubert
921206b73d0SCy Schubert /*
922206b73d0SCy Schubert * Try to generate Phase 2 data to piggyback
923206b73d0SCy Schubert * with the end of Phase 1 to avoid extra
924206b73d0SCy Schubert * roundtrip.
925206b73d0SCy Schubert */
926206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
927206b73d0SCy Schubert "EAP-TEAP: Try to start Phase 2");
928206b73d0SCy Schubert res = eap_teap_process_phase2_start(sm, data);
929206b73d0SCy Schubert if (res == 1) {
930206b73d0SCy Schubert req = eap_teap_build_crypto_binding(
931206b73d0SCy Schubert sm, data);
932206b73d0SCy Schubert piggyback = 1;
933206b73d0SCy Schubert break;
934206b73d0SCy Schubert }
935206b73d0SCy Schubert
936206b73d0SCy Schubert if (res)
937206b73d0SCy Schubert break;
938206b73d0SCy Schubert req = eap_teap_build_phase2_req(sm, data, id);
939206b73d0SCy Schubert piggyback = 1;
940206b73d0SCy Schubert }
941206b73d0SCy Schubert }
942206b73d0SCy Schubert break;
943206b73d0SCy Schubert case PHASE2_ID:
944206b73d0SCy Schubert case PHASE2_BASIC_AUTH:
945206b73d0SCy Schubert case PHASE2_METHOD:
946206b73d0SCy Schubert req = eap_teap_build_phase2_req(sm, data, id);
947206b73d0SCy Schubert break;
948206b73d0SCy Schubert case CRYPTO_BINDING:
949206b73d0SCy Schubert req = eap_teap_build_crypto_binding(sm, data);
950*a90b9d01SCy Schubert if (req && sm->cfg->eap_teap_auth == 0 &&
951*a90b9d01SCy Schubert data->inner_eap_not_done &&
952*a90b9d01SCy Schubert !data->phase2_method &&
953*a90b9d01SCy Schubert sm->cfg->eap_teap_method_sequence == 0) {
954*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
955*a90b9d01SCy Schubert "EAP-TEAP: Continue with inner EAP authentication for second credential (optimized)");
956*a90b9d01SCy Schubert eap_teap_state(data, PHASE2_ID);
957*a90b9d01SCy Schubert if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
958*a90b9d01SCy Schubert EAP_TYPE_IDENTITY) < 0) {
959*a90b9d01SCy Schubert eap_teap_state(data, FAILURE);
960*a90b9d01SCy Schubert wpabuf_free(req);
961*a90b9d01SCy Schubert return NULL;
962*a90b9d01SCy Schubert }
963*a90b9d01SCy Schubert move_to_method = false;
964*a90b9d01SCy Schubert }
965206b73d0SCy Schubert if (data->phase2_method) {
966206b73d0SCy Schubert /*
967206b73d0SCy Schubert * Include the start of the next EAP method in the
968206b73d0SCy Schubert * sequence in the same message with Crypto-Binding to
969206b73d0SCy Schubert * save a round-trip.
970206b73d0SCy Schubert */
971206b73d0SCy Schubert struct wpabuf *eap;
972206b73d0SCy Schubert
973206b73d0SCy Schubert eap = eap_teap_build_phase2_req(sm, data, id);
974206b73d0SCy Schubert req = wpabuf_concat(req, eap);
975*a90b9d01SCy Schubert if (move_to_method)
976206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD);
977206b73d0SCy Schubert }
978206b73d0SCy Schubert break;
979206b73d0SCy Schubert case REQUEST_PAC:
980206b73d0SCy Schubert req = eap_teap_build_pac(sm, data);
981206b73d0SCy Schubert break;
982206b73d0SCy Schubert case FAILURE_SEND_RESULT:
983206b73d0SCy Schubert req = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
984206b73d0SCy Schubert if (data->error_code)
985206b73d0SCy Schubert req = wpabuf_concat(
986206b73d0SCy Schubert req, eap_teap_tlv_error(data->error_code));
987206b73d0SCy Schubert break;
988c1d255d3SCy Schubert case SUCCESS_SEND_RESULT:
989c1d255d3SCy Schubert req = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
990c1d255d3SCy Schubert data->final_result = 1;
991c1d255d3SCy Schubert break;
992206b73d0SCy Schubert default:
993206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
994206b73d0SCy Schubert __func__, data->state);
995206b73d0SCy Schubert return NULL;
996206b73d0SCy Schubert }
997206b73d0SCy Schubert
998206b73d0SCy Schubert if (req && eap_teap_encrypt_phase2(sm, data, req, piggyback) < 0)
999206b73d0SCy Schubert return NULL;
1000206b73d0SCy Schubert
1001206b73d0SCy Schubert return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TEAP,
1002206b73d0SCy Schubert data->teap_version, id);
1003206b73d0SCy Schubert }
1004206b73d0SCy Schubert
1005206b73d0SCy Schubert
eap_teap_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)1006c1d255d3SCy Schubert static bool eap_teap_check(struct eap_sm *sm, void *priv,
1007206b73d0SCy Schubert struct wpabuf *respData)
1008206b73d0SCy Schubert {
1009206b73d0SCy Schubert const u8 *pos;
1010206b73d0SCy Schubert size_t len;
1011206b73d0SCy Schubert
1012206b73d0SCy Schubert pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len);
1013206b73d0SCy Schubert if (!pos || len < 1) {
1014206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: Invalid frame");
1015c1d255d3SCy Schubert return true;
1016206b73d0SCy Schubert }
1017206b73d0SCy Schubert
1018c1d255d3SCy Schubert return false;
1019206b73d0SCy Schubert }
1020206b73d0SCy Schubert
1021206b73d0SCy Schubert
eap_teap_phase2_init(struct eap_sm * sm,struct eap_teap_data * data,int vendor,enum eap_type eap_type)1022206b73d0SCy Schubert static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
1023c1d255d3SCy Schubert int vendor, enum eap_type eap_type)
1024206b73d0SCy Schubert {
1025206b73d0SCy Schubert if (data->phase2_priv && data->phase2_method) {
1026206b73d0SCy Schubert data->phase2_method->reset(sm, data->phase2_priv);
1027206b73d0SCy Schubert data->phase2_method = NULL;
1028206b73d0SCy Schubert data->phase2_priv = NULL;
1029206b73d0SCy Schubert }
1030c1d255d3SCy Schubert data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
1031206b73d0SCy Schubert if (!data->phase2_method)
1032206b73d0SCy Schubert return -1;
1033206b73d0SCy Schubert
1034*a90b9d01SCy Schubert /* While RFC 7170 does not describe this, EAP-TEAP has been deployed
1035*a90b9d01SCy Schubert * with implementations that use the EAP-FAST-MSCHAPv2, instead of the
1036*a90b9d01SCy Schubert * EAP-MSCHAPv2, way of deriving the MSK for IMSK. Use that design here
1037*a90b9d01SCy Schubert * to interoperate.
1038*a90b9d01SCy Schubert */
1039*a90b9d01SCy Schubert sm->eap_fast_mschapv2 = true;
1040*a90b9d01SCy Schubert
1041206b73d0SCy Schubert sm->init_phase2 = 1;
1042206b73d0SCy Schubert data->phase2_priv = data->phase2_method->init(sm);
1043206b73d0SCy Schubert sm->init_phase2 = 0;
1044206b73d0SCy Schubert
1045206b73d0SCy Schubert return data->phase2_priv ? 0 : -1;
1046206b73d0SCy Schubert }
1047206b73d0SCy Schubert
1048206b73d0SCy Schubert
eap_teap_valid_id_type(struct eap_sm * sm,struct eap_teap_data * data,enum teap_identity_types id_type)1049c1d255d3SCy Schubert static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data,
1050c1d255d3SCy Schubert enum teap_identity_types id_type)
1051c1d255d3SCy Schubert {
1052c1d255d3SCy Schubert if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER &&
1053c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_USER)
1054c1d255d3SCy Schubert return 0;
1055c1d255d3SCy Schubert if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE &&
1056c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_MACHINE)
1057c1d255d3SCy Schubert return 0;
1058c1d255d3SCy Schubert if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE &&
1059c1d255d3SCy Schubert id_type != data->cur_id_type)
1060c1d255d3SCy Schubert return 0;
1061c1d255d3SCy Schubert if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY &&
1062c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_USER &&
1063c1d255d3SCy Schubert id_type != TEAP_IDENTITY_TYPE_MACHINE)
1064c1d255d3SCy Schubert return 0;
1065c1d255d3SCy Schubert return 1;
1066c1d255d3SCy Schubert }
1067c1d255d3SCy Schubert
1068c1d255d3SCy Schubert
eap_teap_process_phase2_response(struct eap_sm * sm,struct eap_teap_data * data,u8 * in_data,size_t in_len,enum teap_identity_types id_type)1069206b73d0SCy Schubert static void eap_teap_process_phase2_response(struct eap_sm *sm,
1070206b73d0SCy Schubert struct eap_teap_data *data,
1071c1d255d3SCy Schubert u8 *in_data, size_t in_len,
1072c1d255d3SCy Schubert enum teap_identity_types id_type)
1073206b73d0SCy Schubert {
1074c1d255d3SCy Schubert int next_vendor = EAP_VENDOR_IETF;
1075c1d255d3SCy Schubert enum eap_type next_type = EAP_TYPE_NONE;
1076206b73d0SCy Schubert struct eap_hdr *hdr;
1077206b73d0SCy Schubert u8 *pos;
1078206b73d0SCy Schubert size_t left;
1079206b73d0SCy Schubert struct wpabuf buf;
1080206b73d0SCy Schubert const struct eap_method *m = data->phase2_method;
1081206b73d0SCy Schubert void *priv = data->phase2_priv;
1082206b73d0SCy Schubert
1083206b73d0SCy Schubert if (!priv) {
1084206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1085206b73d0SCy Schubert "EAP-TEAP: %s - Phase 2 not initialized?!",
1086206b73d0SCy Schubert __func__);
1087206b73d0SCy Schubert return;
1088206b73d0SCy Schubert }
1089206b73d0SCy Schubert
1090206b73d0SCy Schubert hdr = (struct eap_hdr *) in_data;
1091206b73d0SCy Schubert pos = (u8 *) (hdr + 1);
1092206b73d0SCy Schubert
1093206b73d0SCy Schubert if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
1094206b73d0SCy Schubert left = in_len - sizeof(*hdr);
1095206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG,
1096206b73d0SCy Schubert "EAP-TEAP: Phase 2 type Nak'ed; allowed types",
1097206b73d0SCy Schubert pos + 1, left - 1);
1098206b73d0SCy Schubert #ifdef EAP_SERVER_TNC
1099206b73d0SCy Schubert if (m && m->vendor == EAP_VENDOR_IETF &&
1100206b73d0SCy Schubert m->method == EAP_TYPE_TNC) {
1101206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1102206b73d0SCy Schubert "EAP-TEAP: Peer Nak'ed required TNC negotiation");
1103c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1104206b73d0SCy Schubert next_type = eap_teap_req_failure(data, 0);
1105c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type);
1106206b73d0SCy Schubert return;
1107206b73d0SCy Schubert }
1108206b73d0SCy Schubert #endif /* EAP_SERVER_TNC */
1109206b73d0SCy Schubert eap_sm_process_nak(sm, pos + 1, left - 1);
1110206b73d0SCy Schubert if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
1111206b73d0SCy Schubert sm->user->methods[sm->user_eap_method_index].method !=
1112206b73d0SCy Schubert EAP_TYPE_NONE) {
1113c1d255d3SCy Schubert next_vendor = sm->user->methods[
1114c1d255d3SCy Schubert sm->user_eap_method_index].vendor;
1115206b73d0SCy Schubert next_type = sm->user->methods[
1116206b73d0SCy Schubert sm->user_eap_method_index++].method;
1117c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %u:%u",
1118c1d255d3SCy Schubert next_vendor, next_type);
1119206b73d0SCy Schubert } else {
1120c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1121206b73d0SCy Schubert next_type = eap_teap_req_failure(data, 0);
1122206b73d0SCy Schubert }
1123c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type);
1124206b73d0SCy Schubert return;
1125206b73d0SCy Schubert }
1126206b73d0SCy Schubert
1127206b73d0SCy Schubert wpabuf_set(&buf, in_data, in_len);
1128206b73d0SCy Schubert
1129206b73d0SCy Schubert if (m->check(sm, priv, &buf)) {
1130206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1131206b73d0SCy Schubert "EAP-TEAP: Phase 2 check() asked to ignore the packet");
1132206b73d0SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
1133206b73d0SCy Schubert return;
1134206b73d0SCy Schubert }
1135206b73d0SCy Schubert
1136206b73d0SCy Schubert m->process(sm, priv, &buf);
1137206b73d0SCy Schubert
1138206b73d0SCy Schubert if (!m->isDone(sm, priv))
1139206b73d0SCy Schubert return;
1140206b73d0SCy Schubert
1141206b73d0SCy Schubert if (!m->isSuccess(sm, priv)) {
1142206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 method failed");
1143c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1144206b73d0SCy Schubert next_type = eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
1145c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type);
1146206b73d0SCy Schubert return;
1147206b73d0SCy Schubert }
1148206b73d0SCy Schubert
1149206b73d0SCy Schubert switch (data->state) {
1150206b73d0SCy Schubert case PHASE2_ID:
1151c1d255d3SCy Schubert if (!eap_teap_valid_id_type(sm, data, id_type)) {
1152c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1153c1d255d3SCy Schubert "EAP-TEAP: Provided Identity-Type %u not allowed",
1154c1d255d3SCy Schubert id_type);
1155c1d255d3SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
1156c1d255d3SCy Schubert break;
1157c1d255d3SCy Schubert }
1158206b73d0SCy Schubert if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1159206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG,
1160206b73d0SCy Schubert "EAP-TEAP: Phase 2 Identity not found in the user database",
1161206b73d0SCy Schubert sm->identity, sm->identity_len);
1162c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1163206b73d0SCy Schubert next_type = eap_teap_req_failure(
1164206b73d0SCy Schubert data, TEAP_ERROR_INNER_METHOD);
1165206b73d0SCy Schubert break;
1166206b73d0SCy Schubert }
1167206b73d0SCy Schubert
1168206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD);
1169206b73d0SCy Schubert if (data->anon_provisioning) {
1170206b73d0SCy Schubert /* TODO: Allow any inner EAP method that provides
1171206b73d0SCy Schubert * mutual authentication and EMSK derivation (i.e.,
1172206b73d0SCy Schubert * EAP-pwd or EAP-EKE). */
1173c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1174206b73d0SCy Schubert next_type = EAP_TYPE_PWD;
1175206b73d0SCy Schubert sm->user_eap_method_index = 0;
1176206b73d0SCy Schubert } else {
1177c1d255d3SCy Schubert next_vendor = sm->user->methods[0].vendor;
1178206b73d0SCy Schubert next_type = sm->user->methods[0].method;
1179206b73d0SCy Schubert sm->user_eap_method_index = 1;
1180206b73d0SCy Schubert }
1181c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u",
1182c1d255d3SCy Schubert next_vendor, next_type);
1183206b73d0SCy Schubert break;
1184206b73d0SCy Schubert case PHASE2_METHOD:
1185206b73d0SCy Schubert case CRYPTO_BINDING:
1186206b73d0SCy Schubert eap_teap_update_icmk(sm, data);
1187c1d255d3SCy Schubert if (data->state == PHASE2_METHOD &&
1188c1d255d3SCy Schubert (sm->cfg->eap_teap_id !=
1189c1d255d3SCy Schubert EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
1190c1d255d3SCy Schubert data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE))
1191c1d255d3SCy Schubert data->inner_eap_not_done = 0;
1192206b73d0SCy Schubert eap_teap_state(data, CRYPTO_BINDING);
1193206b73d0SCy Schubert data->eap_seq++;
1194c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1195206b73d0SCy Schubert next_type = EAP_TYPE_NONE;
1196206b73d0SCy Schubert #ifdef EAP_SERVER_TNC
1197c1d255d3SCy Schubert if (sm->cfg->tnc && !data->tnc_started) {
1198206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Initialize TNC");
1199c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1200206b73d0SCy Schubert next_type = EAP_TYPE_TNC;
1201206b73d0SCy Schubert data->tnc_started = 1;
1202206b73d0SCy Schubert }
1203206b73d0SCy Schubert #endif /* EAP_SERVER_TNC */
1204206b73d0SCy Schubert break;
1205206b73d0SCy Schubert case FAILURE:
1206206b73d0SCy Schubert break;
1207206b73d0SCy Schubert default:
1208206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
1209206b73d0SCy Schubert __func__, data->state);
1210206b73d0SCy Schubert break;
1211206b73d0SCy Schubert }
1212206b73d0SCy Schubert
1213c1d255d3SCy Schubert eap_teap_phase2_init(sm, data, next_vendor, next_type);
1214206b73d0SCy Schubert }
1215206b73d0SCy Schubert
1216206b73d0SCy Schubert
eap_teap_process_phase2_eap(struct eap_sm * sm,struct eap_teap_data * data,u8 * in_data,size_t in_len,enum teap_identity_types id_type)1217206b73d0SCy Schubert static void eap_teap_process_phase2_eap(struct eap_sm *sm,
1218206b73d0SCy Schubert struct eap_teap_data *data,
1219c1d255d3SCy Schubert u8 *in_data, size_t in_len,
1220c1d255d3SCy Schubert enum teap_identity_types id_type)
1221206b73d0SCy Schubert {
1222206b73d0SCy Schubert struct eap_hdr *hdr;
1223206b73d0SCy Schubert size_t len;
1224206b73d0SCy Schubert
1225206b73d0SCy Schubert hdr = (struct eap_hdr *) in_data;
1226206b73d0SCy Schubert if (in_len < (int) sizeof(*hdr)) {
1227206b73d0SCy Schubert wpa_printf(MSG_INFO,
1228206b73d0SCy Schubert "EAP-TEAP: Too short Phase 2 EAP frame (len=%lu)",
1229206b73d0SCy Schubert (unsigned long) in_len);
1230206b73d0SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
1231206b73d0SCy Schubert return;
1232206b73d0SCy Schubert }
1233206b73d0SCy Schubert len = be_to_host16(hdr->length);
1234206b73d0SCy Schubert if (len > in_len) {
1235206b73d0SCy Schubert wpa_printf(MSG_INFO,
1236206b73d0SCy Schubert "EAP-TEAP: Length mismatch in Phase 2 EAP frame (len=%lu hdr->length=%lu)",
1237206b73d0SCy Schubert (unsigned long) in_len, (unsigned long) len);
1238206b73d0SCy Schubert eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
1239206b73d0SCy Schubert return;
1240206b73d0SCy Schubert }
1241206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1242206b73d0SCy Schubert "EAP-TEAP: Received Phase 2: code=%d identifier=%d length=%lu",
1243206b73d0SCy Schubert hdr->code, hdr->identifier,
1244206b73d0SCy Schubert (unsigned long) len);
1245206b73d0SCy Schubert switch (hdr->code) {
1246206b73d0SCy Schubert case EAP_CODE_RESPONSE:
1247c1d255d3SCy Schubert eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len,
1248c1d255d3SCy Schubert id_type);
1249206b73d0SCy Schubert break;
1250206b73d0SCy Schubert default:
1251206b73d0SCy Schubert wpa_printf(MSG_INFO,
1252206b73d0SCy Schubert "EAP-TEAP: Unexpected code=%d in Phase 2 EAP header",
1253206b73d0SCy Schubert hdr->code);
1254206b73d0SCy Schubert break;
1255206b73d0SCy Schubert }
1256206b73d0SCy Schubert }
1257206b73d0SCy Schubert
1258206b73d0SCy Schubert
eap_teap_process_basic_auth_resp(struct eap_sm * sm,struct eap_teap_data * data,u8 * in_data,size_t in_len,enum teap_identity_types id_type)1259206b73d0SCy Schubert static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
1260206b73d0SCy Schubert struct eap_teap_data *data,
1261c1d255d3SCy Schubert u8 *in_data, size_t in_len,
1262c1d255d3SCy Schubert enum teap_identity_types id_type)
1263206b73d0SCy Schubert {
1264206b73d0SCy Schubert u8 *pos, *end, *username, *password, *new_id;
1265206b73d0SCy Schubert u8 userlen, passlen;
1266206b73d0SCy Schubert
1267c1d255d3SCy Schubert if (!eap_teap_valid_id_type(sm, data, id_type)) {
1268c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1269c1d255d3SCy Schubert "EAP-TEAP: Provided Identity-Type %u not allowed",
1270c1d255d3SCy Schubert id_type);
1271c1d255d3SCy Schubert eap_teap_req_failure(data, 0);
1272c1d255d3SCy Schubert return;
1273c1d255d3SCy Schubert }
1274c1d255d3SCy Schubert
1275206b73d0SCy Schubert pos = in_data;
1276206b73d0SCy Schubert end = pos + in_len;
1277206b73d0SCy Schubert
1278206b73d0SCy Schubert if (end - pos < 1) {
1279206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1280206b73d0SCy Schubert "EAP-TEAP: No room for Basic-Password-Auth-Resp Userlen field");
1281206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1282206b73d0SCy Schubert return;
1283206b73d0SCy Schubert }
1284206b73d0SCy Schubert userlen = *pos++;
1285206b73d0SCy Schubert if (end - pos < userlen) {
1286206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1287206b73d0SCy Schubert "EAP-TEAP: Truncated Basic-Password-Auth-Resp Username field");
1288206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1289206b73d0SCy Schubert return;
1290206b73d0SCy Schubert }
1291206b73d0SCy Schubert username = pos;
1292206b73d0SCy Schubert pos += userlen;
1293206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG,
1294206b73d0SCy Schubert "EAP-TEAP: Basic-Password-Auth-Resp Username",
1295206b73d0SCy Schubert username, userlen);
1296206b73d0SCy Schubert
1297206b73d0SCy Schubert if (end - pos < 1) {
1298206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1299206b73d0SCy Schubert "EAP-TEAP: No room for Basic-Password-Auth-Resp Passlen field");
1300206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1301206b73d0SCy Schubert return;
1302206b73d0SCy Schubert }
1303206b73d0SCy Schubert passlen = *pos++;
1304206b73d0SCy Schubert if (end - pos < passlen) {
1305206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1306206b73d0SCy Schubert "EAP-TEAP: Truncated Basic-Password-Auth-Resp Password field");
1307206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1308206b73d0SCy Schubert return;
1309206b73d0SCy Schubert }
1310206b73d0SCy Schubert password = pos;
1311206b73d0SCy Schubert pos += passlen;
1312206b73d0SCy Schubert wpa_hexdump_ascii_key(MSG_DEBUG,
1313206b73d0SCy Schubert "EAP-TEAP: Basic-Password-Auth-Resp Password",
1314206b73d0SCy Schubert password, passlen);
1315206b73d0SCy Schubert
1316206b73d0SCy Schubert if (end > pos) {
1317206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1318206b73d0SCy Schubert "EAP-TEAP: Unexpected %d extra octet(s) at the end of Basic-Password-Auth-Resp TLV",
1319206b73d0SCy Schubert (int) (end - pos));
1320206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1321206b73d0SCy Schubert return;
1322206b73d0SCy Schubert }
1323206b73d0SCy Schubert
1324206b73d0SCy Schubert if (eap_user_get(sm, username, userlen, 1) != 0) {
1325206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1326206b73d0SCy Schubert "EAP-TEAP: Username not found in the user database");
1327206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1328206b73d0SCy Schubert return;
1329206b73d0SCy Schubert }
1330206b73d0SCy Schubert
1331206b73d0SCy Schubert if (!sm->user || !sm->user->password || sm->user->password_hash) {
1332206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1333206b73d0SCy Schubert "EAP-TEAP: No plaintext user password configured");
1334206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1335206b73d0SCy Schubert return;
1336206b73d0SCy Schubert }
1337206b73d0SCy Schubert
1338206b73d0SCy Schubert if (sm->user->password_len != passlen ||
1339206b73d0SCy Schubert os_memcmp_const(sm->user->password, password, passlen) != 0) {
1340206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Invalid password");
1341206b73d0SCy Schubert eap_teap_req_failure(data, 0);
1342206b73d0SCy Schubert return;
1343206b73d0SCy Schubert }
1344206b73d0SCy Schubert
1345206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Correct password");
1346206b73d0SCy Schubert new_id = os_memdup(username, userlen);
1347206b73d0SCy Schubert if (new_id) {
1348206b73d0SCy Schubert os_free(sm->identity);
1349206b73d0SCy Schubert sm->identity = new_id;
1350206b73d0SCy Schubert sm->identity_len = userlen;
1351206b73d0SCy Schubert }
1352c1d255d3SCy Schubert if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
1353c1d255d3SCy Schubert data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)
1354c1d255d3SCy Schubert data->basic_auth_not_done = 0;
1355206b73d0SCy Schubert eap_teap_state(data, CRYPTO_BINDING);
1356206b73d0SCy Schubert eap_teap_update_icmk(sm, data);
1357206b73d0SCy Schubert }
1358206b73d0SCy Schubert
1359206b73d0SCy Schubert
eap_teap_parse_tlvs(struct wpabuf * data,struct eap_teap_tlv_parse * tlv)1360206b73d0SCy Schubert static int eap_teap_parse_tlvs(struct wpabuf *data,
1361206b73d0SCy Schubert struct eap_teap_tlv_parse *tlv)
1362206b73d0SCy Schubert {
1363206b73d0SCy Schubert u16 tlv_type;
1364206b73d0SCy Schubert int mandatory, res;
1365206b73d0SCy Schubert size_t len;
1366206b73d0SCy Schubert u8 *pos, *end;
1367206b73d0SCy Schubert
1368206b73d0SCy Schubert os_memset(tlv, 0, sizeof(*tlv));
1369206b73d0SCy Schubert
1370206b73d0SCy Schubert pos = wpabuf_mhead(data);
1371206b73d0SCy Schubert end = pos + wpabuf_len(data);
1372206b73d0SCy Schubert while (end - pos > 4) {
1373206b73d0SCy Schubert mandatory = pos[0] & 0x80;
1374206b73d0SCy Schubert tlv_type = WPA_GET_BE16(pos) & 0x3fff;
1375206b73d0SCy Schubert pos += 2;
1376206b73d0SCy Schubert len = WPA_GET_BE16(pos);
1377206b73d0SCy Schubert pos += 2;
1378206b73d0SCy Schubert if (len > (size_t) (end - pos)) {
1379206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: TLV overflow");
1380206b73d0SCy Schubert return -1;
1381206b73d0SCy Schubert }
1382206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1383206b73d0SCy Schubert "EAP-TEAP: Received Phase 2: TLV type %u (%s) length %u%s",
1384206b73d0SCy Schubert tlv_type, eap_teap_tlv_type_str(tlv_type),
1385206b73d0SCy Schubert (unsigned int) len,
1386206b73d0SCy Schubert mandatory ? " (mandatory)" : "");
1387206b73d0SCy Schubert
1388206b73d0SCy Schubert res = eap_teap_parse_tlv(tlv, tlv_type, pos, len);
1389206b73d0SCy Schubert if (res == -2)
1390206b73d0SCy Schubert break;
1391206b73d0SCy Schubert if (res < 0) {
1392206b73d0SCy Schubert if (mandatory) {
1393206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1394206b73d0SCy Schubert "EAP-TEAP: NAK unknown mandatory TLV type %u",
1395206b73d0SCy Schubert tlv_type);
1396206b73d0SCy Schubert /* TODO: generate NAK TLV */
1397206b73d0SCy Schubert break;
1398206b73d0SCy Schubert }
1399206b73d0SCy Schubert
1400206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1401206b73d0SCy Schubert "EAP-TEAP: Ignore unknown optional TLV type %u",
1402206b73d0SCy Schubert tlv_type);
1403206b73d0SCy Schubert }
1404206b73d0SCy Schubert
1405206b73d0SCy Schubert pos += len;
1406206b73d0SCy Schubert }
1407206b73d0SCy Schubert
1408206b73d0SCy Schubert return 0;
1409206b73d0SCy Schubert }
1410206b73d0SCy Schubert
1411206b73d0SCy Schubert
eap_teap_validate_crypto_binding(struct eap_teap_data * data,const struct teap_tlv_crypto_binding * cb,size_t bind_len)1412206b73d0SCy Schubert static int eap_teap_validate_crypto_binding(
1413206b73d0SCy Schubert struct eap_teap_data *data, const struct teap_tlv_crypto_binding *cb,
1414206b73d0SCy Schubert size_t bind_len)
1415206b73d0SCy Schubert {
1416206b73d0SCy Schubert u8 flags, subtype;
1417206b73d0SCy Schubert
1418206b73d0SCy Schubert subtype = cb->subtype & 0x0f;
1419206b73d0SCy Schubert flags = cb->subtype >> 4;
1420206b73d0SCy Schubert
1421206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1422206b73d0SCy Schubert "EAP-TEAP: Reply Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
1423206b73d0SCy Schubert cb->version, cb->received_version, flags, subtype);
1424206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
1425206b73d0SCy Schubert cb->nonce, sizeof(cb->nonce));
1426206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
1427206b73d0SCy Schubert cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac));
1428206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
1429206b73d0SCy Schubert cb->msk_compound_mac, sizeof(cb->msk_compound_mac));
1430206b73d0SCy Schubert
1431206b73d0SCy Schubert if (cb->version != EAP_TEAP_VERSION ||
1432206b73d0SCy Schubert cb->received_version != data->peer_version) {
1433206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1434206b73d0SCy Schubert "EAP-TEAP: Unexpected version in Crypto-Binding: Version %u Received Version %u",
1435206b73d0SCy Schubert cb->version, cb->received_version);
1436206b73d0SCy Schubert return -1;
1437206b73d0SCy Schubert }
1438206b73d0SCy Schubert
1439206b73d0SCy Schubert if (flags < 1 || flags > 3) {
1440206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1441206b73d0SCy Schubert "EAP-TEAP: Unexpected Flags in Crypto-Binding: %u",
1442206b73d0SCy Schubert flags);
1443206b73d0SCy Schubert return -1;
1444206b73d0SCy Schubert }
1445206b73d0SCy Schubert
1446206b73d0SCy Schubert if (subtype != TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
1447206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1448206b73d0SCy Schubert "EAP-TEAP: Unexpected Sub-Type in Crypto-Binding: %u",
1449206b73d0SCy Schubert subtype);
1450206b73d0SCy Schubert return -1;
1451206b73d0SCy Schubert }
1452206b73d0SCy Schubert
1453206b73d0SCy Schubert if (os_memcmp_const(data->crypto_binding_nonce, cb->nonce,
1454206b73d0SCy Schubert EAP_TEAP_NONCE_LEN - 1) != 0 ||
1455206b73d0SCy Schubert (data->crypto_binding_nonce[EAP_TEAP_NONCE_LEN - 1] | 1) !=
1456206b73d0SCy Schubert cb->nonce[EAP_TEAP_NONCE_LEN - 1]) {
1457206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1458206b73d0SCy Schubert "EAP-TEAP: Invalid Nonce in Crypto-Binding");
1459206b73d0SCy Schubert return -1;
1460206b73d0SCy Schubert }
1461206b73d0SCy Schubert
1462206b73d0SCy Schubert if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
1463206b73d0SCy Schubert flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) {
1464206b73d0SCy Schubert u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
1465206b73d0SCy Schubert
1466206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb,
1467206b73d0SCy Schubert data->server_outer_tlvs,
1468206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_msk,
1469206b73d0SCy Schubert msk_compound_mac) < 0)
1470206b73d0SCy Schubert return -1;
1471206b73d0SCy Schubert if (os_memcmp_const(msk_compound_mac, cb->msk_compound_mac,
1472206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN) != 0) {
1473206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG,
1474206b73d0SCy Schubert "EAP-TEAP: Calculated MSK Compound MAC",
1475206b73d0SCy Schubert msk_compound_mac,
1476206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN);
1477206b73d0SCy Schubert wpa_printf(MSG_INFO,
1478206b73d0SCy Schubert "EAP-TEAP: MSK Compound MAC did not match");
1479206b73d0SCy Schubert return -1;
1480206b73d0SCy Schubert }
1481206b73d0SCy Schubert }
1482206b73d0SCy Schubert
1483206b73d0SCy Schubert if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
1484206b73d0SCy Schubert flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) &&
1485206b73d0SCy Schubert data->cmk_emsk_available) {
1486206b73d0SCy Schubert u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
1487206b73d0SCy Schubert
1488206b73d0SCy Schubert if (eap_teap_compound_mac(data->tls_cs, cb,
1489206b73d0SCy Schubert data->server_outer_tlvs,
1490206b73d0SCy Schubert data->peer_outer_tlvs, data->cmk_emsk,
1491206b73d0SCy Schubert emsk_compound_mac) < 0)
1492206b73d0SCy Schubert return -1;
1493206b73d0SCy Schubert if (os_memcmp_const(emsk_compound_mac, cb->emsk_compound_mac,
1494206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN) != 0) {
1495206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG,
1496206b73d0SCy Schubert "EAP-TEAP: Calculated EMSK Compound MAC",
1497206b73d0SCy Schubert emsk_compound_mac,
1498206b73d0SCy Schubert EAP_TEAP_COMPOUND_MAC_LEN);
1499206b73d0SCy Schubert wpa_printf(MSG_INFO,
1500206b73d0SCy Schubert "EAP-TEAP: EMSK Compound MAC did not match");
1501206b73d0SCy Schubert return -1;
1502206b73d0SCy Schubert }
1503206b73d0SCy Schubert }
1504206b73d0SCy Schubert
1505206b73d0SCy Schubert if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC &&
1506206b73d0SCy Schubert !data->cmk_emsk_available) {
1507206b73d0SCy Schubert wpa_printf(MSG_INFO,
1508206b73d0SCy Schubert "EAP-TEAP: Peer included only EMSK Compound MAC, but no locally generated inner EAP EMSK to validate this");
1509206b73d0SCy Schubert return -1;
1510206b73d0SCy Schubert }
1511206b73d0SCy Schubert
1512206b73d0SCy Schubert return 0;
1513206b73d0SCy Schubert }
1514206b73d0SCy Schubert
1515206b73d0SCy Schubert
eap_teap_pac_type(u8 * pac,size_t len,u16 type)1516206b73d0SCy Schubert static int eap_teap_pac_type(u8 *pac, size_t len, u16 type)
1517206b73d0SCy Schubert {
1518206b73d0SCy Schubert struct teap_attr_pac_type *tlv;
1519206b73d0SCy Schubert
1520206b73d0SCy Schubert if (!pac || len != sizeof(*tlv))
1521206b73d0SCy Schubert return 0;
1522206b73d0SCy Schubert
1523206b73d0SCy Schubert tlv = (struct teap_attr_pac_type *) pac;
1524206b73d0SCy Schubert
1525206b73d0SCy Schubert return be_to_host16(tlv->type) == PAC_TYPE_PAC_TYPE &&
1526206b73d0SCy Schubert be_to_host16(tlv->length) == 2 &&
1527206b73d0SCy Schubert be_to_host16(tlv->pac_type) == type;
1528206b73d0SCy Schubert }
1529206b73d0SCy Schubert
1530206b73d0SCy Schubert
eap_teap_process_phase2_tlvs(struct eap_sm * sm,struct eap_teap_data * data,struct wpabuf * in_data)1531206b73d0SCy Schubert static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
1532206b73d0SCy Schubert struct eap_teap_data *data,
1533206b73d0SCy Schubert struct wpabuf *in_data)
1534206b73d0SCy Schubert {
1535206b73d0SCy Schubert struct eap_teap_tlv_parse tlv;
1536*a90b9d01SCy Schubert bool check_crypto_binding = data->state == CRYPTO_BINDING ||
1537*a90b9d01SCy Schubert data->check_crypto_binding;
1538206b73d0SCy Schubert
1539206b73d0SCy Schubert if (eap_teap_parse_tlvs(in_data, &tlv) < 0) {
1540206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1541206b73d0SCy Schubert "EAP-TEAP: Failed to parse received Phase 2 TLVs");
1542206b73d0SCy Schubert return;
1543206b73d0SCy Schubert }
1544206b73d0SCy Schubert
1545206b73d0SCy Schubert if (tlv.result == TEAP_STATUS_FAILURE) {
1546206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Result TLV indicated failure");
1547206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1548206b73d0SCy Schubert return;
1549206b73d0SCy Schubert }
1550206b73d0SCy Schubert
1551206b73d0SCy Schubert if (tlv.nak) {
1552206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1553206b73d0SCy Schubert "EAP-TEAP: Peer NAK'ed Vendor-Id %u NAK-Type %u",
1554206b73d0SCy Schubert WPA_GET_BE32(tlv.nak), WPA_GET_BE16(tlv.nak + 4));
1555206b73d0SCy Schubert eap_teap_state(data, FAILURE_SEND_RESULT);
1556206b73d0SCy Schubert return;
1557206b73d0SCy Schubert }
1558206b73d0SCy Schubert
1559206b73d0SCy Schubert if (data->state == REQUEST_PAC) {
1560206b73d0SCy Schubert u16 type, len, res;
1561206b73d0SCy Schubert
1562206b73d0SCy Schubert if (!tlv.pac || tlv.pac_len < 6) {
1563206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1564206b73d0SCy Schubert "EAP-TEAP: No PAC Acknowledgement received");
1565206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1566206b73d0SCy Schubert return;
1567206b73d0SCy Schubert }
1568206b73d0SCy Schubert
1569206b73d0SCy Schubert type = WPA_GET_BE16(tlv.pac);
1570206b73d0SCy Schubert len = WPA_GET_BE16(tlv.pac + 2);
1571206b73d0SCy Schubert res = WPA_GET_BE16(tlv.pac + 4);
1572206b73d0SCy Schubert
1573206b73d0SCy Schubert if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
1574206b73d0SCy Schubert res != TEAP_STATUS_SUCCESS) {
1575206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1576206b73d0SCy Schubert "EAP-TEAP: PAC TLV did not contain acknowledgement");
1577206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1578206b73d0SCy Schubert return;
1579206b73d0SCy Schubert }
1580206b73d0SCy Schubert
1581206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1582206b73d0SCy Schubert "EAP-TEAP: PAC-Acknowledgement received - PAC provisioning succeeded");
1583206b73d0SCy Schubert eap_teap_state(data, SUCCESS);
1584206b73d0SCy Schubert return;
1585206b73d0SCy Schubert }
1586206b73d0SCy Schubert
1587206b73d0SCy Schubert if (check_crypto_binding) {
1588206b73d0SCy Schubert if (!tlv.crypto_binding) {
1589206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1590206b73d0SCy Schubert "EAP-TEAP: No Crypto-Binding TLV received");
1591206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1592206b73d0SCy Schubert return;
1593206b73d0SCy Schubert }
1594206b73d0SCy Schubert
1595206b73d0SCy Schubert if (data->final_result &&
1596206b73d0SCy Schubert tlv.result != TEAP_STATUS_SUCCESS) {
1597206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1598206b73d0SCy Schubert "EAP-TEAP: Crypto-Binding TLV without Success Result");
1599206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1600206b73d0SCy Schubert return;
1601206b73d0SCy Schubert }
1602206b73d0SCy Schubert
1603c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth != 1 &&
1604c1d255d3SCy Schubert !data->skipped_inner_auth &&
1605206b73d0SCy Schubert tlv.iresult != TEAP_STATUS_SUCCESS) {
1606206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1607206b73d0SCy Schubert "EAP-TEAP: Crypto-Binding TLV without intermediate Success Result");
1608206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1609206b73d0SCy Schubert return;
1610206b73d0SCy Schubert }
1611206b73d0SCy Schubert
1612206b73d0SCy Schubert if (eap_teap_validate_crypto_binding(data, tlv.crypto_binding,
1613206b73d0SCy Schubert tlv.crypto_binding_len)) {
1614206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1615206b73d0SCy Schubert return;
1616206b73d0SCy Schubert }
1617206b73d0SCy Schubert
1618206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1619206b73d0SCy Schubert "EAP-TEAP: Valid Crypto-Binding TLV received");
1620*a90b9d01SCy Schubert data->check_crypto_binding = false;
1621206b73d0SCy Schubert if (data->final_result) {
1622206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1623206b73d0SCy Schubert "EAP-TEAP: Authentication completed successfully");
1624206b73d0SCy Schubert }
1625206b73d0SCy Schubert
1626206b73d0SCy Schubert if (data->anon_provisioning &&
1627c1d255d3SCy Schubert sm->cfg->eap_fast_prov != ANON_PROV &&
1628c1d255d3SCy Schubert sm->cfg->eap_fast_prov != BOTH_PROV) {
1629206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1630206b73d0SCy Schubert "EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled");
1631206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1632206b73d0SCy Schubert return;
1633206b73d0SCy Schubert }
1634206b73d0SCy Schubert
1635c1d255d3SCy Schubert if (sm->cfg->eap_fast_prov != AUTH_PROV &&
1636c1d255d3SCy Schubert sm->cfg->eap_fast_prov != BOTH_PROV &&
1637206b73d0SCy Schubert tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
1638206b73d0SCy Schubert eap_teap_pac_type(tlv.pac, tlv.pac_len,
1639206b73d0SCy Schubert PAC_TYPE_TUNNEL_PAC)) {
1640206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1641206b73d0SCy Schubert "EAP-TEAP: Client is trying to use authenticated provisioning which is disabled");
1642206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1643206b73d0SCy Schubert return;
1644206b73d0SCy Schubert }
1645206b73d0SCy Schubert
1646206b73d0SCy Schubert if (data->anon_provisioning ||
1647206b73d0SCy Schubert (tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
1648206b73d0SCy Schubert eap_teap_pac_type(tlv.pac, tlv.pac_len,
1649206b73d0SCy Schubert PAC_TYPE_TUNNEL_PAC))) {
1650206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1651206b73d0SCy Schubert "EAP-TEAP: Requested a new Tunnel PAC");
1652206b73d0SCy Schubert eap_teap_state(data, REQUEST_PAC);
1653206b73d0SCy Schubert } else if (data->send_new_pac) {
1654206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1655206b73d0SCy Schubert "EAP-TEAP: Server triggered re-keying of Tunnel PAC");
1656206b73d0SCy Schubert eap_teap_state(data, REQUEST_PAC);
1657c1d255d3SCy Schubert } else if (data->final_result) {
1658206b73d0SCy Schubert eap_teap_state(data, SUCCESS);
1659c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_separate_result) {
1660c1d255d3SCy Schubert eap_teap_state(data, SUCCESS_SEND_RESULT);
1661c1d255d3SCy Schubert }
1662206b73d0SCy Schubert }
1663206b73d0SCy Schubert
1664206b73d0SCy Schubert if (tlv.basic_auth_resp) {
1665c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth != 1) {
1666206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1667206b73d0SCy Schubert "EAP-TEAP: Unexpected Basic-Password-Auth-Resp when trying to use inner EAP");
1668206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1669206b73d0SCy Schubert return;
1670206b73d0SCy Schubert }
1671206b73d0SCy Schubert eap_teap_process_basic_auth_resp(sm, data, tlv.basic_auth_resp,
1672c1d255d3SCy Schubert tlv.basic_auth_resp_len,
1673c1d255d3SCy Schubert tlv.identity_type);
1674206b73d0SCy Schubert }
1675206b73d0SCy Schubert
1676206b73d0SCy Schubert if (tlv.eap_payload_tlv) {
1677c1d255d3SCy Schubert if (sm->cfg->eap_teap_auth == 1) {
1678206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1679206b73d0SCy Schubert "EAP-TEAP: Unexpected EAP Payload TLV when trying to use Basic-Password-Auth");
1680206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1681206b73d0SCy Schubert return;
1682206b73d0SCy Schubert }
1683206b73d0SCy Schubert eap_teap_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
1684c1d255d3SCy Schubert tlv.eap_payload_tlv_len,
1685c1d255d3SCy Schubert tlv.identity_type);
1686c1d255d3SCy Schubert }
1687c1d255d3SCy Schubert
1688c1d255d3SCy Schubert if (data->state == SUCCESS_SEND_RESULT &&
1689c1d255d3SCy Schubert tlv.result == TEAP_STATUS_SUCCESS) {
1690c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1691c1d255d3SCy Schubert "EAP-TEAP: Peer agreed with final success - authentication completed");
1692c1d255d3SCy Schubert eap_teap_state(data, SUCCESS);
1693c1d255d3SCy Schubert } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
1694c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) {
1695c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1696c1d255d3SCy Schubert "EAP-TEAP: Continue with basic password authentication for second credential");
1697c1d255d3SCy Schubert eap_teap_state(data, PHASE2_BASIC_AUTH);
1698c1d255d3SCy Schubert } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
1699*a90b9d01SCy Schubert sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done &&
1700*a90b9d01SCy Schubert sm->cfg->eap_teap_method_sequence == 1) {
1701c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1702c1d255d3SCy Schubert "EAP-TEAP: Continue with inner EAP authentication for second credential");
1703c1d255d3SCy Schubert eap_teap_state(data, PHASE2_ID);
1704c1d255d3SCy Schubert if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
1705c1d255d3SCy Schubert EAP_TYPE_IDENTITY) < 0)
1706c1d255d3SCy Schubert eap_teap_state(data, FAILURE);
1707206b73d0SCy Schubert }
1708206b73d0SCy Schubert }
1709206b73d0SCy Schubert
1710206b73d0SCy Schubert
eap_teap_process_phase2(struct eap_sm * sm,struct eap_teap_data * data,struct wpabuf * in_buf)1711206b73d0SCy Schubert static void eap_teap_process_phase2(struct eap_sm *sm,
1712206b73d0SCy Schubert struct eap_teap_data *data,
1713206b73d0SCy Schubert struct wpabuf *in_buf)
1714206b73d0SCy Schubert {
1715206b73d0SCy Schubert struct wpabuf *in_decrypted;
1716206b73d0SCy Schubert
1717206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1718206b73d0SCy Schubert "EAP-TEAP: Received %lu bytes encrypted data for Phase 2",
1719206b73d0SCy Schubert (unsigned long) wpabuf_len(in_buf));
1720206b73d0SCy Schubert
1721206b73d0SCy Schubert if (data->pending_phase2_resp) {
1722206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1723206b73d0SCy Schubert "EAP-TEAP: Pending Phase 2 response - skip decryption and use old data");
1724206b73d0SCy Schubert eap_teap_process_phase2_tlvs(sm, data,
1725206b73d0SCy Schubert data->pending_phase2_resp);
1726206b73d0SCy Schubert wpabuf_free(data->pending_phase2_resp);
1727206b73d0SCy Schubert data->pending_phase2_resp = NULL;
1728206b73d0SCy Schubert return;
1729206b73d0SCy Schubert }
1730206b73d0SCy Schubert
1731c1d255d3SCy Schubert in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
1732206b73d0SCy Schubert in_buf);
1733206b73d0SCy Schubert if (!in_decrypted) {
1734206b73d0SCy Schubert wpa_printf(MSG_INFO,
1735206b73d0SCy Schubert "EAP-TEAP: Failed to decrypt Phase 2 data");
1736206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1737206b73d0SCy Schubert return;
1738206b73d0SCy Schubert }
1739206b73d0SCy Schubert
1740206b73d0SCy Schubert wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Decrypted Phase 2 TLVs",
1741206b73d0SCy Schubert in_decrypted);
1742206b73d0SCy Schubert
1743206b73d0SCy Schubert eap_teap_process_phase2_tlvs(sm, data, in_decrypted);
1744206b73d0SCy Schubert
1745206b73d0SCy Schubert if (sm->method_pending == METHOD_PENDING_WAIT) {
1746206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1747206b73d0SCy Schubert "EAP-TEAP: Phase 2 method is in pending wait state - save decrypted response");
1748206b73d0SCy Schubert wpabuf_free(data->pending_phase2_resp);
1749206b73d0SCy Schubert data->pending_phase2_resp = in_decrypted;
1750206b73d0SCy Schubert return;
1751206b73d0SCy Schubert }
1752206b73d0SCy Schubert
1753206b73d0SCy Schubert wpabuf_free(in_decrypted);
1754206b73d0SCy Schubert }
1755206b73d0SCy Schubert
1756206b73d0SCy Schubert
eap_teap_process_version(struct eap_sm * sm,void * priv,int peer_version)1757206b73d0SCy Schubert static int eap_teap_process_version(struct eap_sm *sm, void *priv,
1758206b73d0SCy Schubert int peer_version)
1759206b73d0SCy Schubert {
1760206b73d0SCy Schubert struct eap_teap_data *data = priv;
1761206b73d0SCy Schubert
1762206b73d0SCy Schubert if (peer_version < 1) {
1763206b73d0SCy Schubert /* Version 1 was the first defined version, so reject 0 */
1764206b73d0SCy Schubert wpa_printf(MSG_INFO,
1765206b73d0SCy Schubert "EAP-TEAP: Peer used unknown TEAP version %u",
1766206b73d0SCy Schubert peer_version);
1767206b73d0SCy Schubert return -1;
1768206b73d0SCy Schubert }
1769206b73d0SCy Schubert
1770206b73d0SCy Schubert if (peer_version < data->teap_version) {
1771206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: peer ver=%u, own ver=%u; "
1772206b73d0SCy Schubert "use version %u",
1773206b73d0SCy Schubert peer_version, data->teap_version, peer_version);
1774206b73d0SCy Schubert data->teap_version = peer_version;
1775206b73d0SCy Schubert }
1776206b73d0SCy Schubert
1777206b73d0SCy Schubert data->peer_version = peer_version;
1778206b73d0SCy Schubert
1779206b73d0SCy Schubert return 0;
1780206b73d0SCy Schubert }
1781206b73d0SCy Schubert
1782206b73d0SCy Schubert
eap_teap_process_phase1(struct eap_sm * sm,struct eap_teap_data * data)1783206b73d0SCy Schubert static int eap_teap_process_phase1(struct eap_sm *sm,
1784206b73d0SCy Schubert struct eap_teap_data *data)
1785206b73d0SCy Schubert {
1786206b73d0SCy Schubert if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
1787206b73d0SCy Schubert wpa_printf(MSG_INFO, "EAP-TEAP: TLS processing failed");
1788206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1789206b73d0SCy Schubert return -1;
1790206b73d0SCy Schubert }
1791206b73d0SCy Schubert
1792c1d255d3SCy Schubert if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
1793206b73d0SCy Schubert wpabuf_len(data->ssl.tls_out) > 0)
1794206b73d0SCy Schubert return 1;
1795206b73d0SCy Schubert
1796206b73d0SCy Schubert /*
1797206b73d0SCy Schubert * Phase 1 was completed with the received message (e.g., when using
1798206b73d0SCy Schubert * abbreviated handshake), so Phase 2 can be started immediately
1799206b73d0SCy Schubert * without having to send through an empty message to the peer.
1800206b73d0SCy Schubert */
1801206b73d0SCy Schubert
1802206b73d0SCy Schubert return eap_teap_phase1_done(sm, data);
1803206b73d0SCy Schubert }
1804206b73d0SCy Schubert
1805206b73d0SCy Schubert
eap_teap_process_phase2_start(struct eap_sm * sm,struct eap_teap_data * data)1806206b73d0SCy Schubert static int eap_teap_process_phase2_start(struct eap_sm *sm,
1807206b73d0SCy Schubert struct eap_teap_data *data)
1808206b73d0SCy Schubert {
1809c1d255d3SCy Schubert int next_vendor;
1810c1d255d3SCy Schubert enum eap_type next_type;
1811206b73d0SCy Schubert
1812206b73d0SCy Schubert if (data->identity) {
1813206b73d0SCy Schubert /* Used PAC and identity is from PAC-Opaque */
1814206b73d0SCy Schubert os_free(sm->identity);
1815206b73d0SCy Schubert sm->identity = data->identity;
1816206b73d0SCy Schubert data->identity = NULL;
1817206b73d0SCy Schubert sm->identity_len = data->identity_len;
1818206b73d0SCy Schubert data->identity_len = 0;
1819206b73d0SCy Schubert if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1820206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG,
1821206b73d0SCy Schubert "EAP-TEAP: Phase 2 Identity not found in the user database",
1822206b73d0SCy Schubert sm->identity, sm->identity_len);
1823c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1824206b73d0SCy Schubert next_type = EAP_TYPE_NONE;
1825206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD);
1826c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_pac_no_inner ||
1827c1d255d3SCy Schubert sm->cfg->eap_teap_auth == 2) {
1828206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1829c1d255d3SCy Schubert "EAP-TEAP: Used PAC or client certificate and identity already known - skip inner auth");
1830c1d255d3SCy Schubert data->skipped_inner_auth = 1;
1831206b73d0SCy Schubert /* FIX: Need to derive CMK here. However, how is that
1832206b73d0SCy Schubert * supposed to be done? RFC 7170 does not tell that for
1833206b73d0SCy Schubert * the no-inner-auth case. */
1834c1d255d3SCy Schubert eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
1835c1d255d3SCy Schubert data->simck_msk,
1836206b73d0SCy Schubert data->cmk_msk);
1837206b73d0SCy Schubert eap_teap_state(data, CRYPTO_BINDING);
1838206b73d0SCy Schubert return 1;
1839c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_auth == 1) {
1840206b73d0SCy Schubert eap_teap_state(data, PHASE2_BASIC_AUTH);
1841206b73d0SCy Schubert return 1;
1842206b73d0SCy Schubert } else {
1843206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1844206b73d0SCy Schubert "EAP-TEAP: Identity already known - skip Phase 2 Identity Request");
1845c1d255d3SCy Schubert next_vendor = sm->user->methods[0].vendor;
1846206b73d0SCy Schubert next_type = sm->user->methods[0].method;
1847206b73d0SCy Schubert sm->user_eap_method_index = 1;
1848206b73d0SCy Schubert eap_teap_state(data, PHASE2_METHOD);
1849206b73d0SCy Schubert }
1850206b73d0SCy Schubert
1851c1d255d3SCy Schubert } else if (sm->cfg->eap_teap_auth == 1) {
1852206b73d0SCy Schubert eap_teap_state(data, PHASE2_BASIC_AUTH);
1853206b73d0SCy Schubert return 0;
1854206b73d0SCy Schubert } else {
1855206b73d0SCy Schubert eap_teap_state(data, PHASE2_ID);
1856c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF;
1857206b73d0SCy Schubert next_type = EAP_TYPE_IDENTITY;
1858206b73d0SCy Schubert }
1859206b73d0SCy Schubert
1860c1d255d3SCy Schubert return eap_teap_phase2_init(sm, data, next_vendor, next_type);
1861206b73d0SCy Schubert }
1862206b73d0SCy Schubert
1863206b73d0SCy Schubert
eap_teap_process_msg(struct eap_sm * sm,void * priv,const struct wpabuf * respData)1864206b73d0SCy Schubert static void eap_teap_process_msg(struct eap_sm *sm, void *priv,
1865206b73d0SCy Schubert const struct wpabuf *respData)
1866206b73d0SCy Schubert {
1867206b73d0SCy Schubert struct eap_teap_data *data = priv;
1868206b73d0SCy Schubert
1869206b73d0SCy Schubert switch (data->state) {
1870206b73d0SCy Schubert case PHASE1:
1871206b73d0SCy Schubert case PHASE1B:
1872206b73d0SCy Schubert if (eap_teap_process_phase1(sm, data))
1873206b73d0SCy Schubert break;
1874206b73d0SCy Schubert
1875206b73d0SCy Schubert /* fall through */
1876206b73d0SCy Schubert case PHASE2_START:
1877206b73d0SCy Schubert eap_teap_process_phase2_start(sm, data);
1878206b73d0SCy Schubert break;
1879206b73d0SCy Schubert case PHASE2_ID:
1880206b73d0SCy Schubert case PHASE2_BASIC_AUTH:
1881206b73d0SCy Schubert case PHASE2_METHOD:
1882206b73d0SCy Schubert case CRYPTO_BINDING:
1883206b73d0SCy Schubert case REQUEST_PAC:
1884c1d255d3SCy Schubert case SUCCESS_SEND_RESULT:
1885206b73d0SCy Schubert eap_teap_process_phase2(sm, data, data->ssl.tls_in);
1886206b73d0SCy Schubert break;
1887206b73d0SCy Schubert case FAILURE_SEND_RESULT:
1888206b73d0SCy Schubert /* Protected failure result indication completed. Ignore the
1889206b73d0SCy Schubert * received message (which is supposed to include Result TLV
1890206b73d0SCy Schubert * indicating failure) and terminate exchange with cleartext
1891206b73d0SCy Schubert * EAP-Failure. */
1892206b73d0SCy Schubert eap_teap_state(data, FAILURE);
1893206b73d0SCy Schubert break;
1894206b73d0SCy Schubert default:
1895206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "EAP-TEAP: Unexpected state %d in %s",
1896206b73d0SCy Schubert data->state, __func__);
1897206b73d0SCy Schubert break;
1898206b73d0SCy Schubert }
1899206b73d0SCy Schubert }
1900206b73d0SCy Schubert
1901206b73d0SCy Schubert
eap_teap_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)1902206b73d0SCy Schubert static void eap_teap_process(struct eap_sm *sm, void *priv,
1903206b73d0SCy Schubert struct wpabuf *respData)
1904206b73d0SCy Schubert {
1905206b73d0SCy Schubert struct eap_teap_data *data = priv;
1906206b73d0SCy Schubert const u8 *pos;
1907206b73d0SCy Schubert size_t len;
1908206b73d0SCy Schubert struct wpabuf *resp = respData;
1909206b73d0SCy Schubert u8 flags;
1910206b73d0SCy Schubert
1911206b73d0SCy Schubert pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len);
1912206b73d0SCy Schubert if (!pos || len < 1)
1913206b73d0SCy Schubert return;
1914206b73d0SCy Schubert
1915206b73d0SCy Schubert flags = *pos++;
1916206b73d0SCy Schubert len--;
1917206b73d0SCy Schubert
1918206b73d0SCy Schubert if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) {
1919206b73d0SCy Schubert /* Extract Outer TLVs from the message before common TLS
1920206b73d0SCy Schubert * processing */
1921206b73d0SCy Schubert u32 message_len = 0, outer_tlv_len;
1922206b73d0SCy Schubert const u8 *hdr;
1923206b73d0SCy Schubert
1924206b73d0SCy Schubert if (data->state != PHASE1) {
1925206b73d0SCy Schubert wpa_printf(MSG_INFO,
1926206b73d0SCy Schubert "EAP-TEAP: Unexpected Outer TLVs in a message that is not the first message from the peer");
1927206b73d0SCy Schubert return;
1928206b73d0SCy Schubert }
1929206b73d0SCy Schubert
1930206b73d0SCy Schubert if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
1931206b73d0SCy Schubert if (len < 4) {
1932206b73d0SCy Schubert wpa_printf(MSG_INFO,
1933206b73d0SCy Schubert "EAP-TEAP: Too short message to include Message Length field");
1934206b73d0SCy Schubert return;
1935206b73d0SCy Schubert }
1936206b73d0SCy Schubert
1937206b73d0SCy Schubert message_len = WPA_GET_BE32(pos);
1938206b73d0SCy Schubert pos += 4;
1939206b73d0SCy Schubert len -= 4;
1940206b73d0SCy Schubert if (message_len < 4) {
1941206b73d0SCy Schubert wpa_printf(MSG_INFO,
1942206b73d0SCy Schubert "EAP-TEAP: Message Length field has too msall value to include Outer TLV Length field");
1943206b73d0SCy Schubert return;
1944206b73d0SCy Schubert }
1945206b73d0SCy Schubert }
1946206b73d0SCy Schubert
1947206b73d0SCy Schubert if (len < 4) {
1948206b73d0SCy Schubert wpa_printf(MSG_INFO,
1949206b73d0SCy Schubert "EAP-TEAP: Too short message to include Outer TLVs Length field");
1950206b73d0SCy Schubert return;
1951206b73d0SCy Schubert }
1952206b73d0SCy Schubert
1953206b73d0SCy Schubert outer_tlv_len = WPA_GET_BE32(pos);
1954206b73d0SCy Schubert pos += 4;
1955206b73d0SCy Schubert len -= 4;
1956206b73d0SCy Schubert
1957206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1958206b73d0SCy Schubert "EAP-TEAP: Message Length %u Outer TLV Length %u",
1959206b73d0SCy Schubert message_len, outer_tlv_len);
1960206b73d0SCy Schubert if (len < outer_tlv_len) {
1961206b73d0SCy Schubert wpa_printf(MSG_INFO,
1962206b73d0SCy Schubert "EAP-TEAP: Too short message to include Outer TLVs field");
1963206b73d0SCy Schubert return;
1964206b73d0SCy Schubert }
1965206b73d0SCy Schubert
1966206b73d0SCy Schubert if (message_len &&
1967206b73d0SCy Schubert (message_len < outer_tlv_len ||
1968206b73d0SCy Schubert message_len < 4 + outer_tlv_len)) {
1969206b73d0SCy Schubert wpa_printf(MSG_INFO,
1970206b73d0SCy Schubert "EAP-TEAP: Message Length field has too small value to include Outer TLVs");
1971206b73d0SCy Schubert return;
1972206b73d0SCy Schubert }
1973206b73d0SCy Schubert
1974206b73d0SCy Schubert if (wpabuf_len(respData) < 4 + outer_tlv_len ||
1975206b73d0SCy Schubert len < outer_tlv_len)
1976206b73d0SCy Schubert return;
1977206b73d0SCy Schubert resp = wpabuf_alloc(wpabuf_len(respData) - 4 - outer_tlv_len);
1978206b73d0SCy Schubert if (!resp)
1979206b73d0SCy Schubert return;
1980206b73d0SCy Schubert hdr = wpabuf_head(respData);
1981206b73d0SCy Schubert wpabuf_put_u8(resp, *hdr++); /* Code */
1982206b73d0SCy Schubert wpabuf_put_u8(resp, *hdr++); /* Identifier */
1983206b73d0SCy Schubert wpabuf_put_be16(resp, WPA_GET_BE16(hdr) - 4 - outer_tlv_len);
1984206b73d0SCy Schubert hdr += 2;
1985206b73d0SCy Schubert wpabuf_put_u8(resp, *hdr++); /* Type */
1986206b73d0SCy Schubert /* Flags | Ver */
1987206b73d0SCy Schubert wpabuf_put_u8(resp, flags & ~EAP_TEAP_FLAGS_OUTER_TLV_LEN);
1988206b73d0SCy Schubert
1989206b73d0SCy Schubert if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
1990206b73d0SCy Schubert wpabuf_put_be32(resp, message_len - 4 - outer_tlv_len);
1991206b73d0SCy Schubert
1992206b73d0SCy Schubert wpabuf_put_data(resp, pos, len - outer_tlv_len);
1993206b73d0SCy Schubert pos += len - outer_tlv_len;
1994206b73d0SCy Schubert wpabuf_free(data->peer_outer_tlvs);
1995206b73d0SCy Schubert data->peer_outer_tlvs = wpabuf_alloc_copy(pos, outer_tlv_len);
1996206b73d0SCy Schubert if (!data->peer_outer_tlvs)
1997206b73d0SCy Schubert return;
1998206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: Outer TLVs",
1999206b73d0SCy Schubert data->peer_outer_tlvs);
2000206b73d0SCy Schubert
2001206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG,
2002206b73d0SCy Schubert "EAP-TEAP: TLS Data message after Outer TLV removal",
2003206b73d0SCy Schubert resp);
2004206b73d0SCy Schubert pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, resp,
2005206b73d0SCy Schubert &len);
2006206b73d0SCy Schubert if (!pos || len < 1) {
2007206b73d0SCy Schubert wpa_printf(MSG_INFO,
2008206b73d0SCy Schubert "EAP-TEAP: Invalid frame after Outer TLV removal");
2009206b73d0SCy Schubert return;
2010206b73d0SCy Schubert }
2011206b73d0SCy Schubert }
2012206b73d0SCy Schubert
2013206b73d0SCy Schubert if (data->state == PHASE1)
2014206b73d0SCy Schubert eap_teap_state(data, PHASE1B);
2015206b73d0SCy Schubert
2016206b73d0SCy Schubert if (eap_server_tls_process(sm, &data->ssl, resp, data,
2017206b73d0SCy Schubert EAP_TYPE_TEAP, eap_teap_process_version,
2018206b73d0SCy Schubert eap_teap_process_msg) < 0)
2019206b73d0SCy Schubert eap_teap_state(data, FAILURE);
2020206b73d0SCy Schubert
2021206b73d0SCy Schubert if (resp != respData)
2022206b73d0SCy Schubert wpabuf_free(resp);
2023206b73d0SCy Schubert }
2024206b73d0SCy Schubert
2025206b73d0SCy Schubert
eap_teap_isDone(struct eap_sm * sm,void * priv)2026c1d255d3SCy Schubert static bool eap_teap_isDone(struct eap_sm *sm, void *priv)
2027206b73d0SCy Schubert {
2028206b73d0SCy Schubert struct eap_teap_data *data = priv;
2029206b73d0SCy Schubert
2030206b73d0SCy Schubert return data->state == SUCCESS || data->state == FAILURE;
2031206b73d0SCy Schubert }
2032206b73d0SCy Schubert
2033206b73d0SCy Schubert
eap_teap_getKey(struct eap_sm * sm,void * priv,size_t * len)2034206b73d0SCy Schubert static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len)
2035206b73d0SCy Schubert {
2036206b73d0SCy Schubert struct eap_teap_data *data = priv;
2037206b73d0SCy Schubert u8 *eapKeyData;
2038206b73d0SCy Schubert
2039206b73d0SCy Schubert if (data->state != SUCCESS)
2040206b73d0SCy Schubert return NULL;
2041206b73d0SCy Schubert
2042206b73d0SCy Schubert eapKeyData = os_malloc(EAP_TEAP_KEY_LEN);
2043206b73d0SCy Schubert if (!eapKeyData)
2044206b73d0SCy Schubert return NULL;
2045206b73d0SCy Schubert
2046206b73d0SCy Schubert /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
2047206b73d0SCy Schubert * is used in this derivation */
2048c1d255d3SCy Schubert if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
2049c1d255d3SCy Schubert eapKeyData) < 0) {
2050206b73d0SCy Schubert os_free(eapKeyData);
2051206b73d0SCy Schubert return NULL;
2052206b73d0SCy Schubert }
2053206b73d0SCy Schubert *len = EAP_TEAP_KEY_LEN;
2054206b73d0SCy Schubert
2055206b73d0SCy Schubert return eapKeyData;
2056206b73d0SCy Schubert }
2057206b73d0SCy Schubert
2058206b73d0SCy Schubert
eap_teap_get_emsk(struct eap_sm * sm,void * priv,size_t * len)2059206b73d0SCy Schubert static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
2060206b73d0SCy Schubert {
2061206b73d0SCy Schubert struct eap_teap_data *data = priv;
2062206b73d0SCy Schubert u8 *eapKeyData;
2063206b73d0SCy Schubert
2064206b73d0SCy Schubert if (data->state != SUCCESS)
2065206b73d0SCy Schubert return NULL;
2066206b73d0SCy Schubert
2067206b73d0SCy Schubert eapKeyData = os_malloc(EAP_EMSK_LEN);
2068206b73d0SCy Schubert if (!eapKeyData)
2069206b73d0SCy Schubert return NULL;
2070206b73d0SCy Schubert
2071206b73d0SCy Schubert /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
2072206b73d0SCy Schubert * is used in this derivation */
2073c1d255d3SCy Schubert if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
2074c1d255d3SCy Schubert eapKeyData) < 0) {
2075206b73d0SCy Schubert os_free(eapKeyData);
2076206b73d0SCy Schubert return NULL;
2077206b73d0SCy Schubert }
2078206b73d0SCy Schubert *len = EAP_EMSK_LEN;
2079206b73d0SCy Schubert
2080206b73d0SCy Schubert return eapKeyData;
2081206b73d0SCy Schubert }
2082206b73d0SCy Schubert
2083206b73d0SCy Schubert
eap_teap_isSuccess(struct eap_sm * sm,void * priv)2084c1d255d3SCy Schubert static bool eap_teap_isSuccess(struct eap_sm *sm, void *priv)
2085206b73d0SCy Schubert {
2086206b73d0SCy Schubert struct eap_teap_data *data = priv;
2087206b73d0SCy Schubert
2088206b73d0SCy Schubert return data->state == SUCCESS;
2089206b73d0SCy Schubert }
2090206b73d0SCy Schubert
2091206b73d0SCy Schubert
eap_teap_get_session_id(struct eap_sm * sm,void * priv,size_t * len)2092206b73d0SCy Schubert static u8 * eap_teap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
2093206b73d0SCy Schubert {
2094206b73d0SCy Schubert struct eap_teap_data *data = priv;
2095206b73d0SCy Schubert const size_t max_id_len = 100;
2096206b73d0SCy Schubert int res;
2097206b73d0SCy Schubert u8 *id;
2098206b73d0SCy Schubert
2099206b73d0SCy Schubert if (data->state != SUCCESS)
2100206b73d0SCy Schubert return NULL;
2101206b73d0SCy Schubert
2102206b73d0SCy Schubert id = os_malloc(max_id_len);
2103206b73d0SCy Schubert if (!id)
2104206b73d0SCy Schubert return NULL;
2105206b73d0SCy Schubert
2106206b73d0SCy Schubert id[0] = EAP_TYPE_TEAP;
2107206b73d0SCy Schubert res = tls_get_tls_unique(data->ssl.conn, id + 1, max_id_len - 1);
2108206b73d0SCy Schubert if (res < 0) {
2109206b73d0SCy Schubert os_free(id);
2110206b73d0SCy Schubert wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id");
2111206b73d0SCy Schubert return NULL;
2112206b73d0SCy Schubert }
2113206b73d0SCy Schubert
2114206b73d0SCy Schubert *len = 1 + res;
2115206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Derived Session-Id", id, *len);
2116206b73d0SCy Schubert return id;
2117206b73d0SCy Schubert }
2118206b73d0SCy Schubert
2119206b73d0SCy Schubert
eap_server_teap_register(void)2120206b73d0SCy Schubert int eap_server_teap_register(void)
2121206b73d0SCy Schubert {
2122206b73d0SCy Schubert struct eap_method *eap;
2123206b73d0SCy Schubert
2124206b73d0SCy Schubert eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
2125206b73d0SCy Schubert EAP_VENDOR_IETF, EAP_TYPE_TEAP, "TEAP");
2126206b73d0SCy Schubert if (!eap)
2127206b73d0SCy Schubert return -1;
2128206b73d0SCy Schubert
2129206b73d0SCy Schubert eap->init = eap_teap_init;
2130206b73d0SCy Schubert eap->reset = eap_teap_reset;
2131206b73d0SCy Schubert eap->buildReq = eap_teap_buildReq;
2132206b73d0SCy Schubert eap->check = eap_teap_check;
2133206b73d0SCy Schubert eap->process = eap_teap_process;
2134206b73d0SCy Schubert eap->isDone = eap_teap_isDone;
2135206b73d0SCy Schubert eap->getKey = eap_teap_getKey;
2136206b73d0SCy Schubert eap->get_emsk = eap_teap_get_emsk;
2137206b73d0SCy Schubert eap->isSuccess = eap_teap_isSuccess;
2138206b73d0SCy Schubert eap->getSessionId = eap_teap_get_session_id;
2139206b73d0SCy Schubert
2140206b73d0SCy Schubert return eap_server_method_register(eap);
2141206b73d0SCy Schubert }
2142