Coverage Report

Created: 2026-01-16 07:10

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