From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@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