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