Coverage Report

Created: 2026-05-30 06:46

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