From 6d7f1e427c767cf420b1a0036be67c7fbc11b1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 1 Jul 2012 19:43:13 -0400 Subject: [PATCH] libwinpr-sspi: get partial server-side NLA functionality with mstsc.exe as a client --- libfreerdp-crypto/nla.c | 6 ++++ winpr/sspi/NTLM/ntlm.c | 4 +-- winpr/sspi/NTLM/ntlm.h | 12 ++++++- winpr/sspi/NTLM/ntlm_message.c | 66 ++++++++++++++++++++++++---------- 4 files changed, 66 insertions(+), 22 deletions(-) diff --git a/libfreerdp-crypto/nla.c b/libfreerdp-crypto/nla.c index 22dcef76f..a88eb2582 100644 --- a/libfreerdp-crypto/nla.c +++ b/libfreerdp-crypto/nla.c @@ -537,6 +537,12 @@ int credssp_server_authenticate(rdpCredssp* credssp) status = SEC_I_CONTINUE_NEEDED; } + if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED)) + { + printf("AcceptSecurityContext status: 0x%08X\n", status); + return -1; + } + /* send authentication token */ #ifdef WITH_DEBUG_CREDSSP diff --git a/winpr/sspi/NTLM/ntlm.c b/winpr/sspi/NTLM/ntlm.c index 791bb50d8..fa14b7e45 100644 --- a/winpr/sspi/NTLM/ntlm.c +++ b/winpr/sspi/NTLM/ntlm.c @@ -86,12 +86,12 @@ NTLM_CONTEXT* ntlm_ContextNew() if (context != NULL) { - context->ntlm_v2 = TRUE; + context->ntlm_v2 = FALSE; context->NegotiateFlags = 0; context->SendVersionInfo = TRUE; context->LmCompatibilityLevel = 3; context->state = NTLM_STATE_INITIAL; - context->SuppressExtendedProtection = 1; + context->SuppressExtendedProtection = TRUE; context->av_pairs = (AV_PAIRS*) malloc(sizeof(AV_PAIRS)); ZeroMemory(context->av_pairs, sizeof(AV_PAIRS)); } diff --git a/winpr/sspi/NTLM/ntlm.h b/winpr/sspi/NTLM/ntlm.h index bdd801455..e16c2c4f2 100644 --- a/winpr/sspi/NTLM/ntlm.h +++ b/winpr/sspi/NTLM/ntlm.h @@ -147,6 +147,16 @@ struct _NTLM_VERSION_INFO }; typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO; +struct _NTLM_RESTRICTION_ENCODING +{ + UINT32 Size; + UINT32 Z4; + UINT32 IntegrityLevel; + UINT32 SubjectIntegrityLevel; + BYTE MachineId[32]; +}; +typedef struct _NTLM_RESTRICTION_ENCODING NTLM_RESTRICTION_ENCODING; + struct _NTLM_RESPONSE { BYTE Response[24]; @@ -236,7 +246,7 @@ struct _NTLM_CONTEXT NTLM_STATE state; int SendSeqNum; int RecvSeqNum; - int SendVersionInfo; + BOOL SendVersionInfo; BOOL confidentiality; RC4_KEY SendRc4Seal; RC4_KEY RecvRc4Seal; diff --git a/winpr/sspi/NTLM/ntlm_message.c b/winpr/sspi/NTLM/ntlm_message.c index 2108d04a9..9470ec841 100644 --- a/winpr/sspi/NTLM/ntlm_message.c +++ b/winpr/sspi/NTLM/ntlm_message.c @@ -219,8 +219,8 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf context->NegotiateMessage.BufferType = buffer->BufferType; #ifdef WITH_DEBUG_NTLM - printf("NEGOTIATE_MESSAGE (length = %d)\n", length); - winpr_HexDump(s->data, length); + printf("NEGOTIATE_MESSAGE (length = %d)\n", (int) context->NegotiateMessage.cbBuffer); + winpr_HexDump(context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); printf("\n"); ntlm_print_negotiate_flags(message.NegotiateFlags); @@ -353,7 +353,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf /* TargetNameFields (8 bytes) */ ntlm_read_message_fields(s, &(message.TargetName)); - StreamRead_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */ + context->NegotiateFlags = message.NegotiateFlags; StreamRead(s, message.ServerChallenge, 8); /* ServerChallenge (8 bytes) */ CopyMemory(context->ServerChallenge, message.ServerChallenge, 8); @@ -602,11 +603,17 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer { PStream s; int length; - UINT32 flags = 0; + UINT32 flags; + UINT32 MicOffset; + NTLM_AV_PAIR* AvFlags; NTLMv2_RESPONSE response; UINT32 PayloadBufferOffset; NTLM_AUTHENTICATE_MESSAGE message; + flags = 0; + MicOffset = 0; + AvFlags = NULL; + ZeroMemory(&message, sizeof(message)); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); @@ -664,12 +671,16 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (message.NtChallengeResponse.Len > 0) { - NTLM_AV_PAIR* AvFlags; - PStream s = PStreamAllocAttach(message.NtChallengeResponse.Buffer, message.NtChallengeResponse.Len); ntlm_read_ntlm_v2_response(s, &response); PStreamFreeDetach(s); + context->NtChallengeResponse.pvBuffer = message.NtChallengeResponse.Buffer; + context->NtChallengeResponse.cbBuffer = message.NtChallengeResponse.Len; + + context->TargetInfo.pvBuffer = (void*) response.Challenge.AvPairs; + context->TargetInfo.cbBuffer = message.NtChallengeResponse.Len - (28 + 16); + CopyMemory(context->ClientChallenge, response.Challenge.ClientChallenge, 8); AvFlags = ntlm_av_pair_get(response.Challenge.AvPairs, MsvAvFlags); @@ -682,25 +693,23 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer ntlm_read_message_fields_buffer(s, &(message.EncryptedRandomSessionKey)); CopyMemory(context->EncryptedRandomSessionKey, message.EncryptedRandomSessionKey.Buffer, 16); - StreamSetOffset(s, PayloadBufferOffset); - - if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) - { - StreamRead(s, message.MessageIntegrityCheck, 16); - PayloadBufferOffset += 16; - } - - /* move to end of stream, incorrectly assumes the EncryptedRandomSessionKey buffer is last */ - StreamSetOffset(s, message.EncryptedRandomSessionKey.BufferOffset + message.EncryptedRandomSessionKey.Len); - length = StreamSize(s); sspi_SecBufferAlloc(&context->AuthenticateMessage, length); CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length); buffer->cbBuffer = length; + StreamSetOffset(s, PayloadBufferOffset); + + if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) + { + MicOffset = StreamGetOffset(s); + StreamRead(s, message.MessageIntegrityCheck, 16); + PayloadBufferOffset += 16; + } + #ifdef WITH_DEBUG_NTLM - printf("AUTHENTICATE_MESSAGE (length = %d)\n", length); - winpr_HexDump(s->data, length); + printf("AUTHENTICATE_MESSAGE (length = %d)\n", (int) context->AuthenticateMessage.cbBuffer); + winpr_HexDump(context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer); printf("\n"); if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) @@ -751,6 +760,25 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer /* ExportedSessionKey */ ntlm_generate_exported_session_key(context); + if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) + { + ZeroMemory(&((PBYTE) context->AuthenticateMessage.pvBuffer)[MicOffset], 16); + ntlm_compute_message_integrity_check(context); + CopyMemory(&((PBYTE) context->AuthenticateMessage.pvBuffer)[MicOffset], message.MessageIntegrityCheck, 16); + + if (memcmp(context->MessageIntegrityCheck, message.MessageIntegrityCheck, 16) != 0) + { + printf("Message Integrity Check (MIC) verification failed!\n"); + + printf("Expected MIC:\n"); + winpr_HexDump(context->MessageIntegrityCheck, 16); + printf("Actual MIC:\n"); + winpr_HexDump(message.MessageIntegrityCheck, 16); + + //return SEC_E_MESSAGE_ALTERED; + } + } + /* Generate signing keys */ ntlm_generate_client_signing_key(context); ntlm_generate_server_signing_key(context);