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 if (enabled && nla->identity)
1841 {
1842 username.len = nla->identity->UserLength * sizeof(WCHAR);
1843 username.data = (BYTE*)nla->identity->User;
1844
1845 domain.len = nla->identity->DomainLength * sizeof(WCHAR);
1846 domain.data = (BYTE*)nla->identity->Domain;
1847
1848 password.len = nla->identity->PasswordLength * sizeof(WCHAR);
1849 password.data = (BYTE*)nla->identity->Password;
1850 }
1851
1852 if (WinPrAsn1EncContextualOctetString(enc, 0, &domain) == 0)
1853 return FALSE;
1854 if (WinPrAsn1EncContextualOctetString(enc, 1, &username) == 0)
1855 return FALSE;
1856 if (WinPrAsn1EncContextualOctetString(enc, 2, &password) == 0)
1857 return FALSE;
1858
1859 /* End TSPasswordCreds */
1860 return WinPrAsn1EncEndContainer(enc) != 0;
1861}
1862
1863WINPR_ATTR_NODISCARD
1864static BOOL nla_encode_ts_remoteguard_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1865{
1866 WINPR_ASSERT(nla);
1867 WINPR_ASSERT(enc);
1868
1869 /* TSRemoteGuardCreds */
1870 if (!WinPrAsn1EncSeqContainer(enc))
1871 return FALSE;
1872
1873 /* logonCred [0] TSRemoteGuardPackageCred, */
1874 if (!WinPrAsn1EncContextualSeqContainer(enc, 0))
1875 return FALSE;
1876
1877 if (!nla_write_TSRemoteGuardKerbCred(nla, enc) || !WinPrAsn1EncEndContainer(enc))
1878 return FALSE;
1879
1880 /* TODO: compute the NTLM supplemental creds */
1882 if (ntlm)
1883 {
1884 /* supplementalCreds [1] SEQUENCE OF TSRemoteGuardPackageCred OPTIONAL */
1885 if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
1886 return FALSE;
1887
1888 if (!WinPrAsn1EncSeqContainer(enc)) /* start NTLM */
1889 return FALSE;
1890
1891 if (!nla_write_TSRemoteGuardNtlmCred(nla, enc, ntlm))
1892 return FALSE;
1893
1894 if (!WinPrAsn1EncEndContainer(enc)) /* end NTLM */
1895 return FALSE;
1896
1897 if (!WinPrAsn1EncEndContainer(enc)) /* supplementalCreds */
1898 return FALSE;
1899 }
1900
1901 /* End TSRemoteGuardCreds */
1902 return WinPrAsn1EncEndContainer(enc) != 0;
1903}
1904
1911WINPR_ATTR_NODISCARD
1912static BOOL nla_encode_ts_credentials(rdpNla* nla)
1913{
1914 BOOL ret = FALSE;
1915 WinPrAsn1Encoder* enc = nullptr;
1916 size_t length = 0;
1917 wStream s = WINPR_C_ARRAY_INIT;
1918 TsCredentialsType credType = TSCREDS_INVALID;
1919
1920 WINPR_ASSERT(nla);
1921 WINPR_ASSERT(nla->rdpcontext);
1922
1923 rdpSettings* settings = nla->rdpcontext->settings;
1924 WINPR_ASSERT(settings);
1925
1926 if (settings->RemoteCredentialGuard)
1927 credType = TSCREDS_REMOTEGUARD;
1928 else if (settings->SmartcardLogon)
1929 credType = TSCREDS_SMARTCARD;
1930 else
1931 credType = TSCREDS_USER_PASSWD;
1932
1933 enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
1934 if (!enc)
1935 return FALSE;
1936
1937 /* TSCredentials */
1938 if (!WinPrAsn1EncSeqContainer(enc))
1939 goto out;
1940
1941 /* credType [0] INTEGER */
1942 if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)credType))
1943 goto out;
1944
1945 /* credentials [1] OCTET STRING */
1946 if (!WinPrAsn1EncContextualOctetStringContainer(enc, 1))
1947 goto out;
1948
1949 switch (credType)
1950 {
1951 case TSCREDS_SMARTCARD:
1952 if (!nla_encode_ts_smartcard_credentials(nla, enc))
1953 goto out;
1954 break;
1955
1956 case TSCREDS_USER_PASSWD:
1957 if (!nla_encode_ts_password_credentials(nla, enc))
1958 goto out;
1959 break;
1960
1961 case TSCREDS_REMOTEGUARD:
1962 if (!nla_encode_ts_remoteguard_credentials(nla, enc))
1963 goto out;
1964 break;
1965 default:
1966 goto out;
1967 }
1968
1969 /* End credentials | End TSCredentials */
1970 if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
1971 goto out;
1972
1973 if (!WinPrAsn1EncStreamSize(enc, &length))
1974 goto out;
1975
1976 if (!nla_sec_buffer_alloc(&nla->tsCredentials, length))
1977 {
1978 WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
1979 goto out;
1980 }
1981
1982 Stream_StaticInit(&s, (BYTE*)nla->tsCredentials.pvBuffer, length);
1983
1984 ret = WinPrAsn1EncToStream(enc, &s);
1985
1986out:
1987 WinPrAsn1Encoder_Free(&enc);
1988 return ret;
1989}
1990
1991WINPR_ATTR_NODISCARD
1992static BOOL nla_encrypt_ts_credentials(rdpNla* nla)
1993{
1994 WINPR_ASSERT(nla);
1995
1996 if (!nla_encode_ts_credentials(nla))
1997 return FALSE;
1998
1999 sspi_SecBufferFree(&nla->authInfo);
2000 return (credssp_auth_encrypt(nla->auth, &nla->tsCredentials, &nla->authInfo, nullptr,
2001 nla->sendSeqNum++));
2002}
2003
2004WINPR_ATTR_NODISCARD
2005static BOOL nla_decrypt_ts_credentials(rdpNla* nla)
2006{
2007 WINPR_ASSERT(nla);
2008
2009 if (nla->authInfo.cbBuffer < 1)
2010 {
2011 WLog_ERR(TAG, "nla_decrypt_ts_credentials missing authInfo buffer");
2012 return FALSE;
2013 }
2014
2015 sspi_SecBufferFree(&nla->tsCredentials);
2016 if (!credssp_auth_decrypt(nla->auth, &nla->authInfo, &nla->tsCredentials, nla->recvSeqNum++))
2017 return FALSE;
2018
2019 if (!nla_read_ts_credentials(nla, &nla->tsCredentials))
2020 return FALSE;
2021
2022 return TRUE;
2023}
2024
2025WINPR_ATTR_NODISCARD
2026static BOOL nla_write_octet_string(WinPrAsn1Encoder* enc, const SecBuffer* buffer,
2027 WinPrAsn1_tagId tagId, const char* msg)
2028{
2029 BOOL res = FALSE;
2030
2031 WINPR_ASSERT(enc);
2032 WINPR_ASSERT(buffer);
2033 WINPR_ASSERT(msg);
2034
2035 if (buffer->cbBuffer > 0)
2036 {
2037 size_t rc = 0;
2038 WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
2039
2040 WLog_DBG(TAG, " ----->> %s", msg);
2041 octet_string.data = buffer->pvBuffer;
2042 octet_string.len = buffer->cbBuffer;
2043 rc = WinPrAsn1EncContextualOctetString(enc, tagId, &octet_string);
2044 if (rc != 0)
2045 res = TRUE;
2046 }
2047
2048 return res;
2049}
2050
2051WINPR_ATTR_NODISCARD
2052static BOOL nla_write_octet_string_free(WinPrAsn1Encoder* enc, SecBuffer* buffer,
2053 WinPrAsn1_tagId tagId, const char* msg)
2054{
2055 const BOOL rc = nla_write_octet_string(enc, buffer, tagId, msg);
2056 sspi_SecBufferFree(buffer);
2057 return rc;
2058}
2059
2068BOOL nla_send(rdpNla* nla)
2069{
2070 BOOL rc = FALSE;
2071 wStream* s = nullptr;
2072 size_t length = 0;
2073 WinPrAsn1Encoder* enc = nullptr;
2074
2075 WINPR_ASSERT(nla);
2076
2077 enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
2078 if (!enc)
2079 return FALSE;
2080
2081 /* TSRequest */
2082 WLog_DBG(TAG, "----->> sending...");
2083 if (!WinPrAsn1EncSeqContainer(enc))
2084 goto fail;
2085
2086 /* version [0] INTEGER */
2087 WLog_DBG(TAG, " ----->> protocol version %" PRIu32, nla->version);
2088 if (!WinPrAsn1EncContextualInteger(enc, 0,
2089 WINPR_ASSERTING_INT_CAST(WinPrAsn1_INTEGER, nla->version)))
2090 goto fail;
2091
2092 /* negoTokens [1] SEQUENCE OF SEQUENCE */
2093 if (nla_get_state(nla) <= NLA_STATE_NEGO_TOKEN && credssp_auth_have_output_token(nla->auth))
2094 {
2095 const SecBuffer* buffer = credssp_auth_get_output_buffer(nla->auth);
2096
2097 if (!WinPrAsn1EncContextualSeqContainer(enc, 1) || !WinPrAsn1EncSeqContainer(enc))
2098 goto fail;
2099
2100 /* negoToken [0] OCTET STRING */
2101 if (!nla_write_octet_string(enc, buffer, 0, "negoToken"))
2102 goto fail;
2103
2104 /* End negoTokens (SEQUENCE OF SEQUENCE) */
2105 if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
2106 goto fail;
2107 }
2108
2109 /* authInfo [2] OCTET STRING */
2110 if (nla->authInfo.cbBuffer > 0)
2111 {
2112 if (!nla_write_octet_string_free(enc, &nla->authInfo, 2, "auth info"))
2113 goto fail;
2114 }
2115
2116 /* pubKeyAuth [3] OCTET STRING */
2117 if (nla->pubKeyAuth.cbBuffer > 0)
2118 {
2119 if (!nla_write_octet_string_free(enc, &nla->pubKeyAuth, 3, "public key auth"))
2120 goto fail;
2121 }
2122
2123 /* errorCode [4] INTEGER */
2124 if (nla->errorCode && nla->peerVersion >= 3 && nla->peerVersion != 5)
2125 {
2126 WLog_DBG(TAG, " ----->> error code %s 0x%08" PRIx32, NtStatus2Tag(nla->errorCode),
2127 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2128 if (!WinPrAsn1EncContextualInteger(
2129 enc, 4, WINPR_ASSERTING_INT_CAST(WinPrAsn1_INTEGER, nla->errorCode)))
2130 goto fail;
2131 }
2132
2133 /* clientNonce [5] OCTET STRING */
2134 if (!nla->server && nla->ClientNonce.cbBuffer > 0)
2135 {
2136 if (!nla_write_octet_string(enc, &nla->ClientNonce, 5, "client nonce"))
2137 goto fail;
2138 }
2139
2140 /* End TSRequest */
2141 if (!WinPrAsn1EncEndContainer(enc))
2142 goto fail;
2143
2144 if (!WinPrAsn1EncStreamSize(enc, &length))
2145 goto fail;
2146
2147 s = Stream_New(nullptr, length);
2148 if (!s)
2149 goto fail;
2150
2151 if (!WinPrAsn1EncToStream(enc, s))
2152 goto fail;
2153
2154 WLog_DBG(TAG, "[%" PRIuz " bytes]", length);
2155 if (transport_write(nla->transport, s) < 0)
2156 goto fail;
2157 rc = TRUE;
2158
2159fail:
2160 Stream_Free(s, TRUE);
2161 WinPrAsn1Encoder_Free(&enc);
2162 return rc;
2163}
2164
2165WINPR_ATTR_NODISCARD
2166static int nla_decode_ts_request(rdpNla* nla, wStream* s)
2167{
2168 WinPrAsn1Decoder dec = WinPrAsn1Decoder_init();
2169 WinPrAsn1Decoder dec2 = WinPrAsn1Decoder_init();
2170 BOOL error = FALSE;
2171 WinPrAsn1_tagId tag = WINPR_C_ARRAY_INIT;
2172 WinPrAsn1_INTEGER val = WINPR_C_ARRAY_INIT;
2173 UINT32 version = 0;
2174
2175 WINPR_ASSERT(nla);
2176 WINPR_ASSERT(s);
2177
2178 WinPrAsn1Decoder_Init(&dec, WINPR_ASN1_DER, s);
2179
2180 WLog_DBG(TAG, "<<----- receiving...");
2181
2182 /* TSRequest */
2183 const size_t offset = WinPrAsn1DecReadSequence(&dec, &dec2);
2184 if (offset == 0)
2185 return -1;
2186 dec = dec2;
2187
2188 /* version [0] INTEGER */
2189 if (WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val) == 0)
2190 return -1;
2191
2192 if (!Stream_SafeSeek(s, offset))
2193 return -1;
2194
2195 version = (UINT)val;
2196 WLog_DBG(TAG, " <<----- protocol version %" PRIu32, version);
2197
2198 if (nla->peerVersion == 0)
2199 nla->peerVersion = version;
2200
2201 /* if the peer suddenly changed its version - kick it */
2202 if (nla->peerVersion != version)
2203 {
2204 WLog_ERR(TAG, "CredSSP peer changed protocol version from %" PRIu32 " to %" PRIu32,
2205 nla->peerVersion, version);
2206 return -1;
2207 }
2208
2209 size_t tagcount = 0;
2210 while (WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2) != 0)
2211 {
2212 WinPrAsn1Decoder dec3 = WinPrAsn1Decoder_init();
2213 WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
2214
2215 tagcount++;
2216 switch (tag)
2217 {
2218 case 1:
2219 WLog_DBG(TAG, " <<----- nego token");
2220 /* negoTokens [1] SEQUENCE OF SEQUENCE */
2221 if ((WinPrAsn1DecReadSequence(&dec2, &dec3) == 0) ||
2222 (WinPrAsn1DecReadSequence(&dec3, &dec2) == 0))
2223 return -1;
2224 /* negoToken [0] OCTET STRING */
2225 if ((WinPrAsn1DecReadContextualOctetString(&dec2, 0, &error, &octet_string,
2226 FALSE) == 0) &&
2227 error)
2228 return -1;
2229 if (!nla_sec_buffer_alloc_from_data(&nla->negoToken, octet_string.data, 0,
2230 octet_string.len))
2231 return -1;
2232 break;
2233 case 2:
2234 WLog_DBG(TAG, " <<----- auth info");
2235 /* authInfo [2] OCTET STRING */
2236 if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2237 return -1;
2238 if (!nla_sec_buffer_alloc_from_data(&nla->authInfo, octet_string.data, 0,
2239 octet_string.len))
2240 return -1;
2241 break;
2242 case 3:
2243 WLog_DBG(TAG, " <<----- public key auth");
2244 /* pubKeyAuth [3] OCTET STRING */
2245 if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2246 return -1;
2247 if (!nla_sec_buffer_alloc_from_data(&nla->pubKeyAuth, octet_string.data, 0,
2248 octet_string.len))
2249 return -1;
2250 break;
2251 case 4:
2252 /* errorCode [4] INTEGER */
2253 if (WinPrAsn1DecReadInteger(&dec2, &val) == 0)
2254 return -1;
2255 nla->errorCode = val;
2256 WLog_DBG(TAG, " <<----- error code %s 0x%08" PRIx32, NtStatus2Tag(nla->errorCode),
2257 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2258 break;
2259 case 5:
2260 WLog_DBG(TAG, " <<----- client nonce");
2261 /* clientNonce [5] OCTET STRING */
2262 if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2263 return -1;
2264 if (!nla_sec_buffer_alloc_from_data(&nla->ClientNonce, octet_string.data, 0,
2265 octet_string.len))
2266 return -1;
2267 break;
2268 default:
2269 return -1;
2270 }
2271 }
2272
2273 return tagcount > 0 ? 1 : -1;
2274}
2275
2276int nla_recv_pdu(rdpNla* nla, wStream* s)
2277{
2278 WINPR_ASSERT(nla);
2279 WINPR_ASSERT(s);
2280
2281 if (nla_get_state(nla) == NLA_STATE_EARLY_USER_AUTH)
2282 {
2283 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2284 return -1;
2285
2286 const UINT32 authzResult = Stream_Get_UINT32(s);
2287 if (authzResult != AUTHZ_SUCCESS)
2288 {
2289 UINT32 code = FREERDP_ERROR_AUTHENTICATION_FAILED;
2290
2291 switch (authzResult)
2292 {
2293 case AUTHZ_ACCESS_DENIED:
2294 /* The user authenticated successfully but is not authorized to open a
2295 * session on this host, e.g. it lacks the 'Allow log on through Remote
2296 * Desktop Services' right. */
2297 code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
2298 break;
2299 default:
2300 break;
2301 }
2302
2303 WLog_ERR(TAG, "Early User Auth active: FAILURE authorization result 0x%08" PRIX32 "",
2304 authzResult);
2305 freerdp_set_last_error_log(nla->rdpcontext, code);
2306 return -1;
2307 }
2308 else
2309 WLog_DBG(TAG, "Early User Auth active: SUCCESS");
2310 }
2311 else
2312 {
2313 if (nla_decode_ts_request(nla, s) < 1)
2314 return -1;
2315
2316 if (nla->errorCode)
2317 {
2318 UINT32 code = 0;
2319
2320 switch (nla->errorCode)
2321 {
2322 case STATUS_PASSWORD_MUST_CHANGE:
2323 code = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
2324 break;
2325
2326 case STATUS_PASSWORD_EXPIRED:
2327 code = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
2328 break;
2329
2330 case STATUS_ACCOUNT_DISABLED:
2331 code = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
2332 break;
2333
2334 case STATUS_LOGON_FAILURE:
2335 code = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
2336 break;
2337
2338 case STATUS_WRONG_PASSWORD:
2339 code = FREERDP_ERROR_CONNECT_WRONG_PASSWORD;
2340 break;
2341
2342 case STATUS_ACCESS_DENIED:
2343 code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
2344 break;
2345
2346 case STATUS_ACCOUNT_RESTRICTION:
2347 code = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
2348 break;
2349
2350 case STATUS_ACCOUNT_LOCKED_OUT:
2351 code = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
2352 break;
2353
2354 case STATUS_ACCOUNT_EXPIRED:
2355 code = FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED;
2356 break;
2357
2358 case STATUS_LOGON_TYPE_NOT_GRANTED:
2359 code = FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED;
2360 break;
2361
2362 case STATUS_NTLM_BLOCKED:
2363 /* mstsc shows the same ambiguity for this code: NTLM policy block, or a
2364 * CredSSP encryption oracle remediation mismatch. */
2365 case SEC_E_UNSUPPORTED_FUNCTION:
2366 code = FREERDP_ERROR_CONNECT_NTLM_BLOCKED;
2367 break;
2368
2369 default:
2370 WLog_ERR(TAG, "SPNEGO failed with NTSTATUS: %s [0x%08" PRIx32 "]",
2371 NtStatus2Tag(nla->errorCode),
2372 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2373 code = FREERDP_ERROR_AUTHENTICATION_FAILED;
2374 break;
2375 }
2376
2377 freerdp_set_last_error_log(nla->rdpcontext, code);
2378 return -1;
2379 }
2380 }
2381
2382 return nla_client_recv(nla);
2383}
2384
2385int nla_server_recv(rdpNla* nla)
2386{
2387 int status = -1;
2388
2389 WINPR_ASSERT(nla);
2390
2391 wStream* s = nla_server_recv_stream(nla);
2392 if (!s)
2393 goto fail;
2394 status = nla_decode_ts_request(nla, s);
2395
2396fail:
2397 Stream_Free(s, TRUE);
2398 return status;
2399}
2400
2410rdpNla* nla_new(rdpContext* context, rdpTransport* transport)
2411{
2412 WINPR_ASSERT(transport);
2413 WINPR_ASSERT(context);
2414
2415 rdpSettings* settings = context->settings;
2416 WINPR_ASSERT(settings);
2417
2418 rdpNla* nla = (rdpNla*)calloc(1, sizeof(rdpNla));
2419
2420 if (!nla)
2421 return nullptr;
2422
2423 nla->rdpcontext = context;
2424 nla->server = settings->ServerMode;
2425 nla->transport = transport;
2426 nla->sendSeqNum = 0;
2427 nla->recvSeqNum = 0;
2428 nla->version = 6;
2429 nla->earlyUserAuth = FALSE;
2430
2431 nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
2432 if (!nla->identity)
2433 goto cleanup;
2434
2435 nla->auth = credssp_auth_new(context);
2436 if (!nla->auth)
2437 goto cleanup;
2438
2439 /* init to 0 or we end up freeing a bad pointer if the alloc fails */
2440 if (!nla_sec_buffer_alloc(&nla->ClientNonce, NonceLength))
2441 goto cleanup;
2442
2443 /* generate random 32-byte nonce */
2444 if (winpr_RAND(nla->ClientNonce.pvBuffer, NonceLength) < 0)
2445 goto cleanup;
2446
2447 return nla;
2448cleanup:
2449 WINPR_PRAGMA_DIAG_PUSH
2450 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2451 nla_free(nla);
2452 WINPR_PRAGMA_DIAG_POP
2453 return nullptr;
2454}
2455
2461void nla_free(rdpNla* nla)
2462{
2463 if (!nla)
2464 return;
2465
2466 smartcardCertInfo_Free(nla->smartcardCert);
2467 nla_buffer_free(nla);
2468 sspi_SecBufferFree(&nla->tsCredentials);
2469 credssp_auth_free(nla->auth);
2470
2471 sspi_FreeAuthIdentity(nla->identity);
2472 free(nla->pkinitArgs);
2473 free(nla->identity);
2474 free(nla);
2475}
2476
2477SEC_WINNT_AUTH_IDENTITY* nla_get_identity(rdpNla* nla)
2478{
2479 if (!nla)
2480 return nullptr;
2481
2482 return nla->identity;
2483}
2484
2485NLA_STATE nla_get_state(const rdpNla* nla)
2486{
2487 if (!nla)
2488 return NLA_STATE_FINAL;
2489
2490 return nla->state;
2491}
2492
2493BOOL nla_set_state(rdpNla* nla, NLA_STATE state)
2494{
2495 if (!nla)
2496 return FALSE;
2497
2498 WLog_DBG(TAG, "-- %s\t--> %s", nla_get_state_str(nla->state), nla_get_state_str(state));
2499 nla->state = state;
2500 return TRUE;
2501}
2502
2503BOOL nla_set_service_principal(rdpNla* nla, const char* service, const char* hostname)
2504{
2505 return (credssp_auth_set_spn(nla->auth, service, hostname));
2506}
2507
2508BOOL nla_impersonate(rdpNla* nla)
2509{
2510 return credssp_auth_impersonate(nla->auth);
2511}
2512
2513BOOL nla_revert_to_self(rdpNla* nla)
2514{
2515 return credssp_auth_revert_to_self(nla->auth);
2516}
2517
2518const char* nla_get_state_str(NLA_STATE state)
2519{
2520 switch (state)
2521 {
2522 case NLA_STATE_INITIAL:
2523 return "NLA_STATE_INITIAL";
2524 case NLA_STATE_NEGO_TOKEN:
2525 return "NLA_STATE_NEGO_TOKEN";
2526 case NLA_STATE_PUB_KEY_AUTH:
2527 return "NLA_STATE_PUB_KEY_AUTH";
2528 case NLA_STATE_AUTH_INFO:
2529 return "NLA_STATE_AUTH_INFO";
2530 case NLA_STATE_POST_NEGO:
2531 return "NLA_STATE_POST_NEGO";
2532 case NLA_STATE_EARLY_USER_AUTH:
2533 return "NLA_STATE_EARLY_USER_AUTH";
2534 case NLA_STATE_FINAL:
2535 return "NLA_STATE_FINAL";
2536 default:
2537 return "UNKNOWN";
2538 }
2539}
2540
2541DWORD nla_get_error(const rdpNla* nla)
2542{
2543 if (!nla)
2544 return ERROR_INTERNAL_ERROR;
2545 return (UINT32)nla->errorCode;
2546}
2547
2548INT32 nla_get_sspi_error(const rdpNla* nla)
2549{
2550 WINPR_ASSERT(nla);
2551 return credssp_auth_sspi_error(nla->auth);
2552}
2553
2554BOOL nla_encrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer)
2555{
2556 WINPR_ASSERT(nla);
2557 WINPR_ASSERT(inBuffer);
2558 WINPR_ASSERT(outBuffer);
2559 return credssp_auth_encrypt(nla->auth, inBuffer, outBuffer, nullptr, nla->sendSeqNum++);
2560}
2561
2562BOOL nla_decrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer)
2563{
2564 WINPR_ASSERT(nla);
2565 WINPR_ASSERT(inBuffer);
2566 WINPR_ASSERT(outBuffer);
2567 return credssp_auth_decrypt(nla->auth, inBuffer, outBuffer, nla->recvSeqNum++);
2568}
2569
2570SECURITY_STATUS nla_QueryContextAttributes(rdpNla* nla, DWORD ulAttr, PVOID pBuffer)
2571{
2572 WINPR_ASSERT(nla);
2573
2574 SecurityFunctionTable* table = nullptr;
2575 CtxtHandle context = WINPR_C_ARRAY_INIT;
2576 credssp_auth_tableAndContext(nla->auth, &table, &context);
2577
2578 return table->QueryContextAttributes(&context, ulAttr, pBuffer);
2579}
2580
2581SECURITY_STATUS nla_FreeContextBuffer(rdpNla* nla, PVOID pBuffer)
2582{
2583 WINPR_ASSERT(nla);
2584
2585 SecurityFunctionTable* table = nullptr;
2586 CtxtHandle context = WINPR_C_ARRAY_INIT;
2587 credssp_auth_tableAndContext(nla->auth, &table, &context);
2588
2589 return table->FreeContextBuffer(pBuffer);
2590}
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.