libfreerdp-sspi: fix server-side NTLM session key generation

This commit is contained in:
Marc-André Moreau
2012-03-18 22:02:23 -04:00
parent 141c928579
commit 76dedc59bf
7 changed files with 138 additions and 113 deletions

View File

@@ -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;

View File

@@ -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");

View File

@@ -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[] =

View File

@@ -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}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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));