Coverage Report

Created: 2026-09-14 06:32

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