eap_sake.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "eap_server/eap_i.h"
00020 #include "eap_common/eap_sake_common.h"
00021 
00022 
00023 struct eap_sake_data {
00024         enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
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         u8 *peerid;
00035         size_t peerid_len;
00036         u8 *serverid;
00037         size_t serverid_len;
00038 };
00039 
00040 
00041 static const char * eap_sake_state_txt(int state)
00042 {
00043         switch (state) {
00044         case IDENTITY:
00045                 return "IDENTITY";
00046         case CHALLENGE:
00047                 return "CHALLENGE";
00048         case CONFIRM:
00049                 return "CONFIRM";
00050         case SUCCESS:
00051                 return "SUCCESS";
00052         case FAILURE:
00053                 return "FAILURE";
00054         default:
00055                 return "?";
00056         }
00057 }
00058 
00059 
00060 static void eap_sake_state(struct eap_sake_data *data, int state)
00061 {
00062         wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
00063                    eap_sake_state_txt(data->state),
00064                    eap_sake_state_txt(state));
00065         data->state = state;
00066 }
00067 
00068 
00069 static void * eap_sake_init(struct eap_sm *sm)
00070 {
00071         struct eap_sake_data *data;
00072 
00073         data = os_zalloc(sizeof(*data));
00074         if (data == NULL)
00075                 return NULL;
00076         data->state = CHALLENGE;
00077 
00078         if (os_get_random(&data->session_id, 1)) {
00079                 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
00080                 os_free(data);
00081                 return NULL;
00082         }
00083         wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
00084                    data->session_id);
00085 
00086         /* TODO: add support for configuring SERVERID */
00087         data->serverid = (u8 *) os_strdup("hostapd");
00088         if (data->serverid)
00089                 data->serverid_len = os_strlen((char *) data->serverid);
00090 
00091         return data;
00092 }
00093 
00094 
00095 static void eap_sake_reset(struct eap_sm *sm, void *priv)
00096 {
00097         struct eap_sake_data *data = priv;
00098         os_free(data->serverid);
00099         os_free(data->peerid);
00100         os_free(data);
00101 }
00102 
00103 
00104 static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
00105                                           u8 id, size_t length, u8 subtype)
00106 {
00107         struct eap_sake_hdr *sake;
00108         struct wpabuf *msg;
00109         size_t plen;
00110 
00111         plen = sizeof(struct eap_sake_hdr) + length;
00112 
00113         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
00114                             EAP_CODE_REQUEST, id);
00115         if (msg == NULL) {
00116                 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
00117                            "request");
00118                 return NULL;
00119         }
00120 
00121         sake = wpabuf_put(msg, sizeof(*sake));
00122         sake->version = EAP_SAKE_VERSION;
00123         sake->session_id = data->session_id;
00124         sake->subtype = subtype;
00125 
00126         return msg;
00127 }
00128 
00129 
00130 static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
00131                                                struct eap_sake_data *data,
00132                                                u8 id)
00133 {
00134         struct wpabuf *msg;
00135         size_t plen;
00136 
00137         wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
00138 
00139         plen = 4;
00140         if (data->serverid)
00141                 plen += 2 + data->serverid_len;
00142         msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
00143         if (msg == NULL) {
00144                 data->state = FAILURE;
00145                 return NULL;
00146         }
00147 
00148         wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
00149         eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
00150 
00151         if (data->serverid) {
00152                 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
00153                 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
00154                                   data->serverid, data->serverid_len);
00155         }
00156 
00157         return msg;
00158 }
00159 
00160 
00161 static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
00162                                                 struct eap_sake_data *data,
00163                                                 u8 id)
00164 {
00165         struct wpabuf *msg;
00166         size_t plen;
00167 
00168         wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
00169 
00170         if (os_get_random(data->rand_s, EAP_SAKE_RAND_LEN)) {
00171                 wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
00172                 data->state = FAILURE;
00173                 return NULL;
00174         }
00175         wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
00176                     data->rand_s, EAP_SAKE_RAND_LEN);
00177 
00178         plen = 2 + EAP_SAKE_RAND_LEN;
00179         if (data->serverid)
00180                 plen += 2 + data->serverid_len;
00181         msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
00182         if (msg == NULL) {
00183                 data->state = FAILURE;
00184                 return NULL;
00185         }
00186 
00187         wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
00188         eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
00189                           data->rand_s, EAP_SAKE_RAND_LEN);
00190 
00191         if (data->serverid) {
00192                 wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
00193                 eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
00194                                   data->serverid, data->serverid_len);
00195         }
00196 
00197         return msg;
00198 }
00199 
00200 
00201 static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
00202                                               struct eap_sake_data *data,
00203                                               u8 id)
00204 {
00205         struct wpabuf *msg;
00206         u8 *mic;
00207 
00208         wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
00209 
00210         msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
00211                                  EAP_SAKE_SUBTYPE_CONFIRM);
00212         if (msg == NULL) {
00213                 data->state = FAILURE;
00214                 return NULL;
00215         }
00216 
00217         wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
00218         wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
00219         wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
00220         mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
00221         if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
00222                                  data->serverid, data->serverid_len,
00223                                  data->peerid, data->peerid_len, 0,
00224                                  wpabuf_head(msg), wpabuf_len(msg), mic, mic))
00225         {
00226                 wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
00227                 data->state = FAILURE;
00228                 os_free(msg);
00229                 return NULL;
00230         }
00231 
00232         return msg;
00233 }
00234 
00235 
00236 static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
00237 {
00238         struct eap_sake_data *data = priv;
00239 
00240         switch (data->state) {
00241         case IDENTITY:
00242                 return eap_sake_build_identity(sm, data, id);
00243         case CHALLENGE:
00244                 return eap_sake_build_challenge(sm, data, id);
00245         case CONFIRM:
00246                 return eap_sake_build_confirm(sm, data, id);
00247         default:
00248                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
00249                            data->state);
00250                 break;
00251         }
00252         return NULL;
00253 }
00254 
00255 
00256 static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
00257                               struct wpabuf *respData)
00258 {
00259         struct eap_sake_data *data = priv;
00260         struct eap_sake_hdr *resp;
00261         size_t len;
00262         u8 version, session_id, subtype;
00263         const u8 *pos;
00264 
00265         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
00266         if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
00267                 wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
00268                 return TRUE;
00269         }
00270 
00271         resp = (struct eap_sake_hdr *) pos;
00272         version = resp->version;
00273         session_id = resp->session_id;
00274         subtype = resp->subtype;
00275 
00276         if (version != EAP_SAKE_VERSION) {
00277                 wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
00278                 return TRUE;
00279         }
00280 
00281         if (session_id != data->session_id) {
00282                 wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
00283                            session_id, data->session_id);
00284                 return TRUE;
00285         }
00286 
00287         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
00288 
00289         if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
00290                 return FALSE;
00291 
00292         if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
00293                 return FALSE;
00294 
00295         if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
00296                 return FALSE;
00297 
00298         if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
00299                 return FALSE;
00300 
00301         wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
00302                    subtype, data->state);
00303 
00304         return TRUE;
00305 }
00306 
00307 
00308 static void eap_sake_process_identity(struct eap_sm *sm,
00309                                       struct eap_sake_data *data,
00310                                       const struct wpabuf *respData,
00311                                       const u8 *payload, size_t payloadlen)
00312 {
00313         if (data->state != IDENTITY)
00314                 return;
00315 
00316         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
00317         /* TODO: update identity and select new user data */
00318         eap_sake_state(data, CHALLENGE);
00319 }
00320 
00321 
00322 static void eap_sake_process_challenge(struct eap_sm *sm,
00323                                        struct eap_sake_data *data,
00324                                        const struct wpabuf *respData,
00325                                        const u8 *payload, size_t payloadlen)
00326 {
00327         struct eap_sake_parse_attr attr;
00328         u8 mic_p[EAP_SAKE_MIC_LEN];
00329 
00330         if (data->state != CHALLENGE)
00331                 return;
00332 
00333         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
00334 
00335         if (eap_sake_parse_attributes(payload, payloadlen, &attr))
00336                 return;
00337 
00338         if (!attr.rand_p || !attr.mic_p) {
00339                 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
00340                            "include AT_RAND_P or AT_MIC_P");
00341                 return;
00342         }
00343 
00344         os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
00345 
00346         os_free(data->peerid);
00347         data->peerid = NULL;
00348         data->peerid_len = 0;
00349         if (attr.peerid) {
00350                 data->peerid = os_malloc(attr.peerid_len);
00351                 if (data->peerid == NULL)
00352                         return;
00353                 os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
00354                 data->peerid_len = attr.peerid_len;
00355         }
00356 
00357         if (sm->user == NULL || sm->user->password == NULL ||
00358             sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
00359                 wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
00360                            "%d-byte key not configured",
00361                            2 * EAP_SAKE_ROOT_SECRET_LEN);
00362                 data->state = FAILURE;
00363                 return;
00364         }
00365         eap_sake_derive_keys(sm->user->password,
00366                              sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
00367                              data->rand_s, data->rand_p,
00368                              (u8 *) &data->tek, data->msk, data->emsk);
00369 
00370         eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
00371                              data->serverid, data->serverid_len,
00372                              data->peerid, data->peerid_len, 1,
00373                              wpabuf_head(respData), wpabuf_len(respData),
00374                              attr.mic_p, mic_p);
00375         if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
00376                 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
00377                 eap_sake_state(data, FAILURE);
00378                 return;
00379         }
00380 
00381         eap_sake_state(data, CONFIRM);
00382 }
00383 
00384 
00385 static void eap_sake_process_confirm(struct eap_sm *sm,
00386                                      struct eap_sake_data *data,
00387                                      const struct wpabuf *respData,
00388                                      const u8 *payload, size_t payloadlen)
00389 {
00390         struct eap_sake_parse_attr attr;
00391         u8 mic_p[EAP_SAKE_MIC_LEN];
00392 
00393         if (data->state != CONFIRM)
00394                 return;
00395 
00396         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
00397 
00398         if (eap_sake_parse_attributes(payload, payloadlen, &attr))
00399                 return;
00400 
00401         if (!attr.mic_p) {
00402                 wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
00403                            "include AT_MIC_P");
00404                 return;
00405         }
00406 
00407         eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
00408                              data->serverid, data->serverid_len,
00409                              data->peerid, data->peerid_len, 1,
00410                              wpabuf_head(respData), wpabuf_len(respData),
00411                              attr.mic_p, mic_p);
00412         if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
00413                 wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
00414                 eap_sake_state(data, FAILURE);
00415         } else
00416                 eap_sake_state(data, SUCCESS);
00417 }
00418 
00419 
00420 static void eap_sake_process_auth_reject(struct eap_sm *sm,
00421                                          struct eap_sake_data *data,
00422                                          const struct wpabuf *respData,
00423                                          const u8 *payload, size_t payloadlen)
00424 {
00425         wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
00426         eap_sake_state(data, FAILURE);
00427 }
00428 
00429 
00430 static void eap_sake_process(struct eap_sm *sm, void *priv,
00431                              struct wpabuf *respData)
00432 {
00433         struct eap_sake_data *data = priv;
00434         struct eap_sake_hdr *resp;
00435         u8 subtype;
00436         size_t len;
00437         const u8 *pos, *end;
00438 
00439         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
00440         if (pos == NULL || len < sizeof(struct eap_sake_hdr))
00441                 return;
00442 
00443         resp = (struct eap_sake_hdr *) pos;
00444         end = pos + len;
00445         subtype = resp->subtype;
00446         pos = (u8 *) (resp + 1);
00447 
00448         wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
00449                     pos, end - pos);
00450 
00451         switch (subtype) {
00452         case EAP_SAKE_SUBTYPE_IDENTITY:
00453                 eap_sake_process_identity(sm, data, respData, pos, end - pos);
00454                 break;
00455         case EAP_SAKE_SUBTYPE_CHALLENGE:
00456                 eap_sake_process_challenge(sm, data, respData, pos, end - pos);
00457                 break;
00458         case EAP_SAKE_SUBTYPE_CONFIRM:
00459                 eap_sake_process_confirm(sm, data, respData, pos, end - pos);
00460                 break;
00461         case EAP_SAKE_SUBTYPE_AUTH_REJECT:
00462                 eap_sake_process_auth_reject(sm, data, respData, pos,
00463                                              end - pos);
00464                 break;
00465         }
00466 }
00467 
00468 
00469 static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
00470 {
00471         struct eap_sake_data *data = priv;
00472         return data->state == SUCCESS || data->state == FAILURE;
00473 }
00474 
00475 
00476 static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
00477 {
00478         struct eap_sake_data *data = priv;
00479         u8 *key;
00480 
00481         if (data->state != SUCCESS)
00482                 return NULL;
00483 
00484         key = os_malloc(EAP_MSK_LEN);
00485         if (key == NULL)
00486                 return NULL;
00487         os_memcpy(key, data->msk, EAP_MSK_LEN);
00488         *len = EAP_MSK_LEN;
00489 
00490         return key;
00491 }
00492 
00493 
00494 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
00495 {
00496         struct eap_sake_data *data = priv;
00497         u8 *key;
00498 
00499         if (data->state != SUCCESS)
00500                 return NULL;
00501 
00502         key = os_malloc(EAP_EMSK_LEN);
00503         if (key == NULL)
00504                 return NULL;
00505         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
00506         *len = EAP_EMSK_LEN;
00507 
00508         return key;
00509 }
00510 
00511 
00512 static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
00513 {
00514         struct eap_sake_data *data = priv;
00515         return data->state == SUCCESS;
00516 }
00517 
00518 
00519 int eap_server_sake_register(void)
00520 {
00521         struct eap_method *eap;
00522         int ret;
00523 
00524         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
00525                                       EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
00526         if (eap == NULL)
00527                 return -1;
00528 
00529         eap->init = eap_sake_init;
00530         eap->reset = eap_sake_reset;
00531         eap->buildReq = eap_sake_buildReq;
00532         eap->check = eap_sake_check;
00533         eap->process = eap_sake_process;
00534         eap->isDone = eap_sake_isDone;
00535         eap->getKey = eap_sake_getKey;
00536         eap->isSuccess = eap_sake_isSuccess;
00537         eap->get_emsk = eap_sake_get_emsk;
00538 
00539         ret = eap_server_method_register(eap);
00540         if (ret)
00541                 eap_server_method_free(eap);
00542         return ret;
00543 }
00544 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1