$search
00001 /* 00002 * EAP peer method: EAP-SAKE (RFC 4763) 00003 * Copyright (c) 2006-2008, 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_peer/eap_i.h" 00019 #include "eap_common/eap_sake_common.h" 00020 00021 struct eap_sake_data { 00022 enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state; 00023 u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN]; 00024 u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN]; 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 int session_id_set; 00035 u8 *peerid; 00036 size_t peerid_len; 00037 u8 *serverid; 00038 size_t serverid_len; 00039 }; 00040 00041 00042 static const char * eap_sake_state_txt(int state) 00043 { 00044 switch (state) { 00045 case IDENTITY: 00046 return "IDENTITY"; 00047 case CHALLENGE: 00048 return "CHALLENGE"; 00049 case CONFIRM: 00050 return "CONFIRM"; 00051 case SUCCESS: 00052 return "SUCCESS"; 00053 case FAILURE: 00054 return "FAILURE"; 00055 default: 00056 return "?"; 00057 } 00058 } 00059 00060 00061 static void eap_sake_state(struct eap_sake_data *data, int state) 00062 { 00063 wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s", 00064 eap_sake_state_txt(data->state), 00065 eap_sake_state_txt(state)); 00066 data->state = state; 00067 } 00068 00069 00070 static void eap_sake_deinit(struct eap_sm *sm, void *priv); 00071 00072 00073 static void * eap_sake_init(struct eap_sm *sm) 00074 { 00075 struct eap_sake_data *data; 00076 const u8 *identity, *password; 00077 size_t identity_len, password_len; 00078 00079 password = eap_get_config_password(sm, &password_len); 00080 if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { 00081 wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length " 00082 "configured"); 00083 return NULL; 00084 } 00085 00086 data = os_zalloc(sizeof(*data)); 00087 if (data == NULL) 00088 return NULL; 00089 data->state = IDENTITY; 00090 00091 identity = eap_get_config_identity(sm, &identity_len); 00092 if (identity) { 00093 data->peerid = os_malloc(identity_len); 00094 if (data->peerid == NULL) { 00095 eap_sake_deinit(sm, data); 00096 return NULL; 00097 } 00098 os_memcpy(data->peerid, identity, identity_len); 00099 data->peerid_len = identity_len; 00100 } 00101 00102 os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN); 00103 os_memcpy(data->root_secret_b, 00104 password + EAP_SAKE_ROOT_SECRET_LEN, 00105 EAP_SAKE_ROOT_SECRET_LEN); 00106 00107 return data; 00108 } 00109 00110 00111 static void eap_sake_deinit(struct eap_sm *sm, void *priv) 00112 { 00113 struct eap_sake_data *data = priv; 00114 os_free(data->serverid); 00115 os_free(data->peerid); 00116 os_free(data); 00117 } 00118 00119 00120 static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data, 00121 int id, size_t length, u8 subtype) 00122 { 00123 struct eap_sake_hdr *sake; 00124 struct wpabuf *msg; 00125 size_t plen; 00126 00127 plen = length + sizeof(struct eap_sake_hdr); 00128 00129 msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen, 00130 EAP_CODE_RESPONSE, id); 00131 if (msg == NULL) { 00132 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " 00133 "request"); 00134 return NULL; 00135 } 00136 00137 sake = wpabuf_put(msg, sizeof(*sake)); 00138 sake->version = EAP_SAKE_VERSION; 00139 sake->session_id = data->session_id; 00140 sake->subtype = subtype; 00141 00142 return msg; 00143 } 00144 00145 00146 static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm, 00147 struct eap_sake_data *data, 00148 struct eap_method_ret *ret, 00149 const struct wpabuf *reqData, 00150 const u8 *payload, 00151 size_t payload_len) 00152 { 00153 struct eap_sake_parse_attr attr; 00154 struct wpabuf *resp; 00155 00156 if (data->state != IDENTITY) { 00157 ret->ignore = TRUE; 00158 return NULL; 00159 } 00160 00161 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity"); 00162 00163 if (eap_sake_parse_attributes(payload, payload_len, &attr)) 00164 return NULL; 00165 00166 if (!attr.perm_id_req && !attr.any_id_req) { 00167 wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or " 00168 "AT_ANY_ID_REQ in Request/Identity"); 00169 return NULL; 00170 } 00171 00172 wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity"); 00173 00174 resp = eap_sake_build_msg(data, eap_get_id(reqData), 00175 2 + data->peerid_len, 00176 EAP_SAKE_SUBTYPE_IDENTITY); 00177 if (resp == NULL) 00178 return NULL; 00179 00180 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); 00181 eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, 00182 data->peerid, data->peerid_len); 00183 00184 eap_sake_state(data, CHALLENGE); 00185 00186 return resp; 00187 } 00188 00189 00190 static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm, 00191 struct eap_sake_data *data, 00192 struct eap_method_ret *ret, 00193 const struct wpabuf *reqData, 00194 const u8 *payload, 00195 size_t payload_len) 00196 { 00197 struct eap_sake_parse_attr attr; 00198 struct wpabuf *resp; 00199 u8 *rpos; 00200 size_t rlen; 00201 00202 if (data->state != IDENTITY && data->state != CHALLENGE) { 00203 wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received " 00204 "in unexpected state (%d)", data->state); 00205 ret->ignore = TRUE; 00206 return NULL; 00207 } 00208 if (data->state == IDENTITY) 00209 eap_sake_state(data, CHALLENGE); 00210 00211 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge"); 00212 00213 if (eap_sake_parse_attributes(payload, payload_len, &attr)) 00214 return NULL; 00215 00216 if (!attr.rand_s) { 00217 wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not " 00218 "include AT_RAND_S"); 00219 return NULL; 00220 } 00221 00222 os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN); 00223 wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", 00224 data->rand_s, EAP_SAKE_RAND_LEN); 00225 00226 if (os_get_random(data->rand_p, EAP_SAKE_RAND_LEN)) { 00227 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); 00228 return NULL; 00229 } 00230 wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)", 00231 data->rand_p, EAP_SAKE_RAND_LEN); 00232 00233 os_free(data->serverid); 00234 data->serverid = NULL; 00235 data->serverid_len = 0; 00236 if (attr.serverid) { 00237 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID", 00238 attr.serverid, attr.serverid_len); 00239 data->serverid = os_malloc(attr.serverid_len); 00240 if (data->serverid == NULL) 00241 return NULL; 00242 os_memcpy(data->serverid, attr.serverid, attr.serverid_len); 00243 data->serverid_len = attr.serverid_len; 00244 } 00245 00246 eap_sake_derive_keys(data->root_secret_a, data->root_secret_b, 00247 data->rand_s, data->rand_p, 00248 (u8 *) &data->tek, data->msk, data->emsk); 00249 00250 wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge"); 00251 00252 rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN; 00253 if (data->peerid) 00254 rlen += 2 + data->peerid_len; 00255 resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen, 00256 EAP_SAKE_SUBTYPE_CHALLENGE); 00257 if (resp == NULL) 00258 return NULL; 00259 00260 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P"); 00261 eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P, 00262 data->rand_p, EAP_SAKE_RAND_LEN); 00263 00264 if (data->peerid) { 00265 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); 00266 eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, 00267 data->peerid, data->peerid_len); 00268 } 00269 00270 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); 00271 wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); 00272 wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); 00273 rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); 00274 if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, 00275 data->serverid, data->serverid_len, 00276 data->peerid, data->peerid_len, 1, 00277 wpabuf_head(resp), wpabuf_len(resp), rpos, 00278 rpos)) { 00279 wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); 00280 wpabuf_free(resp); 00281 return NULL; 00282 } 00283 00284 eap_sake_state(data, CONFIRM); 00285 00286 return resp; 00287 } 00288 00289 00290 static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm, 00291 struct eap_sake_data *data, 00292 struct eap_method_ret *ret, 00293 const struct wpabuf *reqData, 00294 const u8 *payload, 00295 size_t payload_len) 00296 { 00297 struct eap_sake_parse_attr attr; 00298 u8 mic_s[EAP_SAKE_MIC_LEN]; 00299 struct wpabuf *resp; 00300 u8 *rpos; 00301 00302 if (data->state != CONFIRM) { 00303 ret->ignore = TRUE; 00304 return NULL; 00305 } 00306 00307 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm"); 00308 00309 if (eap_sake_parse_attributes(payload, payload_len, &attr)) 00310 return NULL; 00311 00312 if (!attr.mic_s) { 00313 wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not " 00314 "include AT_MIC_S"); 00315 return NULL; 00316 } 00317 00318 eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, 00319 data->serverid, data->serverid_len, 00320 data->peerid, data->peerid_len, 0, 00321 wpabuf_head(reqData), wpabuf_len(reqData), 00322 attr.mic_s, mic_s); 00323 if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) { 00324 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S"); 00325 eap_sake_state(data, FAILURE); 00326 ret->methodState = METHOD_DONE; 00327 ret->decision = DECISION_FAIL; 00328 ret->allowNotifications = FALSE; 00329 wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending " 00330 "Response/Auth-Reject"); 00331 return eap_sake_build_msg(data, eap_get_id(reqData), 0, 00332 EAP_SAKE_SUBTYPE_AUTH_REJECT); 00333 } 00334 00335 wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm"); 00336 00337 resp = eap_sake_build_msg(data, eap_get_id(reqData), 00338 2 + EAP_SAKE_MIC_LEN, 00339 EAP_SAKE_SUBTYPE_CONFIRM); 00340 if (resp == NULL) 00341 return NULL; 00342 00343 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); 00344 wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); 00345 wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); 00346 rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); 00347 if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, 00348 data->serverid, data->serverid_len, 00349 data->peerid, data->peerid_len, 1, 00350 wpabuf_head(resp), wpabuf_len(resp), rpos, 00351 rpos)) { 00352 wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); 00353 wpabuf_free(resp); 00354 return NULL; 00355 } 00356 00357 eap_sake_state(data, SUCCESS); 00358 ret->methodState = METHOD_DONE; 00359 ret->decision = DECISION_UNCOND_SUCC; 00360 ret->allowNotifications = FALSE; 00361 00362 return resp; 00363 } 00364 00365 00366 static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv, 00367 struct eap_method_ret *ret, 00368 const struct wpabuf *reqData) 00369 { 00370 struct eap_sake_data *data = priv; 00371 const struct eap_sake_hdr *req; 00372 struct wpabuf *resp; 00373 const u8 *pos, *end; 00374 size_t len; 00375 u8 subtype, session_id; 00376 00377 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len); 00378 if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { 00379 ret->ignore = TRUE; 00380 return NULL; 00381 } 00382 00383 req = (const struct eap_sake_hdr *) pos; 00384 end = pos + len; 00385 subtype = req->subtype; 00386 session_id = req->session_id; 00387 pos = (const u8 *) (req + 1); 00388 00389 wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d " 00390 "session_id %d", subtype, session_id); 00391 wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", 00392 pos, end - pos); 00393 00394 if (data->session_id_set && data->session_id != session_id) { 00395 wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", 00396 session_id, data->session_id); 00397 ret->ignore = TRUE; 00398 return NULL; 00399 } 00400 data->session_id = session_id; 00401 data->session_id_set = 1; 00402 00403 ret->ignore = FALSE; 00404 ret->methodState = METHOD_MAY_CONT; 00405 ret->decision = DECISION_FAIL; 00406 ret->allowNotifications = TRUE; 00407 00408 switch (subtype) { 00409 case EAP_SAKE_SUBTYPE_IDENTITY: 00410 resp = eap_sake_process_identity(sm, data, ret, reqData, 00411 pos, end - pos); 00412 break; 00413 case EAP_SAKE_SUBTYPE_CHALLENGE: 00414 resp = eap_sake_process_challenge(sm, data, ret, reqData, 00415 pos, end - pos); 00416 break; 00417 case EAP_SAKE_SUBTYPE_CONFIRM: 00418 resp = eap_sake_process_confirm(sm, data, ret, reqData, 00419 pos, end - pos); 00420 break; 00421 default: 00422 wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with " 00423 "unknown subtype %d", subtype); 00424 ret->ignore = TRUE; 00425 return NULL; 00426 } 00427 00428 if (ret->methodState == METHOD_DONE) 00429 ret->allowNotifications = FALSE; 00430 00431 return resp; 00432 } 00433 00434 00435 static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv) 00436 { 00437 struct eap_sake_data *data = priv; 00438 return data->state == SUCCESS; 00439 } 00440 00441 00442 static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len) 00443 { 00444 struct eap_sake_data *data = priv; 00445 u8 *key; 00446 00447 if (data->state != SUCCESS) 00448 return NULL; 00449 00450 key = os_malloc(EAP_MSK_LEN); 00451 if (key == NULL) 00452 return NULL; 00453 os_memcpy(key, data->msk, EAP_MSK_LEN); 00454 *len = EAP_MSK_LEN; 00455 00456 return key; 00457 } 00458 00459 00460 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 00461 { 00462 struct eap_sake_data *data = priv; 00463 u8 *key; 00464 00465 if (data->state != SUCCESS) 00466 return NULL; 00467 00468 key = os_malloc(EAP_EMSK_LEN); 00469 if (key == NULL) 00470 return NULL; 00471 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 00472 *len = EAP_EMSK_LEN; 00473 00474 return key; 00475 } 00476 00477 00478 int eap_peer_sake_register(void) 00479 { 00480 struct eap_method *eap; 00481 int ret; 00482 00483 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 00484 EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE"); 00485 if (eap == NULL) 00486 return -1; 00487 00488 eap->init = eap_sake_init; 00489 eap->deinit = eap_sake_deinit; 00490 eap->process = eap_sake_process; 00491 eap->isKeyAvailable = eap_sake_isKeyAvailable; 00492 eap->getKey = eap_sake_getKey; 00493 eap->get_emsk = eap_sake_get_emsk; 00494 00495 ret = eap_peer_method_register(eap); 00496 if (ret) 00497 eap_peer_method_free(eap); 00498 return ret; 00499 }