2
* WinPR: Windows Portable Runtime
3
* NTLM Security Package
5
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
11
* http://www.apache.org/licenses/LICENSE-2.0
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.
25
#include <openssl/des.h>
26
#include <openssl/md4.h>
27
#include <openssl/hmac.h>
28
#include <openssl/rand.h>
29
#include <openssl/engine.h>
31
#include <winpr/crt.h>
32
#include <winpr/sspi.h>
33
#include <winpr/print.h>
34
#include <winpr/sysinfo.h>
35
#include <winpr/registry.h>
40
#include "ntlm_message.h"
42
char* NTLM_PACKAGE_NAME = "NTLM";
44
void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
50
GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize);
51
Workstation = malloc(nSize);
52
GetComputerNameExA(ComputerNameNetBIOS, Workstation, &nSize);
55
context->Workstation.Length = ConvertToUnicode(CP_UTF8, 0,
56
Workstation, -1, &context->Workstation.Buffer, 0) - 1;
57
context->Workstation.Length *= 2;
63
void ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
65
context->ServicePrincipalName.Length = _wcslen(ServicePrincipalName) * 2;
66
if (!ServicePrincipalName)
68
context->ServicePrincipalName.Buffer = NULL;
71
context->ServicePrincipalName.Buffer = (PWSTR) malloc(context->ServicePrincipalName.Length + 2);
72
CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName, context->ServicePrincipalName.Length + 2);
75
void ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName)
77
context->ServicePrincipalName.Length = ConvertToUnicode(CP_UTF8, 0,
78
ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0) - 1;
79
context->ServicePrincipalName.Length *= 2;
82
void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
88
GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize);
89
TargetName = malloc(nSize);
90
GetComputerNameExA(ComputerNameDnsHostname, TargetName, &nSize);
91
CharUpperA(TargetName);
94
context->TargetName.cbBuffer = ConvertToUnicode(CP_UTF8, 0,
95
TargetName, -1, (LPWSTR*) &context->TargetName.pvBuffer, 0) - 1;
96
context->TargetName.cbBuffer *= 2;
102
NTLM_CONTEXT* ntlm_ContextNew()
104
NTLM_CONTEXT* context;
106
context = (NTLM_CONTEXT*) malloc(sizeof(NTLM_CONTEXT));
107
ZeroMemory(context, sizeof(NTLM_CONTEXT));
117
context->NTLMv2 = TRUE;
118
context->UseMIC = FALSE;
119
context->SendVersionInfo = TRUE;
120
context->SendSingleHostData = FALSE;
121
context->SendWorkstationName = TRUE;
123
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
125
if (status == ERROR_SUCCESS)
127
if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
128
context->NTLMv2 = dwValue ? 1 : 0;
130
if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
131
context->UseMIC = dwValue ? 1 : 0;
133
if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
134
context->SendVersionInfo = dwValue ? 1 : 0;
136
if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
137
context->SendSingleHostData = dwValue ? 1 : 0;
139
if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
140
context->SendWorkstationName = dwValue ? 1 : 0;
142
if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
144
char* workstation = (char*) malloc(dwSize + 1);
146
status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*) workstation, &dwSize);
147
workstation[dwSize] = '\0';
149
ntlm_SetContextWorkstation(context, workstation);
157
* Extended Protection is enabled by default in Windows 7,
158
* but enabling it in WinPR breaks TS Gateway at this point
160
context->SuppressExtendedProtection = FALSE;
162
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
164
if (status == ERROR_SUCCESS)
166
if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
167
context->SuppressExtendedProtection = dwValue ? 1 : 0;
172
context->NegotiateFlags = 0;
173
context->LmCompatibilityLevel = 3;
174
context->state = NTLM_STATE_INITIAL;
175
memset(context->MachineID, 0xAA, sizeof(context->MachineID));
178
context->UseMIC = TRUE;
184
void ntlm_ContextFree(NTLM_CONTEXT* context)
189
sspi_SecBufferFree(&context->NegotiateMessage);
190
sspi_SecBufferFree(&context->ChallengeMessage);
191
sspi_SecBufferFree(&context->AuthenticateMessage);
192
sspi_SecBufferFree(&context->ChallengeTargetInfo);
193
sspi_SecBufferFree(&context->TargetName);
194
sspi_SecBufferFree(&context->NtChallengeResponse);
195
sspi_SecBufferFree(&context->LmChallengeResponse);
197
free(context->ServicePrincipalName.Buffer);
199
free(context->identity.User);
200
free(context->identity.Password);
201
free(context->identity.Domain);
202
free(context->Workstation.Buffer);
206
SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage,
207
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
208
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
210
CREDENTIALS* credentials;
211
SEC_WINNT_AUTH_IDENTITY* identity;
213
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
215
credentials = sspi_CredentialsNew();
217
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
219
if (identity != NULL)
220
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
222
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
223
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
227
else if (fCredentialUse == SECPKG_CRED_INBOUND)
229
credentials = sspi_CredentialsNew();
231
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
234
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
236
ZeroMemory(&(credentials->identity), sizeof(SEC_WINNT_AUTH_IDENTITY));
238
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
239
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
247
SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage,
248
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
249
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
251
CREDENTIALS* credentials;
252
SEC_WINNT_AUTH_IDENTITY* identity;
254
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
256
credentials = sspi_CredentialsNew();
258
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
260
if (identity != NULL)
261
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
263
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
264
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
268
else if (fCredentialUse == SECPKG_CRED_INBOUND)
270
credentials = sspi_CredentialsNew();
272
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
274
if (identity != NULL)
275
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
277
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
278
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
286
SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
288
CREDENTIALS* credentials;
291
return SEC_E_INVALID_HANDLE;
293
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
296
return SEC_E_INVALID_HANDLE;
298
sspi_CredentialsFree(credentials);
303
SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
305
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
310
return SEC_E_UNSUPPORTED_FUNCTION;
313
SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
315
return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
319
* @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374707
321
SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext,
322
PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
323
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
325
NTLM_CONTEXT* context;
326
SECURITY_STATUS status;
327
CREDENTIALS* credentials;
328
PSecBuffer input_buffer;
329
PSecBuffer output_buffer;
331
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
335
context = ntlm_ContextNew();
338
return SEC_E_INSUFFICIENT_MEMORY;
342
if (fContextReq & ASC_REQ_CONFIDENTIALITY)
343
context->confidentiality = 1;
345
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
346
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
348
ntlm_SetContextTargetName(context, NULL);
350
sspi_SecureHandleSetLowerPointer(phNewContext, context);
351
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
354
if (context->state == NTLM_STATE_INITIAL)
356
context->state = NTLM_STATE_NEGOTIATE;
359
return SEC_E_INVALID_TOKEN;
361
if (pInput->cBuffers < 1)
362
return SEC_E_INVALID_TOKEN;
364
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
367
return SEC_E_INVALID_TOKEN;
369
if (input_buffer->cbBuffer < 1)
370
return SEC_E_INVALID_TOKEN;
372
status = ntlm_read_NegotiateMessage(context, input_buffer);
374
if (context->state == NTLM_STATE_CHALLENGE)
377
return SEC_E_INVALID_TOKEN;
379
if (pOutput->cBuffers < 1)
380
return SEC_E_INVALID_TOKEN;
382
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
384
if (!output_buffer->BufferType)
385
return SEC_E_INVALID_TOKEN;
387
if (output_buffer->cbBuffer < 1)
388
return SEC_E_INSUFFICIENT_MEMORY;
390
return ntlm_write_ChallengeMessage(context, output_buffer);
393
return SEC_E_OUT_OF_SEQUENCE;
395
else if (context->state == NTLM_STATE_AUTHENTICATE)
398
return SEC_E_INVALID_TOKEN;
400
if (pInput->cBuffers < 1)
401
return SEC_E_INVALID_TOKEN;
403
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
406
return SEC_E_INVALID_TOKEN;
408
if (input_buffer->cbBuffer < 1)
409
return SEC_E_INVALID_TOKEN;
411
status = ntlm_read_AuthenticateMessage(context, input_buffer);
417
for (i = 0; i < pOutput->cBuffers; i++)
419
pOutput->pBuffers[i].cbBuffer = 0;
420
pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
427
return SEC_E_OUT_OF_SEQUENCE;
430
SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
435
SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
436
SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
437
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
438
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
440
NTLM_CONTEXT* context;
441
SECURITY_STATUS status;
442
CREDENTIALS* credentials;
443
PSecBuffer input_buffer = NULL;
444
PSecBuffer output_buffer = NULL;
445
PSecBuffer channel_bindings = NULL;
447
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
451
context = ntlm_ContextNew();
454
return SEC_E_INSUFFICIENT_MEMORY;
456
if (fContextReq & ISC_REQ_CONFIDENTIALITY)
457
context->confidentiality = 1;
459
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
461
if (context->Workstation.Length < 1)
462
ntlm_SetContextWorkstation(context, NULL);
464
ntlm_SetContextServicePrincipalNameW(context, pszTargetName);
465
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
467
sspi_SecureHandleSetLowerPointer(phNewContext, context);
468
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
471
if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE))
474
return SEC_E_INVALID_TOKEN;
476
if (pOutput->cBuffers < 1)
477
return SEC_E_INVALID_TOKEN;
479
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
482
return SEC_E_INVALID_TOKEN;
484
if (output_buffer->cbBuffer < 1)
485
return SEC_E_INVALID_TOKEN;
487
if (context->state == NTLM_STATE_INITIAL)
488
context->state = NTLM_STATE_NEGOTIATE;
490
if (context->state == NTLM_STATE_NEGOTIATE)
491
return ntlm_write_NegotiateMessage(context, output_buffer);
493
return SEC_E_OUT_OF_SEQUENCE;
497
if (pInput->cBuffers < 1)
498
return SEC_E_INVALID_TOKEN;
500
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
503
return SEC_E_INVALID_TOKEN;
505
if (input_buffer->cbBuffer < 1)
506
return SEC_E_INVALID_TOKEN;
508
channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
510
if (channel_bindings)
512
context->Bindings.BindingsLength = channel_bindings->cbBuffer;
513
context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*) channel_bindings->pvBuffer;
516
if (context->state == NTLM_STATE_CHALLENGE)
518
status = ntlm_read_ChallengeMessage(context, input_buffer);
521
return SEC_E_INVALID_TOKEN;
523
if (pOutput->cBuffers < 1)
524
return SEC_E_INVALID_TOKEN;
526
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
529
return SEC_E_INVALID_TOKEN;
531
if (output_buffer->cbBuffer < 1)
532
return SEC_E_INSUFFICIENT_MEMORY;
534
if (context->state == NTLM_STATE_AUTHENTICATE)
535
return ntlm_write_AuthenticateMessage(context, output_buffer);
538
return SEC_E_OUT_OF_SEQUENCE;
541
return SEC_E_OUT_OF_SEQUENCE;
545
* @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375512%28v=vs.85%29.aspx
547
SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
548
SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
549
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
550
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
552
SECURITY_STATUS status;
553
SEC_WCHAR* pszTargetNameW = NULL;
555
if (pszTargetName != NULL)
557
ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0);
560
status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
561
Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
563
if (pszTargetNameW != NULL)
564
free(pszTargetNameW);
569
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375354 */
571
SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
573
NTLM_CONTEXT* context;
575
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
578
return SEC_E_INVALID_HANDLE;
580
ntlm_ContextFree(context);
585
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379337/ */
587
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
590
return SEC_E_INVALID_HANDLE;
593
return SEC_E_INSUFFICIENT_MEMORY;
595
if (ulAttribute == SECPKG_ATTR_SIZES)
597
SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer;
599
ContextSizes->cbMaxToken = 2010;
600
ContextSizes->cbMaxSignature = 16;
601
ContextSizes->cbBlockSize = 0;
602
ContextSizes->cbSecurityTrailer = 16;
607
return SEC_E_UNSUPPORTED_FUNCTION;
610
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
612
return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
615
SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
620
SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
631
NTLM_CONTEXT* context;
632
PSecBuffer data_buffer = NULL;
633
PSecBuffer signature_buffer = NULL;
635
SeqNo = MessageSeqNo;
636
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
638
for (index = 0; index < (int) pMessage->cBuffers; index++)
640
if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
641
data_buffer = &pMessage->pBuffers[index];
642
else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
643
signature_buffer = &pMessage->pBuffers[index];
647
return SEC_E_INVALID_TOKEN;
649
if (!signature_buffer)
650
return SEC_E_INVALID_TOKEN;
652
/* Copy original data buffer */
653
length = data_buffer->cbBuffer;
654
data = malloc(length);
655
CopyMemory(data, data_buffer->pvBuffer, length);
657
/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
658
HMAC_CTX_init(&hmac);
659
HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL);
660
HMAC_Update(&hmac, (void*) &(SeqNo), 4);
661
HMAC_Update(&hmac, data, length);
662
HMAC_Final(&hmac, digest, NULL);
663
HMAC_CTX_cleanup(&hmac);
665
/* Encrypt message using with RC4, result overwrites original buffer */
667
if (context->confidentiality)
668
RC4(&context->SendRc4Seal, length, data, data_buffer->pvBuffer);
670
CopyMemory(data_buffer->pvBuffer, data, length);
672
#ifdef WITH_DEBUG_NTLM
673
fprintf(stderr, "Data Buffer (length = %d)\n", length);
674
winpr_HexDump(data, length);
675
fprintf(stderr, "\n");
677
fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer);
678
winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer);
679
fprintf(stderr, "\n");
684
/* RC4-encrypt first 8 bytes of digest */
685
RC4(&context->SendRc4Seal, 8, digest, checksum);
687
signature = (BYTE*) signature_buffer->pvBuffer;
689
/* Concatenate version, ciphertext and sequence number to build signature */
690
CopyMemory(signature, (void*) &version, 4);
691
CopyMemory(&signature[4], (void*) checksum, 8);
692
CopyMemory(&signature[12], (void*) &(SeqNo), 4);
693
context->SendSeqNum++;
695
#ifdef WITH_DEBUG_NTLM
696
fprintf(stderr, "Signature (length = %d)\n", (int) signature_buffer->cbBuffer);
697
winpr_HexDump(signature_buffer->pvBuffer, signature_buffer->cbBuffer);
698
fprintf(stderr, "\n");
704
SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
714
NTLM_CONTEXT* context;
715
BYTE expected_signature[16];
716
PSecBuffer data_buffer = NULL;
717
PSecBuffer signature_buffer = NULL;
719
SeqNo = (UINT32) MessageSeqNo;
720
context = sspi_SecureHandleGetLowerPointer(phContext);
722
for (index = 0; index < (int) pMessage->cBuffers; index++)
724
if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
725
data_buffer = &pMessage->pBuffers[index];
726
else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
727
signature_buffer = &pMessage->pBuffers[index];
731
return SEC_E_INVALID_TOKEN;
733
if (!signature_buffer)
734
return SEC_E_INVALID_TOKEN;
736
/* Copy original data buffer */
737
length = data_buffer->cbBuffer;
738
data = malloc(length);
739
CopyMemory(data, data_buffer->pvBuffer, length);
741
/* Decrypt message using with RC4, result overwrites original buffer */
743
if (context->confidentiality)
744
RC4(&context->RecvRc4Seal, length, data, data_buffer->pvBuffer);
746
CopyMemory(data_buffer->pvBuffer, data, length);
748
/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
749
HMAC_CTX_init(&hmac);
750
HMAC_Init_ex(&hmac, context->RecvSigningKey, 16, EVP_md5(), NULL);
751
HMAC_Update(&hmac, (void*) &(SeqNo), 4);
752
HMAC_Update(&hmac, data_buffer->pvBuffer, data_buffer->cbBuffer);
753
HMAC_Final(&hmac, digest, NULL);
754
HMAC_CTX_cleanup(&hmac);
756
#ifdef WITH_DEBUG_NTLM
757
fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", length);
758
winpr_HexDump(data, length);
759
fprintf(stderr, "\n");
761
fprintf(stderr, "Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer);
762
winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer);
763
fprintf(stderr, "\n");
768
/* RC4-encrypt first 8 bytes of digest */
769
RC4(&context->RecvRc4Seal, 8, digest, checksum);
771
/* Concatenate version, ciphertext and sequence number to build signature */
772
CopyMemory(expected_signature, (void*) &version, 4);
773
CopyMemory(&expected_signature[4], (void*) checksum, 8);
774
CopyMemory(&expected_signature[12], (void*) &(SeqNo), 4);
775
context->RecvSeqNum++;
777
if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
779
/* signature verification failed! */
780
fprintf(stderr, "signature verification failed, something nasty is going on!\n");
782
fprintf(stderr, "Expected Signature:\n");
783
winpr_HexDump(expected_signature, 16);
784
fprintf(stderr, "Actual Signature:\n");
785
winpr_HexDump(signature_buffer->pvBuffer, 16);
787
return SEC_E_MESSAGE_ALTERED;
793
SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
798
SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
803
const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
806
NULL, /* EnumerateSecurityPackages */
807
ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
808
ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
809
ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
810
NULL, /* Reserved2 */
811
ntlm_InitializeSecurityContextA, /* InitializeSecurityContext */
812
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
813
NULL, /* CompleteAuthToken */
814
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
815
NULL, /* ApplyControlToken */
816
ntlm_QueryContextAttributesA, /* QueryContextAttributes */
817
ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
818
ntlm_RevertSecurityContext, /* RevertSecurityContext */
819
ntlm_MakeSignature, /* MakeSignature */
820
ntlm_VerifySignature, /* VerifySignature */
821
NULL, /* FreeContextBuffer */
822
NULL, /* QuerySecurityPackageInfo */
823
NULL, /* Reserved3 */
824
NULL, /* Reserved4 */
825
NULL, /* ExportSecurityContext */
826
NULL, /* ImportSecurityContext */
827
NULL, /* AddCredentials */
828
NULL, /* Reserved8 */
829
NULL, /* QuerySecurityContextToken */
830
ntlm_EncryptMessage, /* EncryptMessage */
831
ntlm_DecryptMessage, /* DecryptMessage */
832
NULL, /* SetContextAttributes */
835
const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
838
NULL, /* EnumerateSecurityPackages */
839
ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
840
ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
841
ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
842
NULL, /* Reserved2 */
843
ntlm_InitializeSecurityContextW, /* InitializeSecurityContext */
844
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
845
NULL, /* CompleteAuthToken */
846
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
847
NULL, /* ApplyControlToken */
848
ntlm_QueryContextAttributesW, /* QueryContextAttributes */
849
ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
850
ntlm_RevertSecurityContext, /* RevertSecurityContext */
851
ntlm_MakeSignature, /* MakeSignature */
852
ntlm_VerifySignature, /* VerifySignature */
853
NULL, /* FreeContextBuffer */
854
NULL, /* QuerySecurityPackageInfo */
855
NULL, /* Reserved3 */
856
NULL, /* Reserved4 */
857
NULL, /* ExportSecurityContext */
858
NULL, /* ImportSecurityContext */
859
NULL, /* AddCredentials */
860
NULL, /* Reserved8 */
861
NULL, /* QuerySecurityContextToken */
862
ntlm_EncryptMessage, /* EncryptMessage */
863
ntlm_DecryptMessage, /* DecryptMessage */
864
NULL, /* SetContextAttributes */
867
const SecPkgInfoA NTLM_SecPkgInfoA =
869
0x00082B37, /* fCapabilities */
872
0x00000B48, /* cbMaxToken */
874
"NTLM Security Package" /* Comment */
877
WCHAR NTLM_SecPkgInfoW_Name[] = { 'N','T','L','M','\0' };
879
WCHAR NTLM_SecPkgInfoW_Comment[] =
882
'S','e','c','u','r','i','t','y',' ',
883
'P','a','c','k','a','g','e','\0'
886
const SecPkgInfoW NTLM_SecPkgInfoW =
888
0x00082B37, /* fCapabilities */
891
0x00000B48, /* cbMaxToken */
892
NTLM_SecPkgInfoW_Name, /* Name */
893
NTLM_SecPkgInfoW_Comment /* Comment */