eap_sake_common.c
Go to the documentation of this file.
00001 /*
00002  * EAP server/peer: EAP-SAKE shared routines
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 "wpabuf.h"
00019 #include "crypto/sha1.h"
00020 #include "eap_defs.h"
00021 #include "eap_sake_common.h"
00022 
00023 
00024 static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
00025                                    const u8 *pos)
00026 {
00027         size_t i;
00028 
00029         switch (pos[0]) {
00030         case EAP_SAKE_AT_RAND_S:
00031                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
00032                 if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
00033                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
00034                                    "invalid length %d", pos[1]);
00035                         return -1;
00036                 }
00037                 attr->rand_s = pos + 2;
00038                 break;
00039         case EAP_SAKE_AT_RAND_P:
00040                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
00041                 if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
00042                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
00043                                    "invalid length %d", pos[1]);
00044                         return -1;
00045                 }
00046                 attr->rand_p = pos + 2;
00047                 break;
00048         case EAP_SAKE_AT_MIC_S:
00049                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
00050                 if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
00051                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
00052                                    "invalid length %d", pos[1]);
00053                         return -1;
00054                 }
00055                 attr->mic_s = pos + 2;
00056                 break;
00057         case EAP_SAKE_AT_MIC_P:
00058                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
00059                 if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
00060                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
00061                                    "invalid length %d", pos[1]);
00062                         return -1;
00063                 }
00064                 attr->mic_p = pos + 2;
00065                 break;
00066         case EAP_SAKE_AT_SERVERID:
00067                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
00068                 attr->serverid = pos + 2;
00069                 attr->serverid_len = pos[1] - 2;
00070                 break;
00071         case EAP_SAKE_AT_PEERID:
00072                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
00073                 attr->peerid = pos + 2;
00074                 attr->peerid_len = pos[1] - 2;
00075                 break;
00076         case EAP_SAKE_AT_SPI_S:
00077                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
00078                 attr->spi_s = pos + 2;
00079                 attr->spi_s_len = pos[1] - 2;
00080                 break;
00081         case EAP_SAKE_AT_SPI_P:
00082                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
00083                 attr->spi_p = pos + 2;
00084                 attr->spi_p_len = pos[1] - 2;
00085                 break;
00086         case EAP_SAKE_AT_ANY_ID_REQ:
00087                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
00088                 if (pos[1] != 4) {
00089                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
00090                                    " length %d", pos[1]);
00091                         return -1;
00092                 }
00093                 attr->any_id_req = pos + 2;
00094                 break;
00095         case EAP_SAKE_AT_PERM_ID_REQ:
00096                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
00097                 if (pos[1] != 4) {
00098                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
00099                                    "AT_PERM_ID_REQ length %d", pos[1]);
00100                         return -1;
00101                 }
00102                 attr->perm_id_req = pos + 2;
00103                 break;
00104         case EAP_SAKE_AT_ENCR_DATA:
00105                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
00106                 attr->encr_data = pos + 2;
00107                 attr->encr_data_len = pos[1] - 2;
00108                 break;
00109         case EAP_SAKE_AT_IV:
00110                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
00111                 attr->iv = pos + 2;
00112                 attr->iv_len = pos[1] - 2;
00113                 break;
00114         case EAP_SAKE_AT_PADDING:
00115                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
00116                 for (i = 2; i < pos[1]; i++) {
00117                         if (pos[i]) {
00118                                 wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
00119                                            "with non-zero pad byte");
00120                                 return -1;
00121                         }
00122                 }
00123                 break;
00124         case EAP_SAKE_AT_NEXT_TMPID:
00125                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
00126                 attr->next_tmpid = pos + 2;
00127                 attr->next_tmpid_len = pos[1] - 2;
00128                 break;
00129         case EAP_SAKE_AT_MSK_LIFE:
00130                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
00131                 if (pos[1] != 6) {
00132                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
00133                                    "AT_MSK_LIFE length %d", pos[1]);
00134                         return -1;
00135                 }
00136                 attr->msk_life = pos + 2;
00137                 break;
00138         default:
00139                 if (pos[0] < 128) {
00140                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
00141                                    " attribute %d", pos[0]);
00142                         return -1;
00143                 }
00144                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
00145                            "attribute %d", pos[0]);
00146                 break;
00147         }
00148 
00149         if (attr->iv && !attr->encr_data) {
00150                 wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
00151                            "AT_ENCR_DATA");
00152                 return -1;
00153         }
00154 
00155         return 0;
00156 }
00157 
00158 
00166 int eap_sake_parse_attributes(const u8 *buf, size_t len,
00167                               struct eap_sake_parse_attr *attr)
00168 {
00169         const u8 *pos = buf, *end = buf + len;
00170 
00171         os_memset(attr, 0, sizeof(*attr));
00172         while (pos < end) {
00173                 if (end - pos < 2) {
00174                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
00175                         return -1;
00176                 }
00177 
00178                 if (pos[1] < 2) {
00179                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
00180                                    "length (%d)", pos[1]);
00181                         return -1;
00182                 }
00183 
00184                 if (pos + pos[1] > end) {
00185                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
00186                         return -1;
00187                 }
00188 
00189                 if (eap_sake_parse_add_attr(attr, pos))
00190                         return -1;
00191 
00192                 pos += pos[1];
00193         }
00194 
00195         return 0;
00196 }
00197 
00198 
00214 static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
00215                          const u8 *data, size_t data_len,
00216                          const u8 *data2, size_t data2_len,
00217                          u8 *buf, size_t buf_len)
00218 {
00219         u8 counter = 0;
00220         size_t pos, plen;
00221         u8 hash[SHA1_MAC_LEN];
00222         size_t label_len = os_strlen(label) + 1;
00223         const unsigned char *addr[4];
00224         size_t len[4];
00225 
00226         addr[0] = (u8 *) label; /* Label | Y */
00227         len[0] = label_len;
00228         addr[1] = data; /* Msg[start] */
00229         len[1] = data_len;
00230         addr[2] = data2; /* Msg[end] */
00231         len[2] = data2_len;
00232         addr[3] = &counter; /* Length */
00233         len[3] = 1;
00234 
00235         pos = 0;
00236         while (pos < buf_len) {
00237                 plen = buf_len - pos;
00238                 if (plen >= SHA1_MAC_LEN) {
00239                         hmac_sha1_vector(key, key_len, 4, addr, len,
00240                                          &buf[pos]);
00241                         pos += SHA1_MAC_LEN;
00242                 } else {
00243                         hmac_sha1_vector(key, key_len, 4, addr, len,
00244                                          hash);
00245                         os_memcpy(&buf[pos], hash, plen);
00246                         break;
00247                 }
00248                 counter++;
00249         }
00250 }
00251 
00252 
00265 void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
00266                           const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
00267                           u8 *emsk)
00268 {
00269         u8 sms_a[EAP_SAKE_SMS_LEN];
00270         u8 sms_b[EAP_SAKE_SMS_LEN];
00271         u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
00272 
00273         wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
00274 
00275         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
00276                         root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
00277         eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
00278                      "SAKE Master Secret A",
00279                      rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
00280                      sms_a, EAP_SAKE_SMS_LEN);
00281         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
00282         eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
00283                      rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
00284                      tek, EAP_SAKE_TEK_LEN);
00285         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
00286                         tek, EAP_SAKE_TEK_AUTH_LEN);
00287         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
00288                         tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
00289 
00290         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
00291                         root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
00292         eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
00293                      "SAKE Master Secret B",
00294                      rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
00295                      sms_b, EAP_SAKE_SMS_LEN);
00296         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
00297         eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
00298                      rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
00299                      key_buf, sizeof(key_buf));
00300         os_memcpy(msk, key_buf, EAP_MSK_LEN);
00301         os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
00302         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
00303         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
00304 }
00305 
00306 
00322 int eap_sake_compute_mic(const u8 *tek_auth,
00323                          const u8 *rand_s, const u8 *rand_p,
00324                          const u8 *serverid, size_t serverid_len,
00325                          const u8 *peerid, size_t peerid_len,
00326                          int peer, const u8 *eap, size_t eap_len,
00327                          const u8 *mic_pos, u8 *mic)
00328 {
00329         u8 _rand[2 * EAP_SAKE_RAND_LEN];
00330         u8 *tmp, *pos;
00331         size_t tmplen;
00332 
00333         tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
00334         tmp = os_malloc(tmplen);
00335         if (tmp == NULL)
00336                 return -1;
00337         pos = tmp;
00338         if (peer) {
00339                 if (peerid) {
00340                         os_memcpy(pos, peerid, peerid_len);
00341                         pos += peerid_len;
00342                 }
00343                 *pos++ = 0x00;
00344                 if (serverid) {
00345                         os_memcpy(pos, serverid, serverid_len);
00346                         pos += serverid_len;
00347                 }
00348                 *pos++ = 0x00;
00349 
00350                 os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
00351                 os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
00352                           EAP_SAKE_RAND_LEN);
00353         } else {
00354                 if (serverid) {
00355                         os_memcpy(pos, serverid, serverid_len);
00356                         pos += serverid_len;
00357                 }
00358                 *pos++ = 0x00;
00359                 if (peerid) {
00360                         os_memcpy(pos, peerid, peerid_len);
00361                         pos += peerid_len;
00362                 }
00363                 *pos++ = 0x00;
00364 
00365                 os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
00366                 os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
00367                           EAP_SAKE_RAND_LEN);
00368         }
00369 
00370         os_memcpy(pos, eap, eap_len);
00371         os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
00372 
00373         eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
00374                      peer ? "Peer MIC" : "Server MIC",
00375                      _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
00376                      mic, EAP_SAKE_MIC_LEN);
00377 
00378         os_free(tmp);
00379 
00380         return 0;
00381 }
00382 
00383 
00384 void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
00385                        size_t len)
00386 {
00387         wpabuf_put_u8(buf, type);
00388         wpabuf_put_u8(buf, 2 + len); /* Length; including attr header */
00389         if (data)
00390                 wpabuf_put_data(buf, data, len);
00391         else
00392                 os_memset(wpabuf_put(buf, len), 0, len);
00393 }


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:25:13