[PATCH v2 02/12] secur32: Manage gnutls transport data in unixlib.
Nikolay Sivov
wine at gitlab.winehq.org
Thu Jun 2 06:45:42 CDT 2022
From: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/secur32/schannel.c | 66 +++++++++++++-------------
dlls/secur32/schannel_gnutls.c | 86 ++++++++++++++++++++++++----------
dlls/secur32/secur32_priv.h | 21 ++-------
3 files changed, 97 insertions(+), 76 deletions(-)
diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 30c86c724b4..3242aebebbe 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -61,7 +61,7 @@ struct schan_handle
struct schan_context
{
- struct schan_transport transport;
+ schan_session session;
ULONG req_ctx_attr;
const CERT_CONTEXT *cert;
SIZE_T header_size;
@@ -758,14 +758,15 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
{
const ULONG extra_size = 0x10000;
struct schan_context *ctx;
- struct schan_buffers *out_buffers;
struct schan_credentials *cred;
SIZE_T expected_size = 0;
SECURITY_STATUS ret;
SecBuffer *buffer;
SecBuffer alloc_buffer = { 0 };
- struct handshake_params params;
+ struct handshake_params params = { 0 };
+ int output_buffer_idx = -1;
int idx, i;
+ ULONG input_offset = 0, output_offset = 0;
TRACE("%p %p %s 0x%08lx %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
@@ -815,9 +816,8 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
return SEC_E_INTERNAL_ERROR;
}
- create_params.transport = &ctx->transport;
create_params.cred = cred;
- create_params.session = &ctx->transport.session;
+ create_params.session = &ctx->session;
if (GNUTLS_CALL( create_session, &create_params ))
{
schan_free_handle(handle, SCHAN_HANDLE_CTX);
@@ -837,7 +837,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
if (target)
{
- struct set_session_target_params params = { ctx->transport.session, target };
+ struct set_session_target_params params = { ctx->session, target };
WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL );
GNUTLS_CALL( set_session_target, ¶ms );
free( target );
@@ -846,8 +846,8 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_APPLICATION_PROTOCOLS)) != -1)
{
- struct set_application_protocols_params params = { ctx->transport.session,
- pInput->pBuffers[idx].pvBuffer, pInput->pBuffers[idx].cbBuffer };
+ struct set_application_protocols_params params = { ctx->session, pInput->pBuffers[idx].pvBuffer,
+ pInput->pBuffers[idx].cbBuffer };
GNUTLS_CALL( set_application_protocols, ¶ms );
}
@@ -856,7 +856,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
buffer = &pInput->pBuffers[idx];
if (buffer->cbBuffer >= sizeof(WORD))
{
- struct set_dtls_mtu_params params = { ctx->transport.session, *(WORD *)buffer->pvBuffer };
+ struct set_dtls_mtu_params params = { ctx->session, *(WORD *)buffer->pvBuffer };
GNUTLS_CALL( set_dtls_mtu, ¶ms );
}
else WARN("invalid buffer size %lu\n", buffer->cbBuffer);
@@ -864,7 +864,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
if (is_dtls_context(ctx))
{
- struct set_dtls_timeouts_params params = { ctx->transport.session, 0, 60000 };
+ struct set_dtls_timeouts_params params = { ctx->session, 0, 60000 };
GNUTLS_CALL( set_dtls_timeouts, ¶ms );
}
@@ -917,18 +917,20 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
alloc_buffer.BufferType = SECBUFFER_TOKEN;
alloc_buffer.pvBuffer = RtlAllocateHeap( GetProcessHeap(), 0, extra_size );
}
- params.session = ctx->transport.session;
+ params.session = ctx->session;
params.input = pInput;
params.input_size = expected_size;
params.output = pOutput;
params.alloc_buffer = &alloc_buffer;
+ params.input_offset = &input_offset;
+ params.output_buffer_idx = &output_buffer_idx;
+ params.output_offset = &output_offset;
ret = GNUTLS_CALL( handshake, ¶ms );
- out_buffers = &ctx->transport.out;
- if (out_buffers->current_buffer_idx != -1)
+ if (output_buffer_idx != -1)
{
- SecBuffer *buffer = &out_buffers->desc->pBuffers[out_buffers->current_buffer_idx];
- buffer->cbBuffer = out_buffers->offset;
+ SecBuffer *buffer = &pOutput->pBuffers[output_buffer_idx];
+ buffer->cbBuffer = output_offset;
if (buffer->pvBuffer == alloc_buffer.pvBuffer)
{
RtlReAllocateHeap( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
@@ -936,19 +938,19 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
alloc_buffer.pvBuffer = NULL;
}
}
- else if (out_buffers->desc && out_buffers->desc->cBuffers > 0)
+ else if (pOutput && pOutput->cBuffers)
{
- SecBuffer *buffer = &out_buffers->desc->pBuffers[0];
- buffer->cbBuffer = 0;
+ pOutput->pBuffers[0].cbBuffer = 0;
}
RtlFreeHeap( GetProcessHeap(), 0, alloc_buffer.pvBuffer );
- if(ctx->transport.in.offset && ctx->transport.in.offset != pInput->pBuffers[0].cbBuffer) {
+ if (input_offset && input_offset != pInput->pBuffers[0].cbBuffer)
+ {
if(pInput->cBuffers<2 || pInput->pBuffers[1].BufferType!=SECBUFFER_EMPTY)
return SEC_E_INVALID_TOKEN;
pInput->pBuffers[1].BufferType = SECBUFFER_EXTRA;
- pInput->pBuffers[1].cbBuffer = pInput->pBuffers[0].cbBuffer-ctx->transport.in.offset;
+ pInput->pBuffers[1].cbBuffer = pInput->pBuffers[0].cbBuffer - input_offset;
}
for (i = 0; i < pOutput->cBuffers; i++)
@@ -1031,7 +1033,7 @@ static SECURITY_STATUS ensure_remote_cert(struct schan_context *ctx)
PCCERT_CONTEXT cert = NULL;
SECURITY_STATUS status;
ULONG count, size = 0;
- struct get_session_peer_certificate_params params = { ctx->transport.session, NULL, &size, &count };
+ struct get_session_peer_certificate_params params = { ctx->session, NULL, &size, &count };
if (ctx->cert) return SEC_E_OK;
if (!(store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL)))
@@ -1089,11 +1091,11 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_STREAM_SIZES:
{
SecPkgContext_ConnectionInfo info;
- struct get_connection_info_params params = { ctx->transport.session, &info };
+ struct get_connection_info_params params = { ctx->session, &info };
status = GNUTLS_CALL( get_connection_info, ¶ms );
if (status == SEC_E_OK)
{
- struct session_params params = { ctx->transport.session };
+ struct session_params params = { ctx->session };
SecPkgContext_StreamSizes *stream_sizes = buffer;
SIZE_T mac_size = info.dwHashStrength;
unsigned int block_size = GNUTLS_CALL( get_session_cipher_block_size, ¶ms );
@@ -1115,11 +1117,11 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_KEY_INFO:
{
SecPkgContext_ConnectionInfo conn_info;
- struct get_connection_info_params params = { ctx->transport.session, &conn_info };
+ struct get_connection_info_params params = { ctx->session, &conn_info };
status = GNUTLS_CALL( get_connection_info, ¶ms );
if (status == SEC_E_OK)
{
- struct session_params params = { ctx->transport.session };
+ struct session_params params = { ctx->session };
SecPkgContext_KeyInfoW *info = buffer;
info->KeySize = conn_info.dwCipherStrength;
info->SignatureAlgorithm = GNUTLS_CALL( get_key_signature_algorithm, ¶ms );
@@ -1143,7 +1145,7 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_CONNECTION_INFO:
{
SecPkgContext_ConnectionInfo *info = buffer;
- struct get_connection_info_params params = { ctx->transport.session, info };
+ struct get_connection_info_params params = { ctx->session, info };
return GNUTLS_CALL( get_connection_info, ¶ms );
}
case SECPKG_ATTR_ENDPOINT_BINDINGS:
@@ -1193,7 +1195,7 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
SecPkgContext_Bindings *bindings = buffer;
ULONG size;
char *p;
- struct get_unique_channel_binding_params params = { ctx->transport.session, NULL, &size };
+ struct get_unique_channel_binding_params params = { ctx->session, NULL, &size };
if (GNUTLS_CALL( get_unique_channel_binding, ¶ms ) != SEC_E_BUFFER_TOO_SMALL)
return SEC_E_INTERNAL_ERROR;
@@ -1216,7 +1218,7 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_APPLICATION_PROTOCOL:
{
SecPkgContext_ApplicationProtocol *protocol = buffer;
- struct get_application_protocol_params params = { ctx->transport.session, protocol };
+ struct get_application_protocol_params params = { ctx->session, protocol };
return GNUTLS_CALL( get_application_protocol, ¶ms );
}
@@ -1297,7 +1299,7 @@ static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle
memcpy(data, buffer->pvBuffer, data_size);
length = data_size;
- params.session = ctx->transport.session;
+ params.session = ctx->session;
params.output = message;
params.buffer = data;
params.length = &length;
@@ -1421,7 +1423,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
received = data_size;
- params.session = ctx->transport.session;
+ params.session = ctx->session;
params.input = message;
params.input_size = expected_size;
params.buffer = data;
@@ -1469,7 +1471,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context
if (!ctx) return SEC_E_INVALID_HANDLE;
if (ctx->cert) CertFreeCertificateContext(ctx->cert);
- params.session = ctx->transport.session;
+ params.session = ctx->session;
GNUTLS_CALL( dispose_session, ¶ms );
free(ctx);
return SEC_E_OK;
@@ -1610,7 +1612,7 @@ void SECUR32_deinitSchannelSP(void)
if (schan_handle_table[i].type == SCHAN_HANDLE_CTX)
{
struct schan_context *ctx = schan_free_handle(i, SCHAN_HANDLE_CTX);
- struct session_params params = { ctx->transport.session };
+ struct session_params params = { ctx->session };
GNUTLS_CALL( dispose_session, ¶ms );
free(ctx);
}
diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c
index a79ca7040a5..098ca239598 100644
--- a/dlls/secur32/schannel_gnutls.c
+++ b/dlls/secur32/schannel_gnutls.c
@@ -141,6 +141,23 @@ static inline gnutls_session_t session_from_handle(UINT64 handle)
return (gnutls_session_t)(ULONG_PTR)handle;
}
+struct schan_buffers
+{
+ SIZE_T offset;
+ SIZE_T limit;
+ const SecBufferDesc *desc;
+ SecBuffer *alloc_buffer;
+ int current_buffer_idx;
+ int (*get_next_buffer)(struct schan_buffers *);
+};
+
+struct schan_transport
+{
+ gnutls_session_t session;
+ struct schan_buffers in;
+ struct schan_buffers out;
+};
+
static int compat_cipher_get_block_size(gnutls_cipher_algorithm_t cipher)
{
switch(cipher) {
@@ -374,7 +391,6 @@ static char *get_buffer(struct schan_buffers *s, SIZE_T *count)
static ssize_t pull_adapter(gnutls_transport_ptr_t transport, void *buff, size_t buff_len)
{
struct schan_transport *t = (struct schan_transport*)transport;
- gnutls_session_t s = session_from_handle(t->session);
SIZE_T len = buff_len;
char *b;
@@ -383,7 +399,7 @@ static ssize_t pull_adapter(gnutls_transport_ptr_t transport, void *buff, size_t
b = get_buffer(&t->in, &len);
if (!b)
{
- pgnutls_transport_set_errno(s, EAGAIN);
+ pgnutls_transport_set_errno(t->session, EAGAIN);
return -1;
}
memcpy(buff, b, len);
@@ -395,7 +411,6 @@ static ssize_t pull_adapter(gnutls_transport_ptr_t transport, void *buff, size_t
static ssize_t push_adapter(gnutls_transport_ptr_t transport, const void *buff, size_t buff_len)
{
struct schan_transport *t = (struct schan_transport*)transport;
- gnutls_session_t s = session_from_handle(t->session);
SIZE_T len = buff_len;
char *b;
@@ -404,7 +419,7 @@ static ssize_t push_adapter(gnutls_transport_ptr_t transport, const void *buff,
b = get_buffer(&t->out, &len);
if (!b)
{
- pgnutls_transport_set_errno(s, EAGAIN);
+ pgnutls_transport_set_errno(t->session, EAGAIN);
return -1;
}
memcpy(b, buff, len);
@@ -483,6 +498,7 @@ static NTSTATUS schan_create_session( void *args )
char priority[128] = "NORMAL:%LATEST_RECORD_VERSION", *p;
BOOL using_vers_all = FALSE, disabled;
unsigned int i, flags = (cred->credential_use == SECPKG_CRED_INBOUND) ? GNUTLS_SERVER : GNUTLS_CLIENT;
+ struct schan_transport *transport;
gnutls_session_t s;
int err;
@@ -500,6 +516,13 @@ static NTSTATUS schan_create_session( void *args )
return STATUS_INTERNAL_ERROR;
}
+ if (!(transport = calloc(1, sizeof(*transport))))
+ {
+ pgnutls_deinit(s);
+ return STATUS_INTERNAL_ERROR;
+ }
+ transport->session = s;
+
p = priority + strlen(priority);
/* VERS-ALL is nice to use for forward compatibility. It was introduced before support for TLS1.3,
@@ -531,6 +554,7 @@ static NTSTATUS schan_create_session( void *args )
{
pgnutls_perror(err);
pgnutls_deinit(s);
+ free(transport);
return STATUS_INTERNAL_ERROR;
}
@@ -540,13 +564,14 @@ static NTSTATUS schan_create_session( void *args )
{
pgnutls_perror(err);
pgnutls_deinit(s);
+ free(transport);
return STATUS_INTERNAL_ERROR;
}
pgnutls_transport_set_pull_function(s, pull_adapter);
if (flags & GNUTLS_DATAGRAM) pgnutls_transport_set_pull_timeout_function(s, pull_timeout);
pgnutls_transport_set_push_function(s, push_adapter);
- pgnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)params->transport);
+ pgnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)transport);
*params->session = (ULONG_PTR)s;
return STATUS_SUCCESS;
@@ -556,7 +581,10 @@ static NTSTATUS schan_dispose_session( void *args )
{
const struct session_params *params = args;
gnutls_session_t s = session_from_handle(params->session);
+ struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
+ pgnutls_transport_set_ptr(s, NULL);
pgnutls_deinit(s);
+ free(t);
return STATUS_SUCCESS;
}
@@ -573,6 +601,7 @@ static NTSTATUS schan_handshake( void *args )
const struct handshake_params *params = args;
gnutls_session_t s = session_from_handle(params->session);
struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
+ NTSTATUS status;
int err;
init_schan_buffers(&t->in, params->input, handshake_get_next_buffer);
@@ -580,47 +609,52 @@ static NTSTATUS schan_handshake( void *args )
init_schan_buffers(&t->out, params->output, handshake_get_next_buffer_alloc );
t->out.alloc_buffer = params->alloc_buffer;
- while(1) {
+ while (1)
+ {
err = pgnutls_handshake(s);
- switch(err) {
- case GNUTLS_E_SUCCESS:
+ if (err == GNUTLS_E_SUCCESS)
+ {
TRACE("Handshake completed\n");
- return SEC_E_OK;
-
- case GNUTLS_E_AGAIN:
+ status = SEC_E_OK;
+ }
+ else if (err == GNUTLS_E_AGAIN)
+ {
TRACE("Continue...\n");
- return SEC_I_CONTINUE_NEEDED;
-
- case GNUTLS_E_WARNING_ALERT_RECEIVED:
+ status = SEC_I_CONTINUE_NEEDED;
+ }
+ else if (err == GNUTLS_E_WARNING_ALERT_RECEIVED)
{
gnutls_alert_description_t alert = pgnutls_alert_get(s);
WARN("WARNING ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert));
- switch(alert) {
- case GNUTLS_A_UNRECOGNIZED_NAME:
+ if (alert == GNUTLS_A_UNRECOGNIZED_NAME)
+ {
TRACE("Ignoring\n");
continue;
- default:
- return SEC_E_INTERNAL_ERROR;
}
+ else
+ status = SEC_E_INTERNAL_ERROR;
}
-
- case GNUTLS_E_FATAL_ALERT_RECEIVED:
+ else if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
{
gnutls_alert_description_t alert = pgnutls_alert_get(s);
WARN("FATAL ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert));
- return SEC_E_INTERNAL_ERROR;
+ status = SEC_E_INTERNAL_ERROR;
}
-
- default:
+ else
+ {
pgnutls_perror(err);
- return SEC_E_INTERNAL_ERROR;
+ status = SEC_E_INTERNAL_ERROR;
}
+ break;
}
- /* Never reached */
- return SEC_E_OK;
+ *params->input_offset = t->in.offset;
+ *params->output_buffer_idx = t->out.current_buffer_idx;
+ *params->output_offset = t->out.offset;
+
+ return status;
}
static DWORD get_protocol(gnutls_protocol_t proto)
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index fcc007f77ef..8a59458e875 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -88,23 +88,6 @@ typedef struct schan_credentials
DWORD enabled_protocols;
} schan_credentials;
-struct schan_buffers
-{
- SIZE_T offset;
- SIZE_T limit;
- const SecBufferDesc *desc;
- SecBuffer *alloc_buffer;
- int current_buffer_idx;
- int (*get_next_buffer)(struct schan_buffers *);
-};
-
-struct schan_transport
-{
- schan_session session;
- struct schan_buffers in;
- struct schan_buffers out;
-};
-
struct session_params
{
schan_session session;
@@ -122,7 +105,6 @@ struct allocate_certificate_credentials_params
struct create_session_params
{
- struct schan_transport *transport;
schan_credentials *cred;
schan_session *session;
};
@@ -166,6 +148,9 @@ struct handshake_params
SIZE_T input_size;
SecBufferDesc *output;
SecBuffer *alloc_buffer;
+ ULONG *input_offset;
+ int *output_buffer_idx;
+ ULONG *output_offset;
};
struct recv_params
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/160
More information about the wine-devel
mailing list