libfreerdp-auth: get refactored SSPI NTLM module to authenticate successfully
This commit is contained in:
parent
35f396db7e
commit
d0f2e007e0
@ -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 */
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user