FreeRDP
Loading...
Searching...
No Matches
nla.c
1
25#include <freerdp/config.h>
26
27#include "settings.h"
28
29#include <time.h>
30#include <ctype.h>
31
32#include <freerdp/log.h>
33#include <freerdp/build-config.h>
34
35#include <winpr/crt.h>
36#include <winpr/assert.h>
37#include <winpr/sam.h>
38#include <winpr/sspi.h>
39#include <winpr/print.h>
40#include <winpr/tchar.h>
41#include <winpr/ncrypt.h>
42#include <winpr/cred.h>
43#include <winpr/debug.h>
44#include <winpr/asn1.h>
45#include <winpr/secapi.h>
46#include <winpr/nt.h>
47
48#include "../crypto/tls.h"
49#include "nego.h"
50#include "rdp.h"
51#include "nla.h"
52#include "utils.h"
53#include "credssp_auth.h"
54#include <freerdp/utils/smartcardlogon.h>
55
56#define TAG FREERDP_TAG("core.nla")
57
58#define NLA_AUTH_PKG NEGO_SSP_NAME
59
60typedef enum
61{
62 AUTHZ_SUCCESS = 0x00000000,
63 AUTHZ_ACCESS_DENIED = 0x00000005,
64} AUTHZ_RESULT;
65
109struct rdp_nla
110{
111 BOOL server;
112 NLA_STATE state;
113 ULONG sendSeqNum;
114 ULONG recvSeqNum;
115 rdpContext* rdpcontext;
116 rdpTransport* transport;
117 UINT32 version;
118 UINT32 peerVersion;
119 INT32 errorCode;
120
121 /* Lifetime of buffer nla_new -> nla_free */
122 SecBuffer ClientNonce; /* Depending on protocol version a random nonce or a value read from the
123 server. */
124
125 SecBuffer negoToken;
126 SecBuffer pubKeyAuth;
127 SecBuffer authInfo;
128 SecBuffer PublicKey;
129 SecBuffer tsCredentials;
130
131 SEC_WINNT_AUTH_IDENTITY* identity;
132
133 rdpCredsspAuth* auth;
134 char* pkinitArgs;
135 SmartcardCertInfo* smartcardCert;
136 BYTE certSha1[20];
137 BOOL earlyUserAuth;
138};
139
140WINPR_ATTR_NODISCARD
141static BOOL nla_send(rdpNla* nla);
142
143WINPR_ATTR_NODISCARD
144static int nla_server_recv(rdpNla* nla);
145
146WINPR_ATTR_NODISCARD
147static BOOL nla_encrypt_public_key_echo(rdpNla* nla);
148
149WINPR_ATTR_NODISCARD
150static BOOL nla_encrypt_public_key_hash(rdpNla* nla);
151
152WINPR_ATTR_NODISCARD
153static BOOL nla_decrypt_public_key_echo(rdpNla* nla);
154
155WINPR_ATTR_NODISCARD
156static BOOL nla_decrypt_public_key_hash(rdpNla* nla);
157
158WINPR_ATTR_NODISCARD
159static BOOL nla_encrypt_ts_credentials(rdpNla* nla);
160
161WINPR_ATTR_NODISCARD
162static BOOL nla_decrypt_ts_credentials(rdpNla* nla);
163
164void nla_set_early_user_auth(rdpNla* nla, BOOL earlyUserAuth)
165{
166 WINPR_ASSERT(nla);
167 WLog_DBG(TAG, "Early User Auth active: %s", earlyUserAuth ? "true" : "false");
168 nla->earlyUserAuth = earlyUserAuth;
169}
170
171static void nla_buffer_free(rdpNla* nla)
172{
173 WINPR_ASSERT(nla);
174 sspi_SecBufferFree(&nla->pubKeyAuth);
175 sspi_SecBufferFree(&nla->authInfo);
176 sspi_SecBufferFree(&nla->negoToken);
177 sspi_SecBufferFree(&nla->ClientNonce);
178 sspi_SecBufferFree(&nla->PublicKey);
179}
180
181WINPR_ATTR_NODISCARD
182static BOOL nla_Digest_Update_From_SecBuffer(WINPR_DIGEST_CTX* ctx, const SecBuffer* buffer)
183{
184 if (!buffer)
185 return FALSE;
186 return winpr_Digest_Update(ctx, buffer->pvBuffer, buffer->cbBuffer);
187}
188
189WINPR_ATTR_NODISCARD
190static BOOL nla_sec_buffer_alloc(SecBuffer* buffer, size_t size)
191{
192 WINPR_ASSERT(buffer);
193 sspi_SecBufferFree(buffer);
194 if (size > UINT32_MAX)
195 return FALSE;
196 if (!sspi_SecBufferAlloc(buffer, (ULONG)size))
197 return FALSE;
198
199 WINPR_ASSERT(buffer);
200 buffer->BufferType = SECBUFFER_TOKEN;
201 return TRUE;
202}
203
204WINPR_ATTR_NODISCARD
205static BOOL nla_sec_buffer_alloc_from_data(SecBuffer* buffer, const BYTE* data, size_t offset,
206 size_t size)
207{
208 if (!nla_sec_buffer_alloc(buffer, offset + size))
209 return FALSE;
210
211 WINPR_ASSERT(buffer);
212 BYTE* pb = buffer->pvBuffer;
213 memcpy(&pb[offset], data, size);
214 return TRUE;
215}
216
217/* CredSSP Client-To-Server Binding Hash\0 */
218static const BYTE ClientServerHashMagic[] = { 0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20,
219 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x54,
220 0x6F, 0x2D, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
221 0x20, 0x42, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67,
222 0x20, 0x48, 0x61, 0x73, 0x68, 0x00 };
223
224/* CredSSP Server-To-Client Binding Hash\0 */
225static const BYTE ServerClientHashMagic[] = { 0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20,
226 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2D, 0x54,
227 0x6F, 0x2D, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74,
228 0x20, 0x42, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67,
229 0x20, 0x48, 0x61, 0x73, 0x68, 0x00 };
230
231static const UINT32 NonceLength = 32;
232
233WINPR_ATTR_NODISCARD
234static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
235{
236 BOOL ret = FALSE;
237
238 WINPR_ASSERT(nla);
239 WINPR_ASSERT(nla->rdpcontext);
240
241 rdpSettings* settings = nla->rdpcontext->settings;
242 WINPR_ASSERT(settings);
243
244 if (!settings->SmartcardLogon)
245 return TRUE;
246
247 smartcardCertInfo_Free(nla->smartcardCert);
248
249 if (!smartcard_getCert(nla->rdpcontext, &nla->smartcardCert, FALSE))
250 {
251 WLog_ERR(TAG, "unable to get smartcard certificate for logon");
252 return FALSE;
253 }
254
255 if (!settings->CspName)
256 {
257 /* Use KSP instead of legacy CSP — the CSP does not support ECC keys,
258 * which are common on modern PIV smartcards. The KSP supports both RSA and ECC. */
259 if (!freerdp_settings_set_string_from_utf16(settings, FreeRDP_CspName,
260 MS_SMART_CARD_KEY_STORAGE_PROVIDER))
261 {
262 WLog_ERR(TAG, "unable to set CSP name");
263 goto out;
264 }
265 }
266
267 if (!settings->ReaderName && nla->smartcardCert->reader)
268 {
269 if (!freerdp_settings_set_string_from_utf16(settings, FreeRDP_ReaderName,
270 nla->smartcardCert->reader))
271 {
272 WLog_ERR(TAG, "unable to copy reader name");
273 goto out;
274 }
275 }
276
277 if (!settings->ContainerName && nla->smartcardCert->containerName)
278 {
279 if (!freerdp_settings_set_string_from_utf16(settings, FreeRDP_ContainerName,
280 nla->smartcardCert->containerName))
281 {
282 WLog_ERR(TAG, "unable to copy container name");
283 goto out;
284 }
285 }
286
287 /* KSP uses KeySpec=0 for CNG keys; AT_KEYEXCHANGE is only valid for legacy CSP RSA */
288 if (!freerdp_settings_set_uint32(settings, FreeRDP_KeySpec, 0))
289 {
290 WLog_ERR(TAG, "unable to set KeySpec");
291 goto out;
292 }
293
294 WLog_DBG(TAG, "Smartcard logon: Provider='%s' Reader='%s' Container='%s' KeySpec=%" PRIu32,
295 freerdp_settings_get_string(settings, FreeRDP_CspName),
296 freerdp_settings_get_string(settings, FreeRDP_ReaderName),
297 freerdp_settings_get_string(settings, FreeRDP_ContainerName),
298 freerdp_settings_get_uint32(settings, FreeRDP_KeySpec));
299
300 memcpy(nla->certSha1, nla->smartcardCert->sha1Hash, sizeof(nla->certSha1));
301
302 if (nla->smartcardCert->pkinitArgs)
303 {
304 nla->pkinitArgs = _strdup(nla->smartcardCert->pkinitArgs);
305 if (!nla->pkinitArgs)
306 {
307 WLog_ERR(TAG, "unable to copy pkinitArgs");
308 goto out;
309 }
310 }
311
312 ret = TRUE;
313out:
314 return ret;
315}
316
317WINPR_ATTR_NODISCARD
318static BOOL nla_client_setup_identity(rdpNla* nla)
319{
320 BOOL PromptPassword = FALSE;
321
322 WINPR_ASSERT(nla);
323 WINPR_ASSERT(nla->rdpcontext);
324
325 rdpSettings* settings = nla->rdpcontext->settings;
326 WINPR_ASSERT(settings);
327
328 freerdp* instance = nla->rdpcontext->instance;
329 WINPR_ASSERT(instance);
330
331 /* */
332 if ((utils_str_is_empty(settings->Username) ||
333 (utils_str_is_empty(settings->Password) &&
334 utils_str_is_empty((const char*)settings->RedirectionPassword))))
335 {
336 PromptPassword = TRUE;
337 }
338
339 if (PromptPassword && !utils_str_is_empty(settings->Username))
340 {
341 WINPR_SAM* sam = SamOpen(nullptr, TRUE);
342 if (sam)
343 {
344 const UINT32 userLength = (UINT32)strnlen(settings->Username, INT32_MAX);
345 WINPR_SAM_ENTRY* entry =
346 SamLookupUserA(sam, settings->Username,
347 userLength + 1 /* ensure '\0' is checked too */, nullptr, 0);
348 if (entry)
349 {
354 PromptPassword = FALSE;
355 SamFreeEntry(sam, entry);
356 }
357
358 SamClose(sam);
359 }
360 }
361
362 if (PromptPassword)
363 {
364 if (settings->RestrictedAdminModeRequired)
365 {
366 if ((settings->PasswordHash) && (strlen(settings->PasswordHash) > 0))
367 PromptPassword = FALSE;
368 }
369
370 if (settings->RemoteCredentialGuard)
371 PromptPassword = FALSE;
372 }
373
374 BOOL smartCardLogonWasDisabled = !settings->SmartcardLogon;
375 if (PromptPassword)
376 {
377 switch (utils_authenticate(instance, AUTH_NLA, TRUE))
378 {
379 case AUTH_SKIP:
380 case AUTH_SUCCESS:
381 break;
382 case AUTH_CANCELLED:
383 freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
384 return FALSE;
385 case AUTH_NO_CREDENTIALS:
386 WLog_INFO(TAG, "No credentials provided - using nullptr identity");
387 break;
388 default:
389 return FALSE;
390 }
391 }
392
393 if (!settings->Username)
394 {
395 sspi_FreeAuthIdentity(nla->identity);
396 free(nla->identity);
397 nla->identity = nullptr;
398 }
399 else if (settings->SmartcardLogon)
400 {
401 if (smartCardLogonWasDisabled)
402 {
403 if (!nla_adjust_settings_from_smartcard(nla))
404 return FALSE;
405 }
406
407 if (!identity_set_from_smartcard_hash(nla->identity, settings, FreeRDP_Username,
408 FreeRDP_Domain, FreeRDP_Password, nla->certSha1,
409 sizeof(nla->certSha1)))
410 return FALSE;
411 }
412 else
413 {
414 BOOL usePassword = TRUE;
415
416 if (settings->RedirectionPassword && (settings->RedirectionPasswordLength > 0))
417 {
418 const WCHAR* wstr =
419 WINPR_PACKED_ALIGN_CAST(const WCHAR*, settings->RedirectionPassword);
420 const size_t len = _wcsnlen(wstr, settings->RedirectionPasswordLength / sizeof(WCHAR));
421
422 if (!identity_set_from_settings_with_pwd(nla->identity, settings, FreeRDP_Username,
423 FreeRDP_Domain, wstr, len))
424 return FALSE;
425
426 usePassword = FALSE;
427 }
428
429 if (settings->RestrictedAdminModeRequired)
430 {
431 if (settings->PasswordHash && strnlen(settings->PasswordHash, 33) == 32)
432 {
433 if (!identity_set_from_settings(nla->identity, settings, FreeRDP_Username,
434 FreeRDP_Domain, FreeRDP_PasswordHash))
435 return FALSE;
436
437 nla->identity->Flags |= SEC_WINPR_AUTH_IDENTITY_PASSWORD_HASH;
438 usePassword = FALSE;
439 }
440 }
441
442 if (usePassword)
443 {
444 if (!identity_set_from_settings(nla->identity, settings, FreeRDP_Username,
445 FreeRDP_Domain, FreeRDP_Password))
446 return FALSE;
447 }
448 }
449
450 return TRUE;
451}
452
453WINPR_ATTR_NODISCARD
454static int nla_client_init(rdpNla* nla)
455{
456 WINPR_ASSERT(nla);
457 WINPR_ASSERT(nla->rdpcontext);
458
459 rdpSettings* settings = nla->rdpcontext->settings;
460 WINPR_ASSERT(settings);
461
462 nla_set_state(nla, NLA_STATE_INITIAL);
463
464 if (!nla_adjust_settings_from_smartcard(nla))
465 return -1;
466
467 if (!credssp_auth_init(nla->auth, NLA_AUTH_PKG, nullptr))
468 return -1;
469
470 if (!nla_client_setup_identity(nla))
471 return -1;
472
473 const char* hostname = freerdp_settings_get_server_name(settings);
474
475 if (!credssp_auth_setup_client(nla->auth, "TERMSRV", hostname, nla->identity, nla->pkinitArgs))
476 return -1;
477
478 const BYTE* data = nullptr;
479 DWORD length = 0;
480 if (!transport_get_public_key(nla->transport, &data, &length))
481 {
482 WLog_ERR(TAG, "Failed to get public key");
483 return -1;
484 }
485
486 if (!nla_sec_buffer_alloc_from_data(&nla->PublicKey, data, 0, length))
487 {
488 WLog_ERR(TAG, "Failed to allocate sspi secBuffer");
489 return -1;
490 }
491
492 return 1;
493}
494
495int nla_client_begin(rdpNla* nla)
496{
497 WINPR_ASSERT(nla);
498
499 if (nla_client_init(nla) < 1)
500 return -1;
501
502 if (nla_get_state(nla) != NLA_STATE_INITIAL)
503 return -1;
504
505 /*
506 * from tspkg.dll: 0x00000132
507 * ISC_REQ_MUTUAL_AUTH
508 * ISC_REQ_CONFIDENTIALITY
509 * ISC_REQ_USE_SESSION_KEY
510 * ISC_REQ_ALLOCATE_MEMORY
511 */
512 credssp_auth_set_flags(nla->auth, ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY);
513
514 const int rc = credssp_auth_authenticate(nla->auth);
515
516 switch (rc)
517 {
518 case 0:
519 if (!nla_send(nla))
520 return -1;
521 nla_set_state(nla, NLA_STATE_NEGO_TOKEN);
522 break;
523 case 1:
524 if (credssp_auth_have_output_token(nla->auth))
525 {
526 if (!nla_send(nla))
527 return -1;
528 }
529 nla_set_state(nla, NLA_STATE_FINAL);
530 break;
531 default:
532 switch (credssp_auth_sspi_error(nla->auth))
533 {
534 case SEC_E_LOGON_DENIED:
535 case SEC_E_NO_CREDENTIALS:
536 freerdp_set_last_error_log(nla->rdpcontext,
537 FREERDP_ERROR_CONNECT_LOGON_FAILURE);
538 break;
539 default:
540 break;
541 }
542 return -1;
543 }
544
545 return 1;
546}
547
548WINPR_ATTR_NODISCARD
549static int nla_client_recv_nego_token(rdpNla* nla)
550{
551 credssp_auth_take_input_buffer(nla->auth, &nla->negoToken);
552 const int rc = credssp_auth_authenticate(nla->auth);
553
554 switch (rc)
555 {
556 case 0:
557 if (!nla_send(nla))
558 return -1;
559 break;
560 case 1: /* completed */
561 {
562 int res = -1;
563 if (nla->peerVersion < 5)
564 res = nla_encrypt_public_key_echo(nla);
565 else
566 res = nla_encrypt_public_key_hash(nla);
567
568 if (!res)
569 return -1;
570
571 if (!nla_send(nla))
572 return -1;
573
574 nla_set_state(nla, NLA_STATE_PUB_KEY_AUTH);
575 }
576 break;
577
578 default:
579 return -1;
580 }
581
582 return 1;
583}
584
585WINPR_ATTR_NODISCARD
586static int nla_client_recv_pub_key_auth(rdpNla* nla)
587{
588 BOOL rc = FALSE;
589
590 WINPR_ASSERT(nla);
591
592 /* Verify Server Public Key Echo */
593 if (nla->peerVersion < 5)
594 rc = nla_decrypt_public_key_echo(nla);
595 else
596 rc = nla_decrypt_public_key_hash(nla);
597
598 sspi_SecBufferFree(&nla->pubKeyAuth);
599
600 if (!rc)
601 return -1;
602
603 /* Send encrypted credentials */
604 rc = nla_encrypt_ts_credentials(nla);
605 if (!rc)
606 return -1;
607
608 if (!nla_send(nla))
609 return -1;
610
611 if (nla->earlyUserAuth)
612 {
613 transport_set_early_user_auth_mode(nla->transport, TRUE);
614 nla_set_state(nla, NLA_STATE_EARLY_USER_AUTH);
615 }
616 else
617 nla_set_state(nla, NLA_STATE_AUTH_INFO);
618 return 1;
619}
620
621WINPR_ATTR_NODISCARD
622static int nla_client_recv_early_user_auth(rdpNla* nla)
623{
624 WINPR_ASSERT(nla);
625
626 transport_set_early_user_auth_mode(nla->transport, FALSE);
627 nla_set_state(nla, NLA_STATE_AUTH_INFO);
628 return 1;
629}
630
631WINPR_ATTR_NODISCARD
632static BOOL nla_send_early_user_auth(rdpNla* nla, BOOL success)
633{
634 WINPR_ASSERT(nla);
635
636 BOOL rc = FALSE;
637
638 WINPR_ASSERT(nla);
639
640 WLog_DBG(TAG, "----->> sending %s", success ? "AUTHZ_SUCCESS" : "AUTHZ_ACCESS_DENIED");
641 wStream* s = Stream_New(nullptr, 32);
642 if (!s)
643 goto fail;
644 if (success)
645 Stream_Write_UINT32(s, AUTHZ_SUCCESS);
646 else
647 Stream_Write_UINT32(s, AUTHZ_ACCESS_DENIED);
648 Stream_SealLength(s);
649 WLog_DBG(TAG, "[%" PRIuz " bytes]", Stream_Length(s));
650 if (transport_write(nla->transport, s) < 0)
651 goto fail;
652 rc = TRUE;
653
654fail:
655 Stream_Free(s, TRUE);
656 return rc;
657}
658
659WINPR_ATTR_NODISCARD
660static int nla_client_recv(rdpNla* nla)
661{
662 WINPR_ASSERT(nla);
663
664 switch (nla_get_state(nla))
665 {
666 case NLA_STATE_NEGO_TOKEN:
667 return nla_client_recv_nego_token(nla);
668
669 case NLA_STATE_PUB_KEY_AUTH:
670 return nla_client_recv_pub_key_auth(nla);
671
672 case NLA_STATE_EARLY_USER_AUTH:
673 return nla_client_recv_early_user_auth(nla);
674
675 case NLA_STATE_FINAL:
676 default:
677 WLog_ERR(TAG, "NLA in invalid client receive state %s",
678 nla_get_state_str(nla_get_state(nla)));
679 return -1;
680 }
681}
682
683WINPR_ATTR_NODISCARD
684static int nla_client_authenticate(rdpNla* nla)
685{
686 int rc = -1;
687
688 WINPR_ASSERT(nla);
689
690 wStream* s = Stream_New(nullptr, 4096);
691
692 if (!s)
693 {
694 WLog_ERR(TAG, "Stream_New failed!");
695 return -1;
696 }
697
698 if (nla_client_begin(nla) < 1)
699 goto fail;
700
701 while (nla_get_state(nla) < NLA_STATE_AUTH_INFO)
702 {
703 Stream_ResetPosition(s);
704 const int status = transport_read_pdu(nla->transport, s);
705
706 if (status < 0)
707 {
708 WLog_ERR(TAG, "nla_client_authenticate failure");
709 goto fail;
710 }
711
712 const int status2 = nla_recv_pdu(nla, s);
713
714 if (status2 < 0)
715 goto fail;
716 }
717
718 rc = 1;
719fail:
720 Stream_Free(s, TRUE);
721 return rc;
722}
723
727WINPR_ATTR_NODISCARD
728static int nla_server_init(rdpNla* nla)
729{
730 WINPR_ASSERT(nla);
731
732 const BYTE* data = nullptr;
733 DWORD length = 0;
734 if (!transport_get_public_key(nla->transport, &data, &length))
735 {
736 WLog_ERR(TAG, "Failed to get public key");
737 return -1;
738 }
739
740 if (!nla_sec_buffer_alloc_from_data(&nla->PublicKey, data, 0, length))
741 {
742 WLog_ERR(TAG, "Failed to allocate SecBuffer for public key");
743 return -1;
744 }
745
746 if (!credssp_auth_init(nla->auth, NLA_AUTH_PKG, nullptr))
747 return -1;
748
749 if (!credssp_auth_setup_server(nla->auth))
750 return -1;
751
752 nla_set_state(nla, NLA_STATE_INITIAL);
753 return 1;
754}
755
756WINPR_ATTR_MALLOC(Stream_Free, 1)
757static wStream* nla_server_recv_stream(rdpNla* nla)
758{
759 int status = -1;
760
761 WINPR_ASSERT(nla);
762
763 wStream* s = Stream_New(nullptr, 4096);
764
765 if (!s)
766 goto fail;
767
768 status = transport_read_pdu(nla->transport, s);
769
770fail:
771 if (status < 0)
772 {
773 WLog_ERR(TAG, "nla_recv() error: %d", status);
774 Stream_Free(s, TRUE);
775 return nullptr;
776 }
777
778 return s;
779}
780
781WINPR_ATTR_NODISCARD
782static BOOL nla_server_recv_credentials(rdpNla* nla)
783{
784 WINPR_ASSERT(nla);
785
786 if (nla_server_recv(nla) < 0)
787 return FALSE;
788
789 if (!nla_decrypt_ts_credentials(nla))
790 return FALSE;
791
792 if (!nla_impersonate(nla))
793 return FALSE;
794
795 if (!nla_revert_to_self(nla))
796 return FALSE;
797
798 return TRUE;
799}
800
807WINPR_ATTR_NODISCARD
808static int nla_server_authenticate(rdpNla* nla)
809{
810 int ret = -1;
811
812 WINPR_ASSERT(nla);
813
814 if (nla_server_init(nla) < 1)
815 goto fail;
816
817 /*
818 * from tspkg.dll: 0x00000112
819 * ASC_REQ_MUTUAL_AUTH
820 * ASC_REQ_CONFIDENTIALITY
821 * ASC_REQ_ALLOCATE_MEMORY
822 */
823 credssp_auth_set_flags(nla->auth, ASC_REQ_MUTUAL_AUTH | ASC_REQ_CONFIDENTIALITY |
824 ASC_REQ_CONNECTION | ASC_REQ_USE_SESSION_KEY |
825 ASC_REQ_SEQUENCE_DETECT | ASC_REQ_EXTENDED_ERROR);
826
827 /* Client is starting, here is the state machine:
828 *
829 * -- NLA_STATE_INITIAL --> NLA_STATE_INITIAL
830 * ----->> sending...
831 * ----->> protocol version 6
832 * ----->> nego token
833 * ----->> client nonce
834 * <<----- receiving...
835 * <<----- protocol version 6
836 * <<----- nego token
837 * ----->> sending...
838 * ----->> protocol version 6
839 * ----->> nego token
840 * ----->> public key auth
841 * ----->> client nonce
842 * -- NLA_STATE_NEGO_TOKEN --> NLA_STATE_PUB_KEY_AUTH
843 * <<----- receiving...
844 * <<----- protocol version 6
845 * <<----- public key info
846 * ----->> sending...
847 * ----->> protocol version 6
848 * ----->> auth info
849 * ----->> client nonce
850 * -- NLA_STATE_PUB_KEY_AUTH --> NLA_STATE
851 */
852
853 while (TRUE)
854 {
855 int res = -1;
856
857 if (nla_server_recv(nla) < 0)
858 goto fail;
859
860 WLog_DBG(TAG, "Receiving Authentication Token");
861 credssp_auth_take_input_buffer(nla->auth, &nla->negoToken);
862
863 res = credssp_auth_authenticate(nla->auth);
864
865 if (res == -1)
866 {
867 /* Special handling of these specific error codes as NTSTATUS_FROM_WIN32
868 unfortunately does not map directly to the corresponding NTSTATUS values
869 */
870 switch (GetLastError())
871 {
872 case ERROR_PASSWORD_MUST_CHANGE:
873 nla->errorCode = STATUS_PASSWORD_MUST_CHANGE;
874 break;
875
876 case ERROR_PASSWORD_EXPIRED:
877 nla->errorCode = STATUS_PASSWORD_EXPIRED;
878 break;
879
880 case ERROR_ACCOUNT_DISABLED:
881 nla->errorCode = STATUS_ACCOUNT_DISABLED;
882 break;
883
884 default:
885 {
886 nla->errorCode = STATUS_LOGON_FAILURE;
887 const INT32 sspi = credssp_auth_sspi_error(nla->auth);
888 if (sspi != SEC_E_OK)
889 WLog_DBG(TAG, "[sspi][%s] failed with %s", credssp_auth_pkg_name(nla->auth),
890 GetSecurityStatusString(sspi));
891 }
892 break;
893 }
894
895 (void)nla_send(nla);
896 /* Access Denied */
897 goto fail;
898 }
899
900 if (res == 1)
901 {
902 /* Process final part of the nego token exchange */
903 if (credssp_auth_have_output_token(nla->auth))
904 {
905 if (!nla_send(nla))
906 goto fail;
907
908 if (nla_server_recv(nla) < 0)
909 goto fail;
910
911 WLog_DBG(TAG, "Receiving pubkey Token");
912 }
913
914 if (nla->peerVersion < 5)
915 res = nla_decrypt_public_key_echo(nla);
916 else
917 res = nla_decrypt_public_key_hash(nla);
918
919 if (!res)
920 goto fail;
921
922 /* Clear nego token buffer or we will send it again to the client */
923 sspi_SecBufferFree(&nla->negoToken);
924
925 if (nla->peerVersion < 5)
926 res = nla_encrypt_public_key_echo(nla);
927 else
928 res = nla_encrypt_public_key_hash(nla);
929
930 if (!res)
931 goto fail;
932 }
933
934 /* send authentication token */
935 WLog_DBG(TAG, "Sending Authentication Token");
936
937 if (!nla_send(nla))
938 goto fail;
939
940 if (res == 1)
941 {
942 ret = 1;
943 break;
944 }
945 }
946
947 /* Receive encrypted credentials */
948 if (!nla_server_recv_credentials(nla))
949 ret = -1;
950 else if (nla->earlyUserAuth)
951 {
952 if (!nla_send_early_user_auth(nla, ret == 1))
953 goto fail;
954 }
955
956fail:
957 nla_buffer_free(nla);
958 return ret;
959}
960
968int nla_authenticate(rdpNla* nla)
969{
970 WINPR_ASSERT(nla);
971
972 if (nla->server)
973 return nla_server_authenticate(nla);
974 else
975 return nla_client_authenticate(nla);
976}
977
978static void ap_integer_increment_le(BYTE* number, size_t size)
979{
980 WINPR_ASSERT(number || (size == 0));
981
982 for (size_t index = 0; index < size; index++)
983 {
984 if (number[index] < 0xFF)
985 {
986 number[index]++;
987 break;
988 }
989 else
990 {
991 number[index] = 0;
992 continue;
993 }
994 }
995}
996
997static void ap_integer_decrement_le(BYTE* number, size_t size)
998{
999 WINPR_ASSERT(number || (size == 0));
1000
1001 for (size_t index = 0; index < size; index++)
1002 {
1003 if (number[index] > 0)
1004 {
1005 number[index]--;
1006 break;
1007 }
1008 else
1009 {
1010 number[index] = 0xFF;
1011 continue;
1012 }
1013 }
1014}
1015
1016BOOL nla_encrypt_public_key_echo(rdpNla* nla)
1017{
1018 BOOL status = FALSE;
1019
1020 WINPR_ASSERT(nla);
1021
1022 sspi_SecBufferFree(&nla->pubKeyAuth);
1023 if (nla->server)
1024 {
1025 SecBuffer buf = WINPR_C_ARRAY_INIT;
1026 if (!sspi_SecBufferAlloc(&buf, nla->PublicKey.cbBuffer))
1027 return FALSE;
1028 ap_integer_increment_le(buf.pvBuffer, buf.cbBuffer);
1029 status =
1030 credssp_auth_encrypt(nla->auth, &buf, &nla->pubKeyAuth, nullptr, nla->sendSeqNum++);
1031 sspi_SecBufferFree(&buf);
1032 }
1033 else
1034 {
1035 status = credssp_auth_encrypt(nla->auth, &nla->PublicKey, &nla->pubKeyAuth, nullptr,
1036 nla->sendSeqNum++);
1037 }
1038
1039 return status;
1040}
1041
1042BOOL nla_encrypt_public_key_hash(rdpNla* nla)
1043{
1044 BOOL status = FALSE;
1045 WINPR_DIGEST_CTX* sha256 = nullptr;
1046 SecBuffer buf = WINPR_C_ARRAY_INIT;
1047
1048 WINPR_ASSERT(nla);
1049
1050 const BYTE* hashMagic = nla->server ? ServerClientHashMagic : ClientServerHashMagic;
1051 const size_t hashSize =
1052 nla->server ? sizeof(ServerClientHashMagic) : sizeof(ClientServerHashMagic);
1053
1054 if (!sspi_SecBufferAlloc(&buf, WINPR_SHA256_DIGEST_LENGTH))
1055 return FALSE;
1056
1057 /* generate SHA256 of following data: ClientServerHashMagic, Nonce, SubjectPublicKey */
1058 if (!(sha256 = winpr_Digest_New()))
1059 goto out;
1060
1061 if (!winpr_Digest_Init(sha256, WINPR_MD_SHA256))
1062 goto out;
1063
1064 /* include trailing \0 from hashMagic */
1065 if (!winpr_Digest_Update(sha256, hashMagic, hashSize))
1066 goto out;
1067
1068 if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->ClientNonce))
1069 goto out;
1070
1071 /* SubjectPublicKey */
1072 if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->PublicKey))
1073 goto out;
1074
1075 if (!winpr_Digest_Final(sha256, buf.pvBuffer, WINPR_SHA256_DIGEST_LENGTH))
1076 goto out;
1077
1078 sspi_SecBufferFree(&nla->pubKeyAuth);
1079 if (!credssp_auth_encrypt(nla->auth, &buf, &nla->pubKeyAuth, nullptr, nla->sendSeqNum++))
1080 goto out;
1081
1082 status = TRUE;
1083
1084out:
1085 winpr_Digest_Free(sha256);
1086 sspi_SecBufferFree(&buf);
1087 return status;
1088}
1089
1090BOOL nla_decrypt_public_key_echo(rdpNla* nla)
1091{
1092 BOOL status = FALSE;
1093 SecBuffer public_key = WINPR_C_ARRAY_INIT;
1094
1095 if (!nla)
1096 goto fail;
1097
1098 if (!credssp_auth_decrypt(nla->auth, &nla->pubKeyAuth, &public_key, nla->recvSeqNum++))
1099 return FALSE;
1100
1101 if (!nla->server)
1102 {
1103 /* server echos the public key +1 */
1104 ap_integer_decrement_le(public_key.pvBuffer, public_key.cbBuffer);
1105 }
1106
1107 if (public_key.cbBuffer != nla->PublicKey.cbBuffer ||
1108 memcmp(public_key.pvBuffer, nla->PublicKey.pvBuffer, public_key.cbBuffer) != 0)
1109 {
1110 WLog_ERR(TAG, "Could not verify server's public key echo");
1111#if defined(WITH_DEBUG_NLA)
1112 WLog_ERR(TAG, "Expected (length = %" PRIu32 "):", nla->PublicKey.cbBuffer);
1113 winpr_HexDump(TAG, WLOG_ERROR, nla->PublicKey.pvBuffer, nla->PublicKey.cbBuffer);
1114 WLog_ERR(TAG, "Actual (length = %" PRIu32 "):", public_key.cbBuffer);
1115 winpr_HexDump(TAG, WLOG_ERROR, public_key.pvBuffer, public_key.cbBuffer);
1116#endif
1117 /* DO NOT SEND CREDENTIALS! */
1118 goto fail;
1119 }
1120
1121 status = TRUE;
1122fail:
1123 sspi_SecBufferFree(&public_key);
1124 return status;
1125}
1126
1127BOOL nla_decrypt_public_key_hash(rdpNla* nla)
1128{
1129 WINPR_DIGEST_CTX* sha256 = nullptr;
1130 BYTE serverClientHash[WINPR_SHA256_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1131 BOOL status = FALSE;
1132
1133 WINPR_ASSERT(nla);
1134
1135 const BYTE* hashMagic = nla->server ? ClientServerHashMagic : ServerClientHashMagic;
1136 const size_t hashSize =
1137 nla->server ? sizeof(ClientServerHashMagic) : sizeof(ServerClientHashMagic);
1138 SecBuffer hash = WINPR_C_ARRAY_INIT;
1139
1140 if (!credssp_auth_decrypt(nla->auth, &nla->pubKeyAuth, &hash, nla->recvSeqNum++))
1141 return FALSE;
1142
1143 /* generate SHA256 of following data: ServerClientHashMagic, Nonce, SubjectPublicKey */
1144 if (!(sha256 = winpr_Digest_New()))
1145 goto fail;
1146
1147 if (!winpr_Digest_Init(sha256, WINPR_MD_SHA256))
1148 goto fail;
1149
1150 /* include trailing \0 from hashMagic */
1151 if (!winpr_Digest_Update(sha256, hashMagic, hashSize))
1152 goto fail;
1153
1154 if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->ClientNonce))
1155 goto fail;
1156
1157 /* SubjectPublicKey */
1158 if (!nla_Digest_Update_From_SecBuffer(sha256, &nla->PublicKey))
1159 goto fail;
1160
1161 if (!winpr_Digest_Final(sha256, serverClientHash, sizeof(serverClientHash)))
1162 goto fail;
1163
1164 /* verify hash */
1165 if (hash.cbBuffer != WINPR_SHA256_DIGEST_LENGTH ||
1166 memcmp(serverClientHash, hash.pvBuffer, WINPR_SHA256_DIGEST_LENGTH) != 0)
1167 {
1168 WLog_ERR(TAG, "Could not verify server's hash");
1169 /* DO NOT SEND CREDENTIALS! */
1170 goto fail;
1171 }
1172
1173 status = TRUE;
1174fail:
1175 winpr_Digest_Free(sha256);
1176 sspi_SecBufferFree(&hash);
1177 return status;
1178}
1179
1180WINPR_ATTR_NODISCARD
1181static BOOL set_creds_octetstring_to_settings(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
1182 BOOL optional, FreeRDP_Settings_Keys_String settingId,
1183 rdpSettings* settings)
1184{
1185 if (optional)
1186 {
1187 WinPrAsn1_tagId itemTag = 0;
1188 if (!WinPrAsn1DecPeekTag(dec, &itemTag) || (itemTag != (ER_TAG_CONTEXTUAL | tagId)))
1189 return TRUE;
1190 }
1191
1192 BOOL error = FALSE;
1193 WinPrAsn1_OctetString value = WINPR_C_ARRAY_INIT;
1194 /* note: not checking "error" value, as the not present optional item case is handled above
1195 * if the function fails it's because of a real error not because the item is not present
1196 */
1197 if (!WinPrAsn1DecReadContextualOctetString(dec, tagId, &error, &value, TRUE))
1198 return FALSE;
1199
1201 settings, settingId, WINPR_PACKED_ALIGN_CAST(const WCHAR*, value.data),
1202 value.len / sizeof(WCHAR));
1203 free(value.data);
1204 return rc;
1205}
1206
1207WINPR_ATTR_NODISCARD
1208static BOOL nla_read_TSCspDataDetail(WinPrAsn1Decoder* dec, rdpSettings* settings)
1209{
1210 BOOL error = FALSE;
1211
1212 /* keySpec [0] INTEGER */
1213 WinPrAsn1_INTEGER keyspec = 0;
1214 if (!WinPrAsn1DecReadContextualInteger(dec, 0, &error, &keyspec))
1215 return FALSE;
1216 settings->KeySpec = (UINT32)keyspec;
1217
1218 /* cardName [1] OCTET STRING OPTIONAL */
1219 if (!set_creds_octetstring_to_settings(dec, 1, TRUE, FreeRDP_CardName, settings))
1220 return FALSE;
1221
1222 /* readerName [2] OCTET STRING OPTIONAL */
1223 if (!set_creds_octetstring_to_settings(dec, 2, TRUE, FreeRDP_ReaderName, settings))
1224 return FALSE;
1225
1226 /* containerName [3] OCTET STRING OPTIONAL */
1227 if (!set_creds_octetstring_to_settings(dec, 3, TRUE, FreeRDP_ContainerName, settings))
1228 return FALSE;
1229
1230 /* cspName [4] OCTET STRING OPTIONAL */
1231 return set_creds_octetstring_to_settings(dec, 4, TRUE, FreeRDP_CspName, settings);
1232}
1233
1234WINPR_ATTR_NODISCARD
1235static BOOL nla_messageTypeValid(UINT32 type)
1236{
1237 switch (type)
1238 {
1239 case KerbInvalidValue:
1240 case KerbInteractiveLogon:
1241 case KerbSmartCardLogon:
1242 case KerbWorkstationUnlockLogon:
1243 case KerbSmartCardUnlockLogon:
1244 case KerbProxyLogon:
1245 case KerbTicketLogon:
1246 case KerbTicketUnlockLogon:
1247#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0501)
1248 case KerbS4ULogon:
1249#endif
1250#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600)
1251 case KerbCertificateLogon:
1252 case KerbCertificateS4ULogon:
1253 case KerbCertificateUnlockLogon:
1254#endif
1255#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0602)
1256 case KerbNoElevationLogon:
1257 case KerbLuidLogon:
1258#endif
1259 return TRUE;
1260 default:
1261 WLog_ERR(TAG, "Invalid message type %" PRIu32, type);
1262 return FALSE;
1263 }
1264}
1265
1266WINPR_ATTR_NODISCARD
1267static BOOL nla_read_KERB_TICKET_LOGON(WINPR_ATTR_UNUSED rdpNla* nla, wStream* s,
1268 KERB_TICKET_LOGON* ticket)
1269{
1270 WINPR_ASSERT(nla);
1271
1272 if (!ticket)
1273 return FALSE;
1274
1275 /* mysterious extra 16 bytes before TGS/TGT content */
1276 if (!Stream_CheckAndLogRequiredLength(TAG, s, 16 + 16))
1277 return FALSE;
1278
1279 {
1280 const UINT32 type = Stream_Get_UINT32(s);
1281 if (!nla_messageTypeValid(type))
1282 return FALSE;
1283
1284 ticket->MessageType = (KERB_LOGON_SUBMIT_TYPE)type;
1285 }
1286 Stream_Read_UINT32(s, ticket->Flags);
1287 Stream_Read_UINT32(s, ticket->ServiceTicketLength);
1288 Stream_Read_UINT32(s, ticket->TicketGrantingTicketLength);
1289
1290 if (ticket->MessageType != KerbTicketLogon)
1291 {
1292 WLog_ERR(TAG, "Not a KerbTicketLogon");
1293 return FALSE;
1294 }
1295
1296 if (!Stream_CheckAndLogRequiredLength(
1297 TAG, s, 16ull + ticket->ServiceTicketLength + ticket->TicketGrantingTicketLength))
1298 return FALSE;
1299
1300 /* mysterious 16 bytes in the way, maybe they would need to be interpreted... */
1301 Stream_Seek(s, 16);
1302
1303 /*WLog_INFO(TAG, "TGS");
1304 winpr_HexDump(TAG, WLOG_DEBUG, Stream_PointerAs(s, const BYTE), ticket->ServiceTicketLength);*/
1305 ticket->ServiceTicket = Stream_PointerAs(s, UCHAR);
1306 Stream_Seek(s, ticket->ServiceTicketLength);
1307
1308 /*WLog_INFO(TAG, "TGT");
1309 winpr_HexDump(TAG, WLOG_DEBUG, Stream_PointerAs(s, const BYTE),
1310 ticket->TicketGrantingTicketLength);*/
1311 ticket->TicketGrantingTicket = Stream_PointerAs(s, UCHAR);
1312 return TRUE;
1313}
1314
1315WINPR_ATTR_NODISCARD
1316static BOOL nla_credentialTypeValid(UINT32 type)
1317{
1318 switch (type)
1319 {
1320 case InvalidCredKey:
1321 case DeprecatedIUMCredKey:
1322 case DomainUserCredKey:
1323 case LocalUserCredKey:
1324 case ExternallySuppliedCredKey:
1325 return TRUE;
1326 default:
1327 WLog_ERR(TAG, "Invalid credential type %" PRIu32, type);
1328 return FALSE;
1329 }
1330}
1331
1332WINPR_ATTR_MALLOC(free, 1)
1333static MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* nla_read_NtlmCreds(WINPR_ATTR_UNUSED rdpNla* nla,
1334 wStream* s)
1335{
1336 WINPR_ASSERT(nla);
1337 WINPR_ASSERT(s);
1338
1339 if (!Stream_CheckAndLogRequiredLength(TAG, s, 32 + 4))
1340 return nullptr;
1341
1342 size_t pos = Stream_GetPosition(s);
1343 Stream_Seek(s, 32);
1344
1345 ULONG EncryptedCredsSize = Stream_Get_UINT32(s);
1346 if (!Stream_CheckAndLogRequiredLength(TAG, s, EncryptedCredsSize))
1347 return nullptr;
1348
1349 if (!Stream_SetPosition(s, pos))
1350 return nullptr;
1351
1353 1, sizeof(MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL) - 1 + EncryptedCredsSize);
1354 if (!ret)
1355 return nullptr;
1356
1357 ret->Version = Stream_Get_UINT32(s);
1358 ret->Flags = Stream_Get_UINT32(s);
1359 Stream_Read(s, ret->CredentialKey.Data, MSV1_0_CREDENTIAL_KEY_LENGTH);
1360 {
1361 const UINT32 val = Stream_Get_UINT32(s);
1362 if (!nla_credentialTypeValid(val))
1363 {
1364 free(ret);
1365 return nullptr;
1366 }
1367 ret->CredentialKeyType = WINPR_ASSERTING_INT_CAST(MSV1_0_CREDENTIAL_KEY_TYPE, val);
1368 }
1369 ret->EncryptedCredsSize = EncryptedCredsSize;
1370 Stream_Read(s, ret->EncryptedCreds, EncryptedCredsSize);
1371
1372 return ret;
1373}
1374
1376typedef enum
1377{
1378 RCG_TYPE_NONE,
1379 RCG_TYPE_KERB,
1380 RCG_TYPE_NTLM
1381} RemoteGuardPackageCredType;
1382
1383WINPR_ATTR_NODISCARD
1384static BOOL nla_read_TSRemoteGuardPackageCred(WINPR_ATTR_UNUSED rdpNla* nla, WinPrAsn1Decoder* dec,
1385 RemoteGuardPackageCredType* credsType,
1386 wStream* payload)
1387{
1388 WinPrAsn1_OctetString credBuffer = WINPR_C_ARRAY_INIT;
1389 BOOL error = FALSE;
1390 char packageNameStr[100] = WINPR_C_ARRAY_INIT;
1391
1392 WINPR_ASSERT(nla);
1393 WINPR_ASSERT(dec);
1394 WINPR_ASSERT(credsType);
1395 WINPR_ASSERT(payload);
1396
1397 *credsType = RCG_TYPE_NONE;
1398
1399 /* packageName [0] OCTET STRING */
1400 {
1401 WinPrAsn1_OctetString packageName = WINPR_C_ARRAY_INIT;
1402 if (!WinPrAsn1DecReadContextualOctetString(dec, 0, &error, &packageName, TRUE) || error)
1403 return FALSE;
1404
1405 ConvertMszWCharNToUtf8(WINPR_PACKED_ALIGN_CAST(WCHAR*, packageName.data),
1406 packageName.len / sizeof(WCHAR), packageNameStr,
1407 sizeof(packageNameStr));
1408 free(packageName.data);
1409 }
1410 WLog_DBG(TAG, "TSRemoteGuardPackageCred(%s)", packageNameStr);
1411
1412 /* credBuffer [1] OCTET STRING, */
1413 if (!WinPrAsn1DecReadContextualOctetString(dec, 1, &error, &credBuffer, FALSE) || error)
1414 return FALSE;
1415
1416 if (_stricmp(packageNameStr, "Kerberos") == 0)
1417 {
1418 *credsType = RCG_TYPE_KERB;
1419 }
1420 else if (_stricmp(packageNameStr, "NTLM") == 0)
1421 {
1422 *credsType = RCG_TYPE_NTLM;
1423 }
1424 else
1425 {
1426 WLog_INFO(TAG, "TSRemoteGuardPackageCred package %s not handled", packageNameStr);
1427 return FALSE;
1428 }
1429
1430 Stream_StaticInit(payload, credBuffer.data, credBuffer.len);
1431 return TRUE;
1432}
1433
1435typedef enum
1436{
1437 TSCREDS_INVALID = 0,
1438 TSCREDS_USER_PASSWD = 1,
1439 TSCREDS_SMARTCARD = 2,
1440 TSCREDS_REMOTEGUARD = 6
1441} TsCredentialsType;
1442
1443WINPR_ATTR_NODISCARD
1444static BOOL nla_read_ts_credentials(rdpNla* nla, SecBuffer* data)
1445{
1446 WinPrAsn1Decoder dec = WinPrAsn1Decoder_init();
1447 WinPrAsn1Decoder dec2 = WinPrAsn1Decoder_init();
1448 WinPrAsn1_OctetString credentials = WINPR_C_ARRAY_INIT;
1449 BOOL error = FALSE;
1450 WinPrAsn1_INTEGER credType = -1;
1451 BOOL ret = TRUE;
1452
1453 WINPR_ASSERT(nla);
1454 WINPR_ASSERT(data);
1455
1456 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, (BYTE*)data->pvBuffer, data->cbBuffer);
1457
1458 /* TSCredentials */
1459 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1460 return FALSE;
1461 dec = dec2;
1462
1463 /* credType [0] INTEGER */
1464 if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &credType))
1465 return FALSE;
1466
1467 /* credentials [1] OCTET STRING */
1468 if (!WinPrAsn1DecReadContextualOctetString(&dec, 1, &error, &credentials, FALSE))
1469 return FALSE;
1470
1471 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, credentials.data, credentials.len);
1472
1473 rdpSettings* settings = nla->rdpcontext->settings;
1474 if (nego_get_remoteCredentialGuard(nla->rdpcontext->rdp->nego) &&
1475 credType != TSCREDS_REMOTEGUARD)
1476 {
1477 WLog_ERR(TAG, "connecting with RCG but it's not TSRemoteGuard credentials");
1478 return FALSE;
1479 }
1480
1481 switch (credType)
1482 {
1483 case TSCREDS_USER_PASSWD:
1484 {
1485 /* TSPasswordCreds */
1486 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1487 return FALSE;
1488 dec = dec2;
1489
1490 /* domainName [0] OCTET STRING */
1491 if (!set_creds_octetstring_to_settings(&dec, 0, FALSE, FreeRDP_Domain, settings))
1492 return FALSE;
1493
1494 /* userName [1] OCTET STRING */
1495 if (!set_creds_octetstring_to_settings(&dec, 1, FALSE, FreeRDP_Username, settings))
1496 return FALSE;
1497
1498 /* password [2] OCTET STRING */
1499 return set_creds_octetstring_to_settings(&dec, 2, FALSE, FreeRDP_Password, settings);
1500 }
1501 case TSCREDS_SMARTCARD:
1502 {
1503 /* TSSmartCardCreds */
1504 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1505 return FALSE;
1506 dec = dec2;
1507
1508 /* pin [0] OCTET STRING, */
1509 if (!set_creds_octetstring_to_settings(&dec, 0, FALSE, FreeRDP_Password, settings))
1510 return FALSE;
1511 settings->PasswordIsSmartcardPin = TRUE;
1512
1513 /* cspData [1] TSCspDataDetail */
1514 WinPrAsn1Decoder cspDetails = WinPrAsn1Decoder_init();
1515 if (!WinPrAsn1DecReadContextualSequence(&dec, 1, &error, &cspDetails) && error)
1516 return FALSE;
1517 if (!nla_read_TSCspDataDetail(&cspDetails, settings))
1518 return FALSE;
1519
1520 /* userHint [2] OCTET STRING OPTIONAL */
1521 if (!set_creds_octetstring_to_settings(&dec, 2, TRUE, FreeRDP_Username, settings))
1522 return FALSE;
1523
1524 /* domainHint [3] OCTET STRING OPTIONAL */
1525 return set_creds_octetstring_to_settings(&dec, 3, TRUE, FreeRDP_Domain, settings);
1526 }
1527 case TSCREDS_REMOTEGUARD:
1528 {
1529 /* TSRemoteGuardCreds */
1530 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1531 return FALSE;
1532
1533 /* logonCred[0] TSRemoteGuardPackageCred */
1534 KERB_TICKET_LOGON kerbLogon = { .MessageType = KerbInvalidValue,
1535 .Flags = 0,
1536 .ServiceTicketLength = 0,
1537 .TicketGrantingTicketLength = 0,
1538 .ServiceTicket = nullptr,
1539 .TicketGrantingTicket = nullptr };
1540
1541 WinPrAsn1Decoder logonCredsSeq = WinPrAsn1Decoder_init();
1542
1543 if (!WinPrAsn1DecReadContextualSequence(&dec2, 0, &error, &logonCredsSeq) || error)
1544 return FALSE;
1545
1546 RemoteGuardPackageCredType logonCredsType = RCG_TYPE_NONE;
1547 wStream logonPayload = WINPR_C_ARRAY_INIT;
1548 if (!nla_read_TSRemoteGuardPackageCred(nla, &logonCredsSeq, &logonCredsType,
1549 &logonPayload))
1550 return FALSE;
1551 if (logonCredsType != RCG_TYPE_KERB)
1552 {
1553 WLog_ERR(TAG, "logonCred must be some Kerberos creds");
1554 return FALSE;
1555 }
1556
1557 if (!nla_read_KERB_TICKET_LOGON(nla, &logonPayload, &kerbLogon))
1558 {
1559 WLog_ERR(TAG, "invalid KERB_TICKET_LOGON");
1560 return FALSE;
1561 }
1562
1563 /* supplementalCreds [1] SEQUENCE OF TSRemoteGuardPackageCred OPTIONAL, */
1564 MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* suppCreds = nullptr;
1565 WinPrAsn1Decoder suppCredsSeq = WinPrAsn1Decoder_init();
1566
1567 if (WinPrAsn1DecReadContextualSequence(&dec2, 1, &error, &suppCredsSeq) &&
1568 Stream_GetRemainingLength(&suppCredsSeq.source))
1569 {
1570 WinPrAsn1Decoder ntlmCredsSeq = WinPrAsn1Decoder_init();
1571 if (!WinPrAsn1DecReadSequence(&suppCredsSeq, &ntlmCredsSeq))
1572 return FALSE;
1573
1574 RemoteGuardPackageCredType suppCredsType = RCG_TYPE_NONE;
1575 wStream ntlmPayload = WINPR_C_ARRAY_INIT;
1576 if (!nla_read_TSRemoteGuardPackageCred(nla, &ntlmCredsSeq, &suppCredsType,
1577 &ntlmPayload))
1578 return FALSE;
1579
1580 if (suppCredsType != RCG_TYPE_NTLM)
1581 {
1582 WLog_ERR(TAG, "supplementalCreds must be some NTLM creds");
1583 return FALSE;
1584 }
1585
1586 suppCreds = nla_read_NtlmCreds(nla, &ntlmPayload);
1587 if (!suppCreds)
1588 {
1589 WLog_ERR(TAG, "invalid supplementalCreds");
1590 return FALSE;
1591 }
1592 }
1593 else if (error)
1594 {
1595 WLog_ERR(TAG, "invalid supplementalCreds");
1596 return FALSE;
1597 }
1598
1599 freerdp_peer* peer = nla->rdpcontext->peer;
1600 ret = IFCALLRESULT(TRUE, peer->RemoteCredentials, peer, &kerbLogon, suppCreds);
1601 free(suppCreds);
1602 break;
1603 }
1604 default:
1605 WLog_DBG(TAG, "TSCredentials type %d not supported for now", credType);
1606 ret = FALSE;
1607 break;
1608 }
1609
1610 return ret;
1611}
1612
1613WINPR_ATTR_NODISCARD
1614static BOOL nla_write_KERB_TICKET_LOGON(wStream* s, const KERB_TICKET_LOGON* ticket)
1615{
1616 WINPR_ASSERT(ticket);
1617
1618 if (!Stream_EnsureRemainingCapacity(s, (4ULL * 4ull) + 16ULL + ticket->ServiceTicketLength +
1619 ticket->TicketGrantingTicketLength))
1620 return FALSE;
1621
1622 Stream_Write_UINT32(s, KerbTicketLogon);
1623 Stream_Write_UINT32(s, ticket->Flags);
1624 Stream_Write_UINT32(s, ticket->ServiceTicketLength);
1625 Stream_Write_UINT32(s, ticket->TicketGrantingTicketLength);
1626
1627 Stream_Write_UINT64(s, 0x20); /* offset of TGS in the packet */
1628 Stream_Write_UINT64(s, 0x20 + ticket->ServiceTicketLength); /* offset of TGT in packet */
1629
1630 Stream_Write(s, ticket->ServiceTicket, ticket->ServiceTicketLength);
1631 Stream_Write(s, ticket->TicketGrantingTicket, ticket->TicketGrantingTicketLength);
1632 return TRUE;
1633}
1634
1635WINPR_ATTR_NODISCARD
1636static BOOL nla_get_KERB_TICKET_LOGON(rdpNla* nla, KERB_TICKET_LOGON* logonTicket)
1637{
1638 WINPR_ASSERT(nla);
1639 WINPR_ASSERT(logonTicket);
1640
1641 SecurityFunctionTable* table = nullptr;
1642 CtxtHandle context = WINPR_C_ARRAY_INIT;
1643 credssp_auth_tableAndContext(nla->auth, &table, &context);
1644 return table->QueryContextAttributes(&context, SECPKG_CRED_ATTR_TICKET_LOGON, logonTicket) ==
1645 SEC_E_OK;
1646}
1647
1648WINPR_ATTR_NODISCARD
1649static BOOL nla_write_TSRemoteGuardKerbCred(rdpNla* nla, WinPrAsn1Encoder* enc)
1650{
1651 BOOL ret = FALSE;
1652 wStream* s = nullptr;
1653 char kerberos[] = { 'K', '\0', 'e', '\0', 'r', '\0', 'b', '\0',
1654 'e', '\0', 'r', '\0', 'o', '\0', 's', '\0' };
1655 WinPrAsn1_OctetString packageName = { sizeof(kerberos), (BYTE*)kerberos };
1656 WinPrAsn1_OctetString credBuffer;
1657 KERB_TICKET_LOGON logonTicket;
1658
1659 logonTicket.ServiceTicket = nullptr;
1660 logonTicket.TicketGrantingTicket = nullptr;
1661
1662 /* packageName [0] OCTET STRING */
1663 if (!WinPrAsn1EncContextualOctetString(enc, 0, &packageName))
1664 goto out;
1665
1666 /* credBuffer [1] OCTET STRING */
1667 if (!nla_get_KERB_TICKET_LOGON(nla, &logonTicket))
1668 goto out;
1669
1670 s = Stream_New(nullptr, 2000);
1671 if (!s)
1672 goto out;
1673
1674 if (!nla_write_KERB_TICKET_LOGON(s, &logonTicket))
1675 goto out;
1676
1677 credBuffer.len = Stream_GetPosition(s);
1678 credBuffer.data = Stream_Buffer(s);
1679 ret = WinPrAsn1EncContextualOctetString(enc, 1, &credBuffer) != 0;
1680
1681out:
1682 free(logonTicket.ServiceTicket);
1683 free(logonTicket.TicketGrantingTicket);
1684 Stream_Free(s, TRUE);
1685 return ret;
1686}
1687
1688WINPR_ATTR_NODISCARD
1689static BOOL nla_write_TSRemoteGuardNtlmCred(rdpNla* nla, WinPrAsn1Encoder* enc,
1691{
1692 WINPR_UNUSED(nla);
1693 BOOL ret = FALSE;
1694 BYTE ntlm[] = { 'N', '\0', 'T', '\0', 'L', '\0', 'M', '\0' };
1695 const WinPrAsn1_OctetString packageName = { sizeof(ntlm), ntlm };
1696
1697 /* packageName [0] OCTET STRING */
1698 if (!WinPrAsn1EncContextualOctetString(enc, 0, &packageName))
1699 return FALSE;
1700
1701 /* credBuffer [1] OCTET STRING */
1702 wStream* s = Stream_New(nullptr, 300);
1703 if (!s)
1704 goto out;
1705
1706 Stream_Write_UINT32(s, pntlm->Version); /* Version */
1707 Stream_Write_UINT32(s, pntlm->Flags); /* Flags */
1708
1709 Stream_Write(s, pntlm->CredentialKey.Data, MSV1_0_CREDENTIAL_KEY_LENGTH);
1710 Stream_Write_UINT32(s, pntlm->CredentialKeyType);
1711 Stream_Write_UINT32(s, pntlm->EncryptedCredsSize);
1712 Stream_Write(s, pntlm->EncryptedCreds, pntlm->EncryptedCredsSize);
1713 Stream_Zero(s, 6 + 16 * 4 + 14);
1714
1715 {
1716 WinPrAsn1_OctetString credBuffer = { Stream_GetPosition(s), Stream_Buffer(s) };
1717 ret = WinPrAsn1EncContextualOctetString(enc, 1, &credBuffer) != 0;
1718 }
1719
1720out:
1721 Stream_Free(s, TRUE);
1722 return ret;
1723}
1724
1725WINPR_ATTR_NODISCARD
1726static BOOL nla_encode_ts_smartcard_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1727{
1728 struct
1729 {
1730 WinPrAsn1_tagId tag;
1731 FreeRDP_Settings_Keys_String setting_id;
1732 } cspData_fields[] = { { 1, FreeRDP_CardName },
1733 { 2, FreeRDP_ReaderName },
1734 { 3, FreeRDP_ContainerName },
1735 { 4, FreeRDP_CspName } };
1736 WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
1737
1738 WINPR_ASSERT(nla);
1739 WINPR_ASSERT(enc);
1740 WINPR_ASSERT(nla->rdpcontext);
1741
1742 const rdpSettings* settings = nla->rdpcontext->settings;
1743 WINPR_ASSERT(settings);
1744
1745 /* TSSmartCardCreds */
1746 if (!WinPrAsn1EncSeqContainer(enc))
1747 return FALSE;
1748
1749 /* pin [0] OCTET STRING */
1750 size_t ss = 0;
1751 octet_string.data =
1752 (BYTE*)freerdp_settings_get_string_as_utf16(settings, FreeRDP_Password, &ss);
1753 octet_string.len = ss * sizeof(WCHAR);
1754 BOOL res = WinPrAsn1EncContextualOctetString(enc, 0, &octet_string) > 0;
1755 WinPrAsn1FreeOctetString(&octet_string);
1756 if (!res)
1757 return FALSE;
1758
1759 /* cspData [1] SEQUENCE */
1760 if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
1761 return FALSE;
1762
1763 /* keySpec [0] INTEGER */
1764 if (!WinPrAsn1EncContextualInteger(
1765 enc, 0,
1766 WINPR_ASSERTING_INT_CAST(WinPrAsn1_INTEGER,
1767 freerdp_settings_get_uint32(settings, FreeRDP_KeySpec))))
1768 return FALSE;
1769
1770 for (size_t i = 0; i < ARRAYSIZE(cspData_fields); i++)
1771 {
1772 size_t len = 0;
1773
1774 octet_string.data = (BYTE*)freerdp_settings_get_string_as_utf16(
1775 settings, cspData_fields[i].setting_id, &len);
1776 octet_string.len = len * sizeof(WCHAR);
1777 if (octet_string.len)
1778 {
1779 const BOOL res2 =
1780 WinPrAsn1EncContextualOctetString(enc, cspData_fields[i].tag, &octet_string) > 0;
1781 WinPrAsn1FreeOctetString(&octet_string);
1782 if (!res2)
1783 return FALSE;
1784 }
1785 }
1786
1787 /* End cspData */
1788 if (!WinPrAsn1EncEndContainer(enc))
1789 return FALSE;
1790
1791 /* userHint [2] OCTET STRING OPTIONAL, */
1792 if (freerdp_settings_get_string(settings, FreeRDP_Username))
1793 {
1794 octet_string.data =
1795 (BYTE*)freerdp_settings_get_string_as_utf16(settings, FreeRDP_Username, &ss);
1796 octet_string.len = ss * sizeof(WCHAR);
1797 res = WinPrAsn1EncContextualOctetString(enc, 2, &octet_string) > 0;
1798 WinPrAsn1FreeOctetString(&octet_string);
1799 if (!res)
1800 return FALSE;
1801 }
1802
1803 /* domainHint [3] OCTET STRING OPTIONAL */
1804 if (freerdp_settings_get_string(settings, FreeRDP_Domain))
1805 {
1806 octet_string.data =
1807 (BYTE*)freerdp_settings_get_string_as_utf16(settings, FreeRDP_Domain, &ss);
1808 octet_string.len = ss * sizeof(WCHAR);
1809 res = WinPrAsn1EncContextualOctetString(enc, 3, &octet_string) > 0;
1810 WinPrAsn1FreeOctetString(&octet_string);
1811 if (!res)
1812 return FALSE;
1813 }
1814
1815 /* End TSSmartCardCreds */
1816 return WinPrAsn1EncEndContainer(enc) != 0;
1817}
1818
1819WINPR_ATTR_NODISCARD
1820static BOOL nla_encode_ts_password_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1821{
1822 WinPrAsn1_OctetString username = WINPR_C_ARRAY_INIT;
1823 WinPrAsn1_OctetString domain = WINPR_C_ARRAY_INIT;
1824 WinPrAsn1_OctetString password = WINPR_C_ARRAY_INIT;
1825
1826 WINPR_ASSERT(nla);
1827 WINPR_ASSERT(enc);
1828 WINPR_ASSERT(nla->rdpcontext);
1829
1830 const rdpSettings* settings = nla->rdpcontext->settings;
1831 WINPR_ASSERT(settings);
1832
1833 /* TSPasswordCreds */
1834 if (!WinPrAsn1EncSeqContainer(enc))
1835 return FALSE;
1836
1837 const BOOL enabled =
1838 !freerdp_settings_get_bool(settings, FreeRDP_DisableCredentialsDelegation) &&
1839 !freerdp_settings_get_bool(settings, FreeRDP_RestrictedAdminModeRequired) &&
1840 !freerdp_settings_get_bool(settings, FreeRDP_RemoteCredentialGuard);
1841 if (enabled && nla->identity)
1842 {
1843 username.len = nla->identity->UserLength * sizeof(WCHAR);
1844 username.data = (BYTE*)nla->identity->User;
1845
1846 domain.len = nla->identity->DomainLength * sizeof(WCHAR);
1847 domain.data = (BYTE*)nla->identity->Domain;
1848
1849 password.len = nla->identity->PasswordLength * sizeof(WCHAR);
1850 password.data = (BYTE*)nla->identity->Password;
1851 }
1852
1853 if (WinPrAsn1EncContextualOctetString(enc, 0, &domain) == 0)
1854 return FALSE;
1855 if (WinPrAsn1EncContextualOctetString(enc, 1, &username) == 0)
1856 return FALSE;
1857 if (WinPrAsn1EncContextualOctetString(enc, 2, &password) == 0)
1858 return FALSE;
1859
1860 /* End TSPasswordCreds */
1861 return WinPrAsn1EncEndContainer(enc) != 0;
1862}
1863
1864WINPR_ATTR_NODISCARD
1865static BOOL nla_encode_ts_remoteguard_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1866{
1867 WINPR_ASSERT(nla);
1868 WINPR_ASSERT(enc);
1869
1870 /* TSRemoteGuardCreds */
1871 if (!WinPrAsn1EncSeqContainer(enc))
1872 return FALSE;
1873
1874 /* logonCred [0] TSRemoteGuardPackageCred, */
1875 if (!WinPrAsn1EncContextualSeqContainer(enc, 0))
1876 return FALSE;
1877
1878 if (!nla_write_TSRemoteGuardKerbCred(nla, enc) || !WinPrAsn1EncEndContainer(enc))
1879 return FALSE;
1880
1881 /* TODO: compute the NTLM supplemental creds */
1883 if (ntlm)
1884 {
1885 /* supplementalCreds [1] SEQUENCE OF TSRemoteGuardPackageCred OPTIONAL */
1886 if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
1887 return FALSE;
1888
1889 if (!WinPrAsn1EncSeqContainer(enc)) /* start NTLM */
1890 return FALSE;
1891
1892 if (!nla_write_TSRemoteGuardNtlmCred(nla, enc, ntlm))
1893 return FALSE;
1894
1895 if (!WinPrAsn1EncEndContainer(enc)) /* end NTLM */
1896 return FALSE;
1897
1898 if (!WinPrAsn1EncEndContainer(enc)) /* supplementalCreds */
1899 return FALSE;
1900 }
1901
1902 /* End TSRemoteGuardCreds */
1903 return WinPrAsn1EncEndContainer(enc) != 0;
1904}
1905
1912WINPR_ATTR_NODISCARD
1913static BOOL nla_encode_ts_credentials(rdpNla* nla)
1914{
1915 BOOL ret = FALSE;
1916 WinPrAsn1Encoder* enc = nullptr;
1917 size_t length = 0;
1918 wStream s = WINPR_C_ARRAY_INIT;
1919 TsCredentialsType credType = TSCREDS_INVALID;
1920
1921 WINPR_ASSERT(nla);
1922 WINPR_ASSERT(nla->rdpcontext);
1923
1924 rdpSettings* settings = nla->rdpcontext->settings;
1925 WINPR_ASSERT(settings);
1926
1927 if (settings->RemoteCredentialGuard)
1928 credType = TSCREDS_REMOTEGUARD;
1929 else if (settings->SmartcardLogon)
1930 credType = TSCREDS_SMARTCARD;
1931 else
1932 credType = TSCREDS_USER_PASSWD;
1933
1934 enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
1935 if (!enc)
1936 return FALSE;
1937
1938 /* TSCredentials */
1939 if (!WinPrAsn1EncSeqContainer(enc))
1940 goto out;
1941
1942 /* credType [0] INTEGER */
1943 if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)credType))
1944 goto out;
1945
1946 /* credentials [1] OCTET STRING */
1947 if (!WinPrAsn1EncContextualOctetStringContainer(enc, 1))
1948 goto out;
1949
1950 switch (credType)
1951 {
1952 case TSCREDS_SMARTCARD:
1953 if (!nla_encode_ts_smartcard_credentials(nla, enc))
1954 goto out;
1955 break;
1956
1957 case TSCREDS_USER_PASSWD:
1958 if (!nla_encode_ts_password_credentials(nla, enc))
1959 goto out;
1960 break;
1961
1962 case TSCREDS_REMOTEGUARD:
1963 if (!nla_encode_ts_remoteguard_credentials(nla, enc))
1964 goto out;
1965 break;
1966 default:
1967 goto out;
1968 }
1969
1970 /* End credentials | End TSCredentials */
1971 if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
1972 goto out;
1973
1974 if (!WinPrAsn1EncStreamSize(enc, &length))
1975 goto out;
1976
1977 if (!nla_sec_buffer_alloc(&nla->tsCredentials, length))
1978 {
1979 WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
1980 goto out;
1981 }
1982
1983 Stream_StaticInit(&s, (BYTE*)nla->tsCredentials.pvBuffer, length);
1984
1985 ret = WinPrAsn1EncToStream(enc, &s);
1986
1987out:
1988 WinPrAsn1Encoder_Free(&enc);
1989 return ret;
1990}
1991
1992WINPR_ATTR_NODISCARD
1993static BOOL nla_encrypt_ts_credentials(rdpNla* nla)
1994{
1995 WINPR_ASSERT(nla);
1996
1997 if (!nla_encode_ts_credentials(nla))
1998 return FALSE;
1999
2000 sspi_SecBufferFree(&nla->authInfo);
2001 return (credssp_auth_encrypt(nla->auth, &nla->tsCredentials, &nla->authInfo, nullptr,
2002 nla->sendSeqNum++));
2003}
2004
2005WINPR_ATTR_NODISCARD
2006static BOOL nla_decrypt_ts_credentials(rdpNla* nla)
2007{
2008 WINPR_ASSERT(nla);
2009
2010 if (nla->authInfo.cbBuffer < 1)
2011 {
2012 WLog_ERR(TAG, "nla_decrypt_ts_credentials missing authInfo buffer");
2013 return FALSE;
2014 }
2015
2016 sspi_SecBufferFree(&nla->tsCredentials);
2017 if (!credssp_auth_decrypt(nla->auth, &nla->authInfo, &nla->tsCredentials, nla->recvSeqNum++))
2018 return FALSE;
2019
2020 if (!nla_read_ts_credentials(nla, &nla->tsCredentials))
2021 return FALSE;
2022
2023 return TRUE;
2024}
2025
2026WINPR_ATTR_NODISCARD
2027static BOOL nla_write_octet_string(WinPrAsn1Encoder* enc, const SecBuffer* buffer,
2028 WinPrAsn1_tagId tagId, const char* msg)
2029{
2030 BOOL res = FALSE;
2031
2032 WINPR_ASSERT(enc);
2033 WINPR_ASSERT(buffer);
2034 WINPR_ASSERT(msg);
2035
2036 if (buffer->cbBuffer > 0)
2037 {
2038 size_t rc = 0;
2039 WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
2040
2041 WLog_DBG(TAG, " ----->> %s", msg);
2042 octet_string.data = buffer->pvBuffer;
2043 octet_string.len = buffer->cbBuffer;
2044 rc = WinPrAsn1EncContextualOctetString(enc, tagId, &octet_string);
2045 if (rc != 0)
2046 res = TRUE;
2047 }
2048
2049 return res;
2050}
2051
2052WINPR_ATTR_NODISCARD
2053static BOOL nla_write_octet_string_free(WinPrAsn1Encoder* enc, SecBuffer* buffer,
2054 WinPrAsn1_tagId tagId, const char* msg)
2055{
2056 const BOOL rc = nla_write_octet_string(enc, buffer, tagId, msg);
2057 sspi_SecBufferFree(buffer);
2058 return rc;
2059}
2060
2069BOOL nla_send(rdpNla* nla)
2070{
2071 BOOL rc = FALSE;
2072 wStream* s = nullptr;
2073 size_t length = 0;
2074 WinPrAsn1Encoder* enc = nullptr;
2075
2076 WINPR_ASSERT(nla);
2077
2078 enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
2079 if (!enc)
2080 return FALSE;
2081
2082 /* TSRequest */
2083 WLog_DBG(TAG, "----->> sending...");
2084 if (!WinPrAsn1EncSeqContainer(enc))
2085 goto fail;
2086
2087 /* version [0] INTEGER */
2088 WLog_DBG(TAG, " ----->> protocol version %" PRIu32, nla->version);
2089 if (!WinPrAsn1EncContextualInteger(enc, 0,
2090 WINPR_ASSERTING_INT_CAST(WinPrAsn1_INTEGER, nla->version)))
2091 goto fail;
2092
2093 /* negoTokens [1] SEQUENCE OF SEQUENCE */
2094 if (nla_get_state(nla) <= NLA_STATE_NEGO_TOKEN && credssp_auth_have_output_token(nla->auth))
2095 {
2096 const SecBuffer* buffer = credssp_auth_get_output_buffer(nla->auth);
2097
2098 if (!WinPrAsn1EncContextualSeqContainer(enc, 1) || !WinPrAsn1EncSeqContainer(enc))
2099 goto fail;
2100
2101 /* negoToken [0] OCTET STRING */
2102 if (!nla_write_octet_string(enc, buffer, 0, "negoToken"))
2103 goto fail;
2104
2105 /* End negoTokens (SEQUENCE OF SEQUENCE) */
2106 if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
2107 goto fail;
2108 }
2109
2110 /* authInfo [2] OCTET STRING */
2111 if (nla->authInfo.cbBuffer > 0)
2112 {
2113 if (!nla_write_octet_string_free(enc, &nla->authInfo, 2, "auth info"))
2114 goto fail;
2115 }
2116
2117 /* pubKeyAuth [3] OCTET STRING */
2118 if (nla->pubKeyAuth.cbBuffer > 0)
2119 {
2120 if (!nla_write_octet_string_free(enc, &nla->pubKeyAuth, 3, "public key auth"))
2121 goto fail;
2122 }
2123
2124 /* errorCode [4] INTEGER */
2125 if (nla->errorCode && nla->peerVersion >= 3 && nla->peerVersion != 5)
2126 {
2127 WLog_DBG(TAG, " ----->> error code %s 0x%08" PRIx32, NtStatus2Tag(nla->errorCode),
2128 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2129 if (!WinPrAsn1EncContextualInteger(
2130 enc, 4, WINPR_ASSERTING_INT_CAST(WinPrAsn1_INTEGER, nla->errorCode)))
2131 goto fail;
2132 }
2133
2134 /* clientNonce [5] OCTET STRING */
2135 if (!nla->server && nla->ClientNonce.cbBuffer > 0)
2136 {
2137 if (!nla_write_octet_string(enc, &nla->ClientNonce, 5, "client nonce"))
2138 goto fail;
2139 }
2140
2141 /* End TSRequest */
2142 if (!WinPrAsn1EncEndContainer(enc))
2143 goto fail;
2144
2145 if (!WinPrAsn1EncStreamSize(enc, &length))
2146 goto fail;
2147
2148 s = Stream_New(nullptr, length);
2149 if (!s)
2150 goto fail;
2151
2152 if (!WinPrAsn1EncToStream(enc, s))
2153 goto fail;
2154
2155 WLog_DBG(TAG, "[%" PRIuz " bytes]", length);
2156 if (transport_write(nla->transport, s) < 0)
2157 goto fail;
2158 rc = TRUE;
2159
2160fail:
2161 Stream_Free(s, TRUE);
2162 WinPrAsn1Encoder_Free(&enc);
2163 return rc;
2164}
2165
2166WINPR_ATTR_NODISCARD
2167static int nla_decode_ts_request(rdpNla* nla, wStream* s)
2168{
2169 WinPrAsn1Decoder dec = WinPrAsn1Decoder_init();
2170 WinPrAsn1Decoder dec2 = WinPrAsn1Decoder_init();
2171 BOOL error = FALSE;
2172 WinPrAsn1_tagId tag = WINPR_C_ARRAY_INIT;
2173 WinPrAsn1_INTEGER val = WINPR_C_ARRAY_INIT;
2174 UINT32 version = 0;
2175
2176 WINPR_ASSERT(nla);
2177 WINPR_ASSERT(s);
2178
2179 WinPrAsn1Decoder_Init(&dec, WINPR_ASN1_DER, s);
2180
2181 WLog_DBG(TAG, "<<----- receiving...");
2182
2183 /* TSRequest */
2184 const size_t offset = WinPrAsn1DecReadSequence(&dec, &dec2);
2185 if (offset == 0)
2186 return -1;
2187 dec = dec2;
2188
2189 /* version [0] INTEGER */
2190 if (WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val) == 0)
2191 return -1;
2192
2193 if (!Stream_SafeSeek(s, offset))
2194 return -1;
2195
2196 version = (UINT)val;
2197 WLog_DBG(TAG, " <<----- protocol version %" PRIu32, version);
2198
2199 if (nla->peerVersion == 0)
2200 nla->peerVersion = version;
2201
2202 /* if the peer suddenly changed its version - kick it */
2203 if (nla->peerVersion != version)
2204 {
2205 WLog_ERR(TAG, "CredSSP peer changed protocol version from %" PRIu32 " to %" PRIu32,
2206 nla->peerVersion, version);
2207 return -1;
2208 }
2209
2210 size_t tagcount = 0;
2211 while (WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2) != 0)
2212 {
2213 WinPrAsn1Decoder dec3 = WinPrAsn1Decoder_init();
2214 WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
2215
2216 tagcount++;
2217 switch (tag)
2218 {
2219 case 1:
2220 WLog_DBG(TAG, " <<----- nego token");
2221 /* negoTokens [1] SEQUENCE OF SEQUENCE */
2222 if ((WinPrAsn1DecReadSequence(&dec2, &dec3) == 0) ||
2223 (WinPrAsn1DecReadSequence(&dec3, &dec2) == 0))
2224 return -1;
2225 /* negoToken [0] OCTET STRING */
2226 if ((WinPrAsn1DecReadContextualOctetString(&dec2, 0, &error, &octet_string,
2227 FALSE) == 0) &&
2228 error)
2229 return -1;
2230 if (!nla_sec_buffer_alloc_from_data(&nla->negoToken, octet_string.data, 0,
2231 octet_string.len))
2232 return -1;
2233 break;
2234 case 2:
2235 WLog_DBG(TAG, " <<----- auth info");
2236 /* authInfo [2] OCTET STRING */
2237 if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2238 return -1;
2239 if (!nla_sec_buffer_alloc_from_data(&nla->authInfo, octet_string.data, 0,
2240 octet_string.len))
2241 return -1;
2242 break;
2243 case 3:
2244 WLog_DBG(TAG, " <<----- public key auth");
2245 /* pubKeyAuth [3] OCTET STRING */
2246 if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2247 return -1;
2248 if (!nla_sec_buffer_alloc_from_data(&nla->pubKeyAuth, octet_string.data, 0,
2249 octet_string.len))
2250 return -1;
2251 break;
2252 case 4:
2253 /* errorCode [4] INTEGER */
2254 if (WinPrAsn1DecReadInteger(&dec2, &val) == 0)
2255 return -1;
2256 nla->errorCode = val;
2257 WLog_DBG(TAG, " <<----- error code %s 0x%08" PRIx32, NtStatus2Tag(nla->errorCode),
2258 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2259 break;
2260 case 5:
2261 WLog_DBG(TAG, " <<----- client nonce");
2262 /* clientNonce [5] OCTET STRING */
2263 if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2264 return -1;
2265 if (!nla_sec_buffer_alloc_from_data(&nla->ClientNonce, octet_string.data, 0,
2266 octet_string.len))
2267 return -1;
2268 break;
2269 default:
2270 return -1;
2271 }
2272 }
2273
2274 return tagcount > 0 ? 1 : -1;
2275}
2276
2277int nla_recv_pdu(rdpNla* nla, wStream* s)
2278{
2279 WINPR_ASSERT(nla);
2280 WINPR_ASSERT(s);
2281
2282 if (nla_get_state(nla) == NLA_STATE_EARLY_USER_AUTH)
2283 {
2284 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2285 return -1;
2286
2287 const UINT32 authzResult = Stream_Get_UINT32(s);
2288 if (authzResult != AUTHZ_SUCCESS)
2289 {
2290 UINT32 code = FREERDP_ERROR_AUTHENTICATION_FAILED;
2291
2292 switch (authzResult)
2293 {
2294 case AUTHZ_ACCESS_DENIED:
2295 /* The user authenticated successfully but is not authorized to open a
2296 * session on this host, e.g. it lacks the 'Allow log on through Remote
2297 * Desktop Services' right. */
2298 code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
2299 break;
2300 default:
2301 break;
2302 }
2303
2304 WLog_ERR(TAG, "Early User Auth active: FAILURE authorization result 0x%08" PRIX32 "",
2305 authzResult);
2306 freerdp_set_last_error_log(nla->rdpcontext, code);
2307 return -1;
2308 }
2309 else
2310 WLog_DBG(TAG, "Early User Auth active: SUCCESS");
2311 }
2312 else
2313 {
2314 if (nla_decode_ts_request(nla, s) < 1)
2315 return -1;
2316
2317 if (nla->errorCode)
2318 {
2319 UINT32 code = 0;
2320
2321 switch (nla->errorCode)
2322 {
2323 case STATUS_PASSWORD_MUST_CHANGE:
2324 code = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
2325 break;
2326
2327 case STATUS_PASSWORD_EXPIRED:
2328 code = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
2329 break;
2330
2331 case STATUS_ACCOUNT_DISABLED:
2332 code = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
2333 break;
2334
2335 case STATUS_LOGON_FAILURE:
2336 code = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
2337 break;
2338
2339 case STATUS_WRONG_PASSWORD:
2340 code = FREERDP_ERROR_CONNECT_WRONG_PASSWORD;
2341 break;
2342
2343 case STATUS_ACCESS_DENIED:
2344 code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
2345 break;
2346
2347 case STATUS_ACCOUNT_RESTRICTION:
2348 code = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
2349 break;
2350
2351 case STATUS_ACCOUNT_LOCKED_OUT:
2352 code = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
2353 break;
2354
2355 case STATUS_ACCOUNT_EXPIRED:
2356 code = FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED;
2357 break;
2358
2359 case STATUS_LOGON_TYPE_NOT_GRANTED:
2360 code = FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED;
2361 break;
2362
2363 case STATUS_NTLM_BLOCKED:
2364 /* mstsc shows the same ambiguity for this code: NTLM policy block, or a
2365 * CredSSP encryption oracle remediation mismatch. */
2366 case SEC_E_UNSUPPORTED_FUNCTION:
2367 code = FREERDP_ERROR_CONNECT_NTLM_BLOCKED;
2368 break;
2369
2370 default:
2371 WLog_ERR(TAG, "SPNEGO failed with NTSTATUS: %s [0x%08" PRIx32 "]",
2372 NtStatus2Tag(nla->errorCode),
2373 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2374 code = FREERDP_ERROR_AUTHENTICATION_FAILED;
2375 break;
2376 }
2377
2378 freerdp_set_last_error_log(nla->rdpcontext, code);
2379 return -1;
2380 }
2381 }
2382
2383 return nla_client_recv(nla);
2384}
2385
2386int nla_server_recv(rdpNla* nla)
2387{
2388 int status = -1;
2389
2390 WINPR_ASSERT(nla);
2391
2392 wStream* s = nla_server_recv_stream(nla);
2393 if (!s)
2394 goto fail;
2395 status = nla_decode_ts_request(nla, s);
2396
2397fail:
2398 Stream_Free(s, TRUE);
2399 return status;
2400}
2401
2411rdpNla* nla_new(rdpContext* context, rdpTransport* transport)
2412{
2413 WINPR_ASSERT(transport);
2414 WINPR_ASSERT(context);
2415
2416 rdpSettings* settings = context->settings;
2417 WINPR_ASSERT(settings);
2418
2419 rdpNla* nla = (rdpNla*)calloc(1, sizeof(rdpNla));
2420
2421 if (!nla)
2422 return nullptr;
2423
2424 nla->rdpcontext = context;
2425 nla->server = settings->ServerMode;
2426 nla->transport = transport;
2427 nla->sendSeqNum = 0;
2428 nla->recvSeqNum = 0;
2429 nla->version = 6;
2430 nla->earlyUserAuth = FALSE;
2431
2432 nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
2433 if (!nla->identity)
2434 goto cleanup;
2435
2436 nla->auth = credssp_auth_new(context);
2437 if (!nla->auth)
2438 goto cleanup;
2439
2440 /* init to 0 or we end up freeing a bad pointer if the alloc fails */
2441 if (!nla_sec_buffer_alloc(&nla->ClientNonce, NonceLength))
2442 goto cleanup;
2443
2444 /* generate random 32-byte nonce */
2445 if (winpr_RAND(nla->ClientNonce.pvBuffer, NonceLength) < 0)
2446 goto cleanup;
2447
2448 return nla;
2449cleanup:
2450 WINPR_PRAGMA_DIAG_PUSH
2451 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2452 nla_free(nla);
2453 WINPR_PRAGMA_DIAG_POP
2454 return nullptr;
2455}
2456
2462void nla_free(rdpNla* nla)
2463{
2464 if (!nla)
2465 return;
2466
2467 smartcardCertInfo_Free(nla->smartcardCert);
2468 nla_buffer_free(nla);
2469 sspi_SecBufferFree(&nla->tsCredentials);
2470 credssp_auth_free(nla->auth);
2471
2472 sspi_FreeAuthIdentity(nla->identity);
2473 free(nla->pkinitArgs);
2474 free(nla->identity);
2475 free(nla);
2476}
2477
2478SEC_WINNT_AUTH_IDENTITY* nla_get_identity(rdpNla* nla)
2479{
2480 if (!nla)
2481 return nullptr;
2482
2483 return nla->identity;
2484}
2485
2486NLA_STATE nla_get_state(const rdpNla* nla)
2487{
2488 if (!nla)
2489 return NLA_STATE_FINAL;
2490
2491 return nla->state;
2492}
2493
2494BOOL nla_set_state(rdpNla* nla, NLA_STATE state)
2495{
2496 if (!nla)
2497 return FALSE;
2498
2499 WLog_DBG(TAG, "-- %s\t--> %s", nla_get_state_str(nla->state), nla_get_state_str(state));
2500 nla->state = state;
2501 return TRUE;
2502}
2503
2504BOOL nla_set_service_principal(rdpNla* nla, const char* service, const char* hostname)
2505{
2506 return (credssp_auth_set_spn(nla->auth, service, hostname));
2507}
2508
2509BOOL nla_impersonate(rdpNla* nla)
2510{
2511 return credssp_auth_impersonate(nla->auth);
2512}
2513
2514BOOL nla_revert_to_self(rdpNla* nla)
2515{
2516 return credssp_auth_revert_to_self(nla->auth);
2517}
2518
2519const char* nla_get_state_str(NLA_STATE state)
2520{
2521 switch (state)
2522 {
2523 case NLA_STATE_INITIAL:
2524 return "NLA_STATE_INITIAL";
2525 case NLA_STATE_NEGO_TOKEN:
2526 return "NLA_STATE_NEGO_TOKEN";
2527 case NLA_STATE_PUB_KEY_AUTH:
2528 return "NLA_STATE_PUB_KEY_AUTH";
2529 case NLA_STATE_AUTH_INFO:
2530 return "NLA_STATE_AUTH_INFO";
2531 case NLA_STATE_POST_NEGO:
2532 return "NLA_STATE_POST_NEGO";
2533 case NLA_STATE_EARLY_USER_AUTH:
2534 return "NLA_STATE_EARLY_USER_AUTH";
2535 case NLA_STATE_FINAL:
2536 return "NLA_STATE_FINAL";
2537 default:
2538 return "UNKNOWN";
2539 }
2540}
2541
2542DWORD nla_get_error(const rdpNla* nla)
2543{
2544 if (!nla)
2545 return ERROR_INTERNAL_ERROR;
2546 return (UINT32)nla->errorCode;
2547}
2548
2549INT32 nla_get_sspi_error(const rdpNla* nla)
2550{
2551 WINPR_ASSERT(nla);
2552 return credssp_auth_sspi_error(nla->auth);
2553}
2554
2555BOOL nla_encrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer)
2556{
2557 WINPR_ASSERT(nla);
2558 WINPR_ASSERT(inBuffer);
2559 WINPR_ASSERT(outBuffer);
2560 return credssp_auth_encrypt(nla->auth, inBuffer, outBuffer, nullptr, nla->sendSeqNum++);
2561}
2562
2563BOOL nla_decrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer)
2564{
2565 WINPR_ASSERT(nla);
2566 WINPR_ASSERT(inBuffer);
2567 WINPR_ASSERT(outBuffer);
2568 return credssp_auth_decrypt(nla->auth, inBuffer, outBuffer, nla->recvSeqNum++);
2569}
2570
2571SECURITY_STATUS nla_QueryContextAttributes(rdpNla* nla, DWORD ulAttr, PVOID pBuffer)
2572{
2573 WINPR_ASSERT(nla);
2574
2575 SecurityFunctionTable* table = nullptr;
2576 CtxtHandle context = WINPR_C_ARRAY_INIT;
2577 credssp_auth_tableAndContext(nla->auth, &table, &context);
2578
2579 return table->QueryContextAttributes(&context, ulAttr, pBuffer);
2580}
2581
2582SECURITY_STATUS nla_FreeContextBuffer(rdpNla* nla, PVOID pBuffer)
2583{
2584 WINPR_ASSERT(nla);
2585
2586 SecurityFunctionTable* table = nullptr;
2587 CtxtHandle context = WINPR_C_ARRAY_INIT;
2588 credssp_auth_tableAndContext(nla->auth, &table, &context);
2589
2590 return table->FreeContextBuffer(pBuffer);
2591}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string_from_utf16N(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const WCHAR *param, size_t length)
Sets a string settings value. The param is converted to UTF-8 and the copy stored.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string_from_utf16(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const WCHAR *param)
Sets a string settings value. The param is converted to UTF-8 and the copy stored.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API WCHAR * freerdp_settings_get_string_as_utf16(const rdpSettings *settings, FreeRDP_Settings_Keys_String id, size_t *pCharLen)
Return an allocated UTF16 string.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.