libfreerdp-auth: start using new SSPI package optionally

This commit is contained in:
Marc-André Moreau 2012-02-24 17:17:38 -05:00
parent 0303c7a3d4
commit 29bed60b07
7 changed files with 453 additions and 5 deletions

View File

@ -147,8 +147,6 @@ void test_InitializeSecurityContext(void)
status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo);
printf("pPackageInfo: 0x%08X ppPackageInfo:0x%08X\n", pPackageInfo, &pPackageInfo);
if (status != SEC_E_OK)
{
printf("QuerySecurityPackageInfo status: 0x%08X\n", status);

View File

@ -46,6 +46,7 @@ NTLM_CONTEXT* ntlm_ContextNew()
context->ntlm_v2 = false;
context->NegotiateFlags = 0;
context->state = NTLM_STATE_INITIAL;
context->uniconv = freerdp_uniconv_new();
}
return context;
@ -127,7 +128,7 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H
NTLM_CONTEXT* context;
SEC_BUFFER* sec_buffer;
if (pInput == NULL)
if (!pInput)
{
context = ntlm_ContextNew();
@ -145,8 +146,31 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H
if (sec_buffer->cbBuffer < 1)
return SEC_E_INSUFFICIENT_MEMORY;
sspi_SecureHandleSetLowerPointer(phNewContext, context);
return ntlm_write_NegotiateMessage(context, sec_buffer);
}
else
{
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
if (!context)
return SEC_E_INVALID_HANDLE;
if (!pInput)
return SEC_E_INVALID_TOKEN;
if (pInput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
sec_buffer = &pInput->pBuffers[0];
if (sec_buffer->BufferType != SECBUFFER_TOKEN)
return SEC_E_INVALID_TOKEN;
if (sec_buffer->cbBuffer < 1)
return SEC_E_INVALID_TOKEN;
}
return SEC_E_OK;
}

View File

@ -23,6 +23,8 @@
#include <freerdp/auth/sspi.h>
#include <freerdp/auth/credssp.h>
#include <freerdp/utils/unicode.h>
#include "../sspi.h"
enum _NTLM_STATE
@ -39,10 +41,28 @@ struct _NTLM_CONTEXT
{
boolean ntlm_v2;
NTLM_STATE state;
UNICONV* uniconv;
uint32 NegotiateFlags;
SEC_BUFFER NegotiateMessage;
SEC_BUFFER ChallengeMessage;
SEC_BUFFER AuthenticateMessage;
SEC_BUFFER TargetInfo;
SEC_BUFFER TargetName;
SEC_BUFFER NtChallengeResponse;
SEC_BUFFER LmChallengeResponse;
uint8 Timestamp[8];
uint8 ServerChallenge[8];
uint8 ClientChallenge[8];
uint8 SessionBaseKey[16];
uint8 KeyExchangeKey[16];
uint8 RandomSessionKey[16];
uint8 ExportedSessionKey[16];
uint8 EncryptedRandomSessionKey[16];
uint8 ClientSigningKey[16];
uint8 ClientSealingKey[16];
uint8 ServerSigningKey[16];
uint8 ServerSealingKey[16];
uint8 MessageIntegrityCheck[16];
};
typedef struct _NTLM_CONTEXT NTLM_CONTEXT;

View File

@ -21,9 +21,12 @@
#include "../sspi.h"
#include <freerdp/utils/stream.h>
#include <freerdp/utils/hexdump.h>
#include "ntlm_message.h"
#define WITH_DEBUG_NTLM
#define NTLMSSP_NEGOTIATE_56 0x80000000 /* W (0) */
#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V (1) */
#define NTLMSSP_NEGOTIATE_128 0x20000000 /* U (2) */
@ -70,6 +73,42 @@
static const char NTLM_SIGNATURE[] = "NTLMSSP";
static const char* const NTLM_NEGOTIATE_STRINGS[] =
{
"NTLMSSP_NEGOTIATE_56",
"NTLMSSP_NEGOTIATE_KEY_EXCH",
"NTLMSSP_NEGOTIATE_128",
"NTLMSSP_RESERVED1",
"NTLMSSP_RESERVED2",
"NTLMSSP_RESERVED3",
"NTLMSSP_NEGOTIATE_VERSION",
"NTLMSSP_RESERVED4",
"NTLMSSP_NEGOTIATE_TARGET_INFO",
"NTLMSSP_REQUEST_NON_NT_SESSION_KEY",
"NTLMSSP_RESERVED5",
"NTLMSSP_NEGOTIATE_IDENTIFY",
"NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY",
"NTLMSSP_RESERVED6",
"NTLMSSP_TARGET_TYPE_SERVER",
"NTLMSSP_TARGET_TYPE_DOMAIN",
"NTLMSSP_NEGOTIATE_ALWAYS_SIGN",
"NTLMSSP_RESERVED7",
"NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED",
"NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED",
"NTLMSSP_NEGOTIATE_ANONYMOUS",
"NTLMSSP_RESERVED8",
"NTLMSSP_NEGOTIATE_NTLM",
"NTLMSSP_RESERVED9",
"NTLMSSP_NEGOTIATE_LM_KEY",
"NTLMSSP_NEGOTIATE_DATAGRAM",
"NTLMSSP_NEGOTIATE_SEAL",
"NTLMSSP_NEGOTIATE_SIGN",
"NTLMSSP_RESERVED10",
"NTLMSSP_REQUEST_TARGET",
"NTLMSSP_NEGOTIATE_OEM",
"NTLMSSP_NEGOTIATE_UNICODE"
};
/**
* Output VERSION structure.\n
* VERSION @msdn{cc236654}
@ -87,6 +126,25 @@ void ntlm_output_version(STREAM* s)
stream_write_uint8(s, NTLMSSP_REVISION_W2K3); /* NTLMRevisionCurrent (1 byte) */
}
void ntlm_print_negotiate_flags(uint32 flags)
{
int i;
const char* str;
printf("negotiateFlags \"0x%08X\"{\n", flags);
for (i = 31; i >= 0; i--)
{
if ((flags >> i) & 1)
{
str = NTLM_NEGOTIATE_STRINGS[(31 - i)];
printf("\t%s (%d),\n", str, (31 - i));
}
}
printf("}\n");
}
SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer)
{
STREAM* s;
@ -150,15 +208,199 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* b
{
/* Only present if NTLMSSP_NEGOTIATE_VERSION is set */
ntlm_output_version(s);
#ifdef WITH_DEBUG_NTLM
printf("Version (length = 8)\n");
freerdp_hexdump((s->p - 8), 8);
printf("\n");
#endif
}
length = s->p - s->data;
buffer->cbBuffer = length;
//freerdp_blob_alloc(&context->negotiate_message, length);
//memcpy(context->negotiate_message.data, s->data, length);
sspi_SecBufferAlloc(&context->NegotiateMessage, length);
memcpy(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
context->NegotiateMessage.BufferType = buffer->BufferType;
#ifdef WITH_DEBUG_NTLM
printf("NEGOTIATE_MESSAGE (length = %d)\n", length);
freerdp_hexdump(s->data, length);
printf("\n");
#endif
context->state = NTLM_STATE_CHALLENGE;
return SEC_I_CONTINUE_NEEDED;
}
SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer)
{
uint8* p;
STREAM* s;
int length;
uint8* start_offset;
uint8* payload_offset;
uint16 targetNameLen;
uint16 targetNameMaxLen;
uint32 targetNameBufferOffset;
uint16 targetInfoLen;
uint16 targetInfoMaxLen;
uint32 targetInfoBufferOffset;
s = stream_new(0);
stream_attach(s, buffer->pvBuffer, buffer->cbBuffer);
start_offset = s->p - 12;
/* TargetNameFields (8 bytes) */
stream_read_uint16(s, targetNameLen); /* TargetNameLen (2 bytes) */
stream_read_uint16(s, targetNameMaxLen); /* TargetNameMaxLen (2 bytes) */
stream_read_uint32(s, targetNameBufferOffset); /* TargetNameBufferOffset (4 bytes) */
stream_read_uint32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */
#ifdef WITH_DEBUG_NTLM
ntlm_print_negotiate_flags(context->NegotiateFlags);
#endif
stream_read(s, context->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
stream_seek(s, 8); /* Reserved (8 bytes), should be ignored */
/* TargetInfoFields (8 bytes) */
stream_read_uint16(s, targetInfoLen); /* TargetInfoLen (2 bytes) */
stream_read_uint16(s, targetInfoMaxLen); /* TargetInfoMaxLen (2 bytes) */
stream_read_uint32(s, targetInfoBufferOffset); /* TargetInfoBufferOffset (4 bytes) */
/* only present if NTLMSSP_NEGOTIATE_VERSION is set */
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{
stream_seek(s, 8); /* Version (8 bytes), can be ignored */
}
/* Payload (variable) */
payload_offset = s->p;
if (targetNameLen > 0)
{
p = start_offset + targetNameBufferOffset;
sspi_SecBufferAlloc(&context->TargetName, targetNameLen);
memcpy(context->TargetName.pvBuffer, p, targetNameLen);
#ifdef WITH_DEBUG_NTLM
printf("TargetName (length = %d, offset = %d)\n", targetNameLen, targetNameBufferOffset);
freerdp_hexdump(context->TargetName.pvBuffer, context->TargetName.cbBuffer);
printf("\n");
#endif
}
if (targetInfoLen > 0)
{
p = start_offset + targetInfoBufferOffset;
sspi_SecBufferAlloc(&context->TargetInfo, targetInfoLen);
memcpy(context->TargetInfo.pvBuffer, p, targetInfoLen);
#ifdef WITH_DEBUG_NTLM
printf("TargetInfo (length = %d, offset = %d)\n", targetInfoLen, targetInfoBufferOffset);
freerdp_hexdump(context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer);
printf("\n");
#endif
if (context->ntlm_v2)
{
s->p = p;
//ntlm_input_av_pairs(context, s);
}
}
length = (payload_offset - start_offset) + targetNameLen + targetInfoLen;
sspi_SecBufferAlloc(&context->ChallengeMessage, length);
memcpy(context->ChallengeMessage.pvBuffer, start_offset, length);
#ifdef WITH_DEBUG_NTLM
printf("CHALLENGE_MESSAGE (length = %d)\n", length);
freerdp_hexdump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
printf("\n");
#endif
#if 0
/* AV_PAIRs */
if (context->ntlm_v2)
ntlmssp_populate_av_pairs(context);
/* Timestamp */
ntlm_generate_timestamp(context);
/* LmChallengeResponse */
ntlm_compute_lm_v2_response(context);
if ((context->ntlm_v2) && (context->LmChallengeResponse.cbBuffer > 0))
memset(context->LmChallengeResponse.pvBuffer, 0, context->LmChallengeResponse.cbBuffer);
/* NtChallengeResponse */
ntlm_compute_ntlm_v2_response(context);
/* KeyExchangeKey */
ntlm_generate_key_exchange_key(context);
/* EncryptedRandomSessionKey */
ntlm_encrypt_random_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 using client sealing key */
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("ClientSignKey\n");
freerdp_hexdump(context->ClientSigningKey, 16);
printf("\n");
printf("ClientSealingKey\n");
freerdp_hexdump(context->ClientSealingKey, 16);
printf("\n");
printf("Timestamp\n");
freerdp_hexdump(context->Timestamp, 8);
printf("\n");
#endif
#endif
context->state = NTLMSSP_STATE_AUTHENTICATE;
return SEC_I_CONTINUE_NEEDED;
}

View File

@ -29,6 +29,8 @@
#include <freerdp/auth/sspi.h>
#include <freerdp/auth/credssp.h>
//#define WITH_SSPI 1
/**
* TSRequest ::= SEQUENCE {
* version [0] INTEGER,
@ -142,6 +144,8 @@ int credssp_ntlmssp_server_init(rdpCredssp* credssp)
* @return 1 if authentication is successful
*/
#ifndef WITH_SSPI
int credssp_client_authenticate(rdpCredssp* credssp)
{
NTLMSSP* ntlmssp = credssp->ntlmssp;
@ -202,6 +206,151 @@ int credssp_client_authenticate(rdpCredssp* credssp)
return 1;
}
#else
#define NTLM_PACKAGE_NAME "NTLM"
int credssp_client_authenticate(rdpCredssp* credssp)
{
uint32 cbMaxLen;
uint32 fContextReq;
void* output_buffer;
CTXT_HANDLE context;
uint32 pfContextAttr;
SECURITY_STATUS status;
CRED_HANDLE credentials;
SEC_TIMESTAMP expiration;
SEC_PKG_INFO* pPackageInfo;
SEC_AUTH_IDENTITY identity;
SECURITY_FUNCTION_TABLE* table;
SEC_BUFFER* p_sec_buffer;
SEC_BUFFER output_sec_buffer;
SEC_BUFFER_DESC output_sec_buffer_desc;
SEC_BUFFER input_sec_buffer;
SEC_BUFFER_DESC input_sec_buffer_desc;
rdpSettings* settings = credssp->settings;
sspi_GlobalInit();
if (credssp_ntlmssp_client_init(credssp) == 0)
return 0;
table = InitSecurityInterface();
status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo);
if (status != SEC_E_OK)
{
printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
return 0;
}
cbMaxLen = 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_AUTH_IDENTITY_ANSI;
status = table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration);
if (status != SEC_E_OK)
{
printf("AcquireCredentialsHandle status: 0x%08X\n", status);
return 0;
}
fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
output_buffer = xmalloc(cbMaxLen);
printf("First Call to InitializeSecurityContext()\n");
output_sec_buffer_desc.ulVersion = 0;
output_sec_buffer_desc.cBuffers = 1;
output_sec_buffer_desc.pBuffers = &output_sec_buffer;
output_sec_buffer.cbBuffer = cbMaxLen;
output_sec_buffer.BufferType = SECBUFFER_TOKEN;
output_sec_buffer.pvBuffer = output_buffer;
status = table->InitializeSecurityContext(&credentials, NULL, NULL, fContextReq, 0, 0, NULL, 0,
&context, &output_sec_buffer_desc, &pfContextAttr, &expiration);
if (status != SEC_I_CONTINUE_NEEDED)
{
printf("InitializeSecurityContext status: 0x%08X\n", status);
return 0;
}
p_sec_buffer = &output_sec_buffer_desc.pBuffers[0];
freerdp_hexdump((uint8*) p_sec_buffer->pvBuffer, p_sec_buffer->cbBuffer);
credssp->negoToken.data = p_sec_buffer->pvBuffer;
credssp->negoToken.length = p_sec_buffer->cbBuffer;
/* NTLMSSP NEGOTIATE MESSAGE */
credssp_send(credssp, &credssp->negoToken, NULL, NULL);
printf("sent NTLMSSP_NEGOTIATE_MESSAGE\n");
/* NTLMSSP CHALLENGE MESSAGE */
if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
return -1;
printf("received NTLM CHALLENGE MESSAGE\n");
input_sec_buffer_desc.ulVersion = 0;
input_sec_buffer_desc.cBuffers = 1;
input_sec_buffer_desc.pBuffers = &input_sec_buffer;
input_sec_buffer.cbBuffer = credssp->negoToken.length;
input_sec_buffer.BufferType = SECBUFFER_TOKEN;
input_sec_buffer.pvBuffer = credssp->negoToken.data;
output_sec_buffer_desc.ulVersion = 0;
output_sec_buffer_desc.cBuffers = 1;
output_sec_buffer_desc.pBuffers = &output_sec_buffer;
output_sec_buffer.cbBuffer = cbMaxLen;
output_sec_buffer.BufferType = SECBUFFER_TOKEN;
output_sec_buffer.pvBuffer = output_buffer;
printf("Second Call to InitializeSecurityContext()\n");
status = table->InitializeSecurityContext(&credentials, &context, NULL, fContextReq, 0, 0,
&input_sec_buffer_desc, 0, &context, &output_sec_buffer_desc, &pfContextAttr, &expiration);
if (status != SEC_I_CONTINUE_NEEDED)
{
printf("InitializeSecurityContext status: 0x%08X\n", status);
return 0;
}
FreeCredentialsHandle(&credentials);
FreeContextBuffer(pPackageInfo);
return 1;
}
#endif
/**
* Authenticate with client using CredSSP (server).
* @param credssp

View File

@ -185,6 +185,18 @@ void sspi_CredentialsFree(CREDENTIALS* credentials)
xfree(credentials);
}
void sspi_SecBufferAlloc(SEC_BUFFER* sec_buffer, size_t size)
{
sec_buffer->cbBuffer = size;
sec_buffer->pvBuffer = xzalloc(size);
}
void sspi_SecBufferFree(SEC_BUFFER* sec_buffer)
{
sec_buffer->cbBuffer = 0;
xfree(sec_buffer->pvBuffer);
}
SEC_HANDLE* sspi_SecureHandleAlloc()
{
SEC_HANDLE* handle = xmalloc(sizeof(SEC_HANDLE));

View File

@ -32,6 +32,9 @@ typedef struct _CREDENTIALS CREDENTIALS;
CREDENTIALS* sspi_CredentialsNew();
void sspi_CredentialsFree(CREDENTIALS* credentials);
void sspi_SecBufferAlloc(SEC_BUFFER* sec_buffer, size_t size);
void sspi_SecBufferFree(SEC_BUFFER* sec_buffer);
SEC_HANDLE* sspi_SecureHandleAlloc();
void sspi_SecureHandleInit(SEC_HANDLE* handle);
void sspi_SecureHandleInvalidate(SEC_HANDLE* handle);