mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
libfreerdp-sspi: fix server-side NTLM session key generation
This commit is contained in:
@@ -39,6 +39,7 @@ struct rdp_credssp
|
||||
rdpTls* tls;
|
||||
boolean server;
|
||||
int send_seq_num;
|
||||
int recv_seq_num;
|
||||
UNICONV* uniconv;
|
||||
freerdp* instance;
|
||||
CtxtHandle context;
|
||||
|
||||
@@ -62,11 +62,13 @@ void ntlm_SetContextIdentity(NTLM_CONTEXT* context, SEC_WINNT_AUTH_IDENTITY* ide
|
||||
{
|
||||
context->identity.User = (uint16*) xmalloc(identity->UserLength);
|
||||
memcpy(context->identity.User, identity->User, identity->UserLength);
|
||||
context->identity.UserLength = identity->UserLength;
|
||||
|
||||
if (identity->DomainLength > 0)
|
||||
{
|
||||
context->identity.Domain = (uint16*) xmalloc(identity->DomainLength);
|
||||
memcpy(context->identity.Domain, identity->Domain, identity->DomainLength);
|
||||
context->identity.DomainLength = identity->DomainLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -76,6 +78,7 @@ void ntlm_SetContextIdentity(NTLM_CONTEXT* context, SEC_WINNT_AUTH_IDENTITY* ide
|
||||
|
||||
context->identity.Password = (uint16*) xmalloc(identity->PasswordLength);
|
||||
memcpy(context->identity.Password, identity->Password, identity->PasswordLength);
|
||||
context->identity.PasswordLength = identity->PasswordLength;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +148,8 @@ SECURITY_STATUS ntlm_AcquireCredentialsHandle(char* pszPrincipal, char* pszPacka
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
memcpy(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
@@ -158,6 +161,9 @@ SECURITY_STATUS ntlm_AcquireCredentialsHandle(char* pszPrincipal, char* pszPacka
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
memcpy(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
@@ -221,6 +227,7 @@ SECURITY_STATUS ntlm_AcceptSecurityContext(CredHandle* phCredential, CtxtHandle*
|
||||
context = ntlm_ContextNew();
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
ntlm_SetContextIdentity(context, &credentials->identity);
|
||||
|
||||
ntlm_SetContextTargetName(context, "FreeRDP");
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/hexdump.h>
|
||||
|
||||
#include "ntlm_compute.h"
|
||||
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
const char* const AV_PAIRS_STRINGS[] =
|
||||
|
||||
@@ -402,6 +402,17 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey, context->EncryptedRandomSessionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt RandomSessionKey (RC4-encrypted RandomSessionKey, using KeyExchangeKey as the key).
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the KeyExchangeKey */
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey, context->RandomSessionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate signing key.\n
|
||||
* @msdn{cc236711}
|
||||
|
||||
@@ -43,6 +43,7 @@ void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_random_session_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_exported_session_key(NTLM_CONTEXT* context);
|
||||
void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context);
|
||||
|
||||
@@ -437,6 +437,12 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buf
|
||||
/* KeyExchangeKey */
|
||||
ntlm_generate_key_exchange_key(context);
|
||||
|
||||
/* RandomSessionKey */
|
||||
ntlm_generate_random_session_key(context);
|
||||
|
||||
/* ExportedSessionKey */
|
||||
ntlm_generate_exported_session_key(context);
|
||||
|
||||
/* EncryptedRandomSessionKey */
|
||||
ntlm_encrypt_random_session_key(context);
|
||||
|
||||
@@ -476,7 +482,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buf
|
||||
freerdp_hexdump(context->RandomSessionKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ClientSignKey\n");
|
||||
printf("ClientSigningKey\n");
|
||||
freerdp_hexdump(context->ClientSigningKey, 16);
|
||||
printf("\n");
|
||||
|
||||
@@ -484,6 +490,14 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buf
|
||||
freerdp_hexdump(context->ClientSealingKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ServerSigningKey\n");
|
||||
freerdp_hexdump(context->ServerSigningKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ServerSealingKey\n");
|
||||
freerdp_hexdump(context->ServerSealingKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("Timestamp\n");
|
||||
freerdp_hexdump(context->Timestamp, 8);
|
||||
printf("\n");
|
||||
@@ -612,15 +626,6 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* Initialize RC4 seal state */
|
||||
ntlm_init_rc4_seal_states(context);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
printf("ServerChallenge\n");
|
||||
freerdp_hexdump(context->ServerChallenge, 8);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
context->state = NTLM_STATE_AUTHENTICATE;
|
||||
|
||||
stream_detach(s);
|
||||
@@ -783,7 +788,13 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer*
|
||||
/* NtChallengeResponse */
|
||||
if (NtChallengeResponseLen > 0)
|
||||
{
|
||||
uint8* ClientChallengeBuffer;
|
||||
|
||||
NtChallengeResponseBuffer = s->data + NtChallengeResponseBufferOffset;
|
||||
|
||||
ClientChallengeBuffer = NtChallengeResponseBuffer + 32;
|
||||
memcpy(context->ClientChallenge, ClientChallengeBuffer, 8);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
printf("NtChallengeResponse (length = %d, offset = %d)\n", NtChallengeResponseLen, NtChallengeResponseBufferOffset);
|
||||
freerdp_hexdump(NtChallengeResponseBuffer, NtChallengeResponseLen);
|
||||
@@ -795,6 +806,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer*
|
||||
if (EncryptedRandomSessionKeyLen > 0)
|
||||
{
|
||||
EncryptedRandomSessionKeyBuffer = s->data + EncryptedRandomSessionKeyBufferOffset;
|
||||
memcpy(context->EncryptedRandomSessionKey, EncryptedRandomSessionKeyBuffer, 16);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
printf("EncryptedRandomSessionKey (length = %d, offset = %d)\n", EncryptedRandomSessionKeyLen, EncryptedRandomSessionKeyBufferOffset);
|
||||
freerdp_hexdump(EncryptedRandomSessionKeyBuffer, EncryptedRandomSessionKeyLen);
|
||||
@@ -802,6 +815,81 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer*
|
||||
#endif
|
||||
}
|
||||
|
||||
/* LmChallengeResponse */
|
||||
ntlm_compute_lm_v2_response(context);
|
||||
|
||||
if (context->ntlm_v2)
|
||||
memset(context->LmChallengeResponse.pvBuffer, 0, context->LmChallengeResponse.cbBuffer);
|
||||
|
||||
/* NtChallengeResponse */
|
||||
ntlm_compute_ntlm_v2_response(context);
|
||||
|
||||
/* KeyExchangeKey */
|
||||
ntlm_generate_key_exchange_key(context);
|
||||
|
||||
/* EncryptedRandomSessionKey */
|
||||
ntlm_decrypt_random_session_key(context);
|
||||
|
||||
/* ExportedSessionKey */
|
||||
ntlm_generate_exported_session_key(context);
|
||||
|
||||
/* Generate signing keys */
|
||||
ntlm_generate_client_signing_key(context);
|
||||
ntlm_generate_server_signing_key(context);
|
||||
|
||||
/* Generate sealing keys */
|
||||
ntlm_generate_client_sealing_key(context);
|
||||
ntlm_generate_server_sealing_key(context);
|
||||
|
||||
/* Initialize RC4 seal state */
|
||||
ntlm_init_rc4_seal_states(context);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
printf("ClientChallenge\n");
|
||||
freerdp_hexdump(context->ClientChallenge, 8);
|
||||
printf("\n");
|
||||
|
||||
printf("ServerChallenge\n");
|
||||
freerdp_hexdump(context->ServerChallenge, 8);
|
||||
printf("\n");
|
||||
|
||||
printf("SessionBaseKey\n");
|
||||
freerdp_hexdump(context->SessionBaseKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("KeyExchangeKey\n");
|
||||
freerdp_hexdump(context->KeyExchangeKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ExportedSessionKey\n");
|
||||
freerdp_hexdump(context->ExportedSessionKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("RandomSessionKey\n");
|
||||
freerdp_hexdump(context->RandomSessionKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ClientSigningKey\n");
|
||||
freerdp_hexdump(context->ClientSigningKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ClientSealingKey\n");
|
||||
freerdp_hexdump(context->ClientSealingKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ServerSigningKey\n");
|
||||
freerdp_hexdump(context->ServerSigningKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("ServerSealingKey\n");
|
||||
freerdp_hexdump(context->ServerSealingKey, 16);
|
||||
printf("\n");
|
||||
|
||||
printf("Timestamp\n");
|
||||
freerdp_hexdump(context->Timestamp, 8);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
context->state = NTLM_STATE_FINAL;
|
||||
|
||||
stream_detach(s);
|
||||
|
||||
@@ -77,49 +77,27 @@
|
||||
#define WITH_DEBUG_CREDSSP
|
||||
#endif
|
||||
|
||||
void credssp_SetContextIdentity(rdpCredssp* context, SEC_WINNT_AUTH_IDENTITY* identity)
|
||||
void credssp_SetContextIdentity(rdpCredssp* context, char* user, char* domain, char* password)
|
||||
{
|
||||
size_t size;
|
||||
context->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
|
||||
if (identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
|
||||
context->identity.User = (uint16*) freerdp_uniconv_out(context->uniconv, user, &size);
|
||||
context->identity.UserLength = (uint32) size;
|
||||
|
||||
if (domain)
|
||||
{
|
||||
context->identity.User = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) identity->User, &size);
|
||||
context->identity.UserLength = (uint32) size;
|
||||
|
||||
if (identity->DomainLength > 0)
|
||||
{
|
||||
context->identity.Domain = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) identity->Domain, &size);
|
||||
context->identity.DomainLength = (uint32) size;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->identity.Domain = (uint16*) NULL;
|
||||
context->identity.DomainLength = 0;
|
||||
}
|
||||
|
||||
context->identity.Password = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) identity->Password, &size);
|
||||
context->identity.PasswordLength = (uint32) size;
|
||||
context->identity.Domain = (uint16*) freerdp_uniconv_out(context->uniconv, domain, &size);
|
||||
context->identity.DomainLength = (uint32) size;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->identity.User = (uint16*) xmalloc(identity->UserLength);
|
||||
memcpy(context->identity.User, identity->User, identity->UserLength);
|
||||
|
||||
if (identity->DomainLength > 0)
|
||||
{
|
||||
context->identity.Domain = (uint16*) xmalloc(identity->DomainLength);
|
||||
memcpy(context->identity.Domain, identity->Domain, identity->DomainLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->identity.Domain = (uint16*) NULL;
|
||||
context->identity.DomainLength = 0;
|
||||
}
|
||||
|
||||
context->identity.Password = (uint16*) xmalloc(identity->PasswordLength);
|
||||
memcpy(context->identity.Password, identity->User, identity->PasswordLength);
|
||||
context->identity.Domain = (uint16*) NULL;
|
||||
context->identity.DomainLength = 0;
|
||||
}
|
||||
|
||||
context->identity.Password = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) password, &size);
|
||||
context->identity.PasswordLength = (uint32) size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +108,6 @@ void credssp_SetContextIdentity(rdpCredssp* context, SEC_WINNT_AUTH_IDENTITY* id
|
||||
int credssp_ntlm_client_init(rdpCredssp* credssp)
|
||||
{
|
||||
freerdp* instance;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
rdpSettings* settings = credssp->settings;
|
||||
instance = (freerdp*) settings->instance;
|
||||
|
||||
@@ -145,34 +122,11 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
|
||||
}
|
||||
}
|
||||
|
||||
identity.User = (uint16*) xstrdup(settings->username);
|
||||
identity.UserLength = strlen(settings->username);
|
||||
|
||||
if (settings->domain)
|
||||
{
|
||||
identity.Domain = (uint16*) xstrdup(settings->domain);
|
||||
identity.DomainLength = strlen(settings->domain);
|
||||
}
|
||||
else
|
||||
{
|
||||
identity.Domain = (uint16*) NULL;
|
||||
identity.DomainLength = 0;
|
||||
}
|
||||
|
||||
identity.Password = (uint16*) xstrdup(settings->password);
|
||||
identity.PasswordLength = strlen(settings->password);
|
||||
|
||||
identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||||
|
||||
credssp_SetContextIdentity(credssp, &identity);
|
||||
credssp_SetContextIdentity(credssp, settings->username, settings->domain, settings->password);
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
|
||||
memcpy(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
|
||||
|
||||
xfree(identity.User);
|
||||
xfree(identity.Domain);
|
||||
xfree(identity.Password);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -186,31 +140,15 @@ char* test_Password = "password";
|
||||
|
||||
int credssp_ntlm_server_init(rdpCredssp* credssp)
|
||||
{
|
||||
size_t size;
|
||||
freerdp* instance;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
rdpSettings* settings = credssp->settings;
|
||||
instance = (freerdp*) settings->instance;
|
||||
|
||||
identity.User = (uint16*) freerdp_uniconv_out(credssp->uniconv, test_User, &size);
|
||||
identity.UserLength = (uint32) size;
|
||||
|
||||
identity.Domain = (uint16*) NULL;
|
||||
identity.DomainLength = 0;
|
||||
|
||||
identity.Password = (uint16*) freerdp_uniconv_out(credssp->uniconv, test_Password, &size);
|
||||
identity.PasswordLength = (uint32) size;
|
||||
|
||||
identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
|
||||
credssp_SetContextIdentity(credssp, &identity);
|
||||
credssp_SetContextIdentity(credssp, test_User, NULL, test_Password);
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
|
||||
memcpy(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
|
||||
|
||||
xfree(identity.User);
|
||||
xfree(identity.Password);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -225,7 +163,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
CredHandle credentials;
|
||||
SEC_TIMESTAMP expiration;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SecBuffer* p_buffer;
|
||||
SecBuffer input_buffer;
|
||||
SecBuffer output_buffer;
|
||||
@@ -234,7 +171,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
boolean have_context;
|
||||
boolean have_input_buffer;
|
||||
boolean have_pub_key_auth;
|
||||
rdpSettings* settings = credssp->settings;
|
||||
|
||||
sspi_GlobalInit();
|
||||
|
||||
@@ -253,27 +189,8 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
|
||||
cbMaxToken = pPackageInfo->cbMaxToken;
|
||||
|
||||
identity.User = (uint16*) xstrdup(settings->username);
|
||||
identity.UserLength = strlen(settings->username);
|
||||
|
||||
if (settings->domain)
|
||||
{
|
||||
identity.Domain = (uint16*) xstrdup(settings->domain);
|
||||
identity.DomainLength = strlen(settings->domain);
|
||||
}
|
||||
else
|
||||
{
|
||||
identity.Domain = (uint16*) NULL;
|
||||
identity.DomainLength = 0;
|
||||
}
|
||||
|
||||
identity.Password = (uint16*) xstrdup(settings->password);
|
||||
identity.PasswordLength = strlen(settings->password);
|
||||
|
||||
identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||||
|
||||
status = credssp->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration);
|
||||
SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
@@ -432,9 +349,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
|
||||
FreeCredentialsHandle(&credentials);
|
||||
FreeContextBuffer(pPackageInfo);
|
||||
xfree(identity.User);
|
||||
xfree(identity.Domain);
|
||||
xfree(identity.Password);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -481,7 +395,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
cbMaxToken = pPackageInfo->cbMaxToken;
|
||||
|
||||
status = credssp->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
|
||||
SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration);
|
||||
SECPKG_CRED_INBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
@@ -1081,6 +995,7 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings)
|
||||
credssp->server = settings->server_mode;
|
||||
credssp->tls = tls;
|
||||
credssp->send_seq_num = 0;
|
||||
credssp->recv_seq_num = 0;
|
||||
credssp->uniconv = freerdp_uniconv_new();
|
||||
memset(&credssp->negoToken, 0, sizeof(SecBuffer));
|
||||
memset(&credssp->pubKeyAuth, 0, sizeof(SecBuffer));
|
||||
|
||||
Reference in New Issue
Block a user