eap_server_sake.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:37