eap_psk.c
Go to the documentation of this file.
00001 /*
00002  * EAP peer method: EAP-PSK (RFC 4764)
00003  * Copyright (c) 2004-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  * Note: EAP-PSK is an EAP authentication method and as such, completely
00015  * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
00016  */
00017 
00018 #include "includes.h"
00019 
00020 #include "common.h"
00021 #include "crypto/aes_wrap.h"
00022 #include "eap_common/eap_psk_common.h"
00023 #include "eap_i.h"
00024 
00025 
00026 struct eap_psk_data {
00027         enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
00028         u8 rand_p[EAP_PSK_RAND_LEN];
00029         u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
00030         u8 *id_s, *id_p;
00031         size_t id_s_len, id_p_len;
00032         u8 msk[EAP_MSK_LEN];
00033         u8 emsk[EAP_EMSK_LEN];
00034 };
00035 
00036 
00037 static void * eap_psk_init(struct eap_sm *sm)
00038 {
00039         struct eap_psk_data *data;
00040         const u8 *identity, *password;
00041         size_t identity_len, password_len;
00042 
00043         password = eap_get_config_password(sm, &password_len);
00044         if (!password || password_len != 16) {
00045                 wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not "
00046                            "configured");
00047                 return NULL;
00048         }
00049 
00050         data = os_zalloc(sizeof(*data));
00051         if (data == NULL)
00052                 return NULL;
00053         if (eap_psk_key_setup(password, data->ak, data->kdk)) {
00054                 os_free(data);
00055                 return NULL;
00056         }
00057         wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
00058         wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
00059         data->state = PSK_INIT;
00060 
00061         identity = eap_get_config_identity(sm, &identity_len);
00062         if (identity) {
00063                 data->id_p = os_malloc(identity_len);
00064                 if (data->id_p)
00065                         os_memcpy(data->id_p, identity, identity_len);
00066                 data->id_p_len = identity_len;
00067         }
00068         if (data->id_p == NULL) {
00069                 wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
00070                 os_free(data);
00071                 return NULL;
00072         }
00073 
00074         return data;
00075 }
00076 
00077 
00078 static void eap_psk_deinit(struct eap_sm *sm, void *priv)
00079 {
00080         struct eap_psk_data *data = priv;
00081         os_free(data->id_s);
00082         os_free(data->id_p);
00083         os_free(data);
00084 }
00085 
00086 
00087 static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
00088                                          struct eap_method_ret *ret,
00089                                          const struct wpabuf *reqData)
00090 {
00091         const struct eap_psk_hdr_1 *hdr1;
00092         struct eap_psk_hdr_2 *hdr2;
00093         struct wpabuf *resp;
00094         u8 *buf, *pos;
00095         size_t buflen, len;
00096         const u8 *cpos;
00097 
00098         wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
00099 
00100         cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
00101         hdr1 = (const struct eap_psk_hdr_1 *) cpos;
00102         if (cpos == NULL || len < sizeof(*hdr1)) {
00103                 wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
00104                            "length (%lu; expected %lu or more)",
00105                            (unsigned long) len,
00106                            (unsigned long) sizeof(*hdr1));
00107                 ret->ignore = TRUE;
00108                 return NULL;
00109         }
00110         wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
00111         if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
00112                 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
00113                            EAP_PSK_FLAGS_GET_T(hdr1->flags));
00114                 ret->methodState = METHOD_DONE;
00115                 ret->decision = DECISION_FAIL;
00116                 return NULL;
00117         }
00118         wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
00119                     EAP_PSK_RAND_LEN);
00120         os_free(data->id_s);
00121         data->id_s_len = len - sizeof(*hdr1);
00122         data->id_s = os_malloc(data->id_s_len);
00123         if (data->id_s == NULL) {
00124                 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
00125                            "ID_S (len=%lu)", (unsigned long) data->id_s_len);
00126                 ret->ignore = TRUE;
00127                 return NULL;
00128         }
00129         os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
00130         wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
00131                           data->id_s, data->id_s_len);
00132 
00133         if (os_get_random(data->rand_p, EAP_PSK_RAND_LEN)) {
00134                 wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
00135                 ret->ignore = TRUE;
00136                 return NULL;
00137         }
00138 
00139         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
00140                              sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE,
00141                              eap_get_id(reqData));
00142         if (resp == NULL)
00143                 return NULL;
00144         hdr2 = wpabuf_put(resp, sizeof(*hdr2));
00145         hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
00146         os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
00147         os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
00148         wpabuf_put_data(resp, data->id_p, data->id_p_len);
00149         /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
00150         buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
00151         buf = os_malloc(buflen);
00152         if (buf == NULL) {
00153                 wpabuf_free(resp);
00154                 return NULL;
00155         }
00156         os_memcpy(buf, data->id_p, data->id_p_len);
00157         pos = buf + data->id_p_len;
00158         os_memcpy(pos, data->id_s, data->id_s_len);
00159         pos += data->id_s_len;
00160         os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
00161         pos += EAP_PSK_RAND_LEN;
00162         os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
00163         if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) {
00164                 os_free(buf);
00165                 wpabuf_free(resp);
00166                 return NULL;
00167         }
00168         os_free(buf);
00169         wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
00170                     EAP_PSK_RAND_LEN);
00171         wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
00172         wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
00173                           data->id_p, data->id_p_len);
00174 
00175         data->state = PSK_MAC_SENT;
00176 
00177         return resp;
00178 }
00179 
00180 
00181 static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
00182                                          struct eap_method_ret *ret,
00183                                          const struct wpabuf *reqData)
00184 {
00185         const struct eap_psk_hdr_3 *hdr3;
00186         struct eap_psk_hdr_4 *hdr4;
00187         struct wpabuf *resp;
00188         u8 *buf, *rpchannel, nonce[16], *decrypted;
00189         const u8 *pchannel, *tag, *msg;
00190         u8 mac[EAP_PSK_MAC_LEN];
00191         size_t buflen, left, data_len, len, plen;
00192         int failed = 0;
00193         const u8 *pos;
00194 
00195         wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
00196 
00197         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
00198                                reqData, &len);
00199         hdr3 = (const struct eap_psk_hdr_3 *) pos;
00200         if (pos == NULL || len < sizeof(*hdr3)) {
00201                 wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
00202                            "length (%lu; expected %lu or more)",
00203                            (unsigned long) len,
00204                            (unsigned long) sizeof(*hdr3));
00205                 ret->ignore = TRUE;
00206                 return NULL;
00207         }
00208         left = len - sizeof(*hdr3);
00209         pchannel = (const u8 *) (hdr3 + 1);
00210         wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
00211         if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
00212                 wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
00213                            EAP_PSK_FLAGS_GET_T(hdr3->flags));
00214                 ret->methodState = METHOD_DONE;
00215                 ret->decision = DECISION_FAIL;
00216                 return NULL;
00217         }
00218         wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
00219                     EAP_PSK_RAND_LEN);
00220         wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
00221         wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
00222 
00223         if (left < 4 + 16 + 1) {
00224                 wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
00225                            "third message (len=%lu, expected 21)",
00226                            (unsigned long) left);
00227                 ret->ignore = TRUE;
00228                 return NULL;
00229         }
00230 
00231         /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
00232         buflen = data->id_s_len + EAP_PSK_RAND_LEN;
00233         buf = os_malloc(buflen);
00234         if (buf == NULL)
00235                 return NULL;
00236         os_memcpy(buf, data->id_s, data->id_s_len);
00237         os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
00238         if (omac1_aes_128(data->ak, buf, buflen, mac)) {
00239                 os_free(buf);
00240                 return NULL;
00241         }
00242         os_free(buf);
00243         if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
00244                 wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
00245                            "message");
00246                 ret->methodState = METHOD_DONE;
00247                 ret->decision = DECISION_FAIL;
00248                 return NULL;
00249         }
00250         wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
00251 
00252         if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
00253                                 data->msk, data->emsk)) {
00254                 ret->methodState = METHOD_DONE;
00255                 ret->decision = DECISION_FAIL;
00256                 return NULL;
00257         }
00258         wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
00259         wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
00260         wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
00261 
00262         os_memset(nonce, 0, 12);
00263         os_memcpy(nonce + 12, pchannel, 4);
00264         pchannel += 4;
00265         left -= 4;
00266 
00267         tag = pchannel;
00268         pchannel += 16;
00269         left -= 16;
00270 
00271         msg = pchannel;
00272 
00273         wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
00274                     nonce, sizeof(nonce));
00275         wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr",
00276                     wpabuf_head(reqData), 5);
00277         wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
00278 
00279         decrypted = os_malloc(left);
00280         if (decrypted == NULL) {
00281                 ret->methodState = METHOD_DONE;
00282                 ret->decision = DECISION_FAIL;
00283                 return NULL;
00284         }
00285         os_memcpy(decrypted, msg, left);
00286 
00287         if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
00288                                 wpabuf_head(reqData),
00289                                 sizeof(struct eap_hdr) + 1 +
00290                                 sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted,
00291                                 left, tag)) {
00292                 wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
00293                 os_free(decrypted);
00294                 return NULL;
00295         }
00296         wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
00297                     decrypted, left);
00298 
00299         /* Verify R flag */
00300         switch (decrypted[0] >> 6) {
00301         case EAP_PSK_R_FLAG_CONT:
00302                 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
00303                 failed = 1;
00304                 break;
00305         case EAP_PSK_R_FLAG_DONE_SUCCESS:
00306                 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
00307                 break;
00308         case EAP_PSK_R_FLAG_DONE_FAILURE:
00309                 wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
00310                 wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
00311                            "authentication");
00312                 failed = 1;
00313                 break;
00314         }
00315 
00316         data_len = 1;
00317         if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1)
00318                 data_len++;
00319         plen = sizeof(*hdr4) + 4 + 16 + data_len;
00320         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen,
00321                              EAP_CODE_RESPONSE, eap_get_id(reqData));
00322         if (resp == NULL) {
00323                 os_free(decrypted);
00324                 return NULL;
00325         }
00326         hdr4 = wpabuf_put(resp, sizeof(*hdr4));
00327         hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
00328         os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
00329         rpchannel = wpabuf_put(resp, 4 + 16 + data_len);
00330 
00331         /* nonce++ */
00332         inc_byte_array(nonce, sizeof(nonce));
00333         os_memcpy(rpchannel, nonce + 12, 4);
00334 
00335         if (decrypted[0] & EAP_PSK_E_FLAG) {
00336                 wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
00337                 failed = 1;
00338                 rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
00339                         EAP_PSK_E_FLAG;
00340                 if (left > 1) {
00341                         /* Add empty EXT_Payload with same EXT_Type */
00342                         rpchannel[4 + 16 + 1] = decrypted[1];
00343                 }
00344         } else if (failed)
00345                 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
00346         else
00347                 rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
00348 
00349         wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
00350                     rpchannel + 4 + 16, data_len);
00351         if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
00352                                 wpabuf_head(resp),
00353                                 sizeof(struct eap_hdr) + 1 + sizeof(*hdr4),
00354                                 rpchannel + 4 + 16, data_len, rpchannel + 4)) {
00355                 os_free(decrypted);
00356                 wpabuf_free(resp);
00357                 return NULL;
00358         }
00359         wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
00360                     rpchannel, 4 + 16 + data_len);
00361 
00362         wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
00363                    failed ? "un" : "");
00364         data->state = PSK_DONE;
00365         ret->methodState = METHOD_DONE;
00366         ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
00367 
00368         os_free(decrypted);
00369 
00370         return resp;
00371 }
00372 
00373 
00374 static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
00375                                        struct eap_method_ret *ret,
00376                                        const struct wpabuf *reqData)
00377 {
00378         struct eap_psk_data *data = priv;
00379         const u8 *pos;
00380         struct wpabuf *resp = NULL;
00381         size_t len;
00382 
00383         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
00384         if (pos == NULL) {
00385                 ret->ignore = TRUE;
00386                 return NULL;
00387         }
00388 
00389         ret->ignore = FALSE;
00390         ret->methodState = METHOD_MAY_CONT;
00391         ret->decision = DECISION_FAIL;
00392         ret->allowNotifications = TRUE;
00393 
00394         switch (data->state) {
00395         case PSK_INIT:
00396                 resp = eap_psk_process_1(data, ret, reqData);
00397                 break;
00398         case PSK_MAC_SENT:
00399                 resp = eap_psk_process_3(data, ret, reqData);
00400                 break;
00401         case PSK_DONE:
00402                 wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
00403                            "unexpected message");
00404                 ret->ignore = TRUE;
00405                 return NULL;
00406         }
00407 
00408         if (ret->methodState == METHOD_DONE) {
00409                 ret->allowNotifications = FALSE;
00410         }
00411 
00412         return resp;
00413 }
00414 
00415 
00416 static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
00417 {
00418         struct eap_psk_data *data = priv;
00419         return data->state == PSK_DONE;
00420 }
00421 
00422 
00423 static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
00424 {
00425         struct eap_psk_data *data = priv;
00426         u8 *key;
00427 
00428         if (data->state != PSK_DONE)
00429                 return NULL;
00430 
00431         key = os_malloc(EAP_MSK_LEN);
00432         if (key == NULL)
00433                 return NULL;
00434 
00435         *len = EAP_MSK_LEN;
00436         os_memcpy(key, data->msk, EAP_MSK_LEN);
00437 
00438         return key;
00439 }
00440 
00441 
00442 static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
00443 {
00444         struct eap_psk_data *data = priv;
00445         u8 *key;
00446 
00447         if (data->state != PSK_DONE)
00448                 return NULL;
00449 
00450         key = os_malloc(EAP_EMSK_LEN);
00451         if (key == NULL)
00452                 return NULL;
00453 
00454         *len = EAP_EMSK_LEN;
00455         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
00456 
00457         return key;
00458 }
00459 
00460 
00461 int eap_peer_psk_register(void)
00462 {
00463         struct eap_method *eap;
00464         int ret;
00465 
00466         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
00467                                     EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
00468         if (eap == NULL)
00469                 return -1;
00470 
00471         eap->init = eap_psk_init;
00472         eap->deinit = eap_psk_deinit;
00473         eap->process = eap_psk_process;
00474         eap->isKeyAvailable = eap_psk_isKeyAvailable;
00475         eap->getKey = eap_psk_getKey;
00476         eap->get_emsk = eap_psk_get_emsk;
00477 
00478         ret = eap_peer_method_register(eap);
00479         if (ret)
00480                 eap_peer_method_free(eap);
00481         return ret;
00482 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:34