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;
00230 len[0] = label_len;
00231 addr[1] = data;
00232 len[1] = data_len;
00233 addr[2] = data2;
00234 len[2] = data2_len;
00235 addr[3] = &counter;
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);
00394 if (data)
00395 wpabuf_put_data(buf, data, len);
00396 else
00397 os_memset(wpabuf_put(buf, len), 0, len);
00398 }
00399