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