Coverage Report

Created: 2026-02-26 06:54

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