[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, &params );
                 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, &params );
         }
 
@@ -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, &params );
             }
             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, &params );
         }
 
@@ -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, &params );
 
-    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, &params );
             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, &params );
@@ -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, &params );
             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, &params );
@@ -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, &params );
         }
         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, &params ) != 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, &params );
         }
 
@@ -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, &params );
     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, &params );
             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