From 13603394222dfb936447d6b6c5ca6bdf236aa1dd Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Wed, 8 Nov 2006 21:53:23 +0100 Subject: [PATCH] secur32: Implement ntlmv2 signing. --- dlls/secur32/ntlm.c | 96 +++++++++++++++++++++++++++++++++---- dlls/secur32/secur32_priv.h | 11 +++++ dlls/secur32/util.c | 62 ++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 8 deletions(-) diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c index 4affe6c169d..1bee91b85f5 100644 --- a/dlls/secur32/ntlm.c +++ b/dlls/secur32/ntlm.c @@ -28,6 +28,7 @@ #include "sspi.h" #include "lm.h" #include "secur32_priv.h" +#include "hmac_md5.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(secur32); @@ -528,10 +529,6 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( max_len-1, &bin_len)) != SEC_E_OK) goto isc_end; - /* Mask away the NTLMv2 flag, as well as the key exchange flag */ - bin[14] &= ~0x08; - bin[15] &= ~0x40; - /* put the decoded client blob into the out buffer */ ret = SEC_I_CONTINUE_NEEDED; @@ -703,6 +700,15 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( helper->crypt.ntlm.a4i = SECUR32_arc4Alloc(); SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16); helper->crypt.ntlm.seq_num = 0l; + SECUR32_CreateNTLMv2SubKeys(helper); + helper->crypt.ntlm2.send_a4i = SECUR32_arc4Alloc(); + helper->crypt.ntlm2.recv_a4i = SECUR32_arc4Alloc(); + SECUR32_arc4Init(helper->crypt.ntlm2.send_a4i, + (BYTE *)helper->crypt.ntlm2.send_seal_key, 16); + SECUR32_arc4Init(helper->crypt.ntlm2.recv_a4i, + (BYTE *)helper->crypt.ntlm2.recv_seal_key, 16); + helper->crypt.ntlm2.send_seq_no = 0l; + helper->crypt.ntlm2.recv_seq_no = 0l; } if(ret != SEC_I_CONTINUE_NEEDED) @@ -1093,6 +1099,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContex SECUR32_arc4Cleanup(helper->crypt.ntlm.a4i); HeapFree(GetProcessHeap(), 0, helper->session_key); helper->valid_session_key = FALSE; + SECUR32_arc4Cleanup(helper->crypt.ntlm2.send_a4i); + SECUR32_arc4Cleanup(helper->crypt.ntlm2.recv_a4i); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_sign_key); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_seal_key); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_sign_key); + HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_seal_key); return SEC_E_OK; } @@ -1229,16 +1241,84 @@ static SECURITY_STATUS ntlm_CreateSignature(PNegoHelper helper, PSecBufferDesc p { ULONG sign_version = 1; UINT i; - TRACE("%p, %p, %d\n", helper, pMessage, direction); + PBYTE sig; + TRACE("%p, %p, %d, %d\n", helper, pMessage, token_idx, direction); - if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && + sig = pMessage->pBuffers[token_idx].pvBuffer; + + if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - return SEC_E_UNSUPPORTED_FUNCTION; + BYTE digest[16]; + BYTE seq_no[4]; + HMAC_MD5_CTX hmac_md5_ctx; + + TRACE("Encrypting NTLM2 style\n"); + + if(direction == NTLM_SEND) + { + TRACE("Signing for sending\n"); + seq_no[0] = (helper->crypt.ntlm2.send_seq_no >> 0) & 0xff; + seq_no[1] = (helper->crypt.ntlm2.send_seq_no >> 8) & 0xff; + seq_no[2] = (helper->crypt.ntlm2.send_seq_no >> 16) & 0xff; + seq_no[3] = (helper->crypt.ntlm2.send_seq_no >> 24) & 0xff; + + ++(helper->crypt.ntlm2.send_seq_no); + + TRACE("HMACMD5Init...\n"); + HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.send_sign_key, 16); + TRACE("Done\n"); + } + else + { + seq_no[0] = (helper->crypt.ntlm2.recv_seq_no >> 0) & 0xff; + seq_no[1] = (helper->crypt.ntlm2.recv_seq_no >> 8) & 0xff; + seq_no[2] = (helper->crypt.ntlm2.recv_seq_no >> 16) & 0xff; + seq_no[3] = (helper->crypt.ntlm2.recv_seq_no >> 24) & 0xff; + + ++(helper->crypt.ntlm2.recv_seq_no); + + HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.recv_sign_key, 16); + } + + TRACE("Starting the update loop\n"); + + HMACMD5Update(&hmac_md5_ctx, seq_no, 4); + for( i = 0; i < pMessage->cBuffers; ++i ) + { + if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) + HMACMD5Update(&hmac_md5_ctx, (BYTE *)pMessage->pBuffers[i].pvBuffer, + pMessage->pBuffers[i].cbBuffer); + } + + HMACMD5Final(&hmac_md5_ctx, digest); + + TRACE("After HMACMD5Final\n"); + + if(helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE) + { + if(direction == NTLM_SEND) + SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, digest, 8); + else + SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i, digest, 8); + } + + /* The NTLM2 signature is the sign version */ + sig[ 0] = (sign_version >> 0) & 0xff; + sig[ 1] = (sign_version >> 8) & 0xff; + sig[ 2] = (sign_version >> 16) & 0xff; + sig[ 3] = (sign_version >> 24) & 0xff; + /* The first 8 bytes of the digest */ + memcpy(sig+4, digest, 8); + /* And the sequence number */ + memcpy(sig+12, seq_no, 4); + + pMessage->pBuffers[token_idx].cbBuffer = 16; + + return SEC_E_OK; } if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - PBYTE sig = pMessage->pBuffers[token_idx].pvBuffer; ULONG crc = 0U; for(i=0; i < pMessage->cBuffers; ++i) diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h index d7448309156..7ca43f0e6b3 100644 --- a/dlls/secur32/secur32_priv.h +++ b/dlls/secur32/secur32_priv.h @@ -77,6 +77,16 @@ typedef struct _NegoHelper { ULONG seq_num; arc4_info *a4i; } ntlm; + struct { + BYTE *send_sign_key; + BYTE *send_seal_key; + BYTE *recv_sign_key; + BYTE *recv_seal_key; + ULONG send_seq_no; + ULONG recv_seq_no; + arc4_info *send_a4i; + arc4_info *recv_a4i; + } ntlm2; } crypt; } NegoHelper, *PNegoHelper; @@ -141,6 +151,7 @@ SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf, /* Functions from util.c */ ULONG ComputeCrc32(const BYTE *pData, INT iLen, ULONG initial_crc); SECURITY_STATUS SECUR32_CreateNTLMv1SessionKey(PBYTE password, int len, PBYTE session_key); +SECURITY_STATUS SECUR32_CreateNTLMv2SubKeys(PNegoHelper helper); arc4_info *SECUR32_arc4Alloc(void); void SECUR32_arc4Init(arc4_info *a4i, const BYTE *key, unsigned int keyLen); void SECUR32_arc4Process(arc4_info *a4i, BYTE *inoutString, unsigned int length); diff --git a/dlls/secur32/util.c b/dlls/secur32/util.c index d9277f1baef..7a43de76ebb 100644 --- a/dlls/secur32/util.c +++ b/dlls/secur32/util.c @@ -81,6 +81,11 @@ static const ULONG CRC_table[256] = 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; +static const char client_to_server_sign_constant[] = "session key to client-to-server signing key magic constant"; +static const char client_to_server_seal_constant[] = "session key to client-to-server sealing key magic constant"; +static const char server_to_client_sign_constant[] = "session key to server-to-client signing key magic constant"; +static const char server_to_client_seal_constant[] = "session key to server-to-client sealing key magic constant"; + typedef struct { unsigned int buf[4]; @@ -89,9 +94,21 @@ typedef struct unsigned char digest[16]; } MD4_CTX; +/* And now the same with a different memory layout. */ +typedef struct +{ + unsigned int i[2]; + unsigned int buf[4]; + unsigned char in[64]; + unsigned char digest[16]; +} MD5_CTX; + VOID WINAPI MD4Init( MD4_CTX *ctx ); VOID WINAPI MD4Update( MD4_CTX *ctx, const unsigned char *buf, unsigned int len ); VOID WINAPI MD4Final( MD4_CTX *ctx ); +VOID WINAPI MD5Init( MD5_CTX *ctx ); +VOID WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len ); +VOID WINAPI MD5Final( MD5_CTX *ctx ); ULONG ComputeCrc32(const BYTE *pData, INT iLen, ULONG initial_crc) { @@ -128,6 +145,51 @@ SECURITY_STATUS SECUR32_CreateNTLMv1SessionKey(PBYTE password, int len, PBYTE se return SEC_E_OK; } +void SECUR32_CalcNTLMv2Subkey(PBYTE session_key, const char *magic, PBYTE subkey) +{ + MD5_CTX ctx; + + MD5Init(&ctx); + MD5Update(&ctx, session_key, 16); + MD5Update(&ctx, (unsigned char*)magic, lstrlenA(magic)+1); + MD5Final(&ctx); + memcpy(subkey, ctx.digest, 16); +} + +/* This assumes we do have a valid NTLM2 user session key */ +SECURITY_STATUS SECUR32_CreateNTLMv2SubKeys(PNegoHelper helper) +{ + helper->crypt.ntlm2.send_sign_key = HeapAlloc(GetProcessHeap(), 0, 16); + helper->crypt.ntlm2.send_seal_key = HeapAlloc(GetProcessHeap(), 0, 16); + helper->crypt.ntlm2.recv_sign_key = HeapAlloc(GetProcessHeap(), 0, 16); + helper->crypt.ntlm2.recv_seal_key = HeapAlloc(GetProcessHeap(), 0, 16); + + if(helper->mode == NTLM_CLIENT) + { + SECUR32_CalcNTLMv2Subkey(helper->session_key, client_to_server_sign_constant, + helper->crypt.ntlm2.send_sign_key); + SECUR32_CalcNTLMv2Subkey(helper->session_key, client_to_server_seal_constant, + helper->crypt.ntlm2.send_seal_key); + SECUR32_CalcNTLMv2Subkey(helper->session_key, server_to_client_sign_constant, + helper->crypt.ntlm2.recv_sign_key); + SECUR32_CalcNTLMv2Subkey(helper->session_key, server_to_client_seal_constant, + helper->crypt.ntlm2.recv_seal_key); + } + else + { + SECUR32_CalcNTLMv2Subkey(helper->session_key, server_to_client_sign_constant, + helper->crypt.ntlm2.send_sign_key); + SECUR32_CalcNTLMv2Subkey(helper->session_key, server_to_client_seal_constant, + helper->crypt.ntlm2.send_seal_key); + SECUR32_CalcNTLMv2Subkey(helper->session_key, client_to_server_sign_constant, + helper->crypt.ntlm2.recv_sign_key); + SECUR32_CalcNTLMv2Subkey(helper->session_key, client_to_server_seal_constant, + helper->crypt.ntlm2.recv_seal_key); + } + + return SEC_E_OK; +} + arc4_info *SECUR32_arc4Alloc(void) { arc4_info *a4i = HeapAlloc(GetProcessHeap(), 0, sizeof(arc4_info));