00001
00016 #include "includes.h"
00017
00018 #include "common.h"
00019 #include "eap_server/eap_i.h"
00020 #include "eap_common/eap_pax_common.h"
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 struct eap_pax_data {
00032 enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state;
00033 u8 mac_id;
00034 union {
00035 u8 e[2 * EAP_PAX_RAND_LEN];
00036 struct {
00037 u8 x[EAP_PAX_RAND_LEN];
00038 u8 y[EAP_PAX_RAND_LEN];
00039 } r;
00040 } rand;
00041 u8 ak[EAP_PAX_AK_LEN];
00042 u8 mk[EAP_PAX_MK_LEN];
00043 u8 ck[EAP_PAX_CK_LEN];
00044 u8 ick[EAP_PAX_ICK_LEN];
00045 int keys_set;
00046 char *cid;
00047 size_t cid_len;
00048 };
00049
00050
00051 static void * eap_pax_init(struct eap_sm *sm)
00052 {
00053 struct eap_pax_data *data;
00054
00055 data = os_zalloc(sizeof(*data));
00056 if (data == NULL)
00057 return NULL;
00058 data->state = PAX_STD_1;
00059
00060
00061
00062
00063 data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
00064
00065 return data;
00066 }
00067
00068
00069 static void eap_pax_reset(struct eap_sm *sm, void *priv)
00070 {
00071 struct eap_pax_data *data = priv;
00072 os_free(data->cid);
00073 os_free(data);
00074 }
00075
00076
00077 static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
00078 struct eap_pax_data *data, u8 id)
00079 {
00080 struct wpabuf *req;
00081 struct eap_pax_hdr *pax;
00082 u8 *pos;
00083
00084 wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
00085
00086 if (os_get_random(data->rand.r.x, EAP_PAX_RAND_LEN)) {
00087 wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
00088 data->state = FAILURE;
00089 return NULL;
00090 }
00091
00092 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
00093 sizeof(*pax) + 2 + EAP_PAX_RAND_LEN +
00094 EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
00095 if (req == NULL) {
00096 wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
00097 "request");
00098 data->state = FAILURE;
00099 return NULL;
00100 }
00101
00102 pax = wpabuf_put(req, sizeof(*pax));
00103 pax->op_code = EAP_PAX_OP_STD_1;
00104 pax->flags = 0;
00105 pax->mac_id = data->mac_id;
00106 pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
00107 pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
00108
00109 wpabuf_put_be16(req, EAP_PAX_RAND_LEN);
00110 wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN);
00111 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
00112 data->rand.r.x, EAP_PAX_RAND_LEN);
00113
00114 pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
00115 eap_pax_mac(data->mac_id, (u8 *) "", 0,
00116 wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
00117 NULL, 0, NULL, 0, pos);
00118 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
00119
00120 return req;
00121 }
00122
00123
00124 static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
00125 struct eap_pax_data *data, u8 id)
00126 {
00127 struct wpabuf *req;
00128 struct eap_pax_hdr *pax;
00129 u8 *pos;
00130
00131 wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");
00132
00133 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
00134 sizeof(*pax) + 2 + EAP_PAX_MAC_LEN +
00135 EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
00136 if (req == NULL) {
00137 wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
00138 "request");
00139 data->state = FAILURE;
00140 return NULL;
00141 }
00142
00143 pax = wpabuf_put(req, sizeof(*pax));
00144 pax->op_code = EAP_PAX_OP_STD_3;
00145 pax->flags = 0;
00146 pax->mac_id = data->mac_id;
00147 pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
00148 pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
00149
00150 wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
00151 pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
00152 eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
00153 data->rand.r.y, EAP_PAX_RAND_LEN,
00154 (u8 *) data->cid, data->cid_len, NULL, 0, pos);
00155 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
00156 pos, EAP_PAX_MAC_LEN);
00157 pos += EAP_PAX_MAC_LEN;
00158
00159
00160
00161 pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
00162 eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
00163 wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
00164 NULL, 0, NULL, 0, pos);
00165 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
00166
00167 return req;
00168 }
00169
00170
00171 static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id)
00172 {
00173 struct eap_pax_data *data = priv;
00174
00175 switch (data->state) {
00176 case PAX_STD_1:
00177 return eap_pax_build_std_1(sm, data, id);
00178 case PAX_STD_3:
00179 return eap_pax_build_std_3(sm, data, id);
00180 default:
00181 wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq",
00182 data->state);
00183 break;
00184 }
00185 return NULL;
00186 }
00187
00188
00189 static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
00190 struct wpabuf *respData)
00191 {
00192 struct eap_pax_data *data = priv;
00193 struct eap_pax_hdr *resp;
00194 const u8 *pos;
00195 size_t len, mlen;
00196 u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
00197
00198 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
00199 if (pos == NULL || len < sizeof(*resp)) {
00200 wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
00201 return TRUE;
00202 }
00203
00204 mlen = sizeof(struct eap_hdr) + 1 + len;
00205 resp = (struct eap_pax_hdr *) pos;
00206
00207 wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
00208 "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
00209 "public_key_id 0x%x",
00210 resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
00211 resp->public_key_id);
00212 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
00213 (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);
00214
00215 if (data->state == PAX_STD_1 &&
00216 resp->op_code != EAP_PAX_OP_STD_2) {
00217 wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
00218 "ignore op %d", resp->op_code);
00219 return TRUE;
00220 }
00221
00222 if (data->state == PAX_STD_3 &&
00223 resp->op_code != EAP_PAX_OP_ACK) {
00224 wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
00225 "ignore op %d", resp->op_code);
00226 return TRUE;
00227 }
00228
00229 if (resp->op_code != EAP_PAX_OP_STD_2 &&
00230 resp->op_code != EAP_PAX_OP_ACK) {
00231 wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
00232 resp->op_code);
00233 }
00234
00235 if (data->mac_id != resp->mac_id) {
00236 wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
00237 "received 0x%x", data->mac_id, resp->mac_id);
00238 return TRUE;
00239 }
00240
00241 if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
00242 wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
00243 "received 0x%x", EAP_PAX_DH_GROUP_NONE,
00244 resp->dh_group_id);
00245 return TRUE;
00246 }
00247
00248 if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
00249 wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
00250 "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
00251 resp->public_key_id);
00252 return TRUE;
00253 }
00254
00255 if (resp->flags & EAP_PAX_FLAGS_MF) {
00256
00257 wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
00258 return TRUE;
00259 }
00260
00261 if (resp->flags & EAP_PAX_FLAGS_CE) {
00262 wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
00263 return TRUE;
00264 }
00265
00266 if (data->keys_set) {
00267 if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
00268 wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
00269 return TRUE;
00270 }
00271 icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
00272 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
00273 eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
00274 wpabuf_mhead(respData),
00275 wpabuf_len(respData) - EAP_PAX_ICV_LEN,
00276 NULL, 0, NULL, 0, icvbuf);
00277 if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
00278 wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
00279 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
00280 icvbuf, EAP_PAX_ICV_LEN);
00281 return TRUE;
00282 }
00283 }
00284
00285 return FALSE;
00286 }
00287
00288
00289 static void eap_pax_process_std_2(struct eap_sm *sm,
00290 struct eap_pax_data *data,
00291 struct wpabuf *respData)
00292 {
00293 struct eap_pax_hdr *resp;
00294 u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
00295 const u8 *pos;
00296 size_t len, left;
00297 int i;
00298
00299 if (data->state != PAX_STD_1)
00300 return;
00301
00302 wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");
00303
00304 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
00305 if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN)
00306 return;
00307
00308 resp = (struct eap_pax_hdr *) pos;
00309 pos = (u8 *) (resp + 1);
00310 left = len - sizeof(*resp);
00311
00312 if (left < 2 + EAP_PAX_RAND_LEN ||
00313 WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
00314 wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
00315 return;
00316 }
00317 pos += 2;
00318 left -= 2;
00319 os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
00320 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
00321 data->rand.r.y, EAP_PAX_RAND_LEN);
00322 pos += EAP_PAX_RAND_LEN;
00323 left -= EAP_PAX_RAND_LEN;
00324
00325 if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) {
00326 wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
00327 return;
00328 }
00329 data->cid_len = WPA_GET_BE16(pos);
00330 os_free(data->cid);
00331 data->cid = os_malloc(data->cid_len);
00332 if (data->cid == NULL) {
00333 wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
00334 "CID");
00335 return;
00336 }
00337 os_memcpy(data->cid, pos + 2, data->cid_len);
00338 pos += 2 + data->cid_len;
00339 left -= 2 + data->cid_len;
00340 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
00341 (u8 *) data->cid, data->cid_len);
00342
00343 if (left < 2 + EAP_PAX_MAC_LEN ||
00344 WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
00345 wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
00346 return;
00347 }
00348 pos += 2;
00349 left -= 2;
00350 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
00351 pos, EAP_PAX_MAC_LEN);
00352
00353 if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
00354 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
00355 (u8 *) data->cid, data->cid_len);
00356 data->state = FAILURE;
00357 return;
00358 }
00359
00360 for (i = 0;
00361 i < EAP_MAX_METHODS &&
00362 (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
00363 sm->user->methods[i].method != EAP_TYPE_NONE);
00364 i++) {
00365 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
00366 sm->user->methods[i].method == EAP_TYPE_PAX)
00367 break;
00368 }
00369
00370 if (i >= EAP_MAX_METHODS ||
00371 sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
00372 sm->user->methods[i].method != EAP_TYPE_PAX) {
00373 wpa_hexdump_ascii(MSG_DEBUG,
00374 "EAP-PAX: EAP-PAX not enabled for CID",
00375 (u8 *) data->cid, data->cid_len);
00376 data->state = FAILURE;
00377 return;
00378 }
00379
00380 if (sm->user->password == NULL ||
00381 sm->user->password_len != EAP_PAX_AK_LEN) {
00382 wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
00383 "user database for CID",
00384 (u8 *) data->cid, data->cid_len);
00385 data->state = FAILURE;
00386 return;
00387 }
00388 os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);
00389
00390 if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
00391 data->rand.e, data->mk, data->ck,
00392 data->ick) < 0) {
00393 wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
00394 "key derivation");
00395 data->state = FAILURE;
00396 return;
00397 }
00398 data->keys_set = 1;
00399
00400 eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
00401 data->rand.r.x, EAP_PAX_RAND_LEN,
00402 data->rand.r.y, EAP_PAX_RAND_LEN,
00403 (u8 *) data->cid, data->cid_len, mac);
00404 if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
00405 wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
00406 "PAX_STD-2");
00407 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
00408 mac, EAP_PAX_MAC_LEN);
00409 data->state = FAILURE;
00410 return;
00411 }
00412
00413 pos += EAP_PAX_MAC_LEN;
00414 left -= EAP_PAX_MAC_LEN;
00415
00416 if (left < EAP_PAX_ICV_LEN) {
00417 wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
00418 "PAX_STD-2", (unsigned long) left);
00419 return;
00420 }
00421 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
00422 eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
00423 wpabuf_head(respData),
00424 wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
00425 icvbuf);
00426 if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
00427 wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
00428 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
00429 icvbuf, EAP_PAX_ICV_LEN);
00430 return;
00431 }
00432 pos += EAP_PAX_ICV_LEN;
00433 left -= EAP_PAX_ICV_LEN;
00434
00435 if (left > 0) {
00436 wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
00437 pos, left);
00438 }
00439
00440 data->state = PAX_STD_3;
00441 }
00442
00443
00444 static void eap_pax_process_ack(struct eap_sm *sm,
00445 struct eap_pax_data *data,
00446 struct wpabuf *respData)
00447 {
00448 if (data->state != PAX_STD_3)
00449 return;
00450
00451 wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication "
00452 "completed successfully");
00453 data->state = SUCCESS;
00454 }
00455
00456
00457 static void eap_pax_process(struct eap_sm *sm, void *priv,
00458 struct wpabuf *respData)
00459 {
00460 struct eap_pax_data *data = priv;
00461 struct eap_pax_hdr *resp;
00462 const u8 *pos;
00463 size_t len;
00464
00465 if (sm->user == NULL || sm->user->password == NULL) {
00466 wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
00467 "configured");
00468 data->state = FAILURE;
00469 return;
00470 }
00471
00472 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
00473 if (pos == NULL || len < sizeof(*resp))
00474 return;
00475
00476 resp = (struct eap_pax_hdr *) pos;
00477
00478 switch (resp->op_code) {
00479 case EAP_PAX_OP_STD_2:
00480 eap_pax_process_std_2(sm, data, respData);
00481 break;
00482 case EAP_PAX_OP_ACK:
00483 eap_pax_process_ack(sm, data, respData);
00484 break;
00485 }
00486 }
00487
00488
00489 static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
00490 {
00491 struct eap_pax_data *data = priv;
00492 return data->state == SUCCESS || data->state == FAILURE;
00493 }
00494
00495
00496 static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
00497 {
00498 struct eap_pax_data *data = priv;
00499 u8 *key;
00500
00501 if (data->state != SUCCESS)
00502 return NULL;
00503
00504 key = os_malloc(EAP_MSK_LEN);
00505 if (key == NULL)
00506 return NULL;
00507
00508 *len = EAP_MSK_LEN;
00509 eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
00510 "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
00511 EAP_MSK_LEN, key);
00512
00513 return key;
00514 }
00515
00516
00517 static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
00518 {
00519 struct eap_pax_data *data = priv;
00520 u8 *key;
00521
00522 if (data->state != SUCCESS)
00523 return NULL;
00524
00525 key = os_malloc(EAP_EMSK_LEN);
00526 if (key == NULL)
00527 return NULL;
00528
00529 *len = EAP_EMSK_LEN;
00530 eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
00531 "Extended Master Session Key",
00532 data->rand.e, 2 * EAP_PAX_RAND_LEN,
00533 EAP_EMSK_LEN, key);
00534
00535 return key;
00536 }
00537
00538
00539 static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
00540 {
00541 struct eap_pax_data *data = priv;
00542 return data->state == SUCCESS;
00543 }
00544
00545
00546 int eap_server_pax_register(void)
00547 {
00548 struct eap_method *eap;
00549 int ret;
00550
00551 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
00552 EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
00553 if (eap == NULL)
00554 return -1;
00555
00556 eap->init = eap_pax_init;
00557 eap->reset = eap_pax_reset;
00558 eap->buildReq = eap_pax_buildReq;
00559 eap->check = eap_pax_check;
00560 eap->process = eap_pax_process;
00561 eap->isDone = eap_pax_isDone;
00562 eap->getKey = eap_pax_getKey;
00563 eap->isSuccess = eap_pax_isSuccess;
00564 eap->get_emsk = eap_pax_get_emsk;
00565
00566 ret = eap_server_method_register(eap);
00567 if (ret)
00568 eap_server_method_free(eap);
00569 return ret;
00570 }
00571