139beb93cSSam Leffler /*
239beb93cSSam Leffler * EAP peer method: EAP-SAKE (RFC 4763)
34bc52338SCy Schubert * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #include "common.h"
12f05cddf9SRui Paulo #include "crypto/random.h"
1339beb93cSSam Leffler #include "eap_peer/eap_i.h"
1439beb93cSSam Leffler #include "eap_common/eap_sake_common.h"
1539beb93cSSam Leffler
1639beb93cSSam Leffler struct eap_sake_data {
1739beb93cSSam Leffler enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
1839beb93cSSam Leffler u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
1939beb93cSSam Leffler u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
2039beb93cSSam Leffler u8 rand_s[EAP_SAKE_RAND_LEN];
2139beb93cSSam Leffler u8 rand_p[EAP_SAKE_RAND_LEN];
2239beb93cSSam Leffler struct {
2339beb93cSSam Leffler u8 auth[EAP_SAKE_TEK_AUTH_LEN];
2439beb93cSSam Leffler u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
2539beb93cSSam Leffler } tek;
2639beb93cSSam Leffler u8 msk[EAP_MSK_LEN];
2739beb93cSSam Leffler u8 emsk[EAP_EMSK_LEN];
2839beb93cSSam Leffler u8 session_id;
2939beb93cSSam Leffler int session_id_set;
3039beb93cSSam Leffler u8 *peerid;
3139beb93cSSam Leffler size_t peerid_len;
3239beb93cSSam Leffler u8 *serverid;
3339beb93cSSam Leffler size_t serverid_len;
3439beb93cSSam Leffler };
3539beb93cSSam Leffler
3639beb93cSSam Leffler
eap_sake_state_txt(int state)3739beb93cSSam Leffler static const char * eap_sake_state_txt(int state)
3839beb93cSSam Leffler {
3939beb93cSSam Leffler switch (state) {
4039beb93cSSam Leffler case IDENTITY:
4139beb93cSSam Leffler return "IDENTITY";
4239beb93cSSam Leffler case CHALLENGE:
4339beb93cSSam Leffler return "CHALLENGE";
4439beb93cSSam Leffler case CONFIRM:
4539beb93cSSam Leffler return "CONFIRM";
4639beb93cSSam Leffler case SUCCESS:
4739beb93cSSam Leffler return "SUCCESS";
4839beb93cSSam Leffler case FAILURE:
4939beb93cSSam Leffler return "FAILURE";
5039beb93cSSam Leffler default:
5139beb93cSSam Leffler return "?";
5239beb93cSSam Leffler }
5339beb93cSSam Leffler }
5439beb93cSSam Leffler
5539beb93cSSam Leffler
eap_sake_state(struct eap_sake_data * data,int state)5639beb93cSSam Leffler static void eap_sake_state(struct eap_sake_data *data, int state)
5739beb93cSSam Leffler {
5839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
5939beb93cSSam Leffler eap_sake_state_txt(data->state),
6039beb93cSSam Leffler eap_sake_state_txt(state));
6139beb93cSSam Leffler data->state = state;
6239beb93cSSam Leffler }
6339beb93cSSam Leffler
6439beb93cSSam Leffler
6539beb93cSSam Leffler static void eap_sake_deinit(struct eap_sm *sm, void *priv);
6639beb93cSSam Leffler
6739beb93cSSam Leffler
eap_sake_init(struct eap_sm * sm)6839beb93cSSam Leffler static void * eap_sake_init(struct eap_sm *sm)
6939beb93cSSam Leffler {
7039beb93cSSam Leffler struct eap_sake_data *data;
7139beb93cSSam Leffler const u8 *identity, *password;
7239beb93cSSam Leffler size_t identity_len, password_len;
7339beb93cSSam Leffler
7439beb93cSSam Leffler password = eap_get_config_password(sm, &password_len);
7539beb93cSSam Leffler if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
7639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
7739beb93cSSam Leffler "configured");
7839beb93cSSam Leffler return NULL;
7939beb93cSSam Leffler }
8039beb93cSSam Leffler
8139beb93cSSam Leffler data = os_zalloc(sizeof(*data));
8239beb93cSSam Leffler if (data == NULL)
8339beb93cSSam Leffler return NULL;
8439beb93cSSam Leffler data->state = IDENTITY;
8539beb93cSSam Leffler
8639beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len);
8739beb93cSSam Leffler if (identity) {
8885732ac8SCy Schubert data->peerid = os_memdup(identity, identity_len);
8939beb93cSSam Leffler if (data->peerid == NULL) {
9039beb93cSSam Leffler eap_sake_deinit(sm, data);
9139beb93cSSam Leffler return NULL;
9239beb93cSSam Leffler }
9339beb93cSSam Leffler data->peerid_len = identity_len;
9439beb93cSSam Leffler }
9539beb93cSSam Leffler
9639beb93cSSam Leffler os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
9739beb93cSSam Leffler os_memcpy(data->root_secret_b,
9839beb93cSSam Leffler password + EAP_SAKE_ROOT_SECRET_LEN,
9939beb93cSSam Leffler EAP_SAKE_ROOT_SECRET_LEN);
10039beb93cSSam Leffler
10139beb93cSSam Leffler return data;
10239beb93cSSam Leffler }
10339beb93cSSam Leffler
10439beb93cSSam Leffler
eap_sake_deinit(struct eap_sm * sm,void * priv)10539beb93cSSam Leffler static void eap_sake_deinit(struct eap_sm *sm, void *priv)
10639beb93cSSam Leffler {
10739beb93cSSam Leffler struct eap_sake_data *data = priv;
10839beb93cSSam Leffler os_free(data->serverid);
10939beb93cSSam Leffler os_free(data->peerid);
1105b9c547cSRui Paulo bin_clear_free(data, sizeof(*data));
11139beb93cSSam Leffler }
11239beb93cSSam Leffler
11339beb93cSSam Leffler
eap_sake_build_msg(struct eap_sake_data * data,int id,size_t length,u8 subtype)11439beb93cSSam Leffler static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
11539beb93cSSam Leffler int id, size_t length, u8 subtype)
11639beb93cSSam Leffler {
11739beb93cSSam Leffler struct eap_sake_hdr *sake;
11839beb93cSSam Leffler struct wpabuf *msg;
11939beb93cSSam Leffler size_t plen;
12039beb93cSSam Leffler
12139beb93cSSam Leffler plen = length + sizeof(struct eap_sake_hdr);
12239beb93cSSam Leffler
12339beb93cSSam Leffler msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
12439beb93cSSam Leffler EAP_CODE_RESPONSE, id);
12539beb93cSSam Leffler if (msg == NULL) {
12639beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
12739beb93cSSam Leffler "request");
12839beb93cSSam Leffler return NULL;
12939beb93cSSam Leffler }
13039beb93cSSam Leffler
13139beb93cSSam Leffler sake = wpabuf_put(msg, sizeof(*sake));
13239beb93cSSam Leffler sake->version = EAP_SAKE_VERSION;
13339beb93cSSam Leffler sake->session_id = data->session_id;
13439beb93cSSam Leffler sake->subtype = subtype;
13539beb93cSSam Leffler
13639beb93cSSam Leffler return msg;
13739beb93cSSam Leffler }
13839beb93cSSam Leffler
13939beb93cSSam Leffler
eap_sake_process_identity(struct eap_sm * sm,struct eap_sake_data * data,struct eap_method_ret * ret,u8 id,const u8 * payload,size_t payload_len)14039beb93cSSam Leffler static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
14139beb93cSSam Leffler struct eap_sake_data *data,
14239beb93cSSam Leffler struct eap_method_ret *ret,
143325151a3SRui Paulo u8 id,
14439beb93cSSam Leffler const u8 *payload,
14539beb93cSSam Leffler size_t payload_len)
14639beb93cSSam Leffler {
14739beb93cSSam Leffler struct eap_sake_parse_attr attr;
14839beb93cSSam Leffler struct wpabuf *resp;
14939beb93cSSam Leffler
15039beb93cSSam Leffler if (data->state != IDENTITY) {
151*c1d255d3SCy Schubert ret->ignore = true;
15239beb93cSSam Leffler return NULL;
15339beb93cSSam Leffler }
15439beb93cSSam Leffler
15539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
15639beb93cSSam Leffler
15739beb93cSSam Leffler if (eap_sake_parse_attributes(payload, payload_len, &attr))
15839beb93cSSam Leffler return NULL;
15939beb93cSSam Leffler
16039beb93cSSam Leffler if (!attr.perm_id_req && !attr.any_id_req) {
16139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
16239beb93cSSam Leffler "AT_ANY_ID_REQ in Request/Identity");
16339beb93cSSam Leffler return NULL;
16439beb93cSSam Leffler }
16539beb93cSSam Leffler
16639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
16739beb93cSSam Leffler
168325151a3SRui Paulo resp = eap_sake_build_msg(data, id, 2 + data->peerid_len,
16939beb93cSSam Leffler EAP_SAKE_SUBTYPE_IDENTITY);
17039beb93cSSam Leffler if (resp == NULL)
17139beb93cSSam Leffler return NULL;
17239beb93cSSam Leffler
17339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
17439beb93cSSam Leffler eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
17539beb93cSSam Leffler data->peerid, data->peerid_len);
17639beb93cSSam Leffler
17739beb93cSSam Leffler eap_sake_state(data, CHALLENGE);
17839beb93cSSam Leffler
17939beb93cSSam Leffler return resp;
18039beb93cSSam Leffler }
18139beb93cSSam Leffler
18239beb93cSSam Leffler
eap_sake_process_challenge(struct eap_sm * sm,struct eap_sake_data * data,struct eap_method_ret * ret,u8 id,const u8 * payload,size_t payload_len)18339beb93cSSam Leffler static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
18439beb93cSSam Leffler struct eap_sake_data *data,
18539beb93cSSam Leffler struct eap_method_ret *ret,
186325151a3SRui Paulo u8 id,
18739beb93cSSam Leffler const u8 *payload,
18839beb93cSSam Leffler size_t payload_len)
18939beb93cSSam Leffler {
19039beb93cSSam Leffler struct eap_sake_parse_attr attr;
19139beb93cSSam Leffler struct wpabuf *resp;
19239beb93cSSam Leffler u8 *rpos;
19339beb93cSSam Leffler size_t rlen;
19439beb93cSSam Leffler
19539beb93cSSam Leffler if (data->state != IDENTITY && data->state != CHALLENGE) {
19639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
19739beb93cSSam Leffler "in unexpected state (%d)", data->state);
198*c1d255d3SCy Schubert ret->ignore = true;
19939beb93cSSam Leffler return NULL;
20039beb93cSSam Leffler }
20139beb93cSSam Leffler if (data->state == IDENTITY)
20239beb93cSSam Leffler eap_sake_state(data, CHALLENGE);
20339beb93cSSam Leffler
20439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
20539beb93cSSam Leffler
20639beb93cSSam Leffler if (eap_sake_parse_attributes(payload, payload_len, &attr))
20739beb93cSSam Leffler return NULL;
20839beb93cSSam Leffler
20939beb93cSSam Leffler if (!attr.rand_s) {
21039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
21139beb93cSSam Leffler "include AT_RAND_S");
21239beb93cSSam Leffler return NULL;
21339beb93cSSam Leffler }
21439beb93cSSam Leffler
21539beb93cSSam Leffler os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
21639beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
21739beb93cSSam Leffler data->rand_s, EAP_SAKE_RAND_LEN);
21839beb93cSSam Leffler
219f05cddf9SRui Paulo if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) {
22039beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
22139beb93cSSam Leffler return NULL;
22239beb93cSSam Leffler }
22339beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
22439beb93cSSam Leffler data->rand_p, EAP_SAKE_RAND_LEN);
22539beb93cSSam Leffler
22639beb93cSSam Leffler os_free(data->serverid);
22739beb93cSSam Leffler data->serverid = NULL;
22839beb93cSSam Leffler data->serverid_len = 0;
22939beb93cSSam Leffler if (attr.serverid) {
23039beb93cSSam Leffler wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
23139beb93cSSam Leffler attr.serverid, attr.serverid_len);
23285732ac8SCy Schubert data->serverid = os_memdup(attr.serverid, attr.serverid_len);
23339beb93cSSam Leffler if (data->serverid == NULL)
23439beb93cSSam Leffler return NULL;
23539beb93cSSam Leffler data->serverid_len = attr.serverid_len;
23639beb93cSSam Leffler }
23739beb93cSSam Leffler
2384bc52338SCy Schubert if (eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
23939beb93cSSam Leffler data->rand_s, data->rand_p,
2404bc52338SCy Schubert (u8 *) &data->tek, data->msk,
2414bc52338SCy Schubert data->emsk) < 0) {
2424bc52338SCy Schubert wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
2434bc52338SCy Schubert return NULL;
2444bc52338SCy Schubert }
24539beb93cSSam Leffler
24639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
24739beb93cSSam Leffler
24839beb93cSSam Leffler rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
24939beb93cSSam Leffler if (data->peerid)
25039beb93cSSam Leffler rlen += 2 + data->peerid_len;
251325151a3SRui Paulo resp = eap_sake_build_msg(data, id, rlen, EAP_SAKE_SUBTYPE_CHALLENGE);
25239beb93cSSam Leffler if (resp == NULL)
25339beb93cSSam Leffler return NULL;
25439beb93cSSam Leffler
25539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
25639beb93cSSam Leffler eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
25739beb93cSSam Leffler data->rand_p, EAP_SAKE_RAND_LEN);
25839beb93cSSam Leffler
25939beb93cSSam Leffler if (data->peerid) {
26039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
26139beb93cSSam Leffler eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
26239beb93cSSam Leffler data->peerid, data->peerid_len);
26339beb93cSSam Leffler }
26439beb93cSSam Leffler
26539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
26639beb93cSSam Leffler wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
26739beb93cSSam Leffler wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
26839beb93cSSam Leffler rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
26939beb93cSSam Leffler if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
27039beb93cSSam Leffler data->serverid, data->serverid_len,
27139beb93cSSam Leffler data->peerid, data->peerid_len, 1,
27239beb93cSSam Leffler wpabuf_head(resp), wpabuf_len(resp), rpos,
27339beb93cSSam Leffler rpos)) {
27439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
27539beb93cSSam Leffler wpabuf_free(resp);
27639beb93cSSam Leffler return NULL;
27739beb93cSSam Leffler }
27839beb93cSSam Leffler
27939beb93cSSam Leffler eap_sake_state(data, CONFIRM);
28039beb93cSSam Leffler
28139beb93cSSam Leffler return resp;
28239beb93cSSam Leffler }
28339beb93cSSam Leffler
28439beb93cSSam Leffler
eap_sake_process_confirm(struct eap_sm * sm,struct eap_sake_data * data,struct eap_method_ret * ret,u8 id,const struct wpabuf * reqData,const u8 * payload,size_t payload_len)28539beb93cSSam Leffler static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
28639beb93cSSam Leffler struct eap_sake_data *data,
28739beb93cSSam Leffler struct eap_method_ret *ret,
288325151a3SRui Paulo u8 id,
28939beb93cSSam Leffler const struct wpabuf *reqData,
29039beb93cSSam Leffler const u8 *payload,
29139beb93cSSam Leffler size_t payload_len)
29239beb93cSSam Leffler {
29339beb93cSSam Leffler struct eap_sake_parse_attr attr;
29439beb93cSSam Leffler u8 mic_s[EAP_SAKE_MIC_LEN];
29539beb93cSSam Leffler struct wpabuf *resp;
29639beb93cSSam Leffler u8 *rpos;
29739beb93cSSam Leffler
29839beb93cSSam Leffler if (data->state != CONFIRM) {
299*c1d255d3SCy Schubert ret->ignore = true;
30039beb93cSSam Leffler return NULL;
30139beb93cSSam Leffler }
30239beb93cSSam Leffler
30339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
30439beb93cSSam Leffler
30539beb93cSSam Leffler if (eap_sake_parse_attributes(payload, payload_len, &attr))
30639beb93cSSam Leffler return NULL;
30739beb93cSSam Leffler
30839beb93cSSam Leffler if (!attr.mic_s) {
30939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
31039beb93cSSam Leffler "include AT_MIC_S");
31139beb93cSSam Leffler return NULL;
31239beb93cSSam Leffler }
31339beb93cSSam Leffler
314780fb4a2SCy Schubert if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
31539beb93cSSam Leffler data->serverid, data->serverid_len,
31639beb93cSSam Leffler data->peerid, data->peerid_len, 0,
31739beb93cSSam Leffler wpabuf_head(reqData), wpabuf_len(reqData),
318780fb4a2SCy Schubert attr.mic_s, mic_s)) {
319780fb4a2SCy Schubert wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
320780fb4a2SCy Schubert eap_sake_state(data, FAILURE);
321780fb4a2SCy Schubert ret->methodState = METHOD_DONE;
322780fb4a2SCy Schubert ret->decision = DECISION_FAIL;
323*c1d255d3SCy Schubert ret->allowNotifications = false;
324780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
325780fb4a2SCy Schubert return eap_sake_build_msg(data, id, 0,
326780fb4a2SCy Schubert EAP_SAKE_SUBTYPE_AUTH_REJECT);
327780fb4a2SCy Schubert }
3285b9c547cSRui Paulo if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
32939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
33039beb93cSSam Leffler eap_sake_state(data, FAILURE);
33139beb93cSSam Leffler ret->methodState = METHOD_DONE;
33239beb93cSSam Leffler ret->decision = DECISION_FAIL;
333*c1d255d3SCy Schubert ret->allowNotifications = false;
33439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
33539beb93cSSam Leffler "Response/Auth-Reject");
336325151a3SRui Paulo return eap_sake_build_msg(data, id, 0,
33739beb93cSSam Leffler EAP_SAKE_SUBTYPE_AUTH_REJECT);
33839beb93cSSam Leffler }
33939beb93cSSam Leffler
34039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
34139beb93cSSam Leffler
342325151a3SRui Paulo resp = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
34339beb93cSSam Leffler EAP_SAKE_SUBTYPE_CONFIRM);
34439beb93cSSam Leffler if (resp == NULL)
34539beb93cSSam Leffler return NULL;
34639beb93cSSam Leffler
34739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
34839beb93cSSam Leffler wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
34939beb93cSSam Leffler wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
35039beb93cSSam Leffler rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
35139beb93cSSam Leffler if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
35239beb93cSSam Leffler data->serverid, data->serverid_len,
35339beb93cSSam Leffler data->peerid, data->peerid_len, 1,
35439beb93cSSam Leffler wpabuf_head(resp), wpabuf_len(resp), rpos,
35539beb93cSSam Leffler rpos)) {
35639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
35739beb93cSSam Leffler wpabuf_free(resp);
35839beb93cSSam Leffler return NULL;
35939beb93cSSam Leffler }
36039beb93cSSam Leffler
36139beb93cSSam Leffler eap_sake_state(data, SUCCESS);
36239beb93cSSam Leffler ret->methodState = METHOD_DONE;
36339beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC;
364*c1d255d3SCy Schubert ret->allowNotifications = false;
36539beb93cSSam Leffler
36639beb93cSSam Leffler return resp;
36739beb93cSSam Leffler }
36839beb93cSSam Leffler
36939beb93cSSam Leffler
eap_sake_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)37039beb93cSSam Leffler static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
37139beb93cSSam Leffler struct eap_method_ret *ret,
37239beb93cSSam Leffler const struct wpabuf *reqData)
37339beb93cSSam Leffler {
37439beb93cSSam Leffler struct eap_sake_data *data = priv;
37539beb93cSSam Leffler const struct eap_sake_hdr *req;
37639beb93cSSam Leffler struct wpabuf *resp;
37739beb93cSSam Leffler const u8 *pos, *end;
37839beb93cSSam Leffler size_t len;
379325151a3SRui Paulo u8 subtype, session_id, id;
38039beb93cSSam Leffler
38139beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
38239beb93cSSam Leffler if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
383*c1d255d3SCy Schubert ret->ignore = true;
38439beb93cSSam Leffler return NULL;
38539beb93cSSam Leffler }
38639beb93cSSam Leffler
38739beb93cSSam Leffler req = (const struct eap_sake_hdr *) pos;
38839beb93cSSam Leffler end = pos + len;
389325151a3SRui Paulo id = eap_get_id(reqData);
39039beb93cSSam Leffler subtype = req->subtype;
39139beb93cSSam Leffler session_id = req->session_id;
39239beb93cSSam Leffler pos = (const u8 *) (req + 1);
39339beb93cSSam Leffler
39439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
39539beb93cSSam Leffler "session_id %d", subtype, session_id);
39639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
39739beb93cSSam Leffler pos, end - pos);
39839beb93cSSam Leffler
39939beb93cSSam Leffler if (data->session_id_set && data->session_id != session_id) {
40039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
40139beb93cSSam Leffler session_id, data->session_id);
402*c1d255d3SCy Schubert ret->ignore = true;
40339beb93cSSam Leffler return NULL;
40439beb93cSSam Leffler }
40539beb93cSSam Leffler data->session_id = session_id;
40639beb93cSSam Leffler data->session_id_set = 1;
40739beb93cSSam Leffler
408*c1d255d3SCy Schubert ret->ignore = false;
40939beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT;
41039beb93cSSam Leffler ret->decision = DECISION_FAIL;
411*c1d255d3SCy Schubert ret->allowNotifications = true;
41239beb93cSSam Leffler
41339beb93cSSam Leffler switch (subtype) {
41439beb93cSSam Leffler case EAP_SAKE_SUBTYPE_IDENTITY:
415325151a3SRui Paulo resp = eap_sake_process_identity(sm, data, ret, id,
41639beb93cSSam Leffler pos, end - pos);
41739beb93cSSam Leffler break;
41839beb93cSSam Leffler case EAP_SAKE_SUBTYPE_CHALLENGE:
419325151a3SRui Paulo resp = eap_sake_process_challenge(sm, data, ret, id,
42039beb93cSSam Leffler pos, end - pos);
42139beb93cSSam Leffler break;
42239beb93cSSam Leffler case EAP_SAKE_SUBTYPE_CONFIRM:
423325151a3SRui Paulo resp = eap_sake_process_confirm(sm, data, ret, id, reqData,
42439beb93cSSam Leffler pos, end - pos);
42539beb93cSSam Leffler break;
42639beb93cSSam Leffler default:
42739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
42839beb93cSSam Leffler "unknown subtype %d", subtype);
429*c1d255d3SCy Schubert ret->ignore = true;
43039beb93cSSam Leffler return NULL;
43139beb93cSSam Leffler }
43239beb93cSSam Leffler
43339beb93cSSam Leffler if (ret->methodState == METHOD_DONE)
434*c1d255d3SCy Schubert ret->allowNotifications = false;
43539beb93cSSam Leffler
43639beb93cSSam Leffler return resp;
43739beb93cSSam Leffler }
43839beb93cSSam Leffler
43939beb93cSSam Leffler
eap_sake_isKeyAvailable(struct eap_sm * sm,void * priv)440*c1d255d3SCy Schubert static bool eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
44139beb93cSSam Leffler {
44239beb93cSSam Leffler struct eap_sake_data *data = priv;
44339beb93cSSam Leffler return data->state == SUCCESS;
44439beb93cSSam Leffler }
44539beb93cSSam Leffler
44639beb93cSSam Leffler
eap_sake_getKey(struct eap_sm * sm,void * priv,size_t * len)44739beb93cSSam Leffler static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
44839beb93cSSam Leffler {
44939beb93cSSam Leffler struct eap_sake_data *data = priv;
45039beb93cSSam Leffler u8 *key;
45139beb93cSSam Leffler
45239beb93cSSam Leffler if (data->state != SUCCESS)
45339beb93cSSam Leffler return NULL;
45439beb93cSSam Leffler
45585732ac8SCy Schubert key = os_memdup(data->msk, EAP_MSK_LEN);
45639beb93cSSam Leffler if (key == NULL)
45739beb93cSSam Leffler return NULL;
45839beb93cSSam Leffler *len = EAP_MSK_LEN;
45939beb93cSSam Leffler
46039beb93cSSam Leffler return key;
46139beb93cSSam Leffler }
46239beb93cSSam Leffler
46339beb93cSSam Leffler
eap_sake_get_session_id(struct eap_sm * sm,void * priv,size_t * len)4645b9c547cSRui Paulo static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
4655b9c547cSRui Paulo {
4665b9c547cSRui Paulo struct eap_sake_data *data = priv;
4675b9c547cSRui Paulo u8 *id;
4685b9c547cSRui Paulo
4695b9c547cSRui Paulo if (data->state != SUCCESS)
4705b9c547cSRui Paulo return NULL;
4715b9c547cSRui Paulo
4725b9c547cSRui Paulo *len = 1 + 2 * EAP_SAKE_RAND_LEN;
4735b9c547cSRui Paulo id = os_malloc(*len);
4745b9c547cSRui Paulo if (id == NULL)
4755b9c547cSRui Paulo return NULL;
4765b9c547cSRui Paulo
4775b9c547cSRui Paulo id[0] = EAP_TYPE_SAKE;
4785b9c547cSRui Paulo os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
4795b9c547cSRui Paulo os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
4805b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
4815b9c547cSRui Paulo
4825b9c547cSRui Paulo return id;
4835b9c547cSRui Paulo }
4845b9c547cSRui Paulo
4855b9c547cSRui Paulo
eap_sake_get_emsk(struct eap_sm * sm,void * priv,size_t * len)48639beb93cSSam Leffler static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
48739beb93cSSam Leffler {
48839beb93cSSam Leffler struct eap_sake_data *data = priv;
48939beb93cSSam Leffler u8 *key;
49039beb93cSSam Leffler
49139beb93cSSam Leffler if (data->state != SUCCESS)
49239beb93cSSam Leffler return NULL;
49339beb93cSSam Leffler
49485732ac8SCy Schubert key = os_memdup(data->emsk, EAP_EMSK_LEN);
49539beb93cSSam Leffler if (key == NULL)
49639beb93cSSam Leffler return NULL;
49739beb93cSSam Leffler *len = EAP_EMSK_LEN;
49839beb93cSSam Leffler
49939beb93cSSam Leffler return key;
50039beb93cSSam Leffler }
50139beb93cSSam Leffler
50239beb93cSSam Leffler
eap_peer_sake_register(void)50339beb93cSSam Leffler int eap_peer_sake_register(void)
50439beb93cSSam Leffler {
50539beb93cSSam Leffler struct eap_method *eap;
50639beb93cSSam Leffler
50739beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
50839beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
50939beb93cSSam Leffler if (eap == NULL)
51039beb93cSSam Leffler return -1;
51139beb93cSSam Leffler
51239beb93cSSam Leffler eap->init = eap_sake_init;
51339beb93cSSam Leffler eap->deinit = eap_sake_deinit;
51439beb93cSSam Leffler eap->process = eap_sake_process;
51539beb93cSSam Leffler eap->isKeyAvailable = eap_sake_isKeyAvailable;
51639beb93cSSam Leffler eap->getKey = eap_sake_getKey;
5175b9c547cSRui Paulo eap->getSessionId = eap_sake_get_session_id;
51839beb93cSSam Leffler eap->get_emsk = eap_sake_get_emsk;
51939beb93cSSam Leffler
520780fb4a2SCy Schubert return eap_peer_method_register(eap);
52139beb93cSSam Leffler }
522