libwinpr-sspi: fix server-side NTLM signing and sealing
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 24 May 2012 19:19:11 +0000 (15:19 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 24 May 2012 19:19:11 +0000 (15:19 -0400)
include/winpr/credssp.h
winpr/sspi/CredSSP/credssp.c
winpr/sspi/NTLM/ntlm.c
winpr/sspi/NTLM/ntlm_compute.c

index 2e690cc..f19c1c0 100644 (file)
@@ -66,6 +66,7 @@ FREERDP_API void credssp_buffer_free(rdpCredssp* credssp);
 SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp);
 FREERDP_API void credssp_encode_ts_credentials(rdpCredssp* credssp);
 SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
+SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
 
 FREERDP_API rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings);
 FREERDP_API void credssp_free(rdpCredssp* credssp);
index 62b6710..9a48e7b 100644 (file)
@@ -100,10 +100,18 @@ void credssp_SetContextIdentity(rdpCredssp* context, char* user, char* domain, c
                context->identity.DomainLength = 0;
        }
 
-       context->identity.PasswordLength = strlen(password) * 2;
-       context->identity.Password = (uint16*) malloc(context->identity.PasswordLength);
-       MultiByteToWideChar(CP_ACP, 0, password, strlen(password),
-                       (LPWSTR) context->identity.Password, context->identity.PasswordLength / 2);
+       if (password != NULL)
+       {
+               context->identity.PasswordLength = strlen(password) * 2;
+               context->identity.Password = (uint16*) malloc(context->identity.PasswordLength);
+               MultiByteToWideChar(CP_ACP, 0, password, strlen(password),
+                               (LPWSTR) context->identity.Password, context->identity.PasswordLength / 2);
+       }
+       else
+       {
+               context->identity.Password = NULL;
+               context->identity.PasswordLength = 0;
+       }
 }
 
 /**
@@ -522,16 +530,18 @@ int credssp_server_authenticate(rdpCredssp* credssp)
 
                        have_pub_key_auth = true;
 
-                       sspi_SecBufferFree(&credssp->negoToken);
-                       credssp->negoToken.pvBuffer = NULL;
-                       credssp->negoToken.cbBuffer = 0;
-
                        if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
                        {
                                printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
                                return 0;
                        }
 
+                       credssp_verify_public_key_echo(credssp);
+
+                       sspi_SecBufferFree(&credssp->negoToken);
+                       credssp->negoToken.pvBuffer = NULL;
+                       credssp->negoToken.cbBuffer = 0;
+
                        if (have_pub_key_auth)
                        {
                                uint8* p;
@@ -591,6 +601,8 @@ int credssp_server_authenticate(rdpCredssp* credssp)
        if (credssp_recv(credssp) < 0)
                return -1;
 
+       credssp_decrypt_ts_credentials(credssp);
+
        if (status != SEC_E_OK)
        {
                printf("AcceptSecurityContext status: 0x%08X\n", status);
@@ -647,19 +659,19 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
        SECURITY_STATUS status;
 
        length = credssp->pubKeyAuth.cbBuffer;
-       pub_key_auth = (uint8*) credssp->pubKeyAuth.pvBuffer;
+       pub_key_auth = (BYTE*) credssp->pubKeyAuth.pvBuffer;
        public_key_length = credssp->PublicKey.cbBuffer;
 
        Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
        Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
 
        Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
-       Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
-       memcpy(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
+       Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
+       CopyMemory(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
 
        Buffers[1].cbBuffer = length - Buffers[0].cbBuffer;
-       Buffers[1].pvBuffer = xmalloc(Buffers[1].cbBuffer);
-       memcpy(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
+       Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
+       CopyMemory(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
 
        Message.cBuffers = 2;
        Message.ulVersion = SECBUFFER_VERSION;
@@ -673,10 +685,11 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
                return status;
        }
 
-       public_key1 = (uint8*) credssp->PublicKey.pvBuffer;
-       public_key2 = (uint8*) Buffers[1].pvBuffer;
+       public_key1 = (BYTE*) credssp->PublicKey.pvBuffer;
+       public_key2 = (BYTE*) Buffers[1].pvBuffer;
 
-       public_key2[0]--; /* server echos the public key +1 */
+       if (!credssp->server)
+               public_key2[0]--; /* server echos the public key +1 */
 
        if (memcmp(public_key1, public_key2, public_key_length) != 0)
        {
@@ -701,22 +714,22 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
 
 SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
 {
-       uint8* p;
+       BYTE* p;
        SecBuffer Buffers[2];
        SecBufferDesc Message;
        SECURITY_STATUS status;
 
        credssp_encode_ts_credentials(credssp);
 
-       Buffers[0].BufferType = SECBUFFER_DATA; /* TSCredentials */
-       Buffers[1].BufferType = SECBUFFER_TOKEN; /* Signature */
+       Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+       Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
 
-       Buffers[0].cbBuffer = credssp->ts_credentials.cbBuffer;
-       Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
-       memcpy(Buffers[0].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[0].cbBuffer);
+       Buffers[0].cbBuffer = 16;
+       Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
 
-       Buffers[1].cbBuffer = 16;
-       Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
+       Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
+       Buffers[1].pvBuffer = xmalloc(Buffers[1].cbBuffer);
+       CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
 
        Message.cBuffers = 2;
        Message.ulVersion = SECBUFFER_VERSION;
@@ -729,9 +742,9 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
        if (status != SEC_E_OK)
                return status;
 
-       p = (uint8*) credssp->authInfo.pvBuffer;
-       memcpy(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
-       memcpy(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted TSCredentials */
+       p = (BYTE*) credssp->authInfo.pvBuffer;
+       CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
+       CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted TSCredentials */
 
        xfree(Buffers[0].pvBuffer);
        xfree(Buffers[1].pvBuffer);
@@ -739,6 +752,45 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
        return SEC_E_OK;
 }
 
+SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
+{
+       BYTE* p;
+       SecBuffer Buffers[2];
+       SecBufferDesc Message;
+       SECURITY_STATUS status;
+
+       Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+       Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
+
+       Buffers[0].cbBuffer = 16;
+       Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
+       CopyMemory(Buffers[0].pvBuffer, credssp->authInfo.pvBuffer, Buffers[0].cbBuffer);
+
+       Buffers[1].cbBuffer = credssp->authInfo.cbBuffer - Buffers[0].cbBuffer;
+       Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
+       p = (BYTE*) credssp->authInfo.pvBuffer;
+       CopyMemory(Buffers[1].pvBuffer, &p[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
+
+       Message.cBuffers = 2;
+       Message.ulVersion = SECBUFFER_VERSION;
+       Message.pBuffers = (PSecBuffer) &Buffers;
+
+       sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
+
+       status = credssp->table->DecryptMessage(&credssp->context, &Message, 1, 0);
+
+       freerdp_hexdump(Buffers[0].pvBuffer, Buffers[0].cbBuffer);
+       freerdp_hexdump(Buffers[1].pvBuffer, Buffers[1].cbBuffer);
+
+       if (status != SEC_E_OK)
+               return status;
+
+       free(Buffers[0].pvBuffer);
+       free(Buffers[1].pvBuffer);
+
+       return SEC_E_OK;
+}
+
 int credssp_skip_ts_password_creds(rdpCredssp* credssp)
 {
        int length;
index 6115423..3904e5a 100644 (file)
@@ -564,7 +564,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
        /* Copy original data buffer */
        length = data_buffer->cbBuffer;
        data = malloc(length);
-       memcpy(data, data_buffer->pvBuffer, length);
+       CopyMemory(data, data_buffer->pvBuffer, length);
 
        /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
        HMAC_CTX_init(&hmac);
@@ -599,9 +599,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
        signature = (BYTE*) signature_buffer->pvBuffer;
 
        /* Concatenate version, ciphertext and sequence number to build signature */
-       memcpy(signature, (void*) &version, 4);
-       memcpy(&signature[4], (void*) checksum, 8);
-       memcpy(&signature[12], (void*) &(MessageSeqNo), 4);
+       CopyMemory(signature, (void*) &version, 4);
+       CopyMemory(&signature[4], (void*) checksum, 8);
+       CopyMemory(&signature[12], (void*) &(MessageSeqNo), 4);
        context->SendSeqNum++;
 
 #ifdef WITH_DEBUG_NTLM
@@ -646,10 +646,14 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
        /* Copy original data buffer */
        length = data_buffer->cbBuffer;
        data = malloc(length);
-       memcpy(data, data_buffer->pvBuffer, length);
+       CopyMemory(data, data_buffer->pvBuffer, length);
 
-       /* Decrypt message using with RC4 */
-       crypto_rc4(context->RecvRc4Seal, length, data, data_buffer->pvBuffer);
+       /* Decrypt message using with RC4, result overwrites original buffer */
+
+       if (context->confidentiality)
+               crypto_rc4(context->RecvRc4Seal, length, data, data_buffer->pvBuffer);
+       else
+               CopyMemory(data_buffer->pvBuffer, data, length);
 
        /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
        HMAC_CTX_init(&hmac);
@@ -675,15 +679,21 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
        crypto_rc4(context->RecvRc4Seal, 8, digest, checksum);
 
        /* Concatenate version, ciphertext and sequence number to build signature */
-       memcpy(expected_signature, (void*) &version, 4);
-       memcpy(&expected_signature[4], (void*) checksum, 8);
-       memcpy(&expected_signature[12], (void*) &(MessageSeqNo), 4);
+       CopyMemory(expected_signature, (void*) &version, 4);
+       CopyMemory(&expected_signature[4], (void*) checksum, 8);
+       CopyMemory(&expected_signature[12], (void*) &(MessageSeqNo), 4);
        context->RecvSeqNum++;
 
        if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
        {
                /* signature verification failed! */
                printf("signature verification failed, something nasty is going on!\n");
+
+               printf("Expected Signature:\n");
+               freerdp_hexdump(expected_signature, 16);
+               printf("Actual Signature:\n");
+               freerdp_hexdump(signature_buffer->pvBuffer, 16);
+
                return SEC_E_MESSAGE_ALTERED;
        }
 
index 8657e39..8db1651 100644 (file)
@@ -213,6 +213,11 @@ static void ascii_hex_string_to_binary(char* str, unsigned char* hex)
        }
 }
 
+/*
+ * username // password
+ * username:661e58eb6743798326f388fc5edb0b3a
+ */
+
 void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
 {
        FILE* fp;
@@ -270,9 +275,8 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
                        {
                                if (memcmp(User, context->identity.User, UserLength) == 0)
                                {
-                                       printf("%s:%s\n", db_user, db_hash);
                                        ascii_hex_string_to_binary(db_hash, db_hash_bin);
-                                       memcpy(hash, db_hash_bin, 16);
+                                       CopyMemory(hash, db_hash_bin, 16);
                                }
                        }
                }