$search
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 }