eap_sake_common.c

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

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