Coverage Report

Created: 2026-04-12 07:03

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