/src/freeradius-server/src/lib/tls/session.c
Line | Count | Source |
1 | | /* |
2 | | * This program is free software; you can redistribute it and/or modify |
3 | | * it under the terms of the GNU General Public License as published by |
4 | | * the Free Software Foundation; either version 2 of the License, or |
5 | | * (at your option) any later version. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
15 | | */ |
16 | | |
17 | | /** |
18 | | * $Id: cb2da10fd40b5b4cf48dd5c754adaad922474ada $ |
19 | | * |
20 | | * @file tls/session.c |
21 | | * @brief Initialise OpenSSL sessions, and read/write data to/from them. |
22 | | * |
23 | | * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com) |
24 | | * @copyright 2003 Alan DeKok (aland@freeradius.org) |
25 | | * @copyright 2006-2016 The FreeRADIUS server project |
26 | | */ |
27 | | #ifdef WITH_TLS |
28 | 0 | #define LOG_PREFIX "tls" |
29 | | |
30 | | #include <freeradius-devel/server/pair.h> |
31 | | #include <freeradius-devel/server/log.h> |
32 | | |
33 | | #include <freeradius-devel/util/debug.h> |
34 | | #include <freeradius-devel/util/base16.h> |
35 | | #include <freeradius-devel/util/skip.h> |
36 | | #include <freeradius-devel/util/pair_legacy.h> |
37 | | |
38 | | #include <freeradius-devel/protocol/freeradius/freeradius.internal.h> |
39 | | |
40 | | #include <freeradius-devel/unlang/call.h> |
41 | | #include <freeradius-devel/unlang/subrequest.h> |
42 | | |
43 | | #include <sys/stat.h> |
44 | | #include <fcntl.h> |
45 | | |
46 | | #include "attrs.h" |
47 | | #include "base.h" |
48 | | #include "log.h" |
49 | | |
50 | | #include <openssl/x509v3.h> |
51 | | #include <openssl/ssl.h> |
52 | | |
53 | | static char const *tls_version_str[] = { |
54 | | [SSL2_VERSION] = "SSL 2.0", |
55 | | [SSL3_VERSION] = "SSL 3.0", |
56 | | [TLS1_VERSION] = "TLS 1.0", |
57 | | #ifdef TLS1_1_VERSION |
58 | | [TLS1_1_VERSION] = "TLS 1.1", |
59 | | #endif |
60 | | #ifdef TLS1_2_VERSION |
61 | | [TLS1_2_VERSION] = "TLS 1.2", |
62 | | #endif |
63 | | #ifdef TLS1_3_VERSION |
64 | | [TLS1_3_VERSION] = "TLS 1.3", |
65 | | #endif |
66 | | #ifdef TLS1_4_VERSION |
67 | | [TLS1_4_VERSION] = "TLS 1.4", |
68 | | #endif |
69 | | }; |
70 | | |
71 | | static char const *tls_content_type_str[] = { |
72 | | [SSL3_RT_CHANGE_CIPHER_SPEC] = "change_cipher_spec", |
73 | | [SSL3_RT_ALERT] = "alert", |
74 | | [SSL3_RT_HANDSHAKE] = "handshake", |
75 | | [SSL3_RT_APPLICATION_DATA] = "application_data", |
76 | | #ifdef SSL3_RT_HEADER |
77 | | [SSL3_RT_HEADER] = "header", |
78 | | #endif |
79 | | #ifdef SSL3_RT_INNER_CONTENT_TYPE |
80 | | [SSL3_RT_INNER_CONTENT_TYPE] = "inner_content_type", |
81 | | #endif |
82 | | }; |
83 | | |
84 | | static char const *tls_alert_description_str[] = { |
85 | | [SSL3_AD_CLOSE_NOTIFY] = "close_notify", |
86 | | [SSL3_AD_UNEXPECTED_MESSAGE] = "unexpected_message", |
87 | | [SSL3_AD_BAD_RECORD_MAC] = "bad_record_mac", |
88 | | [TLS1_AD_DECRYPTION_FAILED] = "decryption_failed", |
89 | | [TLS1_AD_RECORD_OVERFLOW] = "record_overflow", |
90 | | [SSL3_AD_DECOMPRESSION_FAILURE] = "decompression_failure", |
91 | | [SSL3_AD_HANDSHAKE_FAILURE] = "handshake_failure", |
92 | | [SSL3_AD_BAD_CERTIFICATE] = "bad_certificate", |
93 | | [SSL3_AD_UNSUPPORTED_CERTIFICATE] = "unsupported_certificate", |
94 | | [SSL3_AD_CERTIFICATE_REVOKED] = "certificate_revoked", |
95 | | [SSL3_AD_CERTIFICATE_EXPIRED] = "certificate_expired", |
96 | | [SSL3_AD_CERTIFICATE_UNKNOWN] = "certificate_unknown", |
97 | | [SSL3_AD_ILLEGAL_PARAMETER] = "illegal_parameter", |
98 | | [TLS1_AD_UNKNOWN_CA] = "unknown_ca", |
99 | | [TLS1_AD_ACCESS_DENIED] = "access_denied", |
100 | | [TLS1_AD_DECODE_ERROR] = "decode_error", |
101 | | [TLS1_AD_DECRYPT_ERROR] = "decrypt_error", |
102 | | [TLS1_AD_EXPORT_RESTRICTION] = "export_restriction", |
103 | | [TLS1_AD_PROTOCOL_VERSION] = "protocol_version", |
104 | | [TLS1_AD_INSUFFICIENT_SECURITY] = "insufficient_security", |
105 | | [TLS1_AD_INTERNAL_ERROR] = "internal_error", |
106 | | [TLS1_AD_USER_CANCELLED] = "user_cancelled", |
107 | | [TLS1_AD_NO_RENEGOTIATION] = "no_renegotiation", |
108 | | #ifdef TLS13_AD_MISSING_EXTENSION |
109 | | [TLS13_AD_MISSING_EXTENSION] = "missing_extension", |
110 | | #endif |
111 | | #ifdef TLS13_AD_CERTIFICATE_REQUIRED |
112 | | [TLS13_AD_CERTIFICATE_REQUIRED] = "certificate_required", |
113 | | #endif |
114 | | #ifdef TLS1_AD_UNSUPPORTED_EXTENSION |
115 | | [TLS1_AD_UNSUPPORTED_EXTENSION] = "unsupported_extension", |
116 | | #endif |
117 | | #ifdef TLS1_AD_CERTIFICATE_UNOBTAINABLE |
118 | | [TLS1_AD_CERTIFICATE_UNOBTAINABLE] = "certificate_unobtainable", |
119 | | #endif |
120 | | #ifdef TLS1_AD_UNRECOGNIZED_NAME |
121 | | [TLS1_AD_UNRECOGNIZED_NAME] = "unrecognised_name", |
122 | | #endif |
123 | | #ifdef TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE |
124 | | [TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE] = "bad_certificate_status_response", |
125 | | #endif |
126 | | #ifdef TLS1_AD_BAD_CERTIFICATE_HASH_VALUE |
127 | | [TLS1_AD_BAD_CERTIFICATE_HASH_VALUE] = "bad_certificate_hash_value", |
128 | | #endif |
129 | | #ifdef TLS1_AD_UNKNOWN_PSK_IDENTITY |
130 | | [TLS1_AD_UNKNOWN_PSK_IDENTITY] = "unknown_psk_identity", |
131 | | #endif |
132 | | #ifdef TLS1_AD_NO_APPLICATION_PROTOCOL |
133 | | [TLS1_AD_NO_APPLICATION_PROTOCOL] = "no_application_protocol", |
134 | | #endif |
135 | | }; |
136 | | |
137 | | static char const *tls_handshake_type_str[] = { |
138 | | [SSL3_MT_HELLO_REQUEST] = "hello_request", |
139 | | [SSL3_MT_CLIENT_HELLO] = "client_hello", |
140 | | [SSL3_MT_SERVER_HELLO] = "server_hello", |
141 | | #ifdef SSL3_MT_NEWSESSION_TICKET |
142 | | [SSL3_MT_NEWSESSION_TICKET] = "new_session_ticket", |
143 | | #endif |
144 | | #ifdef SSL3_MT_END_OF_EARLY_DATA |
145 | | [SSL3_MT_END_OF_EARLY_DATA] = "end_of_early_data", |
146 | | #endif |
147 | | #ifdef SSL3_MT_ENCRYPTED_EXTENSIONS |
148 | | [SSL3_MT_ENCRYPTED_EXTENSIONS] = "encrypted_extensions", |
149 | | #endif |
150 | | [SSL3_MT_CERTIFICATE] = "certificate", |
151 | | [SSL3_MT_SERVER_KEY_EXCHANGE] = "server_key_exchange", |
152 | | [SSL3_MT_CERTIFICATE_REQUEST] = "certificate_request", |
153 | | [SSL3_MT_SERVER_DONE] = "server_hello_done", |
154 | | [SSL3_MT_CERTIFICATE_VERIFY] = "certificate_verify", |
155 | | [SSL3_MT_CLIENT_KEY_EXCHANGE] = "client_key_exchange", |
156 | | [SSL3_MT_FINISHED] = "finished", |
157 | | #ifdef SSL3_MT_CERTIFICATE_URL |
158 | | [SSL3_MT_CERTIFICATE_URL] = "certificate_url", |
159 | | #endif |
160 | | #ifdef SSL3_MT_CERTIFICATE_STATUS |
161 | | [SSL3_MT_CERTIFICATE_STATUS] = "certificate_status", |
162 | | #endif |
163 | | #ifdef SSL3_MT_SUPPLEMENTAL_DATA |
164 | | [SSL3_MT_SUPPLEMENTAL_DATA] = "supplemental_data", |
165 | | #endif |
166 | | #ifdef SSL3_MT_KEY_UPDATE |
167 | | [SSL3_MT_KEY_UPDATE] = "key_update", |
168 | | #endif |
169 | | #ifdef SSL3_MT_NEXT_PROTO |
170 | | [SSL3_MT_NEXT_PROTO] = "next_proto", |
171 | | #endif |
172 | | #ifdef SSL3_MT_MESSAGE_HASH |
173 | | [SSL3_MT_MESSAGE_HASH] = "message_hash", |
174 | | #endif |
175 | | #ifdef DTLS1_MT_HELLO_VERIFY_REQUEST |
176 | | [DTLS1_MT_HELLO_VERIFY_REQUEST] = "hello_verify_request", |
177 | | #endif |
178 | | #ifdef SSL3_MT_CHANGE_CIPHER_SPEC |
179 | | [SSL3_MT_CHANGE_CIPHER_SPEC] = "change_cipher_spec", |
180 | | #endif |
181 | | }; |
182 | | |
183 | | /** Clear a record buffer |
184 | | * |
185 | | * @param record buffer to clear. |
186 | | */ |
187 | | inline static void record_init(fr_tls_record_t *record) |
188 | 0 | { |
189 | 0 | record->used = 0; |
190 | 0 | } |
191 | | |
192 | | /** Destroy a record buffer |
193 | | * |
194 | | * @param record buffer to destroy clear. |
195 | | */ |
196 | | inline static void record_close(fr_tls_record_t *record) |
197 | 0 | { |
198 | 0 | record->used = 0; |
199 | 0 | } |
200 | | |
201 | | /** Copy data to the intermediate buffer, before we send it somewhere |
202 | | * |
203 | | * @param[in] record buffer to write to. |
204 | | * @param[in] in data to write. |
205 | | * @param[in] inlen Length of data to write. |
206 | | * @return the amount of data written to the record buffer. |
207 | | */ |
208 | | inline static unsigned int record_from_buff(fr_tls_record_t *record, void const *in, unsigned int inlen) |
209 | 0 | { |
210 | 0 | unsigned int added = FR_TLS_MAX_RECORD_SIZE - record->used; |
211 | |
|
212 | 0 | if (added > inlen) added = inlen; |
213 | 0 | if (added == 0) return 0; |
214 | | |
215 | 0 | memcpy(record->data + record->used, in, added); |
216 | 0 | record->used += added; |
217 | |
|
218 | 0 | return added; |
219 | 0 | } |
220 | | |
221 | | /** Take data from the buffer, and give it to the caller |
222 | | * |
223 | | * @param[in] record buffer to read from. |
224 | | * @param[out] out where to write data from record buffer. |
225 | | * @param[in] outlen The length of the output buffer. |
226 | | * @return the amount of data written to the output buffer. |
227 | | */ |
228 | | inline static unsigned int record_to_buff(fr_tls_record_t *record, void *out, unsigned int outlen) |
229 | 0 | { |
230 | 0 | unsigned int taken = record->used; |
231 | |
|
232 | 0 | if (taken > outlen) taken = outlen; |
233 | 0 | if (taken == 0) return 0; |
234 | 0 | if (out) memcpy(out, record->data, taken); |
235 | |
|
236 | 0 | record->used -= taken; |
237 | | |
238 | | /* |
239 | | * This is pretty bad... |
240 | | */ |
241 | 0 | if (record->used > 0) memmove(record->data, record->data + taken, record->used); |
242 | |
|
243 | 0 | return taken; |
244 | 0 | } |
245 | | |
246 | | /** Return the static private key password we have configured |
247 | | * |
248 | | * @param[out] buf Where to write the password to. |
249 | | * @param[in] size The length of buf. |
250 | | * @param[in] rwflag |
251 | | * - 0 if password used for decryption. |
252 | | * - 1 if password used for encryption. |
253 | | * @param[in] u The static password. |
254 | | * @return |
255 | | * - 0 on error. |
256 | | * - >0 on success (the length of the password). |
257 | | */ |
258 | | int fr_tls_session_password_cb(char *buf, int size, int rwflag UNUSED, void *u) |
259 | 0 | { |
260 | 0 | size_t len; |
261 | | |
262 | | /* |
263 | | * We do this instead of not registering the callback |
264 | | * to ensure OpenSSL doesn't try and read a password |
265 | | * from stdin (causes server to block). |
266 | | */ |
267 | 0 | if (!u) { |
268 | 0 | ERROR("Private key encrypted but no private_key_password configured"); |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | 0 | len = strlcpy(buf, (char *)u, size); |
273 | 0 | if (len > (size_t)size) { |
274 | 0 | ERROR("Password too long. Maximum length is %i bytes", size - 1); |
275 | 0 | return 0; |
276 | 0 | } |
277 | | |
278 | 0 | return len; |
279 | 0 | } |
280 | | |
281 | | #ifdef PSK_MAX_IDENTITY_LEN |
282 | | /** Verify the PSK identity contains no reserved chars |
283 | | * |
284 | | * @param identity to check. |
285 | | * @return |
286 | | * - true identity does not contain reserved chars. |
287 | | * - false identity contains reserved chars. |
288 | | */ |
289 | | static bool session_psk_identity_is_safe(const char *identity) |
290 | 0 | { |
291 | 0 | char c; |
292 | |
|
293 | 0 | if (!identity) return true; |
294 | | |
295 | 0 | while ((c = *(identity++)) != '\0') { |
296 | 0 | if (isalpha((uint8_t) c) || isdigit((uint8_t) c) || isspace((uint8_t) c) || |
297 | 0 | (c == '@') || (c == '-') || (c == '_') || (c == '.')) { |
298 | 0 | continue; |
299 | 0 | } |
300 | | |
301 | 0 | return false; |
302 | 0 | } |
303 | | |
304 | 0 | return true; |
305 | 0 | } |
306 | | |
307 | | /** Determine the PSK to use for an outgoing connection |
308 | | * |
309 | | * @param[in] ssl session. |
310 | | * @param[in] identity The identity of the PSK to search for. |
311 | | * @param[out] psk Where to write the PSK we found (if any). |
312 | | * @param[in] max_psk_len The length of the buffer provided for PSK. |
313 | | * @return |
314 | | * - 0 if no PSK matching identity was found. |
315 | | * - >0 if a PSK matching identity was found (the length of bytes written to psk). |
316 | | */ |
317 | | unsigned int fr_tls_session_psk_client_cb(SSL *ssl, UNUSED char const *hint, |
318 | | char *identity, unsigned int max_identity_len, |
319 | | unsigned char *psk, unsigned int max_psk_len) |
320 | 0 | { |
321 | 0 | unsigned int psk_len; |
322 | 0 | fr_tls_conf_t *conf; |
323 | |
|
324 | 0 | conf = (fr_tls_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF); |
325 | 0 | if (!conf) return 0; |
326 | | |
327 | 0 | psk_len = strlen(conf->psk_password); |
328 | 0 | if (psk_len > (2 * max_psk_len)) return 0; |
329 | | |
330 | 0 | strlcpy(identity, conf->psk_identity, max_identity_len); |
331 | |
|
332 | 0 | return fr_base16_decode(NULL, |
333 | 0 | &FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len), |
334 | 0 | &FR_SBUFF_IN(conf->psk_password, (size_t)psk_len), false); |
335 | 0 | } |
336 | | |
337 | | /** Determine the PSK to use for an incoming connection |
338 | | * |
339 | | * @param[in] ssl session. |
340 | | * @param[in] identity The identity of the PSK to search for. |
341 | | * @param[out] psk Where to write the PSK we found (if any). |
342 | | * @param[in] max_psk_len The length of the buffer provided for PSK. |
343 | | * @return |
344 | | * - 0 if no PSK matching identity was found. |
345 | | * - >0 if a PSK matching identity was found (the length of bytes written to psk). |
346 | | */ |
347 | | unsigned int fr_tls_session_psk_server_cb(SSL *ssl, const char *identity, |
348 | | unsigned char *psk, unsigned int max_psk_len) |
349 | 0 | { |
350 | 0 | size_t psk_len = 0; |
351 | 0 | fr_tls_conf_t *conf; |
352 | 0 | request_t *request; |
353 | |
|
354 | 0 | conf = (fr_tls_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF); |
355 | 0 | if (!conf) return 0; |
356 | | |
357 | 0 | request = fr_tls_session_request(ssl); |
358 | 0 | if (request && conf->psk_query) { |
359 | 0 | size_t hex_len; |
360 | 0 | fr_pair_t *vp; |
361 | 0 | char buffer[2 * PSK_MAX_PSK_LEN + 4]; /* allow for too-long keys */ |
362 | | |
363 | | /* |
364 | | * The passed identity is weird. Deny it. |
365 | | */ |
366 | 0 | if (!session_psk_identity_is_safe(identity)) { |
367 | 0 | RWDEBUG("Invalid characters in PSK identity %s", identity); |
368 | 0 | return 0; |
369 | 0 | } |
370 | | |
371 | 0 | MEM(pair_update_request(&vp, attr_tls_psk_identity) >= 0); |
372 | 0 | if (fr_pair_value_from_str(vp, identity, strlen(identity), NULL, true) < 0) { |
373 | 0 | RPWDEBUG2("Failed parsing TLS PSK Identity"); |
374 | 0 | talloc_free(vp); |
375 | 0 | return 0; |
376 | 0 | } |
377 | | |
378 | 0 | hex_len = xlat_eval(buffer, sizeof(buffer), request, conf->psk_query, NULL, NULL); |
379 | 0 | if (!hex_len) { |
380 | 0 | RWDEBUG("PSK expansion returned an empty string."); |
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | | /* |
385 | | * The returned key is truncated at MORE than |
386 | | * OpenSSL can handle. That way we can detect |
387 | | * the truncation, and complain about it. |
388 | | */ |
389 | 0 | if (hex_len > (2 * max_psk_len)) { |
390 | 0 | RWDEBUG("Returned PSK is too long (%u > %u)", (unsigned int) hex_len, 2 * max_psk_len); |
391 | 0 | return 0; |
392 | 0 | } |
393 | | |
394 | | /* |
395 | | * Leave the TLS-PSK-Identity in the request, and |
396 | | * convert the expansion from printable string |
397 | | * back to hex. |
398 | | */ |
399 | 0 | return fr_base16_decode(NULL, |
400 | 0 | &FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len), |
401 | 0 | &FR_SBUFF_IN(buffer, hex_len), false); |
402 | 0 | } |
403 | | |
404 | 0 | if (!conf->psk_identity) { |
405 | 0 | DEBUG("No static PSK identity set. Rejecting the user"); |
406 | 0 | return 0; |
407 | 0 | } |
408 | | |
409 | | /* |
410 | | * No request_t, or no dynamic query. Just look for a |
411 | | * static identity. |
412 | | */ |
413 | 0 | if (strcmp(identity, conf->psk_identity) != 0) { |
414 | 0 | ERROR("Supplied PSK identity %s does not match configuration. Rejecting.", |
415 | 0 | identity); |
416 | 0 | return 0; |
417 | 0 | } |
418 | | |
419 | 0 | psk_len = strlen(conf->psk_password); |
420 | 0 | if (psk_len > (2 * max_psk_len)) return 0; |
421 | | |
422 | 0 | return fr_base16_decode(NULL, |
423 | 0 | &FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len), |
424 | 0 | &FR_SBUFF_IN(conf->psk_password, psk_len), false); |
425 | 0 | } |
426 | | #endif /* PSK_MAX_IDENTITY_LEN */ |
427 | | |
428 | | DIAG_OFF(DIAG_UNKNOWN_PRAGMAS) |
429 | | DIAG_OFF(used-but-marked-unused) /* Fix spurious warnings for sk_ macros */ |
430 | | /** Record session state changes |
431 | | * |
432 | | * Called by OpenSSL whenever the session state changes, an alert is received or an error occurs. |
433 | | * |
434 | | * @param[in] ssl session. |
435 | | * @param[in] where Which context the callback is being called in. |
436 | | * See https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_info_callback.html |
437 | | * for additional info. |
438 | | * @param[in] ret 0 if an error occurred, or the alert type if an alert was received. |
439 | | */ |
440 | | void fr_tls_session_info_cb(SSL const *ssl, int where, int ret) |
441 | 0 | { |
442 | 0 | char const *role, *state; |
443 | 0 | request_t *request = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST); |
444 | |
|
445 | 0 | if ((where & ~SSL_ST_MASK) & SSL_ST_CONNECT) { |
446 | 0 | role = "Client "; |
447 | 0 | } else if (((where & ~SSL_ST_MASK)) & SSL_ST_ACCEPT) { |
448 | 0 | role = "Server "; |
449 | 0 | } else { |
450 | 0 | role = ""; |
451 | 0 | } |
452 | |
|
453 | 0 | state = SSL_state_string_long(ssl); |
454 | 0 | state = state ? state : "<INVALID>"; |
455 | |
|
456 | 0 | if ((where & SSL_CB_LOOP) || (where & SSL_CB_HANDSHAKE_START) || (where & SSL_CB_HANDSHAKE_DONE)) { |
457 | 0 | if (ROPTIONAL_ENABLED(RDEBUG_ENABLED3, DEBUG_ENABLED3)) { |
458 | 0 | char const *abbrv = SSL_state_string(ssl); |
459 | 0 | size_t len; |
460 | | |
461 | | /* |
462 | | * Trim crappy OpenSSL state strings... |
463 | | */ |
464 | 0 | len = strlen(abbrv); |
465 | 0 | if ((len > 1) && (abbrv[len - 1] == ' ')) len--; |
466 | |
|
467 | 0 | ROPTIONAL(RDEBUG3, DEBUG3, "Handshake state [%.*s] - %s%s", (int)len, abbrv, role, state); |
468 | |
|
469 | | #ifdef OPENSSL_NO_SSL_TRACE |
470 | | { |
471 | | STACK_OF(SSL_CIPHER) *server_ciphers; |
472 | | STACK_OF(SSL_CIPHER) *client_ciphers; |
473 | | |
474 | | /* |
475 | | * After a ClientHello, list all the proposed ciphers |
476 | | * from the client. |
477 | | * |
478 | | * Only do this if we don't have SSL_trace() as |
479 | | * SSL_trace() prints this information and we don't |
480 | | * want to duplicate it. |
481 | | */ |
482 | | if (SSL_get_state(ssl) == TLS_ST_SR_CLNT_HELLO && |
483 | | (client_ciphers = SSL_get_client_ciphers(ssl))) { |
484 | | int i; |
485 | | int num_ciphers; |
486 | | const SSL_CIPHER *this_cipher; |
487 | | |
488 | | server_ciphers = SSL_get_ciphers(ssl); |
489 | | /* |
490 | | * These are printed on startup, so not usually |
491 | | * required. |
492 | | */ |
493 | | ROPTIONAL(RDEBUG4, DEBUG4, "Our preferred ciphers (by priority)"); |
494 | | if (ROPTIONAL_ENABLED(RDEBUG_ENABLED4, DEBUG_ENABLED4)) { |
495 | | if (request) RINDENT(); |
496 | | num_ciphers = sk_SSL_CIPHER_num(server_ciphers); |
497 | | for (i = 0; i < num_ciphers; i++) { |
498 | | this_cipher = sk_SSL_CIPHER_value(server_ciphers, i); |
499 | | ROPTIONAL(RDEBUG4, DEBUG4, "[%i] %s", i, SSL_CIPHER_get_name(this_cipher)); |
500 | | } |
501 | | if (request) REXDENT(); |
502 | | } |
503 | | |
504 | | /* |
505 | | * Print information about the client's |
506 | | * handshake message. |
507 | | */ |
508 | | if (ROPTIONAL_ENABLED(RDEBUG_ENABLED3, DEBUG_ENABLED3)) { |
509 | | ROPTIONAL(RDEBUG3, DEBUG3, "Client's preferred ciphers (by priority)"); |
510 | | if (request) RINDENT(); |
511 | | num_ciphers = sk_SSL_CIPHER_num(client_ciphers); |
512 | | for (i = 0; i < num_ciphers; i++) { |
513 | | this_cipher = sk_SSL_CIPHER_value(client_ciphers, i); |
514 | | ROPTIONAL(RDEBUG3, DEBUG3, "[%i] %s", i, SSL_CIPHER_get_name(this_cipher)); |
515 | | } |
516 | | if (request) REXDENT(); |
517 | | } |
518 | | } |
519 | | } |
520 | | # endif |
521 | 0 | } else { |
522 | 0 | ROPTIONAL(RDEBUG2, DEBUG2, "Handshake state - %s%s (%u)", role, state, SSL_get_state(ssl)); |
523 | 0 | } |
524 | 0 | return; |
525 | 0 | } |
526 | | |
527 | 0 | if (where & SSL_CB_ALERT) { |
528 | 0 | if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) return; |
529 | | |
530 | | /* |
531 | | * We got an alert... |
532 | | */ |
533 | 0 | if (where & SSL_CB_READ) { |
534 | 0 | fr_pair_t *vp; |
535 | |
|
536 | 0 | ROPTIONAL(REDEBUG, ERROR, "Client sent %s TLS alert (%i) - %s", SSL_alert_type_string_long(ret), |
537 | 0 | ret & 0xff, SSL_alert_desc_string_long(ret)); |
538 | | |
539 | | /* |
540 | | * Offer helpful advice... Should be expanded. |
541 | | */ |
542 | 0 | switch (ret & 0xff) { |
543 | 0 | case TLS1_AD_UNKNOWN_CA: |
544 | 0 | REDEBUG("Verify the client has a copy of the server's Certificate " |
545 | 0 | "Authority (CA) installed, and trusts that CA"); |
546 | 0 | break; |
547 | | |
548 | 0 | default: |
549 | 0 | break; |
550 | 0 | } |
551 | | |
552 | 0 | if (request) { |
553 | 0 | MEM(pair_update_request(&vp, attr_tls_client_error_code) >= 0); |
554 | 0 | vp->vp_uint8 = ret & 0xff; |
555 | 0 | RDEBUG2("TLS-Client-Error-Code := %pV", &vp->data); |
556 | 0 | } |
557 | | /* |
558 | | * We're sending the client an alert. |
559 | | */ |
560 | 0 | } else { |
561 | 0 | ROPTIONAL(REDEBUG, ERROR, "Sending client %s TLS alert (%i) - %s", |
562 | 0 | SSL_alert_type_string_long(ret), ret & 0xff, SSL_alert_desc_string_long(ret)); |
563 | | |
564 | | /* |
565 | | * Offer helpful advice... Should be expanded. |
566 | | */ |
567 | 0 | switch (ret & 0xff) { |
568 | 0 | case TLS1_AD_PROTOCOL_VERSION: |
569 | 0 | ROPTIONAL(REDEBUG, ERROR, "Client requested a TLS protocol version that is not " |
570 | 0 | "enabled or not supported. Upgrade FreeRADIUS + OpenSSL to their latest " |
571 | 0 | "versions and/or adjust 'tls_max_version'/'tls_min_version' if you want " |
572 | 0 | "authentication to succeed"); |
573 | 0 | break; |
574 | | |
575 | 0 | default: |
576 | 0 | break; |
577 | 0 | } |
578 | 0 | } |
579 | 0 | return; |
580 | 0 | } |
581 | | |
582 | 0 | if (where & SSL_CB_EXIT) { |
583 | 0 | if (ret == 0) { |
584 | 0 | ROPTIONAL(REDEBUG, ERROR, "Handshake exit state %s%s", role, state); |
585 | 0 | return; |
586 | 0 | } |
587 | | |
588 | 0 | if (ret < 0) { |
589 | 0 | if (SSL_want_read(ssl)) { |
590 | 0 | RDEBUG2("Need more data from client"); /* State same as previous call, don't print */ |
591 | 0 | return; |
592 | 0 | } |
593 | 0 | ROPTIONAL(REDEBUG, ERROR, "Handshake exit state %s%s", role, state); |
594 | 0 | } |
595 | 0 | } |
596 | 0 | } |
597 | | DIAG_ON(used-but-marked-unused) |
598 | | DIAG_ON(DIAG_UNKNOWN_PRAGMAS) |
599 | | |
600 | | /** Print a message to the request or global log detailing handshake state |
601 | | * |
602 | | * @param[in] request The current #request_t. |
603 | | * @param[in] tls_session The current TLS session. |
604 | | */ |
605 | | static void session_msg_log(request_t *request, fr_tls_session_t *tls_session, uint8_t const *data, size_t data_len) |
606 | 0 | { |
607 | 0 | char const *version, *content_type; |
608 | 0 | char const *str_details1 = NULL; |
609 | 0 | char const *str_details2 = NULL; |
610 | 0 | char unknown_version[32]; |
611 | 0 | char unknown_content_type[32]; |
612 | 0 | char unknown_alert_level[32]; |
613 | 0 | char unknown_alert_description[32]; |
614 | 0 | char unknown_handshake_type[32]; |
615 | | |
616 | | /* |
617 | | * Don't print this out in the normal course of |
618 | | * operations. |
619 | | */ |
620 | 0 | if (!ROPTIONAL_ENABLED(RDEBUG_ENABLED2, DEBUG_ENABLED2)) return; |
621 | | |
622 | 0 | if (((size_t)tls_session->info.version >= NUM_ELEMENTS(tls_version_str)) || |
623 | 0 | !tls_version_str[tls_session->info.version]) { |
624 | 0 | snprintf(unknown_version, sizeof(unknown_version), "unknown_tls_version_0x%04x", |
625 | 0 | (unsigned int) tls_session->info.version); |
626 | 0 | version = unknown_version; |
627 | 0 | } else { |
628 | 0 | version = tls_version_str[tls_session->info.version]; |
629 | 0 | } |
630 | | |
631 | | /* |
632 | | * TLS 1.0, 1.1, 1.2 content types are the same as SSLv3 |
633 | | */ |
634 | 0 | if (((size_t)tls_session->info.content_type >= NUM_ELEMENTS(tls_content_type_str)) || |
635 | 0 | !tls_content_type_str[tls_session->info.content_type]) { |
636 | 0 | snprintf(unknown_content_type, sizeof(unknown_content_type), |
637 | 0 | "unknown_content_type_0x%04x", (unsigned int) tls_session->info.content_type); |
638 | 0 | content_type = unknown_content_type; |
639 | 0 | } else { |
640 | 0 | content_type = tls_content_type_str[tls_session->info.content_type]; |
641 | 0 | } |
642 | |
|
643 | 0 | if (tls_session->info.content_type == SSL3_RT_ALERT) { |
644 | 0 | if (tls_session->info.record_len == 2) { |
645 | 0 | switch (tls_session->info.alert_level) { |
646 | 0 | case SSL3_AL_WARNING: |
647 | 0 | str_details1 = "warning"; |
648 | 0 | break; |
649 | 0 | case SSL3_AL_FATAL: |
650 | 0 | str_details1 = "fatal"; |
651 | 0 | break; |
652 | | |
653 | 0 | default: |
654 | 0 | snprintf(unknown_alert_level, sizeof(unknown_alert_level), |
655 | 0 | "unknown_alert_level_0x%04x", tls_session->info.alert_level); |
656 | 0 | str_details1 = unknown_alert_level; |
657 | 0 | break; |
658 | 0 | } |
659 | | |
660 | 0 | if (((size_t)tls_session->info.alert_description >= NUM_ELEMENTS(tls_alert_description_str)) || |
661 | 0 | !tls_alert_description_str[tls_session->info.alert_description]) { |
662 | 0 | snprintf(unknown_alert_description, sizeof(unknown_alert_description), |
663 | 0 | "unknown_alert_0x%04x", tls_session->info.alert_description); |
664 | 0 | str_details2 = unknown_alert_description; |
665 | 0 | } else { |
666 | 0 | str_details2 = tls_alert_description_str[tls_session->info.alert_description]; |
667 | 0 | } |
668 | 0 | } else { |
669 | 0 | str_details1 = "unknown_alert_level"; |
670 | 0 | str_details2 = "unknown_alert"; |
671 | 0 | } |
672 | 0 | } |
673 | | |
674 | 0 | if ((size_t)tls_session->info.content_type == SSL3_RT_HANDSHAKE) { |
675 | 0 | if (tls_session->info.record_len > 0) { |
676 | | /* |
677 | | * Range guard not needed due to size of array |
678 | | * and underlying type. |
679 | | */ |
680 | 0 | if (!tls_handshake_type_str[tls_session->info.handshake_type]) { |
681 | 0 | snprintf(unknown_handshake_type, sizeof(unknown_handshake_type), |
682 | 0 | "unknown_handshake_type_0x%02x", tls_session->info.handshake_type); |
683 | 0 | str_details1 = unknown_handshake_type; |
684 | 0 | } else { |
685 | 0 | str_details1 = tls_handshake_type_str[tls_session->info.handshake_type]; |
686 | 0 | } |
687 | 0 | } |
688 | 0 | } |
689 | |
|
690 | 0 | snprintf(tls_session->info.info_description, sizeof(tls_session->info.info_description), |
691 | 0 | "%s %s, %s[length %lu]%s%s%s%s", |
692 | 0 | tls_session->info.origin ? ">>> send" : "<<< recv", |
693 | 0 | version, |
694 | 0 | content_type, |
695 | 0 | (unsigned long)tls_session->info.record_len, |
696 | 0 | str_details1 ? ", " : "", |
697 | 0 | str_details1 ? str_details1 : "", |
698 | 0 | str_details2 ? ", " : "", |
699 | 0 | str_details2 ? str_details2 : ""); |
700 | | |
701 | | /* |
702 | | * Print out information about the record and print the |
703 | | * data at higher debug levels. |
704 | | */ |
705 | 0 | if (ROPTIONAL_ENABLED(RDEBUG_ENABLED4, DEBUG_ENABLED4)) { |
706 | 0 | ROPTIONAL(RHEXDUMP4, HEXDUMP4, data, data_len, "%s", tls_session->info.info_description); |
707 | 0 | } else { |
708 | 0 | ROPTIONAL(RDEBUG2, DEBUG2, "%s", tls_session->info.info_description); |
709 | 0 | } |
710 | 0 | } |
711 | | |
712 | | /** Record the progression of the TLS handshake |
713 | | * |
714 | | * This callback is called by OpenSSL whenever a protocol message relating to a handshake is sent |
715 | | * or received. |
716 | | * |
717 | | * This function copies state information from the various arguments into the state->info |
718 | | * structure of the #fr_tls_session_t, to allow us to track the progression of the handshake. |
719 | | * |
720 | | * @param[in] write_p |
721 | | * - 0 when a message has been received. |
722 | | * - 1 when a message has been sent. |
723 | | * |
724 | | * @param[in] msg_version The TLS version negotiated, should be one of: |
725 | | * - TLS1_VERSION |
726 | | * - TLS1_1_VERSION |
727 | | * - TLS1_2_VERSION |
728 | | * - TLS1_3_VERSION |
729 | | * |
730 | | * @param[in] content_type One of the contentType values defined for TLS: |
731 | | * - SSL3_RT_CHANGE_CIPHER_SPEC (20) |
732 | | * - SSL3_RT_ALERT (21) |
733 | | * - SSL3_RT_HANDSHAKE (22) |
734 | | * - TLS1_RT_HEARTBEAT (24) |
735 | | * |
736 | | * @param[in] inbuf The raw protocol message. |
737 | | * @param[in] len Length of the raw protocol message. |
738 | | * @param[in] ssl The SSL session. |
739 | | * @param[in] arg The #fr_tls_session_t holding the SSL session. |
740 | | */ |
741 | | void fr_tls_session_msg_cb(int write_p, int msg_version, int content_type, |
742 | | void const *inbuf, size_t len, |
743 | | SSL *ssl, void *arg) |
744 | 0 | { |
745 | 0 | uint8_t const *buf = inbuf; |
746 | 0 | fr_tls_session_t *tls_session = talloc_get_type_abort(arg, fr_tls_session_t); |
747 | 0 | request_t *request = fr_tls_session_request(tls_session->ssl); |
748 | | |
749 | | /* |
750 | | * Mostly to check for memory corruption... |
751 | | */ |
752 | 0 | if (!fr_cond_assert(tls_session->ssl == ssl)) { |
753 | 0 | ROPTIONAL(REDEBUG, ERROR, "fr_tls_session_t and ssl arg do not match in fr_tls_session_msg_cb"); |
754 | 0 | tls_session->invalid = true; |
755 | 0 | return; |
756 | 0 | } |
757 | | |
758 | | /* |
759 | | * As per https://tools.ietf.org/html/rfc7568 |
760 | | * |
761 | | * We explicitly disable SSLv2/v3, hence the asserts. |
762 | | */ |
763 | 0 | #ifdef SSL2_VERSION |
764 | 0 | if (!fr_cond_assert(msg_version != SSL2_VERSION)) { |
765 | 0 | ROPTIONAL(REDEBUG, ERROR, "Invalid version (SSLv2) in handshake"); |
766 | 0 | tls_session->invalid = true; |
767 | 0 | return; |
768 | 0 | } |
769 | 0 | #endif |
770 | | |
771 | 0 | #ifdef SSL3_VERSION |
772 | 0 | if (!fr_cond_assert(msg_version != SSL3_VERSION)) { |
773 | 0 | ROPTIONAL(REDEBUG, ERROR, "Invalid version (SSLv3) in handshake"); |
774 | 0 | tls_session->invalid = true; |
775 | 0 | return; |
776 | 0 | } |
777 | 0 | #endif |
778 | | |
779 | | /* |
780 | | * OpenSSL >= 1.0.2 calls this function with 'pseudo' |
781 | | * content types. Which breaks our tracking of |
782 | | * the SSL Session state. |
783 | | */ |
784 | 0 | if ((msg_version == 0) && (content_type > UINT8_MAX)) { |
785 | 0 | ROPTIONAL(REDEBUG4, DEBUG4, "Ignoring fr_tls_session_msg_cb call with pseudo content type %i, version %i", |
786 | 0 | content_type, msg_version); |
787 | 0 | return; |
788 | 0 | } |
789 | | |
790 | 0 | if ((write_p != 0) && (write_p != 1)) { |
791 | 0 | ROPTIONAL(REDEBUG4, DEBUG4, "Ignoring fr_tls_session_msg_cb call with invalid write_p %d", write_p); |
792 | 0 | return; |
793 | 0 | } |
794 | | |
795 | | /* |
796 | | * 0 - received (from peer) |
797 | | * 1 - sending (to peer) |
798 | | */ |
799 | 0 | tls_session->info.origin = write_p; |
800 | 0 | tls_session->info.content_type = content_type; |
801 | 0 | tls_session->info.record_len = len; |
802 | 0 | tls_session->info.version = msg_version; |
803 | 0 | tls_session->info.initialized = true; |
804 | |
|
805 | 0 | switch (content_type) { |
806 | 0 | case SSL3_RT_ALERT: |
807 | 0 | if (len < 2) { |
808 | 0 | invalid_alert: |
809 | 0 | ROPTIONAL(REDEBUG, ERROR, "Invalid TLS Alert. Closing connection"); |
810 | 0 | tls_session->invalid = true; |
811 | 0 | return; |
812 | 0 | } |
813 | | |
814 | 0 | tls_session->info.alert_level = buf[0]; |
815 | 0 | tls_session->info.alert_description = buf[1]; |
816 | 0 | tls_session->info.handshake_type = 0x00; |
817 | 0 | break; |
818 | | |
819 | 0 | case SSL3_RT_HANDSHAKE: |
820 | 0 | if (!len) goto invalid_alert; |
821 | | |
822 | 0 | tls_session->info.handshake_type = buf[0]; |
823 | 0 | tls_session->info.alert_level = 0x00; |
824 | 0 | tls_session->info.alert_description = 0x00; |
825 | 0 | break; |
826 | | |
827 | | #ifdef SSL3_RT_HEARTBEAT |
828 | | case TLS1_RT_HEARTBEAT: |
829 | | uint8_t *p = buf; |
830 | | |
831 | | if ((len >= 3) && (p[0] == 1)) { |
832 | | size_t payload_len; |
833 | | |
834 | | payload_len = fr_nbo_to_uint16(p + 1); |
835 | | if ((payload_len + 3) > len) { |
836 | | tls_session->invalid = true; |
837 | | ROPTIONAL(REDEBUG, ERROR, "OpenSSL Heartbeat attack detected. Closing connection"); |
838 | | return; |
839 | | } |
840 | | } |
841 | | break; |
842 | | #endif |
843 | 0 | default: |
844 | 0 | break; |
845 | 0 | } |
846 | | |
847 | 0 | session_msg_log(request, tls_session, (uint8_t const *)inbuf, len); |
848 | |
|
849 | 0 | #ifndef OPENSSL_NO_SSL_TRACE |
850 | 0 | if (ROPTIONAL_ENABLED(RDEBUG_ENABLED3, DEBUG_ENABLED3)) { |
851 | 0 | SSL_trace(tls_session->info.origin, |
852 | 0 | tls_session->info.version, |
853 | 0 | tls_session->info.content_type, |
854 | 0 | inbuf, len, |
855 | 0 | ssl, |
856 | 0 | request ? |
857 | 0 | fr_tls_request_log_bio(request, L_DBG, L_DBG_LVL_3) : |
858 | 0 | fr_tls_global_log_bio(L_DBG, L_DBG_LVL_3)); |
859 | 0 | } |
860 | 0 | #endif |
861 | 0 | } |
862 | | |
863 | | /* |
864 | | * By setting the environment variable SSLKEYLOGFILE to a filename keying |
865 | | * material will be exported that you may use with Wireshark to decode any |
866 | | * TLS flows. Please see the following for more details: |
867 | | * |
868 | | * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption |
869 | | * |
870 | | * An example logging session is (you should delete the file on each run): |
871 | | * |
872 | | * rm -f /tmp/sslkey.log; env SSLKEYLOGFILE=/tmp/sslkey.log freeradius -X | tee /tmp/debug |
873 | | * |
874 | | * Note that we rely on the OS to check file permissions. If the |
875 | | * caller can run radiusd, then they can only write to files which |
876 | | * they own. If radiusd is running as root, then only root can |
877 | | * change the environment variables for radiusd. |
878 | | */ |
879 | | void fr_tls_session_keylog_cb(const SSL *ssl, const char *line) |
880 | 0 | { |
881 | 0 | int fd; |
882 | 0 | size_t len; |
883 | 0 | const char *filename; |
884 | 0 | char buffer[64 + 2*SSL3_RANDOM_SIZE + 2*SSL_MAX_MASTER_KEY_LENGTH]; |
885 | | |
886 | | /* |
887 | | * Prefer the environment variable definition to the |
888 | | * configuration file. This allows for "one-shot" |
889 | | * dumping of EAP keys when you know you're not using |
890 | | * RadSec, and you don't want to edit the configuration. |
891 | | */ |
892 | 0 | filename = getenv("SSLKEYLOGFILE"); |
893 | 0 | if (!filename) { |
894 | 0 | fr_tls_conf_t *conf; |
895 | |
|
896 | 0 | conf = (fr_tls_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF); |
897 | 0 | if (!conf || !conf->keylog_file || !*conf->keylog_file) return; |
898 | | |
899 | 0 | filename = conf->keylog_file; |
900 | 0 | } |
901 | | |
902 | | /* |
903 | | * We write all of the data at once. This is *generally* |
904 | | * atomic on most systems. |
905 | | */ |
906 | 0 | len = strlen(line); |
907 | 0 | if ((len + 1) > sizeof(buffer)) { |
908 | 0 | DEBUG("SSLKEYLOGFILE buffer not large enough, max %lu, required %lu", sizeof(buffer), len + 1); |
909 | 0 | return; |
910 | 0 | } |
911 | | |
912 | | /* |
913 | | * Add a \n, which means that in order to write() the |
914 | | * buffer AND the trailing \n, we have to place both |
915 | | * strings into the same buffer. |
916 | | */ |
917 | 0 | memcpy(buffer, line, len); |
918 | 0 | buffer[len] = '\n'; |
919 | |
|
920 | 0 | fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); |
921 | 0 | if (fd < 0) { |
922 | 0 | DEBUG("Failed to open file %s: %s", filename, strerror(errno)); |
923 | 0 | return; |
924 | 0 | } |
925 | | |
926 | | /* |
927 | | * This should work in most situations. |
928 | | */ |
929 | 0 | if (write(fd, buffer, len + 1) < 0) { |
930 | 0 | DEBUG("Failed to write to file %s: %s", filename, strerror(errno)); |
931 | 0 | } |
932 | |
|
933 | 0 | close(fd); |
934 | 0 | } |
935 | | |
936 | | /** Decrypt application data |
937 | | * |
938 | | * @note Handshake must have completed before this function may be called. |
939 | | * |
940 | | * Feed data from dirty_in to OpenSSL, and read the clean data into clean_out. |
941 | | * |
942 | | * @param[in] request The current #request_t. |
943 | | * @param[in] tls_session The current TLS session. |
944 | | * @return |
945 | | * - -1 on error. |
946 | | * - 1 if more fragments are required to fully reassemble the record for decryption. |
947 | | * - 0 if we decrypted a complete record. |
948 | | */ |
949 | | int fr_tls_session_recv(request_t *request, fr_tls_session_t *tls_session) |
950 | 0 | { |
951 | 0 | int ret; |
952 | |
|
953 | 0 | fr_tls_session_request_bind(tls_session->ssl, request); |
954 | |
|
955 | 0 | if (!SSL_is_init_finished(tls_session->ssl)) { |
956 | 0 | REDEBUG("Attempted to read application data before handshake completed"); |
957 | 0 | error: |
958 | 0 | ret = -1; |
959 | 0 | goto finish; |
960 | 0 | } |
961 | | |
962 | | /* |
963 | | * Decrypt the complete record. |
964 | | */ |
965 | 0 | if (tls_session->dirty_in.used) { |
966 | 0 | ret = BIO_write(tls_session->into_ssl, tls_session->dirty_in.data, tls_session->dirty_in.used); |
967 | 0 | if (ret != (int) tls_session->dirty_in.used) { |
968 | 0 | REDEBUG("Failed writing %zu bytes to SSL BIO: %d", tls_session->dirty_in.used, ret); |
969 | 0 | record_init(&tls_session->dirty_in); |
970 | 0 | goto error; |
971 | 0 | } |
972 | | |
973 | 0 | record_init(&tls_session->dirty_in); |
974 | 0 | } |
975 | | |
976 | | /* |
977 | | * Clear the dirty buffer now that we are done with it |
978 | | * and init the clean_out buffer to store decrypted data |
979 | | */ |
980 | 0 | record_init(&tls_session->clean_out); |
981 | | |
982 | | /* |
983 | | * Prevent spurious errors on the thread local error |
984 | | * stack causing SSL_get_error() to return SSL_ERROR_SSL |
985 | | * instead of what of the SSL_ERROR_WANT_* values. |
986 | | */ |
987 | 0 | ERR_clear_error(); |
988 | | |
989 | | /* |
990 | | * Read (and decrypt) the tunneled data from the |
991 | | * SSL session, and put it into the decrypted |
992 | | * data buffer. |
993 | | */ |
994 | 0 | ret = SSL_read(tls_session->ssl, tls_session->clean_out.data, sizeof(tls_session->clean_out.data)); |
995 | 0 | if (ret < 0) { |
996 | 0 | int code; |
997 | |
|
998 | 0 | code = SSL_get_error(tls_session->ssl, ret); |
999 | 0 | switch (code) { |
1000 | 0 | case SSL_ERROR_WANT_READ: |
1001 | 0 | RWDEBUG("Peer indicated record was complete, but OpenSSL returned SSL_WANT_READ. " |
1002 | 0 | "Attempting to continue"); |
1003 | 0 | ret = 1; |
1004 | 0 | goto finish; |
1005 | | |
1006 | 0 | case SSL_ERROR_WANT_WRITE: |
1007 | 0 | REDEBUG("Error in fragmentation logic: SSL_WANT_WRITE"); |
1008 | 0 | goto error; |
1009 | | |
1010 | 0 | case SSL_ERROR_NONE: |
1011 | 0 | RDEBUG2("No application data received. Assuming handshake is continuing..."); |
1012 | 0 | ret = 0; |
1013 | 0 | break; |
1014 | | |
1015 | 0 | default: |
1016 | 0 | REDEBUG("Error in fragmentation logic"); |
1017 | 0 | fr_tls_log_io_error(request, code, "SSL_read (%s)", __FUNCTION__); |
1018 | 0 | goto error; |
1019 | 0 | } |
1020 | 0 | } |
1021 | | |
1022 | | /* |
1023 | | * Passed all checks, successfully decrypted data |
1024 | | */ |
1025 | 0 | tls_session->clean_out.used = ret; |
1026 | 0 | ret = 0; |
1027 | |
|
1028 | 0 | if (RDEBUG_ENABLED3) { |
1029 | 0 | RHEXDUMP3(tls_session->clean_out.data, tls_session->clean_out.used, |
1030 | 0 | "Decrypted TLS application data (%zu bytes)", tls_session->clean_out.used); |
1031 | 0 | } else { |
1032 | 0 | RDEBUG2("Decrypted TLS application data (%zu bytes)", tls_session->clean_out.used); |
1033 | 0 | } |
1034 | 0 | finish: |
1035 | 0 | fr_tls_session_request_unbind(tls_session->ssl); |
1036 | |
|
1037 | 0 | return ret; |
1038 | 0 | } |
1039 | | |
1040 | | /** Encrypt application data |
1041 | | * |
1042 | | * @note Handshake must have completed before this function may be called. |
1043 | | * |
1044 | | * Take cleartext data from clean_in, and feed it to OpenSSL, reading |
1045 | | * the encrypted data into dirty_out. |
1046 | | * |
1047 | | * @param[in] request The current request. |
1048 | | * @param[in] tls_session The current TLS session. |
1049 | | * @return |
1050 | | * - -1 on failure. |
1051 | | * - 0 on success. |
1052 | | */ |
1053 | | int fr_tls_session_send(request_t *request, fr_tls_session_t *tls_session) |
1054 | 0 | { |
1055 | 0 | int ret = 0; |
1056 | |
|
1057 | 0 | fr_tls_session_request_bind(tls_session->ssl, request); |
1058 | |
|
1059 | 0 | if (!SSL_is_init_finished(tls_session->ssl)) { |
1060 | 0 | REDEBUG("Attempted to write application data before handshake completed"); |
1061 | 0 | ret = -1; |
1062 | 0 | goto finish; |
1063 | 0 | } |
1064 | | |
1065 | | /* |
1066 | | * If there's un-encrypted data in 'clean_in', then write |
1067 | | * that data to the SSL session, and then call the BIO function |
1068 | | * to get that encrypted data from the SSL session, into |
1069 | | * a buffer which we can then package into an EAP packet. |
1070 | | * |
1071 | | * Based on Server's logic this clean_in is expected to |
1072 | | * contain the data to send to the client. |
1073 | | */ |
1074 | 0 | if (tls_session->clean_in.used > 0) { |
1075 | | /* |
1076 | | * Ensure spurious errors aren't printed |
1077 | | */ |
1078 | 0 | ERR_clear_error(); |
1079 | |
|
1080 | 0 | if (RDEBUG_ENABLED3) { |
1081 | 0 | RHEXDUMP3(tls_session->clean_in.data, tls_session->clean_in.used, |
1082 | 0 | "TLS application data to encrypt (%zu bytes)", tls_session->clean_in.used); |
1083 | 0 | } else { |
1084 | 0 | RDEBUG2("TLS application data to encrypt (%zu bytes)", tls_session->clean_in.used); |
1085 | 0 | } |
1086 | |
|
1087 | 0 | ret = SSL_write(tls_session->ssl, tls_session->clean_in.data, tls_session->clean_in.used); |
1088 | 0 | if (ret < 0) goto log_io_error; |
1089 | 0 | record_to_buff(&tls_session->clean_in, NULL, ret); |
1090 | | |
1091 | | /* Get the dirty data from Bio to send it */ |
1092 | 0 | ret = BIO_read(tls_session->from_ssl, tls_session->dirty_out.data, |
1093 | 0 | sizeof(tls_session->dirty_out.data)); |
1094 | 0 | if (ret < 0) { |
1095 | 0 | log_io_error: |
1096 | 0 | ret = fr_tls_log_io_error(request, SSL_get_error(tls_session->ssl, ret), |
1097 | 0 | "SSL_write (%s)", __FUNCTION__); |
1098 | | /* |
1099 | | * ret<0 means that we have a real error. |
1100 | | * |
1101 | | * ret=0 means the "error" is SSL_WANT_READ, SSL_WANT_WRITE, etc. |
1102 | | */ |
1103 | 0 | } else { |
1104 | 0 | tls_session->dirty_out.used = ret; |
1105 | 0 | ret = 0; |
1106 | 0 | } |
1107 | 0 | } |
1108 | | |
1109 | 0 | finish: |
1110 | 0 | fr_tls_session_request_unbind(tls_session->ssl); |
1111 | |
|
1112 | 0 | return ret; |
1113 | 0 | } |
1114 | | |
1115 | | /** Instruct fr_tls_session_async_handshake to create a synthesised TLS alert record and send it to the peer |
1116 | | * |
1117 | | */ |
1118 | | int fr_tls_session_alert(UNUSED request_t *request, fr_tls_session_t *session, uint8_t level, uint8_t description) |
1119 | 0 | { |
1120 | 0 | if (session->alerts_sent > 3) return -1; /* Some kind of state machine brokenness */ |
1121 | | |
1122 | | /* |
1123 | | * Ignore less severe alerts |
1124 | | */ |
1125 | 0 | if (session->pending_alert && (level < session->pending_alert_level)) return 0; |
1126 | | |
1127 | 0 | session->pending_alert = true; |
1128 | 0 | session->pending_alert_level = level; |
1129 | 0 | session->pending_alert_description = description; |
1130 | |
|
1131 | 0 | return 0; |
1132 | 0 | } |
1133 | | |
1134 | | static void fr_tls_session_alert_send(request_t *request, fr_tls_session_t *session) |
1135 | 0 | { |
1136 | | /* |
1137 | | * Update our internal view of the session |
1138 | | */ |
1139 | 0 | session->info.origin = TLS_INFO_ORIGIN_RECORD_SENT; |
1140 | 0 | session->info.content_type = SSL3_RT_ALERT; |
1141 | 0 | session->info.alert_level = session->pending_alert_level; |
1142 | 0 | session->info.alert_description = session->pending_alert_description; |
1143 | |
|
1144 | 0 | session->dirty_out.data[0] = session->info.content_type; |
1145 | 0 | session->dirty_out.data[1] = 3; |
1146 | 0 | session->dirty_out.data[2] = 1; |
1147 | 0 | session->dirty_out.data[3] = 0; |
1148 | 0 | session->dirty_out.data[4] = 2; |
1149 | 0 | session->dirty_out.data[5] = session->pending_alert_level; |
1150 | 0 | session->dirty_out.data[6] = session->pending_alert_description; |
1151 | |
|
1152 | 0 | session->dirty_out.used = 7; |
1153 | |
|
1154 | 0 | session->pending_alert = false; |
1155 | 0 | session->alerts_sent++; |
1156 | |
|
1157 | 0 | SSL_clear(session->ssl); /* Reset the SSL *, to allow the client to restart the session */ |
1158 | |
|
1159 | 0 | session_msg_log(request, session, session->dirty_out.data, session->dirty_out.used); |
1160 | 0 | } |
1161 | | |
1162 | | /** Process the result of `establish session { ... }` |
1163 | | * |
1164 | | * As this is just a logging session, it's result doesn't affect the parent. |
1165 | | */ |
1166 | | static unlang_action_t tls_establish_session_result(UNUSED request_t *request, UNUSED void *uctx) |
1167 | 0 | { |
1168 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
1169 | 0 | } |
1170 | | |
1171 | | /** Push an `establish session { ... }` call into the current request, using a subrequest |
1172 | | * |
1173 | | * @param[in] request The current request. |
1174 | | * @param[in] conf TLS configuration. |
1175 | | * @param[in] tls_session The current TLS session. |
1176 | | * @return |
1177 | | * - UNLANG_ACTION_PUSHED_CHILD on success. |
1178 | | * - UNLANG_ACTION_FAIL on failure. |
1179 | | */ |
1180 | | static inline CC_HINT(always_inline) |
1181 | | unlang_action_t tls_establish_session_push(request_t *request, fr_tls_conf_t *conf, fr_tls_session_t *tls_session) |
1182 | 0 | { |
1183 | 0 | request_t *child; |
1184 | 0 | fr_pair_t *vp; |
1185 | 0 | unlang_action_t ua; |
1186 | 0 | uint8_t const *session_id; |
1187 | 0 | unsigned int len; |
1188 | |
|
1189 | 0 | MEM(child = unlang_subrequest_alloc(request, dict_tls)); |
1190 | 0 | request = child; |
1191 | | |
1192 | | /* |
1193 | | * Setup the child request for reporting session |
1194 | | */ |
1195 | 0 | MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0); |
1196 | 0 | vp->vp_uint32 = enum_tls_packet_type_establish_session->vb_uint32; |
1197 | |
|
1198 | 0 | session_id = SSL_SESSION_get_id(tls_session->session, &len); |
1199 | 0 | if (session_id && (len > 0)) { |
1200 | 0 | MEM(pair_append_request(&vp, attr_tls_session_id) >= 0); |
1201 | 0 | fr_pair_value_memdup(vp, session_id, len, false); |
1202 | 0 | } |
1203 | | |
1204 | | /* |
1205 | | * Allocate a child, and set it up to call |
1206 | | * the TLS virtual server. |
1207 | | */ |
1208 | 0 | ua = fr_tls_call_push(child, tls_establish_session_result, conf, tls_session, false); |
1209 | 0 | if (ua < 0) { |
1210 | 0 | talloc_free(child); |
1211 | 0 | return UNLANG_ACTION_FAIL; |
1212 | 0 | } |
1213 | | |
1214 | 0 | return ua; |
1215 | 0 | } |
1216 | | |
1217 | | /** Finish off a handshake round, possibly adding attributes to the request |
1218 | | * |
1219 | | */ |
1220 | | static unlang_action_t tls_session_async_handshake_done_round(request_t *request, void *uctx) |
1221 | 0 | { |
1222 | 0 | fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t); |
1223 | 0 | int ret; |
1224 | |
|
1225 | 0 | RDEBUG3("entered state %s", __FUNCTION__); |
1226 | | |
1227 | | /* |
1228 | | * This only occurs once per session, where calling |
1229 | | * SSL_read updates the state of the SSL session, setting |
1230 | | * this flag to true. |
1231 | | * |
1232 | | * Callbacks provide enough info so we don't need to |
1233 | | * print debug statements when the handshake is in other |
1234 | | * states. |
1235 | | */ |
1236 | 0 | if (SSL_is_init_finished(tls_session->ssl)) { |
1237 | 0 | SSL_CIPHER const *cipher; |
1238 | 0 | fr_pair_t *vp; |
1239 | 0 | char const *version; |
1240 | |
|
1241 | 0 | char cipher_desc[256], cipher_desc_clean[256]; |
1242 | 0 | char *p = cipher_desc, *q = cipher_desc_clean; |
1243 | |
|
1244 | 0 | cipher = SSL_get_current_cipher(tls_session->ssl); |
1245 | 0 | SSL_CIPHER_description(cipher, cipher_desc, sizeof(cipher_desc)); |
1246 | | |
1247 | | /* |
1248 | | * Cleanup the output from OpenSSL |
1249 | | * Seems to print info in a tabular format. |
1250 | | */ |
1251 | 0 | while (*p != '\0') { |
1252 | 0 | if (isspace((uint8_t) *p)) { |
1253 | 0 | *q++ = *p; |
1254 | 0 | fr_skip_whitespace(p); |
1255 | 0 | continue; |
1256 | 0 | } |
1257 | 0 | *q++ = *p++; |
1258 | 0 | } |
1259 | 0 | *q = '\0'; |
1260 | |
|
1261 | 0 | RDEBUG2("Cipher suite: %s", cipher_desc_clean); |
1262 | |
|
1263 | 0 | RDEBUG2("Adding TLS session information to request"); |
1264 | 0 | RINDENT(); |
1265 | 0 | MEM(pair_update_session_state(&vp, attr_tls_session_cipher_suite) >= 0); |
1266 | 0 | fr_pair_value_strdup(vp, SSL_CIPHER_get_name(cipher), false); |
1267 | 0 | RDEBUG2("session-state.%pP", vp); |
1268 | |
|
1269 | 0 | if (((size_t)tls_session->info.version >= NUM_ELEMENTS(tls_version_str)) || |
1270 | 0 | !tls_version_str[tls_session->info.version]) { |
1271 | 0 | version = "UNKNOWN"; |
1272 | 0 | } else { |
1273 | 0 | version = tls_version_str[tls_session->info.version]; |
1274 | 0 | } |
1275 | |
|
1276 | 0 | MEM(pair_update_session_state(&vp, attr_tls_session_version) >= 0); |
1277 | 0 | fr_pair_value_strdup(vp, version, false); |
1278 | 0 | RDEBUG2("session-state.%pP", vp); |
1279 | 0 | REXDENT(); |
1280 | | |
1281 | | /* |
1282 | | * Cache the SSL_SESSION pointer. |
1283 | | * |
1284 | | * Which contains all the data we need for session resumption. |
1285 | | */ |
1286 | 0 | if (!tls_session->session) { |
1287 | 0 | tls_session->session = SSL_get_session(tls_session->ssl); |
1288 | 0 | if (!tls_session->session) { |
1289 | 0 | REDEBUG("Failed getting TLS session"); |
1290 | 0 | error: |
1291 | 0 | tls_session->result = FR_TLS_RESULT_ERROR; |
1292 | 0 | fr_tls_session_request_unbind(tls_session->ssl); |
1293 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
1294 | 0 | } |
1295 | 0 | } |
1296 | | |
1297 | 0 | if (RDEBUG_ENABLED3) { |
1298 | 0 | if (SSL_SESSION_print(fr_tls_request_log_bio(request, L_DBG, L_DBG_LVL_3), |
1299 | 0 | tls_session->session) != 1) { |
1300 | 0 | RDEBUG3("Failed retrieving session data"); |
1301 | 0 | } |
1302 | 0 | } |
1303 | | |
1304 | | /* |
1305 | | * Session was resumed, add attribute to mark it as such. |
1306 | | */ |
1307 | 0 | if (SSL_session_reused(tls_session->ssl)) { |
1308 | | /* |
1309 | | * Mark the request as resumed. |
1310 | | */ |
1311 | 0 | MEM(pair_update_request(&vp, attr_session_resumed) >= 0); |
1312 | 0 | vp->vp_bool = true; |
1313 | 0 | } |
1314 | 0 | } |
1315 | | |
1316 | | /* |
1317 | | * Get data to pack and send back to the TLS peer. |
1318 | | */ |
1319 | 0 | ret = BIO_ctrl_pending(tls_session->from_ssl); |
1320 | 0 | if (ret > 0) { |
1321 | 0 | ret = BIO_read(tls_session->from_ssl, tls_session->dirty_out.data, |
1322 | 0 | sizeof(tls_session->dirty_out.data)); |
1323 | 0 | if (ret > 0) { |
1324 | 0 | tls_session->dirty_out.used = ret; |
1325 | 0 | } else if (BIO_should_retry(tls_session->from_ssl)) { |
1326 | 0 | record_init(&tls_session->dirty_in); |
1327 | 0 | RDEBUG2("Asking for more data in tunnel"); |
1328 | |
|
1329 | 0 | } else { |
1330 | 0 | fr_tls_log(NULL, NULL); |
1331 | 0 | record_init(&tls_session->dirty_in); |
1332 | 0 | goto error; |
1333 | 0 | } |
1334 | 0 | } else { |
1335 | | /* Its clean application data, do whatever we want */ |
1336 | 0 | record_init(&tls_session->clean_out); |
1337 | 0 | } |
1338 | | |
1339 | | /* |
1340 | | * Trash the current data in dirty_out, and synthesize |
1341 | | * a TLS error record. |
1342 | | * |
1343 | | * OpensSL annoyingly provides no mechanism for us to |
1344 | | * send alerts, and we need to send alerts as part of |
1345 | | * RFC 5216, so this is our only option. |
1346 | | */ |
1347 | 0 | if (tls_session->pending_alert) fr_tls_session_alert_send(request, tls_session); |
1348 | | |
1349 | | /* We are done with dirty_in, reinitialize it */ |
1350 | 0 | record_init(&tls_session->dirty_in); |
1351 | |
|
1352 | 0 | tls_session->result = FR_TLS_RESULT_SUCCESS; |
1353 | 0 | fr_tls_session_request_unbind(tls_session->ssl); |
1354 | 0 | if (SSL_is_init_finished(tls_session->ssl)) { |
1355 | 0 | fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl); |
1356 | 0 | if (conf->establish_session) return tls_establish_session_push(request, conf, tls_session); |
1357 | 0 | } |
1358 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
1359 | 0 | } |
1360 | | |
1361 | | /** Try very hard to get the SSL * into a consistent state where it's not yielded |
1362 | | * |
1363 | | * ...because if it's yielded, we'll probably leak thread contexts and all kinds of memory. |
1364 | | * |
1365 | | * @param[in] request being cancelled. |
1366 | | * @param[in] action we're being signalled with. |
1367 | | * @param[in] uctx the SSL * to cancel. |
1368 | | */ |
1369 | | static void tls_session_async_handshake_signal(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx) |
1370 | 0 | { |
1371 | 0 | fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t); |
1372 | 0 | int ret; |
1373 | | |
1374 | | /* |
1375 | | * We might want to set can_pause = false here |
1376 | | * but that would trigger asserts in the |
1377 | | * cache code. |
1378 | | */ |
1379 | | |
1380 | | /* |
1381 | | * If SSL_get_error returns SSL_ERROR_WANT_ASYNC |
1382 | | * it means we're yielded in the middle of a |
1383 | | * callback. |
1384 | | * |
1385 | | * Keep calling SSL_read() in a loop until we |
1386 | | * no longer get SSL_ERROR_WANT_ASYNC, then |
1387 | | * shut it down so it's in a consistent state. |
1388 | | * |
1389 | | * It'll get freed later when the request is |
1390 | | * freed. |
1391 | | */ |
1392 | 0 | for (ret = tls_session->last_ret; |
1393 | 0 | SSL_get_error(tls_session->ssl, ret) == SSL_ERROR_WANT_ASYNC; |
1394 | 0 | ret = SSL_read(tls_session->ssl, tls_session->clean_out.data + tls_session->clean_out.used, |
1395 | 0 | sizeof(tls_session->clean_out.data) - tls_session->clean_out.used)); |
1396 | | |
1397 | | /* |
1398 | | * Unbind the cancelled request from the SSL * |
1399 | | */ |
1400 | 0 | fr_tls_session_request_unbind(tls_session->ssl); |
1401 | 0 | } |
1402 | | |
1403 | | /** Call SSL_read() to continue the TLS state machine |
1404 | | * |
1405 | | * This function may be called multiple times, once after every asynchronous request. |
1406 | | * |
1407 | | * @param[in] request The current request. |
1408 | | * @param[in] uctx #fr_tls_session_t to continue. |
1409 | | * @return |
1410 | | * - UNLANG_ACTION_CALCULATE_RESULT - We're done with this round. |
1411 | | * - UNLANG_ACTION_PUSHED_CHILD - Need to perform more asynchronous actions. |
1412 | | */ |
1413 | | static unlang_action_t tls_session_async_handshake_cont(request_t *request, void *uctx) |
1414 | 0 | { |
1415 | 0 | fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t); |
1416 | 0 | int err; |
1417 | |
|
1418 | 0 | RDEBUG3("(re-)entered state %s", __FUNCTION__); |
1419 | | |
1420 | | /* |
1421 | | * Clear OpenSSL's thread local error stack. |
1422 | | * |
1423 | | * Why do we need to do this here? Although SSL_get_error |
1424 | | * takes an `SSL *`, which would make you _think_ it was |
1425 | | * operating on the error stack for that SSL, it will also |
1426 | | * return SSL_ERROR_SSL if there are any errors in the stack. |
1427 | | * |
1428 | | * When operating normally SSL_read() can return < 0, to |
1429 | | * indicate it wants more data, or that we need to perform |
1430 | | * asynchronous processing. |
1431 | | * |
1432 | | * If spurious errors have been left on the thread local |
1433 | | * stack they MUST be cleared before we can call SSL_get_error |
1434 | | * otherwise stale errors mask the async notifications |
1435 | | * and cause random handshake failures. |
1436 | | */ |
1437 | 0 | ERR_clear_error(); |
1438 | | |
1439 | | /* |
1440 | | * Magic/More magic? Although SSL_read is normally |
1441 | | * used to read application data, it will also |
1442 | | * continue the TLS handshake. Removing this call will |
1443 | | * cause the handshake to fail. |
1444 | | * |
1445 | | * We don't ever expect to actually *receive* application |
1446 | | * data here. |
1447 | | * |
1448 | | * The reason why we call SSL_read instead of SSL_accept, |
1449 | | * or SSL_connect, as it allows this function |
1450 | | * to be used, irrespective or whether we're acting |
1451 | | * as a client or a server. |
1452 | | * |
1453 | | * If acting as a client SSL_set_connect_state must have |
1454 | | * been called before this function. |
1455 | | * |
1456 | | * If acting as a server SSL_set_accept_state must have |
1457 | | * been called before this function. |
1458 | | */ |
1459 | 0 | tls_session->can_pause = true; |
1460 | 0 | tls_session->last_ret = SSL_read(tls_session->ssl, tls_session->clean_out.data + tls_session->clean_out.used, |
1461 | 0 | sizeof(tls_session->clean_out.data) - tls_session->clean_out.used); |
1462 | 0 | tls_session->can_pause = false; |
1463 | 0 | if (tls_session->last_ret > 0) { |
1464 | 0 | tls_session->clean_out.used += tls_session->last_ret; |
1465 | | |
1466 | | /* |
1467 | | * Round successful, and we don't need to do any |
1468 | | * further processing. |
1469 | | */ |
1470 | 0 | tls_session->result = FR_TLS_RESULT_SUCCESS; |
1471 | 0 | finish: |
1472 | | /* |
1473 | | * Was bound by caller |
1474 | | */ |
1475 | 0 | fr_tls_session_request_unbind(tls_session->ssl); |
1476 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
1477 | 0 | } |
1478 | | |
1479 | | /* |
1480 | | * Bug in OpenSSL 3.0 - Normal handshaking behaviour |
1481 | | * results in spurious "BIO_R_UNSUPPORTED_METHOD" |
1482 | | * errors. |
1483 | | * |
1484 | | * SSL_get_error apparently returns SSL_ERROR_SSL if |
1485 | | * there are any errors in the stack. This masks |
1486 | | * SSL_ERROR_WANT_ASYNC and causes the handshake to |
1487 | | * fail. |
1488 | | * |
1489 | | * Note: We may want some version of this code |
1490 | | * included for all OpenSSL versions. |
1491 | | * |
1492 | | * It would call ERR_GET_FATAL() on each of the errors |
1493 | | * in the stack to drain non-fatal errors and prevent |
1494 | | * the other (more useful) return codes of |
1495 | | * SSL_get_error from being masked. I guess we'll see |
1496 | | * if this occurs in other scenarios. |
1497 | | */ |
1498 | 0 | if (SSL_get_error(tls_session->ssl, tls_session->last_ret) == SSL_ERROR_SSL) { |
1499 | 0 | unsigned long ssl_err; |
1500 | | |
1501 | | /* |
1502 | | * Some weird OpenSSL thing marking ERR_GET_REASON |
1503 | | * as "unused". Unclear why this is done as it's |
1504 | | * not deprecated. |
1505 | | */ |
1506 | 0 | DIAG_OFF(DIAG_UNKNOWN_PRAGMAS) |
1507 | 0 | DIAG_OFF(used-but-marked-unused) |
1508 | 0 | while ((ssl_err = ERR_peek_error()) && (ERR_GET_REASON(ssl_err) == BIO_R_UNSUPPORTED_METHOD)) { |
1509 | 0 | (void) ERR_get_error(); |
1510 | 0 | } |
1511 | 0 | DIAG_ON(used-but-marked-unused) |
1512 | 0 | DIAG_ON(DIAG_UNKNOWN_PRAGMAS) |
1513 | 0 | } |
1514 | | |
1515 | | /* |
1516 | | * Deal with asynchronous requests from OpenSSL. |
1517 | | * These aren't actually errors, they're the |
1518 | | * result of one of our callbacks indicating that |
1519 | | * it'd like to perform the operation |
1520 | | * asynchronously. |
1521 | | */ |
1522 | 0 | switch (err = SSL_get_error(tls_session->ssl, tls_session->last_ret)) { |
1523 | 0 | case SSL_ERROR_WANT_ASYNC: /* Certification validation or cache loads */ |
1524 | 0 | { |
1525 | 0 | unlang_action_t ua; |
1526 | |
|
1527 | 0 | RDEBUG3("Performing async action for libssl"); |
1528 | | |
1529 | | /* |
1530 | | * Call this function again once we're done |
1531 | | * asynchronously satisfying the load request. |
1532 | | */ |
1533 | 0 | if (unlikely(unlang_function_repeat_set(request, tls_session_async_handshake_cont) < 0)) { |
1534 | 0 | error: |
1535 | 0 | tls_session->result = FR_TLS_RESULT_ERROR; |
1536 | 0 | goto finish; |
1537 | 0 | } |
1538 | | |
1539 | | /* |
1540 | | * First service any pending cache actions |
1541 | | */ |
1542 | 0 | ua = fr_tls_cache_pending_push(request, tls_session); |
1543 | 0 | switch (ua) { |
1544 | 0 | case UNLANG_ACTION_FAIL: |
1545 | 0 | IGNORE(unlang_function_clear(request), int); |
1546 | 0 | goto error; |
1547 | | |
1548 | 0 | case UNLANG_ACTION_PUSHED_CHILD: |
1549 | 0 | return ua; |
1550 | | |
1551 | 0 | default: |
1552 | 0 | break; |
1553 | 0 | } |
1554 | | |
1555 | | /* |
1556 | | * Next service any pending certificate |
1557 | | * validation actions. |
1558 | | */ |
1559 | 0 | ua = fr_tls_verify_cert_pending_push(request, tls_session); |
1560 | 0 | switch (ua) { |
1561 | 0 | case UNLANG_ACTION_FAIL: |
1562 | 0 | IGNORE(unlang_function_clear(request), int); |
1563 | 0 | goto error; |
1564 | | |
1565 | 0 | default: |
1566 | 0 | return ua; |
1567 | 0 | } |
1568 | 0 | } |
1569 | | |
1570 | 0 | case SSL_ERROR_WANT_ASYNC_JOB: |
1571 | 0 | RERROR("No async jobs available in pool, increase thread.openssl_async_pool_max"); |
1572 | 0 | goto error; |
1573 | | |
1574 | 0 | default: |
1575 | | /* |
1576 | | * Returns 0 if we can continue processing the handshake |
1577 | | * Returns -1 if we encountered a fatal error. |
1578 | | */ |
1579 | 0 | if (fr_tls_log_io_error(request, |
1580 | 0 | err, "SSL_read (%s)", __FUNCTION__) < 0) goto error; |
1581 | 0 | return tls_session_async_handshake_done_round(request, uctx); |
1582 | 0 | } |
1583 | 0 | } |
1584 | | |
1585 | | /** Ingest data for another handshake round |
1586 | | * |
1587 | | * Advance the TLS handshake by feeding OpenSSL data from dirty_in, |
1588 | | * and reading data from OpenSSL into dirty_out. |
1589 | | * |
1590 | | * Calls #tls_session_async_handshake_read to perform the actual ingestion. |
1591 | | * #tls_session_async_handshake_read is split out because we may need to call |
1592 | | * it multiple times, once after every async action. |
1593 | | * |
1594 | | * @param[in] request The current request. |
1595 | | * @param[in] uctx #fr_tls_session_t to continue. |
1596 | | * @return |
1597 | | * - UNLANG_ACTION_CALCULATE_RESULT - We're done with this round. |
1598 | | * - UNLANG_ACTION_PUSHED_CHILD - Need to perform more asynchronous actions. |
1599 | | */ |
1600 | | static unlang_action_t tls_session_async_handshake(request_t *request, void *uctx) |
1601 | 0 | { |
1602 | 0 | fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t); |
1603 | 0 | int ret; |
1604 | |
|
1605 | 0 | RDEBUG3("entered state %s", __FUNCTION__); |
1606 | |
|
1607 | 0 | tls_session->result = FR_TLS_RESULT_IN_PROGRESS; |
1608 | |
|
1609 | 0 | fr_tls_session_request_bind(tls_session->ssl, request); /* May be unbound in this function or asynchronously */ |
1610 | | |
1611 | | /* |
1612 | | * This is a logic error. fr_tls_session_async_handshake |
1613 | | * must not be called if the handshake is |
1614 | | * complete fr_tls_session_recv must be |
1615 | | * called instead. |
1616 | | */ |
1617 | 0 | if (SSL_is_init_finished(tls_session->ssl)) { |
1618 | 0 | REDEBUG("Attempted to continue TLS handshake, but handshake has completed"); |
1619 | 0 | error: |
1620 | 0 | tls_session->result = FR_TLS_RESULT_ERROR; |
1621 | 0 | fr_tls_session_request_unbind(tls_session->ssl); /* Was bound in this function */ |
1622 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
1623 | 0 | } |
1624 | | |
1625 | 0 | if (tls_session->invalid) { |
1626 | 0 | REDEBUG("Preventing invalid session from continuing"); |
1627 | 0 | goto error; |
1628 | 0 | } |
1629 | | |
1630 | | /* |
1631 | | * Feed dirty data into OpenSSL, so that is can either |
1632 | | * process it as Application data (decrypting it) |
1633 | | * or continue the TLS handshake. |
1634 | | */ |
1635 | 0 | if (tls_session->dirty_in.used) { |
1636 | 0 | ret = BIO_write(tls_session->into_ssl, tls_session->dirty_in.data, tls_session->dirty_in.used); |
1637 | 0 | if (ret != (int)tls_session->dirty_in.used) { |
1638 | 0 | REDEBUG("Failed writing %zu bytes to TLS BIO: %d", tls_session->dirty_in.used, ret); |
1639 | 0 | record_init(&tls_session->dirty_in); |
1640 | 0 | goto error; |
1641 | 0 | } |
1642 | 0 | record_init(&tls_session->dirty_in); |
1643 | 0 | } |
1644 | | |
1645 | 0 | return tls_session_async_handshake_cont(request, uctx); /* Must unbind request, possibly asynchronously */ |
1646 | 0 | } |
1647 | | |
1648 | | /** Push a handshake call onto the stack |
1649 | | * |
1650 | | * We push the handshake frame (as opposed to having the caller do it), |
1651 | | * so that we guarantee there's a frame that the handshake function can |
1652 | | * manipulate to manage its own state. |
1653 | | * |
1654 | | * The result of processing this handshake round can be found in |
1655 | | * tls_session->result. |
1656 | | * |
1657 | | * @param[in] request The current request. |
1658 | | * @param[in] tls_session to continue handshaking. |
1659 | | * @return |
1660 | | * - UNLANG_ACTION_PUSHED_CHILD on success. |
1661 | | * - UNLANG_ACTION_FAIL on failure. |
1662 | | */ |
1663 | | unlang_action_t fr_tls_session_async_handshake_push(request_t *request, fr_tls_session_t *tls_session) |
1664 | 0 | { |
1665 | 0 | return unlang_function_push(request, |
1666 | 0 | tls_session_async_handshake, |
1667 | 0 | NULL, |
1668 | 0 | tls_session_async_handshake_signal, |
1669 | 0 | ~FR_SIGNAL_CANCEL, |
1670 | 0 | UNLANG_SUB_FRAME, |
1671 | 0 | tls_session); |
1672 | 0 | } |
1673 | | |
1674 | | /** Free a TLS session and any associated OpenSSL data |
1675 | | * |
1676 | | * @param session to free. |
1677 | | * @return 0. |
1678 | | */ |
1679 | | static int _fr_tls_session_free(fr_tls_session_t *session) |
1680 | 0 | { |
1681 | 0 | if (session->ssl) { |
1682 | | /* |
1683 | | * The OpenSSL docs state: |
1684 | | * |
1685 | | * SSL_shutdown() can be modified to only set the |
1686 | | * connection to "shutdown" state but not actually |
1687 | | * send the "close notify" alert messages, see |
1688 | | * SSL_CTX_set_quiet_shutdown(3). When "quiet shutdown" |
1689 | | * is enabled, SSL_shutdown() will always succeed and |
1690 | | * return 1. |
1691 | | * |
1692 | | * This is only partially correct. This call does mean |
1693 | | * we don't notify the other party, but the SSL_shutdown |
1694 | | * call can still fail if the handshake hasn't begun, leaving |
1695 | | * spurious errors on the thread local error stack. |
1696 | | */ |
1697 | 0 | SSL_set_quiet_shutdown(session->ssl, 1); |
1698 | | |
1699 | | /* |
1700 | | * Don't leave spurious errors raised by SSL_shutdown on |
1701 | | * the error stack. |
1702 | | */ |
1703 | 0 | if (SSL_shutdown(session->ssl) != 1) ERR_clear_error(); |
1704 | |
|
1705 | 0 | SSL_free(session->ssl); |
1706 | 0 | session->ssl = NULL; |
1707 | 0 | } |
1708 | |
|
1709 | 0 | return 0; |
1710 | 0 | } |
1711 | | |
1712 | | static void session_init(fr_tls_session_t *session) |
1713 | 0 | { |
1714 | 0 | session->ssl = NULL; |
1715 | 0 | session->into_ssl = session->from_ssl = NULL; |
1716 | 0 | record_init(&session->clean_in); |
1717 | 0 | record_init(&session->clean_out); |
1718 | 0 | record_init(&session->dirty_in); |
1719 | 0 | record_init(&session->dirty_out); |
1720 | |
|
1721 | 0 | memset(&session->info, 0, sizeof(session->info)); |
1722 | |
|
1723 | 0 | session->mtu = 0; |
1724 | 0 | session->opaque = NULL; |
1725 | 0 | } |
1726 | | |
1727 | | /** Create a new client TLS session |
1728 | | * |
1729 | | * Configures a new client TLS session, configuring options, setting callbacks etc... |
1730 | | * |
1731 | | * @param[in] ctx to alloc session data in. Should usually be NULL unless the lifetime of the |
1732 | | * session is tied to another talloc'd object. |
1733 | | * @param[in] ssl_ctx containing the base configuration for this session. |
1734 | | * @return |
1735 | | * - A new session on success. |
1736 | | * - NULL on error. |
1737 | | */ |
1738 | | fr_tls_session_t *fr_tls_session_alloc_client(TALLOC_CTX *ctx, SSL_CTX *ssl_ctx) |
1739 | 0 | { |
1740 | 0 | int verify_mode; |
1741 | 0 | fr_tls_session_t *tls_session = NULL; |
1742 | 0 | fr_tls_conf_t *conf = fr_tls_ctx_conf(ssl_ctx); |
1743 | |
|
1744 | 0 | MEM(tls_session = talloc_zero(ctx, fr_tls_session_t)); |
1745 | 0 | talloc_set_destructor(tls_session, _fr_tls_session_free); |
1746 | 0 | fr_pair_list_init(&tls_session->extra_pairs); |
1747 | |
|
1748 | 0 | tls_session->ssl = SSL_new(ssl_ctx); |
1749 | 0 | if (!tls_session->ssl) { |
1750 | 0 | talloc_free(tls_session); |
1751 | 0 | return NULL; |
1752 | 0 | } |
1753 | | |
1754 | | /* |
1755 | | * Add the message callback to identify what type of |
1756 | | * message/handshake is passed |
1757 | | */ |
1758 | 0 | SSL_set_msg_callback(tls_session->ssl, fr_tls_session_msg_cb); |
1759 | 0 | SSL_set_msg_callback_arg(tls_session->ssl, tls_session); |
1760 | 0 | SSL_set_info_callback(tls_session->ssl, fr_tls_session_info_cb); |
1761 | | |
1762 | | /* |
1763 | | * In Client mode we only accept. |
1764 | | * |
1765 | | * This sets up the SSL session to work correctly with |
1766 | | * fr_tls_session_handshake. |
1767 | | */ |
1768 | 0 | SSL_set_connect_state(tls_session->ssl); |
1769 | | |
1770 | | /* |
1771 | | * Always verify the peer certificate. |
1772 | | */ |
1773 | 0 | DEBUG2("Requiring Server certificate"); |
1774 | 0 | verify_mode = SSL_VERIFY_PEER; |
1775 | 0 | verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
1776 | | |
1777 | | /* |
1778 | | * Callback should be fr_tls_verify_cert_cb but this |
1779 | | * requires support around SSL_connect for dealing |
1780 | | * with async. |
1781 | | * |
1782 | | * If the callback is NULL OpenSSL uses its own validation |
1783 | | * function, and the flags modifies that function's |
1784 | | * behaviour. |
1785 | | */ |
1786 | 0 | SSL_set_verify(tls_session->ssl, verify_mode, NULL); |
1787 | 0 | SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf); |
1788 | 0 | SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)tls_session); |
1789 | |
|
1790 | 0 | tls_session->mtu = conf->fragment_size; |
1791 | |
|
1792 | 0 | return tls_session; |
1793 | 0 | } |
1794 | | |
1795 | | /** Create a new server TLS session |
1796 | | * |
1797 | | * Configures a new server TLS session, configuring options, setting callbacks etc... |
1798 | | * |
1799 | | * @param[in] ctx to alloc session data in. Should usually be NULL |
1800 | | * unless the lifetime of the session is tied to another |
1801 | | * talloc'd object. |
1802 | | * @param[in] ssl_ctx containing the base configuration for this session. |
1803 | | * @param[in] request The current #request_t. |
1804 | | * @param[in] dynamic_mtu If greater than 100, overrides the MTU configured for the SSL_CTX. |
1805 | | * @param[in] client_cert Whether to require a client_cert. |
1806 | | * @return |
1807 | | * - A new session on success. |
1808 | | * - NULL on error. |
1809 | | */ |
1810 | | fr_tls_session_t *fr_tls_session_alloc_server(TALLOC_CTX *ctx, SSL_CTX *ssl_ctx, request_t *request, size_t dynamic_mtu, bool client_cert) |
1811 | 0 | { |
1812 | 0 | fr_tls_session_t *tls_session = NULL; |
1813 | 0 | SSL *ssl = NULL; |
1814 | 0 | int verify_mode = 0; |
1815 | 0 | fr_pair_t *vp; |
1816 | 0 | fr_tls_conf_t *conf = fr_tls_ctx_conf(ssl_ctx); |
1817 | |
|
1818 | 0 | RDEBUG2("Initiating new TLS session"); |
1819 | |
|
1820 | 0 | MEM(tls_session = talloc_zero(ctx, fr_tls_session_t)); |
1821 | |
|
1822 | 0 | ssl = SSL_new(ssl_ctx); |
1823 | 0 | if (ssl == NULL) { |
1824 | 0 | talloc_free(tls_session); |
1825 | 0 | fr_tls_log(request, "Error creating new TLS session"); |
1826 | 0 | return NULL; |
1827 | 0 | } |
1828 | 0 | fr_pair_list_init(&tls_session->extra_pairs); |
1829 | |
|
1830 | 0 | session_init(tls_session); |
1831 | 0 | tls_session->ctx = ssl_ctx; |
1832 | 0 | tls_session->ssl = ssl; |
1833 | 0 | talloc_set_destructor(tls_session, _fr_tls_session_free); |
1834 | |
|
1835 | 0 | fr_tls_session_request_bind(tls_session->ssl, request); /* Is unbound in this function */ |
1836 | | |
1837 | | /* |
1838 | | * Initialize callbacks |
1839 | | */ |
1840 | 0 | tls_session->record_init = record_init; |
1841 | 0 | tls_session->record_close = record_close; |
1842 | 0 | tls_session->record_from_buff = record_from_buff; |
1843 | 0 | tls_session->record_to_buff = record_to_buff; |
1844 | | |
1845 | | /* |
1846 | | * Create & hook the BIOs to handle the dirty side of the |
1847 | | * SSL. This is *very important* as we want to handle |
1848 | | * the transmission part. Now the only IO interface |
1849 | | * that SSL is aware of, is our defined BIO buffers. |
1850 | | * |
1851 | | * This means that all SSL IO is done to/from memory, |
1852 | | * and we can update those BIOs from the packets we've |
1853 | | * received. |
1854 | | */ |
1855 | 0 | MEM(tls_session->into_ssl = BIO_new(BIO_s_mem())); |
1856 | 0 | MEM(tls_session->from_ssl = BIO_new(BIO_s_mem())); |
1857 | 0 | SSL_set_bio(tls_session->ssl, tls_session->into_ssl, tls_session->from_ssl); |
1858 | | |
1859 | | /* |
1860 | | * Add the message callback to identify what type of |
1861 | | * message/handshake is passed |
1862 | | */ |
1863 | 0 | SSL_set_msg_callback(ssl, fr_tls_session_msg_cb); |
1864 | 0 | SSL_set_msg_callback_arg(ssl, tls_session); |
1865 | 0 | SSL_set_info_callback(ssl, fr_tls_session_info_cb); |
1866 | | |
1867 | | /* |
1868 | | * This sets the context sessions can be resumed in. |
1869 | | * This is to prevent sessions being created by one application |
1870 | | * and used by another. In our case it prevents sessions being |
1871 | | * reused between modules, or TLS server components such as |
1872 | | * RADSEC. |
1873 | | * |
1874 | | * A context must always be set when doing session resumption |
1875 | | * otherwise session resumption will fail. |
1876 | | * |
1877 | | * As the context ID must be <= 32, we digest the context |
1878 | | * data with sha256. |
1879 | | * |
1880 | | * This seems to only be used for stateful session resumption |
1881 | | * not session-tickets |
1882 | | */ |
1883 | 0 | if (conf->cache.mode != FR_TLS_CACHE_DISABLED) { |
1884 | 0 | char *context_id; |
1885 | 0 | EVP_MD_CTX *md_ctx; |
1886 | 0 | uint8_t digest[SHA256_DIGEST_LENGTH]; |
1887 | |
|
1888 | 0 | static_assert(sizeof(digest) <= SSL_MAX_SSL_SESSION_ID_LENGTH, |
1889 | 0 | "SSL_MAX_SSL_SESSION_ID_LENGTH must be >= SHA256_DIGEST_LENGTH"); |
1890 | 0 | fr_assert(conf->cache.id_name); |
1891 | |
|
1892 | 0 | if (tmpl_aexpand(tls_session, &context_id, request, conf->cache.id_name, NULL, NULL) < 0) { |
1893 | 0 | RPEDEBUG("Failed expanding session ID"); |
1894 | 0 | error: |
1895 | 0 | fr_tls_session_request_unbind(tls_session->ssl); /* Was bound in this function */ |
1896 | 0 | talloc_free(tls_session); |
1897 | 0 | return NULL; |
1898 | 0 | } |
1899 | | |
1900 | 0 | MEM(md_ctx = EVP_MD_CTX_create()); |
1901 | 0 | EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL); |
1902 | 0 | EVP_DigestUpdate(md_ctx, context_id, talloc_strlen(context_id)); |
1903 | 0 | EVP_DigestFinal_ex(md_ctx, digest, NULL); |
1904 | 0 | EVP_MD_CTX_destroy(md_ctx); |
1905 | 0 | talloc_free(context_id); |
1906 | |
|
1907 | 0 | if (!fr_cond_assert(SSL_set_session_id_context(tls_session->ssl, |
1908 | 0 | digest, sizeof(digest)) == 1)) goto error; |
1909 | 0 | } |
1910 | | |
1911 | | /* |
1912 | | * Add the session certificate to the session. |
1913 | | */ |
1914 | 0 | vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_tls_session_cert_file); |
1915 | 0 | if (vp) { |
1916 | 0 | RDEBUG2("Loading TLS session certificate \"%pV\"", &vp->data); |
1917 | |
|
1918 | 0 | if (SSL_use_certificate_file(tls_session->ssl, vp->vp_strvalue, SSL_FILETYPE_PEM) != 1) { |
1919 | 0 | fr_tls_log(request, "Failed loading TLS session certificate \"%s\"", |
1920 | 0 | vp->vp_strvalue); |
1921 | 0 | goto error; |
1922 | 0 | } |
1923 | | |
1924 | 0 | if (SSL_use_PrivateKey_file(tls_session->ssl, vp->vp_strvalue, SSL_FILETYPE_PEM) != 1) { |
1925 | 0 | fr_tls_log(request, "Failed loading TLS session certificate \"%s\"", |
1926 | 0 | vp->vp_strvalue); |
1927 | 0 | goto error; |
1928 | 0 | } |
1929 | | |
1930 | 0 | if (SSL_check_private_key(tls_session->ssl) != 1) { |
1931 | 0 | fr_tls_log(request, "Failed validating TLS session certificate \"%s\"", |
1932 | 0 | vp->vp_strvalue); |
1933 | 0 | goto error; |
1934 | 0 | } |
1935 | | /* |
1936 | | * Better to perform explicit checks, than rely |
1937 | | * on OpenSSL's opaque error messages. |
1938 | | */ |
1939 | 0 | } else { |
1940 | 0 | if (!conf->chains || !conf->chains[0]->private_key_file) { |
1941 | 0 | ERROR("TLS Server requires a private key file"); |
1942 | 0 | goto error; |
1943 | 0 | } |
1944 | | |
1945 | 0 | if (!conf->chains || !conf->chains[0]->certificate_file) { |
1946 | 0 | ERROR("TLS Server requires a certificate file"); |
1947 | 0 | goto error; |
1948 | 0 | } |
1949 | 0 | } |
1950 | | |
1951 | | /** Dynamic toggle for allowing disallowing client certs |
1952 | | * |
1953 | | * This is mainly used for testing in environments where we can't |
1954 | | * get test credentials for the host. |
1955 | | */ |
1956 | 0 | vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_tls_session_require_client_cert); |
1957 | 0 | if (vp) client_cert = vp->vp_bool; |
1958 | | |
1959 | | /* |
1960 | | * In Server mode we only accept. |
1961 | | * |
1962 | | * This sets up the SSL session to work correctly with |
1963 | | * fr_tls_session_handshake. |
1964 | | */ |
1965 | 0 | SSL_set_accept_state(tls_session->ssl); |
1966 | | |
1967 | | /* |
1968 | | * Verify the peer certificate, if asked. |
1969 | | */ |
1970 | 0 | if (client_cert) { |
1971 | 0 | RDEBUG2("Setting verify mode to require certificate from client"); |
1972 | 0 | verify_mode = SSL_VERIFY_PEER; |
1973 | 0 | verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
1974 | 0 | verify_mode |= SSL_VERIFY_CLIENT_ONCE; |
1975 | 0 | } |
1976 | 0 | tls_session->verify_client_cert = client_cert; |
1977 | |
|
1978 | 0 | SSL_set_verify(tls_session->ssl, verify_mode, fr_tls_verify_cert_cb); |
1979 | 0 | SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf); |
1980 | 0 | SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)tls_session); |
1981 | |
|
1982 | 0 | if (conf->client_hello_parse) { |
1983 | 0 | SSL_CTX_set_client_hello_cb(ssl_ctx, fr_tls_session_client_hello_cb, NULL); |
1984 | 0 | } |
1985 | |
|
1986 | 0 | tls_session->mtu = conf->fragment_size; |
1987 | 0 | if (dynamic_mtu > 100 && dynamic_mtu < tls_session->mtu) { |
1988 | 0 | RDEBUG2("Setting fragment_len to %zu from dynamic_mtu", dynamic_mtu); |
1989 | 0 | tls_session->mtu = dynamic_mtu; |
1990 | 0 | } |
1991 | |
|
1992 | 0 | if (conf->cache.mode != FR_TLS_CACHE_DISABLED) { |
1993 | 0 | tls_session->allow_session_resumption = true; /* otherwise it's false */ |
1994 | 0 | fr_tls_cache_session_alloc(tls_session); |
1995 | 0 | } |
1996 | |
|
1997 | 0 | fr_tls_session_request_unbind(tls_session->ssl); /* Was bound in this function */ |
1998 | |
|
1999 | 0 | return tls_session; |
2000 | 0 | } |
2001 | | |
2002 | | static unlang_action_t tls_new_session_result(request_t *request, UNUSED void *uctx) |
2003 | 0 | { |
2004 | 0 | request_t *parent = request->parent; |
2005 | |
|
2006 | 0 | fr_assert(parent); |
2007 | | |
2008 | | /* |
2009 | | * Copy control attributes back to the parent. |
2010 | | */ |
2011 | 0 | if (fr_pair_list_copy(parent->control_ctx, &parent->control_pairs, &request->control_pairs) < 0) return UNLANG_ACTION_FAIL; |
2012 | | |
2013 | 0 | return UNLANG_ACTION_CALCULATE_RESULT; |
2014 | 0 | } |
2015 | | |
2016 | | unlang_action_t fr_tls_new_session_push(request_t *request, fr_tls_conf_t const *tls_conf) |
2017 | 0 | { |
2018 | 0 | request_t *child; |
2019 | 0 | fr_pair_t *vp; |
2020 | |
|
2021 | 0 | MEM(child = unlang_subrequest_alloc(request, dict_tls)); |
2022 | |
|
2023 | 0 | MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0); |
2024 | 0 | vp->vp_uint32 = enum_tls_packet_type_new_session->vb_uint32; |
2025 | |
|
2026 | 0 | if (unlang_subrequest_child_push(NULL, child, request, true, UNLANG_SUB_FRAME) < 0) { |
2027 | 0 | talloc_free(child); |
2028 | 0 | return UNLANG_ACTION_FAIL; |
2029 | 0 | } |
2030 | | |
2031 | 0 | if (unlang_function_push(child, |
2032 | 0 | NULL, |
2033 | 0 | tls_new_session_result, |
2034 | 0 | NULL, 0, |
2035 | 0 | UNLANG_SUB_FRAME, NULL) < 0) { |
2036 | 0 | talloc_free(child); |
2037 | 0 | return UNLANG_ACTION_FAIL; |
2038 | 0 | } |
2039 | | |
2040 | 0 | if (unlang_call_push(NULL, child, tls_conf->virtual_server, UNLANG_SUB_FRAME) < 0) { |
2041 | 0 | talloc_free(child); |
2042 | 0 | return UNLANG_ACTION_FAIL; |
2043 | 0 | } |
2044 | | |
2045 | 0 | return UNLANG_ACTION_PUSHED_CHILD; |
2046 | 0 | } |
2047 | | #endif /* WITH_TLS */ |