Coverage Report

Created: 2026-03-04 06:17

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
15.4k
{
157
15.4k
  WINPR_ASSERT(nla);
158
15.4k
  sspi_SecBufferFree(&nla->pubKeyAuth);
159
15.4k
  sspi_SecBufferFree(&nla->authInfo);
160
15.4k
  sspi_SecBufferFree(&nla->negoToken);
161
15.4k
  sspi_SecBufferFree(&nla->ClientNonce);
162
15.4k
  sspi_SecBufferFree(&nla->PublicKey);
163
15.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
15.4k
{
174
15.4k
  WINPR_ASSERT(buffer);
175
15.4k
  sspi_SecBufferFree(buffer);
176
15.4k
  if (size > UINT32_MAX)
177
0
    return FALSE;
178
15.4k
  if (!sspi_SecBufferAlloc(buffer, (ULONG)size))
179
0
    return FALSE;
180
181
15.4k
  WINPR_ASSERT(buffer);
182
15.4k
  buffer->BufferType = SECBUFFER_TOKEN;
183
15.4k
  return TRUE;
184
15.4k
}
185
186
static BOOL nla_sec_buffer_alloc_from_data(SecBuffer* buffer, const BYTE* data, size_t offset,
187
                                           size_t size)
188
10
{
189
10
  if (!nla_sec_buffer_alloc(buffer, offset + size))
190
0
    return FALSE;
191
192
10
  WINPR_ASSERT(buffer);
193
10
  BYTE* pb = buffer->pvBuffer;
194
10
  memcpy(&pb[offset], data, size);
195
10
  return TRUE;
196
10
}
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(nullptr, TRUE);
312
0
    if (sam)
313
0
    {
314
0
      const UINT32 userLength = (UINT32)strnlen(settings->Username, INT32_MAX);
315
0
      WINPR_SAM_ENTRY* entry =
316
0
          SamLookupUserA(sam, settings->Username,
317
0
                         userLength + 1 /* ensure '\0' is checked too */, nullptr, 0);
318
0
      if (entry)
319
0
      {
320
        /**
321
         * The user could be found in SAM database.
322
         * Use entry in SAM database later instead of prompt
323
         */
324
0
        PromptPassword = FALSE;
325
0
        SamFreeEntry(sam, entry);
326
0
      }
327
328
0
      SamClose(sam);
329
0
    }
330
0
  }
331
332
0
  if (PromptPassword)
333
0
  {
334
0
    if (settings->RestrictedAdminModeRequired)
335
0
    {
336
0
      if ((settings->PasswordHash) && (strlen(settings->PasswordHash) > 0))
337
0
        PromptPassword = FALSE;
338
0
    }
339
340
0
    if (settings->RemoteCredentialGuard)
341
0
      PromptPassword = FALSE;
342
0
  }
343
344
0
  BOOL smartCardLogonWasDisabled = !settings->SmartcardLogon;
345
0
  if (PromptPassword)
346
0
  {
347
0
    switch (utils_authenticate(instance, AUTH_NLA, TRUE))
348
0
    {
349
0
      case AUTH_SKIP:
350
0
      case AUTH_SUCCESS:
351
0
        break;
352
0
      case AUTH_CANCELLED:
353
0
        freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
354
0
        return FALSE;
355
0
      case AUTH_NO_CREDENTIALS:
356
0
        WLog_INFO(TAG, "No credentials provided - using nullptr identity");
357
0
        break;
358
0
      default:
359
0
        return FALSE;
360
0
    }
361
0
  }
362
363
0
  if (!settings->Username)
364
0
  {
365
0
    sspi_FreeAuthIdentity(nla->identity);
366
0
    free(nla->identity);
367
0
    nla->identity = nullptr;
368
0
  }
369
0
  else if (settings->SmartcardLogon)
370
0
  {
371
0
    if (smartCardLogonWasDisabled)
372
0
    {
373
0
      if (!nla_adjust_settings_from_smartcard(nla))
374
0
        return FALSE;
375
0
    }
376
377
0
    if (!identity_set_from_smartcard_hash(nla->identity, settings, FreeRDP_Username,
378
0
                                          FreeRDP_Domain, FreeRDP_Password, nla->certSha1,
379
0
                                          sizeof(nla->certSha1)))
380
0
      return FALSE;
381
0
  }
382
0
  else
383
0
  {
384
0
    BOOL usePassword = TRUE;
385
386
0
    if (settings->RedirectionPassword && (settings->RedirectionPasswordLength > 0))
387
0
    {
388
0
      const WCHAR* wstr = (const WCHAR*)settings->RedirectionPassword;
389
0
      const size_t len = _wcsnlen(wstr, settings->RedirectionPasswordLength / sizeof(WCHAR));
390
391
0
      if (!identity_set_from_settings_with_pwd(nla->identity, settings, FreeRDP_Username,
392
0
                                               FreeRDP_Domain, wstr, len))
393
0
        return FALSE;
394
395
0
      usePassword = FALSE;
396
0
    }
397
398
0
    if (settings->RestrictedAdminModeRequired)
399
0
    {
400
0
      if (settings->PasswordHash && strlen(settings->PasswordHash) == 32)
401
0
      {
402
0
        if (!identity_set_from_settings(nla->identity, settings, FreeRDP_Username,
403
0
                                        FreeRDP_Domain, FreeRDP_PasswordHash))
404
0
          return FALSE;
405
406
        /**
407
         * Increase password hash length by LB_PASSWORD_MAX_LENGTH to obtain a
408
         * length exceeding the maximum (LB_PASSWORD_MAX_LENGTH) and use it this for
409
         * hash identification in WinPR.
410
         */
411
0
        nla->identity->PasswordLength += LB_PASSWORD_MAX_LENGTH;
412
0
        usePassword = FALSE;
413
0
      }
414
0
    }
415
416
0
    if (usePassword)
417
0
    {
418
0
      if (!identity_set_from_settings(nla->identity, settings, FreeRDP_Username,
419
0
                                      FreeRDP_Domain, FreeRDP_Password))
420
0
        return FALSE;
421
0
    }
422
0
  }
423
424
0
  return TRUE;
425
0
}
426
427
static int nla_client_init(rdpNla* nla)
428
0
{
429
0
  WINPR_ASSERT(nla);
430
0
  WINPR_ASSERT(nla->rdpcontext);
431
432
0
  rdpSettings* settings = nla->rdpcontext->settings;
433
0
  WINPR_ASSERT(settings);
434
435
0
  nla_set_state(nla, NLA_STATE_INITIAL);
436
437
0
  if (!nla_adjust_settings_from_smartcard(nla))
438
0
    return -1;
439
440
0
  if (!credssp_auth_init(nla->auth, NLA_AUTH_PKG, nullptr))
441
0
    return -1;
442
443
0
  if (!nla_client_setup_identity(nla))
444
0
    return -1;
445
446
0
  const char* hostname = freerdp_settings_get_server_name(settings);
447
448
0
  if (!credssp_auth_setup_client(nla->auth, "TERMSRV", hostname, nla->identity, nla->pkinitArgs))
449
0
    return -1;
450
451
0
  const BYTE* data = nullptr;
452
0
  DWORD length = 0;
453
0
  if (!transport_get_public_key(nla->transport, &data, &length))
454
0
  {
455
0
    WLog_ERR(TAG, "Failed to get public key");
456
0
    return -1;
457
0
  }
458
459
0
  if (!nla_sec_buffer_alloc_from_data(&nla->PublicKey, data, 0, length))
460
0
  {
461
0
    WLog_ERR(TAG, "Failed to allocate sspi secBuffer");
462
0
    return -1;
463
0
  }
464
465
0
  return 1;
466
0
}
467
468
int nla_client_begin(rdpNla* nla)
469
0
{
470
0
  WINPR_ASSERT(nla);
471
472
0
  if (nla_client_init(nla) < 1)
473
0
    return -1;
474
475
0
  if (nla_get_state(nla) != NLA_STATE_INITIAL)
476
0
    return -1;
477
478
  /*
479
   * from tspkg.dll: 0x00000132
480
   * ISC_REQ_MUTUAL_AUTH
481
   * ISC_REQ_CONFIDENTIALITY
482
   * ISC_REQ_USE_SESSION_KEY
483
   * ISC_REQ_ALLOCATE_MEMORY
484
   */
485
0
  credssp_auth_set_flags(nla->auth, ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY);
486
487
0
  const int rc = credssp_auth_authenticate(nla->auth);
488
489
0
  switch (rc)
490
0
  {
491
0
    case 0:
492
0
      if (!nla_send(nla))
493
0
        return -1;
494
0
      nla_set_state(nla, NLA_STATE_NEGO_TOKEN);
495
0
      break;
496
0
    case 1:
497
0
      if (credssp_auth_have_output_token(nla->auth))
498
0
      {
499
0
        if (!nla_send(nla))
500
0
          return -1;
501
0
      }
502
0
      nla_set_state(nla, NLA_STATE_FINAL);
503
0
      break;
504
0
    default:
505
0
      switch (credssp_auth_sspi_error(nla->auth))
506
0
      {
507
0
        case SEC_E_LOGON_DENIED:
508
0
        case SEC_E_NO_CREDENTIALS:
509
0
          freerdp_set_last_error_log(nla->rdpcontext,
510
0
                                     FREERDP_ERROR_CONNECT_LOGON_FAILURE);
511
0
          break;
512
0
        default:
513
0
          break;
514
0
      }
515
0
      return -1;
516
0
  }
517
518
0
  return 1;
519
0
}
520
521
static int nla_client_recv_nego_token(rdpNla* nla)
522
0
{
523
0
  credssp_auth_take_input_buffer(nla->auth, &nla->negoToken);
524
0
  const int rc = credssp_auth_authenticate(nla->auth);
525
526
0
  switch (rc)
527
0
  {
528
0
    case 0:
529
0
      if (!nla_send(nla))
530
0
        return -1;
531
0
      break;
532
0
    case 1: /* completed */
533
0
    {
534
0
      int res = -1;
535
0
      if (nla->peerVersion < 5)
536
0
        res = nla_encrypt_public_key_echo(nla);
537
0
      else
538
0
        res = nla_encrypt_public_key_hash(nla);
539
540
0
      if (!res)
541
0
        return -1;
542
543
0
      if (!nla_send(nla))
544
0
        return -1;
545
546
0
      nla_set_state(nla, NLA_STATE_PUB_KEY_AUTH);
547
0
    }
548
0
    break;
549
550
0
    default:
551
0
      return -1;
552
0
  }
553
554
0
  return 1;
555
0
}
556
557
static int nla_client_recv_pub_key_auth(rdpNla* nla)
558
0
{
559
0
  BOOL rc = FALSE;
560
561
0
  WINPR_ASSERT(nla);
562
563
  /* Verify Server Public Key Echo */
564
0
  if (nla->peerVersion < 5)
565
0
    rc = nla_decrypt_public_key_echo(nla);
566
0
  else
567
0
    rc = nla_decrypt_public_key_hash(nla);
568
569
0
  sspi_SecBufferFree(&nla->pubKeyAuth);
570
571
0
  if (!rc)
572
0
    return -1;
573
574
  /* Send encrypted credentials */
575
0
  rc = nla_encrypt_ts_credentials(nla);
576
0
  if (!rc)
577
0
    return -1;
578
579
0
  if (!nla_send(nla))
580
0
    return -1;
581
582
0
  if (nla->earlyUserAuth)
583
0
  {
584
0
    transport_set_early_user_auth_mode(nla->transport, TRUE);
585
0
    nla_set_state(nla, NLA_STATE_EARLY_USER_AUTH);
586
0
  }
587
0
  else
588
0
    nla_set_state(nla, NLA_STATE_AUTH_INFO);
589
0
  return 1;
590
0
}
591
592
static int nla_client_recv_early_user_auth(rdpNla* nla)
593
0
{
594
0
  WINPR_ASSERT(nla);
595
596
0
  transport_set_early_user_auth_mode(nla->transport, FALSE);
597
0
  nla_set_state(nla, NLA_STATE_AUTH_INFO);
598
0
  return 1;
599
0
}
600
601
static int nla_client_recv(rdpNla* nla)
602
18
{
603
18
  WINPR_ASSERT(nla);
604
605
18
  switch (nla_get_state(nla))
606
18
  {
607
0
    case NLA_STATE_NEGO_TOKEN:
608
0
      return nla_client_recv_nego_token(nla);
609
610
0
    case NLA_STATE_PUB_KEY_AUTH:
611
0
      return nla_client_recv_pub_key_auth(nla);
612
613
0
    case NLA_STATE_EARLY_USER_AUTH:
614
0
      return nla_client_recv_early_user_auth(nla);
615
616
0
    case NLA_STATE_FINAL:
617
18
    default:
618
18
      WLog_ERR(TAG, "NLA in invalid client receive state %s",
619
18
               nla_get_state_str(nla_get_state(nla)));
620
18
      return -1;
621
18
  }
622
18
}
623
624
static int nla_client_authenticate(rdpNla* nla)
625
0
{
626
0
  int rc = -1;
627
628
0
  WINPR_ASSERT(nla);
629
630
0
  wStream* s = Stream_New(nullptr, 4096);
631
632
0
  if (!s)
633
0
  {
634
0
    WLog_ERR(TAG, "Stream_New failed!");
635
0
    return -1;
636
0
  }
637
638
0
  if (nla_client_begin(nla) < 1)
639
0
    goto fail;
640
641
0
  while (nla_get_state(nla) < NLA_STATE_AUTH_INFO)
642
0
  {
643
0
    Stream_ResetPosition(s);
644
0
    const int status = transport_read_pdu(nla->transport, s);
645
646
0
    if (status < 0)
647
0
    {
648
0
      WLog_ERR(TAG, "nla_client_authenticate failure");
649
0
      goto fail;
650
0
    }
651
652
0
    const int status2 = nla_recv_pdu(nla, s);
653
654
0
    if (status2 < 0)
655
0
      goto fail;
656
0
  }
657
658
0
  rc = 1;
659
0
fail:
660
0
  Stream_Free(s, TRUE);
661
0
  return rc;
662
0
}
663
664
/**
665
 * Initialize NTLMSSP authentication module (server).
666
 */
667
668
static int nla_server_init(rdpNla* nla)
669
0
{
670
0
  WINPR_ASSERT(nla);
671
672
0
  const BYTE* data = nullptr;
673
0
  DWORD length = 0;
674
0
  if (!transport_get_public_key(nla->transport, &data, &length))
675
0
  {
676
0
    WLog_ERR(TAG, "Failed to get public key");
677
0
    return -1;
678
0
  }
679
680
0
  if (!nla_sec_buffer_alloc_from_data(&nla->PublicKey, data, 0, length))
681
0
  {
682
0
    WLog_ERR(TAG, "Failed to allocate SecBuffer for public key");
683
0
    return -1;
684
0
  }
685
686
0
  if (!credssp_auth_init(nla->auth, NLA_AUTH_PKG, nullptr))
687
0
    return -1;
688
689
0
  if (!credssp_auth_setup_server(nla->auth))
690
0
    return -1;
691
692
0
  nla_set_state(nla, NLA_STATE_INITIAL);
693
0
  return 1;
694
0
}
695
696
static wStream* nla_server_recv_stream(rdpNla* nla)
697
0
{
698
0
  wStream* s = nullptr;
699
0
  int status = -1;
700
701
0
  WINPR_ASSERT(nla);
702
703
0
  s = Stream_New(nullptr, 4096);
704
705
0
  if (!s)
706
0
    goto fail;
707
708
0
  status = transport_read_pdu(nla->transport, s);
709
710
0
fail:
711
0
  if (status < 0)
712
0
  {
713
0
    WLog_ERR(TAG, "nla_recv() error: %d", status);
714
0
    Stream_Free(s, TRUE);
715
0
    return nullptr;
716
0
  }
717
718
0
  return s;
719
0
}
720
721
static BOOL nla_server_recv_credentials(rdpNla* nla)
722
0
{
723
0
  WINPR_ASSERT(nla);
724
725
0
  if (nla_server_recv(nla) < 0)
726
0
    return FALSE;
727
728
0
  if (!nla_decrypt_ts_credentials(nla))
729
0
    return FALSE;
730
731
0
  if (!nla_impersonate(nla))
732
0
    return FALSE;
733
734
0
  if (!nla_revert_to_self(nla))
735
0
    return FALSE;
736
737
0
  return TRUE;
738
0
}
739
740
/**
741
 * Authenticate with client using CredSSP (server).
742
 * @param nla The NLA instance to use
743
 *
744
 * @return 1 if authentication is successful
745
 */
746
747
static int nla_server_authenticate(rdpNla* nla)
748
0
{
749
0
  int ret = -1;
750
751
0
  WINPR_ASSERT(nla);
752
753
0
  if (nla_server_init(nla) < 1)
754
0
    goto fail;
755
756
  /*
757
   * from tspkg.dll: 0x00000112
758
   * ASC_REQ_MUTUAL_AUTH
759
   * ASC_REQ_CONFIDENTIALITY
760
   * ASC_REQ_ALLOCATE_MEMORY
761
   */
762
0
  credssp_auth_set_flags(nla->auth, ASC_REQ_MUTUAL_AUTH | ASC_REQ_CONFIDENTIALITY |
763
0
                                        ASC_REQ_CONNECTION | ASC_REQ_USE_SESSION_KEY |
764
0
                                        ASC_REQ_SEQUENCE_DETECT | ASC_REQ_EXTENDED_ERROR);
765
766
  /* Client is starting, here es the state machine:
767
   *
768
   *  -- NLA_STATE_INITIAL  --> NLA_STATE_INITIAL
769
   * ----->> sending...
770
   *    ----->> protocol version 6
771
   *    ----->> nego token
772
   *    ----->> client nonce
773
   * <<----- receiving...
774
   *    <<----- protocol version 6
775
   *    <<----- nego token
776
   * ----->> sending...
777
   *    ----->> protocol version 6
778
   *    ----->> nego token
779
   *    ----->> public key auth
780
   *    ----->> client nonce
781
   * -- NLA_STATE_NEGO_TOKEN  --> NLA_STATE_PUB_KEY_AUTH
782
   * <<----- receiving...
783
   *    <<----- protocol version 6
784
   *    <<----- public key info
785
   * ----->> sending...
786
   *    ----->> protocol version 6
787
   *    ----->> auth info
788
   *    ----->> client nonce
789
   * -- NLA_STATE_PUB_KEY_AUTH  --> NLA_STATE
790
   */
791
792
0
  while (TRUE)
793
0
  {
794
0
    int res = -1;
795
796
0
    if (nla_server_recv(nla) < 0)
797
0
      goto fail;
798
799
0
    WLog_DBG(TAG, "Receiving Authentication Token");
800
0
    credssp_auth_take_input_buffer(nla->auth, &nla->negoToken);
801
802
0
    res = credssp_auth_authenticate(nla->auth);
803
804
0
    if (res == -1)
805
0
    {
806
      /* Special handling of these specific error codes as NTSTATUS_FROM_WIN32
807
         unfortunately does not map directly to the corresponding NTSTATUS values
808
       */
809
0
      switch (GetLastError())
810
0
      {
811
0
        case ERROR_PASSWORD_MUST_CHANGE:
812
0
          nla->errorCode = STATUS_PASSWORD_MUST_CHANGE;
813
0
          break;
814
815
0
        case ERROR_PASSWORD_EXPIRED:
816
0
          nla->errorCode = STATUS_PASSWORD_EXPIRED;
817
0
          break;
818
819
0
        case ERROR_ACCOUNT_DISABLED:
820
0
          nla->errorCode = STATUS_ACCOUNT_DISABLED;
821
0
          break;
822
823
0
        default:
824
0
          nla->errorCode = NTSTATUS_FROM_WIN32(GetLastError());
825
0
          break;
826
0
      }
827
828
0
      (void)nla_send(nla);
829
      /* Access Denied */
830
0
      goto fail;
831
0
    }
832
833
0
    if (res == 1)
834
0
    {
835
      /* Process final part of the nego token exchange */
836
0
      if (credssp_auth_have_output_token(nla->auth))
837
0
      {
838
0
        if (!nla_send(nla))
839
0
          goto fail;
840
841
0
        if (nla_server_recv(nla) < 0)
842
0
          goto fail;
843
844
0
        WLog_DBG(TAG, "Receiving pubkey Token");
845
0
      }
846
847
0
      if (nla->peerVersion < 5)
848
0
        res = nla_decrypt_public_key_echo(nla);
849
0
      else
850
0
        res = nla_decrypt_public_key_hash(nla);
851
852
0
      if (!res)
853
0
        goto fail;
854
855
      /* Clear nego token buffer or we will send it again to the client */
856
0
      sspi_SecBufferFree(&nla->negoToken);
857
858
0
      if (nla->peerVersion < 5)
859
0
        res = nla_encrypt_public_key_echo(nla);
860
0
      else
861
0
        res = nla_encrypt_public_key_hash(nla);
862
863
0
      if (!res)
864
0
        goto fail;
865
0
    }
866
867
    /* send authentication token */
868
0
    WLog_DBG(TAG, "Sending Authentication Token");
869
870
0
    if (!nla_send(nla))
871
0
      goto fail;
872
873
0
    if (res == 1)
874
0
    {
875
0
      ret = 1;
876
0
      break;
877
0
    }
878
0
  }
879
880
  /* Receive encrypted credentials */
881
0
  if (!nla_server_recv_credentials(nla))
882
0
    ret = -1;
883
884
0
fail:
885
0
  nla_buffer_free(nla);
886
0
  return ret;
887
0
}
888
889
/**
890
 * Authenticate using CredSSP.
891
 * @param nla The NLA instance to use
892
 *
893
 * @return 1 if authentication is successful
894
 */
895
896
int nla_authenticate(rdpNla* nla)
897
0
{
898
0
  WINPR_ASSERT(nla);
899
900
0
  if (nla->server)
901
0
    return nla_server_authenticate(nla);
902
0
  else
903
0
    return nla_client_authenticate(nla);
904
0
}
905
906
static void ap_integer_increment_le(BYTE* number, size_t size)
907
0
{
908
0
  WINPR_ASSERT(number || (size == 0));
909
910
0
  for (size_t index = 0; index < size; index++)
911
0
  {
912
0
    if (number[index] < 0xFF)
913
0
    {
914
0
      number[index]++;
915
0
      break;
916
0
    }
917
0
    else
918
0
    {
919
0
      number[index] = 0;
920
0
      continue;
921
0
    }
922
0
  }
923
0
}
924
925
static void ap_integer_decrement_le(BYTE* number, size_t size)
926
0
{
927
0
  WINPR_ASSERT(number || (size == 0));
928
929
0
  for (size_t index = 0; index < size; index++)
930
0
  {
931
0
    if (number[index] > 0)
932
0
    {
933
0
      number[index]--;
934
0
      break;
935
0
    }
936
0
    else
937
0
    {
938
0
      number[index] = 0xFF;
939
0
      continue;
940
0
    }
941
0
  }
942
0
}
943
944
BOOL nla_encrypt_public_key_echo(rdpNla* nla)
945
0
{
946
0
  BOOL status = FALSE;
947
948
0
  WINPR_ASSERT(nla);
949
950
0
  sspi_SecBufferFree(&nla->pubKeyAuth);
951
0
  if (nla->server)
952
0
  {
953
0
    SecBuffer buf = WINPR_C_ARRAY_INIT;
954
0
    if (!sspi_SecBufferAlloc(&buf, nla->PublicKey.cbBuffer))
955
0
      return FALSE;
956
0
    ap_integer_increment_le(buf.pvBuffer, buf.cbBuffer);
957
0
    status =
958
0
        credssp_auth_encrypt(nla->auth, &buf, &nla->pubKeyAuth, nullptr, 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, nullptr,
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 = nullptr;
974
0
  SecBuffer buf = WINPR_C_ARRAY_INIT;
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, nullptr, 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 = WINPR_C_ARRAY_INIT;
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 = nullptr;
1058
0
  BYTE serverClientHash[WINPR_SHA256_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
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 = WINPR_C_ARRAY_INIT;
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
WINPR_ATTR_NODISCARD
1254
static MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* nla_read_NtlmCreds(WINPR_ATTR_UNUSED rdpNla* nla,
1255
                                                                 wStream* s)
1256
0
{
1257
0
  WINPR_ASSERT(nla);
1258
0
  WINPR_ASSERT(s);
1259
1260
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 32 + 4))
1261
0
    return nullptr;
1262
1263
0
  size_t pos = Stream_GetPosition(s);
1264
0
  Stream_Seek(s, 32);
1265
1266
0
  ULONG EncryptedCredsSize = Stream_Get_UINT32(s);
1267
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, EncryptedCredsSize))
1268
0
    return nullptr;
1269
1270
0
  if (!Stream_SetPosition(s, pos))
1271
0
    return nullptr;
1272
1273
0
  MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* ret = (MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL*)calloc(
1274
0
      1, sizeof(MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL) - 1 + EncryptedCredsSize);
1275
0
  if (!ret)
1276
0
    return nullptr;
1277
1278
0
  ret->Version = Stream_Get_UINT32(s);
1279
0
  ret->Flags = Stream_Get_UINT32(s);
1280
0
  Stream_Read(s, ret->CredentialKey.Data, MSV1_0_CREDENTIAL_KEY_LENGTH);
1281
0
  {
1282
0
    const UINT32 val = Stream_Get_UINT32(s);
1283
0
    if (!nla_credentialTypeValid(val))
1284
0
    {
1285
0
      free(ret);
1286
0
      return nullptr;
1287
0
    }
1288
0
    ret->CredentialKeyType = WINPR_ASSERTING_INT_CAST(MSV1_0_CREDENTIAL_KEY_TYPE, val);
1289
0
  }
1290
0
  ret->EncryptedCredsSize = EncryptedCredsSize;
1291
0
  Stream_Read(s, ret->EncryptedCreds, EncryptedCredsSize);
1292
1293
0
  return ret;
1294
0
}
1295
1296
/** @brief kind of RCG credentials */
1297
typedef enum
1298
{
1299
  RCG_TYPE_NONE,
1300
  RCG_TYPE_KERB,
1301
  RCG_TYPE_NTLM
1302
} RemoteGuardPackageCredType;
1303
1304
static BOOL nla_read_TSRemoteGuardPackageCred(WINPR_ATTR_UNUSED rdpNla* nla, WinPrAsn1Decoder* dec,
1305
                                              RemoteGuardPackageCredType* credsType,
1306
                                              wStream* payload)
1307
0
{
1308
0
  WinPrAsn1_OctetString packageName = WINPR_C_ARRAY_INIT;
1309
0
  WinPrAsn1_OctetString credBuffer = WINPR_C_ARRAY_INIT;
1310
0
  BOOL error = FALSE;
1311
0
  char packageNameStr[100] = WINPR_C_ARRAY_INIT;
1312
1313
0
  WINPR_ASSERT(nla);
1314
0
  WINPR_ASSERT(dec);
1315
0
  WINPR_ASSERT(credsType);
1316
0
  WINPR_ASSERT(payload);
1317
1318
0
  *credsType = RCG_TYPE_NONE;
1319
1320
  /* packageName [0] OCTET STRING */
1321
0
  if (!WinPrAsn1DecReadContextualOctetString(dec, 0, &error, &packageName, FALSE) || error)
1322
0
    return FALSE;
1323
1324
0
  ConvertMszWCharNToUtf8((WCHAR*)packageName.data, packageName.len / sizeof(WCHAR),
1325
0
                         packageNameStr, sizeof(packageNameStr));
1326
0
  WLog_DBG(TAG, "TSRemoteGuardPackageCred(%s)", packageNameStr);
1327
1328
  /* credBuffer [1] OCTET STRING, */
1329
0
  if (!WinPrAsn1DecReadContextualOctetString(dec, 1, &error, &credBuffer, FALSE) || error)
1330
0
    return FALSE;
1331
1332
0
  if (_stricmp(packageNameStr, "Kerberos") == 0)
1333
0
  {
1334
0
    *credsType = RCG_TYPE_KERB;
1335
0
  }
1336
0
  else if (_stricmp(packageNameStr, "NTLM") == 0)
1337
0
  {
1338
0
    *credsType = RCG_TYPE_NTLM;
1339
0
  }
1340
0
  else
1341
0
  {
1342
0
    WLog_INFO(TAG, "TSRemoteGuardPackageCred package %s not handled", packageNameStr);
1343
0
    return FALSE;
1344
0
  }
1345
1346
0
  Stream_StaticInit(payload, credBuffer.data, credBuffer.len);
1347
0
  return TRUE;
1348
0
}
1349
1350
/** @brief kind of TSCreds */
1351
typedef enum
1352
{
1353
  TSCREDS_INVALID = 0,
1354
  TSCREDS_USER_PASSWD = 1,
1355
  TSCREDS_SMARTCARD = 2,
1356
  TSCREDS_REMOTEGUARD = 6
1357
} TsCredentialsType;
1358
1359
static BOOL nla_read_ts_credentials(rdpNla* nla, SecBuffer* data)
1360
0
{
1361
0
  WinPrAsn1Decoder dec = WinPrAsn1Decoder_init();
1362
0
  WinPrAsn1Decoder dec2 = WinPrAsn1Decoder_init();
1363
0
  WinPrAsn1_OctetString credentials = WINPR_C_ARRAY_INIT;
1364
0
  BOOL error = FALSE;
1365
0
  WinPrAsn1_INTEGER credType = -1;
1366
0
  BOOL ret = TRUE;
1367
1368
0
  WINPR_ASSERT(nla);
1369
0
  WINPR_ASSERT(data);
1370
1371
0
  WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, (BYTE*)data->pvBuffer, data->cbBuffer);
1372
1373
  /* TSCredentials */
1374
0
  if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1375
0
    return FALSE;
1376
0
  dec = dec2;
1377
1378
  /* credType [0] INTEGER */
1379
0
  if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &credType))
1380
0
    return FALSE;
1381
1382
  /* credentials [1] OCTET STRING */
1383
0
  if (!WinPrAsn1DecReadContextualOctetString(&dec, 1, &error, &credentials, FALSE))
1384
0
    return FALSE;
1385
1386
0
  WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, credentials.data, credentials.len);
1387
1388
0
  rdpSettings* settings = nla->rdpcontext->settings;
1389
0
  if (nego_get_remoteCredentialGuard(nla->rdpcontext->rdp->nego) &&
1390
0
      credType != TSCREDS_REMOTEGUARD)
1391
0
  {
1392
0
    WLog_ERR(TAG, "connecting with RCG but it's not TSRemoteGuard credentials");
1393
0
    return FALSE;
1394
0
  }
1395
1396
0
  switch (credType)
1397
0
  {
1398
0
    case TSCREDS_USER_PASSWD:
1399
0
    {
1400
      /* TSPasswordCreds */
1401
0
      if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1402
0
        return FALSE;
1403
0
      dec = dec2;
1404
1405
      /* domainName [0] OCTET STRING */
1406
0
      if (!set_creds_octetstring_to_settings(&dec, 0, FALSE, FreeRDP_Domain, settings))
1407
0
        return FALSE;
1408
1409
      /* userName [1] OCTET STRING */
1410
0
      if (!set_creds_octetstring_to_settings(&dec, 1, FALSE, FreeRDP_Username, settings))
1411
0
        return FALSE;
1412
1413
      /* password [2] OCTET STRING */
1414
0
      return set_creds_octetstring_to_settings(&dec, 2, FALSE, FreeRDP_Password, settings);
1415
0
    }
1416
0
    case TSCREDS_SMARTCARD:
1417
0
    {
1418
      /* TSSmartCardCreds */
1419
0
      if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1420
0
        return FALSE;
1421
0
      dec = dec2;
1422
1423
      /* pin [0] OCTET STRING, */
1424
0
      if (!set_creds_octetstring_to_settings(&dec, 0, FALSE, FreeRDP_Password, settings))
1425
0
        return FALSE;
1426
0
      settings->PasswordIsSmartcardPin = TRUE;
1427
1428
      /* cspData [1] TSCspDataDetail */
1429
0
      WinPrAsn1Decoder cspDetails = WinPrAsn1Decoder_init();
1430
0
      if (!WinPrAsn1DecReadContextualSequence(&dec, 1, &error, &cspDetails) && error)
1431
0
        return FALSE;
1432
0
      if (!nla_read_TSCspDataDetail(&cspDetails, settings))
1433
0
        return FALSE;
1434
1435
      /* userHint [2] OCTET STRING OPTIONAL */
1436
0
      if (!set_creds_octetstring_to_settings(&dec, 2, TRUE, FreeRDP_Username, settings))
1437
0
        return FALSE;
1438
1439
      /* domainHint [3] OCTET STRING OPTIONAL */
1440
0
      return set_creds_octetstring_to_settings(&dec, 3, TRUE, FreeRDP_Domain, settings);
1441
0
    }
1442
0
    case TSCREDS_REMOTEGUARD:
1443
0
    {
1444
      /* TSRemoteGuardCreds */
1445
0
      if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1446
0
        return FALSE;
1447
1448
      /* logonCred[0] TSRemoteGuardPackageCred */
1449
0
      KERB_TICKET_LOGON kerbLogon = { .MessageType = KerbInvalidValue,
1450
0
                                    .Flags = 0,
1451
0
                                    .ServiceTicketLength = 0,
1452
0
                                    .TicketGrantingTicketLength = 0,
1453
0
                                    .ServiceTicket = nullptr,
1454
0
                                    .TicketGrantingTicket = nullptr };
1455
1456
0
      WinPrAsn1Decoder logonCredsSeq = WinPrAsn1Decoder_init();
1457
1458
0
      if (!WinPrAsn1DecReadContextualSequence(&dec2, 0, &error, &logonCredsSeq) || error)
1459
0
        return FALSE;
1460
1461
0
      RemoteGuardPackageCredType logonCredsType = RCG_TYPE_NONE;
1462
0
      wStream logonPayload = WINPR_C_ARRAY_INIT;
1463
0
      if (!nla_read_TSRemoteGuardPackageCred(nla, &logonCredsSeq, &logonCredsType,
1464
0
                                             &logonPayload))
1465
0
        return FALSE;
1466
0
      if (logonCredsType != RCG_TYPE_KERB)
1467
0
      {
1468
0
        WLog_ERR(TAG, "logonCred must be some Kerberos creds");
1469
0
        return FALSE;
1470
0
      }
1471
1472
0
      if (!nla_read_KERB_TICKET_LOGON(nla, &logonPayload, &kerbLogon))
1473
0
      {
1474
0
        WLog_ERR(TAG, "invalid KERB_TICKET_LOGON");
1475
0
        return FALSE;
1476
0
      }
1477
1478
      /* supplementalCreds [1] SEQUENCE OF TSRemoteGuardPackageCred OPTIONAL, */
1479
0
      MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* suppCreds = nullptr;
1480
0
      WinPrAsn1Decoder suppCredsSeq = WinPrAsn1Decoder_init();
1481
1482
0
      if (WinPrAsn1DecReadContextualSequence(&dec2, 1, &error, &suppCredsSeq) &&
1483
0
          Stream_GetRemainingLength(&suppCredsSeq.source))
1484
0
      {
1485
0
        WinPrAsn1Decoder ntlmCredsSeq = WinPrAsn1Decoder_init();
1486
0
        if (!WinPrAsn1DecReadSequence(&suppCredsSeq, &ntlmCredsSeq))
1487
0
          return FALSE;
1488
1489
0
        RemoteGuardPackageCredType suppCredsType = RCG_TYPE_NONE;
1490
0
        wStream ntlmPayload = WINPR_C_ARRAY_INIT;
1491
0
        if (!nla_read_TSRemoteGuardPackageCred(nla, &ntlmCredsSeq, &suppCredsType,
1492
0
                                               &ntlmPayload))
1493
0
          return FALSE;
1494
1495
0
        if (suppCredsType != RCG_TYPE_NTLM)
1496
0
        {
1497
0
          WLog_ERR(TAG, "supplementalCreds must be some NTLM creds");
1498
0
          return FALSE;
1499
0
        }
1500
1501
0
        suppCreds = nla_read_NtlmCreds(nla, &ntlmPayload);
1502
0
        if (!suppCreds)
1503
0
        {
1504
0
          WLog_ERR(TAG, "invalid supplementalCreds");
1505
0
          return FALSE;
1506
0
        }
1507
0
      }
1508
0
      else if (error)
1509
0
      {
1510
0
        WLog_ERR(TAG, "invalid supplementalCreds");
1511
0
        return FALSE;
1512
0
      }
1513
1514
0
      freerdp_peer* peer = nla->rdpcontext->peer;
1515
0
      ret = IFCALLRESULT(TRUE, peer->RemoteCredentials, peer, &kerbLogon, suppCreds);
1516
0
      free(suppCreds);
1517
0
      break;
1518
0
    }
1519
0
    default:
1520
0
      WLog_DBG(TAG, "TSCredentials type %d not supported for now", credType);
1521
0
      ret = FALSE;
1522
0
      break;
1523
0
  }
1524
1525
0
  return ret;
1526
0
}
1527
1528
static BOOL nla_write_KERB_TICKET_LOGON(wStream* s, const KERB_TICKET_LOGON* ticket)
1529
0
{
1530
0
  WINPR_ASSERT(ticket);
1531
1532
0
  if (!Stream_EnsureRemainingCapacity(s, (4ULL * 4) + 16ULL + ticket->ServiceTicketLength +
1533
0
                                             ticket->TicketGrantingTicketLength))
1534
0
    return FALSE;
1535
1536
0
  Stream_Write_UINT32(s, KerbTicketLogon);
1537
0
  Stream_Write_UINT32(s, ticket->Flags);
1538
0
  Stream_Write_UINT32(s, ticket->ServiceTicketLength);
1539
0
  Stream_Write_UINT32(s, ticket->TicketGrantingTicketLength);
1540
1541
0
  Stream_Write_UINT64(s, 0x20);                               /* offset of TGS in the packet */
1542
0
  Stream_Write_UINT64(s, 0x20 + ticket->ServiceTicketLength); /* offset of TGT in packet */
1543
1544
0
  Stream_Write(s, ticket->ServiceTicket, ticket->ServiceTicketLength);
1545
0
  Stream_Write(s, ticket->TicketGrantingTicket, ticket->TicketGrantingTicketLength);
1546
0
  return TRUE;
1547
0
}
1548
1549
static BOOL nla_get_KERB_TICKET_LOGON(rdpNla* nla, KERB_TICKET_LOGON* logonTicket)
1550
0
{
1551
0
  WINPR_ASSERT(nla);
1552
0
  WINPR_ASSERT(logonTicket);
1553
1554
0
  SecurityFunctionTable* table = nullptr;
1555
0
  CtxtHandle context = WINPR_C_ARRAY_INIT;
1556
0
  credssp_auth_tableAndContext(nla->auth, &table, &context);
1557
0
  return table->QueryContextAttributes(&context, SECPKG_CRED_ATTR_TICKET_LOGON, logonTicket) ==
1558
0
         SEC_E_OK;
1559
0
}
1560
1561
static BOOL nla_write_TSRemoteGuardKerbCred(rdpNla* nla, WinPrAsn1Encoder* enc)
1562
0
{
1563
0
  BOOL ret = FALSE;
1564
0
  wStream* s = nullptr;
1565
0
  char kerberos[] = { 'K', '\0', 'e', '\0', 'r', '\0', 'b', '\0',
1566
0
                    'e', '\0', 'r', '\0', 'o', '\0', 's', '\0' };
1567
0
  WinPrAsn1_OctetString packageName = { sizeof(kerberos), (BYTE*)kerberos };
1568
0
  WinPrAsn1_OctetString credBuffer;
1569
0
  KERB_TICKET_LOGON logonTicket;
1570
1571
0
  logonTicket.ServiceTicket = nullptr;
1572
0
  logonTicket.TicketGrantingTicket = nullptr;
1573
1574
  /* packageName [0] OCTET STRING */
1575
0
  if (!WinPrAsn1EncContextualOctetString(enc, 0, &packageName))
1576
0
    goto out;
1577
1578
  /* credBuffer [1] OCTET STRING */
1579
0
  if (!nla_get_KERB_TICKET_LOGON(nla, &logonTicket))
1580
0
    goto out;
1581
1582
0
  s = Stream_New(nullptr, 2000);
1583
0
  if (!s)
1584
0
    goto out;
1585
1586
0
  if (!nla_write_KERB_TICKET_LOGON(s, &logonTicket))
1587
0
    goto out;
1588
1589
0
  credBuffer.len = Stream_GetPosition(s);
1590
0
  credBuffer.data = Stream_Buffer(s);
1591
0
  ret = WinPrAsn1EncContextualOctetString(enc, 1, &credBuffer) != 0;
1592
1593
0
out:
1594
0
  free(logonTicket.ServiceTicket);
1595
0
  free(logonTicket.TicketGrantingTicket);
1596
0
  Stream_Free(s, TRUE);
1597
0
  return ret;
1598
0
}
1599
1600
static BOOL nla_write_TSRemoteGuardNtlmCred(rdpNla* nla, WinPrAsn1Encoder* enc,
1601
                                            const MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* pntlm)
1602
0
{
1603
0
  WINPR_UNUSED(nla);
1604
0
  BOOL ret = FALSE;
1605
0
  BYTE ntlm[] = { 'N', '\0', 'T', '\0', 'L', '\0', 'M', '\0' };
1606
0
  const WinPrAsn1_OctetString packageName = { sizeof(ntlm), ntlm };
1607
1608
  /* packageName [0] OCTET STRING */
1609
0
  if (!WinPrAsn1EncContextualOctetString(enc, 0, &packageName))
1610
0
    return FALSE;
1611
1612
  /* credBuffer [1] OCTET STRING */
1613
0
  wStream* s = Stream_New(nullptr, 300);
1614
0
  if (!s)
1615
0
    goto out;
1616
1617
0
  Stream_Write_UINT32(s, pntlm->Version); /* Version */
1618
0
  Stream_Write_UINT32(s, pntlm->Flags);   /* Flags */
1619
1620
0
  Stream_Write(s, pntlm->CredentialKey.Data, MSV1_0_CREDENTIAL_KEY_LENGTH);
1621
0
  Stream_Write_UINT32(s, pntlm->CredentialKeyType);
1622
0
  Stream_Write_UINT32(s, pntlm->EncryptedCredsSize);
1623
0
  Stream_Write(s, pntlm->EncryptedCreds, pntlm->EncryptedCredsSize);
1624
0
  Stream_Zero(s, 6 + 16 * 4 + 14);
1625
1626
0
  {
1627
0
    WinPrAsn1_OctetString credBuffer = { Stream_GetPosition(s), Stream_Buffer(s) };
1628
0
    ret = WinPrAsn1EncContextualOctetString(enc, 1, &credBuffer) != 0;
1629
0
  }
1630
1631
0
out:
1632
0
  Stream_Free(s, TRUE);
1633
0
  return ret;
1634
0
}
1635
1636
static BOOL nla_encode_ts_smartcard_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1637
0
{
1638
0
  struct
1639
0
  {
1640
0
    WinPrAsn1_tagId tag;
1641
0
    FreeRDP_Settings_Keys_String setting_id;
1642
0
  } cspData_fields[] = { { 1, FreeRDP_CardName },
1643
0
                       { 2, FreeRDP_ReaderName },
1644
0
                       { 3, FreeRDP_ContainerName },
1645
0
                       { 4, FreeRDP_CspName } };
1646
0
  WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
1647
1648
0
  WINPR_ASSERT(nla);
1649
0
  WINPR_ASSERT(enc);
1650
0
  WINPR_ASSERT(nla->rdpcontext);
1651
1652
0
  const rdpSettings* settings = nla->rdpcontext->settings;
1653
0
  WINPR_ASSERT(settings);
1654
1655
  /* TSSmartCardCreds */
1656
0
  if (!WinPrAsn1EncSeqContainer(enc))
1657
0
    return FALSE;
1658
1659
  /* pin [0] OCTET STRING */
1660
0
  size_t ss = 0;
1661
0
  octet_string.data =
1662
0
      (BYTE*)freerdp_settings_get_string_as_utf16(settings, FreeRDP_Password, &ss);
1663
0
  octet_string.len = ss * sizeof(WCHAR);
1664
0
  BOOL res = WinPrAsn1EncContextualOctetString(enc, 0, &octet_string) > 0;
1665
0
  free(octet_string.data);
1666
0
  if (!res)
1667
0
    return FALSE;
1668
1669
  /* cspData [1] SEQUENCE */
1670
0
  if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
1671
0
    return FALSE;
1672
1673
  /* keySpec [0] INTEGER */
1674
0
  if (!WinPrAsn1EncContextualInteger(
1675
0
          enc, 0,
1676
0
          WINPR_ASSERTING_INT_CAST(WinPrAsn1_INTEGER,
1677
0
                                   freerdp_settings_get_uint32(settings, FreeRDP_KeySpec))))
1678
0
    return FALSE;
1679
1680
0
  for (size_t i = 0; i < ARRAYSIZE(cspData_fields); i++)
1681
0
  {
1682
0
    size_t len = 0;
1683
1684
0
    octet_string.data = (BYTE*)freerdp_settings_get_string_as_utf16(
1685
0
        settings, cspData_fields[i].setting_id, &len);
1686
0
    octet_string.len = len * sizeof(WCHAR);
1687
0
    if (octet_string.len)
1688
0
    {
1689
0
      const BOOL res2 =
1690
0
          WinPrAsn1EncContextualOctetString(enc, cspData_fields[i].tag, &octet_string) > 0;
1691
0
      free(octet_string.data);
1692
0
      if (!res2)
1693
0
        return FALSE;
1694
0
    }
1695
0
  }
1696
1697
  /* End cspData */
1698
0
  if (!WinPrAsn1EncEndContainer(enc))
1699
0
    return FALSE;
1700
1701
  /* userHint [2] OCTET STRING OPTIONAL, */
1702
0
  if (freerdp_settings_get_string(settings, FreeRDP_Username))
1703
0
  {
1704
0
    octet_string.data =
1705
0
        (BYTE*)freerdp_settings_get_string_as_utf16(settings, FreeRDP_Username, &ss);
1706
0
    octet_string.len = ss * sizeof(WCHAR);
1707
0
    res = WinPrAsn1EncContextualOctetString(enc, 2, &octet_string) > 0;
1708
0
    free(octet_string.data);
1709
0
    if (!res)
1710
0
      return FALSE;
1711
0
  }
1712
1713
  /* domainHint [3] OCTET STRING OPTIONAL */
1714
0
  if (freerdp_settings_get_string(settings, FreeRDP_Domain))
1715
0
  {
1716
0
    octet_string.data =
1717
0
        (BYTE*)freerdp_settings_get_string_as_utf16(settings, FreeRDP_Domain, &ss);
1718
0
    octet_string.len = ss * sizeof(WCHAR);
1719
0
    res = WinPrAsn1EncContextualOctetString(enc, 3, &octet_string) > 0;
1720
0
    free(octet_string.data);
1721
0
    if (!res)
1722
0
      return FALSE;
1723
0
  }
1724
1725
  /* End TSSmartCardCreds */
1726
0
  return WinPrAsn1EncEndContainer(enc) != 0;
1727
0
}
1728
1729
static BOOL nla_encode_ts_password_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1730
0
{
1731
0
  WinPrAsn1_OctetString username = WINPR_C_ARRAY_INIT;
1732
0
  WinPrAsn1_OctetString domain = WINPR_C_ARRAY_INIT;
1733
0
  WinPrAsn1_OctetString password = WINPR_C_ARRAY_INIT;
1734
1735
0
  WINPR_ASSERT(nla);
1736
0
  WINPR_ASSERT(enc);
1737
0
  WINPR_ASSERT(nla->rdpcontext);
1738
1739
0
  const rdpSettings* settings = nla->rdpcontext->settings;
1740
0
  WINPR_ASSERT(settings);
1741
1742
  /* TSPasswordCreds */
1743
0
  if (!WinPrAsn1EncSeqContainer(enc))
1744
0
    return FALSE;
1745
1746
0
  if (!settings->DisableCredentialsDelegation && nla->identity)
1747
0
  {
1748
0
    username.len = nla->identity->UserLength * sizeof(WCHAR);
1749
0
    username.data = (BYTE*)nla->identity->User;
1750
1751
0
    domain.len = nla->identity->DomainLength * sizeof(WCHAR);
1752
0
    domain.data = (BYTE*)nla->identity->Domain;
1753
1754
0
    password.len = nla->identity->PasswordLength * sizeof(WCHAR);
1755
0
    password.data = (BYTE*)nla->identity->Password;
1756
0
  }
1757
1758
0
  if (WinPrAsn1EncContextualOctetString(enc, 0, &domain) == 0)
1759
0
    return FALSE;
1760
0
  if (WinPrAsn1EncContextualOctetString(enc, 1, &username) == 0)
1761
0
    return FALSE;
1762
0
  if (WinPrAsn1EncContextualOctetString(enc, 2, &password) == 0)
1763
0
    return FALSE;
1764
1765
  /* End TSPasswordCreds */
1766
0
  return WinPrAsn1EncEndContainer(enc) != 0;
1767
0
}
1768
1769
static BOOL nla_encode_ts_remoteguard_credentials(rdpNla* nla, WinPrAsn1Encoder* enc)
1770
0
{
1771
0
  WINPR_ASSERT(nla);
1772
0
  WINPR_ASSERT(enc);
1773
1774
  /* TSRemoteGuardCreds */
1775
0
  if (!WinPrAsn1EncSeqContainer(enc))
1776
0
    return FALSE;
1777
1778
  /* logonCred [0] TSRemoteGuardPackageCred, */
1779
0
  if (!WinPrAsn1EncContextualSeqContainer(enc, 0))
1780
0
    return FALSE;
1781
1782
0
  if (!nla_write_TSRemoteGuardKerbCred(nla, enc) || !WinPrAsn1EncEndContainer(enc))
1783
0
    return FALSE;
1784
1785
  /* TODO: compute the NTLM supplemental creds */
1786
0
  MSV1_0_REMOTE_SUPPLEMENTAL_CREDENTIAL* ntlm = nullptr;
1787
0
  if (ntlm)
1788
0
  {
1789
    /* supplementalCreds [1] SEQUENCE OF TSRemoteGuardPackageCred OPTIONAL */
1790
0
    if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
1791
0
      return FALSE;
1792
1793
0
    if (!WinPrAsn1EncSeqContainer(enc)) /* start NTLM */
1794
0
      return FALSE;
1795
1796
0
    if (!nla_write_TSRemoteGuardNtlmCred(nla, enc, ntlm))
1797
0
      return FALSE;
1798
1799
0
    if (!WinPrAsn1EncEndContainer(enc)) /* end NTLM */
1800
0
      return FALSE;
1801
1802
0
    if (!WinPrAsn1EncEndContainer(enc)) /* supplementalCreds */
1803
0
      return FALSE;
1804
0
  }
1805
1806
  /* End TSRemoteGuardCreds */
1807
0
  return WinPrAsn1EncEndContainer(enc) != 0;
1808
0
}
1809
1810
/**
1811
 * Encode TSCredentials structure.
1812
 * @param nla A pointer to the NLA to use
1813
 *
1814
 * @return \b TRUE for success, \b FALSE otherwise
1815
 */
1816
1817
static BOOL nla_encode_ts_credentials(rdpNla* nla)
1818
0
{
1819
0
  BOOL ret = FALSE;
1820
0
  WinPrAsn1Encoder* enc = nullptr;
1821
0
  size_t length = 0;
1822
0
  wStream s = WINPR_C_ARRAY_INIT;
1823
0
  TsCredentialsType credType = TSCREDS_INVALID;
1824
1825
0
  WINPR_ASSERT(nla);
1826
0
  WINPR_ASSERT(nla->rdpcontext);
1827
1828
0
  rdpSettings* settings = nla->rdpcontext->settings;
1829
0
  WINPR_ASSERT(settings);
1830
1831
0
  if (settings->RemoteCredentialGuard)
1832
0
    credType = TSCREDS_REMOTEGUARD;
1833
0
  else if (settings->SmartcardLogon)
1834
0
    credType = TSCREDS_SMARTCARD;
1835
0
  else
1836
0
    credType = TSCREDS_USER_PASSWD;
1837
1838
0
  enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
1839
0
  if (!enc)
1840
0
    return FALSE;
1841
1842
  /* TSCredentials */
1843
0
  if (!WinPrAsn1EncSeqContainer(enc))
1844
0
    goto out;
1845
1846
  /* credType [0] INTEGER */
1847
0
  if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)credType))
1848
0
    goto out;
1849
1850
  /* credentials [1] OCTET STRING */
1851
0
  if (!WinPrAsn1EncContextualOctetStringContainer(enc, 1))
1852
0
    goto out;
1853
1854
0
  switch (credType)
1855
0
  {
1856
0
    case TSCREDS_SMARTCARD:
1857
0
      if (!nla_encode_ts_smartcard_credentials(nla, enc))
1858
0
        goto out;
1859
0
      break;
1860
1861
0
    case TSCREDS_USER_PASSWD:
1862
0
      if (!nla_encode_ts_password_credentials(nla, enc))
1863
0
        goto out;
1864
0
      break;
1865
1866
0
    case TSCREDS_REMOTEGUARD:
1867
0
      if (!nla_encode_ts_remoteguard_credentials(nla, enc))
1868
0
        goto out;
1869
0
      break;
1870
0
    default:
1871
0
      goto out;
1872
0
  }
1873
1874
  /* End credentials | End TSCredentials */
1875
0
  if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
1876
0
    goto out;
1877
1878
0
  if (!WinPrAsn1EncStreamSize(enc, &length))
1879
0
    goto out;
1880
1881
0
  if (!nla_sec_buffer_alloc(&nla->tsCredentials, length))
1882
0
  {
1883
0
    WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
1884
0
    goto out;
1885
0
  }
1886
1887
0
  Stream_StaticInit(&s, (BYTE*)nla->tsCredentials.pvBuffer, length);
1888
1889
0
  ret = WinPrAsn1EncToStream(enc, &s);
1890
1891
0
out:
1892
0
  WinPrAsn1Encoder_Free(&enc);
1893
0
  return ret;
1894
0
}
1895
1896
static BOOL nla_encrypt_ts_credentials(rdpNla* nla)
1897
0
{
1898
0
  WINPR_ASSERT(nla);
1899
1900
0
  if (!nla_encode_ts_credentials(nla))
1901
0
    return FALSE;
1902
1903
0
  sspi_SecBufferFree(&nla->authInfo);
1904
0
  return (credssp_auth_encrypt(nla->auth, &nla->tsCredentials, &nla->authInfo, nullptr,
1905
0
                               nla->sendSeqNum++));
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 = nullptr;
1973
0
  size_t length = 0;
1974
0
  WinPrAsn1Encoder* enc = nullptr;
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(nullptr, 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
15.4k
{
2068
15.4k
  WinPrAsn1Decoder dec = WinPrAsn1Decoder_init();
2069
15.4k
  WinPrAsn1Decoder dec2 = WinPrAsn1Decoder_init();
2070
15.4k
  BOOL error = FALSE;
2071
15.4k
  WinPrAsn1_tagId tag = WINPR_C_ARRAY_INIT;
2072
15.4k
  WinPrAsn1_INTEGER val = WINPR_C_ARRAY_INIT;
2073
15.4k
  UINT32 version = 0;
2074
2075
15.4k
  WINPR_ASSERT(nla);
2076
15.4k
  WINPR_ASSERT(s);
2077
2078
15.4k
  WinPrAsn1Decoder_Init(&dec, WINPR_ASN1_DER, s);
2079
2080
15.4k
  WLog_DBG(TAG, "<<----- receiving...");
2081
2082
  /* TSRequest */
2083
15.4k
  const size_t offset = WinPrAsn1DecReadSequence(&dec, &dec2);
2084
15.4k
  if (offset == 0)
2085
14.9k
    return -1;
2086
477
  dec = dec2;
2087
2088
  /* version [0] INTEGER */
2089
477
  if (WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val) == 0)
2090
162
    return -1;
2091
2092
315
  if (!Stream_SafeSeek(s, offset))
2093
0
    return -1;
2094
2095
315
  version = (UINT)val;
2096
315
  WLog_DBG(TAG, "   <<----- protocol version %" PRIu32, version);
2097
2098
315
  if (nla->peerVersion == 0)
2099
315
    nla->peerVersion = version;
2100
2101
  /* if the peer suddenly changed its version - kick it */
2102
315
  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
509
  while (WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2) != 0)
2110
334
  {
2111
334
    WinPrAsn1Decoder dec3 = WinPrAsn1Decoder_init();
2112
334
    WinPrAsn1_OctetString octet_string = WINPR_C_ARRAY_INIT;
2113
2114
334
    switch (tag)
2115
334
    {
2116
6
      case 1:
2117
6
        WLog_DBG(TAG, "   <<----- nego token");
2118
        /* negoTokens [1] SEQUENCE OF SEQUENCE */
2119
6
        if ((WinPrAsn1DecReadSequence(&dec2, &dec3) == 0) ||
2120
3
            (WinPrAsn1DecReadSequence(&dec3, &dec2) == 0))
2121
5
          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
4
          return -1;
2136
5
        if (!nla_sec_buffer_alloc_from_data(&nla->authInfo, octet_string.data, 0,
2137
5
                                            octet_string.len))
2138
0
          return -1;
2139
5
        break;
2140
9
      case 3:
2141
9
        WLog_DBG(TAG, "   <<----- public key auth");
2142
        /* pubKeyAuth [3] OCTET STRING */
2143
9
        if (WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE) == 0)
2144
7
          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
294
      case 4:
2150
        /* errorCode [4] INTEGER */
2151
294
        if (WinPrAsn1DecReadInteger(&dec2, &val) == 0)
2152
110
          return -1;
2153
184
        nla->errorCode = val;
2154
184
        WLog_DBG(TAG, "   <<----- error code %s 0x%08" PRIx32, NtStatus2Tag(nla->errorCode),
2155
184
                 WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2156
184
        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
8
          return -1;
2162
3
        if (!nla_sec_buffer_alloc_from_data(&nla->ClientNonce, octet_string.data, 0,
2163
3
                                            octet_string.len))
2164
0
          return -1;
2165
3
        break;
2166
5
      default:
2167
5
        return -1;
2168
334
    }
2169
334
  }
2170
2171
175
  return 1;
2172
315
}
2173
2174
int nla_recv_pdu(rdpNla* nla, wStream* s)
2175
15.4k
{
2176
15.4k
  WINPR_ASSERT(nla);
2177
15.4k
  WINPR_ASSERT(s);
2178
2179
15.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
15.4k
  else
2194
15.4k
  {
2195
15.4k
    if (nla_decode_ts_request(nla, s) < 1)
2196
15.2k
      return -1;
2197
2198
175
    if (nla->errorCode)
2199
157
    {
2200
157
      UINT32 code = 0;
2201
2202
157
      switch (nla->errorCode)
2203
157
      {
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
1
        case STATUS_ACCOUNT_DISABLED:
2213
1
          code = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
2214
1
          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
2
        case STATUS_ACCOUNT_RESTRICTION:
2229
2
          code = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
2230
2
          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
143
        default:
2245
143
          WLog_ERR(TAG, "SPNEGO failed with NTSTATUS: %s [0x%08" PRIx32 "]",
2246
143
                   NtStatus2Tag(nla->errorCode),
2247
143
                   WINPR_CXX_COMPAT_CAST(uint32_t, nla->errorCode));
2248
143
          code = FREERDP_ERROR_AUTHENTICATION_FAILED;
2249
143
          break;
2250
157
      }
2251
2252
157
      freerdp_set_last_error_log(nla->rdpcontext, code);
2253
157
      return -1;
2254
157
    }
2255
175
  }
2256
2257
18
  return nla_client_recv(nla);
2258
15.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
15.4k
{
2287
15.4k
  WINPR_ASSERT(transport);
2288
15.4k
  WINPR_ASSERT(context);
2289
2290
15.4k
  rdpSettings* settings = context->settings;
2291
15.4k
  WINPR_ASSERT(settings);
2292
2293
15.4k
  rdpNla* nla = (rdpNla*)calloc(1, sizeof(rdpNla));
2294
2295
15.4k
  if (!nla)
2296
0
    return nullptr;
2297
2298
15.4k
  nla->rdpcontext = context;
2299
15.4k
  nla->server = settings->ServerMode;
2300
15.4k
  nla->transport = transport;
2301
15.4k
  nla->sendSeqNum = 0;
2302
15.4k
  nla->recvSeqNum = 0;
2303
15.4k
  nla->version = 6;
2304
15.4k
  nla->earlyUserAuth = FALSE;
2305
2306
15.4k
  nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
2307
15.4k
  if (!nla->identity)
2308
0
    goto cleanup;
2309
2310
15.4k
  nla->auth = credssp_auth_new(context);
2311
15.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
15.4k
  if (!nla_sec_buffer_alloc(&nla->ClientNonce, NonceLength))
2316
0
    goto cleanup;
2317
2318
  /* generate random 32-byte nonce */
2319
15.4k
  if (winpr_RAND(nla->ClientNonce.pvBuffer, NonceLength) < 0)
2320
0
    goto cleanup;
2321
2322
15.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 nullptr;
2329
15.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
46.2k
{
2338
46.2k
  if (!nla)
2339
30.8k
    return;
2340
2341
15.4k
  smartcardCertInfo_Free(nla->smartcardCert);
2342
15.4k
  nla_buffer_free(nla);
2343
15.4k
  sspi_SecBufferFree(&nla->tsCredentials);
2344
15.4k
  credssp_auth_free(nla->auth);
2345
2346
15.4k
  sspi_FreeAuthIdentity(nla->identity);
2347
15.4k
  free(nla->pkinitArgs);
2348
15.4k
  free(nla->identity);
2349
15.4k
  free(nla);
2350
15.4k
}
2351
2352
SEC_WINNT_AUTH_IDENTITY* nla_get_identity(rdpNla* nla)
2353
0
{
2354
0
  if (!nla)
2355
0
    return nullptr;
2356
2357
0
  return nla->identity;
2358
0
}
2359
2360
NLA_STATE nla_get_state(const rdpNla* nla)
2361
15.4k
{
2362
15.4k
  if (!nla)
2363
0
    return NLA_STATE_FINAL;
2364
2365
15.4k
  return nla->state;
2366
15.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
  return (credssp_auth_set_spn(nla->auth, service, hostname));
2381
0
}
2382
2383
BOOL nla_impersonate(rdpNla* nla)
2384
0
{
2385
0
  return credssp_auth_impersonate(nla->auth);
2386
0
}
2387
2388
BOOL nla_revert_to_self(rdpNla* nla)
2389
0
{
2390
0
  return credssp_auth_revert_to_self(nla->auth);
2391
0
}
2392
2393
const char* nla_get_state_str(NLA_STATE state)
2394
18
{
2395
18
  switch (state)
2396
18
  {
2397
18
    case NLA_STATE_INITIAL:
2398
18
      return "NLA_STATE_INITIAL";
2399
0
    case NLA_STATE_NEGO_TOKEN:
2400
0
      return "NLA_STATE_NEGO_TOKEN";
2401
0
    case NLA_STATE_PUB_KEY_AUTH:
2402
0
      return "NLA_STATE_PUB_KEY_AUTH";
2403
0
    case NLA_STATE_AUTH_INFO:
2404
0
      return "NLA_STATE_AUTH_INFO";
2405
0
    case NLA_STATE_POST_NEGO:
2406
0
      return "NLA_STATE_POST_NEGO";
2407
0
    case NLA_STATE_EARLY_USER_AUTH:
2408
0
      return "NLA_STATE_EARLY_USER_AUTH";
2409
0
    case NLA_STATE_FINAL:
2410
0
      return "NLA_STATE_FINAL";
2411
0
    default:
2412
0
      return "UNKNOWN";
2413
18
  }
2414
18
}
2415
2416
DWORD nla_get_error(const rdpNla* nla)
2417
0
{
2418
0
  if (!nla)
2419
0
    return ERROR_INTERNAL_ERROR;
2420
0
  return (UINT32)nla->errorCode;
2421
0
}
2422
2423
INT32 nla_get_sspi_error(const rdpNla* nla)
2424
0
{
2425
0
  WINPR_ASSERT(nla);
2426
0
  return credssp_auth_sspi_error(nla->auth);
2427
0
}
2428
2429
BOOL nla_encrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer)
2430
0
{
2431
0
  WINPR_ASSERT(nla);
2432
0
  WINPR_ASSERT(inBuffer);
2433
0
  WINPR_ASSERT(outBuffer);
2434
0
  return credssp_auth_encrypt(nla->auth, inBuffer, outBuffer, nullptr, nla->sendSeqNum++);
2435
0
}
2436
2437
BOOL nla_decrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer)
2438
0
{
2439
0
  WINPR_ASSERT(nla);
2440
0
  WINPR_ASSERT(inBuffer);
2441
0
  WINPR_ASSERT(outBuffer);
2442
0
  return credssp_auth_decrypt(nla->auth, inBuffer, outBuffer, nla->recvSeqNum++);
2443
0
}
2444
2445
SECURITY_STATUS nla_QueryContextAttributes(rdpNla* nla, DWORD ulAttr, PVOID pBuffer)
2446
0
{
2447
0
  WINPR_ASSERT(nla);
2448
2449
0
  SecurityFunctionTable* table = nullptr;
2450
0
  CtxtHandle context = WINPR_C_ARRAY_INIT;
2451
0
  credssp_auth_tableAndContext(nla->auth, &table, &context);
2452
2453
0
  return table->QueryContextAttributes(&context, ulAttr, pBuffer);
2454
0
}
2455
2456
SECURITY_STATUS nla_FreeContextBuffer(rdpNla* nla, PVOID pBuffer)
2457
0
{
2458
0
  WINPR_ASSERT(nla);
2459
2460
0
  SecurityFunctionTable* table = nullptr;
2461
0
  CtxtHandle context = WINPR_C_ARRAY_INIT;
2462
0
  credssp_auth_tableAndContext(nla->auth, &table, &context);
2463
2464
0
  return table->FreeContextBuffer(pBuffer);
2465
0
}