Henri Verbeet : secur32: Implement schannel EncryptMessage().

Alexandre Julliard julliard at winehq.org
Mon Dec 29 08:47:44 CST 2008


Module: wine
Branch: master
Commit: 3954c4ec659a04dbb17591b5e901815ef2eef0c4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=3954c4ec659a04dbb17591b5e901815ef2eef0c4

Author: Henri Verbeet <hverbeet at gmail.com>
Date:   Sun Dec 28 22:21:35 2008 +0100

secur32: Implement schannel EncryptMessage().

---

 dlls/secur32/schannel.c |  118 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index ed583d4..9f5a285 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -61,6 +61,7 @@ MAKE_FUNCPTR(gnutls_mac_get);
 MAKE_FUNCPTR(gnutls_mac_get_key_size);
 MAKE_FUNCPTR(gnutls_perror);
 MAKE_FUNCPTR(gnutls_set_default_priority);
+MAKE_FUNCPTR(gnutls_record_send);
 MAKE_FUNCPTR(gnutls_transport_set_errno);
 MAKE_FUNCPTR(gnutls_transport_set_ptr);
 MAKE_FUNCPTR(gnutls_transport_set_pull_function);
@@ -889,6 +890,118 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA(
     }
 }
 
+static int schan_encrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s)
+{
+    SecBuffer *b;
+
+    if (s->current_buffer_idx == -1)
+        return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_HEADER);
+
+    b = &s->desc->pBuffers[s->current_buffer_idx];
+
+    if (b->BufferType == SECBUFFER_STREAM_HEADER)
+        return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
+
+    if (b->BufferType == SECBUFFER_DATA)
+        return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_TRAILER);
+
+    return -1;
+}
+
+static int schan_encrypt_message_get_next_buffer_token(const struct schan_transport *t, struct schan_buffers *s)
+{
+    SecBuffer *b;
+
+    if (s->current_buffer_idx == -1)
+        return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
+
+    b = &s->desc->pBuffers[s->current_buffer_idx];
+
+    if (b->BufferType == SECBUFFER_TOKEN)
+    {
+        int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
+        if (idx != s->current_buffer_idx) return -1;
+        return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
+    }
+
+    if (b->BufferType == SECBUFFER_DATA)
+    {
+        int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
+        if (idx != -1)
+            idx = schan_find_sec_buffer_idx(s->desc, idx + 1, SECBUFFER_TOKEN);
+        return idx;
+    }
+
+    return -1;
+}
+
+static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle,
+        ULONG quality, PSecBufferDesc message, ULONG message_seq_no)
+{
+    struct schan_transport transport;
+    struct schan_context *ctx;
+    struct schan_buffers *b;
+    SecBuffer *buffer;
+    SIZE_T data_size;
+    char *data;
+    ssize_t sent = 0;
+    ssize_t ret;
+    int idx;
+
+    TRACE("context_handle %p, quality %d, message %p, message_seq_no %d\n",
+            context_handle, quality, message, message_seq_no);
+
+    if (!context_handle) return SEC_E_INVALID_HANDLE;
+    ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
+
+    dump_buffer_desc(message);
+
+    idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_DATA);
+    if (idx == -1)
+    {
+        WARN("No data buffer passed\n");
+        return SEC_E_INTERNAL_ERROR;
+    }
+    buffer = &message->pBuffers[idx];
+
+    data_size = buffer->cbBuffer;
+    data = HeapAlloc(GetProcessHeap(), 0, data_size);
+    memcpy(data, buffer->pvBuffer, data_size);
+
+    transport.ctx = ctx;
+    init_schan_buffers(&transport.in, NULL, NULL);
+    if (schan_find_sec_buffer_idx(message, 0, SECBUFFER_STREAM_HEADER) != -1)
+        init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer);
+    else
+        init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer_token);
+    pgnutls_transport_set_ptr(ctx->session, &transport);
+
+    while (sent < data_size)
+    {
+        ret = pgnutls_record_send(ctx->session, data + sent, data_size - sent);
+        if (ret < 0)
+        {
+            if (ret != GNUTLS_E_AGAIN)
+            {
+                pgnutls_perror(ret);
+                HeapFree(GetProcessHeap(), 0, data);
+                ERR("Returning SEC_E_INTERNAL_ERROR\n");
+                return SEC_E_INTERNAL_ERROR;
+            }
+            else break;
+        }
+        sent += ret;
+    }
+
+    TRACE("Sent %zd bytes\n", sent);
+
+    b = &transport.out;
+    b->desc->pBuffers[b->current_buffer_idx].cbBuffer = b->offset;
+    HeapFree(GetProcessHeap(), 0, data);
+
+    return SEC_E_OK;
+}
+
 static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context_handle)
 {
     struct schan_context *ctx;
@@ -937,7 +1050,7 @@ static const SecurityFunctionTableA schanTableA = {
     NULL, /* AddCredentialsA */
     NULL, /* Reserved8 */
     NULL, /* QuerySecurityContextToken */
-    NULL, /* EncryptMessage */
+    schan_EncryptMessage,
     NULL, /* DecryptMessage */
     NULL, /* SetContextAttributesA */
 };
@@ -968,7 +1081,7 @@ static const SecurityFunctionTableW schanTableW = {
     NULL, /* AddCredentialsW */
     NULL, /* Reserved8 */
     NULL, /* QuerySecurityContextToken */
-    NULL, /* EncryptMessage */
+    schan_EncryptMessage,
     NULL, /* DecryptMessage */
     NULL, /* SetContextAttributesW */
 };
@@ -1035,6 +1148,7 @@ void SECUR32_initSchannelSP(void)
     LOAD_FUNCPTR(gnutls_mac_get_key_size)
     LOAD_FUNCPTR(gnutls_perror)
     LOAD_FUNCPTR(gnutls_set_default_priority)
+    LOAD_FUNCPTR(gnutls_record_send);
     LOAD_FUNCPTR(gnutls_transport_set_errno)
     LOAD_FUNCPTR(gnutls_transport_set_ptr)
     LOAD_FUNCPTR(gnutls_transport_set_pull_function)




More information about the wine-cvs mailing list