18#include <freerdp/config.h>
22#include <winpr/assert.h>
23#include <winpr/cast.h>
25#include <winpr/interlocked.h>
26#include <winpr/synch.h>
27#include <winpr/thread.h>
28#include <winpr/sysinfo.h>
29#include <winpr/winsock.h>
30#include <winpr/stream.h>
33#if defined(WINPR_HAVE_POLL_H)
36#include <sys/select.h>
40#include <openssl/ssl.h>
41#include <openssl/err.h>
42#include <openssl/bio.h>
43#include <openssl/x509.h>
45#include <freerdp/crypto/certificate.h>
47#include "../crypto/certificate.h"
52#define RDPTUNNEL_ACTION_CREATEREQUEST 0x0
53#define RDPTUNNEL_ACTION_CREATERESPONSE 0x1
54#define RDPTUNNEL_ACTION_DATA 0x2
56#define RDPTUNNEL_HEADER_LENGTH 4
59#define RDPTUNNEL_SUBHEADER_AUTODETECT_REQUEST 0x00
62#define RDPEMT_SETUP_TIMEOUT_MS 20000
65#define TLS_RECORD_HEADER_LENGTH 5
68#define TLS_RECORD_OVERHEAD 64
81 size_t publicKeyLength;
83 rdpEmtEventFn callback;
87 rdpEmtReceiverFn receiver;
112static BOOL stream_consume(
wStream* s,
size_t count)
116 const size_t used = Stream_GetPosition(s);
119 BYTE* buffer = Stream_Buffer(s);
120 memmove(buffer, &buffer[count], used - count);
121 return Stream_SetPosition(s, used - count);
124static void emt_fail(rdpEmt* emt,
const char* why)
133 WLog_Print(emt->log, WLOG_WARN,
"UDP multitransport tunnel failed: %s", why);
134 emt->callback(emt->custom, emt, RDPEMT_EVENT_FAILED,
nullptr, 0);
138static void emt_hand_up(rdpEmt* emt,
const BYTE* data,
size_t length)
145 emt->callback(emt->custom, emt, RDPEMT_EVENT_DATA, data, length);
150 wStream* s = Stream_New(
nullptr, length);
153 emt_fail(emt,
"out of memory for tunnel data");
156 Stream_Write(s, data, length);
157 Stream_SealLength(s);
158 Stream_ResetPosition(s);
159 if (!emt->receiver(emt->receiverCustom, s))
161 emt_fail(emt,
"the receiver of tunnel data failed");
165 InterlockedExchangeAdd(&emt->directBytes, WINPR_ASSERTING_INT_CAST(LONG, length));
166 WINPR_UNUSED(direct);
169static void log_ssl_errors(rdpEmt* emt,
const char* what)
174 unsigned long err = 0;
175 while ((err = ERR_get_error()) != 0)
177 char buffer[256] = WINPR_C_ARRAY_INIT;
178 ERR_error_string_n(err, buffer,
sizeof(buffer));
179 WLog_Print(emt->log, WLOG_WARN,
"%s: %s", what, buffer);
187static BOOL emt_flush_tls(rdpEmt* emt)
193 const size_t pending = BIO_ctrl_pending(emt->wbio);
196 if (pending > INT32_MAX)
198 if (!Stream_EnsureRemainingCapacity(emt->out, pending))
201 BIO_read(emt->wbio, Stream_Pointer(emt->out), WINPR_ASSERTING_INT_CAST(
int, pending));
204 Stream_Seek(emt->out, WINPR_ASSERTING_INT_CAST(
size_t, rc));
207 const size_t max = rdpudp_get_max_payload(emt->udp);
210 const BYTE* data = Stream_Buffer(emt->out);
211 wStream sbuffer = WINPR_C_ARRAY_INIT;
212 wStream* s = Stream_StaticConstInit(&sbuffer, data, Stream_GetPosition(emt->out));
215 while (Stream_GetRemainingLength(s) >= TLS_RECORD_HEADER_LENGTH)
218 const size_t pos = Stream_GetPosition(s);
220 const size_t record = TLS_RECORD_HEADER_LENGTH + Stream_Get_UINT16_BE(s);
221 if (Stream_GetRemainingLength(s) < record - TLS_RECORD_HEADER_LENGTH)
223 if (!Stream_SetPosition(s, pos))
227 Stream_Seek(s, record - TLS_RECORD_HEADER_LENGTH);
229 if ((pos > chunk) && (pos + record - chunk > max))
231 if (!rdpudp_send(emt->udp, &data[chunk], pos - chunk))
240 for (
size_t offset = 0; offset < record; offset += max)
242 const size_t length = (record - offset > max) ? max : record - offset;
243 if (!rdpudp_send(emt->udp, &data[pos + offset], length))
246 chunk = pos + record;
250 const size_t end = Stream_GetPosition(s);
251 if ((end > chunk) && !rdpudp_send(emt->udp, &data[chunk], end - chunk))
254 return stream_consume(emt->out, end);
258static BOOL emt_write_pdu(rdpEmt* emt, BYTE action,
const BYTE* subHeader,
size_t subHeaderLength,
259 const BYTE* payload,
size_t length)
262 WINPR_ASSERT(subHeader || (subHeaderLength == 0));
263 WINPR_ASSERT(payload || (length == 0));
265 if ((length > UINT16_MAX) || (subHeaderLength > UINT8_MAX - RDPTUNNEL_HEADER_LENGTH))
268 wStream* s = Stream_New(
nullptr, RDPTUNNEL_HEADER_LENGTH + subHeaderLength + length);
273 const UINT8 actionByte = WINPR_ASSERTING_INT_CAST(UINT8, action & 0x0F);
274 const UINT16 payloadLength = WINPR_ASSERTING_INT_CAST(UINT16, length);
275 const UINT8 headerLength =
276 WINPR_ASSERTING_INT_CAST(UINT8, RDPTUNNEL_HEADER_LENGTH + subHeaderLength);
277 Stream_Write_UINT8(s, actionByte);
278 Stream_Write_UINT16(s, payloadLength);
279 Stream_Write_UINT8(s, headerLength);
280 Stream_Write(s, subHeader, subHeaderLength);
281 Stream_Write(s, payload, length);
283 const int total = WINPR_ASSERTING_INT_CAST(
int, Stream_GetPosition(s));
284 const int rc = SSL_write(emt->ssl, Stream_Buffer(s), total);
285 Stream_Free(s, TRUE);
288 log_ssl_errors(emt,
"SSL_write");
291 return emt_flush_tls(emt);
295static BOOL emt_send_create_request(rdpEmt* emt)
299 BYTE request[24] = WINPR_C_ARRAY_INIT;
300 wStream sbuffer = WINPR_C_ARRAY_INIT;
301 wStream* s = Stream_StaticInit(&sbuffer, request,
sizeof(request));
304 Stream_Write_UINT32(s, emt->requestId);
305 Stream_Write_UINT32(s, 0);
306 Stream_Write(s, emt->cookie,
sizeof(emt->cookie));
308 WLog_Print(emt->log, WLOG_DEBUG,
"sending Tunnel Create Request for request id %" PRIu32,
310 return emt_write_pdu(emt, RDPTUNNEL_ACTION_CREATEREQUEST,
nullptr, 0, Stream_Buffer(s),
311 Stream_GetPosition(s));
317static BOOL emt_verify_peer(rdpEmt* emt)
321 X509* x509 = SSL_get_peer_certificate(emt->ssl);
324 WLog_Print(emt->log, WLOG_WARN,
"the tunnel's TLS session has no server certificate");
331 rdpCertificate* cert = freerdp_certificate_new_from_x509(x509,
nullptr);
332 if (cert && freerdp_certificate_get_public_key(cert, &key, &keyLength))
334 rc = (keyLength == emt->publicKeyLength) && (memcmp(key, emt->publicKey, keyLength) == 0);
337 WLog_Print(emt->log, WLOG_WARN,
338 "the tunnel's TLS certificate differs from the main connection's");
341 freerdp_certificate_free(cert);
350static BOOL emt_process_subheaders(rdpEmt* emt,
const BYTE* data,
size_t length)
353 WINPR_ASSERT(data || (length == 0));
357 const size_t subHeaderLength = data[0];
358 if ((length < 2) || (subHeaderLength < 2) || (subHeaderLength > length))
360 emt_fail(emt,
"invalid tunnel subheader");
364 const BYTE subHeaderType = data[1];
365 if (subHeaderType == RDPTUNNEL_SUBHEADER_AUTODETECT_REQUEST)
366 emt->callback(emt->custom, emt, RDPEMT_EVENT_AUTODETECT_REQUEST, data, subHeaderLength);
368 WLog_Print(emt->log, WLOG_DEBUG,
"ignoring tunnel subheader of type 0x%02" PRIx8,
370 data += subHeaderLength;
371 length -= subHeaderLength;
377static BOOL emt_process_pdus(rdpEmt* emt)
381 wStream sbuffer = WINPR_C_ARRAY_INIT;
383 Stream_StaticConstInit(&sbuffer, Stream_Buffer(emt->in), Stream_GetPosition(emt->in));
385 while (Stream_GetRemainingLength(s) >= RDPTUNNEL_HEADER_LENGTH)
388 const size_t start = Stream_GetPosition(s);
389 const BYTE action = Stream_Get_UINT8(s) & 0x0F;
390 const size_t payloadLength = Stream_Get_UINT16(s);
391 const size_t headerLength = Stream_Get_UINT8(s);
392 if (headerLength < RDPTUNNEL_HEADER_LENGTH)
394 emt_fail(emt,
"invalid tunnel PDU header");
400 WINPR_ASSERT(payloadLength <= UINT16_MAX);
401 WINPR_ASSERT(headerLength <= UINT8_MAX);
402 const size_t rest = headerLength - RDPTUNNEL_HEADER_LENGTH + payloadLength;
403 if (Stream_GetRemainingLength(s) < rest)
406 if (!Stream_SetPosition(s, start))
411 if (!emt_process_subheaders(emt, Stream_ConstPointer(s),
412 headerLength - RDPTUNNEL_HEADER_LENGTH))
414 Stream_Seek(s, headerLength - RDPTUNNEL_HEADER_LENGTH);
418 case RDPTUNNEL_ACTION_CREATERESPONSE:
421 if (payloadLength < 4)
423 emt_fail(emt,
"short Tunnel Create Response");
426 const UINT32 hr = Stream_Get_UINT32(s);
427 Stream_Seek(s, payloadLength - 4);
428 if (FAILED((HRESULT)hr))
430 WLog_Print(emt->log, WLOG_WARN,
431 "the server refused the tunnel, hrResponse 0x%08" PRIx32, hr);
432 emt_fail(emt,
"Tunnel Create Response reported a failure");
437 WLog_Print(emt->log, WLOG_INFO,
438 "UDP multitransport tunnel ready (RDP-UDP version 0x%04" PRIx16
")",
439 rdpudp_get_version(emt->udp));
441 emt->callback(emt->custom, emt, RDPEMT_EVENT_READY,
nullptr, 0);
446 case RDPTUNNEL_ACTION_DATA:
448 if (payloadLength > 0)
449 emt_hand_up(emt, Stream_ConstPointer(s), payloadLength);
450 Stream_Seek(s, payloadLength);
454 WLog_Print(emt->log, WLOG_DEBUG,
"ignoring tunnel PDU with action %" PRIu8, action);
455 Stream_Seek(s, payloadLength);
463 return stream_consume(emt->in, Stream_GetPosition(s));
467static BOOL emt_run_tls(rdpEmt* emt)
471 if (!emt->handshakeDone)
474 const int rc = SSL_do_handshake(emt->ssl);
475 if (!emt_flush_tls(emt))
479 const int err = SSL_get_error(emt->ssl, rc);
480 if ((err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE))
482 log_ssl_errors(emt,
"TLS handshake");
483 emt_fail(emt,
"TLS handshake failed");
487 emt->handshakeDone = TRUE;
488 WLog_Print(emt->log, WLOG_DEBUG,
"tunnel TLS session established (%s, %s)",
489 SSL_get_version(emt->ssl), SSL_get_cipher_name(emt->ssl));
490 if (!emt_verify_peer(emt))
492 emt_fail(emt,
"certificate mismatch");
495 if (!emt_send_create_request(emt))
497 emt_fail(emt,
"failed to send the Tunnel Create Request");
504 if (!Stream_EnsureRemainingCapacity(emt->in, 16384))
508 const int rc = SSL_read(emt->ssl, Stream_Pointer(emt->in), 16384);
511 Stream_Seek(emt->in, WINPR_ASSERTING_INT_CAST(
size_t, rc));
515 const int err = SSL_get_error(emt->ssl, rc);
516 if (err == SSL_ERROR_WANT_READ)
518 log_ssl_errors(emt,
"SSL_read");
519 emt_fail(emt, (err == SSL_ERROR_ZERO_RETURN) ?
"the server closed the tunnel"
520 :
"TLS error inside the tunnel");
525 if (!emt_flush_tls(emt))
528 return emt_process_pdus(emt);
532static BOOL emt_receive(
void* custom,
const BYTE* data,
size_t length)
534 rdpEmt* emt = custom;
536 WINPR_ASSERT(data || (length == 0));
538 if (!emt->tlsStarted || emt->failed)
540 if (length > INT32_MAX)
542 const int len = WINPR_ASSERTING_INT_CAST(
int, length);
543 if (BIO_write(emt->rbio, data, len) != len)
545 return emt_run_tls(emt);
549static BOOL emt_start_tls(rdpEmt* emt)
553 emt->ctx = SSL_CTX_new(TLS_client_method());
557 if (!SSL_CTX_set_min_proto_version(emt->ctx, TLS1_2_VERSION))
559 WLog_Print(emt->log, WLOG_ERROR,
"SSL_CTX_set_min_proto_version failed");
562 SSL_CTX_set_options(emt->ctx, SSL_OP_NO_TICKET | SSL_OP_NO_COMPRESSION);
564 SSL_CTX_set_verify(emt->ctx, SSL_VERIFY_NONE,
nullptr);
565 if (!SSL_CTX_set_cipher_list(emt->ctx,
"ECDHE-RSA-AES256-GCM-SHA384:"
566 "ECDHE-RSA-AES128-GCM-SHA256:"
567 "ECDHE-ECDSA-AES256-GCM-SHA384:"
568 "ECDHE-ECDSA-AES128-GCM-SHA256:"
569 "AES256-GCM-SHA384:AES128-GCM-SHA256"))
571 WLog_Print(emt->log, WLOG_ERROR,
"SSL_CTX_set_cipher_list failed");
574#if OPENSSL_VERSION_NUMBER >= 0x10101000L
575 if (!SSL_CTX_set_ciphersuites(emt->ctx,
"TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"))
577 WLog_Print(emt->log, WLOG_ERROR,
"SSL_CTX_set_ciphersuites failed");
583 if (!SSL_CTX_set1_groups_list(emt->ctx,
"X25519:P-256:P-384"))
585 WLog_Print(emt->log, WLOG_ERROR,
"SSL_CTX_set1_groups_list failed");
588 if (!SSL_CTX_set1_sigalgs_list(emt->ctx,
"rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:"
589 "rsa_pkcs1_sha256:rsa_pkcs1_sha384:"
590 "ecdsa_secp256r1_sha256:ecdsa_secp384r1_sha384"))
592 WLog_Print(emt->log, WLOG_ERROR,
"SSL_CTX_set1_sigalgs_list failed");
595 SSL_CTX_set_read_ahead(emt->ctx, 0);
597 emt->ssl = SSL_new(emt->ctx);
601 emt->rbio = BIO_new(BIO_s_mem());
602 emt->wbio = BIO_new(BIO_s_mem());
603 if (!emt->rbio || !emt->wbio)
611 SSL_set_bio(emt->ssl, emt->rbio, emt->wbio);
612 SSL_set_connect_state(emt->ssl);
614 (void)SSL_set_tlsext_host_name(emt->ssl, emt->hostname);
617 const size_t max = rdpudp_get_max_payload(emt->udp);
618 if (max > TLS_RECORD_OVERHEAD + 512)
620 if (!SSL_set_max_send_fragment(emt->ssl,
621 WINPR_ASSERTING_INT_CAST(
long, max - TLS_RECORD_OVERHEAD)))
623 WLog_Print(emt->log, WLOG_ERROR,
"SSL_set_max_send_fragment failed");
628 emt->tlsStarted = TRUE;
629 return emt_run_tls(emt);
633static BOOL emt_poll(rdpEmt* emt)
640 if (!rdpudp_check(emt->udp))
642 emt_fail(emt,
"the RDP-UDP connection failed");
646 if (!emt->tlsStarted && (rdpudp_get_state(emt->udp) == RDPUDP_STATE_ESTABLISHED))
648 if (!emt_start_tls(emt))
650 log_ssl_errors(emt,
"TLS setup");
651 emt_fail(emt,
"failed to start TLS");
656 if (!emt->ready && (GetTickCount64() - emt->started > RDPEMT_SETUP_TIMEOUT_MS))
658 emt_fail(emt,
"timed out");
667static void emt_wait_readable(SOCKET sockfd, UINT32 timeout)
669#if !defined(_WIN32) && defined(WINPR_HAVE_POLL_H)
671 struct pollfd pollset = WINPR_C_ARRAY_INIT;
672 pollset.fd = WINPR_ASSERTING_INT_CAST(
int, sockfd);
673 pollset.events = POLLIN;
674 const UINT32 ms = (timeout > INT32_MAX) ? INT32_MAX : timeout;
675 (void)poll(&pollset, 1, WINPR_ASSERTING_INT_CAST(
int, ms));
679 if (sockfd >= FD_SETSIZE)
687 FD_SET(sockfd, &rset);
688 struct timeval tv = WINPR_C_ARRAY_INIT;
689 tv.tv_sec = WINPR_ASSERTING_INT_CAST(
long, timeout / 1000);
690 tv.tv_usec = WINPR_ASSERTING_INT_CAST(
long, (timeout % 1000) * 1000);
692 (void)select(0, &rset,
nullptr,
nullptr, &tv);
694 (void)select(WINPR_ASSERTING_INT_CAST(
int, sockfd) + 1, &rset,
nullptr,
nullptr, &tv);
700static BOOL emt_stopping(rdpEmt* emt)
703 return InterlockedCompareExchange(&emt->stop, 0, 0) != 0;
707static DWORD WINAPI emt_thread(LPVOID arg)
712 while (!emt_stopping(emt))
714 EnterCriticalSection(&emt->lock);
715 const UINT32 timeout = rdpudp_get_timeout(emt->udp);
716 const SOCKET sockfd = rdpudp_get_socket(emt->udp);
717 LeaveCriticalSection(&emt->lock);
719 emt_wait_readable(sockfd, timeout);
721 if (emt_stopping(emt))
724 EnterCriticalSection(&emt->lock);
725 const BOOL rc = emt_poll(emt);
726 LeaveCriticalSection(&emt->lock);
735rdpEmt* rdpemt_new(wLog* log, UINT32 requestId,
const BYTE* cookie,
const char* hostname,
736 const BYTE* publicKey,
size_t publicKeyLength, rdpEmtEventFn callback,
740 WINPR_ASSERT(cookie);
741 WINPR_ASSERT(publicKey);
742 WINPR_ASSERT(callback);
744 rdpEmt* emt = calloc(1,
sizeof(rdpEmt));
749 emt->requestId = requestId;
750 memcpy(emt->cookie, cookie,
sizeof(emt->cookie));
751 emt->callback = callback;
752 emt->custom = custom;
753 if (!InitializeCriticalSectionAndSpinCount(&emt->lock, 4000))
761 emt->hostname = _strdup(hostname);
766 emt->publicKey = malloc(publicKeyLength);
769 memcpy(emt->publicKey, publicKey, publicKeyLength);
770 emt->publicKeyLength = publicKeyLength;
774 BYTE digest[32] = WINPR_C_ARRAY_INIT;
775 if (!winpr_Digest(WINPR_MD_SHA256, emt->cookie,
sizeof(emt->cookie), digest,
sizeof(digest)))
777 BYTE cookieHash[32] = WINPR_C_ARRAY_INIT;
779 wStream dbuffer = WINPR_C_ARRAY_INIT;
780 wStream hbuffer = WINPR_C_ARRAY_INIT;
781 wStream* ds = Stream_StaticConstInit(&dbuffer, digest,
sizeof(digest));
782 wStream* hs = Stream_StaticInit(&hbuffer, cookieHash,
sizeof(cookieHash));
783 for (
size_t x = 0; x <
sizeof(cookieHash) / 4; x++)
786 const UINT32 word = Stream_Get_UINT32_BE(ds);
787 Stream_Write_UINT32(hs, word);
791 emt->in = Stream_New(
nullptr, 16384);
792 emt->out = Stream_New(
nullptr, 4096);
793 if (!emt->in || !emt->out)
796 emt->udp = rdpudp_new(log, cookieHash, emt_receive, emt);
802 WINPR_PRAGMA_DIAG_PUSH
803 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
805 WINPR_PRAGMA_DIAG_POP
809BOOL rdpemt_start(rdpEmt* emt,
const struct sockaddr* addr,
size_t addrlen)
814 emt->started = GetTickCount64();
815 if (!rdpudp_connect(emt->udp, addr, addrlen))
818 emt->thread = CreateThread(
nullptr, 0, emt_thread, emt, 0,
nullptr);
819 return emt->thread !=
nullptr;
822void rdpemt_free(rdpEmt* emt)
828 InterlockedIncrement(&emt->stop);
831 (void)WaitForSingleObject(emt->thread, INFINITE);
832 (void)CloseHandle(emt->thread);
836 SSL_CTX_free(emt->ctx);
837 rdpudp_free(emt->udp);
839 free(emt->publicKey);
840 Stream_Free(emt->in, TRUE);
841 Stream_Free(emt->out, TRUE);
842 DeleteCriticalSection(&emt->lock);
846BOOL rdpemt_send_data(rdpEmt* emt,
const BYTE* data,
size_t length)
849 WINPR_ASSERT(data || (length == 0));
852 EnterCriticalSection(&emt->lock);
853 if (emt->ready && !emt->failed)
855 rc = emt_write_pdu(emt, RDPTUNNEL_ACTION_DATA,
nullptr, 0, data, length);
857 emt_fail(emt,
"failed to send tunnel data");
859 LeaveCriticalSection(&emt->lock);
863BOOL rdpemt_set_receiver(rdpEmt* emt, rdpEmtReceiverFn receiver,
void* custom, wQueue* pending)
866 WINPR_ASSERT(receiver);
867 WINPR_ASSERT(pending);
872 EnterCriticalSection(&emt->lock);
873 const BOOL rc = emt->receiver || (Queue_Count(pending) == 0);
877 WLog_Print(emt->log, WLOG_DEBUG,
878 "tunnel data goes to its receiver on the tunnel thread");
879 emt->receiver = receiver;
880 emt->receiverCustom = custom;
882 LeaveCriticalSection(&emt->lock);
886void rdpemt_clear_receiver(rdpEmt* emt)
891 EnterCriticalSection(&emt->lock);
893 WLog_Print(emt->log, WLOG_DEBUG,
"tunnel data goes to the event callback again");
894 emt->receiver =
nullptr;
895 emt->receiverCustom =
nullptr;
896 LeaveCriticalSection(&emt->lock);
899UINT32 rdpemt_take_direct_bytes(rdpEmt* emt)
905 LONG bytes = InterlockedCompareExchange(&emt->directBytes, 0, 0);
908 const LONG seen = InterlockedCompareExchange(&emt->directBytes, 0, bytes);
915 return WINPR_CXX_COMPAT_CAST(UINT32, bytes);
918BOOL rdpemt_send_subheader(rdpEmt* emt,
const BYTE* subHeader,
size_t length)
921 WINPR_ASSERT(subHeader);
924 EnterCriticalSection(&emt->lock);
925 if (emt->ready && !emt->failed)
928 rc = emt_write_pdu(emt, RDPTUNNEL_ACTION_DATA, subHeader, length,
nullptr, 0);
930 emt_fail(emt,
"failed to send a tunnel subheader");
932 LeaveCriticalSection(&emt->lock);
936BOOL rdpemt_is_supported(
void)
941UINT32 rdpemt_get_request_id(
const rdpEmt* emt)
944 return emt->requestId;