diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c index 8f124d75621..d1d951f5909 100644 --- a/dlls/secur32/ntlm.c +++ b/dlls/secur32/ntlm.c @@ -1207,6 +1207,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG { PNegoHelper helper; ULONG sign_version = 1; + UINT i; + int token_idx = -1; TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo); if (!phContext) @@ -1218,12 +1220,22 @@ static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG if(MessageSeqNo) FIXME("Ignoring MessageSeqNo\n"); - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2 || - pMessage->pBuffers[0].BufferType != SECBUFFER_TOKEN || - !pMessage->pBuffers[0].pvBuffer) + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) return SEC_E_INVALID_TOKEN; - if(pMessage->pBuffers[0].cbBuffer < 16) + for(i=0; i < pMessage->cBuffers; ++i) + { + if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) + { + token_idx = i; + break; + } + } + /* If we didn't find a SECBUFFER_TOKEN type buffer */ + if(token_idx == -1) + return SEC_E_INVALID_TOKEN; + + if(pMessage->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL; helper = (PNegoHelper)phContext->dwLower; @@ -1235,9 +1247,17 @@ static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG } if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - PBYTE sig = pMessage->pBuffers[0].pvBuffer; - ULONG crc = ComputeCrc32(pMessage->pBuffers[1].pvBuffer, - pMessage->pBuffers[1].cbBuffer); + PBYTE sig = pMessage->pBuffers[token_idx].pvBuffer; + ULONG crc = 0U; + + for(i=0; i < pMessage->cBuffers; ++i) + { + if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) + { + crc = ComputeCrc32(pMessage->pBuffers[i].pvBuffer, + pMessage->pBuffers[i].cbBuffer, crc); + } + } sig[ 0] = (sign_version >> 0) & 0xff; sig[ 1] = (sign_version >> 8) & 0xff; @@ -1269,9 +1289,9 @@ static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG { TRACE("Generating dummy signature\n"); /* A dummy signature is 0x01 followed by 15 bytes of 0x00 */ - memset(pMessage->pBuffers[0].pvBuffer, 0, 16); - memset(pMessage->pBuffers[0].pvBuffer, 0x01, 1); - pMessage->pBuffers[0].cbBuffer = 16; + memset(pMessage->pBuffers[token_idx].pvBuffer, 0, 16); + memset(pMessage->pBuffers[token_idx].pvBuffer, 0x01, 1); + pMessage->pBuffers[token_idx].cbBuffer = 16; return SEC_E_OK; } @@ -1286,17 +1306,28 @@ static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, { PNegoHelper helper; ULONG fQOP = 0; + UINT i; + int token_idx = -1; TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP); if(!phContext) return SEC_E_INVALID_HANDLE; - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2 || - pMessage->pBuffers[0].BufferType != SECBUFFER_TOKEN || - !pMessage->pBuffers[0].pvBuffer) + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) return SEC_E_INVALID_TOKEN; - if(pMessage->pBuffers[0].cbBuffer < 16) + for(i=0; i < pMessage->cBuffers; ++i) + { + if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) + { + token_idx = i; + break; + } + } + if(token_idx == -1) + return SEC_E_INVALID_TOKEN; + + if(pMessage->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL; if(MessageSeqNo) @@ -1329,7 +1360,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, ntlm_MakeSignature(phContext, fQOP, &local_desc, MessageSeqNo); - if(memcmp(((PBYTE)local_buff[0].pvBuffer) + 8, ((PBYTE)pMessage->pBuffers[0].pvBuffer) + 8, 8)) + if(memcmp(((PBYTE)local_buff[0].pvBuffer) + 8, + ((PBYTE)pMessage->pBuffers[token_idx].pvBuffer) + 8, 8)) return SEC_E_MESSAGE_ALTERED; return SEC_E_OK; @@ -1346,7 +1378,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, const BYTE dummy_sig[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; TRACE("Assuming dummy signature.\n"); - if(memcmp(pMessage->pBuffers[0].pvBuffer, dummy_sig, sizeof(dummy_sig)) != 0) + if(memcmp(pMessage->pBuffers[token_idx].pvBuffer, dummy_sig, sizeof(dummy_sig)) != 0) { TRACE("Failed to verify the packet signature. Not a dummy signature?\n"); return SEC_E_MESSAGE_ALTERED; @@ -1389,6 +1421,9 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) { PNegoHelper helper; + UINT i; + int token_idx = -1; + TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); if(!phContext) @@ -1400,12 +1435,22 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, if(MessageSeqNo) FIXME("Ignoring MessageSeqNo\n"); - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2 || - pMessage->pBuffers[0].BufferType != SECBUFFER_TOKEN || - !pMessage->pBuffers[0].pvBuffer) + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) return SEC_E_INVALID_TOKEN; - if(pMessage->pBuffers[0].cbBuffer < 16) + for(i=0; i < pMessage->cBuffers; ++i) + { + if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) + { + token_idx = i; + break; + } + } + + if(token_idx == -1) + return SEC_E_INVALID_TOKEN; + + if(pMessage->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL; helper = (PNegoHelper) phContext->dwLower; @@ -1417,11 +1462,19 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, } else { - PBYTE sig = pMessage->pBuffers[0].pvBuffer; - ULONG crc = ComputeCrc32(pMessage->pBuffers[1].pvBuffer, - pMessage->pBuffers[1].cbBuffer); + PBYTE sig = pMessage->pBuffers[token_idx].pvBuffer; + ULONG crc = 0U; ULONG sign_version = 1l; + for(i=0; i < pMessage->cBuffers; ++i) + { + if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) + { + crc = ComputeCrc32(pMessage->pBuffers[i].pvBuffer, + pMessage->pBuffers[i].cbBuffer, crc); + } + } + sig[ 0] = (sign_version >> 0) & 0xff; sig[ 1] = (sign_version >> 8) & 0xff; sig[ 2] = (sign_version >> 16) & 0xff; @@ -1459,6 +1512,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, SECURITY_STATUS ret; ULONG ntlmssp_flags_save; PNegoHelper helper; + UINT i; + int token_idx = -1; TRACE("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); if(!phContext) @@ -1467,12 +1522,21 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, if(MessageSeqNo) FIXME("Ignoring MessageSeqNo\n"); - if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2 || - pMessage->pBuffers[0].BufferType != SECBUFFER_TOKEN || - !pMessage->pBuffers[0].pvBuffer) + if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) return SEC_E_INVALID_TOKEN; - if(pMessage->pBuffers[0].cbBuffer < 16) + for(i=0; i < pMessage->cBuffers; ++i) + { + if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) + { + token_idx = i; + break; + } + } + if(token_idx == -1) + return SEC_E_INVALID_TOKEN; + + if(pMessage->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL; helper = (PNegoHelper) phContext->dwLower; diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h index 2f99454b18c..d2002fdf268 100644 --- a/dlls/secur32/secur32_priv.h +++ b/dlls/secur32/secur32_priv.h @@ -134,7 +134,7 @@ SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf, int max_len, int *out_len); /* Functions from util.c */ -ULONG ComputeCrc32(const BYTE *pData, INT iLen); +ULONG ComputeCrc32(const BYTE *pData, INT iLen, ULONG initial_crc); SECURITY_STATUS SECUR32_CreateNTLMv1SessionKey(PBYTE password, int len, PBYTE session_key); arc4_info *SECUR32_arc4Alloc(void); void SECUR32_arc4Init(arc4_info *a4i, const BYTE *key, unsigned int keyLen); diff --git a/dlls/secur32/tests/ntlm.c b/dlls/secur32/tests/ntlm.c index b189685c1b2..7e63697d645 100644 --- a/dlls/secur32/tests/ntlm.c +++ b/dlls/secur32/tests/ntlm.c @@ -111,6 +111,8 @@ static BYTE message_binary[] = static char message[] = "Hello, world!"; +static char message_header[] = "Header Test"; + static BYTE crypt_trailer_client[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xc7, 0xaa, 0x26, 0x16, 0x39, 0x07, 0x4e}; @@ -119,6 +121,14 @@ static BYTE crypt_message_client[] = {0x86, 0x9c, 0x5a, 0x10, 0x78, 0xb3, 0x30, 0x98, 0x46, 0x15, 0xa0, 0x31, 0xd9}; +static BYTE crypt_trailer_client2[] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xa7, + 0xf7, 0x0f, 0x5b, 0x25, 0xbe, 0xa4}; + +static BYTE crypt_message_client2[] = + {0x20, 0x6c, 0x01, 0xab, 0xb0, 0x4c, 0x93, 0xe4, 0x1e, 0xfc, + 0xe1, 0xfa, 0xfe}; + static BYTE crypt_trailer_server[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x46, 0x2e, 0x77, 0xeb, 0xf0, 0xf6, 0x9e}; @@ -674,7 +684,7 @@ static void testSignSeal() SEC_WINNT_AUTH_IDENTITY id; static char sec_pkg_name[] = "NTLM"; SecBufferDesc crypt; - SecBuffer data[2], fake_data[2]; + SecBuffer data[2], fake_data[2], complex_data[4]; ULONG qop = 0; SecPkgContext_Sizes ctxt_sizes; @@ -807,6 +817,45 @@ static void testSignSeal() crypt.pBuffers[1].cbBuffer), "Failed to decrypt message correctly.\n"); + trace("Testing with more than one buffer.\n"); + + crypt.cBuffers = sizeof(complex_data)/sizeof(complex_data[0]); + crypt.pBuffers = complex_data; + + complex_data[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + complex_data[0].cbBuffer = sizeof(message_header); + complex_data[0].pvBuffer = message_header; + + complex_data[1].BufferType = SECBUFFER_DATA; + complex_data[1].cbBuffer = lstrlen(message); + complex_data[1].pvBuffer = HeapAlloc(GetProcessHeap(), 0, data[1].cbBuffer); + memcpy(complex_data[1].pvBuffer, message, complex_data[1].cbBuffer); + + complex_data[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + complex_data[2].cbBuffer = sizeof(message_header); + complex_data[2].pvBuffer = message_header; + + complex_data[3].BufferType = SECBUFFER_TOKEN; + complex_data[3].cbBuffer = ctxt_sizes.cbSecurityTrailer; + complex_data[3].pvBuffer = HeapAlloc(GetProcessHeap(), 0, complex_data[3].cbBuffer); + + /* We should get a dummy signature again. */ + sec_status = pMakeSignature(client.ctxt, 0, &crypt, 0); + ok(sec_status == SEC_E_OK, "MakeSignature returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + ok(!memcmp(crypt.pBuffers[3].pvBuffer, message_signature, + crypt.pBuffers[3].cbBuffer), "Signature is not as expected.\n"); + + sec_status = pEncryptMessage(client.ctxt, 0, &crypt, 0); + ok(sec_status == SEC_E_OK, "EncryptMessage returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + + ok(!memcmp(crypt.pBuffers[3].pvBuffer, crypt_trailer_client2, + crypt.pBuffers[3].cbBuffer), "Crypt trailer not as expected.\n"); + + ok(!memcmp(crypt.pBuffers[1].pvBuffer, crypt_message_client2, + crypt.pBuffers[1].cbBuffer), "Crypt message not as expected.\n"); + end: cleanupBuffers(&client); cleanupBuffers(&server); diff --git a/dlls/secur32/util.c b/dlls/secur32/util.c index 4462ae9f221..d9277f1baef 100644 --- a/dlls/secur32/util.c +++ b/dlls/secur32/util.c @@ -93,9 +93,9 @@ 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 ); -ULONG ComputeCrc32(const BYTE *pData, INT iLen) +ULONG ComputeCrc32(const BYTE *pData, INT iLen, ULONG initial_crc) { - ULONG crc = ~0U; + ULONG crc = ~initial_crc; while (iLen > 0) {