Add manpage for stge(4)
[dragonfly.git] / contrib / wpa_supplicant-0.4.9 / eap_sim_common.c
1 /*
2  * WPA Supplicant / EAP-SIM/AKA shared routines
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "common.h"
20 #include "eap_i.h"
21 #include "sha1.h"
22 #include "crypto.h"
23 #include "aes_wrap.h"
24 #include "eap_sim_common.h"
25
26
27 static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
28 {
29         u8 xkey[64];
30         u32 t[5], _t[5];
31         int i, j, m, k;
32         u8 *xpos = x;
33         u32 carry;
34
35         /* FIPS 186-2 + change notice 1 */
36
37         memcpy(xkey, key, EAP_SIM_MK_LEN);
38         memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_LEN);
39         t[0] = 0x67452301;
40         t[1] = 0xEFCDAB89;
41         t[2] = 0x98BADCFE;
42         t[3] = 0x10325476;
43         t[4] = 0xC3D2E1F0;
44
45         m = xlen / 40;
46         for (j = 0; j < m; j++) {
47                 /* XSEED_j = 0 */
48                 for (i = 0; i < 2; i++) {
49                         /* XVAL = (XKEY + XSEED_j) mod 2^b */
50
51                         /* w_i = G(t, XVAL) */
52                         memcpy(_t, t, 20);
53                         sha1_transform((u8 *) _t, xkey);
54                         _t[0] = host_to_be32(_t[0]);
55                         _t[1] = host_to_be32(_t[1]);
56                         _t[2] = host_to_be32(_t[2]);
57                         _t[3] = host_to_be32(_t[3]);
58                         _t[4] = host_to_be32(_t[4]);
59                         memcpy(xpos, _t, 20);
60
61                         /* XKEY = (1 + XKEY + w_i) mod 2^b */
62                         carry = 1;
63                         for (k = 19; k >= 0; k--) {
64                                 carry += xkey[k] + xpos[k];
65                                 xkey[k] = carry & 0xff;
66                                 carry >>= 8;
67                         }
68
69                         xpos += SHA1_MAC_LEN;
70                 }
71                 /* x_j = w_0|w_1 */
72         }
73 }
74
75
76 void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
77 {
78         u8 buf[120], *pos;
79         eap_sim_prf(mk, buf, 120);
80         pos = buf;
81         memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
82         pos += EAP_SIM_K_ENCR_LEN;
83         memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
84         pos += EAP_SIM_K_AUT_LEN;
85         memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
86
87         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
88                         k_encr, EAP_SIM_K_ENCR_LEN);
89         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
90                         k_aut, EAP_SIM_K_ENCR_LEN);
91         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
92                         msk, EAP_SIM_KEYING_DATA_LEN);
93 }
94
95
96 void eap_sim_derive_keys_reauth(u16 _counter,
97                                 const u8 *identity, size_t identity_len,
98                                 const u8 *nonce_s, const u8 *mk, u8 *msk)
99 {
100         u8 xkey[SHA1_MAC_LEN];
101         u8 counter[2];
102         const u8 *addr[4];
103         size_t len[4];
104
105         addr[0] = identity;
106         len[0] = identity_len;
107         addr[1] = counter;
108         len[1] = 2;
109         addr[2] = nonce_s;
110         len[2] = EAP_SIM_NONCE_S_LEN;
111         addr[3] = mk;
112         len[3] = EAP_SIM_MK_LEN;
113
114         WPA_PUT_BE16(counter, _counter);
115
116         wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
117         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
118                           identity, identity_len);
119         wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
120         wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
121                     EAP_SIM_NONCE_S_LEN);
122         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
123
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
128         eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
129         wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
130                     msk, EAP_SIM_KEYING_DATA_LEN);
131 }
132
133
134 int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
135                        const u8 *mac, const u8 *extra, size_t extra_len)
136 {
137         unsigned char hmac[SHA1_MAC_LEN];
138         const u8 *addr[2];
139         size_t len[2];
140         u8 *tmp;
141
142         if (mac == NULL || req_len < EAP_SIM_MAC_LEN || mac < req ||
143             mac > req + req_len - EAP_SIM_MAC_LEN)
144                 return -1;
145
146         tmp = malloc(req_len);
147         if (tmp == NULL)
148                 return -1;
149
150         addr[0] = tmp;
151         len[0] = req_len;
152         addr[1] = extra;
153         len[1] = extra_len;
154
155         /* HMAC-SHA1-128 */
156         memcpy(tmp, req, req_len);
157         memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
158         hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
159         free(tmp);
160
161         return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
162 }
163
164
165 void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
166                      const u8 *extra, size_t extra_len)
167 {
168         unsigned char hmac[SHA1_MAC_LEN];
169         const u8 *addr[2];
170         size_t len[2];
171
172         addr[0] = msg;
173         len[0] = msg_len;
174         addr[1] = extra;
175         len[1] = extra_len;
176
177         /* HMAC-SHA1-128 */
178         memset(mac, 0, EAP_SIM_MAC_LEN);
179         hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
180         memcpy(mac, hmac, EAP_SIM_MAC_LEN);
181 }
182
183
184 int eap_sim_parse_attr(const u8 *start, const u8 *end,
185                        struct eap_sim_attrs *attr, int aka, int encr)
186 {
187         const u8 *pos = start, *apos;
188         size_t alen, plen;
189         int list_len, i;
190
191         memset(attr, 0, sizeof(*attr));
192         attr->id_req = NO_ID_REQ;
193         attr->notification = -1;
194         attr->counter = -1;
195         attr->selected_version = -1;
196         attr->client_error_code = -1;
197
198         while (pos < end) {
199                 if (pos + 2 > end) {
200                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
201                         return -1;
202                 }
203                 wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
204                            pos[0], pos[1] * 4);
205                 if (pos + pos[1] * 4 > end) {
206                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
207                                    "(pos=%p len=%d end=%p)",
208                                    pos, pos[1] * 4, end);
209                         return -1;
210                 }
211                 apos = pos + 2;
212                 alen = pos[1] * 4 - 2;
213                 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
214                             apos, alen);
215
216                 switch (pos[0]) {
217                 case EAP_SIM_AT_RAND:
218                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
219                         apos += 2;
220                         alen -= 2;
221                         if ((!aka && (alen % GSM_RAND_LEN)) ||
222                             (aka && alen != AKA_RAND_LEN)) {
223                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
224                                            " (len %lu)",
225                                            (unsigned long) alen);
226                                 return -1;
227                         }
228                         attr->rand = apos;
229                         attr->num_chal = alen / GSM_RAND_LEN;
230                         break;
231                 case EAP_SIM_AT_AUTN:
232                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
233                         if (!aka) {
234                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
235                                            "Unexpected AT_AUTN");
236                                 return -1;
237                         }
238                         apos += 2;
239                         alen -= 2;
240                         if (alen != AKA_AUTN_LEN) {
241                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
242                                            " (len %lu)",
243                                            (unsigned long) alen);
244                                 return -1;
245                         }
246                         attr->autn = apos;
247                         break;
248                 case EAP_SIM_AT_PADDING:
249                         if (!encr) {
250                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
251                                            "AT_PADDING");
252                                 return -1;
253                         }
254                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
255                         for (i = 2; i < alen; i++) {
256                                 if (apos[i] != 0) {
257                                         wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
258                                                    "AT_PADDING used a non-zero"
259                                                    " padding byte");
260                                         wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
261                                                     "(encr) padding bytes",
262                                                     apos + 2, alen - 2);
263                                         return -1;
264                                 }
265                         }
266                         break;
267                 case EAP_SIM_AT_NONCE_MT:
268                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
269                         if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
270                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
271                                            "AT_NONCE_MT length");
272                                 return -1;
273                         }
274                         attr->nonce_mt = apos + 2;
275                         break;
276                 case EAP_SIM_AT_PERMANENT_ID_REQ:
277                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
278                         attr->id_req = PERMANENT_ID;
279                         break;
280                 case EAP_SIM_AT_MAC:
281                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
282                         if (alen != 2 + EAP_SIM_MAC_LEN) {
283                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
284                                            "length");
285                                 return -1;
286                         }
287                         attr->mac = apos + 2;
288                         break;
289                 case EAP_SIM_AT_NOTIFICATION:
290                         if (alen != 2) {
291                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
292                                            "AT_NOTIFICATION length %lu",
293                                            (unsigned long) alen);
294                                 return -1;
295                         }
296                         attr->notification = apos[0] * 256 + apos[1];
297                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
298                                    attr->notification);
299                         break;
300                 case EAP_SIM_AT_ANY_ID_REQ:
301                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
302                         attr->id_req = ANY_ID;
303                         break;
304                 case EAP_SIM_AT_IDENTITY:
305                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
306                         attr->identity = apos + 2;
307                         attr->identity_len = alen - 2;
308                         break;
309                 case EAP_SIM_AT_VERSION_LIST:
310                         if (aka) {
311                                 wpa_printf(MSG_DEBUG, "EAP-AKA: "
312                                            "Unexpected AT_VERSION_LIST");
313                                 return -1;
314                         }
315                         list_len = apos[0] * 256 + apos[1];
316                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
317                         if (list_len < 2 || list_len > alen - 2) {
318                                 wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
319                                            "AT_VERSION_LIST (list_len=%d "
320                                            "attr_len=%lu)", list_len,
321                                            (unsigned long) alen);
322                                 return -1;
323                         }
324                         attr->version_list = apos + 2;
325                         attr->version_list_len = list_len;
326                         break;
327                 case EAP_SIM_AT_SELECTED_VERSION:
328                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
329                         if (alen != 2) {
330                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
331                                            "AT_SELECTED_VERSION length %lu",
332                                            (unsigned long) alen);
333                                 return -1;
334                         }
335                         attr->selected_version = apos[0] * 256 + apos[1];
336                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
337                                    "%d", attr->selected_version);
338                         break;
339                 case EAP_SIM_AT_FULLAUTH_ID_REQ:
340                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
341                         attr->id_req = FULLAUTH_ID;
342                         break;
343                 case EAP_SIM_AT_COUNTER:
344                         if (!encr) {
345                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
346                                            "AT_COUNTER");
347                                 return -1;
348                         }
349                         if (alen != 2) {
350                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
351                                            "AT_COUNTER (alen=%lu)",
352                                            (unsigned long) alen);
353                                 return -1;
354                         }
355                         attr->counter = apos[0] * 256 + apos[1];
356                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
357                                    attr->counter);
358                         break;
359                 case EAP_SIM_AT_NONCE_S:
360                         if (!encr) {
361                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
362                                            "AT_NONCE_S");
363                                 return -1;
364                         }
365                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
366                                    "AT_NONCE_S");
367                         if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
368                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
369                                            "AT_NONCE_S (alen=%lu)",
370                                            (unsigned long) alen);
371                                 return -1;
372                         }
373                         attr->nonce_s = apos + 2;
374                         break;
375                 case EAP_SIM_AT_CLIENT_ERROR_CODE:
376                         if (alen != 2) {
377                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
378                                            "AT_CLIENT_ERROR_CODE length %lu",
379                                            (unsigned long) alen);
380                                 return -1;
381                         }
382                         attr->client_error_code = apos[0] * 256 + apos[1];
383                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
384                                    "%d", attr->client_error_code);
385                         break;
386                 case EAP_SIM_AT_IV:
387                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
388                         if (alen != 2 + EAP_SIM_MAC_LEN) {
389                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
390                                            "length %lu", (unsigned long) alen);
391                                 return -1;
392                         }
393                         attr->iv = apos + 2;
394                         break;
395                 case EAP_SIM_AT_ENCR_DATA:
396                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
397                         attr->encr_data = apos + 2;
398                         attr->encr_data_len = alen - 2;
399                         if (attr->encr_data_len % 16) {
400                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
401                                            "AT_ENCR_DATA length %lu",
402                                            (unsigned long)
403                                            attr->encr_data_len);
404                                 return -1;
405                         }
406                         break;
407                 case EAP_SIM_AT_NEXT_PSEUDONYM:
408                         if (!encr) {
409                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
410                                            "AT_NEXT_PSEUDONYM");
411                                 return -1;
412                         }
413                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
414                                    "AT_NEXT_PSEUDONYM");
415                         plen = apos[0] * 256 + apos[1];
416                         if (plen > alen - 2) {
417                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
418                                            " AT_NEXT_PSEUDONYM (actual"
419                                            " len %lu, attr len %lu)",
420                                            (unsigned long) plen,
421                                            (unsigned long) alen);
422                                 return -1;
423                         }
424                         attr->next_pseudonym = pos + 4;
425                         attr->next_pseudonym_len = plen;
426                         break;
427                 case EAP_SIM_AT_NEXT_REAUTH_ID:
428                         if (!encr) {
429                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
430                                            "AT_NEXT_REAUTH_ID");
431                                 return -1;
432                         }
433                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
434                                    "AT_NEXT_REAUTH_ID");
435                         plen = apos[0] * 256 + apos[1];
436                         if (plen > alen - 2) {
437                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
438                                            " AT_NEXT_REAUTH_ID (actual"
439                                            " len %lu, attr len %lu)",
440                                            (unsigned long) plen,
441                                            (unsigned long) alen);
442                                 return -1;
443                         }
444                         attr->next_reauth_id = pos + 4;
445                         attr->next_reauth_id_len = plen;
446                         break;
447                 default:
448                         if (pos[0] < 128) {
449                                 wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
450                                            "non-skippable attribute %d",
451                                            pos[0]);
452                                 return -1;
453                         }
454
455                         wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
456                                    " attribute %d ignored", pos[0]);
457                         break;
458                 }
459
460                 pos += pos[1] * 4;
461         }
462
463         wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
464                    "(aka=%d encr=%d)", aka, encr);
465
466         return 0;
467 }
468
469
470 u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
471                         size_t encr_data_len, const u8 *iv,
472                         struct eap_sim_attrs *attr, int aka)
473 {
474         u8 *decrypted;
475
476         if (!iv) {
477                 wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
478                 return NULL;
479         }
480
481         decrypted = malloc(encr_data_len);
482         if (decrypted == NULL)
483                 return NULL;
484         memcpy(decrypted, encr_data, encr_data_len);
485
486         aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
487         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
488                     decrypted, encr_data_len);
489
490         if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
491                                aka, 1)) {
492                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
493                            "decrypted AT_ENCR_DATA");
494                 free(decrypted);
495                 return NULL;
496         }
497
498         return decrypted;
499 }
500
501
502 #define EAP_SIM_INIT_LEN 128
503
504 struct eap_sim_msg {
505         u8 *buf;
506         size_t buf_len, used;
507         size_t mac, iv, encr; /* index from buf */
508 };
509
510
511 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
512 {
513         struct eap_sim_msg *msg;
514         struct eap_hdr *eap;
515         u8 *pos;
516
517         msg = malloc(sizeof(*msg));
518         if (msg == NULL)
519                 return NULL;
520         memset(msg, 0, sizeof(*msg));
521
522         msg->buf = malloc(EAP_SIM_INIT_LEN);
523         if (msg->buf == NULL) {
524                 free(msg);
525                 return NULL;
526         }
527         memset(msg->buf, 0, EAP_SIM_INIT_LEN);
528         msg->buf_len = EAP_SIM_INIT_LEN;
529         eap = (struct eap_hdr *) msg->buf;
530         eap->code = code;
531         eap->identifier = id;
532         msg->used = sizeof(*eap);
533
534         pos = (u8 *) (eap + 1);
535         *pos++ = type;
536         *pos++ = subtype;
537         *pos++ = 0; /* Reserved */
538         *pos++ = 0; /* Reserved */
539         msg->used += 4;
540
541         return msg;
542 }
543
544
545 u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
546                         const u8 *extra, size_t extra_len)
547 {
548         struct eap_hdr *eap;
549         u8 *buf;
550
551         if (msg == NULL)
552                 return NULL;
553
554         eap = (struct eap_hdr *) msg->buf;
555         eap->length = host_to_be16(msg->used);
556
557         if (k_aut && msg->mac) {
558                 eap_sim_add_mac(k_aut, msg->buf, msg->used,
559                                 msg->buf + msg->mac, extra, extra_len);
560         }
561
562         *len = msg->used;
563         buf = msg->buf;
564         free(msg);
565         return buf;
566 }
567
568
569 void eap_sim_msg_free(struct eap_sim_msg *msg)
570 {
571         if (msg) {
572                 free(msg->buf);
573                 free(msg);
574         }
575 }
576
577
578 static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
579 {
580         if (msg->used + add_len > msg->buf_len) {
581                 u8 *nbuf = realloc(msg->buf, msg->used + add_len);
582                 if (nbuf == NULL)
583                         return -1;
584                 msg->buf = nbuf;
585                 msg->buf_len = msg->used + add_len;
586         }
587         return 0;
588 }
589
590
591 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
592                           const u8 *data, size_t len)
593 {
594         int attr_len = 2 + len;
595         int pad_len;
596         u8 *start, *pos;
597
598         if (msg == NULL)
599                 return NULL;
600
601         pad_len = (4 - attr_len % 4) % 4;
602         attr_len += pad_len;
603         if (eap_sim_msg_resize(msg, attr_len))
604                 return NULL;
605         start = pos = msg->buf + msg->used;
606         *pos++ = attr;
607         *pos++ = attr_len / 4;
608         memcpy(pos, data, len);
609         if (pad_len) {
610                 pos += len;
611                 memset(pos, 0, pad_len);
612         }
613         msg->used += attr_len;
614         return start;
615 }
616
617
618 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
619                      const u8 *data, size_t len)
620 {
621         int attr_len = 4 + len;
622         int pad_len;
623         u8 *start, *pos;
624
625         if (msg == NULL)
626                 return NULL;
627
628         pad_len = (4 - attr_len % 4) % 4;
629         attr_len += pad_len;
630         if (eap_sim_msg_resize(msg, attr_len))
631                 return NULL;
632         start = pos = msg->buf + msg->used;
633         *pos++ = attr;
634         *pos++ = attr_len / 4;
635         WPA_PUT_BE16(pos, value);
636         pos += 2;
637         if (data)
638                 memcpy(pos, data, len);
639         if (pad_len) {
640                 pos += len;
641                 memset(pos, 0, pad_len);
642         }
643         msg->used += attr_len;
644         return start;
645 }
646
647
648 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
649 {
650         u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
651         if (pos)
652                 msg->mac = (pos - msg->buf) + 4;
653         return pos;
654 }
655
656
657 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
658                                u8 attr_encr)
659 {
660         u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
661         if (pos == NULL)
662                 return -1;
663         msg->iv = (pos - msg->buf) + 4;
664         if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
665                 msg->iv = 0;
666                 return -1;
667         }
668
669         pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
670         if (pos == NULL) {
671                 msg->iv = 0;
672                 return -1;
673         }
674         msg->encr = pos - msg->buf;
675
676         return 0;
677 }
678
679
680 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
681 {
682         size_t encr_len;
683
684         if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
685                 return -1;
686
687         encr_len = msg->used - msg->encr - 4;
688         if (encr_len % 16) {
689                 u8 *pos;
690                 int pad_len = 16 - (encr_len % 16);
691                 if (pad_len < 4) {
692                         wpa_printf(MSG_WARNING, "EAP-SIM: "
693                                    "eap_sim_msg_add_encr_end - invalid pad_len"
694                                    " %d", pad_len);
695                         return -1;
696                 }
697                 wpa_printf(MSG_DEBUG, "   *AT_PADDING");
698                 pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
699                 if (pos == NULL)
700                         return -1;
701                 memset(pos + 4, 0, pad_len - 4);
702                 encr_len += pad_len;
703         }
704         wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
705                    (unsigned long) encr_len);
706         msg->buf[msg->encr + 1] = encr_len / 4 + 1;
707         aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
708                             msg->buf + msg->encr + 4, encr_len);
709
710         return 0;
711 }
712
713
714 void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
715 {
716 #ifndef CONFIG_NO_STDOUT_DEBUG
717         const char *type = aka ? "AKA" : "SIM";
718 #endif /* CONFIG_NO_STDOUT_DEBUG */
719
720         switch (notification) {
721         case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
722                 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
723                            "notification (after authentication)", type);
724                 break;
725         case EAP_SIM_TEMPORARILY_DENIED:
726                 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
727                            "User has been temporarily denied access to the "
728                            "requested service", type);
729                 break;
730         case EAP_SIM_NOT_SUBSCRIBED:
731                 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
732                            "User has not subscribed to the requested service",
733                            type);
734                 break;
735         case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
736                 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
737                            "notification (before authentication)", type);
738                 break;
739         case EAP_SIM_SUCCESS:
740                 wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
741                            "notification", type);
742                 break;
743         default:
744                 if (notification >= 32768) {
745                         wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
746                                    "non-failure notification %d",
747                                    type, notification);
748                 } else {
749                         wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
750                                    "failure notification %d",
751                                    type, notification);
752                 }
753         }
754 }
755
756
757 #ifdef TEST_MAIN_EAP_SIM_COMMON
758 static int test_eap_sim_prf(void)
759 {
760         /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
761         u8 xkey[] = {
762                 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
763                 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
764                 0xeb, 0x5a, 0x38, 0xb6
765         };
766         u8 w[] = {
767                 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
768                 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
769                 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
770                 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
771                 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
772         };
773         u8 buf[40];
774
775         printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
776         eap_sim_prf(xkey, buf, sizeof(buf));
777         if (memcmp(w, buf, sizeof(w) != 0)) {
778                 printf("eap_sim_prf failed\n");
779                 return 1;
780         }
781
782         return 0;
783 }
784
785
786 int main(int argc, char *argv[])
787 {
788         int errors = 0;
789
790         errors += test_eap_sim_prf();
791
792         return errors;
793 }
794 #endif /* TEST_MAIN_EAP_SIM_COMMON */