Coverage Report

Created: 2026-10-15 06:31

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