]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions | |
080585c0 | 3 | * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> |
6fc6879b | 4 | * |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
6fc6879b JM |
7 | */ |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "common.h" | |
03da66bd JM |
12 | #include "crypto/sha1.h" |
13 | #include "crypto/tls.h" | |
6fc6879b JM |
14 | #include "eap_i.h" |
15 | #include "eap_tls_common.h" | |
16 | #include "eap_config.h" | |
6fc6879b JM |
17 | |
18 | ||
065d2895 JM |
19 | static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, |
20 | u8 code, u8 identifier) | |
21 | { | |
22 | if (type == EAP_UNAUTH_TLS_TYPE) | |
23 | return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, | |
24 | EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, | |
25 | code, identifier); | |
8e5fdfab JM |
26 | if (type == EAP_WFA_UNAUTH_TLS_TYPE) |
27 | return eap_msg_alloc(EAP_VENDOR_WFA_NEW, | |
28 | EAP_VENDOR_WFA_UNAUTH_TLS, payload_len, | |
29 | code, identifier); | |
065d2895 JM |
30 | return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, |
31 | identifier); | |
32 | } | |
33 | ||
34 | ||
6fc6879b JM |
35 | static int eap_tls_check_blob(struct eap_sm *sm, const char **name, |
36 | const u8 **data, size_t *data_len) | |
37 | { | |
38 | const struct wpa_config_blob *blob; | |
39 | ||
40 | if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) | |
41 | return 0; | |
42 | ||
43 | blob = eap_get_config_blob(sm, *name + 7); | |
44 | if (blob == NULL) { | |
45 | wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " | |
46 | "found", __func__, *name + 7); | |
47 | return -1; | |
48 | } | |
49 | ||
50 | *name = NULL; | |
51 | *data = blob->data; | |
52 | *data_len = blob->len; | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
57 | ||
29446569 JM |
58 | static void eap_tls_params_flags(struct tls_connection_params *params, |
59 | const char *txt) | |
60 | { | |
61 | if (txt == NULL) | |
62 | return; | |
63 | if (os_strstr(txt, "tls_allow_md5=1")) | |
64 | params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; | |
65 | if (os_strstr(txt, "tls_disable_time_checks=1")) | |
66 | params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; | |
f210493b JM |
67 | if (os_strstr(txt, "tls_disable_session_ticket=1")) |
68 | params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; | |
69 | if (os_strstr(txt, "tls_disable_session_ticket=0")) | |
70 | params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET; | |
5650d379 JM |
71 | if (os_strstr(txt, "tls_disable_tlsv1_0=1")) |
72 | params->flags |= TLS_CONN_DISABLE_TLSv1_0; | |
73 | if (os_strstr(txt, "tls_disable_tlsv1_0=0")) | |
74 | params->flags &= ~TLS_CONN_DISABLE_TLSv1_0; | |
e9a6f183 DS |
75 | if (os_strstr(txt, "tls_disable_tlsv1_1=1")) |
76 | params->flags |= TLS_CONN_DISABLE_TLSv1_1; | |
77 | if (os_strstr(txt, "tls_disable_tlsv1_1=0")) | |
78 | params->flags &= ~TLS_CONN_DISABLE_TLSv1_1; | |
79 | if (os_strstr(txt, "tls_disable_tlsv1_2=1")) | |
80 | params->flags |= TLS_CONN_DISABLE_TLSv1_2; | |
81 | if (os_strstr(txt, "tls_disable_tlsv1_2=0")) | |
82 | params->flags &= ~TLS_CONN_DISABLE_TLSv1_2; | |
3c108b75 JM |
83 | if (os_strstr(txt, "tls_ext_cert_check=1")) |
84 | params->flags |= TLS_CONN_EXT_CERT_CHECK; | |
85 | if (os_strstr(txt, "tls_ext_cert_check=0")) | |
86 | params->flags &= ~TLS_CONN_EXT_CERT_CHECK; | |
60ed2f24 JM |
87 | if (os_strstr(txt, "tls_suiteb=1")) |
88 | params->flags |= TLS_CONN_SUITEB; | |
89 | if (os_strstr(txt, "tls_suiteb=0")) | |
90 | params->flags &= ~TLS_CONN_SUITEB; | |
2ed70c75 JM |
91 | if (os_strstr(txt, "tls_suiteb_no_ecdh=1")) |
92 | params->flags |= TLS_CONN_SUITEB_NO_ECDH; | |
93 | if (os_strstr(txt, "tls_suiteb_no_ecdh=0")) | |
94 | params->flags &= ~TLS_CONN_SUITEB_NO_ECDH; | |
29446569 JM |
95 | } |
96 | ||
97 | ||
6fc6879b JM |
98 | static void eap_tls_params_from_conf1(struct tls_connection_params *params, |
99 | struct eap_peer_config *config) | |
100 | { | |
101 | params->ca_cert = (char *) config->ca_cert; | |
102 | params->ca_path = (char *) config->ca_path; | |
103 | params->client_cert = (char *) config->client_cert; | |
104 | params->private_key = (char *) config->private_key; | |
105 | params->private_key_passwd = (char *) config->private_key_passwd; | |
106 | params->dh_file = (char *) config->dh_file; | |
107 | params->subject_match = (char *) config->subject_match; | |
108 | params->altsubject_match = (char *) config->altsubject_match; | |
01f809c7 | 109 | params->suffix_match = config->domain_suffix_match; |
cebee30f | 110 | params->domain_match = config->domain_match; |
98842d51 | 111 | params->engine = config->engine; |
6fc6879b JM |
112 | params->engine_id = config->engine_id; |
113 | params->pin = config->pin; | |
114 | params->key_id = config->key_id; | |
d1f73353 DS |
115 | params->cert_id = config->cert_id; |
116 | params->ca_cert_id = config->ca_cert_id; | |
29446569 | 117 | eap_tls_params_flags(params, config->phase1); |
6fc6879b JM |
118 | } |
119 | ||
120 | ||
121 | static void eap_tls_params_from_conf2(struct tls_connection_params *params, | |
122 | struct eap_peer_config *config) | |
123 | { | |
124 | params->ca_cert = (char *) config->ca_cert2; | |
125 | params->ca_path = (char *) config->ca_path2; | |
126 | params->client_cert = (char *) config->client_cert2; | |
127 | params->private_key = (char *) config->private_key2; | |
128 | params->private_key_passwd = (char *) config->private_key2_passwd; | |
129 | params->dh_file = (char *) config->dh_file2; | |
130 | params->subject_match = (char *) config->subject_match2; | |
131 | params->altsubject_match = (char *) config->altsubject_match2; | |
01f809c7 | 132 | params->suffix_match = config->domain_suffix_match2; |
cebee30f | 133 | params->domain_match = config->domain_match2; |
98842d51 CL |
134 | params->engine = config->engine2; |
135 | params->engine_id = config->engine2_id; | |
136 | params->pin = config->pin2; | |
d1f73353 DS |
137 | params->key_id = config->key2_id; |
138 | params->cert_id = config->cert2_id; | |
139 | params->ca_cert_id = config->ca_cert2_id; | |
29446569 | 140 | eap_tls_params_flags(params, config->phase2); |
6fc6879b JM |
141 | } |
142 | ||
143 | ||
144 | static int eap_tls_params_from_conf(struct eap_sm *sm, | |
145 | struct eap_ssl_data *data, | |
146 | struct tls_connection_params *params, | |
147 | struct eap_peer_config *config, int phase2) | |
148 | { | |
149 | os_memset(params, 0, sizeof(*params)); | |
c22075e1 JM |
150 | if (sm->workaround && data->eap_type != EAP_TYPE_FAST) { |
151 | /* | |
152 | * Some deployed authentication servers seem to be unable to | |
153 | * handle the TLS Session Ticket extension (they are supposed | |
154 | * to ignore unrecognized TLS extensions, but end up rejecting | |
155 | * the ClientHello instead). As a workaround, disable use of | |
156 | * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and | |
157 | * EAP-TTLS (EAP-FAST uses session ticket, so any server that | |
158 | * supports EAP-FAST does not need this workaround). | |
159 | */ | |
160 | params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; | |
161 | } | |
98842d51 CL |
162 | if (phase2) { |
163 | wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); | |
6fc6879b | 164 | eap_tls_params_from_conf2(params, config); |
98842d51 CL |
165 | } else { |
166 | wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); | |
6fc6879b | 167 | eap_tls_params_from_conf1(params, config); |
d4913c58 JM |
168 | if (data->eap_type == EAP_TYPE_FAST) |
169 | params->flags |= TLS_CONN_EAP_FAST; | |
98842d51 | 170 | } |
6fc6879b JM |
171 | |
172 | /* | |
173 | * Use blob data, if available. Otherwise, leave reference to external | |
174 | * file as-is. | |
175 | */ | |
176 | if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, | |
177 | ¶ms->ca_cert_blob_len) || | |
178 | eap_tls_check_blob(sm, ¶ms->client_cert, | |
179 | ¶ms->client_cert_blob, | |
180 | ¶ms->client_cert_blob_len) || | |
181 | eap_tls_check_blob(sm, ¶ms->private_key, | |
182 | ¶ms->private_key_blob, | |
183 | ¶ms->private_key_blob_len) || | |
184 | eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, | |
185 | ¶ms->dh_blob_len)) { | |
186 | wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); | |
187 | return -1; | |
188 | } | |
189 | ||
07e2de31 JM |
190 | params->openssl_ciphers = config->openssl_ciphers; |
191 | ||
3c108b75 JM |
192 | sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK); |
193 | ||
6fc6879b JM |
194 | return 0; |
195 | } | |
196 | ||
197 | ||
198 | static int eap_tls_init_connection(struct eap_sm *sm, | |
199 | struct eap_ssl_data *data, | |
200 | struct eap_peer_config *config, | |
201 | struct tls_connection_params *params) | |
202 | { | |
203 | int res; | |
204 | ||
080585c0 JM |
205 | if (config->ocsp) |
206 | params->flags |= TLS_CONN_REQUEST_OCSP; | |
d6b536f7 | 207 | if (config->ocsp >= 2) |
080585c0 | 208 | params->flags |= TLS_CONN_REQUIRE_OCSP; |
d6b536f7 JM |
209 | if (config->ocsp == 3) |
210 | params->flags |= TLS_CONN_REQUIRE_OCSP_ALL; | |
9f98810c | 211 | data->conn = tls_connection_init(data->ssl_ctx); |
6fc6879b JM |
212 | if (data->conn == NULL) { |
213 | wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " | |
214 | "connection"); | |
215 | return -1; | |
216 | } | |
217 | ||
9f98810c | 218 | res = tls_connection_set_params(data->ssl_ctx, data->conn, params); |
fd4fb281 | 219 | if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) { |
6fc6879b | 220 | /* |
fd4fb281 MG |
221 | * At this point with the pkcs11 engine the PIN is wrong. We |
222 | * reset the PIN in the configuration to be sure to not use it | |
223 | * again and the calling function must request a new one. | |
6fc6879b | 224 | */ |
fd4fb281 MG |
225 | wpa_printf(MSG_INFO, |
226 | "TLS: Bad PIN provided, requesting a new one"); | |
6fc6879b JM |
227 | os_free(config->pin); |
228 | config->pin = NULL; | |
fd4fb281 MG |
229 | eap_sm_request_pin(sm); |
230 | sm->ignore = TRUE; | |
231 | } else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { | |
232 | wpa_printf(MSG_INFO, "TLS: Failed to initialize engine"); | |
6fc6879b JM |
233 | } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { |
234 | wpa_printf(MSG_INFO, "TLS: Failed to load private key"); | |
6fc6879b | 235 | sm->ignore = TRUE; |
fd4fb281 MG |
236 | } |
237 | if (res) { | |
6fc6879b JM |
238 | wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " |
239 | "parameters"); | |
9f98810c | 240 | tls_connection_deinit(data->ssl_ctx, data->conn); |
c7d71160 | 241 | data->conn = NULL; |
6fc6879b JM |
242 | return -1; |
243 | } | |
244 | ||
245 | return 0; | |
246 | } | |
247 | ||
248 | ||
249 | /** | |
250 | * eap_peer_tls_ssl_init - Initialize shared TLS functionality | |
251 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
252 | * @data: Data for TLS processing | |
253 | * @config: Pointer to the network configuration | |
c22075e1 | 254 | * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) |
6fc6879b JM |
255 | * Returns: 0 on success, -1 on failure |
256 | * | |
257 | * This function is used to initialize shared TLS functionality for EAP-TLS, | |
258 | * EAP-PEAP, EAP-TTLS, and EAP-FAST. | |
259 | */ | |
260 | int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, | |
c22075e1 | 261 | struct eap_peer_config *config, u8 eap_type) |
6fc6879b JM |
262 | { |
263 | struct tls_connection_params params; | |
264 | ||
265 | if (config == NULL) | |
266 | return -1; | |
267 | ||
268 | data->eap = sm; | |
c22075e1 | 269 | data->eap_type = eap_type; |
6fc6879b | 270 | data->phase2 = sm->init_phase2; |
9f98810c JM |
271 | data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : |
272 | sm->ssl_ctx; | |
6fc6879b JM |
273 | if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < |
274 | 0) | |
275 | return -1; | |
276 | ||
277 | if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) | |
278 | return -1; | |
279 | ||
280 | data->tls_out_limit = config->fragment_size; | |
281 | if (data->phase2) { | |
282 | /* Limit the fragment size in the inner TLS authentication | |
283 | * since the outer authentication with EAP-PEAP does not yet | |
284 | * support fragmentation */ | |
285 | if (data->tls_out_limit > 100) | |
286 | data->tls_out_limit -= 100; | |
287 | } | |
288 | ||
289 | if (config->phase1 && | |
290 | os_strstr(config->phase1, "include_tls_length=1")) { | |
291 | wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " | |
292 | "unfragmented packets"); | |
293 | data->include_tls_length = 1; | |
294 | } | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
299 | ||
300 | /** | |
301 | * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality | |
302 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
303 | * @data: Data for TLS processing | |
304 | * | |
305 | * This function deinitializes shared TLS functionality that was initialized | |
306 | * with eap_peer_tls_ssl_init(). | |
307 | */ | |
308 | void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) | |
309 | { | |
9f98810c | 310 | tls_connection_deinit(data->ssl_ctx, data->conn); |
6fc6879b JM |
311 | eap_peer_tls_reset_input(data); |
312 | eap_peer_tls_reset_output(data); | |
313 | } | |
314 | ||
315 | ||
316 | /** | |
317 | * eap_peer_tls_derive_key - Derive a key based on TLS session data | |
318 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
319 | * @data: Data for TLS processing | |
320 | * @label: Label string for deriving the keys, e.g., "client EAP encryption" | |
321 | * @len: Length of the key material to generate (usually 64 for MSK) | |
322 | * Returns: Pointer to allocated key on success or %NULL on failure | |
323 | * | |
324 | * This function uses TLS-PRF to generate pseudo-random data based on the TLS | |
325 | * session data (client/server random and master key). Each key type may use a | |
326 | * different label to bind the key usage into the generated material. | |
327 | * | |
328 | * The caller is responsible for freeing the returned buffer. | |
329 | */ | |
330 | u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, | |
331 | const char *label, size_t len) | |
332 | { | |
fa0e7151 | 333 | u8 *out; |
6fc6879b JM |
334 | |
335 | out = os_malloc(len); | |
336 | if (out == NULL) | |
337 | return NULL; | |
338 | ||
73581707 DB |
339 | if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out, |
340 | len)) { | |
fa0e7151 JM |
341 | os_free(out); |
342 | return NULL; | |
343 | } | |
6fc6879b | 344 | |
6fc6879b | 345 | return out; |
6fc6879b JM |
346 | } |
347 | ||
348 | ||
950c5630 SL |
349 | /** |
350 | * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data | |
351 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
352 | * @data: Data for TLS processing | |
353 | * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) | |
354 | * @len: Pointer to length of the session ID generated | |
355 | * Returns: Pointer to allocated Session-Id on success or %NULL on failure | |
356 | * | |
357 | * This function derive the Session-Id based on the TLS session data | |
358 | * (client/server random and method type). | |
359 | * | |
360 | * The caller is responsible for freeing the returned buffer. | |
361 | */ | |
362 | u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, | |
363 | struct eap_ssl_data *data, u8 eap_type, | |
364 | size_t *len) | |
365 | { | |
1046db8b | 366 | struct tls_random keys; |
950c5630 SL |
367 | u8 *out; |
368 | ||
18704f6c JM |
369 | if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) || |
370 | keys.client_random == NULL || keys.server_random == NULL) | |
950c5630 SL |
371 | return NULL; |
372 | ||
373 | *len = 1 + keys.client_random_len + keys.server_random_len; | |
374 | out = os_malloc(*len); | |
375 | if (out == NULL) | |
376 | return NULL; | |
377 | ||
378 | /* Session-Id = EAP type || client.random || server.random */ | |
379 | out[0] = eap_type; | |
380 | os_memcpy(out + 1, keys.client_random, keys.client_random_len); | |
381 | os_memcpy(out + 1 + keys.client_random_len, keys.server_random, | |
d68f74c5 | 382 | keys.server_random_len); |
950c5630 SL |
383 | |
384 | return out; | |
385 | } | |
386 | ||
387 | ||
6fc6879b JM |
388 | /** |
389 | * eap_peer_tls_reassemble_fragment - Reassemble a received fragment | |
390 | * @data: Data for TLS processing | |
391 | * @in_data: Next incoming TLS segment | |
6fc6879b JM |
392 | * Returns: 0 on success, 1 if more data is needed for the full message, or |
393 | * -1 on error | |
394 | */ | |
395 | static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, | |
81c85c06 | 396 | const struct wpabuf *in_data) |
6fc6879b | 397 | { |
81c85c06 JM |
398 | size_t tls_in_len, in_len; |
399 | ||
400 | tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; | |
401 | in_len = in_data ? wpabuf_len(in_data) : 0; | |
6fc6879b | 402 | |
81c85c06 | 403 | if (tls_in_len + in_len == 0) { |
6fc6879b JM |
404 | /* No message data received?! */ |
405 | wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " | |
406 | "tls_in_left=%lu tls_in_len=%lu in_len=%lu", | |
407 | (unsigned long) data->tls_in_left, | |
81c85c06 | 408 | (unsigned long) tls_in_len, |
6fc6879b JM |
409 | (unsigned long) in_len); |
410 | eap_peer_tls_reset_input(data); | |
411 | return -1; | |
412 | } | |
413 | ||
81c85c06 | 414 | if (tls_in_len + in_len > 65536) { |
6fc6879b JM |
415 | /* |
416 | * Limit length to avoid rogue servers from causing large | |
417 | * memory allocations. | |
418 | */ | |
419 | wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " | |
420 | "64 kB)"); | |
421 | eap_peer_tls_reset_input(data); | |
422 | return -1; | |
423 | } | |
424 | ||
425 | if (in_len > data->tls_in_left) { | |
426 | /* Sender is doing something odd - reject message */ | |
427 | wpa_printf(MSG_INFO, "SSL: more data than TLS message length " | |
428 | "indicated"); | |
429 | eap_peer_tls_reset_input(data); | |
430 | return -1; | |
431 | } | |
432 | ||
81c85c06 | 433 | if (wpabuf_resize(&data->tls_in, in_len) < 0) { |
6fc6879b JM |
434 | wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " |
435 | "data"); | |
436 | eap_peer_tls_reset_input(data); | |
437 | return -1; | |
438 | } | |
066608f3 JM |
439 | if (in_data) |
440 | wpabuf_put_buf(data->tls_in, in_data); | |
6fc6879b JM |
441 | data->tls_in_left -= in_len; |
442 | ||
443 | if (data->tls_in_left > 0) { | |
444 | wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " | |
445 | "data", (unsigned long) data->tls_in_left); | |
446 | return 1; | |
447 | } | |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
452 | ||
453 | /** | |
454 | * eap_peer_tls_data_reassemble - Reassemble TLS data | |
455 | * @data: Data for TLS processing | |
456 | * @in_data: Next incoming TLS segment | |
6fc6879b JM |
457 | * @need_more_input: Variable for returning whether more input data is needed |
458 | * to reassemble this TLS packet | |
459 | * Returns: Pointer to output data, %NULL on error or when more data is needed | |
460 | * for the full message (in which case, *need_more_input is also set to 1). | |
461 | * | |
462 | * This function reassembles TLS fragments. Caller must not free the returned | |
463 | * data buffer since an internal pointer to it is maintained. | |
464 | */ | |
81c85c06 JM |
465 | static const struct wpabuf * eap_peer_tls_data_reassemble( |
466 | struct eap_ssl_data *data, const struct wpabuf *in_data, | |
467 | int *need_more_input) | |
6fc6879b JM |
468 | { |
469 | *need_more_input = 0; | |
470 | ||
81c85c06 | 471 | if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { |
6fc6879b | 472 | /* Message has fragments */ |
81c85c06 | 473 | int res = eap_peer_tls_reassemble_fragment(data, in_data); |
6fc6879b JM |
474 | if (res) { |
475 | if (res == 1) | |
476 | *need_more_input = 1; | |
477 | return NULL; | |
478 | } | |
479 | ||
480 | /* Message is now fully reassembled. */ | |
481 | } else { | |
482 | /* No fragments in this message, so just make a copy of it. */ | |
483 | data->tls_in_left = 0; | |
81c85c06 | 484 | data->tls_in = wpabuf_dup(in_data); |
6fc6879b JM |
485 | if (data->tls_in == NULL) |
486 | return NULL; | |
6fc6879b JM |
487 | } |
488 | ||
6fc6879b JM |
489 | return data->tls_in; |
490 | } | |
491 | ||
492 | ||
493 | /** | |
494 | * eap_tls_process_input - Process incoming TLS message | |
495 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
496 | * @data: Data for TLS processing | |
497 | * @in_data: Message received from the server | |
6fc6879b JM |
498 | * @out_data: Buffer for returning a pointer to application data (if available) |
499 | * Returns: 0 on success, 1 if more input data is needed, 2 if application data | |
500 | * is available, -1 on failure | |
501 | */ | |
502 | static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, | |
d36c803c | 503 | const struct wpabuf *in_data, |
6fc6879b JM |
504 | struct wpabuf **out_data) |
505 | { | |
81c85c06 | 506 | const struct wpabuf *msg; |
6fc6879b | 507 | int need_more_input; |
81c85c06 | 508 | struct wpabuf *appl_data; |
6fc6879b | 509 | |
d36c803c | 510 | msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); |
6fc6879b JM |
511 | if (msg == NULL) |
512 | return need_more_input ? 1 : -1; | |
513 | ||
514 | /* Full TLS message reassembled - continue handshake processing */ | |
515 | if (data->tls_out) { | |
516 | /* This should not happen.. */ | |
517 | wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " | |
518 | "tls_out data even though tls_out_len = 0"); | |
81c85c06 | 519 | wpabuf_free(data->tls_out); |
6fc6879b JM |
520 | WPA_ASSERT(data->tls_out == NULL); |
521 | } | |
522 | appl_data = NULL; | |
9f98810c | 523 | data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn, |
81c85c06 | 524 | msg, &appl_data); |
6fc6879b JM |
525 | |
526 | eap_peer_tls_reset_input(data); | |
527 | ||
528 | if (appl_data && | |
9f98810c JM |
529 | tls_connection_established(data->ssl_ctx, data->conn) && |
530 | !tls_connection_get_failed(data->ssl_ctx, data->conn)) { | |
81c85c06 JM |
531 | wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", |
532 | appl_data); | |
533 | *out_data = appl_data; | |
6fc6879b JM |
534 | return 2; |
535 | } | |
536 | ||
81c85c06 | 537 | wpabuf_free(appl_data); |
6fc6879b JM |
538 | |
539 | return 0; | |
540 | } | |
541 | ||
542 | ||
543 | /** | |
544 | * eap_tls_process_output - Process outgoing TLS message | |
545 | * @data: Data for TLS processing | |
546 | * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) | |
547 | * @peap_version: Version number for EAP-PEAP/TTLS | |
548 | * @id: EAP identifier for the response | |
549 | * @ret: Return value to use on success | |
550 | * @out_data: Buffer for returning the allocated output buffer | |
551 | * Returns: ret (0 or 1) on success, -1 on failure | |
552 | */ | |
553 | static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, | |
554 | int peap_version, u8 id, int ret, | |
555 | struct wpabuf **out_data) | |
556 | { | |
557 | size_t len; | |
558 | u8 *flags; | |
559 | int more_fragments, length_included; | |
81c85c06 JM |
560 | |
561 | if (data->tls_out == NULL) | |
562 | return -1; | |
563 | len = wpabuf_len(data->tls_out) - data->tls_out_pos; | |
6fc6879b JM |
564 | wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " |
565 | "%lu bytes)", | |
81c85c06 JM |
566 | (unsigned long) len, |
567 | (unsigned long) wpabuf_len(data->tls_out)); | |
6fc6879b JM |
568 | |
569 | /* | |
570 | * Limit outgoing message to the configured maximum size. Fragment | |
571 | * message if needed. | |
572 | */ | |
573 | if (len > data->tls_out_limit) { | |
574 | more_fragments = 1; | |
575 | len = data->tls_out_limit; | |
576 | wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " | |
577 | "will follow", (unsigned long) len); | |
578 | } else | |
579 | more_fragments = 0; | |
580 | ||
581 | length_included = data->tls_out_pos == 0 && | |
81c85c06 | 582 | (wpabuf_len(data->tls_out) > data->tls_out_limit || |
6fc6879b | 583 | data->include_tls_length); |
f4f2774a JM |
584 | if (!length_included && |
585 | eap_type == EAP_TYPE_PEAP && peap_version == 0 && | |
586 | !tls_connection_established(data->eap->ssl_ctx, data->conn)) { | |
587 | /* | |
588 | * Windows Server 2008 NPS really wants to have the TLS Message | |
589 | * length included in phase 0 even for unfragmented frames or | |
590 | * it will get very confused with Compound MAC calculation and | |
591 | * Outer TLVs. | |
592 | */ | |
593 | length_included = 1; | |
594 | } | |
6fc6879b | 595 | |
065d2895 JM |
596 | *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len, |
597 | EAP_CODE_RESPONSE, id); | |
6fc6879b JM |
598 | if (*out_data == NULL) |
599 | return -1; | |
600 | ||
601 | flags = wpabuf_put(*out_data, 1); | |
602 | *flags = peap_version; | |
603 | if (more_fragments) | |
604 | *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; | |
605 | if (length_included) { | |
606 | *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; | |
81c85c06 | 607 | wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); |
6fc6879b JM |
608 | } |
609 | ||
81c85c06 JM |
610 | wpabuf_put_data(*out_data, |
611 | wpabuf_head_u8(data->tls_out) + data->tls_out_pos, | |
612 | len); | |
6fc6879b JM |
613 | data->tls_out_pos += len; |
614 | ||
615 | if (!more_fragments) | |
616 | eap_peer_tls_reset_output(data); | |
617 | ||
618 | return ret; | |
619 | } | |
620 | ||
621 | ||
622 | /** | |
623 | * eap_peer_tls_process_helper - Process TLS handshake message | |
624 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
625 | * @data: Data for TLS processing | |
626 | * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) | |
627 | * @peap_version: Version number for EAP-PEAP/TTLS | |
628 | * @id: EAP identifier for the response | |
629 | * @in_data: Message received from the server | |
6fc6879b JM |
630 | * @out_data: Buffer for returning a pointer to the response message |
631 | * Returns: 0 on success, 1 if more input data is needed, 2 if application data | |
632 | * is available, or -1 on failure | |
633 | * | |
634 | * This function can be used to process TLS handshake messages. It reassembles | |
635 | * the received fragments and uses a TLS library to process the messages. The | |
636 | * response data from the TLS library is fragmented to suitable output messages | |
637 | * that the caller can send out. | |
638 | * | |
639 | * out_data is used to return the response message if the return value of this | |
640 | * function is 0, 2, or -1. In case of failure, the message is likely a TLS | |
641 | * alarm message. The caller is responsible for freeing the allocated buffer if | |
642 | * *out_data is not %NULL. | |
643 | * | |
644 | * This function is called for each received TLS message during the TLS | |
645 | * handshake after eap_peer_tls_process_init() call and possible processing of | |
646 | * TLS Flags field. Once the handshake has been completed, i.e., when | |
647 | * tls_connection_established() returns 1, EAP method specific decrypting of | |
648 | * the tunneled data is used. | |
649 | */ | |
650 | int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, | |
651 | EapType eap_type, int peap_version, | |
d36c803c | 652 | u8 id, const struct wpabuf *in_data, |
6fc6879b JM |
653 | struct wpabuf **out_data) |
654 | { | |
655 | int ret = 0; | |
656 | ||
657 | *out_data = NULL; | |
658 | ||
d36c803c JM |
659 | if (data->tls_out && wpabuf_len(data->tls_out) > 0 && |
660 | wpabuf_len(in_data) > 0) { | |
6fc6879b JM |
661 | wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " |
662 | "fragments are waiting to be sent out"); | |
663 | return -1; | |
664 | } | |
665 | ||
81c85c06 | 666 | if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { |
6fc6879b JM |
667 | /* |
668 | * No more data to send out - expect to receive more data from | |
669 | * the AS. | |
670 | */ | |
d36c803c | 671 | int res = eap_tls_process_input(sm, data, in_data, out_data); |
6fc6879b JM |
672 | if (res) { |
673 | /* | |
674 | * Input processing failed (res = -1) or more data is | |
675 | * needed (res = 1). | |
676 | */ | |
677 | return res; | |
678 | } | |
679 | ||
680 | /* | |
681 | * The incoming message has been reassembled and processed. The | |
682 | * response was allocated into data->tls_out buffer. | |
683 | */ | |
684 | } | |
685 | ||
686 | if (data->tls_out == NULL) { | |
687 | /* | |
688 | * No outgoing fragments remaining from the previous message | |
689 | * and no new message generated. This indicates an error in TLS | |
690 | * processing. | |
691 | */ | |
692 | eap_peer_tls_reset_output(data); | |
693 | return -1; | |
694 | } | |
695 | ||
9f98810c | 696 | if (tls_connection_get_failed(data->ssl_ctx, data->conn)) { |
6fc6879b JM |
697 | /* TLS processing has failed - return error */ |
698 | wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " | |
3947997d JM |
699 | "report error (len=%u)", |
700 | (unsigned int) wpabuf_len(data->tls_out)); | |
6fc6879b JM |
701 | ret = -1; |
702 | /* TODO: clean pin if engine used? */ | |
3947997d JM |
703 | if (wpabuf_len(data->tls_out) == 0) { |
704 | wpabuf_free(data->tls_out); | |
705 | data->tls_out = NULL; | |
706 | return -1; | |
707 | } | |
6fc6879b JM |
708 | } |
709 | ||
3947997d | 710 | if (wpabuf_len(data->tls_out) == 0) { |
6fc6879b JM |
711 | /* |
712 | * TLS negotiation should now be complete since all other cases | |
713 | * needing more data should have been caught above based on | |
714 | * the TLS Message Length field. | |
715 | */ | |
716 | wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); | |
81c85c06 | 717 | wpabuf_free(data->tls_out); |
6fc6879b JM |
718 | data->tls_out = NULL; |
719 | return 1; | |
720 | } | |
721 | ||
722 | /* Send the pending message (in fragments, if needed). */ | |
723 | return eap_tls_process_output(data, eap_type, peap_version, id, ret, | |
724 | out_data); | |
725 | } | |
726 | ||
727 | ||
728 | /** | |
729 | * eap_peer_tls_build_ack - Build a TLS ACK frame | |
730 | * @id: EAP identifier for the response | |
731 | * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) | |
732 | * @peap_version: Version number for EAP-PEAP/TTLS | |
733 | * Returns: Pointer to the allocated ACK frame or %NULL on failure | |
734 | */ | |
735 | struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, | |
736 | int peap_version) | |
737 | { | |
738 | struct wpabuf *resp; | |
739 | ||
065d2895 | 740 | resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id); |
6fc6879b JM |
741 | if (resp == NULL) |
742 | return NULL; | |
743 | wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", | |
744 | (int) eap_type, id, peap_version); | |
745 | wpabuf_put_u8(resp, peap_version); /* Flags */ | |
746 | return resp; | |
747 | } | |
748 | ||
749 | ||
750 | /** | |
751 | * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption | |
752 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
753 | * @data: Data for TLS processing | |
754 | * Returns: 0 on success, -1 on failure | |
755 | */ | |
756 | int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) | |
757 | { | |
758 | eap_peer_tls_reset_input(data); | |
759 | eap_peer_tls_reset_output(data); | |
9f98810c | 760 | return tls_connection_shutdown(data->ssl_ctx, data->conn); |
6fc6879b JM |
761 | } |
762 | ||
763 | ||
764 | /** | |
765 | * eap_peer_tls_status - Get TLS status | |
766 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
767 | * @data: Data for TLS processing | |
768 | * @buf: Buffer for status information | |
769 | * @buflen: Maximum buffer length | |
770 | * @verbose: Whether to include verbose status information | |
771 | * Returns: Number of bytes written to buf. | |
772 | */ | |
773 | int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, | |
774 | char *buf, size_t buflen, int verbose) | |
775 | { | |
fe1bf329 | 776 | char version[20], name[128]; |
6fc6879b JM |
777 | int len = 0, ret; |
778 | ||
fe1bf329 JM |
779 | if (tls_get_version(data->ssl_ctx, data->conn, version, |
780 | sizeof(version)) < 0) | |
781 | version[0] = '\0'; | |
782 | if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) < 0) | |
783 | name[0] = '\0'; | |
784 | ||
785 | ret = os_snprintf(buf + len, buflen - len, | |
786 | "eap_tls_version=%s\n" | |
787 | "EAP TLS cipher=%s\n" | |
788 | "tls_session_reused=%d\n", | |
789 | version, name, | |
790 | tls_connection_resumed(data->ssl_ctx, data->conn)); | |
791 | if (os_snprintf_error(buflen - len, ret)) | |
792 | return len; | |
793 | len += ret; | |
6fc6879b JM |
794 | |
795 | return len; | |
796 | } | |
797 | ||
798 | ||
799 | /** | |
800 | * eap_peer_tls_process_init - Initial validation/processing of EAP requests | |
801 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
802 | * @data: Data for TLS processing | |
803 | * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) | |
804 | * @ret: Return values from EAP request validation and processing | |
805 | * @reqData: EAP request to be processed (eapReqData) | |
806 | * @len: Buffer for returning length of the remaining payload | |
807 | * @flags: Buffer for returning TLS flags | |
808 | * Returns: Pointer to payload after TLS flags and length or %NULL on failure | |
809 | * | |
810 | * This function validates the EAP header and processes the optional TLS | |
811 | * Message Length field. If this is the first fragment of a TLS message, the | |
812 | * TLS reassembly code is initialized to receive the indicated number of bytes. | |
813 | * | |
814 | * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this | |
815 | * function as the first step in processing received messages. They will need | |
816 | * to process the flags (apart from Message Length Included) that are returned | |
817 | * through the flags pointer and the message payload that will be returned (and | |
818 | * the length is returned through the len pointer). Return values (ret) are set | |
819 | * for continuation of EAP method processing. The caller is responsible for | |
820 | * setting these to indicate completion (either success or failure) based on | |
821 | * the authentication result. | |
822 | */ | |
823 | const u8 * eap_peer_tls_process_init(struct eap_sm *sm, | |
824 | struct eap_ssl_data *data, | |
825 | EapType eap_type, | |
826 | struct eap_method_ret *ret, | |
827 | const struct wpabuf *reqData, | |
828 | size_t *len, u8 *flags) | |
829 | { | |
830 | const u8 *pos; | |
831 | size_t left; | |
832 | unsigned int tls_msg_len; | |
833 | ||
9f98810c | 834 | if (tls_get_errors(data->ssl_ctx)) { |
6fc6879b JM |
835 | wpa_printf(MSG_INFO, "SSL: TLS errors detected"); |
836 | ret->ignore = TRUE; | |
837 | return NULL; | |
838 | } | |
839 | ||
065d2895 JM |
840 | if (eap_type == EAP_UNAUTH_TLS_TYPE) |
841 | pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, | |
842 | EAP_VENDOR_TYPE_UNAUTH_TLS, reqData, | |
843 | &left); | |
8e5fdfab JM |
844 | else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE) |
845 | pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, | |
846 | EAP_VENDOR_WFA_UNAUTH_TLS, reqData, | |
847 | &left); | |
065d2895 JM |
848 | else |
849 | pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, | |
850 | &left); | |
6fc6879b JM |
851 | if (pos == NULL) { |
852 | ret->ignore = TRUE; | |
853 | return NULL; | |
854 | } | |
3f732d1f JM |
855 | if (left == 0) { |
856 | wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " | |
857 | "octet included"); | |
858 | if (!sm->workaround) { | |
859 | ret->ignore = TRUE; | |
860 | return NULL; | |
861 | } | |
862 | ||
863 | wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " | |
864 | "indicates ACK frame"); | |
865 | *flags = 0; | |
866 | } else { | |
867 | *flags = *pos++; | |
868 | left--; | |
869 | } | |
6fc6879b JM |
870 | wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " |
871 | "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), | |
872 | *flags); | |
873 | if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { | |
874 | if (left < 4) { | |
875 | wpa_printf(MSG_INFO, "SSL: Short frame with TLS " | |
876 | "length"); | |
877 | ret->ignore = TRUE; | |
878 | return NULL; | |
879 | } | |
880 | tls_msg_len = WPA_GET_BE32(pos); | |
881 | wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", | |
882 | tls_msg_len); | |
883 | if (data->tls_in_left == 0) { | |
884 | data->tls_in_total = tls_msg_len; | |
885 | data->tls_in_left = tls_msg_len; | |
81c85c06 | 886 | wpabuf_free(data->tls_in); |
6fc6879b | 887 | data->tls_in = NULL; |
6fc6879b JM |
888 | } |
889 | pos += 4; | |
890 | left -= 4; | |
458cb301 JM |
891 | |
892 | if (left > tls_msg_len) { | |
893 | wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " | |
894 | "bytes) smaller than this fragment (%d " | |
895 | "bytes)", (int) tls_msg_len, (int) left); | |
896 | ret->ignore = TRUE; | |
897 | return NULL; | |
898 | } | |
6fc6879b JM |
899 | } |
900 | ||
901 | ret->ignore = FALSE; | |
902 | ret->methodState = METHOD_MAY_CONT; | |
903 | ret->decision = DECISION_FAIL; | |
904 | ret->allowNotifications = TRUE; | |
905 | ||
906 | *len = left; | |
907 | return pos; | |
908 | } | |
909 | ||
910 | ||
911 | /** | |
912 | * eap_peer_tls_reset_input - Reset input buffers | |
913 | * @data: Data for TLS processing | |
914 | * | |
915 | * This function frees any allocated memory for input buffers and resets input | |
916 | * state. | |
917 | */ | |
918 | void eap_peer_tls_reset_input(struct eap_ssl_data *data) | |
919 | { | |
81c85c06 JM |
920 | data->tls_in_left = data->tls_in_total = 0; |
921 | wpabuf_free(data->tls_in); | |
6fc6879b JM |
922 | data->tls_in = NULL; |
923 | } | |
924 | ||
925 | ||
926 | /** | |
927 | * eap_peer_tls_reset_output - Reset output buffers | |
928 | * @data: Data for TLS processing | |
929 | * | |
930 | * This function frees any allocated memory for output buffers and resets | |
931 | * output state. | |
932 | */ | |
933 | void eap_peer_tls_reset_output(struct eap_ssl_data *data) | |
934 | { | |
6fc6879b | 935 | data->tls_out_pos = 0; |
81c85c06 | 936 | wpabuf_free(data->tls_out); |
6fc6879b JM |
937 | data->tls_out = NULL; |
938 | } | |
939 | ||
940 | ||
941 | /** | |
942 | * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message | |
943 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
944 | * @data: Data for TLS processing | |
945 | * @in_data: Message received from the server | |
946 | * @in_decrypted: Buffer for returning a pointer to the decrypted message | |
947 | * Returns: 0 on success, 1 if more input data is needed, or -1 on failure | |
948 | */ | |
949 | int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, | |
950 | const struct wpabuf *in_data, | |
951 | struct wpabuf **in_decrypted) | |
952 | { | |
81c85c06 | 953 | const struct wpabuf *msg; |
6fc6879b JM |
954 | int need_more_input; |
955 | ||
81c85c06 | 956 | msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); |
6fc6879b JM |
957 | if (msg == NULL) |
958 | return need_more_input ? 1 : -1; | |
959 | ||
9f98810c | 960 | *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg); |
6fc6879b | 961 | eap_peer_tls_reset_input(data); |
81c85c06 | 962 | if (*in_decrypted == NULL) { |
6fc6879b JM |
963 | wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); |
964 | return -1; | |
965 | } | |
6fc6879b JM |
966 | return 0; |
967 | } | |
968 | ||
969 | ||
970 | /** | |
971 | * eap_peer_tls_encrypt - Encrypt phase 2 TLS message | |
972 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() | |
973 | * @data: Data for TLS processing | |
974 | * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) | |
975 | * @peap_version: Version number for EAP-PEAP/TTLS | |
976 | * @id: EAP identifier for the response | |
977 | * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments | |
978 | * @out_data: Buffer for returning a pointer to the encrypted response message | |
979 | * Returns: 0 on success, -1 on failure | |
980 | */ | |
981 | int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, | |
982 | EapType eap_type, int peap_version, u8 id, | |
983 | const struct wpabuf *in_data, | |
984 | struct wpabuf **out_data) | |
985 | { | |
6fc6879b JM |
986 | if (in_data) { |
987 | eap_peer_tls_reset_output(data); | |
9f98810c JM |
988 | data->tls_out = tls_connection_encrypt(data->ssl_ctx, |
989 | data->conn, in_data); | |
81c85c06 | 990 | if (data->tls_out == NULL) { |
6fc6879b JM |
991 | wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " |
992 | "data (in_len=%lu)", | |
993 | (unsigned long) wpabuf_len(in_data)); | |
994 | eap_peer_tls_reset_output(data); | |
995 | return -1; | |
996 | } | |
6fc6879b JM |
997 | } |
998 | ||
999 | return eap_tls_process_output(data, eap_type, peap_version, id, 0, | |
1000 | out_data); | |
1001 | } | |
1002 | ||
1003 | ||
1004 | /** | |
1005 | * eap_peer_select_phase2_methods - Select phase 2 EAP method | |
1006 | * @config: Pointer to the network configuration | |
1007 | * @prefix: 'phase2' configuration prefix, e.g., "auth=" | |
1008 | * @types: Buffer for returning allocated list of allowed EAP methods | |
1009 | * @num_types: Buffer for returning number of allocated EAP methods | |
1010 | * Returns: 0 on success, -1 on failure | |
1011 | * | |
1012 | * This function is used to parse EAP method list and select allowed methods | |
1013 | * for Phase2 authentication. | |
1014 | */ | |
1015 | int eap_peer_select_phase2_methods(struct eap_peer_config *config, | |
1016 | const char *prefix, | |
1017 | struct eap_method_type **types, | |
1018 | size_t *num_types) | |
1019 | { | |
1020 | char *start, *pos, *buf; | |
1021 | struct eap_method_type *methods = NULL, *_methods; | |
a867082c | 1022 | u32 method; |
6fc6879b JM |
1023 | size_t num_methods = 0, prefix_len; |
1024 | ||
1025 | if (config == NULL || config->phase2 == NULL) | |
1026 | goto get_defaults; | |
1027 | ||
1028 | start = buf = os_strdup(config->phase2); | |
1029 | if (buf == NULL) | |
1030 | return -1; | |
1031 | ||
1032 | prefix_len = os_strlen(prefix); | |
1033 | ||
1034 | while (start && *start != '\0') { | |
1035 | int vendor; | |
1036 | pos = os_strstr(start, prefix); | |
1037 | if (pos == NULL) | |
1038 | break; | |
1039 | if (start != pos && *(pos - 1) != ' ') { | |
1040 | start = pos + prefix_len; | |
1041 | continue; | |
1042 | } | |
1043 | ||
1044 | start = pos + prefix_len; | |
1045 | pos = os_strchr(start, ' '); | |
1046 | if (pos) | |
1047 | *pos++ = '\0'; | |
1048 | method = eap_get_phase2_type(start, &vendor); | |
1049 | if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { | |
1050 | wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " | |
1051 | "method '%s'", start); | |
cb730085 JM |
1052 | os_free(methods); |
1053 | os_free(buf); | |
1054 | return -1; | |
6fc6879b JM |
1055 | } else { |
1056 | num_methods++; | |
067ffa26 JM |
1057 | _methods = os_realloc_array(methods, num_methods, |
1058 | sizeof(*methods)); | |
6fc6879b JM |
1059 | if (_methods == NULL) { |
1060 | os_free(methods); | |
1061 | os_free(buf); | |
1062 | return -1; | |
1063 | } | |
1064 | methods = _methods; | |
1065 | methods[num_methods - 1].vendor = vendor; | |
1066 | methods[num_methods - 1].method = method; | |
1067 | } | |
1068 | ||
1069 | start = pos; | |
1070 | } | |
1071 | ||
1072 | os_free(buf); | |
1073 | ||
1074 | get_defaults: | |
1075 | if (methods == NULL) | |
1076 | methods = eap_get_phase2_types(config, &num_methods); | |
1077 | ||
1078 | if (methods == NULL) { | |
1079 | wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); | |
1080 | return -1; | |
1081 | } | |
1082 | wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", | |
1083 | (u8 *) methods, | |
1084 | num_methods * sizeof(struct eap_method_type)); | |
1085 | ||
1086 | *types = methods; | |
1087 | *num_types = num_methods; | |
1088 | ||
1089 | return 0; | |
1090 | } | |
1091 | ||
1092 | ||
1093 | /** | |
1094 | * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 | |
1095 | * @types: Buffer for returning allocated list of allowed EAP methods | |
1096 | * @num_types: Buffer for returning number of allocated EAP methods | |
1097 | * @hdr: EAP-Request header (and the following EAP type octet) | |
1098 | * @resp: Buffer for returning the EAP-Nak message | |
1099 | * Returns: 0 on success, -1 on failure | |
1100 | */ | |
1101 | int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, | |
1102 | struct eap_hdr *hdr, struct wpabuf **resp) | |
1103 | { | |
1104 | u8 *pos = (u8 *) (hdr + 1); | |
1105 | size_t i; | |
1106 | ||
1107 | /* TODO: add support for expanded Nak */ | |
1108 | wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); | |
1109 | wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", | |
1110 | (u8 *) types, num_types * sizeof(struct eap_method_type)); | |
1111 | *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, | |
1112 | EAP_CODE_RESPONSE, hdr->identifier); | |
1113 | if (*resp == NULL) | |
1114 | return -1; | |
1115 | ||
1116 | for (i = 0; i < num_types; i++) { | |
1117 | if (types[i].vendor == EAP_VENDOR_IETF && | |
1118 | types[i].method < 256) | |
1119 | wpabuf_put_u8(*resp, types[i].method); | |
1120 | } | |
1121 | ||
1122 | eap_update_len(*resp); | |
1123 | ||
1124 | return 0; | |
1125 | } |