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