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