00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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;
00227 len[0] = label_len;
00228 addr[1] = data;
00229 len[1] = data_len;
00230 addr[2] = data2;
00231 len[2] = data2_len;
00232 addr[3] = &counter;
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);
00389 if (data)
00390 wpabuf_put_data(buf, data, len);
00391 else
00392 os_memset(wpabuf_put(buf, len), 0, len);
00393 }