00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "includes.h"
00016
00017 #include "common.h"
00018 #include "eap_server/eap_i.h"
00019 #include "eap_common/eap_sake_common.h"
00020
00021
00022 struct eap_sake_data {
00023 enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
00024 u8 rand_s[EAP_SAKE_RAND_LEN];
00025 u8 rand_p[EAP_SAKE_RAND_LEN];
00026 struct {
00027 u8 auth[EAP_SAKE_TEK_AUTH_LEN];
00028 u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
00029 } tek;
00030 u8 msk[EAP_MSK_LEN];
00031 u8 emsk[EAP_EMSK_LEN];
00032 u8 session_id;
00033 u8 *peerid;
00034 size_t peerid_len;
00035 u8 *serverid;
00036 size_t serverid_len;
00037 };
00038
00039
00040 static const char * eap_sake_state_txt(int state)
00041 {
00042 switch (state) {
00043 case IDENTITY:
00044 return "IDENTITY";
00045 case CHALLENGE:
00046 return "CHALLENGE";
00047 case CONFIRM:
00048 return "CONFIRM";
00049 case SUCCESS:
00050 return "SUCCESS";
00051 case FAILURE:
00052 return "FAILURE";
00053 default:
00054 return "?";
00055 }
00056 }
00057
00058
00059 static void eap_sake_state(struct eap_sake_data *data, int state)
00060 {
00061 wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
00062 eap_sake_state_txt(data->state),
00063 eap_sake_state_txt(state));
00064 data->state = state;
00065 }
00066
00067
00068 static void * eap_sake_init(struct eap_sm *sm)
00069 {
00070 struct eap_sake_data *data;
00071
00072 data = os_zalloc(sizeof(*data));
00073 if (data == NULL)
00074 return NULL;
00075 data->state = CHALLENGE;
00076
00077 if (os_get_random(&data->session_id, 1)) {
00078 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
00079 os_free(data);
00080 return NULL;
00081 }
00082 wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
00083 data->session_id);
00084
00085
00086 data->serverid = (u8 *) os_strdup("hostapd");
00087 if (data->serverid)
00088 data->serverid_len = os_strlen((char *) data->serverid);
00089
00090 return data;
00091 }
00092
00093
00094 static void eap_sake_reset(struct eap_sm *sm, void *priv)
00095 {
00096 struct eap_sake_data *data = priv;
00097 os_free(data->serverid);
00098 os_free(data->peerid);
00099 os_free(data);
00100 }
00101
00102
00103 static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
00104 u8 id, size_t length, u8 subtype)
00105 {
00106 struct eap_sake_hdr *sake;
00107 struct wpabuf *msg;
00108 size_t plen;
00109
00110 plen = sizeof(struct eap_sake_hdr) + length;
00111
00112 msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
00113 EAP_CODE_REQUEST, id);
00114 if (msg == NULL) {
00115 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
00116 "request");
00117 return NULL;
00118 }
00119
00120 sake = wpabuf_put(msg, sizeof(*sake));
00121 sake->version = EAP_SAKE_VERSION;
00122 sake->session_id = data->session_id;
00123 sake->subtype = subtype;
00124
00125 return msg;
00126 }
00127
00128
00129 static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
00130 struct eap_sake_data *data,
00131 u8 id)
00132 {
00133 struct wpabuf *msg;
00134 size_t plen;
00135
00136 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
00137
00138 plen = 4;
00139 if (data->serverid)
00140 plen += 2 + data->serverid_len;
00141 msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
00142 if (msg == NULL) {
00143 data->state = FAILURE;
00144 return NULL;
00145 }
00146
00147 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
00148 eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
00149
00150 if (data->serverid) {
00151 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
00152 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
00153 data->serverid, data->serverid_len);
00154 }
00155
00156 return msg;
00157 }
00158
00159
00160 static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
00161 struct eap_sake_data *data,
00162 u8 id)
00163 {
00164 struct wpabuf *msg;
00165 size_t plen;
00166
00167 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
00168
00169 if (os_get_random(data->rand_s, EAP_SAKE_RAND_LEN)) {
00170 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
00171 data->state = FAILURE;
00172 return NULL;
00173 }
00174 wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
00175 data->rand_s, EAP_SAKE_RAND_LEN);
00176
00177 plen = 2 + EAP_SAKE_RAND_LEN;
00178 if (data->serverid)
00179 plen += 2 + data->serverid_len;
00180 msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
00181 if (msg == NULL) {
00182 data->state = FAILURE;
00183 return NULL;
00184 }
00185
00186 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
00187 eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
00188 data->rand_s, EAP_SAKE_RAND_LEN);
00189
00190 if (data->serverid) {
00191 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
00192 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
00193 data->serverid, data->serverid_len);
00194 }
00195
00196 return msg;
00197 }
00198
00199
00200 static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
00201 struct eap_sake_data *data,
00202 u8 id)
00203 {
00204 struct wpabuf *msg;
00205 u8 *mic;
00206
00207 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
00208
00209 msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
00210 EAP_SAKE_SUBTYPE_CONFIRM);
00211 if (msg == NULL) {
00212 data->state = FAILURE;
00213 return NULL;
00214 }
00215
00216 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
00217 wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
00218 wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
00219 mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
00220 if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
00221 data->serverid, data->serverid_len,
00222 data->peerid, data->peerid_len, 0,
00223 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
00224 {
00225 wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
00226 data->state = FAILURE;
00227 os_free(msg);
00228 return NULL;
00229 }
00230
00231 return msg;
00232 }
00233
00234
00235 static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
00236 {
00237 struct eap_sake_data *data = priv;
00238
00239 switch (data->state) {
00240 case IDENTITY:
00241 return eap_sake_build_identity(sm, data, id);
00242 case CHALLENGE:
00243 return eap_sake_build_challenge(sm, data, id);
00244 case CONFIRM:
00245 return eap_sake_build_confirm(sm, data, id);
00246 default:
00247 wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
00248 data->state);
00249 break;
00250 }
00251 return NULL;
00252 }
00253
00254
00255 static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
00256 struct wpabuf *respData)
00257 {
00258 struct eap_sake_data *data = priv;
00259 struct eap_sake_hdr *resp;
00260 size_t len;
00261 u8 version, session_id, subtype;
00262 const u8 *pos;
00263
00264 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
00265 if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
00266 wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
00267 return TRUE;
00268 }
00269
00270 resp = (struct eap_sake_hdr *) pos;
00271 version = resp->version;
00272 session_id = resp->session_id;
00273 subtype = resp->subtype;
00274
00275 if (version != EAP_SAKE_VERSION) {
00276 wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
00277 return TRUE;
00278 }
00279
00280 if (session_id != data->session_id) {
00281 wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
00282 session_id, data->session_id);
00283 return TRUE;
00284 }
00285
00286 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
00287
00288 if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
00289 return FALSE;
00290
00291 if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
00292 return FALSE;
00293
00294 if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
00295 return FALSE;
00296
00297 if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
00298 return FALSE;
00299
00300 wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
00301 subtype, data->state);
00302
00303 return TRUE;
00304 }
00305
00306
00307 static void eap_sake_process_identity(struct eap_sm *sm,
00308 struct eap_sake_data *data,
00309 const struct wpabuf *respData,
00310 const u8 *payload, size_t payloadlen)
00311 {
00312 if (data->state != IDENTITY)
00313 return;
00314
00315 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
00316
00317 eap_sake_state(data, CHALLENGE);
00318 }
00319
00320
00321 static void eap_sake_process_challenge(struct eap_sm *sm,
00322 struct eap_sake_data *data,
00323 const struct wpabuf *respData,
00324 const u8 *payload, size_t payloadlen)
00325 {
00326 struct eap_sake_parse_attr attr;
00327 u8 mic_p[EAP_SAKE_MIC_LEN];
00328
00329 if (data->state != CHALLENGE)
00330 return;
00331
00332 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
00333
00334 if (eap_sake_parse_attributes(payload, payloadlen, &attr))
00335 return;
00336
00337 if (!attr.rand_p || !attr.mic_p) {
00338 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
00339 "include AT_RAND_P or AT_MIC_P");
00340 return;
00341 }
00342
00343 os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
00344
00345 os_free(data->peerid);
00346 data->peerid = NULL;
00347 data->peerid_len = 0;
00348 if (attr.peerid) {
00349 data->peerid = os_malloc(attr.peerid_len);
00350 if (data->peerid == NULL)
00351 return;
00352 os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
00353 data->peerid_len = attr.peerid_len;
00354 }
00355
00356 if (sm->user == NULL || sm->user->password == NULL ||
00357 sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
00358 wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
00359 "%d-byte key not configured",
00360 2 * EAP_SAKE_ROOT_SECRET_LEN);
00361 data->state = FAILURE;
00362 return;
00363 }
00364 eap_sake_derive_keys(sm->user->password,
00365 sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
00366 data->rand_s, data->rand_p,
00367 (u8 *) &data->tek, data->msk, data->emsk);
00368
00369 eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
00370 data->serverid, data->serverid_len,
00371 data->peerid, data->peerid_len, 1,
00372 wpabuf_head(respData), wpabuf_len(respData),
00373 attr.mic_p, mic_p);
00374 if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
00375 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
00376 eap_sake_state(data, FAILURE);
00377 return;
00378 }
00379
00380 eap_sake_state(data, CONFIRM);
00381 }
00382
00383
00384 static void eap_sake_process_confirm(struct eap_sm *sm,
00385 struct eap_sake_data *data,
00386 const struct wpabuf *respData,
00387 const u8 *payload, size_t payloadlen)
00388 {
00389 struct eap_sake_parse_attr attr;
00390 u8 mic_p[EAP_SAKE_MIC_LEN];
00391
00392 if (data->state != CONFIRM)
00393 return;
00394
00395 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
00396
00397 if (eap_sake_parse_attributes(payload, payloadlen, &attr))
00398 return;
00399
00400 if (!attr.mic_p) {
00401 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
00402 "include AT_MIC_P");
00403 return;
00404 }
00405
00406 eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
00407 data->serverid, data->serverid_len,
00408 data->peerid, data->peerid_len, 1,
00409 wpabuf_head(respData), wpabuf_len(respData),
00410 attr.mic_p, mic_p);
00411 if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
00412 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
00413 eap_sake_state(data, FAILURE);
00414 } else
00415 eap_sake_state(data, SUCCESS);
00416 }
00417
00418
00419 static void eap_sake_process_auth_reject(struct eap_sm *sm,
00420 struct eap_sake_data *data,
00421 const struct wpabuf *respData,
00422 const u8 *payload, size_t payloadlen)
00423 {
00424 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
00425 eap_sake_state(data, FAILURE);
00426 }
00427
00428
00429 static void eap_sake_process(struct eap_sm *sm, void *priv,
00430 struct wpabuf *respData)
00431 {
00432 struct eap_sake_data *data = priv;
00433 struct eap_sake_hdr *resp;
00434 u8 subtype;
00435 size_t len;
00436 const u8 *pos, *end;
00437
00438 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
00439 if (pos == NULL || len < sizeof(struct eap_sake_hdr))
00440 return;
00441
00442 resp = (struct eap_sake_hdr *) pos;
00443 end = pos + len;
00444 subtype = resp->subtype;
00445 pos = (u8 *) (resp + 1);
00446
00447 wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
00448 pos, end - pos);
00449
00450 switch (subtype) {
00451 case EAP_SAKE_SUBTYPE_IDENTITY:
00452 eap_sake_process_identity(sm, data, respData, pos, end - pos);
00453 break;
00454 case EAP_SAKE_SUBTYPE_CHALLENGE:
00455 eap_sake_process_challenge(sm, data, respData, pos, end - pos);
00456 break;
00457 case EAP_SAKE_SUBTYPE_CONFIRM:
00458 eap_sake_process_confirm(sm, data, respData, pos, end - pos);
00459 break;
00460 case EAP_SAKE_SUBTYPE_AUTH_REJECT:
00461 eap_sake_process_auth_reject(sm, data, respData, pos,
00462 end - pos);
00463 break;
00464 }
00465 }
00466
00467
00468 static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
00469 {
00470 struct eap_sake_data *data = priv;
00471 return data->state == SUCCESS || data->state == FAILURE;
00472 }
00473
00474
00475 static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
00476 {
00477 struct eap_sake_data *data = priv;
00478 u8 *key;
00479
00480 if (data->state != SUCCESS)
00481 return NULL;
00482
00483 key = os_malloc(EAP_MSK_LEN);
00484 if (key == NULL)
00485 return NULL;
00486 os_memcpy(key, data->msk, EAP_MSK_LEN);
00487 *len = EAP_MSK_LEN;
00488
00489 return key;
00490 }
00491
00492
00493 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
00494 {
00495 struct eap_sake_data *data = priv;
00496 u8 *key;
00497
00498 if (data->state != SUCCESS)
00499 return NULL;
00500
00501 key = os_malloc(EAP_EMSK_LEN);
00502 if (key == NULL)
00503 return NULL;
00504 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
00505 *len = EAP_EMSK_LEN;
00506
00507 return key;
00508 }
00509
00510
00511 static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
00512 {
00513 struct eap_sake_data *data = priv;
00514 return data->state == SUCCESS;
00515 }
00516
00517
00518 int eap_server_sake_register(void)
00519 {
00520 struct eap_method *eap;
00521 int ret;
00522
00523 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
00524 EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
00525 if (eap == NULL)
00526 return -1;
00527
00528 eap->init = eap_sake_init;
00529 eap->reset = eap_sake_reset;
00530 eap->buildReq = eap_sake_buildReq;
00531 eap->check = eap_sake_check;
00532 eap->process = eap_sake_process;
00533 eap->isDone = eap_sake_isDone;
00534 eap->getKey = eap_sake_getKey;
00535 eap->isSuccess = eap_sake_isSuccess;
00536 eap->get_emsk = eap_sake_get_emsk;
00537
00538 ret = eap_server_method_register(eap);
00539 if (ret)
00540 eap_server_method_free(eap);
00541 return ret;
00542 }