FreeRDP
Loading...
Searching...
No Matches
libfreerdp/crypto/tls.c
1
22#include <freerdp/config.h>
23
24#include "../core/settings.h"
25
26#include <winpr/assert.h>
27#include <string.h>
28#include <errno.h>
29
30#include <winpr/crt.h>
31#include <winpr/winpr.h>
32#include <winpr/string.h>
33#include <winpr/sspi.h>
34#include <winpr/ssl.h>
35#include <winpr/json.h>
36
37#include <winpr/stream.h>
38#include <freerdp/utils/ringbuffer.h>
39
40#include <freerdp/crypto/certificate.h>
41#include <freerdp/crypto/certificate_data.h>
42#include <freerdp/utils/helpers.h>
43
44#include <freerdp/log.h>
45#include "../crypto/tls.h"
46#include "../core/tcp.h"
47
48#include "opensslcompat.h"
49#include "certificate.h"
50#include "privatekey.h"
51
52#ifdef WINPR_HAVE_POLL_H
53#include <poll.h>
54#endif
55
56#ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
57#include <valgrind/memcheck.h>
58#endif
59
60#define TAG FREERDP_TAG("crypto")
61
84typedef struct
85{
86 SSL* ssl;
88} BIO_RDP_TLS;
89
90static int tls_verify_certificate(rdpTls* tls, const rdpCertificate* cert, const char* hostname,
91 UINT16 port);
92static void tls_print_certificate_name_mismatch_error(const char* hostname, UINT16 port,
93 const char* common_name, char** alt_names,
94 size_t alt_names_count);
95static void tls_print_new_certificate_warn(rdpCertificateStore* store, const char* hostname,
96 UINT16 port, const char* fingerprint);
97static void tls_print_certificate_error(rdpCertificateStore* store, rdpCertificateData* stored_data,
98 const char* hostname, UINT16 port, const char* fingerprint);
99
100static void free_tls_public_key(rdpTls* tls)
101{
102 WINPR_ASSERT(tls);
103 free(tls->PublicKey);
104 tls->PublicKey = NULL;
105 tls->PublicKeyLength = 0;
106}
107
108static void free_tls_bindings(rdpTls* tls)
109{
110 WINPR_ASSERT(tls);
111
112 if (tls->Bindings)
113 free(tls->Bindings->Bindings);
114
115 free(tls->Bindings);
116 tls->Bindings = NULL;
117}
118
119static int bio_rdp_tls_write(BIO* bio, const char* buf, int size)
120{
121 int error = 0;
122 int status = 0;
123 BIO_RDP_TLS* tls = (BIO_RDP_TLS*)BIO_get_data(bio);
124
125 if (!buf || !tls)
126 return 0;
127
128 BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL);
129 EnterCriticalSection(&tls->lock);
130 status = SSL_write(tls->ssl, buf, size);
131 error = SSL_get_error(tls->ssl, status);
132 LeaveCriticalSection(&tls->lock);
133
134 if (status <= 0)
135 {
136 switch (error)
137 {
138 case SSL_ERROR_NONE:
139 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
140 break;
141
142 case SSL_ERROR_WANT_WRITE:
143 BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
144 break;
145
146 case SSL_ERROR_WANT_READ:
147 BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
148 break;
149
150 case SSL_ERROR_WANT_X509_LOOKUP:
151 BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
152 BIO_set_retry_reason(bio, BIO_RR_SSL_X509_LOOKUP);
153 break;
154
155 case SSL_ERROR_WANT_CONNECT:
156 BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
157 BIO_set_retry_reason(bio, BIO_RR_CONNECT);
158 break;
159
160 case SSL_ERROR_SYSCALL:
161 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
162 break;
163
164 case SSL_ERROR_SSL:
165 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
166 break;
167 default:
168 break;
169 }
170 }
171
172 return status;
173}
174
175static int bio_rdp_tls_read(BIO* bio, char* buf, int size)
176{
177 int error = 0;
178 int status = 0;
179 BIO_RDP_TLS* tls = (BIO_RDP_TLS*)BIO_get_data(bio);
180
181 if (!buf || !tls)
182 return 0;
183
184 BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL);
185 EnterCriticalSection(&tls->lock);
186 status = SSL_read(tls->ssl, buf, size);
187 error = SSL_get_error(tls->ssl, status);
188 LeaveCriticalSection(&tls->lock);
189
190 if (status <= 0)
191 {
192
193 switch (error)
194 {
195 case SSL_ERROR_NONE:
196 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
197 break;
198
199 case SSL_ERROR_WANT_READ:
200 BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
201 break;
202
203 case SSL_ERROR_WANT_WRITE:
204 BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
205 break;
206
207 case SSL_ERROR_WANT_X509_LOOKUP:
208 BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
209 BIO_set_retry_reason(bio, BIO_RR_SSL_X509_LOOKUP);
210 break;
211
212 case SSL_ERROR_WANT_ACCEPT:
213 BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
214 BIO_set_retry_reason(bio, BIO_RR_ACCEPT);
215 break;
216
217 case SSL_ERROR_WANT_CONNECT:
218 BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
219 BIO_set_retry_reason(bio, BIO_RR_CONNECT);
220 break;
221
222 case SSL_ERROR_SSL:
223 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
224 break;
225
226 case SSL_ERROR_ZERO_RETURN:
227 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
228 break;
229
230 case SSL_ERROR_SYSCALL:
231 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
232 break;
233 default:
234 break;
235 }
236 }
237
238#ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
239
240 if (status > 0)
241 {
242 VALGRIND_MAKE_MEM_DEFINED(buf, status);
243 }
244
245#endif
246 return status;
247}
248
249static int bio_rdp_tls_puts(BIO* bio, const char* str)
250{
251 if (!str)
252 return 0;
253
254 const size_t size = strnlen(str, INT_MAX + 1UL);
255 if (size > INT_MAX)
256 return -1;
257 ERR_clear_error();
258 return BIO_write(bio, str, (int)size);
259}
260
261static int bio_rdp_tls_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED char* str,
262 WINPR_ATTR_UNUSED int size)
263{
264 return 1;
265}
266
267static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr)
268{
269 BIO* ssl_rbio = NULL;
270 BIO* ssl_wbio = NULL;
271 BIO* next_bio = NULL;
272 long status = -1;
273 BIO_RDP_TLS* tls = (BIO_RDP_TLS*)BIO_get_data(bio);
274
275 if (!tls)
276 return 0;
277
278 if (!tls->ssl && (cmd != BIO_C_SET_SSL))
279 return 0;
280
281 next_bio = BIO_next(bio);
282 ssl_rbio = tls->ssl ? SSL_get_rbio(tls->ssl) : NULL;
283 ssl_wbio = tls->ssl ? SSL_get_wbio(tls->ssl) : NULL;
284
285 switch (cmd)
286 {
287 case BIO_CTRL_RESET:
288 SSL_shutdown(tls->ssl);
289
290 if (SSL_in_connect_init(tls->ssl))
291 SSL_set_connect_state(tls->ssl);
292 else if (SSL_in_accept_init(tls->ssl))
293 SSL_set_accept_state(tls->ssl);
294
295 SSL_clear(tls->ssl);
296
297 if (next_bio)
298 status = BIO_ctrl(next_bio, cmd, num, ptr);
299 else if (ssl_rbio)
300 status = BIO_ctrl(ssl_rbio, cmd, num, ptr);
301 else
302 status = 1;
303
304 break;
305
306 case BIO_C_GET_FD:
307 status = BIO_ctrl(ssl_rbio, cmd, num, ptr);
308 break;
309
310 case BIO_CTRL_INFO:
311 status = 0;
312 break;
313
314 case BIO_CTRL_SET_CALLBACK:
315 status = 0;
316 break;
317
318 case BIO_CTRL_GET_CALLBACK:
319 /* The OpenSSL API is horrible here:
320 * we get a function pointer returned and have to cast it to ULONG_PTR
321 * to return the value to the caller.
322 *
323 * This, of course, is something compilers warn about. So silence it by casting */
324 {
325 void* vptr = WINPR_FUNC_PTR_CAST(SSL_get_info_callback(tls->ssl), void*);
326 *((void**)ptr) = vptr;
327 status = 1;
328 }
329 break;
330
331 case BIO_C_SSL_MODE:
332 if (num)
333 SSL_set_connect_state(tls->ssl);
334 else
335 SSL_set_accept_state(tls->ssl);
336
337 status = 1;
338 break;
339
340 case BIO_CTRL_GET_CLOSE:
341 status = BIO_get_shutdown(bio);
342 break;
343
344 case BIO_CTRL_SET_CLOSE:
345 BIO_set_shutdown(bio, (int)num);
346 status = 1;
347 break;
348
349 case BIO_CTRL_WPENDING:
350 status = BIO_ctrl(ssl_wbio, cmd, num, ptr);
351 break;
352
353 case BIO_CTRL_PENDING:
354 status = SSL_pending(tls->ssl);
355
356 if (status == 0)
357 status = BIO_pending(ssl_rbio);
358
359 break;
360
361 case BIO_CTRL_FLUSH:
362 BIO_clear_retry_flags(bio);
363 status = BIO_ctrl(ssl_wbio, cmd, num, ptr);
364 if (status != 1)
365 WLog_DBG(TAG, "BIO_ctrl returned %d", status);
366 BIO_copy_next_retry(bio);
367 status = 1;
368 break;
369
370 case BIO_CTRL_PUSH:
371 if (next_bio && (next_bio != ssl_rbio))
372 {
373#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
374 (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
375 SSL_set_bio(tls->ssl, next_bio, next_bio);
376 CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO);
377#else
378 /*
379 * We are going to pass ownership of next to the SSL object...but
380 * we don't own a reference to pass yet - so up ref
381 */
382 BIO_up_ref(next_bio);
383 SSL_set_bio(tls->ssl, next_bio, next_bio);
384#endif
385 }
386
387 status = 1;
388 break;
389
390 case BIO_CTRL_POP:
391
392 /* Only detach if we are the BIO explicitly being popped */
393 if (bio == ptr)
394 {
395 if (ssl_rbio != ssl_wbio)
396 BIO_free_all(ssl_wbio);
397
398#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
399 (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
400
401 if (next_bio)
402 CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO);
403
404 tls->ssl->wbio = tls->ssl->rbio = NULL;
405#else
406 /* OpenSSL 1.1: This will also clear the reference we obtained during push */
407 SSL_set_bio(tls->ssl, NULL, NULL);
408#endif
409 }
410
411 status = 1;
412 break;
413
414 case BIO_C_GET_SSL:
415 if (ptr)
416 {
417 *((SSL**)ptr) = tls->ssl;
418 status = 1;
419 }
420
421 break;
422
423 case BIO_C_SET_SSL:
424 BIO_set_shutdown(bio, (int)num);
425
426 if (ptr)
427 {
428 tls->ssl = (SSL*)ptr;
429 ssl_rbio = SSL_get_rbio(tls->ssl);
430 }
431
432 if (ssl_rbio)
433 {
434 if (next_bio)
435 BIO_push(ssl_rbio, next_bio);
436
437 BIO_set_next(bio, ssl_rbio);
438#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
439 (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
440 CRYPTO_add(&(ssl_rbio->references), 1, CRYPTO_LOCK_BIO);
441#else
442 BIO_up_ref(ssl_rbio);
443#endif
444 }
445
446 BIO_set_init(bio, 1);
447 status = 1;
448 break;
449
450 case BIO_C_DO_STATE_MACHINE:
451 BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL);
452 BIO_set_retry_reason(bio, 0);
453 status = SSL_do_handshake(tls->ssl);
454
455 if (status <= 0)
456 {
457 const int err = (status < INT32_MIN) ? INT32_MIN : (int)status;
458 switch (SSL_get_error(tls->ssl, err))
459 {
460 case SSL_ERROR_WANT_READ:
461 BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
462 break;
463
464 case SSL_ERROR_WANT_WRITE:
465 BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
466 break;
467
468 case SSL_ERROR_WANT_CONNECT:
469 BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
470 BIO_set_retry_reason(bio, BIO_get_retry_reason(next_bio));
471 break;
472
473 default:
474 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
475 break;
476 }
477 }
478
479 break;
480
481 default:
482 status = BIO_ctrl(ssl_rbio, cmd, num, ptr);
483 break;
484 }
485
486 return status;
487}
488
489static int bio_rdp_tls_new(BIO* bio)
490{
491 BIO_RDP_TLS* tls = NULL;
492 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
493
494 if (!(tls = calloc(1, sizeof(BIO_RDP_TLS))))
495 return 0;
496
497 InitializeCriticalSectionAndSpinCount(&tls->lock, 4000);
498 BIO_set_data(bio, (void*)tls);
499 return 1;
500}
501
502static int bio_rdp_tls_free(BIO* bio)
503{
504 BIO_RDP_TLS* tls = NULL;
505
506 if (!bio)
507 return 0;
508
509 tls = (BIO_RDP_TLS*)BIO_get_data(bio);
510
511 if (!tls)
512 return 0;
513
514 BIO_set_data(bio, NULL);
515 if (BIO_get_shutdown(bio))
516 {
517 if (BIO_get_init(bio) && tls->ssl)
518 {
519 SSL_shutdown(tls->ssl);
520 SSL_free(tls->ssl);
521 }
522
523 BIO_set_init(bio, 0);
524 BIO_set_flags(bio, 0);
525 }
526
527 DeleteCriticalSection(&tls->lock);
528 free(tls);
529
530 return 1;
531}
532
533static long bio_rdp_tls_callback_ctrl(BIO* bio, int cmd, bio_info_cb* fp)
534{
535 long status = 0;
536
537 if (!bio)
538 return 0;
539
540 BIO_RDP_TLS* tls = (BIO_RDP_TLS*)BIO_get_data(bio);
541
542 if (!tls)
543 return 0;
544
545 switch (cmd)
546 {
547 case BIO_CTRL_SET_CALLBACK:
548 {
549 typedef void (*fkt_t)(const SSL*, int, int);
550
551 /* Documented since https://www.openssl.org/docs/man1.1.1/man3/BIO_set_callback.html
552 * the argument is not really of type bio_info_cb* and must be cast
553 * to the required type */
554
555 fkt_t fkt = WINPR_FUNC_PTR_CAST(fp, fkt_t);
556 SSL_set_info_callback(tls->ssl, fkt);
557 status = 1;
558 }
559 break;
560
561 default:
562 status = BIO_callback_ctrl(SSL_get_rbio(tls->ssl), cmd, fp);
563 break;
564 }
565
566 return status;
567}
568
569#define BIO_TYPE_RDP_TLS 68
570
571static BIO_METHOD* BIO_s_rdp_tls(void)
572{
573 static BIO_METHOD* bio_methods = NULL;
574
575 if (bio_methods == NULL)
576 {
577 if (!(bio_methods = BIO_meth_new(BIO_TYPE_RDP_TLS, "RdpTls")))
578 return NULL;
579
580 BIO_meth_set_write(bio_methods, bio_rdp_tls_write);
581 BIO_meth_set_read(bio_methods, bio_rdp_tls_read);
582 BIO_meth_set_puts(bio_methods, bio_rdp_tls_puts);
583 BIO_meth_set_gets(bio_methods, bio_rdp_tls_gets);
584 BIO_meth_set_ctrl(bio_methods, bio_rdp_tls_ctrl);
585 BIO_meth_set_create(bio_methods, bio_rdp_tls_new);
586 BIO_meth_set_destroy(bio_methods, bio_rdp_tls_free);
587 BIO_meth_set_callback_ctrl(bio_methods, bio_rdp_tls_callback_ctrl);
588 }
589
590 return bio_methods;
591}
592
593static BIO* BIO_new_rdp_tls(SSL_CTX* ctx, int client)
594{
595 BIO* bio = NULL;
596 SSL* ssl = NULL;
597 bio = BIO_new(BIO_s_rdp_tls());
598
599 if (!bio)
600 return NULL;
601
602 ssl = SSL_new(ctx);
603
604 if (!ssl)
605 {
606 BIO_free_all(bio);
607 return NULL;
608 }
609
610 if (client)
611 SSL_set_connect_state(ssl);
612 else
613 SSL_set_accept_state(ssl);
614
615 BIO_set_ssl(bio, ssl, BIO_CLOSE);
616 return bio;
617}
618
619static rdpCertificate* tls_get_certificate(rdpTls* tls, BOOL peer)
620{
621 X509* remote_cert = NULL;
622
623 if (peer)
624 remote_cert = SSL_get_peer_certificate(tls->ssl);
625 else
626 remote_cert = X509_dup(SSL_get_certificate(tls->ssl));
627
628 if (!remote_cert)
629 {
630 WLog_ERR(TAG, "failed to get the server TLS certificate");
631 return NULL;
632 }
633
634 /* Get the peer's chain. If it does not exist, we're setting NULL (clean data either way) */
635 STACK_OF(X509)* chain = SSL_get_peer_cert_chain(tls->ssl);
636 rdpCertificate* cert = freerdp_certificate_new_from_x509(remote_cert, chain);
637 X509_free(remote_cert);
638
639 return cert;
640}
641
642static const char* tls_get_server_name(rdpTls* tls)
643{
644 return tls->serverName ? tls->serverName : tls->hostname;
645}
646
647#define TLS_SERVER_END_POINT "tls-server-end-point:"
648
649static SecPkgContext_Bindings* tls_get_channel_bindings(const rdpCertificate* cert)
650{
651 size_t CertificateHashLength = 0;
652 BYTE* ChannelBindingToken = NULL;
653 SEC_CHANNEL_BINDINGS* ChannelBindings = NULL;
654 const size_t PrefixLength = strnlen(TLS_SERVER_END_POINT, ARRAYSIZE(TLS_SERVER_END_POINT));
655
656 WINPR_ASSERT(cert);
657
658 /* See https://www.rfc-editor.org/rfc/rfc5929 for details about hashes */
659 WINPR_MD_TYPE alg = freerdp_certificate_get_signature_alg(cert);
660 const char* hash = NULL;
661 switch (alg)
662 {
663
664 case WINPR_MD_MD5:
665 case WINPR_MD_SHA1:
666 hash = winpr_md_type_to_string(WINPR_MD_SHA256);
667 break;
668 default:
669 hash = winpr_md_type_to_string(alg);
670 break;
671 }
672 if (!hash)
673 return NULL;
674
675 char* CertificateHash = freerdp_certificate_get_hash(cert, hash, &CertificateHashLength);
676 if (!CertificateHash)
677 return NULL;
678
679 const size_t ChannelBindingTokenLength = PrefixLength + CertificateHashLength;
680 SecPkgContext_Bindings* ContextBindings = calloc(1, sizeof(SecPkgContext_Bindings));
681
682 if (!ContextBindings)
683 goto out_free;
684
685 const size_t slen = sizeof(SEC_CHANNEL_BINDINGS) + ChannelBindingTokenLength;
686 if (slen > UINT32_MAX)
687 goto out_free;
688
689 ContextBindings->BindingsLength = (UINT32)slen;
690 ChannelBindings = (SEC_CHANNEL_BINDINGS*)calloc(1, ContextBindings->BindingsLength);
691
692 if (!ChannelBindings)
693 goto out_free;
694
695 ContextBindings->Bindings = ChannelBindings;
696 ChannelBindings->cbApplicationDataLength = (UINT32)ChannelBindingTokenLength;
697 ChannelBindings->dwApplicationDataOffset = sizeof(SEC_CHANNEL_BINDINGS);
698 ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
699 memcpy(ChannelBindingToken, TLS_SERVER_END_POINT, PrefixLength);
700 memcpy(ChannelBindingToken + PrefixLength, CertificateHash, CertificateHashLength);
701 free(CertificateHash);
702 return ContextBindings;
703out_free:
704 free(CertificateHash);
705 free(ContextBindings);
706 return NULL;
707}
708
709static INIT_ONCE secrets_file_idx_once = INIT_ONCE_STATIC_INIT;
710static int secrets_file_idx = -1;
711
712static BOOL CALLBACK secrets_file_init_cb(WINPR_ATTR_UNUSED PINIT_ONCE once,
713 WINPR_ATTR_UNUSED PVOID param,
714 WINPR_ATTR_UNUSED PVOID* context)
715{
716 secrets_file_idx = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
717
718 return (secrets_file_idx != -1);
719}
720
721static void SSLCTX_keylog_cb(const SSL* ssl, const char* line)
722{
723 char* dfile = NULL;
724
725 if (secrets_file_idx == -1)
726 return;
727
728 dfile = SSL_get_ex_data(ssl, secrets_file_idx);
729 if (dfile)
730 {
731 FILE* f = winpr_fopen(dfile, "a+");
732 if (f)
733 {
734 (void)fwrite(line, strlen(line), 1, f);
735 (void)fwrite("\n", 1, 1, f);
736 (void)fclose(f);
737 }
738 }
739}
740
741static void tls_reset(rdpTls* tls)
742{
743 WINPR_ASSERT(tls);
744
745 if (tls->ctx)
746 {
747 SSL_CTX_free(tls->ctx);
748 tls->ctx = NULL;
749 }
750
751 /* tls->underlying is a stacked BIO under tls->bio.
752 * BIO_free_all will free recursively. */
753 if (tls->bio)
754 BIO_free_all(tls->bio);
755 else if (tls->underlying)
756 BIO_free_all(tls->underlying);
757 tls->bio = NULL;
758 tls->underlying = NULL;
759
760 free_tls_public_key(tls);
761 free_tls_bindings(tls);
762}
763
764#if OPENSSL_VERSION_NUMBER >= 0x010000000L
765static BOOL tls_prepare(rdpTls* tls, BIO* underlying, const SSL_METHOD* method, int options,
766 BOOL clientMode)
767#else
768static BOOL tls_prepare(rdpTls* tls, BIO* underlying, SSL_METHOD* method, int options,
769 BOOL clientMode)
770#endif
771{
772 WINPR_ASSERT(tls);
773
774 rdpSettings* settings = tls->context->settings;
775 WINPR_ASSERT(settings);
776
777 tls_reset(tls);
778 tls->ctx = SSL_CTX_new(method);
779
780 tls->underlying = underlying;
781
782 if (!tls->ctx)
783 {
784 WLog_ERR(TAG, "SSL_CTX_new failed");
785 return FALSE;
786 }
787
788 SSL_CTX_set_mode(tls->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
789 SSL_CTX_set_options(tls->ctx, WINPR_ASSERTING_INT_CAST(uint64_t, options));
790 SSL_CTX_set_read_ahead(tls->ctx, 1);
791#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
792 UINT16 version = freerdp_settings_get_uint16(settings, FreeRDP_TLSMinVersion);
793 if (!SSL_CTX_set_min_proto_version(tls->ctx, version))
794 {
795 WLog_ERR(TAG, "SSL_CTX_set_min_proto_version %s failed", version);
796 return FALSE;
797 }
798 version = freerdp_settings_get_uint16(settings, FreeRDP_TLSMaxVersion);
799 if (!SSL_CTX_set_max_proto_version(tls->ctx, version))
800 {
801 WLog_ERR(TAG, "SSL_CTX_set_max_proto_version %s failed", version);
802 return FALSE;
803 }
804#endif
805#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
806 SSL_CTX_set_security_level(tls->ctx, WINPR_ASSERTING_INT_CAST(int, settings->TlsSecLevel));
807#endif
808
809 if (settings->AllowedTlsCiphers)
810 {
811 if (!SSL_CTX_set_cipher_list(tls->ctx, settings->AllowedTlsCiphers))
812 {
813 WLog_ERR(TAG, "SSL_CTX_set_cipher_list %s failed", settings->AllowedTlsCiphers);
814 return FALSE;
815 }
816 }
817
818 tls->bio = BIO_new_rdp_tls(tls->ctx, clientMode);
819
820 if (BIO_get_ssl(tls->bio, &tls->ssl) < 0)
821 {
822 WLog_ERR(TAG, "unable to retrieve the SSL of the connection");
823 return FALSE;
824 }
825
826 if (settings->TlsSecretsFile)
827 {
828#if OPENSSL_VERSION_NUMBER >= 0x10101000L
829 InitOnceExecuteOnce(&secrets_file_idx_once, secrets_file_init_cb, NULL, NULL);
830
831 if (secrets_file_idx != -1)
832 {
833 SSL_set_ex_data(tls->ssl, secrets_file_idx, settings->TlsSecretsFile);
834 SSL_CTX_set_keylog_callback(tls->ctx, SSLCTX_keylog_cb);
835 }
836#else
837 WLog_WARN(TAG, "Key-Logging not available - requires OpenSSL 1.1.1 or higher");
838#endif
839 }
840
841 BIO_push(tls->bio, underlying);
842 return TRUE;
843}
844
845static void
846adjustSslOptions(WINPR_ATTR_UNUSED int* options) // NOLINT(readability-non-const-parameter)
847{
848 WINPR_ASSERT(options);
849#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
850 *options |= SSL_OP_NO_SSLv2;
851 *options |= SSL_OP_NO_SSLv3;
852#endif
853}
854
855const SSL_METHOD* freerdp_tls_get_ssl_method(BOOL isDtls, BOOL isClient)
856{
857 if (isClient)
858 {
859 if (isDtls)
860 return DTLS_client_method();
861#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
862 return SSLv23_client_method();
863#else
864 return TLS_client_method();
865#endif
866 }
867
868 if (isDtls)
869 return DTLS_server_method();
870
871#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
872 return SSLv23_server_method();
873#else
874 return TLS_server_method();
875#endif
876}
877
878TlsHandshakeResult freerdp_tls_connect_ex(rdpTls* tls, BIO* underlying, const SSL_METHOD* methods)
879{
880 WINPR_ASSERT(tls);
881
882 int options = 0;
892#ifdef SSL_OP_NO_COMPRESSION
893 options |= SSL_OP_NO_COMPRESSION;
894#endif
901 options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
908 options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
909
910 tls->isClientMode = TRUE;
911 adjustSslOptions(&options);
912
913 if (!tls_prepare(tls, underlying, methods, options, TRUE))
914 return 0;
915
916#if !defined(OPENSSL_NO_TLSEXT)
917 const char* str = tls_get_server_name(tls);
918 void* ptr = WINPR_CAST_CONST_PTR_AWAY(str, void*);
919 SSL_set_tlsext_host_name(tls->ssl, ptr);
920#endif
921
922 return freerdp_tls_handshake(tls);
923}
924
925static int bio_err_print(const char* str, size_t len, void* u)
926{
927 wLog* log = u;
928 WLog_Print(log, WLOG_ERROR, "[BIO_do_handshake] %s [%" PRIuz "]", str, len);
929 return 0;
930}
931
932TlsHandshakeResult freerdp_tls_handshake(rdpTls* tls)
933{
934 TlsHandshakeResult ret = TLS_HANDSHAKE_ERROR;
935
936 WINPR_ASSERT(tls);
937 const long status = BIO_do_handshake(tls->bio);
938 if (status != 1)
939 {
940 if (!BIO_should_retry(tls->bio))
941 {
942 wLog* log = WLog_Get(TAG);
943 WLog_Print(log, WLOG_ERROR, "BIO_do_handshake failed");
944 ERR_print_errors_cb(bio_err_print, log);
945 return TLS_HANDSHAKE_ERROR;
946 }
947
948 return TLS_HANDSHAKE_CONTINUE;
949 }
950
951 int verify_status = 0;
952 rdpCertificate* cert = tls_get_certificate(tls, tls->isClientMode);
953
954 if (!cert)
955 {
956 WLog_ERR(TAG, "tls_get_certificate failed to return the server certificate.");
957 return TLS_HANDSHAKE_ERROR;
958 }
959
960 do
961 {
962 free_tls_bindings(tls);
963 tls->Bindings = tls_get_channel_bindings(cert);
964 if (!tls->Bindings)
965 {
966 WLog_ERR(TAG, "unable to retrieve bindings");
967 break;
968 }
969
970 free_tls_public_key(tls);
971 if (!freerdp_certificate_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength))
972 {
973 WLog_ERR(TAG,
974 "freerdp_certificate_get_public_key failed to return the server public key.");
975 break;
976 }
977
978 /* server-side NLA needs public keys (keys from us, the server) but no certificate verify */
979 ret = TLS_HANDSHAKE_SUCCESS;
980
981 if (tls->isClientMode)
982 {
983 WINPR_ASSERT(tls->port <= UINT16_MAX);
984 verify_status =
985 tls_verify_certificate(tls, cert, tls_get_server_name(tls), (UINT16)tls->port);
986
987 if (verify_status < 1)
988 {
989 WLog_ERR(TAG, "certificate not trusted, aborting.");
990 freerdp_tls_send_alert(tls);
991 ret = TLS_HANDSHAKE_VERIFY_ERROR;
992 }
993 }
994 } while (0);
995
996 freerdp_certificate_free(cert);
997 return ret;
998}
999
1000static int pollAndHandshake(rdpTls* tls)
1001{
1002 WINPR_ASSERT(tls);
1003
1004 do
1005 {
1006 HANDLE event = NULL;
1007 DWORD status = 0;
1008 if (BIO_get_event(tls->bio, &event) < 0)
1009 {
1010 WLog_ERR(TAG, "unable to retrieve BIO associated event");
1011 return -1;
1012 }
1013
1014 if (!event)
1015 {
1016 WLog_ERR(TAG, "unable to retrieve BIO event");
1017 return -1;
1018 }
1019
1020 status = WaitForSingleObjectEx(event, 50, TRUE);
1021 switch (status)
1022 {
1023 case WAIT_OBJECT_0:
1024 break;
1025 case WAIT_TIMEOUT:
1026 case WAIT_IO_COMPLETION:
1027 continue;
1028 default:
1029 WLog_ERR(TAG, "error during WaitForSingleObject(): 0x%08" PRIX32 "", status);
1030 return -1;
1031 }
1032
1033 TlsHandshakeResult result = freerdp_tls_handshake(tls);
1034 switch (result)
1035 {
1036 case TLS_HANDSHAKE_CONTINUE:
1037 break;
1038 case TLS_HANDSHAKE_SUCCESS:
1039 return 1;
1040 case TLS_HANDSHAKE_ERROR:
1041 case TLS_HANDSHAKE_VERIFY_ERROR:
1042 default:
1043 return -1;
1044 }
1045 } while (TRUE);
1046}
1047
1048int freerdp_tls_connect(rdpTls* tls, BIO* underlying)
1049{
1050 const SSL_METHOD* method = freerdp_tls_get_ssl_method(FALSE, TRUE);
1051
1052 WINPR_ASSERT(tls);
1053 TlsHandshakeResult result = freerdp_tls_connect_ex(tls, underlying, method);
1054 switch (result)
1055 {
1056 case TLS_HANDSHAKE_SUCCESS:
1057 return 1;
1058 case TLS_HANDSHAKE_CONTINUE:
1059 break;
1060 case TLS_HANDSHAKE_ERROR:
1061 case TLS_HANDSHAKE_VERIFY_ERROR:
1062 return -1;
1063 default:
1064 return -1;
1065 }
1066
1067 return pollAndHandshake(tls);
1068}
1069
1070#if defined(MICROSOFT_IOS_SNI_BUG) && !defined(OPENSSL_NO_TLSEXT) && \
1071 !defined(LIBRESSL_VERSION_NUMBER)
1072static void tls_openssl_tlsext_debug_callback(SSL* s, int client_server, int type,
1073 unsigned char* data, int len, void* arg)
1074{
1075 if (type == TLSEXT_TYPE_server_name)
1076 {
1077 WLog_DBG(TAG, "Client uses SNI (extension disabled)");
1078 s->servername_done = 2;
1079 }
1080}
1081#endif
1082
1083BOOL freerdp_tls_accept(rdpTls* tls, BIO* underlying, rdpSettings* settings)
1084{
1085 WINPR_ASSERT(tls);
1086 TlsHandshakeResult res =
1087 freerdp_tls_accept_ex(tls, underlying, settings, freerdp_tls_get_ssl_method(FALSE, FALSE));
1088 switch (res)
1089 {
1090 case TLS_HANDSHAKE_SUCCESS:
1091 return TRUE;
1092 case TLS_HANDSHAKE_CONTINUE:
1093 break;
1094 case TLS_HANDSHAKE_ERROR:
1095 case TLS_HANDSHAKE_VERIFY_ERROR:
1096 default:
1097 return FALSE;
1098 }
1099
1100 return pollAndHandshake(tls) > 0;
1101}
1102
1103TlsHandshakeResult freerdp_tls_accept_ex(rdpTls* tls, BIO* underlying, rdpSettings* settings,
1104 const SSL_METHOD* methods)
1105{
1106 WINPR_ASSERT(tls);
1107
1108 int options = 0;
1109 int status = 0;
1110
1117 options |= SSL_OP_NO_SSLv2;
1127#ifdef SSL_OP_NO_COMPRESSION
1128 options |= SSL_OP_NO_COMPRESSION;
1129#endif
1136 options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
1143 options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
1144
1151#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) && (OPENSSL_VERSION_NUMBER < 0x30000000L) && \
1152 !defined(LIBRESSL_VERSION_NUMBER)
1153 options |= SSL_OP_NO_RENEGOTIATION;
1154#endif
1155
1156 if (!tls_prepare(tls, underlying, methods, options, FALSE))
1157 return TLS_HANDSHAKE_ERROR;
1158
1159 const rdpPrivateKey* key = freerdp_settings_get_pointer(settings, FreeRDP_RdpServerRsaKey);
1160 if (!key)
1161 {
1162 WLog_ERR(TAG, "invalid private key");
1163 return TLS_HANDSHAKE_ERROR;
1164 }
1165
1166 EVP_PKEY* privkey = freerdp_key_get_evp_pkey(key);
1167 if (!privkey)
1168 {
1169 WLog_ERR(TAG, "invalid private key");
1170 return TLS_HANDSHAKE_ERROR;
1171 }
1172
1173 status = SSL_use_PrivateKey(tls->ssl, privkey);
1174 /* The local reference to the private key will anyway go out of
1175 * scope; so the reference count should be decremented weither
1176 * SSL_use_PrivateKey succeeds or fails.
1177 */
1178 EVP_PKEY_free(privkey);
1179
1180 if (status <= 0)
1181 {
1182 WLog_ERR(TAG, "SSL_CTX_use_PrivateKey_file failed");
1183 return TLS_HANDSHAKE_ERROR;
1184 }
1185
1186 rdpCertificate* cert =
1187 freerdp_settings_get_pointer_writable(settings, FreeRDP_RdpServerCertificate);
1188 if (!cert)
1189 {
1190 WLog_ERR(TAG, "invalid certificate");
1191 return TLS_HANDSHAKE_ERROR;
1192 }
1193
1194 status = SSL_use_certificate(tls->ssl, freerdp_certificate_get_x509(cert));
1195
1196 if (status <= 0)
1197 {
1198 WLog_ERR(TAG, "SSL_use_certificate_file failed");
1199 return TLS_HANDSHAKE_ERROR;
1200 }
1201
1202#if defined(MICROSOFT_IOS_SNI_BUG) && !defined(OPENSSL_NO_TLSEXT) && \
1203 !defined(LIBRESSL_VERSION_NUMBER)
1204 SSL_set_tlsext_debug_callback(tls->ssl, tls_openssl_tlsext_debug_callback);
1205#endif
1206
1207 return freerdp_tls_handshake(tls);
1208}
1209
1210BOOL freerdp_tls_send_alert(rdpTls* tls)
1211{
1212 WINPR_ASSERT(tls);
1213
1214 if (!tls)
1215 return FALSE;
1216
1217 if (!tls->ssl)
1218 return TRUE;
1219
1224#if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x10100000L)) || \
1225 (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER <= 0x2080300fL))
1226
1227 if (tls->alertDescription != TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY)
1228 {
1238 SSL_SESSION* ssl_session = SSL_get_session(tls->ssl);
1239 SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(tls->ssl);
1240 SSL_set_quiet_shutdown(tls->ssl, 1);
1241
1242 if ((tls->alertLevel == TLS_ALERT_LEVEL_FATAL) && (ssl_session))
1243 SSL_CTX_remove_session(ssl_ctx, ssl_session);
1244
1245 tls->ssl->s3->alert_dispatch = 1;
1246 tls->ssl->s3->send_alert[0] = tls->alertLevel;
1247 tls->ssl->s3->send_alert[1] = tls->alertDescription;
1248
1249 if (tls->ssl->s3->wbuf.left == 0)
1250 tls->ssl->method->ssl_dispatch_alert(tls->ssl);
1251 }
1252
1253#endif
1254 return TRUE;
1255}
1256
1257int freerdp_tls_write_all(rdpTls* tls, const BYTE* data, size_t length)
1258{
1259 WINPR_ASSERT(tls);
1260 size_t offset = 0;
1261 BIO* bio = tls->bio;
1262
1263 if (length > INT32_MAX)
1264 return -1;
1265
1266 while (offset < length)
1267 {
1268 ERR_clear_error();
1269 const int status = BIO_write(bio, &data[offset], (int)(length - offset));
1270
1271 if (status > 0)
1272 offset += (size_t)status;
1273 else
1274 {
1275 if (!BIO_should_retry(bio))
1276 return -1;
1277
1278 if (BIO_write_blocked(bio))
1279 {
1280 const long rc = BIO_wait_write(bio, 100);
1281 if (rc < 0)
1282 return -1;
1283 }
1284 else if (BIO_read_blocked(bio))
1285 return -2; /* Abort write, there is data that must be read */
1286 else
1287 USleep(100);
1288 }
1289 }
1290
1291 return (int)length;
1292}
1293
1294int freerdp_tls_set_alert_code(rdpTls* tls, int level, int description)
1295{
1296 WINPR_ASSERT(tls);
1297 tls->alertLevel = level;
1298 tls->alertDescription = description;
1299 return 0;
1300}
1301
1302static BOOL tls_match_hostname(const char* pattern, const size_t pattern_length,
1303 const char* hostname)
1304{
1305 if (strlen(hostname) == pattern_length)
1306 {
1307 if (_strnicmp(hostname, pattern, pattern_length) == 0)
1308 return TRUE;
1309 }
1310
1311 if ((pattern_length > 2) && (pattern[0] == '*') && (pattern[1] == '.') &&
1312 ((strlen(hostname)) >= pattern_length))
1313 {
1314 const char* check_hostname = &hostname[strlen(hostname) - pattern_length + 1];
1315
1316 if (_strnicmp(check_hostname, &pattern[1], pattern_length - 1) == 0)
1317 {
1318 return TRUE;
1319 }
1320 }
1321
1322 return FALSE;
1323}
1324
1325static BOOL is_redirected(rdpTls* tls)
1326{
1327 rdpSettings* settings = tls->context->settings;
1328
1329 if (LB_NOREDIRECT & settings->RedirectionFlags)
1330 return FALSE;
1331
1332 return settings->RedirectionFlags != 0;
1333}
1334
1335static BOOL is_accepted(rdpTls* tls, const rdpCertificate* cert)
1336{
1337 WINPR_ASSERT(tls);
1338 WINPR_ASSERT(tls->context);
1339 WINPR_ASSERT(cert);
1340 rdpSettings* settings = tls->context->settings;
1341 WINPR_ASSERT(settings);
1342
1343 FreeRDP_Settings_Keys_String keyAccepted = FreeRDP_AcceptedCert;
1344 FreeRDP_Settings_Keys_UInt32 keyLength = FreeRDP_AcceptedCertLength;
1345
1346 if (tls->isGatewayTransport)
1347 {
1348 keyAccepted = FreeRDP_GatewayAcceptedCert;
1349 keyLength = FreeRDP_GatewayAcceptedCertLength;
1350 }
1351 else if (is_redirected(tls))
1352 {
1353 keyAccepted = FreeRDP_RedirectionAcceptedCert;
1354 keyLength = FreeRDP_RedirectionAcceptedCertLength;
1355 }
1356
1357 const char* AcceptedKey = freerdp_settings_get_string(settings, keyAccepted);
1358 const UINT32 AcceptedKeyLength = freerdp_settings_get_uint32(settings, keyLength);
1359
1360 if ((AcceptedKeyLength > 0) && AcceptedKey)
1361 {
1362 BOOL accepted = FALSE;
1363 size_t pemLength = 0;
1364 char* pem = freerdp_certificate_get_pem_ex(cert, &pemLength, FALSE);
1365 if (pem && (AcceptedKeyLength == pemLength))
1366 {
1367 if (memcmp(AcceptedKey, pem, AcceptedKeyLength) == 0)
1368 accepted = TRUE;
1369 }
1370 free(pem);
1371 if (accepted)
1372 return TRUE;
1373 }
1374
1375 (void)freerdp_settings_set_string(settings, keyAccepted, NULL);
1376 (void)freerdp_settings_set_uint32(settings, keyLength, 0);
1377
1378 return FALSE;
1379}
1380
1381static BOOL compare_fingerprint(const char* fp, const char* hash, const rdpCertificate* cert,
1382 BOOL separator)
1383{
1384 BOOL equal = 0;
1385 char* strhash = NULL;
1386
1387 WINPR_ASSERT(fp);
1388 WINPR_ASSERT(hash);
1389 WINPR_ASSERT(cert);
1390
1391 strhash = freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, separator);
1392 if (!strhash)
1393 return FALSE;
1394
1395 equal = (_stricmp(strhash, fp) == 0);
1396 free(strhash);
1397 return equal;
1398}
1399
1400static BOOL compare_fingerprint_all(const char* fp, const char* hash, const rdpCertificate* cert)
1401{
1402 WINPR_ASSERT(fp);
1403 WINPR_ASSERT(hash);
1404 WINPR_ASSERT(cert);
1405 if (compare_fingerprint(fp, hash, cert, FALSE))
1406 return TRUE;
1407 if (compare_fingerprint(fp, hash, cert, TRUE))
1408 return TRUE;
1409 return FALSE;
1410}
1411
1412static BOOL is_accepted_fingerprint(const rdpCertificate* cert,
1413 const char* CertificateAcceptedFingerprints)
1414{
1415 WINPR_ASSERT(cert);
1416
1417 BOOL rc = FALSE;
1418 if (CertificateAcceptedFingerprints)
1419 {
1420 char* context = NULL;
1421 char* copy = _strdup(CertificateAcceptedFingerprints);
1422 char* cur = strtok_s(copy, ",", &context);
1423 while (cur)
1424 {
1425 char* subcontext = NULL;
1426 const char* h = strtok_s(cur, ":", &subcontext);
1427
1428 if (!h)
1429 goto next;
1430
1431 const char* fp = h + strlen(h) + 1;
1432 if (compare_fingerprint_all(fp, h, cert))
1433 {
1434 rc = TRUE;
1435 break;
1436 }
1437 next:
1438 cur = strtok_s(NULL, ",", &context);
1439 }
1440 free(copy);
1441 }
1442
1443 return rc;
1444}
1445
1446static BOOL accept_cert(rdpTls* tls, const rdpCertificate* cert)
1447{
1448 WINPR_ASSERT(tls);
1449 WINPR_ASSERT(tls->context);
1450 WINPR_ASSERT(cert);
1451
1452 FreeRDP_Settings_Keys_String id = FreeRDP_AcceptedCert;
1453 FreeRDP_Settings_Keys_UInt32 lid = FreeRDP_AcceptedCertLength;
1454
1455 rdpSettings* settings = tls->context->settings;
1456 WINPR_ASSERT(settings);
1457
1458 if (tls->isGatewayTransport)
1459 {
1460 id = FreeRDP_GatewayAcceptedCert;
1461 lid = FreeRDP_GatewayAcceptedCertLength;
1462 }
1463 else if (is_redirected(tls))
1464 {
1465 id = FreeRDP_RedirectionAcceptedCert;
1466 lid = FreeRDP_RedirectionAcceptedCertLength;
1467 }
1468
1469 size_t pemLength = 0;
1470 char* pem = freerdp_certificate_get_pem_ex(cert, &pemLength, FALSE);
1471 BOOL rc = FALSE;
1472 if (pemLength <= UINT32_MAX)
1473 {
1474 if (freerdp_settings_set_string_len(settings, id, pem, pemLength))
1475 rc = freerdp_settings_set_uint32(settings, lid, (UINT32)pemLength);
1476 }
1477 free(pem);
1478 return rc;
1479}
1480
1481static BOOL tls_extract_full_pem(const rdpCertificate* cert, BYTE** PublicKey,
1482 size_t* PublicKeyLength)
1483{
1484 if (!cert || !PublicKey)
1485 return FALSE;
1486 *PublicKey = (BYTE*)freerdp_certificate_get_pem(cert, PublicKeyLength);
1487 return *PublicKey != NULL;
1488}
1489
1490static int tls_config_parse_bool(WINPR_JSON* json, const char* opt)
1491{
1492 WINPR_JSON* val = WINPR_JSON_GetObjectItem(json, opt);
1493 if (!val || !WINPR_JSON_IsBool(val))
1494 return -1;
1495
1496 if (WINPR_JSON_IsTrue(val))
1497 return 1;
1498 return 0;
1499}
1500
1501static char* tls_config_read(const char* configfile)
1502{
1503 char* data = NULL;
1504 FILE* fp = winpr_fopen(configfile, "r");
1505 if (!fp)
1506 return NULL;
1507
1508 const int rc = fseek(fp, 0, SEEK_END);
1509 if (rc != 0)
1510 goto fail;
1511
1512 const INT64 size = _ftelli64(fp);
1513 if (size <= 0)
1514 goto fail;
1515
1516 const int rc2 = fseek(fp, 0, SEEK_SET);
1517 if (rc2 != 0)
1518 goto fail;
1519
1520 data = calloc((size_t)size + 1, sizeof(char));
1521 if (!data)
1522 goto fail;
1523
1524 const size_t read = fread(data, 1, (size_t)size, fp);
1525 if (read != (size_t)size)
1526 {
1527 free(data);
1528 data = NULL;
1529 goto fail;
1530 }
1531
1532fail:
1533 fclose(fp);
1534 return data;
1535}
1536
1537static int tls_config_check_allowed_hashed(const char* configfile, const rdpCertificate* cert,
1538 WINPR_JSON* json)
1539{
1540 WINPR_ASSERT(configfile);
1541 WINPR_ASSERT(cert);
1542 WINPR_ASSERT(json);
1543
1544 WINPR_JSON* db = WINPR_JSON_GetObjectItem(json, "certificate-db");
1545 if (!db || !WINPR_JSON_IsArray(db))
1546 return 0;
1547
1548 for (size_t x = 0; x < WINPR_JSON_GetArraySize(db); x++)
1549 {
1550 WINPR_JSON* cur = WINPR_JSON_GetArrayItem(db, x);
1551 if (!cur || !WINPR_JSON_IsObject(cur))
1552 {
1553 WLog_WARN(TAG,
1554 "[%s] invalid certificate-db entry at position %" PRIuz ": not a JSON object",
1555 configfile, x);
1556 continue;
1557 }
1558
1559 WINPR_JSON* key = WINPR_JSON_GetObjectItem(cur, "type");
1560 if (!key || !WINPR_JSON_IsString(key))
1561 {
1562 WLog_WARN(TAG,
1563 "[%s] invalid certificate-db entry at position %" PRIuz
1564 ": invalid 'type' element, expected type string",
1565 configfile, x);
1566 continue;
1567 }
1568 WINPR_JSON* val = WINPR_JSON_GetObjectItem(cur, "hash");
1569 if (!val || !WINPR_JSON_IsString(val))
1570 {
1571 WLog_WARN(TAG,
1572 "[%s] invalid certificate-db entry at position %" PRIuz
1573 ": invalid 'hash' element, expected type string",
1574 configfile, x);
1575 continue;
1576 }
1577
1578 const char* skey = WINPR_JSON_GetStringValue(key);
1579 const char* sval = WINPR_JSON_GetStringValue(val);
1580
1581 char* hash = freerdp_certificate_get_fingerprint_by_hash_ex(cert, skey, FALSE);
1582 if (!hash)
1583 {
1584 WLog_WARN(TAG,
1585 "[%s] invalid certificate-db entry at position %" PRIuz
1586 ": hash type '%s' not supported by certificate",
1587 configfile, x, skey);
1588 continue;
1589 }
1590
1591 const int cmp = _stricmp(hash, sval);
1592 free(hash);
1593
1594 if (cmp == 0)
1595 return 1;
1596 }
1597
1598 return 0;
1599}
1600
1601static int tls_config_check_certificate(const rdpCertificate* cert, BOOL* pAllowUserconfig)
1602{
1603 WINPR_ASSERT(cert);
1604 WINPR_ASSERT(pAllowUserconfig);
1605
1606 int rc = 0;
1607 char* configfile = freerdp_GetConfigFilePath(TRUE, "certificates.json");
1608 WINPR_JSON* json = NULL;
1609
1610 if (!configfile)
1611 {
1612 WLog_DBG(TAG, "No configuration file for certificate handling, asking user");
1613 goto fail;
1614 }
1615
1616 char* configdata = tls_config_read(configfile);
1617 if (!configdata)
1618 {
1619 WLog_DBG(TAG, "Configuration file for certificate handling, asking user");
1620 goto fail;
1621 }
1622 json = WINPR_JSON_Parse(configdata);
1623 if (!json)
1624 {
1625 WLog_DBG(TAG, "No valid configuration file '%s' for certificate handling, asking user",
1626 configfile);
1627 goto fail;
1628 }
1629
1630 if (tls_config_parse_bool(json, "deny") > 0)
1631 {
1632 WLog_WARN(TAG, "[%s] certificate denied by configuration", configfile);
1633 rc = -1;
1634 goto fail;
1635 }
1636
1637 if (tls_config_parse_bool(json, "ignore") > 0)
1638 {
1639 WLog_WARN(TAG, "[%s] certificate ignored by configuration", configfile);
1640 rc = 1;
1641 goto fail;
1642 }
1643
1644 if (tls_config_check_allowed_hashed(configfile, cert, json) > 0)
1645 {
1646 WLog_WARN(TAG, "[%s] certificate manually accepted by configuration", configfile);
1647 rc = 1;
1648 goto fail;
1649 }
1650
1651 if (tls_config_parse_bool(json, "deny-userconfig") > 0)
1652 {
1653 WLog_WARN(TAG, "[%s] configuration denies user to accept certificates", configfile);
1654 rc = -1;
1655 goto fail;
1656 }
1657
1658fail:
1659
1660 *pAllowUserconfig = (rc == 0);
1661 WINPR_JSON_Delete(json);
1662 free(configfile);
1663 return rc;
1664}
1665
1666int tls_verify_certificate(rdpTls* tls, const rdpCertificate* cert, const char* hostname,
1667 UINT16 port)
1668{
1669 int match = 0;
1670 size_t length = 0;
1671 BOOL certificate_status = 0;
1672 char* common_name = NULL;
1673 size_t common_name_length = 0;
1674 char** dns_names = 0;
1675 size_t dns_names_count = 0;
1676 size_t* dns_names_lengths = NULL;
1677 int verification_status = -1;
1678 BOOL hostname_match = FALSE;
1679 rdpCertificateData* certificate_data = NULL;
1680 BYTE* pemCert = NULL;
1681 DWORD flags = VERIFY_CERT_FLAG_NONE;
1682 freerdp* instance = NULL;
1683
1684 WINPR_ASSERT(tls);
1685 WINPR_ASSERT(tls->context->settings);
1686
1687 instance = (freerdp*)tls->context->settings->instance;
1688 WINPR_ASSERT(instance);
1689
1690 if (freerdp_shall_disconnect_context(instance->context))
1691 return -1;
1692
1693 if (!tls_extract_full_pem(cert, &pemCert, &length))
1694 goto end;
1695
1696 /* Check, if we already accepted this key. */
1697 if (is_accepted(tls, cert))
1698 {
1699 verification_status = 1;
1700 goto end;
1701 }
1702
1703 if (is_accepted_fingerprint(cert, tls->context->settings->CertificateAcceptedFingerprints))
1704 {
1705 verification_status = 1;
1706 goto end;
1707 }
1708
1709 if (tls->isGatewayTransport || is_redirected(tls))
1710 flags |= VERIFY_CERT_FLAG_LEGACY;
1711
1712 if (tls->isGatewayTransport)
1713 flags |= VERIFY_CERT_FLAG_GATEWAY;
1714
1715 if (is_redirected(tls))
1716 flags |= VERIFY_CERT_FLAG_REDIRECT;
1717
1718 /* Certificate management is done by the application */
1719 if (tls->context->settings->ExternalCertificateManagement)
1720 {
1721 if (instance->VerifyX509Certificate)
1722 verification_status =
1723 instance->VerifyX509Certificate(instance, pemCert, length, hostname, port, flags);
1724 else
1725 WLog_ERR(TAG, "No VerifyX509Certificate callback registered!");
1726
1727 if (verification_status > 0)
1728 accept_cert(tls, cert);
1729 else if (verification_status < 0)
1730 {
1731 WLog_ERR(TAG, "VerifyX509Certificate failed: (length = %" PRIuz ") status: [%d] %s",
1732 length, verification_status, pemCert);
1733 goto end;
1734 }
1735 }
1736 /* ignore certificate verification if user explicitly required it (discouraged) */
1737 else if (tls->context->settings->IgnoreCertificate)
1738 verification_status = 1; /* success! */
1739 else if (!tls->isGatewayTransport && (tls->context->settings->AuthenticationLevel == 0))
1740 verification_status = 1; /* success! */
1741 else
1742 {
1743 /* if user explicitly specified a certificate name, use it instead of the hostname */
1744 if (!tls->isGatewayTransport && tls->context->settings->CertificateName)
1745 hostname = tls->context->settings->CertificateName;
1746
1747 /* attempt verification using OpenSSL and the ~/.freerdp/certs certificate store */
1748 certificate_status = freerdp_certificate_verify(
1749 cert, freerdp_certificate_store_get_certs_path(tls->certificate_store));
1750 /* verify certificate name match */
1751 certificate_data = freerdp_certificate_data_new(hostname, port, cert);
1752 if (!certificate_data)
1753 goto end;
1754 /* extra common name and alternative names */
1755 common_name = freerdp_certificate_get_common_name(cert, &common_name_length);
1756 dns_names = freerdp_certificate_get_dns_names(cert, &dns_names_count, &dns_names_lengths);
1757
1758 /* compare against common name */
1759
1760 if (common_name)
1761 {
1762 if (tls_match_hostname(common_name, common_name_length, hostname))
1763 hostname_match = TRUE;
1764 }
1765
1766 /* compare against alternative names */
1767
1768 if (dns_names)
1769 {
1770 for (size_t index = 0; index < dns_names_count; index++)
1771 {
1772 if (tls_match_hostname(dns_names[index], dns_names_lengths[index], hostname))
1773 {
1774 hostname_match = TRUE;
1775 break;
1776 }
1777 }
1778 }
1779
1780 /* if the certificate is valid and the certificate name matches, verification succeeds
1781 */
1782 if (certificate_status && hostname_match)
1783 verification_status = 1; /* success! */
1784
1785 if (!hostname_match)
1786 flags |= VERIFY_CERT_FLAG_MISMATCH;
1787
1788 BOOL allowUserconfig = TRUE;
1789 if (!certificate_status || !hostname_match)
1790 verification_status = tls_config_check_certificate(cert, &allowUserconfig);
1791
1792 /* verification could not succeed with OpenSSL, use known_hosts file and prompt user for
1793 * manual verification */
1794 if (allowUserconfig && (!certificate_status || !hostname_match))
1795 {
1796 DWORD accept_certificate = 0;
1797 size_t pem_length = 0;
1798 char* issuer = freerdp_certificate_get_issuer(cert);
1799 char* subject = freerdp_certificate_get_subject(cert);
1800 char* pem = freerdp_certificate_get_pem(cert, &pem_length);
1801
1802 if (!pem)
1803 goto end;
1804
1805 /* search for matching entry in known_hosts file */
1806 match =
1807 freerdp_certificate_store_contains_data(tls->certificate_store, certificate_data);
1808
1809 if (match == 1)
1810 {
1811 /* no entry was found in known_hosts file, prompt user for manual verification
1812 */
1813 if (!hostname_match)
1814 tls_print_certificate_name_mismatch_error(hostname, port, common_name,
1815 dns_names, dns_names_count);
1816
1817 {
1818 char* efp = freerdp_certificate_get_fingerprint(cert);
1819 tls_print_new_certificate_warn(tls->certificate_store, hostname, port, efp);
1820 free(efp);
1821 }
1822
1823 /* Automatically accept certificate on first use */
1824 if (tls->context->settings->AutoAcceptCertificate)
1825 {
1826 WLog_INFO(TAG, "No certificate stored, automatically accepting.");
1827 accept_certificate = 1;
1828 }
1829 else if (tls->context->settings->AutoDenyCertificate)
1830 {
1831 WLog_INFO(TAG, "No certificate stored, automatically denying.");
1832 accept_certificate = 0;
1833 }
1834 else if (instance->VerifyX509Certificate)
1835 {
1836 int rc = instance->VerifyX509Certificate(instance, pemCert, pem_length,
1837 hostname, port, flags);
1838
1839 if (rc == 1)
1840 accept_certificate = 1;
1841 else if (rc > 1)
1842 accept_certificate = 2;
1843 else
1844 accept_certificate = 0;
1845 }
1846 else if (instance->VerifyCertificateEx)
1847 {
1848 const BOOL use_pem = freerdp_settings_get_bool(
1849 tls->context->settings, FreeRDP_CertificateCallbackPreferPEM);
1850 char* fp = NULL;
1851 DWORD cflags = flags;
1852 if (use_pem)
1853 {
1854 cflags |= VERIFY_CERT_FLAG_FP_IS_PEM;
1855 fp = pem;
1856 }
1857 else
1858 fp = freerdp_certificate_get_fingerprint(cert);
1859 accept_certificate = instance->VerifyCertificateEx(
1860 instance, hostname, port, common_name, subject, issuer, fp, cflags);
1861 if (!use_pem)
1862 free(fp);
1863 }
1864#if defined(WITH_FREERDP_DEPRECATED)
1865 else if (instance->VerifyCertificate)
1866 {
1867 char* fp = freerdp_certificate_get_fingerprint(cert);
1868
1869 WLog_WARN(TAG, "The VerifyCertificate callback is deprecated, migrate your "
1870 "application to VerifyCertificateEx");
1871 accept_certificate = instance->VerifyCertificate(instance, common_name, subject,
1872 issuer, fp, !hostname_match);
1873 free(fp);
1874 }
1875#endif
1876 }
1877 else if (match == -1)
1878 {
1879 rdpCertificateData* stored_data =
1880 freerdp_certificate_store_load_data(tls->certificate_store, hostname, port);
1881 /* entry was found in known_hosts file, but fingerprint does not match. ask user
1882 * to use it */
1883 {
1884 char* efp = freerdp_certificate_get_fingerprint(cert);
1885 tls_print_certificate_error(tls->certificate_store, stored_data, hostname, port,
1886 efp);
1887 free(efp);
1888 }
1889
1890 if (!stored_data)
1891 WLog_WARN(TAG, "Failed to get certificate entry for %s:%" PRIu16 "", hostname,
1892 port);
1893
1894 if (tls->context->settings->AutoDenyCertificate)
1895 {
1896 WLog_INFO(TAG, "No certificate stored, automatically denying.");
1897 accept_certificate = 0;
1898 }
1899 else if (instance->VerifyX509Certificate)
1900 {
1901 const int rc =
1902 instance->VerifyX509Certificate(instance, pemCert, pem_length, hostname,
1903 port, flags | VERIFY_CERT_FLAG_CHANGED);
1904
1905 if (rc == 1)
1906 accept_certificate = 1;
1907 else if (rc > 1)
1908 accept_certificate = 2;
1909 else
1910 accept_certificate = 0;
1911 }
1912 else if (instance->VerifyChangedCertificateEx)
1913 {
1914 DWORD cflags = flags | VERIFY_CERT_FLAG_CHANGED;
1915 const char* old_subject = freerdp_certificate_data_get_subject(stored_data);
1916 const char* old_issuer = freerdp_certificate_data_get_issuer(stored_data);
1917 const char* old_fp = freerdp_certificate_data_get_fingerprint(stored_data);
1918 const char* old_pem = freerdp_certificate_data_get_pem(stored_data);
1919 const BOOL fpIsAllocated =
1920 !old_pem ||
1921 !freerdp_settings_get_bool(tls->context->settings,
1922 FreeRDP_CertificateCallbackPreferPEM);
1923 char* fp = NULL;
1924 if (!fpIsAllocated)
1925 {
1926 cflags |= VERIFY_CERT_FLAG_FP_IS_PEM;
1927 fp = pem;
1928 old_fp = old_pem;
1929 }
1930 else
1931 {
1932 fp = freerdp_certificate_get_fingerprint(cert);
1933 }
1934 accept_certificate = instance->VerifyChangedCertificateEx(
1935 instance, hostname, port, common_name, subject, issuer, fp, old_subject,
1936 old_issuer, old_fp, cflags);
1937 if (fpIsAllocated)
1938 free(fp);
1939 }
1940#if defined(WITH_FREERDP_DEPRECATED)
1941 else if (instance->VerifyChangedCertificate)
1942 {
1943 char* fp = freerdp_certificate_get_fingerprint(cert);
1944 const char* old_subject = freerdp_certificate_data_get_subject(stored_data);
1945 const char* old_issuer = freerdp_certificate_data_get_issuer(stored_data);
1946 const char* old_fingerprint =
1947 freerdp_certificate_data_get_fingerprint(stored_data);
1948
1949 WLog_WARN(TAG, "The VerifyChangedCertificate callback is deprecated, migrate "
1950 "your application to VerifyChangedCertificateEx");
1951 accept_certificate = instance->VerifyChangedCertificate(
1952 instance, common_name, subject, issuer, fp, old_subject, old_issuer,
1953 old_fingerprint);
1954 free(fp);
1955 }
1956#endif
1957
1958 freerdp_certificate_data_free(stored_data);
1959 }
1960 else if (match == 0)
1961 accept_certificate = 2; /* success! */
1962
1963 /* Save certificate or do a simple accept / reject */
1964 switch (accept_certificate)
1965 {
1966 case 1:
1967
1968 /* user accepted certificate, add entry in known_hosts file */
1969 verification_status = freerdp_certificate_store_save_data(
1970 tls->certificate_store, certificate_data)
1971 ? 1
1972 : -1;
1973 break;
1974
1975 case 2:
1976 /* user did accept temporaty, do not add to known hosts file */
1977 verification_status = 1;
1978 break;
1979
1980 default:
1981 /* user did not accept, abort and do not add entry in known_hosts file */
1982 verification_status = -1; /* failure! */
1983 break;
1984 }
1985
1986 free(issuer);
1987 free(subject);
1988 free(pem);
1989 }
1990
1991 if (verification_status > 0)
1992 accept_cert(tls, cert);
1993 }
1994
1995end:
1996 freerdp_certificate_data_free(certificate_data);
1997 free(common_name);
1998 freerdp_certificate_free_dns_names(dns_names_count, dns_names_lengths, dns_names);
1999 free(pemCert);
2000 return verification_status;
2001}
2002
2003void tls_print_new_certificate_warn(rdpCertificateStore* store, const char* hostname, UINT16 port,
2004 const char* fingerprint)
2005{
2006 char* path = freerdp_certificate_store_get_cert_path(store, hostname, port);
2007
2008 WLog_ERR(TAG, "The host key for %s:%" PRIu16 " has changed", hostname, port);
2009 WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
2010 WLog_ERR(TAG, "@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
2011 WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
2012 WLog_ERR(TAG, "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
2013 WLog_ERR(TAG, "Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
2014 WLog_ERR(TAG, "It is also possible that a host key has just been changed.");
2015 WLog_ERR(TAG, "The fingerprint for the host key sent by the remote host is %s", fingerprint);
2016 WLog_ERR(TAG, "Please contact your system administrator.");
2017 WLog_ERR(TAG, "Add correct host key in %s to get rid of this message.", path);
2018 WLog_ERR(TAG, "Host key for %s has changed and you have requested strict checking.", hostname);
2019 WLog_ERR(TAG, "Host key verification failed.");
2020
2021 free(path);
2022}
2023
2024void tls_print_certificate_error(rdpCertificateStore* store,
2025 WINPR_ATTR_UNUSED rdpCertificateData* stored_data,
2026 const char* hostname, UINT16 port, const char* fingerprint)
2027{
2028 char* path = freerdp_certificate_store_get_cert_path(store, hostname, port);
2029
2030 WLog_ERR(TAG, "New host key for %s:%" PRIu16, hostname, port);
2031 WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
2032 WLog_ERR(TAG, "@ WARNING: NEW HOST IDENTIFICATION! @");
2033 WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
2034
2035 WLog_ERR(TAG, "The fingerprint for the host key sent by the remote host is %s", fingerprint);
2036 WLog_ERR(TAG, "Please contact your system administrator.");
2037 WLog_ERR(TAG, "Add correct host key in %s to get rid of this message.", path);
2038
2039 free(path);
2040}
2041
2042void tls_print_certificate_name_mismatch_error(const char* hostname, UINT16 port,
2043 const char* common_name, char** alt_names,
2044 size_t alt_names_count)
2045{
2046 WINPR_ASSERT(NULL != hostname);
2047 WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
2048 WLog_ERR(TAG, "@ WARNING: CERTIFICATE NAME MISMATCH! @");
2049 WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
2050 WLog_ERR(TAG, "The hostname used for this connection (%s:%" PRIu16 ") ", hostname, port);
2051 WLog_ERR(TAG, "does not match %s given in the certificate:",
2052 alt_names_count < 1 ? "the name" : "any of the names");
2053 WLog_ERR(TAG, "Common Name (CN):");
2054 WLog_ERR(TAG, "\t%s", common_name ? common_name : "no CN found in certificate");
2055
2056 if (alt_names_count > 0)
2057 {
2058 WINPR_ASSERT(NULL != alt_names);
2059 WLog_ERR(TAG, "Alternative names:");
2060
2061 for (size_t index = 0; index < alt_names_count; index++)
2062 {
2063 WINPR_ASSERT(alt_names[index]);
2064 WLog_ERR(TAG, "\t %s", alt_names[index]);
2065 }
2066 }
2067
2068 WLog_ERR(TAG, "A valid certificate for the wrong name should NOT be trusted!");
2069}
2070
2071rdpTls* freerdp_tls_new(rdpContext* context)
2072{
2073 rdpTls* tls = NULL;
2074 tls = (rdpTls*)calloc(1, sizeof(rdpTls));
2075
2076 if (!tls)
2077 return NULL;
2078
2079 tls->context = context;
2080
2081 if (!freerdp_settings_get_bool(tls->context->settings, FreeRDP_ServerMode))
2082 {
2083 tls->certificate_store = freerdp_certificate_store_new(tls->context->settings);
2084
2085 if (!tls->certificate_store)
2086 goto out_free;
2087 }
2088
2089 tls->alertLevel = TLS_ALERT_LEVEL_WARNING;
2090 tls->alertDescription = TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY;
2091 return tls;
2092out_free:
2093 free(tls);
2094 return NULL;
2095}
2096
2097void freerdp_tls_free(rdpTls* tls)
2098{
2099 if (!tls)
2100 return;
2101
2102 tls_reset(tls);
2103
2104 if (tls->certificate_store)
2105 {
2106 freerdp_certificate_store_free(tls->certificate_store);
2107 tls->certificate_store = NULL;
2108 }
2109
2110 free(tls);
2111}
WINPR_API WINPR_JSON * WINPR_JSON_GetObjectItem(const WINPR_JSON *object, const char *string)
Return a pointer to an JSON object item.
Definition json.c:183
WINPR_API BOOL WINPR_JSON_IsString(const WINPR_JSON *item)
Check if JSON item is of type String.
Definition json.c:348
WINPR_API BOOL WINPR_JSON_IsBool(const WINPR_JSON *item)
Check if JSON item is of type BOOL.
Definition json.c:311
WINPR_API WINPR_JSON * WINPR_JSON_GetArrayItem(const WINPR_JSON *array, size_t index)
Return a pointer to an item in the array.
Definition json.c:154
WINPR_API BOOL WINPR_JSON_IsObject(const WINPR_JSON *item)
Check if JSON item is of type Object.
Definition json.c:372
WINPR_API const char * WINPR_JSON_GetStringValue(WINPR_JSON *item)
Return the String value of a JSON item.
Definition json.c:233
WINPR_API void WINPR_JSON_Delete(WINPR_JSON *item)
Delete a WinPR JSON wrapper object.
Definition json.c:143
WINPR_API size_t WINPR_JSON_GetArraySize(const WINPR_JSON *array)
Get the number of arrayitems from an array.
Definition json.c:168
WINPR_API BOOL WINPR_JSON_IsArray(const WINPR_JSON *item)
Check if JSON item is of type Array.
Definition json.c:360
WINPR_API WINPR_JSON * WINPR_JSON_Parse(const char *value)
Parse a '\0' terminated JSON string.
Definition json.c:112
WINPR_API BOOL WINPR_JSON_IsTrue(const WINPR_JSON *item)
Check if JSON item is BOOL value True.
Definition json.c:296
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
FREERDP_API BOOL freerdp_settings_set_string_len(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param, size_t len)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.