[PATCH 4/6] msv1_0: Implement SpMakeSignature.

Hans Leidekker hans at codeweavers.com
Fri Apr 30 04:59:37 CDT 2021


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/msv1_0/main.c | 199 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 198 insertions(+), 1 deletion(-)

diff --git a/dlls/msv1_0/main.c b/dlls/msv1_0/main.c
index e039b68c920..d9b9d16fa64 100644
--- a/dlls/msv1_0/main.c
+++ b/dlls/msv1_0/main.c
@@ -523,6 +523,26 @@ static void arc4_init( struct arc4_info *info, const char *key, unsigned int len
     }
 }
 
+static void arc4_process( struct arc4_info *info, char *buf, unsigned int len )
+{
+    char *state = info->state;
+    unsigned int x = info->x, y = info->y, a, b;
+
+    while (len--)
+    {
+        x = (x + 1) & 0xff;
+        a = state[x];
+        y = (y + a) & 0xff;
+        b = state[y];
+        state[x] = b;
+        state[y] = a;
+        *buf++ ^= state[(a + b) & 0xff];
+    }
+
+    info->x = x;
+    info->y = y;
+}
+
 static int get_buffer_index( SecBufferDesc *desc, ULONG type )
 {
     int idx;
@@ -1178,11 +1198,188 @@ static NTSTATUS NTAPI ntlm_SpInstanceInit( ULONG version, SECPKG_DLL_FUNCTIONS *
     return STATUS_SUCCESS;
 }
 
+struct hmac_md5_ctx
+{
+    struct md5_ctx ctx;
+    char outer_padding[64];
+};
+
+static void hmac_md5_init( struct hmac_md5_ctx *ctx, const char *key, unsigned int key_len )
+{
+    char inner_padding[64], tmp_key[16];
+    unsigned int i;
+
+    if (key_len > 64)
+    {
+        struct md5_ctx tmp_ctx;
+
+        MD5Init( &tmp_ctx );
+        MD5Update( &tmp_ctx, key, key_len );
+        MD5Final( &tmp_ctx );
+        memcpy( tmp_key, tmp_ctx.digest, 16 );
+
+        key = tmp_key;
+        key_len = 16;
+    }
+
+    memset( inner_padding, 0, 64 );
+    memset( ctx->outer_padding, 0, 64 );
+    memcpy( inner_padding, key, key_len );
+    memcpy( ctx->outer_padding, key, key_len );
+
+    for (i = 0; i < 64; i++)
+    {
+        inner_padding[i] ^= 0x36;
+        ctx->outer_padding[i] ^= 0x5c;
+    }
+
+    MD5Init( &ctx->ctx );
+    MD5Update( &ctx->ctx, inner_padding, 64 );
+}
+
+static void hmac_md5_update( struct hmac_md5_ctx *ctx, const char *buf, unsigned int len )
+{
+    MD5Update( &ctx->ctx, buf, len );
+}
+
+static void hmac_md5_final( struct hmac_md5_ctx *ctx, char *digest )
+{
+    struct md5_ctx outer_ctx;
+    char inner_digest[16];
+
+    MD5Final( &ctx->ctx );
+    memcpy( inner_digest, ctx->ctx.digest, 16 );
+
+    MD5Init( &outer_ctx );
+    MD5Update( &outer_ctx, ctx->outer_padding, 64 );
+    MD5Update( &outer_ctx, inner_digest, 16 );
+    MD5Final( &outer_ctx );
+
+    memcpy( digest, outer_ctx.digest, 16 );
+}
+
+static SECURITY_STATUS create_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx,
+                                         enum sign_direction dir, BOOL encrypt )
+{
+    unsigned int i, sign_version = 1;
+    char *sig = msg->pBuffers[idx].pvBuffer;
+
+    if (flags & FLAG_NEGOTIATE_NTLM2 && flags & FLAG_NEGOTIATE_SIGN)
+    {
+        char digest[16], seq_no[4];
+        struct hmac_md5_ctx hmac_md5;
+
+        if (dir == SIGN_SEND)
+        {
+            seq_no[0] = (ctx->crypt.ntlm2.send_seq_no >>  0) & 0xff;
+            seq_no[1] = (ctx->crypt.ntlm2.send_seq_no >>  8) & 0xff;
+            seq_no[2] = (ctx->crypt.ntlm2.send_seq_no >> 16) & 0xff;
+            seq_no[3] = (ctx->crypt.ntlm2.send_seq_no >> 24) & 0xff;
+            ctx->crypt.ntlm2.send_seq_no++;
+
+            hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.send_sign_key, 16 );
+        }
+        else
+        {
+            seq_no[0] = (ctx->crypt.ntlm2.recv_seq_no >>  0) & 0xff;
+            seq_no[1] = (ctx->crypt.ntlm2.recv_seq_no >>  8) & 0xff;
+            seq_no[2] = (ctx->crypt.ntlm2.recv_seq_no >> 16) & 0xff;
+            seq_no[3] = (ctx->crypt.ntlm2.recv_seq_no >> 24) & 0xff;
+            ctx->crypt.ntlm2.recv_seq_no++;
+
+            hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.recv_sign_key, 16 );
+        }
+
+        hmac_md5_update( &hmac_md5, seq_no, 4 );
+        for (i = 0; i < msg->cBuffers; ++i)
+        {
+            if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
+                hmac_md5_update( &hmac_md5, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
+        }
+        hmac_md5_final( &hmac_md5, digest );
+
+        if (encrypt && flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
+        {
+            if (dir == SIGN_SEND)
+                arc4_process( &ctx->crypt.ntlm2.send_arc4info, digest, 8 );
+            else
+                arc4_process( &ctx->crypt.ntlm2.recv_arc4info, digest, 8 );
+        }
+
+        sig[0] = (sign_version >>  0) & 0xff;
+        sig[1] = (sign_version >>  8) & 0xff;
+        sig[2] = (sign_version >> 16) & 0xff;
+        sig[3] = (sign_version >> 24) & 0xff;
+        memcpy( sig + 4, digest, 8 );
+        memcpy( sig + 12, seq_no, 4 );
+
+        msg->pBuffers[idx].cbBuffer = 16;
+        return SEC_E_OK;
+    }
+
+    if (flags & FLAG_NEGOTIATE_SIGN)
+    {
+        unsigned int crc = 0;
+
+        for (i = 0; i < msg->cBuffers; ++i)
+        {
+            if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
+                crc = RtlComputeCrc32( crc, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
+        }
+
+        sig[0] = (sign_version >>  0) & 0xff;
+        sig[1] = (sign_version >>  8) & 0xff;
+        sig[2] = (sign_version >> 16) & 0xff;
+        sig[3] = (sign_version >> 24) & 0xff;
+        memset( sig + 4, 0, 4 );
+        sig[8] = (crc >>  0) & 0xff;
+        sig[9] = (crc >>  8) & 0xff;
+        sig[10] = (crc >> 16) & 0xff;
+        sig[11] = (crc >> 24) & 0xff;
+        sig[12] = (ctx->crypt.ntlm.seq_no >>  0) & 0xff;
+        sig[13] = (ctx->crypt.ntlm.seq_no >>  8) & 0xff;
+        sig[14] = (ctx->crypt.ntlm.seq_no >> 16) & 0xff;
+        sig[15] = (ctx->crypt.ntlm.seq_no >> 24) & 0xff;
+        ctx->crypt.ntlm.seq_no++;
+
+        if (encrypt) arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
+        return SEC_E_OK;
+    }
+
+    if (flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !flags)
+    {
+        /* create dummy signature */
+        memset( msg->pBuffers[idx].pvBuffer, 0, 16 );
+        memset( msg->pBuffers[idx].pvBuffer, 1, 1 );
+        msg->pBuffers[idx].cbBuffer = 16;
+        return SEC_E_OK;
+    }
+
+    return SEC_E_UNSUPPORTED_FUNCTION;
+}
+
+static NTSTATUS NTAPI ntlm_SpMakeSignature( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
+{
+    struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
+    int idx;
+
+    TRACE( "%lx, 0x%08x, %p, %u\n", handle, qop, msg, msg_seq_no );
+    if (qop) FIXME( "ignoring quality of protection %08x\n", qop );
+    if (msg_seq_no) FIXME( "ignoring message sequence number %u\n", msg_seq_no );
+
+    if (!handle) return SEC_E_INVALID_HANDLE;
+    if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
+        return SEC_E_INVALID_TOKEN;
+    if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
+
+    return create_signature( ctx, ctx->flags, msg, idx, SIGN_SEND, TRUE );
+}
+
 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table =
 {
     ntlm_SpInstanceInit,
     NULL, /* SpInitUserModeContext */
-    NULL, /* SpMakeSignature */
+    ntlm_SpMakeSignature,
     NULL, /* SpVerifySignature */
     NULL, /* SpSealMessage */
     NULL, /* SpUnsealMessage */
-- 
2.30.2




More information about the wine-devel mailing list