$search
00001 /* 00002 * hostapd / EAP-SAKE (RFC 4763) server 00003 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 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 /* TODO: add support for configuring SERVERID */ 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 /* TODO: update identity and select new user data */ 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 }