1 /**
2 * WinPR: Windows Portable Runtime
3 * NTLM Security Package
4 *
5 * Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <winpr/crt.h>
25 #include <winpr/sspi.h>
26 #include <winpr/print.h>
27 #include <winpr/tchar.h>
28 #include <winpr/sysinfo.h>
29 #include <winpr/registry.h>
30 #include <winpr/endian.h>
31 #include <freerdp/build-config.h>
32
33 #include "ntlm.h"
34 #include "../sspi.h"
35
36 #include "ntlm_message.h"
37
38 #include "../../log.h"
39 #define TAG WINPR_TAG("sspi.NTLM")
40
41 #define WINPR_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\WinPR\\NTLM"
42
43 static const char* NTLM_PACKAGE_NAME = "NTLM";
44
ntlm_SetContextWorkstation(NTLM_CONTEXT * context,char * Workstation)45 static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
46 {
47 int status;
48 char* ws = Workstation;
49 DWORD nSize = 0;
50 CHAR* computerName;
51
52 if (!Workstation)
53 {
54 if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
55 GetLastError() != ERROR_MORE_DATA)
56 return -1;
57
58 computerName = calloc(nSize, sizeof(CHAR));
59
60 if (!computerName)
61 return -1;
62
63 if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
64 {
65 free(computerName);
66 return -1;
67 }
68
69 if (nSize > MAX_COMPUTERNAME_LENGTH)
70 computerName[MAX_COMPUTERNAME_LENGTH] = '\0';
71
72 ws = computerName;
73
74 if (!ws)
75 return -1;
76 }
77
78 context->Workstation.Buffer = NULL;
79 status = ConvertToUnicode(CP_UTF8, 0, ws, -1, &context->Workstation.Buffer, 0);
80
81 if (!Workstation)
82 free(ws);
83
84 if (status <= 0)
85 return -1;
86
87 context->Workstation.Length = (USHORT)(status - 1);
88 context->Workstation.Length *= 2;
89 return 1;
90 }
91
ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT * context,LPWSTR ServicePrincipalName)92 static int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
93 {
94 if (!ServicePrincipalName)
95 {
96 context->ServicePrincipalName.Buffer = NULL;
97 context->ServicePrincipalName.Length = 0;
98 return 1;
99 }
100
101 context->ServicePrincipalName.Length = (USHORT)(_wcslen(ServicePrincipalName) * 2);
102 context->ServicePrincipalName.Buffer = (PWSTR)malloc(context->ServicePrincipalName.Length + 2);
103
104 if (!context->ServicePrincipalName.Buffer)
105 return -1;
106
107 CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName,
108 context->ServicePrincipalName.Length + 2);
109 return 1;
110 }
111
ntlm_SetContextTargetName(NTLM_CONTEXT * context,char * TargetName)112 static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
113 {
114 int status;
115 char* name = TargetName;
116 DWORD nSize = 0;
117 CHAR* computerName = NULL;
118
119 if (!name)
120 {
121 if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
122 GetLastError() != ERROR_MORE_DATA)
123 return -1;
124
125 computerName = calloc(nSize, sizeof(CHAR));
126
127 if (!computerName)
128 return -1;
129
130 if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
131 {
132 free(computerName);
133 return -1;
134 }
135
136 if (nSize > MAX_COMPUTERNAME_LENGTH)
137 computerName[MAX_COMPUTERNAME_LENGTH] = '\0';
138
139 name = computerName;
140
141 if (!name)
142 return -1;
143
144 CharUpperA(name);
145 }
146
147 context->TargetName.pvBuffer = NULL;
148 status = ConvertToUnicode(CP_UTF8, 0, name, -1, (LPWSTR*)&context->TargetName.pvBuffer, 0);
149
150 if (status <= 0)
151 {
152 if (!TargetName)
153 free(name);
154
155 return -1;
156 }
157
158 context->TargetName.cbBuffer = (USHORT)((status - 1) * 2);
159
160 if (!TargetName)
161 free(name);
162
163 return 1;
164 }
165
ntlm_ContextNew(void)166 static NTLM_CONTEXT* ntlm_ContextNew(void)
167 {
168 HKEY hKey;
169 LONG status;
170 DWORD dwType;
171 DWORD dwSize;
172 DWORD dwValue;
173 NTLM_CONTEXT* context;
174 context = (NTLM_CONTEXT*)calloc(1, sizeof(NTLM_CONTEXT));
175
176 if (!context)
177 return NULL;
178
179 context->NTLMv2 = TRUE;
180 context->UseMIC = FALSE;
181 context->SendVersionInfo = TRUE;
182 context->SendSingleHostData = FALSE;
183 context->SendWorkstationName = TRUE;
184 context->NegotiateKeyExchange = TRUE;
185 context->UseSamFileDatabase = TRUE;
186 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WINPR_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
187
188 if (status == ERROR_SUCCESS)
189 {
190 if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
191 ERROR_SUCCESS)
192 context->NTLMv2 = dwValue ? 1 : 0;
193
194 if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
195 ERROR_SUCCESS)
196 context->UseMIC = dwValue ? 1 : 0;
197
198 if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
199 ERROR_SUCCESS)
200 context->SendVersionInfo = dwValue ? 1 : 0;
201
202 if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*)&dwValue,
203 &dwSize) == ERROR_SUCCESS)
204 context->SendSingleHostData = dwValue ? 1 : 0;
205
206 if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*)&dwValue,
207 &dwSize) == ERROR_SUCCESS)
208 context->SendWorkstationName = dwValue ? 1 : 0;
209
210 if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) ==
211 ERROR_SUCCESS)
212 {
213 char* workstation = (char*)malloc(dwSize + 1);
214
215 if (!workstation)
216 {
217 free(context);
218 return NULL;
219 }
220
221 status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*)workstation,
222 &dwSize);
223 workstation[dwSize] = '\0';
224
225 if (ntlm_SetContextWorkstation(context, workstation) < 0)
226 {
227 free(workstation);
228 free(context);
229 return NULL;
230 }
231
232 free(workstation);
233 }
234
235 RegCloseKey(hKey);
236 }
237
238 /*
239 * Extended Protection is enabled by default in Windows 7,
240 * but enabling it in WinPR breaks TS Gateway at this point
241 */
242 context->SuppressExtendedProtection = FALSE;
243 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0,
244 KEY_READ | KEY_WOW64_64KEY, &hKey);
245
246 if (status == ERROR_SUCCESS)
247 {
248 if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*)&dwValue,
249 &dwSize) == ERROR_SUCCESS)
250 context->SuppressExtendedProtection = dwValue ? 1 : 0;
251
252 RegCloseKey(hKey);
253 }
254
255 context->NegotiateFlags = 0;
256 context->LmCompatibilityLevel = 3;
257 context->state = NTLM_STATE_INITIAL;
258 FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA);
259
260 if (context->NTLMv2)
261 context->UseMIC = TRUE;
262
263 return context;
264 }
265
ntlm_ContextFree(NTLM_CONTEXT * context)266 static void ntlm_ContextFree(NTLM_CONTEXT* context)
267 {
268 if (!context)
269 return;
270
271 winpr_RC4_Free(context->SendRc4Seal);
272 winpr_RC4_Free(context->RecvRc4Seal);
273 sspi_SecBufferFree(&context->NegotiateMessage);
274 sspi_SecBufferFree(&context->ChallengeMessage);
275 sspi_SecBufferFree(&context->AuthenticateMessage);
276 sspi_SecBufferFree(&context->ChallengeTargetInfo);
277 sspi_SecBufferFree(&context->TargetName);
278 sspi_SecBufferFree(&context->NtChallengeResponse);
279 sspi_SecBufferFree(&context->LmChallengeResponse);
280 free(context->ServicePrincipalName.Buffer);
281 free(context->Workstation.Buffer);
282 free(context);
283 }
284
ntlm_AcquireCredentialsHandleW(SEC_WCHAR * pszPrincipal,SEC_WCHAR * pszPackage,ULONG fCredentialUse,void * pvLogonID,void * pAuthData,SEC_GET_KEY_FN pGetKeyFn,void * pvGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)285 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
286 SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
287 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
288 PTimeStamp ptsExpiry)
289 {
290 SSPI_CREDENTIALS* credentials;
291 SEC_WINNT_AUTH_IDENTITY* identity;
292
293 if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
294 (fCredentialUse != SECPKG_CRED_BOTH))
295 {
296 return SEC_E_INVALID_PARAMETER;
297 }
298
299 credentials = sspi_CredentialsNew();
300
301 if (!credentials)
302 return SEC_E_INTERNAL_ERROR;
303
304 credentials->fCredentialUse = fCredentialUse;
305 credentials->pGetKeyFn = pGetKeyFn;
306 credentials->pvGetKeyArgument = pvGetKeyArgument;
307 identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
308
309 if (identity)
310 sspi_CopyAuthIdentity(&(credentials->identity), identity);
311
312 sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
313 sspi_SecureHandleSetUpperPointer(phCredential, (void*)NTLM_PACKAGE_NAME);
314 return SEC_E_OK;
315 }
316
ntlm_AcquireCredentialsHandleA(SEC_CHAR * pszPrincipal,SEC_CHAR * pszPackage,ULONG fCredentialUse,void * pvLogonID,void * pAuthData,SEC_GET_KEY_FN pGetKeyFn,void * pvGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)317 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
318 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
319 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
320 PTimeStamp ptsExpiry)
321 {
322 SSPI_CREDENTIALS* credentials;
323 SEC_WINNT_AUTH_IDENTITY* identity;
324
325 if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
326 (fCredentialUse != SECPKG_CRED_BOTH))
327 {
328 return SEC_E_INVALID_PARAMETER;
329 }
330
331 credentials = sspi_CredentialsNew();
332
333 if (!credentials)
334 return SEC_E_INTERNAL_ERROR;
335
336 credentials->fCredentialUse = fCredentialUse;
337 credentials->pGetKeyFn = pGetKeyFn;
338 credentials->pvGetKeyArgument = pvGetKeyArgument;
339 identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
340
341 if (identity)
342 sspi_CopyAuthIdentity(&(credentials->identity), identity);
343
344 sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
345 sspi_SecureHandleSetUpperPointer(phCredential, (void*)NTLM_PACKAGE_NAME);
346 return SEC_E_OK;
347 }
348
ntlm_FreeCredentialsHandle(PCredHandle phCredential)349 static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
350 {
351 SSPI_CREDENTIALS* credentials;
352
353 if (!phCredential)
354 return SEC_E_INVALID_HANDLE;
355
356 credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
357
358 if (!credentials)
359 return SEC_E_INVALID_HANDLE;
360
361 sspi_CredentialsFree(credentials);
362 return SEC_E_OK;
363 }
364
ntlm_QueryCredentialsAttributesW(PCredHandle phCredential,ULONG ulAttribute,void * pBuffer)365 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(PCredHandle phCredential,
366 ULONG ulAttribute, void* pBuffer)
367 {
368 if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
369 {
370 return SEC_E_OK;
371 }
372
373 WLog_ERR(TAG, "[%s]: TODO: Implement", __FUNCTION__);
374 return SEC_E_UNSUPPORTED_FUNCTION;
375 }
376
ntlm_QueryCredentialsAttributesA(PCredHandle phCredential,ULONG ulAttribute,void * pBuffer)377 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(PCredHandle phCredential,
378 ULONG ulAttribute, void* pBuffer)
379 {
380 return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
381 }
382
383 /**
384 * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374707
385 */
386 static SECURITY_STATUS SEC_ENTRY
ntlm_AcceptSecurityContext(PCredHandle phCredential,PCtxtHandle phContext,PSecBufferDesc pInput,ULONG fContextReq,ULONG TargetDataRep,PCtxtHandle phNewContext,PSecBufferDesc pOutput,PULONG pfContextAttr,PTimeStamp ptsTimeStamp)387 ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
388 ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
389 PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
390 {
391 NTLM_CONTEXT* context;
392 SECURITY_STATUS status;
393 SSPI_CREDENTIALS* credentials;
394 PSecBuffer input_buffer;
395 PSecBuffer output_buffer;
396 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
397
398 if (!context)
399 {
400 context = ntlm_ContextNew();
401
402 if (!context)
403 return SEC_E_INSUFFICIENT_MEMORY;
404
405 context->server = TRUE;
406
407 if (fContextReq & ASC_REQ_CONFIDENTIALITY)
408 context->confidentiality = TRUE;
409
410 credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
411 context->credentials = credentials;
412 ntlm_SetContextTargetName(context, NULL);
413 sspi_SecureHandleSetLowerPointer(phNewContext, context);
414 sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
415 }
416
417 if (context->state == NTLM_STATE_INITIAL)
418 {
419 context->state = NTLM_STATE_NEGOTIATE;
420
421 if (!pInput)
422 return SEC_E_INVALID_TOKEN;
423
424 if (pInput->cBuffers < 1)
425 return SEC_E_INVALID_TOKEN;
426
427 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
428
429 if (!input_buffer)
430 return SEC_E_INVALID_TOKEN;
431
432 if (input_buffer->cbBuffer < 1)
433 return SEC_E_INVALID_TOKEN;
434
435 status = ntlm_read_NegotiateMessage(context, input_buffer);
436
437 if (context->state == NTLM_STATE_CHALLENGE)
438 {
439 if (!pOutput)
440 return SEC_E_INVALID_TOKEN;
441
442 if (pOutput->cBuffers < 1)
443 return SEC_E_INVALID_TOKEN;
444
445 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
446
447 if (!output_buffer->BufferType)
448 return SEC_E_INVALID_TOKEN;
449
450 if (output_buffer->cbBuffer < 1)
451 return SEC_E_INSUFFICIENT_MEMORY;
452
453 return ntlm_write_ChallengeMessage(context, output_buffer);
454 }
455
456 return SEC_E_OUT_OF_SEQUENCE;
457 }
458 else if (context->state == NTLM_STATE_AUTHENTICATE)
459 {
460 if (!pInput)
461 return SEC_E_INVALID_TOKEN;
462
463 if (pInput->cBuffers < 1)
464 return SEC_E_INVALID_TOKEN;
465
466 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
467
468 if (!input_buffer)
469 return SEC_E_INVALID_TOKEN;
470
471 if (input_buffer->cbBuffer < 1)
472 return SEC_E_INVALID_TOKEN;
473
474 status = ntlm_read_AuthenticateMessage(context, input_buffer);
475
476 if (pOutput)
477 {
478 ULONG i;
479
480 for (i = 0; i < pOutput->cBuffers; i++)
481 {
482 pOutput->pBuffers[i].cbBuffer = 0;
483 pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
484 }
485 }
486
487 return status;
488 }
489
490 return SEC_E_OUT_OF_SEQUENCE;
491 }
492
ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)493 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
494 {
495 return SEC_E_OK;
496 }
497
ntlm_InitializeSecurityContextW(PCredHandle phCredential,PCtxtHandle phContext,SEC_WCHAR * pszTargetName,ULONG fContextReq,ULONG Reserved1,ULONG TargetDataRep,PSecBufferDesc pInput,ULONG Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,PULONG pfContextAttr,PTimeStamp ptsExpiry)498 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
499 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq,
500 ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
501 PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
502 {
503 NTLM_CONTEXT* context;
504 SECURITY_STATUS status;
505 SSPI_CREDENTIALS* credentials;
506 PSecBuffer input_buffer = NULL;
507 PSecBuffer output_buffer = NULL;
508 PSecBuffer channel_bindings = NULL;
509 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
510
511 if (!context)
512 {
513 context = ntlm_ContextNew();
514
515 if (!context)
516 return SEC_E_INSUFFICIENT_MEMORY;
517
518 if (fContextReq & ISC_REQ_CONFIDENTIALITY)
519 context->confidentiality = TRUE;
520
521 credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
522 context->credentials = credentials;
523
524 if (context->Workstation.Length < 1)
525 {
526 if (ntlm_SetContextWorkstation(context, NULL) < 0)
527 {
528 ntlm_ContextFree(context);
529 return SEC_E_INTERNAL_ERROR;
530 }
531 }
532
533 if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
534 {
535 ntlm_ContextFree(context);
536 return SEC_E_INTERNAL_ERROR;
537 }
538
539 sspi_SecureHandleSetLowerPointer(phNewContext, context);
540 sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
541 }
542
543 if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE))
544 {
545 if (!pOutput)
546 return SEC_E_INVALID_TOKEN;
547
548 if (pOutput->cBuffers < 1)
549 return SEC_E_INVALID_TOKEN;
550
551 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
552
553 if (!output_buffer)
554 return SEC_E_INVALID_TOKEN;
555
556 if (output_buffer->cbBuffer < 1)
557 return SEC_E_INVALID_TOKEN;
558
559 if (context->state == NTLM_STATE_INITIAL)
560 context->state = NTLM_STATE_NEGOTIATE;
561
562 if (context->state == NTLM_STATE_NEGOTIATE)
563 return ntlm_write_NegotiateMessage(context, output_buffer);
564
565 return SEC_E_OUT_OF_SEQUENCE;
566 }
567 else
568 {
569 if (pInput->cBuffers < 1)
570 return SEC_E_INVALID_TOKEN;
571
572 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
573
574 if (!input_buffer)
575 return SEC_E_INVALID_TOKEN;
576
577 if (input_buffer->cbBuffer < 1)
578 return SEC_E_INVALID_TOKEN;
579
580 channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
581
582 if (channel_bindings)
583 {
584 context->Bindings.BindingsLength = channel_bindings->cbBuffer;
585 context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*)channel_bindings->pvBuffer;
586 }
587
588 if (context->state == NTLM_STATE_CHALLENGE)
589 {
590 status = ntlm_read_ChallengeMessage(context, input_buffer);
591
592 if (!pOutput)
593 return SEC_E_INVALID_TOKEN;
594
595 if (pOutput->cBuffers < 1)
596 return SEC_E_INVALID_TOKEN;
597
598 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
599
600 if (!output_buffer)
601 return SEC_E_INVALID_TOKEN;
602
603 if (output_buffer->cbBuffer < 1)
604 return SEC_E_INSUFFICIENT_MEMORY;
605
606 if (context->state == NTLM_STATE_AUTHENTICATE)
607 return ntlm_write_AuthenticateMessage(context, output_buffer);
608 }
609
610 return SEC_E_OUT_OF_SEQUENCE;
611 }
612
613 return SEC_E_OUT_OF_SEQUENCE;
614 }
615
616 /**
617 * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375512%28v=vs.85%29.aspx
618 */
ntlm_InitializeSecurityContextA(PCredHandle phCredential,PCtxtHandle phContext,SEC_CHAR * pszTargetName,ULONG fContextReq,ULONG Reserved1,ULONG TargetDataRep,PSecBufferDesc pInput,ULONG Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,PULONG pfContextAttr,PTimeStamp ptsExpiry)619 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
620 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
621 ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
622 PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
623 {
624 SECURITY_STATUS status;
625 SEC_WCHAR* pszTargetNameW = NULL;
626
627 if (pszTargetName)
628 {
629 if (ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0) <= 0)
630 return SEC_E_INTERNAL_ERROR;
631 }
632
633 status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
634 Reserved1, TargetDataRep, pInput, Reserved2,
635 phNewContext, pOutput, pfContextAttr, ptsExpiry);
636 free(pszTargetNameW);
637 return status;
638 }
639
ntlm_CompleteAuthToken(PCtxtHandle phContext,PSecBufferDesc pToken)640 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext,
641 PSecBufferDesc pToken)
642 {
643 NTLM_CONTEXT* context;
644 SECURITY_STATUS status = SEC_E_OK;
645 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
646
647 if (!context)
648 return SEC_E_INVALID_HANDLE;
649
650 if (context->server)
651 {
652 status = ntlm_server_AuthenticateComplete(context);
653 }
654
655 return status;
656 }
657
658 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375354 */
659
ntlm_DeleteSecurityContext(PCtxtHandle phContext)660 static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
661 {
662 NTLM_CONTEXT* context;
663 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
664
665 if (!context)
666 return SEC_E_INVALID_HANDLE;
667
668 ntlm_ContextFree(context);
669 return SEC_E_OK;
670 }
671
ntlm_computeProofValue(NTLM_CONTEXT * ntlm,SecBuffer * ntproof)672 SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof)
673 {
674 BYTE* blob;
675 SecBuffer* target = &ntlm->ChallengeTargetInfo;
676
677 if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
678 return SEC_E_INSUFFICIENT_MEMORY;
679
680 blob = (BYTE*)ntproof->pvBuffer;
681 CopyMemory(blob, ntlm->ServerChallenge, 8); /* Server challenge. */
682 blob[8] = 1; /* Response version. */
683 blob[9] = 1; /* Highest response version understood by the client. */
684 /* Reserved 6B. */
685 CopyMemory(&blob[16], ntlm->Timestamp, 8); /* Time. */
686 CopyMemory(&blob[24], ntlm->ClientChallenge, 8); /* Client challenge. */
687 /* Reserved 4B. */
688 /* Server name. */
689 CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
690 return SEC_E_OK;
691 }
692
ntlm_computeMicValue(NTLM_CONTEXT * ntlm,SecBuffer * micvalue)693 SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue)
694 {
695 BYTE* blob;
696 ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
697 ntlm->AuthenticateMessage.cbBuffer;
698
699 if (!sspi_SecBufferAlloc(micvalue, msgSize))
700 return SEC_E_INSUFFICIENT_MEMORY;
701
702 blob = (BYTE*)micvalue->pvBuffer;
703 CopyMemory(blob, ntlm->NegotiateMessage.pvBuffer, ntlm->NegotiateMessage.cbBuffer);
704 blob += ntlm->NegotiateMessage.cbBuffer;
705 CopyMemory(blob, ntlm->ChallengeMessage.pvBuffer, ntlm->ChallengeMessage.cbBuffer);
706 blob += ntlm->ChallengeMessage.cbBuffer;
707 CopyMemory(blob, ntlm->AuthenticateMessage.pvBuffer, ntlm->AuthenticateMessage.cbBuffer);
708 blob += ntlm->MessageIntegrityCheckOffset;
709 ZeroMemory(blob, 16);
710 return SEC_E_OK;
711 }
712
713 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379337/ */
714
ntlm_QueryContextAttributesW(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer)715 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext,
716 ULONG ulAttribute, void* pBuffer)
717 {
718 NTLM_CONTEXT* context;
719
720 if (!phContext)
721 return SEC_E_INVALID_HANDLE;
722
723 if (!pBuffer)
724 return SEC_E_INSUFFICIENT_MEMORY;
725
726 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
727
728 if (ulAttribute == SECPKG_ATTR_SIZES)
729 {
730 SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*)pBuffer;
731 ContextSizes->cbMaxToken = 2010;
732 ContextSizes->cbMaxSignature = 16; /* the size of expected signature is 16 bytes */
733 ContextSizes->cbBlockSize = 0; /* no padding */
734 ContextSizes->cbSecurityTrailer = 16; /* no security trailer appended in NTLM
735 contrary to Kerberos */
736 return SEC_E_OK;
737 }
738 else if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY)
739 {
740 int status;
741 char* UserA = NULL;
742 char* DomainA = NULL;
743 SSPI_CREDENTIALS* credentials;
744 SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*)pBuffer;
745 context->UseSamFileDatabase = FALSE;
746 credentials = context->credentials;
747 ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
748 UserA = AuthIdentity->User;
749
750 if (credentials->identity.UserLength > 0)
751 {
752 status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)credentials->identity.User,
753 credentials->identity.UserLength, &UserA, 256, NULL, NULL);
754
755 if (status <= 0)
756 return SEC_E_INTERNAL_ERROR;
757 }
758
759 DomainA = AuthIdentity->Domain;
760
761 if (credentials->identity.DomainLength > 0)
762 {
763 status =
764 ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)credentials->identity.Domain,
765 credentials->identity.DomainLength, &DomainA, 256, NULL, NULL);
766
767 if (status <= 0)
768 return SEC_E_INTERNAL_ERROR;
769 }
770
771 return SEC_E_OK;
772 }
773 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE)
774 {
775 return ntlm_computeProofValue(context, (SecBuffer*)pBuffer);
776 }
777 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_RANDKEY)
778 {
779 SecBuffer* randkey;
780 randkey = (SecBuffer*)pBuffer;
781
782 if (!sspi_SecBufferAlloc(randkey, 16))
783 return (SEC_E_INSUFFICIENT_MEMORY);
784
785 CopyMemory(randkey->pvBuffer, context->EncryptedRandomSessionKey, 16);
786 return (SEC_E_OK);
787 }
788 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC)
789 {
790 SecBuffer* mic;
791 NTLM_AUTHENTICATE_MESSAGE* message;
792 mic = (SecBuffer*)pBuffer;
793 message = &context->AUTHENTICATE_MESSAGE;
794
795 if (!sspi_SecBufferAlloc(mic, 16))
796 return (SEC_E_INSUFFICIENT_MEMORY);
797
798 CopyMemory(mic->pvBuffer, message->MessageIntegrityCheck, 16);
799 return (SEC_E_OK);
800 }
801 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC_VALUE)
802 {
803 return ntlm_computeMicValue(context, (SecBuffer*)pBuffer);
804 }
805
806 WLog_ERR(TAG, "[%s]: TODO: Implement ulAttribute%08" PRIx32, __FUNCTION__, ulAttribute);
807 return SEC_E_UNSUPPORTED_FUNCTION;
808 }
809
ntlm_QueryContextAttributesA(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer)810 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext,
811 ULONG ulAttribute, void* pBuffer)
812 {
813 return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
814 }
815
ntlm_SetContextAttributesW(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer,ULONG cbBuffer)816 static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext,
817 ULONG ulAttribute, void* pBuffer,
818 ULONG cbBuffer)
819 {
820 NTLM_CONTEXT* context;
821
822 if (!phContext)
823 return SEC_E_INVALID_HANDLE;
824
825 if (!pBuffer)
826 return SEC_E_INVALID_PARAMETER;
827
828 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
829
830 if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH)
831 {
832 SecPkgContext_AuthNtlmHash* AuthNtlmHash = (SecPkgContext_AuthNtlmHash*)pBuffer;
833
834 if (cbBuffer < sizeof(SecPkgContext_AuthNtlmHash))
835 return SEC_E_INVALID_PARAMETER;
836
837 if (AuthNtlmHash->Version == 1)
838 CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
839 else if (AuthNtlmHash->Version == 2)
840 CopyMemory(context->NtlmV2Hash, AuthNtlmHash->NtlmHash, 16);
841
842 return SEC_E_OK;
843 }
844 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SAM_FILE)
845 {
846 const char* filename = (char*)pBuffer;
847 free(context->SamFile);
848 context->SamFile = NULL;
849
850 if (filename)
851 {
852 context->SamFile = _strdup(filename);
853
854 if (!context->SamFile)
855 return SEC_E_INSUFFICIENT_MEMORY;
856 }
857
858 return SEC_E_OK;
859 }
860 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MESSAGE)
861 {
862 SecPkgContext_AuthNtlmMessage* AuthNtlmMessage = (SecPkgContext_AuthNtlmMessage*)pBuffer;
863
864 if (cbBuffer < sizeof(SecPkgContext_AuthNtlmMessage))
865 return SEC_E_INVALID_PARAMETER;
866
867 if (AuthNtlmMessage->type == 1)
868 {
869 sspi_SecBufferFree(&context->NegotiateMessage);
870
871 if (!sspi_SecBufferAlloc(&context->NegotiateMessage, AuthNtlmMessage->length))
872 return SEC_E_INSUFFICIENT_MEMORY;
873
874 CopyMemory(context->NegotiateMessage.pvBuffer, AuthNtlmMessage->buffer,
875 AuthNtlmMessage->length);
876 }
877 else if (AuthNtlmMessage->type == 2)
878 {
879 sspi_SecBufferFree(&context->ChallengeMessage);
880
881 if (!sspi_SecBufferAlloc(&context->ChallengeMessage, AuthNtlmMessage->length))
882 return SEC_E_INSUFFICIENT_MEMORY;
883
884 CopyMemory(context->ChallengeMessage.pvBuffer, AuthNtlmMessage->buffer,
885 AuthNtlmMessage->length);
886 }
887 else if (AuthNtlmMessage->type == 3)
888 {
889 sspi_SecBufferFree(&context->AuthenticateMessage);
890
891 if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, AuthNtlmMessage->length))
892 return SEC_E_INSUFFICIENT_MEMORY;
893
894 CopyMemory(context->AuthenticateMessage.pvBuffer, AuthNtlmMessage->buffer,
895 AuthNtlmMessage->length);
896 }
897
898 return SEC_E_OK;
899 }
900 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_TIMESTAMP)
901 {
902 SecPkgContext_AuthNtlmTimestamp* AuthNtlmTimestamp =
903 (SecPkgContext_AuthNtlmTimestamp*)pBuffer;
904
905 if (cbBuffer < sizeof(SecPkgContext_AuthNtlmTimestamp))
906 return SEC_E_INVALID_PARAMETER;
907
908 if (AuthNtlmTimestamp->ChallengeOrResponse)
909 CopyMemory(context->ChallengeTimestamp, AuthNtlmTimestamp->Timestamp, 8);
910 else
911 CopyMemory(context->Timestamp, AuthNtlmTimestamp->Timestamp, 8);
912
913 return SEC_E_OK;
914 }
915 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE)
916 {
917 SecPkgContext_AuthNtlmClientChallenge* AuthNtlmClientChallenge =
918 (SecPkgContext_AuthNtlmClientChallenge*)pBuffer;
919
920 if (cbBuffer < sizeof(SecPkgContext_AuthNtlmClientChallenge))
921 return SEC_E_INVALID_PARAMETER;
922
923 CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8);
924 return SEC_E_OK;
925 }
926 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE)
927 {
928 SecPkgContext_AuthNtlmServerChallenge* AuthNtlmServerChallenge =
929 (SecPkgContext_AuthNtlmServerChallenge*)pBuffer;
930
931 if (cbBuffer < sizeof(SecPkgContext_AuthNtlmServerChallenge))
932 return SEC_E_INVALID_PARAMETER;
933
934 CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
935 return SEC_E_OK;
936 }
937 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH_CB)
938 {
939 context->HashCallback = (psPeerComputeNtlmHash)pBuffer;
940 return SEC_E_OK;
941 }
942 else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH_CB_DATA)
943 {
944 context->HashCallbackArg = pBuffer;
945 return SEC_E_OK;
946 }
947
948 WLog_ERR(TAG, "[%s]: TODO: Implement ulAttribute=%08" PRIx32, __FUNCTION__, ulAttribute);
949 return SEC_E_UNSUPPORTED_FUNCTION;
950 }
951
ntlm_SetContextAttributesA(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer,ULONG cbBuffer)952 static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(PCtxtHandle phContext,
953 ULONG ulAttribute, void* pBuffer,
954 ULONG cbBuffer)
955 {
956 return ntlm_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
957 }
958
ntlm_RevertSecurityContext(PCtxtHandle phContext)959 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
960 {
961 return SEC_E_OK;
962 }
963
ntlm_EncryptMessage(PCtxtHandle phContext,ULONG fQOP,PSecBufferDesc pMessage,ULONG MessageSeqNo)964 static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
965 PSecBufferDesc pMessage, ULONG MessageSeqNo)
966 {
967 ULONG index;
968 int length;
969 void* data;
970 UINT32 SeqNo;
971 UINT32 value;
972 BYTE digest[WINPR_MD5_DIGEST_LENGTH];
973 BYTE checksum[8];
974 BYTE* signature;
975 ULONG version = 1;
976 WINPR_HMAC_CTX* hmac;
977 NTLM_CONTEXT* context;
978 PSecBuffer data_buffer = NULL;
979 PSecBuffer signature_buffer = NULL;
980 SeqNo = MessageSeqNo;
981 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
982
983 for (index = 0; index < pMessage->cBuffers; index++)
984 {
985 SecBuffer* cur = &pMessage->pBuffers[index];
986
987 if (cur->BufferType & SECBUFFER_DATA)
988 data_buffer = cur;
989 else if (cur->BufferType & SECBUFFER_TOKEN)
990 signature_buffer = cur;
991 }
992
993 if (!data_buffer)
994 return SEC_E_INVALID_TOKEN;
995
996 if (!signature_buffer)
997 return SEC_E_INVALID_TOKEN;
998
999 /* Copy original data buffer */
1000 length = data_buffer->cbBuffer;
1001 data = malloc(length);
1002
1003 if (!data)
1004 return SEC_E_INSUFFICIENT_MEMORY;
1005
1006 CopyMemory(data, data_buffer->pvBuffer, length);
1007 /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
1008 hmac = winpr_HMAC_New();
1009
1010 if (hmac &&
1011 winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1012 {
1013 Data_Write_UINT32(&value, SeqNo);
1014 winpr_HMAC_Update(hmac, (void*)&value, 4);
1015 winpr_HMAC_Update(hmac, (void*)data, length);
1016 winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH);
1017 winpr_HMAC_Free(hmac);
1018 }
1019 else
1020 {
1021 winpr_HMAC_Free(hmac);
1022 free(data);
1023 return SEC_E_INSUFFICIENT_MEMORY;
1024 }
1025
1026 /* Encrypt message using with RC4, result overwrites original buffer */
1027 if ((data_buffer->BufferType & SECBUFFER_READONLY) == 0)
1028 {
1029 if (context->confidentiality)
1030 winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data,
1031 (BYTE*)data_buffer->pvBuffer);
1032 else
1033 CopyMemory(data_buffer->pvBuffer, data, length);
1034 }
1035
1036 #ifdef WITH_DEBUG_NTLM
1037 WLog_DBG(TAG, "Data Buffer (length = %d)", length);
1038 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1039 WLog_DBG(TAG, "Encrypted Data Buffer (length = %" PRIu32 ")", data_buffer->cbBuffer);
1040 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1041 #endif
1042 free(data);
1043 /* RC4-encrypt first 8 bytes of digest */
1044 winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum);
1045 if ((signature_buffer->BufferType & SECBUFFER_READONLY) == 0)
1046 {
1047 signature = (BYTE*)signature_buffer->pvBuffer;
1048 /* Concatenate version, ciphertext and sequence number to build signature */
1049 Data_Write_UINT32(signature, version);
1050 CopyMemory(&signature[4], (void*)checksum, 8);
1051 Data_Write_UINT32(&signature[12], SeqNo);
1052 }
1053 context->SendSeqNum++;
1054 #ifdef WITH_DEBUG_NTLM
1055 WLog_DBG(TAG, "Signature (length = %" PRIu32 ")", signature_buffer->cbBuffer);
1056 winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer);
1057 #endif
1058 return SEC_E_OK;
1059 }
1060
ntlm_DecryptMessage(PCtxtHandle phContext,PSecBufferDesc pMessage,ULONG MessageSeqNo,PULONG pfQOP)1061 static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage,
1062 ULONG MessageSeqNo, PULONG pfQOP)
1063 {
1064 int index;
1065 int length;
1066 void* data;
1067 UINT32 SeqNo;
1068 UINT32 value;
1069 BYTE digest[WINPR_MD5_DIGEST_LENGTH];
1070 BYTE checksum[8];
1071 UINT32 version = 1;
1072 WINPR_HMAC_CTX* hmac;
1073 NTLM_CONTEXT* context;
1074 BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH];
1075 PSecBuffer data_buffer = NULL;
1076 PSecBuffer signature_buffer = NULL;
1077 SeqNo = (UINT32)MessageSeqNo;
1078 context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
1079
1080 for (index = 0; index < (int)pMessage->cBuffers; index++)
1081 {
1082 if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
1083 data_buffer = &pMessage->pBuffers[index];
1084 else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
1085 signature_buffer = &pMessage->pBuffers[index];
1086 }
1087
1088 if (!data_buffer)
1089 return SEC_E_INVALID_TOKEN;
1090
1091 if (!signature_buffer)
1092 return SEC_E_INVALID_TOKEN;
1093
1094 /* Copy original data buffer */
1095 length = data_buffer->cbBuffer;
1096 data = malloc(length);
1097
1098 if (!data)
1099 return SEC_E_INSUFFICIENT_MEMORY;
1100
1101 CopyMemory(data, data_buffer->pvBuffer, length);
1102
1103 /* Decrypt message using with RC4, result overwrites original buffer */
1104
1105 if (context->confidentiality)
1106 winpr_RC4_Update(context->RecvRc4Seal, length, (BYTE*)data, (BYTE*)data_buffer->pvBuffer);
1107 else
1108 CopyMemory(data_buffer->pvBuffer, data, length);
1109
1110 /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
1111 hmac = winpr_HMAC_New();
1112
1113 if (hmac &&
1114 winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1115 {
1116 Data_Write_UINT32(&value, SeqNo);
1117 winpr_HMAC_Update(hmac, (void*)&value, 4);
1118 winpr_HMAC_Update(hmac, (void*)data_buffer->pvBuffer, data_buffer->cbBuffer);
1119 winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH);
1120 winpr_HMAC_Free(hmac);
1121 }
1122 else
1123 {
1124 winpr_HMAC_Free(hmac);
1125 free(data);
1126 return SEC_E_INSUFFICIENT_MEMORY;
1127 }
1128
1129 #ifdef WITH_DEBUG_NTLM
1130 WLog_DBG(TAG, "Encrypted Data Buffer (length = %d)", length);
1131 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1132 WLog_DBG(TAG, "Data Buffer (length = %" PRIu32 ")", data_buffer->cbBuffer);
1133 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1134 #endif
1135 free(data);
1136 /* RC4-encrypt first 8 bytes of digest */
1137 winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum);
1138 /* Concatenate version, ciphertext and sequence number to build signature */
1139 Data_Write_UINT32(expected_signature, version);
1140 CopyMemory(&expected_signature[4], (void*)checksum, 8);
1141 Data_Write_UINT32(&expected_signature[12], SeqNo);
1142 context->RecvSeqNum++;
1143
1144 if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
1145 {
1146 /* signature verification failed! */
1147 WLog_ERR(TAG, "signature verification failed, something nasty is going on!");
1148 #ifdef WITH_DEBUG_NTLM
1149 WLog_ERR(TAG, "Expected Signature:");
1150 winpr_HexDump(TAG, WLOG_ERROR, expected_signature, 16);
1151 WLog_ERR(TAG, "Actual Signature:");
1152 winpr_HexDump(TAG, WLOG_ERROR, (BYTE*)signature_buffer->pvBuffer, 16);
1153 #endif
1154 return SEC_E_MESSAGE_ALTERED;
1155 }
1156
1157 return SEC_E_OK;
1158 }
1159
ntlm_MakeSignature(PCtxtHandle phContext,ULONG fQOP,PSecBufferDesc pMessage,ULONG MessageSeqNo)1160 static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
1161 PSecBufferDesc pMessage, ULONG MessageSeqNo)
1162 {
1163 WLog_ERR(TAG, "[%s]: TODO: Implement", __FUNCTION__);
1164 return SEC_E_UNSUPPORTED_FUNCTION;
1165 }
1166
ntlm_VerifySignature(PCtxtHandle phContext,PSecBufferDesc pMessage,ULONG MessageSeqNo,PULONG pfQOP)1167 static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext,
1168 PSecBufferDesc pMessage, ULONG MessageSeqNo,
1169 PULONG pfQOP)
1170 {
1171 WLog_ERR(TAG, "[%s]: TODO: Implement", __FUNCTION__);
1172 return SEC_E_UNSUPPORTED_FUNCTION;
1173 }
1174
1175 const SecurityFunctionTableA NTLM_SecurityFunctionTableA = {
1176 1, /* dwVersion */
1177 NULL, /* EnumerateSecurityPackages */
1178 ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
1179 ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
1180 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
1181 NULL, /* Reserved2 */
1182 ntlm_InitializeSecurityContextA, /* InitializeSecurityContext */
1183 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
1184 ntlm_CompleteAuthToken, /* CompleteAuthToken */
1185 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
1186 NULL, /* ApplyControlToken */
1187 ntlm_QueryContextAttributesA, /* QueryContextAttributes */
1188 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1189 ntlm_RevertSecurityContext, /* RevertSecurityContext */
1190 ntlm_MakeSignature, /* MakeSignature */
1191 ntlm_VerifySignature, /* VerifySignature */
1192 NULL, /* FreeContextBuffer */
1193 NULL, /* QuerySecurityPackageInfo */
1194 NULL, /* Reserved3 */
1195 NULL, /* Reserved4 */
1196 NULL, /* ExportSecurityContext */
1197 NULL, /* ImportSecurityContext */
1198 NULL, /* AddCredentials */
1199 NULL, /* Reserved8 */
1200 NULL, /* QuerySecurityContextToken */
1201 ntlm_EncryptMessage, /* EncryptMessage */
1202 ntlm_DecryptMessage, /* DecryptMessage */
1203 ntlm_SetContextAttributesA, /* SetContextAttributes */
1204 };
1205
1206 const SecurityFunctionTableW NTLM_SecurityFunctionTableW = {
1207 1, /* dwVersion */
1208 NULL, /* EnumerateSecurityPackages */
1209 ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
1210 ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
1211 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
1212 NULL, /* Reserved2 */
1213 ntlm_InitializeSecurityContextW, /* InitializeSecurityContext */
1214 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
1215 ntlm_CompleteAuthToken, /* CompleteAuthToken */
1216 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
1217 NULL, /* ApplyControlToken */
1218 ntlm_QueryContextAttributesW, /* QueryContextAttributes */
1219 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1220 ntlm_RevertSecurityContext, /* RevertSecurityContext */
1221 ntlm_MakeSignature, /* MakeSignature */
1222 ntlm_VerifySignature, /* VerifySignature */
1223 NULL, /* FreeContextBuffer */
1224 NULL, /* QuerySecurityPackageInfo */
1225 NULL, /* Reserved3 */
1226 NULL, /* Reserved4 */
1227 NULL, /* ExportSecurityContext */
1228 NULL, /* ImportSecurityContext */
1229 NULL, /* AddCredentials */
1230 NULL, /* Reserved8 */
1231 NULL, /* QuerySecurityContextToken */
1232 ntlm_EncryptMessage, /* EncryptMessage */
1233 ntlm_DecryptMessage, /* DecryptMessage */
1234 ntlm_SetContextAttributesA, /* SetContextAttributes */
1235 };
1236
1237 const SecPkgInfoA NTLM_SecPkgInfoA = {
1238 0x00082B37, /* fCapabilities */
1239 1, /* wVersion */
1240 0x000A, /* wRPCID */
1241 0x00000B48, /* cbMaxToken */
1242 "NTLM", /* Name */
1243 "NTLM Security Package" /* Comment */
1244 };
1245
1246 static WCHAR NTLM_SecPkgInfoW_Name[] = { 'N', 'T', 'L', 'M', '\0' };
1247
1248 static WCHAR NTLM_SecPkgInfoW_Comment[] = {
1249 'N', 'T', 'L', 'M', ' ', 'S', 'e', 'c', 'u', 'r', 'i',
1250 't', 'y', ' ', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\0'
1251 };
1252
1253 const SecPkgInfoW NTLM_SecPkgInfoW = {
1254 0x00082B37, /* fCapabilities */
1255 1, /* wVersion */
1256 0x000A, /* wRPCID */
1257 0x00000B48, /* cbMaxToken */
1258 NTLM_SecPkgInfoW_Name, /* Name */
1259 NTLM_SecPkgInfoW_Comment /* Comment */
1260 };
1261