eap_sim_common.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. /*
  2. * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
  3. * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "eap_common/eap_defs.h"
  17. #include "sha1.h"
  18. #include "sha256.h"
  19. #include "crypto.h"
  20. #include "aes_wrap.h"
  21. #include "wpabuf.h"
  22. #include "eap_common/eap_sim_common.h"
  23. static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
  24. {
  25. return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
  26. }
  27. void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
  28. const u8 *nonce_mt, u16 selected_version,
  29. const u8 *ver_list, size_t ver_list_len,
  30. int num_chal, const u8 *kc, u8 *mk)
  31. {
  32. u8 sel_ver[2];
  33. const unsigned char *addr[5];
  34. size_t len[5];
  35. addr[0] = identity;
  36. len[0] = identity_len;
  37. addr[1] = kc;
  38. len[1] = num_chal * EAP_SIM_KC_LEN;
  39. addr[2] = nonce_mt;
  40. len[2] = EAP_SIM_NONCE_MT_LEN;
  41. addr[3] = ver_list;
  42. len[3] = ver_list_len;
  43. addr[4] = sel_ver;
  44. len[4] = 2;
  45. WPA_PUT_BE16(sel_ver, selected_version);
  46. /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
  47. sha1_vector(5, addr, len, mk);
  48. wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
  49. }
  50. void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
  51. const u8 *ik, const u8 *ck, u8 *mk)
  52. {
  53. const u8 *addr[3];
  54. size_t len[3];
  55. addr[0] = identity;
  56. len[0] = identity_len;
  57. addr[1] = ik;
  58. len[1] = EAP_AKA_IK_LEN;
  59. addr[2] = ck;
  60. len[2] = EAP_AKA_CK_LEN;
  61. /* MK = SHA1(Identity|IK|CK) */
  62. sha1_vector(3, addr, len, mk);
  63. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
  64. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
  65. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
  66. }
  67. int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
  68. {
  69. u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
  70. EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
  71. if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
  72. wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
  73. return -1;
  74. }
  75. pos = buf;
  76. os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
  77. pos += EAP_SIM_K_ENCR_LEN;
  78. os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
  79. pos += EAP_SIM_K_AUT_LEN;
  80. os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
  81. pos += EAP_SIM_KEYING_DATA_LEN;
  82. os_memcpy(emsk, pos, EAP_EMSK_LEN);
  83. wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
  84. k_encr, EAP_SIM_K_ENCR_LEN);
  85. wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
  86. k_aut, EAP_SIM_K_AUT_LEN);
  87. wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
  88. msk, EAP_SIM_KEYING_DATA_LEN);
  89. wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
  90. os_memset(buf, 0, sizeof(buf));
  91. return 0;
  92. }
  93. int eap_sim_derive_keys_reauth(u16 _counter,
  94. const u8 *identity, size_t identity_len,
  95. const u8 *nonce_s, const u8 *mk, u8 *msk,
  96. u8 *emsk)
  97. {
  98. u8 xkey[SHA1_MAC_LEN];
  99. u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
  100. u8 counter[2];
  101. const u8 *addr[4];
  102. size_t len[4];
  103. while (identity_len > 0 && identity[identity_len - 1] == 0) {
  104. wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
  105. "character from the end of identity");
  106. identity_len--;
  107. }
  108. addr[0] = identity;
  109. len[0] = identity_len;
  110. addr[1] = counter;
  111. len[1] = 2;
  112. addr[2] = nonce_s;
  113. len[2] = EAP_SIM_NONCE_S_LEN;
  114. addr[3] = mk;
  115. len[3] = EAP_SIM_MK_LEN;
  116. WPA_PUT_BE16(counter, _counter);
  117. wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
  118. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
  119. identity, identity_len);
  120. wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
  121. wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
  122. EAP_SIM_NONCE_S_LEN);
  123. wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
  124. /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
  125. sha1_vector(4, addr, len, xkey);
  126. wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
  127. if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
  128. wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
  129. return -1;
  130. }
  131. if (msk) {
  132. os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
  133. wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
  134. msk, EAP_SIM_KEYING_DATA_LEN);
  135. }
  136. if (emsk) {
  137. os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
  138. wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
  139. }
  140. os_memset(buf, 0, sizeof(buf));
  141. return 0;
  142. }
  143. int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
  144. const u8 *mac, const u8 *extra, size_t extra_len)
  145. {
  146. unsigned char hmac[SHA1_MAC_LEN];
  147. const u8 *addr[2];
  148. size_t len[2];
  149. u8 *tmp;
  150. if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
  151. mac < wpabuf_head_u8(req) ||
  152. mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
  153. return -1;
  154. tmp = os_malloc(wpabuf_len(req));
  155. if (tmp == NULL)
  156. return -1;
  157. addr[0] = tmp;
  158. len[0] = wpabuf_len(req);
  159. addr[1] = extra;
  160. len[1] = extra_len;
  161. /* HMAC-SHA1-128 */
  162. os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
  163. os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
  164. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
  165. tmp, wpabuf_len(req));
  166. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
  167. extra, extra_len);
  168. wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
  169. k_aut, EAP_SIM_K_AUT_LEN);
  170. hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
  171. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
  172. hmac, EAP_SIM_MAC_LEN);
  173. os_free(tmp);
  174. return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
  175. }
  176. void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
  177. const u8 *extra, size_t extra_len)
  178. {
  179. unsigned char hmac[SHA1_MAC_LEN];
  180. const u8 *addr[2];
  181. size_t len[2];
  182. addr[0] = msg;
  183. len[0] = msg_len;
  184. addr[1] = extra;
  185. len[1] = extra_len;
  186. /* HMAC-SHA1-128 */
  187. os_memset(mac, 0, EAP_SIM_MAC_LEN);
  188. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
  189. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
  190. extra, extra_len);
  191. wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
  192. k_aut, EAP_SIM_K_AUT_LEN);
  193. hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
  194. os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
  195. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
  196. mac, EAP_SIM_MAC_LEN);
  197. }
  198. #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
  199. static void prf_prime(const u8 *k, const char *seed1,
  200. const u8 *seed2, size_t seed2_len,
  201. const u8 *seed3, size_t seed3_len,
  202. u8 *res, size_t res_len)
  203. {
  204. const u8 *addr[5];
  205. size_t len[5];
  206. u8 hash[SHA256_MAC_LEN];
  207. u8 iter;
  208. /*
  209. * PRF'(K,S) = T1 | T2 | T3 | T4 | ...
  210. * T1 = HMAC-SHA-256 (K, S | 0x01)
  211. * T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
  212. * T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
  213. * T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
  214. * ...
  215. */
  216. addr[0] = hash;
  217. len[0] = 0;
  218. addr[1] = (const u8 *) seed1;
  219. len[1] = os_strlen(seed1);
  220. addr[2] = seed2;
  221. len[2] = seed2_len;
  222. addr[3] = seed3;
  223. len[3] = seed3_len;
  224. addr[4] = &iter;
  225. len[4] = 1;
  226. iter = 0;
  227. while (res_len) {
  228. size_t hlen;
  229. iter++;
  230. hmac_sha256_vector(k, 32, 5, addr, len, hash);
  231. len[0] = SHA256_MAC_LEN;
  232. hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
  233. os_memcpy(res, hash, hlen);
  234. res += hlen;
  235. res_len -= hlen;
  236. }
  237. }
  238. void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
  239. const u8 *ik, const u8 *ck, u8 *k_encr,
  240. u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk)
  241. {
  242. u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN];
  243. u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN +
  244. EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN];
  245. u8 *pos;
  246. /*
  247. * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
  248. * K_encr = MK[0..127]
  249. * K_aut = MK[128..383]
  250. * K_re = MK[384..639]
  251. * MSK = MK[640..1151]
  252. * EMSK = MK[1152..1663]
  253. */
  254. os_memcpy(key, ik, EAP_AKA_IK_LEN);
  255. os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
  256. prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
  257. keys, sizeof(keys));
  258. pos = keys;
  259. os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
  260. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
  261. k_encr, EAP_SIM_K_ENCR_LEN);
  262. pos += EAP_SIM_K_ENCR_LEN;
  263. os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
  264. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
  265. k_aut, EAP_AKA_PRIME_K_AUT_LEN);
  266. pos += EAP_AKA_PRIME_K_AUT_LEN;
  267. os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
  268. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
  269. k_re, EAP_AKA_PRIME_K_RE_LEN);
  270. pos += EAP_AKA_PRIME_K_RE_LEN;
  271. os_memcpy(msk, pos, EAP_MSK_LEN);
  272. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
  273. pos += EAP_MSK_LEN;
  274. os_memcpy(emsk, pos, EAP_EMSK_LEN);
  275. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
  276. }
  277. int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
  278. const u8 *identity, size_t identity_len,
  279. const u8 *nonce_s, u8 *msk, u8 *emsk)
  280. {
  281. u8 seed3[2 + EAP_SIM_NONCE_S_LEN];
  282. u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN];
  283. u8 *pos;
  284. /*
  285. * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
  286. * MSK = MK[0..511]
  287. * EMSK = MK[512..1023]
  288. */
  289. WPA_PUT_BE16(seed3, counter);
  290. os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
  291. prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
  292. seed3, sizeof(seed3),
  293. keys, sizeof(keys));
  294. pos = keys;
  295. os_memcpy(msk, pos, EAP_MSK_LEN);
  296. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
  297. pos += EAP_MSK_LEN;
  298. os_memcpy(emsk, pos, EAP_EMSK_LEN);
  299. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
  300. os_memset(keys, 0, sizeof(keys));
  301. return 0;
  302. }
  303. int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
  304. const u8 *mac, const u8 *extra, size_t extra_len)
  305. {
  306. unsigned char hmac[SHA256_MAC_LEN];
  307. const u8 *addr[2];
  308. size_t len[2];
  309. u8 *tmp;
  310. if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
  311. mac < wpabuf_head_u8(req) ||
  312. mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
  313. return -1;
  314. tmp = os_malloc(wpabuf_len(req));
  315. if (tmp == NULL)
  316. return -1;
  317. addr[0] = tmp;
  318. len[0] = wpabuf_len(req);
  319. addr[1] = extra;
  320. len[1] = extra_len;
  321. /* HMAC-SHA-256-128 */
  322. os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
  323. os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
  324. wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
  325. tmp, wpabuf_len(req));
  326. wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
  327. extra, extra_len);
  328. wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
  329. k_aut, EAP_AKA_PRIME_K_AUT_LEN);
  330. hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
  331. wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
  332. hmac, EAP_SIM_MAC_LEN);
  333. os_free(tmp);
  334. return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
  335. }
  336. void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
  337. u8 *mac, const u8 *extra, size_t extra_len)
  338. {
  339. unsigned char hmac[SHA256_MAC_LEN];
  340. const u8 *addr[2];
  341. size_t len[2];
  342. addr[0] = msg;
  343. len[0] = msg_len;
  344. addr[1] = extra;
  345. len[1] = extra_len;
  346. /* HMAC-SHA-256-128 */
  347. os_memset(mac, 0, EAP_SIM_MAC_LEN);
  348. wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
  349. wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
  350. extra, extra_len);
  351. wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
  352. k_aut, EAP_AKA_PRIME_K_AUT_LEN);
  353. hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
  354. os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
  355. wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
  356. mac, EAP_SIM_MAC_LEN);
  357. }
  358. void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
  359. const u8 *network_name,
  360. size_t network_name_len)
  361. {
  362. u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN];
  363. u8 hash[SHA256_MAC_LEN];
  364. const u8 *addr[5];
  365. size_t len[5];
  366. u8 fc;
  367. u8 l0[2], l1[2];
  368. /* 3GPP TS 33.402 V8.0.0
  369. * (CK', IK') = F(CK, IK, <access network identity>)
  370. */
  371. /* TODO: CK', IK' generation should really be moved into the actual
  372. * AKA procedure with network name passed in there and option to use
  373. * AMF separation bit = 1 (3GPP TS 33.401). */
  374. /* Change Request 33.402 CR 0033 to version 8.1.1 from
  375. * 3GPP TSG-SA WG3 Meeting #53 in September 2008:
  376. *
  377. * CK' || IK' = HMAC-SHA-256(Key, S)
  378. * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
  379. * Key = CK || IK
  380. * FC = 0x20
  381. * P0 = access network identity (3GPP TS 24.302)
  382. * L0 = length of acceess network identity (2 octets, big endian)
  383. * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0
  384. * L1 = 0x00 0x06
  385. */
  386. fc = 0x20;
  387. wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)");
  388. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN);
  389. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN);
  390. wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc);
  391. wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity",
  392. network_name, network_name_len);
  393. wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6);
  394. os_memcpy(key, ck, EAP_AKA_CK_LEN);
  395. os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN);
  396. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK",
  397. key, sizeof(key));
  398. addr[0] = &fc;
  399. len[0] = 1;
  400. addr[1] = network_name;
  401. len[1] = network_name_len;
  402. WPA_PUT_BE16(l0, network_name_len);
  403. addr[2] = l0;
  404. len[2] = 2;
  405. addr[3] = sqn_ak;
  406. len[3] = 6;
  407. WPA_PUT_BE16(l1, 6);
  408. addr[4] = l1;
  409. len[4] = 2;
  410. hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash);
  411. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')",
  412. hash, sizeof(hash));
  413. os_memcpy(ck, hash, EAP_AKA_CK_LEN);
  414. os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN);
  415. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN);
  416. wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN);
  417. }
  418. #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
  419. int eap_sim_parse_attr(const u8 *start, const u8 *end,
  420. struct eap_sim_attrs *attr, int aka, int encr)
  421. {
  422. const u8 *pos = start, *apos;
  423. size_t alen, plen, i, list_len;
  424. os_memset(attr, 0, sizeof(*attr));
  425. attr->id_req = NO_ID_REQ;
  426. attr->notification = -1;
  427. attr->counter = -1;
  428. attr->selected_version = -1;
  429. attr->client_error_code = -1;
  430. while (pos < end) {
  431. if (pos + 2 > end) {
  432. wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
  433. return -1;
  434. }
  435. wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
  436. pos[0], pos[1] * 4);
  437. if (pos + pos[1] * 4 > end) {
  438. wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
  439. "(pos=%p len=%d end=%p)",
  440. pos, pos[1] * 4, end);
  441. return -1;
  442. }
  443. if (pos[1] == 0) {
  444. wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
  445. return -1;
  446. }
  447. apos = pos + 2;
  448. alen = pos[1] * 4 - 2;
  449. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
  450. apos, alen);
  451. switch (pos[0]) {
  452. case EAP_SIM_AT_RAND:
  453. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
  454. apos += 2;
  455. alen -= 2;
  456. if ((!aka && (alen % GSM_RAND_LEN)) ||
  457. (aka && alen != EAP_AKA_RAND_LEN)) {
  458. wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
  459. " (len %lu)",
  460. (unsigned long) alen);
  461. return -1;
  462. }
  463. attr->rand = apos;
  464. attr->num_chal = alen / GSM_RAND_LEN;
  465. break;
  466. case EAP_SIM_AT_AUTN:
  467. wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
  468. if (!aka) {
  469. wpa_printf(MSG_DEBUG, "EAP-SIM: "
  470. "Unexpected AT_AUTN");
  471. return -1;
  472. }
  473. apos += 2;
  474. alen -= 2;
  475. if (alen != EAP_AKA_AUTN_LEN) {
  476. wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
  477. " (len %lu)",
  478. (unsigned long) alen);
  479. return -1;
  480. }
  481. attr->autn = apos;
  482. break;
  483. case EAP_SIM_AT_PADDING:
  484. if (!encr) {
  485. wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
  486. "AT_PADDING");
  487. return -1;
  488. }
  489. wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
  490. for (i = 2; i < alen; i++) {
  491. if (apos[i] != 0) {
  492. wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
  493. "AT_PADDING used a non-zero"
  494. " padding byte");
  495. wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
  496. "(encr) padding bytes",
  497. apos + 2, alen - 2);
  498. return -1;
  499. }
  500. }
  501. break;
  502. case EAP_SIM_AT_NONCE_MT:
  503. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
  504. if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
  505. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  506. "AT_NONCE_MT length");
  507. return -1;
  508. }
  509. attr->nonce_mt = apos + 2;
  510. break;
  511. case EAP_SIM_AT_PERMANENT_ID_REQ:
  512. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
  513. attr->id_req = PERMANENT_ID;
  514. break;
  515. case EAP_SIM_AT_MAC:
  516. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
  517. if (alen != 2 + EAP_SIM_MAC_LEN) {
  518. wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
  519. "length");
  520. return -1;
  521. }
  522. attr->mac = apos + 2;
  523. break;
  524. case EAP_SIM_AT_NOTIFICATION:
  525. if (alen != 2) {
  526. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  527. "AT_NOTIFICATION length %lu",
  528. (unsigned long) alen);
  529. return -1;
  530. }
  531. attr->notification = apos[0] * 256 + apos[1];
  532. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
  533. attr->notification);
  534. break;
  535. case EAP_SIM_AT_ANY_ID_REQ:
  536. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
  537. attr->id_req = ANY_ID;
  538. break;
  539. case EAP_SIM_AT_IDENTITY:
  540. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
  541. plen = WPA_GET_BE16(apos);
  542. apos += 2;
  543. alen -= 2;
  544. if (plen > alen) {
  545. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  546. "AT_IDENTITY (Actual Length %lu, "
  547. "remaining length %lu)",
  548. (unsigned long) plen,
  549. (unsigned long) alen);
  550. return -1;
  551. }
  552. attr->identity = apos;
  553. attr->identity_len = plen;
  554. break;
  555. case EAP_SIM_AT_VERSION_LIST:
  556. if (aka) {
  557. wpa_printf(MSG_DEBUG, "EAP-AKA: "
  558. "Unexpected AT_VERSION_LIST");
  559. return -1;
  560. }
  561. list_len = apos[0] * 256 + apos[1];
  562. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
  563. if (list_len < 2 || list_len > alen - 2) {
  564. wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
  565. "AT_VERSION_LIST (list_len=%lu "
  566. "attr_len=%lu)",
  567. (unsigned long) list_len,
  568. (unsigned long) alen);
  569. return -1;
  570. }
  571. attr->version_list = apos + 2;
  572. attr->version_list_len = list_len;
  573. break;
  574. case EAP_SIM_AT_SELECTED_VERSION:
  575. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
  576. if (alen != 2) {
  577. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  578. "AT_SELECTED_VERSION length %lu",
  579. (unsigned long) alen);
  580. return -1;
  581. }
  582. attr->selected_version = apos[0] * 256 + apos[1];
  583. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
  584. "%d", attr->selected_version);
  585. break;
  586. case EAP_SIM_AT_FULLAUTH_ID_REQ:
  587. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
  588. attr->id_req = FULLAUTH_ID;
  589. break;
  590. case EAP_SIM_AT_COUNTER:
  591. if (!encr) {
  592. wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
  593. "AT_COUNTER");
  594. return -1;
  595. }
  596. if (alen != 2) {
  597. wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
  598. "AT_COUNTER (alen=%lu)",
  599. (unsigned long) alen);
  600. return -1;
  601. }
  602. attr->counter = apos[0] * 256 + apos[1];
  603. wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
  604. attr->counter);
  605. break;
  606. case EAP_SIM_AT_COUNTER_TOO_SMALL:
  607. if (!encr) {
  608. wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
  609. "AT_COUNTER_TOO_SMALL");
  610. return -1;
  611. }
  612. if (alen != 2) {
  613. wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
  614. "AT_COUNTER_TOO_SMALL (alen=%lu)",
  615. (unsigned long) alen);
  616. return -1;
  617. }
  618. wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
  619. "AT_COUNTER_TOO_SMALL");
  620. attr->counter_too_small = 1;
  621. break;
  622. case EAP_SIM_AT_NONCE_S:
  623. if (!encr) {
  624. wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
  625. "AT_NONCE_S");
  626. return -1;
  627. }
  628. wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
  629. "AT_NONCE_S");
  630. if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
  631. wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
  632. "AT_NONCE_S (alen=%lu)",
  633. (unsigned long) alen);
  634. return -1;
  635. }
  636. attr->nonce_s = apos + 2;
  637. break;
  638. case EAP_SIM_AT_CLIENT_ERROR_CODE:
  639. if (alen != 2) {
  640. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  641. "AT_CLIENT_ERROR_CODE length %lu",
  642. (unsigned long) alen);
  643. return -1;
  644. }
  645. attr->client_error_code = apos[0] * 256 + apos[1];
  646. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
  647. "%d", attr->client_error_code);
  648. break;
  649. case EAP_SIM_AT_IV:
  650. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
  651. if (alen != 2 + EAP_SIM_MAC_LEN) {
  652. wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
  653. "length %lu", (unsigned long) alen);
  654. return -1;
  655. }
  656. attr->iv = apos + 2;
  657. break;
  658. case EAP_SIM_AT_ENCR_DATA:
  659. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
  660. attr->encr_data = apos + 2;
  661. attr->encr_data_len = alen - 2;
  662. if (attr->encr_data_len % 16) {
  663. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  664. "AT_ENCR_DATA length %lu",
  665. (unsigned long)
  666. attr->encr_data_len);
  667. return -1;
  668. }
  669. break;
  670. case EAP_SIM_AT_NEXT_PSEUDONYM:
  671. if (!encr) {
  672. wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
  673. "AT_NEXT_PSEUDONYM");
  674. return -1;
  675. }
  676. wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
  677. "AT_NEXT_PSEUDONYM");
  678. plen = apos[0] * 256 + apos[1];
  679. if (plen > alen - 2) {
  680. wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
  681. " AT_NEXT_PSEUDONYM (actual"
  682. " len %lu, attr len %lu)",
  683. (unsigned long) plen,
  684. (unsigned long) alen);
  685. return -1;
  686. }
  687. attr->next_pseudonym = pos + 4;
  688. attr->next_pseudonym_len = plen;
  689. break;
  690. case EAP_SIM_AT_NEXT_REAUTH_ID:
  691. if (!encr) {
  692. wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
  693. "AT_NEXT_REAUTH_ID");
  694. return -1;
  695. }
  696. wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
  697. "AT_NEXT_REAUTH_ID");
  698. plen = apos[0] * 256 + apos[1];
  699. if (plen > alen - 2) {
  700. wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
  701. " AT_NEXT_REAUTH_ID (actual"
  702. " len %lu, attr len %lu)",
  703. (unsigned long) plen,
  704. (unsigned long) alen);
  705. return -1;
  706. }
  707. attr->next_reauth_id = pos + 4;
  708. attr->next_reauth_id_len = plen;
  709. break;
  710. case EAP_SIM_AT_RES:
  711. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
  712. attr->res_len_bits = WPA_GET_BE16(apos);
  713. apos += 2;
  714. alen -= 2;
  715. if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
  716. alen > EAP_AKA_MAX_RES_LEN) {
  717. wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
  718. "(len %lu)",
  719. (unsigned long) alen);
  720. return -1;
  721. }
  722. attr->res = apos;
  723. attr->res_len = alen;
  724. break;
  725. case EAP_SIM_AT_AUTS:
  726. wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
  727. if (!aka) {
  728. wpa_printf(MSG_DEBUG, "EAP-SIM: "
  729. "Unexpected AT_AUTS");
  730. return -1;
  731. }
  732. if (alen != EAP_AKA_AUTS_LEN) {
  733. wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
  734. " (len %lu)",
  735. (unsigned long) alen);
  736. return -1;
  737. }
  738. attr->auts = apos;
  739. break;
  740. case EAP_SIM_AT_CHECKCODE:
  741. wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE");
  742. if (!aka) {
  743. wpa_printf(MSG_DEBUG, "EAP-SIM: "
  744. "Unexpected AT_CHECKCODE");
  745. return -1;
  746. }
  747. apos += 2;
  748. alen -= 2;
  749. if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
  750. alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
  751. wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
  752. "AT_CHECKCODE (len %lu)",
  753. (unsigned long) alen);
  754. return -1;
  755. }
  756. attr->checkcode = apos;
  757. attr->checkcode_len = alen;
  758. break;
  759. case EAP_SIM_AT_RESULT_IND:
  760. if (encr) {
  761. wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted "
  762. "AT_RESULT_IND");
  763. return -1;
  764. }
  765. if (alen != 2) {
  766. wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
  767. "AT_RESULT_IND (alen=%lu)",
  768. (unsigned long) alen);
  769. return -1;
  770. }
  771. wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
  772. attr->result_ind = 1;
  773. break;
  774. #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
  775. case EAP_SIM_AT_KDF_INPUT:
  776. if (aka != 2) {
  777. wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
  778. "AT_KDF_INPUT");
  779. return -1;
  780. }
  781. wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
  782. plen = WPA_GET_BE16(apos);
  783. apos += 2;
  784. alen -= 2;
  785. if (plen > alen) {
  786. wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
  787. "AT_KDF_INPUT (Actual Length %lu, "
  788. "remaining length %lu)",
  789. (unsigned long) plen,
  790. (unsigned long) alen);
  791. return -1;
  792. }
  793. attr->kdf_input = apos;
  794. attr->kdf_input_len = plen;
  795. break;
  796. case EAP_SIM_AT_KDF:
  797. if (aka != 2) {
  798. wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
  799. "AT_KDF");
  800. return -1;
  801. }
  802. wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
  803. if (alen != 2) {
  804. wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
  805. "AT_KDF (len %lu)",
  806. (unsigned long) alen);
  807. return -1;
  808. }
  809. if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
  810. wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
  811. "AT_KDF attributes - ignore this");
  812. continue;
  813. }
  814. attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
  815. attr->kdf_count++;
  816. break;
  817. case EAP_SIM_AT_BIDDING:
  818. wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING");
  819. if (alen != 2) {
  820. wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
  821. "AT_BIDDING (len %lu)",
  822. (unsigned long) alen);
  823. return -1;
  824. }
  825. attr->bidding = apos;
  826. break;
  827. #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
  828. default:
  829. if (pos[0] < 128) {
  830. wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
  831. "non-skippable attribute %d",
  832. pos[0]);
  833. return -1;
  834. }
  835. wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
  836. " attribute %d ignored", pos[0]);
  837. break;
  838. }
  839. pos += pos[1] * 4;
  840. }
  841. wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
  842. "(aka=%d encr=%d)", aka, encr);
  843. return 0;
  844. }
  845. u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
  846. size_t encr_data_len, const u8 *iv,
  847. struct eap_sim_attrs *attr, int aka)
  848. {
  849. u8 *decrypted;
  850. if (!iv) {
  851. wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
  852. return NULL;
  853. }
  854. decrypted = os_malloc(encr_data_len);
  855. if (decrypted == NULL)
  856. return NULL;
  857. os_memcpy(decrypted, encr_data, encr_data_len);
  858. if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
  859. os_free(decrypted);
  860. return NULL;
  861. }
  862. wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
  863. decrypted, encr_data_len);
  864. if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
  865. aka, 1)) {
  866. wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
  867. "decrypted AT_ENCR_DATA");
  868. os_free(decrypted);
  869. return NULL;
  870. }
  871. return decrypted;
  872. }
  873. #define EAP_SIM_INIT_LEN 128
  874. struct eap_sim_msg {
  875. struct wpabuf *buf;
  876. size_t mac, iv, encr; /* index from buf */
  877. int type;
  878. };
  879. struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
  880. {
  881. struct eap_sim_msg *msg;
  882. struct eap_hdr *eap;
  883. u8 *pos;
  884. msg = os_zalloc(sizeof(*msg));
  885. if (msg == NULL)
  886. return NULL;
  887. msg->type = type;
  888. msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
  889. if (msg->buf == NULL) {
  890. os_free(msg);
  891. return NULL;
  892. }
  893. eap = wpabuf_put(msg->buf, sizeof(*eap));
  894. eap->code = code;
  895. eap->identifier = id;
  896. pos = wpabuf_put(msg->buf, 4);
  897. *pos++ = type;
  898. *pos++ = subtype;
  899. *pos++ = 0; /* Reserved */
  900. *pos++ = 0; /* Reserved */
  901. return msg;
  902. }
  903. struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
  904. const u8 *extra, size_t extra_len)
  905. {
  906. struct eap_hdr *eap;
  907. struct wpabuf *buf;
  908. if (msg == NULL)
  909. return NULL;
  910. eap = wpabuf_mhead(msg->buf);
  911. eap->length = host_to_be16(wpabuf_len(msg->buf));
  912. #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
  913. if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
  914. eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
  915. wpabuf_len(msg->buf),
  916. (u8 *) wpabuf_mhead(msg->buf) +
  917. msg->mac, extra, extra_len);
  918. } else
  919. #endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
  920. if (k_aut && msg->mac) {
  921. eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
  922. wpabuf_len(msg->buf),
  923. (u8 *) wpabuf_mhead(msg->buf) + msg->mac,
  924. extra, extra_len);
  925. }
  926. buf = msg->buf;
  927. os_free(msg);
  928. return buf;
  929. }
  930. void eap_sim_msg_free(struct eap_sim_msg *msg)
  931. {
  932. if (msg) {
  933. wpabuf_free(msg->buf);
  934. os_free(msg);
  935. }
  936. }
  937. u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
  938. const u8 *data, size_t len)
  939. {
  940. int attr_len = 2 + len;
  941. int pad_len;
  942. u8 *start;
  943. if (msg == NULL)
  944. return NULL;
  945. pad_len = (4 - attr_len % 4) % 4;
  946. attr_len += pad_len;
  947. if (wpabuf_resize(&msg->buf, attr_len))
  948. return NULL;
  949. start = wpabuf_put(msg->buf, 0);
  950. wpabuf_put_u8(msg->buf, attr);
  951. wpabuf_put_u8(msg->buf, attr_len / 4);
  952. wpabuf_put_data(msg->buf, data, len);
  953. if (pad_len)
  954. os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
  955. return start;
  956. }
  957. u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
  958. const u8 *data, size_t len)
  959. {
  960. int attr_len = 4 + len;
  961. int pad_len;
  962. u8 *start;
  963. if (msg == NULL)
  964. return NULL;
  965. pad_len = (4 - attr_len % 4) % 4;
  966. attr_len += pad_len;
  967. if (wpabuf_resize(&msg->buf, attr_len))
  968. return NULL;
  969. start = wpabuf_put(msg->buf, 0);
  970. wpabuf_put_u8(msg->buf, attr);
  971. wpabuf_put_u8(msg->buf, attr_len / 4);
  972. wpabuf_put_be16(msg->buf, value);
  973. if (data)
  974. wpabuf_put_data(msg->buf, data, len);
  975. else
  976. wpabuf_put(msg->buf, len);
  977. if (pad_len)
  978. os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
  979. return start;
  980. }
  981. u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
  982. {
  983. u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
  984. if (pos)
  985. msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
  986. return pos;
  987. }
  988. int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
  989. u8 attr_encr)
  990. {
  991. u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
  992. if (pos == NULL)
  993. return -1;
  994. msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
  995. if (os_get_random(wpabuf_mhead_u8(msg->buf) + msg->iv,
  996. EAP_SIM_IV_LEN)) {
  997. msg->iv = 0;
  998. return -1;
  999. }
  1000. pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
  1001. if (pos == NULL) {
  1002. msg->iv = 0;
  1003. return -1;
  1004. }
  1005. msg->encr = pos - wpabuf_head_u8(msg->buf);
  1006. return 0;
  1007. }
  1008. int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
  1009. {
  1010. size_t encr_len;
  1011. if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
  1012. return -1;
  1013. encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
  1014. if (encr_len % 16) {
  1015. u8 *pos;
  1016. int pad_len = 16 - (encr_len % 16);
  1017. if (pad_len < 4) {
  1018. wpa_printf(MSG_WARNING, "EAP-SIM: "
  1019. "eap_sim_msg_add_encr_end - invalid pad_len"
  1020. " %d", pad_len);
  1021. return -1;
  1022. }
  1023. wpa_printf(MSG_DEBUG, " *AT_PADDING");
  1024. pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
  1025. if (pos == NULL)
  1026. return -1;
  1027. os_memset(pos + 4, 0, pad_len - 4);
  1028. encr_len += pad_len;
  1029. }
  1030. wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)",
  1031. (unsigned long) encr_len);
  1032. wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
  1033. return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
  1034. wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
  1035. encr_len);
  1036. }
  1037. void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
  1038. {
  1039. #ifndef CONFIG_NO_STDOUT_DEBUG
  1040. const char *type = aka ? "AKA" : "SIM";
  1041. #endif /* CONFIG_NO_STDOUT_DEBUG */
  1042. switch (notification) {
  1043. case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
  1044. wpa_printf(MSG_WARNING, "EAP-%s: General failure "
  1045. "notification (after authentication)", type);
  1046. break;
  1047. case EAP_SIM_TEMPORARILY_DENIED:
  1048. wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
  1049. "User has been temporarily denied access to the "
  1050. "requested service", type);
  1051. break;
  1052. case EAP_SIM_NOT_SUBSCRIBED:
  1053. wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
  1054. "User has not subscribed to the requested service",
  1055. type);
  1056. break;
  1057. case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
  1058. wpa_printf(MSG_WARNING, "EAP-%s: General failure "
  1059. "notification (before authentication)", type);
  1060. break;
  1061. case EAP_SIM_SUCCESS:
  1062. wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
  1063. "notification", type);
  1064. break;
  1065. default:
  1066. if (notification >= 32768) {
  1067. wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
  1068. "non-failure notification %d",
  1069. type, notification);
  1070. } else {
  1071. wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
  1072. "failure notification %d",
  1073. type, notification);
  1074. }
  1075. }
  1076. }