libfreerdp-auth: get refactored SSPI NTLM module to authenticate successfully

This commit is contained in:
Marc-André Moreau 2012-02-26 22:08:43 -05:00
parent 35f396db7e
commit d0f2e007e0
3 changed files with 202 additions and 23 deletions

View File

@ -316,7 +316,7 @@ SECURITY_STATUS ntlm_EncryptMessage(CTXT_HANDLE* phContext, uint32 fQOP, SEC_BUF
/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,msg) using the client signing key */
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, context->ClientSigningKey, 16, EVP_md5(), NULL);
HMAC_Update(&hmac, (void*) &MessageSeqNo, 4);
HMAC_Update(&hmac, (void*) &context->send_seq_num, 4);
HMAC_Update(&hmac, data, length);
HMAC_Final(&hmac, digest, NULL);
@ -342,8 +342,8 @@ SECURITY_STATUS ntlm_EncryptMessage(CTXT_HANDLE* phContext, uint32 fQOP, SEC_BUF
freerdp_hexdump(data_buffer->pvBuffer, data_buffer->cbBuffer);
printf("\n");
printf("Signature\n");
freerdp_hexdump(signature, 16);
printf("Signature (length = %d)\n", signature_buffer->cbBuffer);
freerdp_hexdump(signature_buffer->pvBuffer, signature_buffer->cbBuffer);
printf("\n");
#endif
@ -355,6 +355,74 @@ SECURITY_STATUS ntlm_EncryptMessage(CTXT_HANDLE* phContext, uint32 fQOP, SEC_BUF
return SEC_E_OK;
}
SECURITY_STATUS ntlm_DecryptMessage(CTXT_HANDLE* phContext, SEC_BUFFER_DESC* pMessage, uint32 MessageSeqNo, uint32* pfQOP)
{
int index;
int length;
void* data;
HMAC_CTX hmac;
uint8 digest[16];
uint8 checksum[8];
uint32 version = 1;
NTLM_CONTEXT* context;
uint8 expected_signature[16];
SEC_BUFFER* data_buffer = NULL;
SEC_BUFFER* signature_buffer = NULL;
context = sspi_SecureHandleGetLowerPointer(phContext);
for (index = 0; index < pMessage->cBuffers; index++)
{
if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
data_buffer = &pMessage->pBuffers[index];
else if (pMessage->pBuffers[index].BufferType == SECBUFFER_PADDING)
signature_buffer = &pMessage->pBuffers[index];
}
if (!data_buffer)
return SEC_E_INVALID_TOKEN;
if (!signature_buffer)
return SEC_E_INVALID_TOKEN;
/* Copy original data buffer */
length = data_buffer->cbBuffer;
data = xmalloc(length);
memcpy(data, data_buffer->pvBuffer, length);
/* Decrypt message using with RC4 */
crypto_rc4(context->recv_rc4_seal, length, data, data_buffer->pvBuffer);
/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,msg) using the client signing key */
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, context->ServerSigningKey, 16, EVP_md5(), NULL);
HMAC_Update(&hmac, (void*) &context->recv_seq_num, 4);
HMAC_Update(&hmac, data_buffer->pvBuffer, data_buffer->cbBuffer);
HMAC_Final(&hmac, digest, NULL);
/* RC4-encrypt first 8 bytes of digest */
crypto_rc4(context->recv_rc4_seal, 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*) &(context->recv_seq_num), 4);
if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
{
/* signature verification failed! */
printf("signature verification failed, something nasty is going on!\n");
return SEC_E_MESSAGE_ALTERED;
}
HMAC_CTX_cleanup(&hmac);
xfree(data);
context->recv_seq_num++;
return SEC_E_OK;
}
const SEC_PKG_INFO NTLM_SEC_PKG_INFO =
{
0x00082B37, /* fCapabilities */
@ -394,6 +462,6 @@ const SECURITY_FUNCTION_TABLE NTLM_SECURITY_FUNCTION_TABLE =
NULL, /* Reserved8 */
NULL, /* QuerySecurityContextToken */
ntlm_EncryptMessage, /* EncryptMessage */
NULL, /* DecryptMessage */
ntlm_DecryptMessage, /* DecryptMessage */
NULL, /* SetContextAttributes */
};

View File

@ -317,35 +317,30 @@ int credssp_client_authenticate(rdpCredssp* credssp)
if (have_pub_key_auth)
{
uint8* p;
SEC_BUFFER* Buffers[2];
SEC_BUFFER data_buffer;
SEC_BUFFER signature_buffer;
SEC_BUFFER Buffers[2];
SEC_BUFFER_DESC Message;
data_buffer.BufferType = SECBUFFER_DATA;
signature_buffer.BufferType = SECBUFFER_PADDING;
Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
Buffers[1].BufferType = SECBUFFER_PADDING; /* Signature */
data_buffer.cbBuffer = credssp->tls->public_key.length;
data_buffer.pvBuffer = xmalloc(data_buffer.cbBuffer);
memcpy(data_buffer.pvBuffer, credssp->tls->public_key.data, data_buffer.cbBuffer);
Buffers[0].cbBuffer = credssp->tls->public_key.length;
Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
memcpy(Buffers[0].pvBuffer, credssp->tls->public_key.data, Buffers[0].cbBuffer);
signature_buffer.cbBuffer = 16;
signature_buffer.pvBuffer = xzalloc(signature_buffer.cbBuffer);
Buffers[0] = &data_buffer;
Buffers[1] = &signature_buffer;
Buffers[1].cbBuffer = 16;
Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
Message.cBuffers = 2;
Message.ulVersion = SECBUFFER_VERSION;
Message.pBuffers = (SEC_BUFFER*) Buffers;
Message.pBuffers = (SEC_BUFFER*) &Buffers;
freerdp_blob_alloc(&credssp->pubKeyAuth, data_buffer.cbBuffer + signature_buffer.cbBuffer);
freerdp_blob_alloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
table->EncryptMessage(&context, 0, &Message, 1);
table->EncryptMessage(&context, 0, &Message, 0);
p = (uint8*) credssp->pubKeyAuth.data;
memcpy(p, signature_buffer.pvBuffer, signature_buffer.cbBuffer); /* Message Signature */
memcpy(&p[signature_buffer.cbBuffer], data_buffer.pvBuffer, data_buffer.cbBuffer); /* Encrypted Public Key */
memcpy(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
memcpy(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted Public Key */
}
if (status == SEC_I_COMPLETE_NEEDED)
@ -403,6 +398,106 @@ int credssp_client_authenticate(rdpCredssp* credssp)
have_context = true;
}
/* Encrypted Public Key +1 */
if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
return -1;
/* Verify Server Public Key Echo */
{
int length;
uint32 pfQOP;
uint8* public_key1;
uint8* public_key2;
uint8* pub_key_auth;
int public_key_length;
SEC_BUFFER Buffers[2];
SEC_BUFFER_DESC Message;
length = credssp->pubKeyAuth.length;
pub_key_auth = (uint8*) credssp->pubKeyAuth.data;
public_key_length = credssp->tls->public_key.length;
Buffers[0].BufferType = SECBUFFER_PADDING; /* Signature */
Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
Buffers[0].cbBuffer = 16;
Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
memcpy(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);
Message.cBuffers = 2;
Message.ulVersion = SECBUFFER_VERSION;
Message.pBuffers = (SEC_BUFFER*) &Buffers;
status = table->DecryptMessage(&context, &Message, 0, &pfQOP);
if (status != SEC_E_OK)
return 0;
public_key1 = (uint8*) credssp->tls->public_key.data;
public_key2 = (uint8*) Buffers[1].pvBuffer;
public_key2[0]--; /* server echos the public key +1 */
if (memcmp(public_key1, public_key2, public_key_length) != 0)
{
printf("Could not verify server's public key echo\n");
printf("Expected (length = %d):\n", public_key_length);
freerdp_hexdump(public_key1, public_key_length);
printf("Actual (length = %d):\n", public_key_length);
freerdp_hexdump(public_key2, public_key_length);
return 0; /* DO NOT SEND CREDENTIALS! */
}
public_key2[0]++;
}
/* Send encrypted credentials */
credssp_encode_ts_credentials(credssp);
/* Encrypt TSCredentials */
{
uint8* p;
SEC_BUFFER Buffers[2];
SEC_BUFFER_DESC Message;
Buffers[0].BufferType = SECBUFFER_DATA; /* TSCredentials */
Buffers[1].BufferType = SECBUFFER_PADDING; /* Signature */
Buffers[0].cbBuffer = credssp->ts_credentials.length;
Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
memcpy(Buffers[0].pvBuffer, credssp->ts_credentials.data, Buffers[0].cbBuffer);
Buffers[1].cbBuffer = 16;
Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
Message.cBuffers = 2;
Message.ulVersion = SECBUFFER_VERSION;
Message.pBuffers = (SEC_BUFFER*) &Buffers;
freerdp_blob_alloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
table->EncryptMessage(&context, 0, &Message, 1);
p = (uint8*) credssp->authInfo.data;
memcpy(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
memcpy(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted TSCredentials */
}
credssp_send(credssp, NULL, &credssp->authInfo, NULL);
freerdp_blob_free(&credssp->negoToken);
freerdp_blob_free(&credssp->pubKeyAuth);
freerdp_blob_free(&credssp->authInfo);
FreeCredentialsHandle(&credentials);
FreeContextBuffer(pPackageInfo);

View File

@ -566,7 +566,23 @@ SECURITY_STATUS RevertSecurityContext(CTXT_HANDLE* phContext)
SECURITY_STATUS DecryptMessage(CTXT_HANDLE* phContext, SEC_BUFFER_DESC* pMessage, uint32 MessageSeqNo, uint32* pfQOP)
{
return SEC_E_OK;
char* Name;
SECURITY_STATUS status;
SECURITY_FUNCTION_TABLE* table;
Name = (char*) sspi_SecureHandleGetUpperPointer(phContext);
if (!Name)
return SEC_E_SECPKG_NOT_FOUND;
table = sspi_GetSecurityFunctionTableByName(Name);
if (!table)
return SEC_E_SECPKG_NOT_FOUND;
status = table->DecryptMessage(phContext, pMessage, MessageSeqNo, pfQOP);
return status;
}
SECURITY_STATUS EncryptMessage(CTXT_HANDLE* phContext, uint32 fQOP, SEC_BUFFER_DESC* pMessage, uint32 MessageSeqNo)