From: Hans Leidekker Subject: [PATCH 1/1] secur32: Return a SECBUFFER_MISSING buffer from the handshake if the input message is incomplete. Message-Id: Date: Wed, 29 Jun 2022 12:56:00 +0000 In-Reply-To: References: From: Hans Leidekker --- dlls/secur32/schannel.c | 25 +++++++++++++++++++++++-- dlls/secur32/tests/schannel.c | 21 ++++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 7dc9bd1d21a..70018e57f7e 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -747,6 +747,18 @@ static inline BOOL is_dtls_context(const struct schan_context *ctx) return ctx->header_size == HEADER_SIZE_DTLS; } +static void fill_missing_sec_buffer(SecBufferDesc *input, DWORD size) +{ + int idx = schan_find_sec_buffer_idx(input, 0, SECBUFFER_EMPTY); + if (idx == -1) WARN("no empty buffer\n"); + else + { + SecBuffer *buffer = &input->pBuffers[idx]; + buffer->BufferType = SECBUFFER_MISSING; + buffer->cbBuffer = size; + } +} + /*********************************************************************** * InitializeSecurityContextW */ @@ -887,7 +899,15 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( buffer = &pInput->pBuffers[idx]; ptr = buffer->pvBuffer; - while (buffer->cbBuffer > expected_size + ctx->header_size) + if (buffer->cbBuffer < ctx->header_size) + { + TRACE("Expected at least %Iu bytes, but buffer only contains %lu bytes.\n", + ctx->header_size, buffer->cbBuffer); + fill_missing_sec_buffer(pInput, ctx->header_size - buffer->cbBuffer); + return SEC_E_INCOMPLETE_MESSAGE; + } + + while (buffer->cbBuffer >= expected_size + ctx->header_size) { record_size = ctx->header_size + read_record_size(ptr, ctx->header_size); @@ -899,7 +919,8 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( if (!expected_size) { TRACE("Expected at least %Iu bytes, but buffer only contains %lu bytes.\n", - max(ctx->header_size + 1, record_size), buffer->cbBuffer); + max(ctx->header_size, record_size), buffer->cbBuffer); + fill_missing_sec_buffer(pInput, record_size - buffer->cbBuffer); return SEC_E_INCOMPLETE_MESSAGE; } diff --git a/dlls/secur32/tests/schannel.c b/dlls/secur32/tests/schannel.c index c68474e9eae..8322b5a80a5 100644 --- a/dlls/secur32/tests/schannel.c +++ b/dlls/secur32/tests/schannel.c @@ -1132,8 +1132,10 @@ static void test_communication(void) ok( context2.dwLower == 0xdeadbeef, "Did not expect dwLower to be set on new context\n"); ok( context2.dwUpper == 0xdeadbeef, "Did not expect dwUpper to be set on new context\n"); - buffers[1].cBuffers = 1; + buffers[1].cBuffers = 2; buffers[1].pBuffers[0].cbBuffer = 0; + buffers[1].pBuffers[1].cbBuffer = 0; + buffers[1].pBuffers[1].BufferType = SECBUFFER_EMPTY; status = InitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost", ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM, @@ -1141,6 +1143,10 @@ static void test_communication(void) ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#lx.\n", status); ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n"); ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n"); + ok(buffers[1].pBuffers[1].cbBuffer == 5 || + broken(buffers[1].pBuffers[1].cbBuffer == 0), /* < win10 */ "Wrong buffer size.\n"); + ok(buffers[1].pBuffers[1].BufferType == SECBUFFER_MISSING || + broken(buffers[1].pBuffers[1].BufferType == SECBUFFER_EMPTY), /* < win10 */ "Wrong buffer type.\n"); buf = &buffers[1].pBuffers[0]; buf->cbBuffer = buf_size; @@ -1149,6 +1155,8 @@ static void test_communication(void) return; buffers[1].pBuffers[0].cbBuffer = 4; + buffers[1].pBuffers[1].cbBuffer = 0; + buffers[1].pBuffers[1].BufferType = SECBUFFER_EMPTY; status = InitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost", ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM, 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL); @@ -1156,9 +1164,15 @@ static void test_communication(void) "Got unexpected status %#lx.\n", status); ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n"); ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n"); + ok(buffers[1].pBuffers[1].cbBuffer == 1 || + broken(buffers[1].pBuffers[1].cbBuffer == 0), /* < win10 */ "Wrong buffer size.\n"); + ok(buffers[1].pBuffers[1].BufferType == SECBUFFER_MISSING || + broken(buffers[1].pBuffers[1].BufferType == SECBUFFER_EMPTY), /* < win10 */ "Wrong buffer type.\n"); context2.dwLower = context2.dwUpper = 0xdeadbeef; buffers[1].pBuffers[0].cbBuffer = 5; + buffers[1].pBuffers[1].cbBuffer = 0; + buffers[1].pBuffers[1].BufferType = SECBUFFER_EMPTY; status = InitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost", ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM, 0, 0, &buffers[1], 0, &context2, &buffers[0], &attrs, NULL); @@ -1166,9 +1180,14 @@ static void test_communication(void) "Got unexpected status %#lx.\n", status); ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n"); ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n"); + ok(buffers[1].pBuffers[1].cbBuffer > 5 || + broken(buffers[1].pBuffers[1].cbBuffer == 0), /* < win10 */ "Wrong buffer size\n" ); + ok(buffers[1].pBuffers[1].BufferType == SECBUFFER_MISSING || + broken(buffers[1].pBuffers[1].BufferType == SECBUFFER_EMPTY), /* < win10 */ "Wrong buffer type.\n"); ok( context2.dwLower == 0xdeadbeef, "Did not expect dwLower to be set on new context\n"); ok( context2.dwUpper == 0xdeadbeef, "Did not expect dwUpper to be set on new context\n"); + buffers[1].cBuffers = 1; buffers[1].pBuffers[0].cbBuffer = ret; status = InitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost", ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM|ISC_REQ_USE_SUPPLIED_CREDS, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/342