xref: /dragonfly/contrib/wpa_supplicant/src/eap_common/eap_teap_common.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * EAP-TEAP common helper functions (RFC 7170)
3  * Copyright (c) 2008-2019, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "crypto/sha1.h"
13 #include "crypto/sha256.h"
14 #include "crypto/sha384.h"
15 #include "crypto/tls.h"
16 #include "eap_defs.h"
17 #include "eap_teap_common.h"
18 
19 
eap_teap_put_tlv_hdr(struct wpabuf * buf,u16 type,u16 len)20 void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
21 {
22           struct teap_tlv_hdr hdr;
23 
24           hdr.tlv_type = host_to_be16(type);
25           hdr.length = host_to_be16(len);
26           wpabuf_put_data(buf, &hdr, sizeof(hdr));
27 }
28 
29 
eap_teap_put_tlv(struct wpabuf * buf,u16 type,const void * data,u16 len)30 void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len)
31 {
32           eap_teap_put_tlv_hdr(buf, type, len);
33           wpabuf_put_data(buf, data, len);
34 }
35 
36 
eap_teap_put_tlv_buf(struct wpabuf * buf,u16 type,const struct wpabuf * data)37 void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
38                                 const struct wpabuf *data)
39 {
40           eap_teap_put_tlv_hdr(buf, type, wpabuf_len(data));
41           wpabuf_put_buf(buf, data);
42 }
43 
44 
eap_teap_tlv_eap_payload(struct wpabuf * buf)45 struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf)
46 {
47           struct wpabuf *e;
48 
49           if (!buf)
50                     return NULL;
51 
52           /* Encapsulate EAP packet in EAP-Payload TLV */
53           wpa_printf(MSG_DEBUG, "EAP-TEAP: Add EAP-Payload TLV");
54           e = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + wpabuf_len(buf));
55           if (!e) {
56                     wpa_printf(MSG_ERROR,
57                                  "EAP-TEAP: Failed to allocate memory for TLV encapsulation");
58                     wpabuf_free(buf);
59                     return NULL;
60           }
61           eap_teap_put_tlv_buf(e, TEAP_TLV_MANDATORY | TEAP_TLV_EAP_PAYLOAD, buf);
62           wpabuf_free(buf);
63 
64           /* TODO: followed by optional TLVs associated with the EAP packet */
65 
66           return e;
67 }
68 
69 
eap_teap_tls_prf(const u8 * secret,size_t secret_len,const char * label,const u8 * seed,size_t seed_len,u8 * out,size_t outlen)70 static int eap_teap_tls_prf(const u8 *secret, size_t secret_len,
71                                   const char *label, const u8 *seed, size_t seed_len,
72                                   u8 *out, size_t outlen)
73 {
74           /* TODO: TLS-PRF for TLSv1.3 */
75           return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
76                                     out, outlen);
77 }
78 
79 
eap_teap_derive_eap_msk(const u8 * simck,u8 * msk)80 int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk)
81 {
82           /*
83            * RFC 7170, Section 5.4: EAP Master Session Key Generation
84            * MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
85            */
86 
87           if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
88                                    "Session Key Generating Function", (u8 *) "", 0,
89                                    msk, EAP_TEAP_KEY_LEN) < 0)
90                     return -1;
91           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (MSK)",
92                               msk, EAP_TEAP_KEY_LEN);
93           return 0;
94 }
95 
96 
eap_teap_derive_eap_emsk(const u8 * simck,u8 * emsk)97 int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
98 {
99           /*
100            * RFC 7170, Section 5.4: EAP Master Session Key Generation
101            * EMSK = TLS-PRF(S-IMCK[j],
102            *        "Extended Session Key Generating Function", 64)
103            */
104 
105           if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
106                                    "Extended Session Key Generating Function",
107                                    (u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
108                     return -1;
109           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (EMSK)",
110                               emsk, EAP_EMSK_LEN);
111           return 0;
112 }
113 
114 
eap_teap_derive_cmk_basic_pw_auth(const u8 * s_imck_msk,u8 * cmk)115 int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
116 {
117           u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
118           int res;
119 
120           /* FIX: The Basic-Password-Auth (i.e., no inner EAP) case is
121            * not fully defined in RFC 7170, so this CMK derivation may
122            * need to be changed if a fixed definition is eventually
123            * published. For now, derive CMK[0] based on S-IMCK[0] and
124            * IMSK of 32 octets of zeros. */
125           os_memset(imsk, 0, 32);
126           res = eap_teap_tls_prf(s_imck_msk, EAP_TEAP_SIMCK_LEN,
127                                      "Inner Methods Compound Keys",
128                                      imsk, 32, imck, sizeof(imck));
129           if (res < 0)
130                     return -1;
131           os_memcpy(cmk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
132           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: CMK[no-inner-EAP]",
133                               cmk, EAP_TEAP_CMK_LEN);
134           forced_memzero(imck, sizeof(imck));
135           return 0;
136 }
137 
138 
eap_teap_derive_imck(const u8 * prev_s_imck_msk,const u8 * prev_s_imck_emsk,const u8 * msk,size_t msk_len,const u8 * emsk,size_t emsk_len,u8 * s_imck_msk,u8 * cmk_msk,u8 * s_imck_emsk,u8 * cmk_emsk)139 int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
140                                const u8 *msk, size_t msk_len,
141                                const u8 *emsk, size_t emsk_len,
142                                u8 *s_imck_msk, u8 *cmk_msk,
143                                u8 *s_imck_emsk, u8 *cmk_emsk)
144 {
145           u8 imsk[64], imck[EAP_TEAP_IMCK_LEN];
146           int res;
147 
148           /*
149            * RFC 7170, Section 5.2:
150            * IMSK = First 32 octets of TLS-PRF(EMSK, "TEAPbindkey@ietf.org" |
151            *                                   "\0" | 64)
152            * (if EMSK is not available, MSK is used instead; if neither is
153            * available, IMSK is 32 octets of zeros; MSK is truncated to 32 octets
154            * or padded to 32 octets, if needed)
155            * (64 is encoded as a 2-octet field in network byte order)
156            *
157            * S-IMCK[0] = session_key_seed
158            * IMCK[j] = TLS-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
159            *                   IMSK[j], 60)
160            * S-IMCK[j] = first 40 octets of IMCK[j]
161            * CMK[j] = last 20 octets of IMCK[j]
162            */
163 
164           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK[j]", msk, msk_len);
165           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK[j]", emsk, emsk_len);
166 
167           if (emsk && emsk_len > 0) {
168                     u8 context[3];
169 
170                     context[0] = 0;
171                     context[1] = 0;
172                     context[2] = 64;
173                     if (eap_teap_tls_prf(emsk, emsk_len, "TEAPbindkey@ietf.org",
174                                              context, sizeof(context), imsk, 64) < 0)
175                               return -1;
176 
177                     wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
178                                         imsk, 32);
179 
180                     res = eap_teap_tls_prf(prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
181                                                "Inner Methods Compound Keys",
182                                                imsk, 32, imck, EAP_TEAP_IMCK_LEN);
183                     forced_memzero(imsk, sizeof(imsk));
184                     if (res < 0)
185                               return -1;
186 
187                     os_memcpy(s_imck_emsk, imck, EAP_TEAP_SIMCK_LEN);
188                     wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK S-IMCK[j]",
189                                         s_imck_emsk, EAP_TEAP_SIMCK_LEN);
190                     os_memcpy(cmk_emsk, &imck[EAP_TEAP_SIMCK_LEN],
191                                 EAP_TEAP_CMK_LEN);
192                     wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK CMK[j]",
193                                         cmk_emsk, EAP_TEAP_CMK_LEN);
194                     forced_memzero(imck, EAP_TEAP_IMCK_LEN);
195           }
196 
197           if (msk && msk_len > 0) {
198                     size_t copy_len = msk_len;
199 
200                     os_memset(imsk, 0, 32); /* zero pad, if needed */
201                     if (copy_len > 32)
202                               copy_len = 32;
203                     os_memcpy(imsk, msk, copy_len);
204                     wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from MSK", imsk, 32);
205           } else {
206                     os_memset(imsk, 0, 32);
207                     wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
208           }
209 
210           res = eap_teap_tls_prf(prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
211                                      "Inner Methods Compound Keys",
212                                      imsk, 32, imck, EAP_TEAP_IMCK_LEN);
213           forced_memzero(imsk, sizeof(imsk));
214           if (res < 0)
215                     return -1;
216 
217           os_memcpy(s_imck_msk, imck, EAP_TEAP_SIMCK_LEN);
218           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK S-IMCK[j]",
219                               s_imck_msk, EAP_TEAP_SIMCK_LEN);
220           os_memcpy(cmk_msk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
221           wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK CMK[j]",
222                               cmk_msk, EAP_TEAP_CMK_LEN);
223           forced_memzero(imck, EAP_TEAP_IMCK_LEN);
224 
225           return 0;
226 }
227 
228 
tls_cipher_suite_match(const u16 * list,size_t count,u16 cs)229 static int tls_cipher_suite_match(const u16 *list, size_t count, u16 cs)
230 {
231           size_t i;
232 
233           for (i = 0; i < count; i++) {
234                     if (list[i] == cs)
235                               return 1;
236           }
237 
238           return 0;
239 }
240 
241 
tls_cipher_suite_mac_sha1(u16 cs)242 static int tls_cipher_suite_mac_sha1(u16 cs)
243 {
244           static const u16 sha1_cs[] = {
245                     0x0005, 0x0007, 0x000a, 0x000d, 0x0010, 0x0013, 0x0016, 0x001b,
246                     0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
247                     0x0037, 0x0038, 0x0039, 0x003a, 0x0041, 0x0042, 0x0043, 0x0044,
248                     0x0045, 0x0046, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089,
249                     0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091,
250                     0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099,
251                     0x009a, 0x009b,
252                     0xc002, 0xc003, 0xc004, 0xc005, 0xc007, 0xc008, 0xc009, 0xc009,
253                     0xc00a, 0xc00c, 0xc00d, 0xc00e, 0xc00f, 0xc011, 0xc012, 0xc013,
254                     0xc014, 0xc016, 0xc017, 0xc018, 0xc019, 0xc01a, 0xc01b, 0xc01c,
255                     0xc014, 0xc01e, 0xc01f, 0xc020, 0xc021, 0xc022, 0xc033, 0xc034,
256                     0xc035, 0xc036
257           };
258 
259           return tls_cipher_suite_match(sha1_cs, ARRAY_SIZE(sha1_cs), cs);
260 }
261 
262 
tls_cipher_suite_mac_sha256(u16 cs)263 static int tls_cipher_suite_mac_sha256(u16 cs)
264 {
265           static const u16 sha256_cs[] = {
266                     0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0067, 0x0068, 0x0069,
267                     0x006a, 0x006b, 0x006c, 0x006d, 0x009c, 0x009e, 0x00a0, 0x00a2,
268                     0x00a4, 0x00a6, 0x00a8, 0x00aa, 0x00ac, 0x00ae, 0x00b2, 0x00b6,
269                     0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bd, 0x00be, 0x00be,
270                     0x00bf, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5,
271                     0x1301, 0x1303, 0x1304, 0x1305,
272                     0xc023, 0xc025, 0xc027, 0xc029, 0xc02b, 0xc02d, 0xc02f, 0xc031,
273                     0xc037, 0xc03c, 0xc03e, 0xc040, 0xc040, 0xc042, 0xc044, 0xc046,
274                     0xc048, 0xc04a, 0xc04c, 0xc04e, 0xc050, 0xc052, 0xc054, 0xc056,
275                     0xc058, 0xc05a, 0xc05c, 0xc05e, 0xc060, 0xc062, 0xc064, 0xc066,
276                     0xc068, 0xc06a, 0xc06c, 0xc06e, 0xc070, 0xc072, 0xc074, 0xc076,
277                     0xc078, 0xc07a, 0xc07c, 0xc07e, 0xc080, 0xc082, 0xc084, 0xc086,
278                     0xc088, 0xc08a, 0xc08c, 0xc08e, 0xc090, 0xc092, 0xc094, 0xc096,
279                     0xc098, 0xc09a, 0xc0b0, 0xc0b2, 0xc0b4,
280                     0xcca8, 0xcca9, 0xccaa, 0xccab, 0xccac, 0xccad, 0xccae,
281                     0xd001, 0xd003, 0xd005
282           };
283 
284           return tls_cipher_suite_match(sha256_cs, ARRAY_SIZE(sha256_cs), cs);
285 }
286 
287 
tls_cipher_suite_mac_sha384(u16 cs)288 static int tls_cipher_suite_mac_sha384(u16 cs)
289 {
290           static const u16 sha384_cs[] = {
291                     0x009d, 0x009f, 0x00a1, 0x00a3, 0x00a5, 0x00a7, 0x00a9, 0x00ab,
292                     0x00ad, 0x00af, 0x00b3, 0x00b7, 0x1302,
293                     0xc024, 0xc026, 0xc028, 0xc02a, 0xc02c, 0xc02e, 0xc030, 0xc032,
294                     0xc038, 0xc03d, 0xc03f, 0xc041, 0xc043, 0xc045, 0xc047, 0xc049,
295                     0xc04b, 0xc04d, 0xc04f, 0xc051, 0xc053, 0xc055, 0xc057, 0xc059,
296                     0xc05b, 0xc05d, 0xc05f, 0xc061, 0xc063, 0xc065, 0xc067, 0xc069,
297                     0xc06b, 0xc06d, 0xc06f, 0xc071, 0xc073, 0xc075, 0xc077, 0xc079,
298                     0xc07b, 0xc07d, 0xc07f, 0xc081, 0xc083, 0xc085, 0xc087, 0xc089,
299                     0xc08b, 0xc08d, 0xc08f, 0xc091, 0xc093, 0xc095, 0xc097, 0xc099,
300                     0xc09b, 0xc0b1, 0xc0b3, 0xc0b5,
301                     0xd002
302           };
303 
304           return tls_cipher_suite_match(sha384_cs, ARRAY_SIZE(sha384_cs), cs);
305 }
306 
307 
eap_teap_tls_mac(u16 tls_cs,const u8 * cmk,size_t cmk_len,const u8 * buffer,size_t buffer_len,u8 * mac,size_t mac_len)308 static int eap_teap_tls_mac(u16 tls_cs, const u8 *cmk, size_t cmk_len,
309                                   const u8 *buffer, size_t buffer_len,
310                                   u8 *mac, size_t mac_len)
311 {
312           int res;
313           u8 tmp[48];
314 
315           os_memset(tmp, 0, sizeof(tmp));
316           os_memset(mac, 0, mac_len);
317 
318           if (tls_cipher_suite_mac_sha1(tls_cs)) {
319                     wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA1");
320                     res = hmac_sha1(cmk, cmk_len, buffer, buffer_len, tmp);
321           } else if (tls_cipher_suite_mac_sha256(tls_cs)) {
322                     wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA256");
323                     res = hmac_sha256(cmk, cmk_len, buffer, buffer_len, tmp);
324           } else if (tls_cipher_suite_mac_sha384(tls_cs)) {
325                     wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA384");
326                     res = hmac_sha384(cmk, cmk_len, buffer, buffer_len, tmp);
327           } else {
328                     wpa_printf(MSG_INFO,
329                                  "EAP-TEAP: Unsupported TLS cipher suite 0x%04x",
330                                  tls_cs);
331                     res = -1;
332           }
333           if (res < 0)
334                     return res;
335 
336           /* FIX: RFC 7170 does not describe how to handle truncation of the
337            * Compound MAC or if the fields are supposed to be of variable length
338            * based on the negotiated TLS cipher suite (they are defined as having
339            * fixed size of 20 octets in the TLV description) */
340           if (mac_len > sizeof(tmp))
341                     mac_len = sizeof(tmp);
342           os_memcpy(mac, tmp, mac_len);
343           return 0;
344 }
345 
346 
eap_teap_compound_mac(u16 tls_cs,const struct teap_tlv_crypto_binding * cb,const struct wpabuf * server_outer_tlvs,const struct wpabuf * peer_outer_tlvs,const u8 * cmk,u8 * compound_mac)347 int eap_teap_compound_mac(u16 tls_cs, const struct teap_tlv_crypto_binding *cb,
348                                 const struct wpabuf *server_outer_tlvs,
349                                 const struct wpabuf *peer_outer_tlvs,
350                                 const u8 *cmk, u8 *compound_mac)
351 {
352           u8 *pos, *buffer;
353           size_t bind_len, buffer_len;
354           struct teap_tlv_crypto_binding *tmp_cb;
355           int res;
356 
357           /* RFC 7170, Section 5.3 */
358           bind_len = sizeof(struct teap_tlv_hdr) + be_to_host16(cb->length);
359           buffer_len = bind_len + 1;
360           if (server_outer_tlvs)
361                     buffer_len += wpabuf_len(server_outer_tlvs);
362           if (peer_outer_tlvs)
363                     buffer_len += wpabuf_len(peer_outer_tlvs);
364           buffer = os_malloc(buffer_len);
365           if (!buffer)
366                     return -1;
367 
368           pos = buffer;
369           /* 1. The entire Crypto-Binding TLV attribute with both the EMSK and MSK
370            * Compound MAC fields zeroed out. */
371           os_memcpy(pos, cb, bind_len);
372           pos += bind_len;
373           tmp_cb = (struct teap_tlv_crypto_binding *) buffer;
374           os_memset(tmp_cb->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
375           os_memset(tmp_cb->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
376 
377           /* 2. The EAP Type sent by the other party in the first TEAP message. */
378           /* This is supposed to be the EAP Type sent by the other party in the
379            * first TEAP message, but since we cannot get here without having
380            * successfully negotiated use of TEAP, this can only be the fixed EAP
381            * Type of TEAP. */
382           *pos++ = EAP_TYPE_TEAP;
383 
384           /* 3. All the Outer TLVs from the first TEAP message sent by EAP server
385            * to peer. */
386           if (server_outer_tlvs) {
387                     os_memcpy(pos, wpabuf_head(server_outer_tlvs),
388                                 wpabuf_len(server_outer_tlvs));
389                     pos += wpabuf_len(server_outer_tlvs);
390           }
391 
392           /* 4. All the Outer TLVs from the first TEAP message sent by the peer to
393            * the EAP server. */
394           if (peer_outer_tlvs) {
395                     os_memcpy(pos, wpabuf_head(peer_outer_tlvs),
396                                 wpabuf_len(peer_outer_tlvs));
397                     pos += wpabuf_len(peer_outer_tlvs);
398           }
399 
400           buffer_len = pos - buffer;
401 
402           wpa_hexdump_key(MSG_MSGDUMP,
403                               "EAP-TEAP: CMK for Compound MAC calculation",
404                               cmk, EAP_TEAP_CMK_LEN);
405           wpa_hexdump(MSG_MSGDUMP,
406                         "EAP-TEAP: BUFFER for Compound MAC calculation",
407                         buffer, buffer_len);
408           res = eap_teap_tls_mac(tls_cs, cmk, EAP_TEAP_CMK_LEN,
409                                      buffer, buffer_len,
410                                      compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
411           os_free(buffer);
412 
413           return res;
414 }
415 
416 
eap_teap_parse_tlv(struct eap_teap_tlv_parse * tlv,int tlv_type,u8 * pos,size_t len)417 int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
418                            int tlv_type, u8 *pos, size_t len)
419 {
420           switch (tlv_type) {
421           case TEAP_TLV_RESULT:
422                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
423                     if (tlv->result) {
424                               wpa_printf(MSG_INFO,
425                                            "EAP-TEAP: More than one Result TLV in the message");
426                               tlv->result = TEAP_STATUS_FAILURE;
427                               return -2;
428                     }
429                     if (len < 2) {
430                               wpa_printf(MSG_INFO, "EAP-TEAP: Too short Result TLV");
431                               tlv->result = TEAP_STATUS_FAILURE;
432                               break;
433                     }
434                     tlv->result = WPA_GET_BE16(pos);
435                     if (tlv->result != TEAP_STATUS_SUCCESS &&
436                         tlv->result != TEAP_STATUS_FAILURE) {
437                               wpa_printf(MSG_INFO, "EAP-TEAP: Unknown Result %d",
438                                            tlv->result);
439                               tlv->result = TEAP_STATUS_FAILURE;
440                     }
441                     wpa_printf(MSG_DEBUG, "EAP-TEAP: Result: %s",
442                                  tlv->result == TEAP_STATUS_SUCCESS ?
443                                  "Success" : "Failure");
444                     break;
445           case TEAP_TLV_NAK:
446                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: NAK TLV", pos, len);
447                     if (len < 6) {
448                               wpa_printf(MSG_INFO, "EAP-TEAP: Too short NAK TLV");
449                               tlv->result = TEAP_STATUS_FAILURE;
450                               break;
451                     }
452                     tlv->nak = pos;
453                     tlv->nak_len = len;
454                     break;
455           case TEAP_TLV_REQUEST_ACTION:
456                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
457                                   pos, len);
458                     if (tlv->request_action) {
459                               wpa_printf(MSG_INFO,
460                                            "EAP-TEAP: More than one Request-Action TLV in the message");
461                               tlv->iresult = TEAP_STATUS_FAILURE;
462                               return -2;
463                     }
464                     if (len < 2) {
465                               wpa_printf(MSG_INFO,
466                                            "EAP-TEAP: Too short Request-Action TLV");
467                               tlv->iresult = TEAP_STATUS_FAILURE;
468                               break;
469                     }
470                     tlv->request_action_status = pos[0];
471                     tlv->request_action = pos[1];
472                     wpa_printf(MSG_DEBUG,
473                                  "EAP-TEAP: Request-Action: Status=%u Action=%u",
474                                  tlv->request_action_status, tlv->request_action);
475                     break;
476           case TEAP_TLV_EAP_PAYLOAD:
477                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EAP-Payload TLV",
478                                   pos, len);
479                     if (tlv->eap_payload_tlv) {
480                               wpa_printf(MSG_INFO,
481                                            "EAP-TEAP: More than one EAP-Payload TLV in the message");
482                               tlv->iresult = TEAP_STATUS_FAILURE;
483                               return -2;
484                     }
485                     tlv->eap_payload_tlv = pos;
486                     tlv->eap_payload_tlv_len = len;
487                     break;
488           case TEAP_TLV_INTERMEDIATE_RESULT:
489                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Intermediate-Result TLV",
490                                   pos, len);
491                     if (len < 2) {
492                               wpa_printf(MSG_INFO,
493                                            "EAP-TEAP: Too short Intermediate-Result TLV");
494                               tlv->iresult = TEAP_STATUS_FAILURE;
495                               break;
496                     }
497                     if (tlv->iresult) {
498                               wpa_printf(MSG_INFO,
499                                            "EAP-TEAP: More than one Intermediate-Result TLV in the message");
500                               tlv->iresult = TEAP_STATUS_FAILURE;
501                               return -2;
502                     }
503                     tlv->iresult = WPA_GET_BE16(pos);
504                     if (tlv->iresult != TEAP_STATUS_SUCCESS &&
505                         tlv->iresult != TEAP_STATUS_FAILURE) {
506                               wpa_printf(MSG_INFO,
507                                            "EAP-TEAP: Unknown Intermediate Result %d",
508                                            tlv->iresult);
509                               tlv->iresult = TEAP_STATUS_FAILURE;
510                     }
511                     wpa_printf(MSG_DEBUG, "EAP-TEAP: Intermediate Result: %s",
512                                  tlv->iresult == TEAP_STATUS_SUCCESS ?
513                                  "Success" : "Failure");
514                     break;
515           case TEAP_TLV_PAC:
516                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: PAC TLV", pos, len);
517                     if (tlv->pac) {
518                               wpa_printf(MSG_INFO,
519                                            "EAP-TEAP: More than one PAC TLV in the message");
520                               tlv->iresult = TEAP_STATUS_FAILURE;
521                               return -2;
522                     }
523                     tlv->pac = pos;
524                     tlv->pac_len = len;
525                     break;
526           case TEAP_TLV_CRYPTO_BINDING:
527                     wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Crypto-Binding TLV",
528                                   pos, len);
529                     if (tlv->crypto_binding) {
530                               wpa_printf(MSG_INFO,
531                                            "EAP-TEAP: More than one Crypto-Binding TLV in the message");
532                               tlv->iresult = TEAP_STATUS_FAILURE;
533                               return -2;
534                     }
535                     tlv->crypto_binding_len = sizeof(struct teap_tlv_hdr) + len;
536                     if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
537                               wpa_printf(MSG_INFO,
538                                            "EAP-TEAP: Too short Crypto-Binding TLV");
539                               tlv->iresult = TEAP_STATUS_FAILURE;
540                               return -2;
541                     }
542                     tlv->crypto_binding = (struct teap_tlv_crypto_binding *)
543                               (pos - sizeof(struct teap_tlv_hdr));
544                     break;
545           case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
546                     wpa_hexdump_ascii(MSG_MSGDUMP,
547                                           "EAP-TEAP: Basic-Password-Auth-Req TLV",
548                                           pos, len);
549                     if (tlv->basic_auth_req) {
550                               wpa_printf(MSG_INFO,
551                                            "EAP-TEAP: More than one Basic-Password-Auth-Req TLV in the message");
552                               tlv->iresult = TEAP_STATUS_FAILURE;
553                               return -2;
554                     }
555                     tlv->basic_auth_req = pos;
556                     tlv->basic_auth_req_len = len;
557                     break;
558           case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
559                     wpa_hexdump_ascii(MSG_MSGDUMP,
560                                           "EAP-TEAP: Basic-Password-Auth-Resp TLV",
561                                           pos, len);
562                     if (tlv->basic_auth_resp) {
563                               wpa_printf(MSG_INFO,
564                                            "EAP-TEAP: More than one Basic-Password-Auth-Resp TLV in the message");
565                               tlv->iresult = TEAP_STATUS_FAILURE;
566                               return -2;
567                     }
568                     tlv->basic_auth_resp = pos;
569                     tlv->basic_auth_resp_len = len;
570                     break;
571           default:
572                     /* Unknown TLV */
573                     return -1;
574           }
575 
576           return 0;
577 }
578 
579 
eap_teap_tlv_type_str(enum teap_tlv_types type)580 const char * eap_teap_tlv_type_str(enum teap_tlv_types type)
581 {
582           switch (type) {
583           case TEAP_TLV_AUTHORITY_ID:
584                     return "Authority-ID";
585           case TEAP_TLV_IDENTITY_TYPE:
586                     return "Identity-Type";
587           case TEAP_TLV_RESULT:
588                     return "Result";
589           case TEAP_TLV_NAK:
590                     return "NAK";
591           case TEAP_TLV_ERROR:
592                     return "Error";
593           case TEAP_TLV_CHANNEL_BINDING:
594                     return "Channel-Binding";
595           case TEAP_TLV_VENDOR_SPECIFIC:
596                     return "Vendor-Specific";
597           case TEAP_TLV_REQUEST_ACTION:
598                     return "Request-Action";
599           case TEAP_TLV_EAP_PAYLOAD:
600                     return "EAP-Payload";
601           case TEAP_TLV_INTERMEDIATE_RESULT:
602                     return "Intermediate-Result";
603           case TEAP_TLV_PAC:
604                     return "PAC";
605           case TEAP_TLV_CRYPTO_BINDING:
606                     return "Crypto-Binding";
607           case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
608                     return "Basic-Password-Auth-Req";
609           case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
610                     return "Basic-Password-Auth-Resp";
611           case TEAP_TLV_PKCS7:
612                     return "PKCS#7";
613           case TEAP_TLV_PKCS10:
614                     return "PKCS#10";
615           case TEAP_TLV_TRUSTED_SERVER_ROOT:
616                     return "Trusted-Server-Root";
617           }
618 
619           return "?";
620 }
621 
622 
eap_teap_tlv_result(int status,int intermediate)623 struct wpabuf * eap_teap_tlv_result(int status, int intermediate)
624 {
625           struct wpabuf *buf;
626           struct teap_tlv_result *result;
627 
628           if (status != TEAP_STATUS_FAILURE && status != TEAP_STATUS_SUCCESS)
629                     return NULL;
630 
631           buf = wpabuf_alloc(sizeof(*result));
632           if (!buf)
633                     return NULL;
634           wpa_printf(MSG_DEBUG, "EAP-TEAP: Add %sResult TLV(status=%s)",
635                        intermediate ? "Intermediate-" : "",
636                        status == TEAP_STATUS_SUCCESS ? "Success" : "Failure");
637           result = wpabuf_put(buf, sizeof(*result));
638           result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
639                                                   (intermediate ?
640                                                    TEAP_TLV_INTERMEDIATE_RESULT :
641                                                    TEAP_TLV_RESULT));
642           result->length = host_to_be16(2);
643           result->status = host_to_be16(status);
644           return buf;
645 }
646 
647 
eap_teap_tlv_error(enum teap_error_codes error)648 struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error)
649 {
650           struct wpabuf *buf;
651 
652           buf = wpabuf_alloc(4 + 4);
653           if (!buf)
654                     return NULL;
655           wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Error TLV(Error Code=%d)",
656                        error);
657           wpabuf_put_be16(buf, TEAP_TLV_MANDATORY | TEAP_TLV_ERROR);
658           wpabuf_put_be16(buf, 4);
659           wpabuf_put_be32(buf, error);
660           return buf;
661 }
662 
663 
eap_teap_allowed_anon_prov_phase2_method(u8 type)664 int eap_teap_allowed_anon_prov_phase2_method(u8 type)
665 {
666           /* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
667            * provide key generation, and be resistant to dictionary attack.
668            * Section 3.8 also mentions requirement for using EMSK Compound MAC. */
669           return type == EAP_TYPE_PWD || type == EAP_TYPE_EKE;
670 }
671 
672 
eap_teap_allowed_anon_prov_cipher_suite(u16 cs)673 int eap_teap_allowed_anon_prov_cipher_suite(u16 cs)
674 {
675           /* RFC 7170, Section 3.8.3: anonymous ciphersuites MAY be supported as
676            * long as the TLS pre-master secret is generated form contribution from
677            * both peers. Accept the recommended TLS_DH_anon_WITH_AES_128_CBC_SHA
678            * cipher suite and other ciphersuites that use DH in some form, have
679            * SHA-1 or stronger MAC function, and use reasonable strong cipher. */
680           static const u16 ok_cs[] = {
681                     /* DH-anon */
682                     0x0034, 0x003a, 0x006c, 0x006d, 0x00a6, 0x00a7,
683                     /* DHE-RSA */
684                     0x0033, 0x0039, 0x0067, 0x006b, 0x009e, 0x009f,
685                     /* ECDH-anon */
686                     0xc018, 0xc019,
687                     /* ECDH-RSA */
688                     0xc003, 0xc00f, 0xc029, 0xc02a, 0xc031, 0xc032,
689                     /* ECDH-ECDSA */
690                     0xc004, 0xc005, 0xc025, 0xc026, 0xc02d, 0xc02e,
691                     /* ECDHE-RSA */
692                     0xc013, 0xc014, 0xc027, 0xc028, 0xc02f, 0xc030,
693                     /* ECDHE-ECDSA */
694                     0xc009, 0xc00a, 0xc023, 0xc024, 0xc02b, 0xc02c,
695           };
696 
697           return tls_cipher_suite_match(ok_cs, ARRAY_SIZE(ok_cs), cs);
698 }
699