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