udp: Merge udp_send and udp_output
[dragonfly.git] / contrib / wpa_supplicant / src / eap_common / eap_fast_common.c
1 /*
2  * EAP-FAST common helper functions (RFC 4851)
3  * Copyright (c) 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
15 #include "includes.h"
16
17 #include "common.h"
18 #include "sha1.h"
19 #include "tls.h"
20 #include "eap_defs.h"
21 #include "eap_tlv_common.h"
22 #include "eap_fast_common.h"
23
24
25 void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
26 {
27         struct pac_tlv_hdr hdr;
28         hdr.type = host_to_be16(type);
29         hdr.len = host_to_be16(len);
30         wpabuf_put_data(buf, &hdr, sizeof(hdr));
31 }
32
33
34 void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
35                              u16 len)
36 {
37         eap_fast_put_tlv_hdr(buf, type, len);
38         wpabuf_put_data(buf, data, len);
39 }
40
41
42 void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
43                                  const struct wpabuf *data)
44 {
45         eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
46         wpabuf_put_buf(buf, data);
47 }
48
49
50 struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
51 {
52         struct wpabuf *e;
53
54         if (buf == NULL)
55                 return NULL;
56
57         /* Encapsulate EAP packet in EAP-Payload TLV */
58         wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
59         e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
60         if (e == NULL) {
61                 wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
62                            "for TLV encapsulation");
63                 wpabuf_free(buf);
64                 return NULL;
65         }
66         eap_fast_put_tlv_buf(e,
67                              EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
68                              buf);
69         wpabuf_free(buf);
70         return e;
71 }
72
73
74 void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
75                                    const u8 *client_random, u8 *master_secret)
76 {
77 #define TLS_RANDOM_LEN 32
78 #define TLS_MASTER_SECRET_LEN 48
79         u8 seed[2 * TLS_RANDOM_LEN];
80
81         wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
82                     client_random, TLS_RANDOM_LEN);
83         wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
84                     server_random, TLS_RANDOM_LEN);
85
86         /*
87          * RFC 4851, Section 5.1:
88          * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
89          *                       server_random + client_random, 48)
90          */
91         os_memcpy(seed, server_random, TLS_RANDOM_LEN);
92         os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
93         sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
94                    "PAC to master secret label hash",
95                    seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
96
97         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
98                         master_secret, TLS_MASTER_SECRET_LEN);
99 }
100
101
102 u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
103                          const char *label, size_t len)
104 {
105         struct tls_keys keys;
106         u8 *rnd = NULL, *out;
107         int block_size;
108
109         block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
110         if (block_size < 0)
111                 return NULL;
112
113         out = os_malloc(block_size + len);
114         if (out == NULL)
115                 return NULL;
116
117         if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
118             == 0) {
119                 os_memmove(out, out + block_size, len);
120                 return out;
121         }
122
123         if (tls_connection_get_keys(ssl_ctx, conn, &keys))
124                 goto fail;
125
126         rnd = os_malloc(keys.client_random_len + keys.server_random_len);
127         if (rnd == NULL)
128                 goto fail;
129
130         os_memcpy(rnd, keys.server_random, keys.server_random_len);
131         os_memcpy(rnd + keys.server_random_len, keys.client_random,
132                   keys.client_random_len);
133
134         wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
135                         "expansion", keys.master_key, keys.master_key_len);
136         if (tls_prf(keys.master_key, keys.master_key_len,
137                     label, rnd, keys.client_random_len +
138                     keys.server_random_len, out, block_size + len))
139                 goto fail;
140         os_free(rnd);
141         os_memmove(out, out + block_size, len);
142         return out;
143
144 fail:
145         os_free(rnd);
146         os_free(out);
147         return NULL;
148 }
149
150
151 void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
152 {
153         /*
154          * RFC 4851, Section 5.4: EAP Master Session Key Generation
155          * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
156          */
157
158         sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
159                    "Session Key Generating Function", (u8 *) "", 0,
160                    msk, EAP_FAST_KEY_LEN);
161         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
162                         msk, EAP_FAST_KEY_LEN);
163 }
164
165
166 void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
167 {
168         /*
169          * RFC 4851, Section 5.4: EAP Master Session Key Genreration
170          * EMSK = T-PRF(S-IMCK[j],
171          *        "Extended Session Key Generating Function", 64)
172          */
173
174         sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
175                    "Extended Session Key Generating Function", (u8 *) "", 0,
176                    emsk, EAP_EMSK_LEN);
177         wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
178                         emsk, EAP_EMSK_LEN);
179 }
180
181
182 int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
183                        int tlv_type, u8 *pos, int len)
184 {
185         switch (tlv_type) {
186         case EAP_TLV_EAP_PAYLOAD_TLV:
187                 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
188                             pos, len);
189                 if (tlv->eap_payload_tlv) {
190                         wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
191                                    "EAP-Payload TLV in the message");
192                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
193                         return -2;
194                 }
195                 tlv->eap_payload_tlv = pos;
196                 tlv->eap_payload_tlv_len = len;
197                 break;
198         case EAP_TLV_RESULT_TLV:
199                 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
200                 if (tlv->result) {
201                         wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
202                                    "Result TLV in the message");
203                         tlv->result = EAP_TLV_RESULT_FAILURE;
204                         return -2;
205                 }
206                 if (len < 2) {
207                         wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
208                                    "Result TLV");
209                         tlv->result = EAP_TLV_RESULT_FAILURE;
210                         break;
211                 }
212                 tlv->result = WPA_GET_BE16(pos);
213                 if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
214                     tlv->result != EAP_TLV_RESULT_FAILURE) {
215                         wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
216                                    tlv->result);
217                         tlv->result = EAP_TLV_RESULT_FAILURE;
218                 }
219                 wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
220                            tlv->result == EAP_TLV_RESULT_SUCCESS ?
221                            "Success" : "Failure");
222                 break;
223         case EAP_TLV_INTERMEDIATE_RESULT_TLV:
224                 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
225                             pos, len);
226                 if (len < 2) {
227                         wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
228                                    "Intermediate-Result TLV");
229                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
230                         break;
231                 }
232                 if (tlv->iresult) {
233                         wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
234                                    "Intermediate-Result TLV in the message");
235                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
236                         return -2;
237                 }
238                 tlv->iresult = WPA_GET_BE16(pos);
239                 if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
240                     tlv->iresult != EAP_TLV_RESULT_FAILURE) {
241                         wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
242                                    "Result %d", tlv->iresult);
243                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
244                 }
245                 wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
246                            tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
247                            "Success" : "Failure");
248                 break;
249         case EAP_TLV_CRYPTO_BINDING_TLV:
250                 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
251                             pos, len);
252                 if (tlv->crypto_binding) {
253                         wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
254                                    "Crypto-Binding TLV in the message");
255                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
256                         return -2;
257                 }
258                 tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
259                 if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
260                         wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
261                                    "Crypto-Binding TLV");
262                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
263                         return -2;
264                 }
265                 tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
266                         (pos - sizeof(struct eap_tlv_hdr));
267                 break;
268         case EAP_TLV_REQUEST_ACTION_TLV:
269                 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
270                             pos, len);
271                 if (tlv->request_action) {
272                         wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
273                                    "Request-Action TLV in the message");
274                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
275                         return -2;
276                 }
277                 if (len < 2) {
278                         wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
279                                    "Request-Action TLV");
280                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
281                         break;
282                 }
283                 tlv->request_action = WPA_GET_BE16(pos);
284                 wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
285                            tlv->request_action);
286                 break;
287         case EAP_TLV_PAC_TLV:
288                 wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
289                 if (tlv->pac) {
290                         wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
291                                    "PAC TLV in the message");
292                         tlv->iresult = EAP_TLV_RESULT_FAILURE;
293                         return -2;
294                 }
295                 tlv->pac = pos;
296                 tlv->pac_len = len;
297                 break;
298         default:
299                 /* Unknown TLV */
300                 return -1;
301         }
302
303         return 0;
304 }