Update changes file and submitted to OBS
[framework/connectivity/wpasupplicant.git] / src / eap_server / eap_server_sake.c
1 /*
2  * hostapd / EAP-SAKE (RFC 4763) server
3  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "crypto/random.h"
19 #include "eap_server/eap_i.h"
20 #include "eap_common/eap_sake_common.h"
21
22
23 struct eap_sake_data {
24         enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
25         u8 rand_s[EAP_SAKE_RAND_LEN];
26         u8 rand_p[EAP_SAKE_RAND_LEN];
27         struct {
28                 u8 auth[EAP_SAKE_TEK_AUTH_LEN];
29                 u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
30         } tek;
31         u8 msk[EAP_MSK_LEN];
32         u8 emsk[EAP_EMSK_LEN];
33         u8 session_id;
34         u8 *peerid;
35         size_t peerid_len;
36         u8 *serverid;
37         size_t serverid_len;
38 };
39
40
41 static const char * eap_sake_state_txt(int state)
42 {
43         switch (state) {
44         case IDENTITY:
45                 return "IDENTITY";
46         case CHALLENGE:
47                 return "CHALLENGE";
48         case CONFIRM:
49                 return "CONFIRM";
50         case SUCCESS:
51                 return "SUCCESS";
52         case FAILURE:
53                 return "FAILURE";
54         default:
55                 return "?";
56         }
57 }
58
59
60 static void eap_sake_state(struct eap_sake_data *data, int state)
61 {
62         wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
63                    eap_sake_state_txt(data->state),
64                    eap_sake_state_txt(state));
65         data->state = state;
66 }
67
68
69 static void * eap_sake_init(struct eap_sm *sm)
70 {
71         struct eap_sake_data *data;
72
73         data = os_zalloc(sizeof(*data));
74         if (data == NULL)
75                 return NULL;
76         data->state = CHALLENGE;
77
78         if (os_get_random(&data->session_id, 1)) {
79                 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
80                 os_free(data);
81                 return NULL;
82         }
83         wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
84                    data->session_id);
85
86         /* TODO: add support for configuring SERVERID */
87         data->serverid = (u8 *) os_strdup("hostapd");
88         if (data->serverid)
89                 data->serverid_len = os_strlen((char *) data->serverid);
90
91         return data;
92 }
93
94
95 static void eap_sake_reset(struct eap_sm *sm, void *priv)
96 {
97         struct eap_sake_data *data = priv;
98         os_free(data->serverid);
99         os_free(data->peerid);
100         os_free(data);
101 }
102
103
104 static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
105                                           u8 id, size_t length, u8 subtype)
106 {
107         struct eap_sake_hdr *sake;
108         struct wpabuf *msg;
109         size_t plen;
110
111         plen = sizeof(struct eap_sake_hdr) + length;
112
113         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
114                             EAP_CODE_REQUEST, id);
115         if (msg == NULL) {
116                 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
117                            "request");
118                 return NULL;
119         }
120
121         sake = wpabuf_put(msg, sizeof(*sake));
122         sake->version = EAP_SAKE_VERSION;
123         sake->session_id = data->session_id;
124         sake->subtype = subtype;
125
126         return msg;
127 }
128
129
130 static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
131                                                struct eap_sake_data *data,
132                                                u8 id)
133 {
134         struct wpabuf *msg;
135         size_t plen;
136
137         wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
138
139         plen = 4;
140         if (data->serverid)
141                 plen += 2 + data->serverid_len;
142         msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
143         if (msg == NULL) {
144                 data->state = FAILURE;
145                 return NULL;
146         }
147
148         wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
149         eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
150
151         if (data->serverid) {
152                 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
153                 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
154                                   data->serverid, data->serverid_len);
155         }
156
157         return msg;
158 }
159
160
161 static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
162                                                 struct eap_sake_data *data,
163                                                 u8 id)
164 {
165         struct wpabuf *msg;
166         size_t plen;
167
168         wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
169
170         if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
171                 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
172                 data->state = FAILURE;
173                 return NULL;
174         }
175         wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
176                     data->rand_s, EAP_SAKE_RAND_LEN);
177
178         plen = 2 + EAP_SAKE_RAND_LEN;
179         if (data->serverid)
180                 plen += 2 + data->serverid_len;
181         msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
182         if (msg == NULL) {
183                 data->state = FAILURE;
184                 return NULL;
185         }
186
187         wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
188         eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
189                           data->rand_s, EAP_SAKE_RAND_LEN);
190
191         if (data->serverid) {
192                 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
193                 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
194                                   data->serverid, data->serverid_len);
195         }
196
197         return msg;
198 }
199
200
201 static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
202                                               struct eap_sake_data *data,
203                                               u8 id)
204 {
205         struct wpabuf *msg;
206         u8 *mic;
207
208         wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
209
210         msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
211                                  EAP_SAKE_SUBTYPE_CONFIRM);
212         if (msg == NULL) {
213                 data->state = FAILURE;
214                 return NULL;
215         }
216
217         wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
218         wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
219         wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
220         mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
221         if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
222                                  data->serverid, data->serverid_len,
223                                  data->peerid, data->peerid_len, 0,
224                                  wpabuf_head(msg), wpabuf_len(msg), mic, mic))
225         {
226                 wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
227                 data->state = FAILURE;
228                 os_free(msg);
229                 return NULL;
230         }
231
232         return msg;
233 }
234
235
236 static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
237 {
238         struct eap_sake_data *data = priv;
239
240         switch (data->state) {
241         case IDENTITY:
242                 return eap_sake_build_identity(sm, data, id);
243         case CHALLENGE:
244                 return eap_sake_build_challenge(sm, data, id);
245         case CONFIRM:
246                 return eap_sake_build_confirm(sm, data, id);
247         default:
248                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
249                            data->state);
250                 break;
251         }
252         return NULL;
253 }
254
255
256 static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
257                               struct wpabuf *respData)
258 {
259         struct eap_sake_data *data = priv;
260         struct eap_sake_hdr *resp;
261         size_t len;
262         u8 version, session_id, subtype;
263         const u8 *pos;
264
265         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
266         if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
267                 wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
268                 return TRUE;
269         }
270
271         resp = (struct eap_sake_hdr *) pos;
272         version = resp->version;
273         session_id = resp->session_id;
274         subtype = resp->subtype;
275
276         if (version != EAP_SAKE_VERSION) {
277                 wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
278                 return TRUE;
279         }
280
281         if (session_id != data->session_id) {
282                 wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
283                            session_id, data->session_id);
284                 return TRUE;
285         }
286
287         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
288
289         if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
290                 return FALSE;
291
292         if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
293                 return FALSE;
294
295         if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
296                 return FALSE;
297
298         if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
299                 return FALSE;
300
301         wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
302                    subtype, data->state);
303
304         return TRUE;
305 }
306
307
308 static void eap_sake_process_identity(struct eap_sm *sm,
309                                       struct eap_sake_data *data,
310                                       const struct wpabuf *respData,
311                                       const u8 *payload, size_t payloadlen)
312 {
313         if (data->state != IDENTITY)
314                 return;
315
316         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
317         /* TODO: update identity and select new user data */
318         eap_sake_state(data, CHALLENGE);
319 }
320
321
322 static void eap_sake_process_challenge(struct eap_sm *sm,
323                                        struct eap_sake_data *data,
324                                        const struct wpabuf *respData,
325                                        const u8 *payload, size_t payloadlen)
326 {
327         struct eap_sake_parse_attr attr;
328         u8 mic_p[EAP_SAKE_MIC_LEN];
329
330         if (data->state != CHALLENGE)
331                 return;
332
333         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
334
335         if (eap_sake_parse_attributes(payload, payloadlen, &attr))
336                 return;
337
338         if (!attr.rand_p || !attr.mic_p) {
339                 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
340                            "include AT_RAND_P or AT_MIC_P");
341                 return;
342         }
343
344         os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
345
346         os_free(data->peerid);
347         data->peerid = NULL;
348         data->peerid_len = 0;
349         if (attr.peerid) {
350                 data->peerid = os_malloc(attr.peerid_len);
351                 if (data->peerid == NULL)
352                         return;
353                 os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
354                 data->peerid_len = attr.peerid_len;
355         }
356
357         if (sm->user == NULL || sm->user->password == NULL ||
358             sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
359                 wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
360                            "%d-byte key not configured",
361                            2 * EAP_SAKE_ROOT_SECRET_LEN);
362                 data->state = FAILURE;
363                 return;
364         }
365         eap_sake_derive_keys(sm->user->password,
366                              sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
367                              data->rand_s, data->rand_p,
368                              (u8 *) &data->tek, data->msk, data->emsk);
369
370         eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
371                              data->serverid, data->serverid_len,
372                              data->peerid, data->peerid_len, 1,
373                              wpabuf_head(respData), wpabuf_len(respData),
374                              attr.mic_p, mic_p);
375         if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
376                 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
377                 eap_sake_state(data, FAILURE);
378                 return;
379         }
380
381         eap_sake_state(data, CONFIRM);
382 }
383
384
385 static void eap_sake_process_confirm(struct eap_sm *sm,
386                                      struct eap_sake_data *data,
387                                      const struct wpabuf *respData,
388                                      const u8 *payload, size_t payloadlen)
389 {
390         struct eap_sake_parse_attr attr;
391         u8 mic_p[EAP_SAKE_MIC_LEN];
392
393         if (data->state != CONFIRM)
394                 return;
395
396         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
397
398         if (eap_sake_parse_attributes(payload, payloadlen, &attr))
399                 return;
400
401         if (!attr.mic_p) {
402                 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
403                            "include AT_MIC_P");
404                 return;
405         }
406
407         eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
408                              data->serverid, data->serverid_len,
409                              data->peerid, data->peerid_len, 1,
410                              wpabuf_head(respData), wpabuf_len(respData),
411                              attr.mic_p, mic_p);
412         if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
413                 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
414                 eap_sake_state(data, FAILURE);
415         } else
416                 eap_sake_state(data, SUCCESS);
417 }
418
419
420 static void eap_sake_process_auth_reject(struct eap_sm *sm,
421                                          struct eap_sake_data *data,
422                                          const struct wpabuf *respData,
423                                          const u8 *payload, size_t payloadlen)
424 {
425         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
426         eap_sake_state(data, FAILURE);
427 }
428
429
430 static void eap_sake_process(struct eap_sm *sm, void *priv,
431                              struct wpabuf *respData)
432 {
433         struct eap_sake_data *data = priv;
434         struct eap_sake_hdr *resp;
435         u8 subtype;
436         size_t len;
437         const u8 *pos, *end;
438
439         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
440         if (pos == NULL || len < sizeof(struct eap_sake_hdr))
441                 return;
442
443         resp = (struct eap_sake_hdr *) pos;
444         end = pos + len;
445         subtype = resp->subtype;
446         pos = (u8 *) (resp + 1);
447
448         wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
449                     pos, end - pos);
450
451         switch (subtype) {
452         case EAP_SAKE_SUBTYPE_IDENTITY:
453                 eap_sake_process_identity(sm, data, respData, pos, end - pos);
454                 break;
455         case EAP_SAKE_SUBTYPE_CHALLENGE:
456                 eap_sake_process_challenge(sm, data, respData, pos, end - pos);
457                 break;
458         case EAP_SAKE_SUBTYPE_CONFIRM:
459                 eap_sake_process_confirm(sm, data, respData, pos, end - pos);
460                 break;
461         case EAP_SAKE_SUBTYPE_AUTH_REJECT:
462                 eap_sake_process_auth_reject(sm, data, respData, pos,
463                                              end - pos);
464                 break;
465         }
466 }
467
468
469 static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
470 {
471         struct eap_sake_data *data = priv;
472         return data->state == SUCCESS || data->state == FAILURE;
473 }
474
475
476 static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
477 {
478         struct eap_sake_data *data = priv;
479         u8 *key;
480
481         if (data->state != SUCCESS)
482                 return NULL;
483
484         key = os_malloc(EAP_MSK_LEN);
485         if (key == NULL)
486                 return NULL;
487         os_memcpy(key, data->msk, EAP_MSK_LEN);
488         *len = EAP_MSK_LEN;
489
490         return key;
491 }
492
493
494 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
495 {
496         struct eap_sake_data *data = priv;
497         u8 *key;
498
499         if (data->state != SUCCESS)
500                 return NULL;
501
502         key = os_malloc(EAP_EMSK_LEN);
503         if (key == NULL)
504                 return NULL;
505         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
506         *len = EAP_EMSK_LEN;
507
508         return key;
509 }
510
511
512 static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
513 {
514         struct eap_sake_data *data = priv;
515         return data->state == SUCCESS;
516 }
517
518
519 int eap_server_sake_register(void)
520 {
521         struct eap_method *eap;
522         int ret;
523
524         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
525                                       EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
526         if (eap == NULL)
527                 return -1;
528
529         eap->init = eap_sake_init;
530         eap->reset = eap_sake_reset;
531         eap->buildReq = eap_sake_buildReq;
532         eap->check = eap_sake_check;
533         eap->process = eap_sake_process;
534         eap->isDone = eap_sake_isDone;
535         eap->getKey = eap_sake_getKey;
536         eap->isSuccess = eap_sake_isSuccess;
537         eap->get_emsk = eap_sake_get_emsk;
538
539         ret = eap_server_method_register(eap);
540         if (ret)
541                 eap_server_method_free(eap);
542         return ret;
543 }