Merge pull request #897 from awakecoding/master

Schannel Improvements + RemoteFX Fix
This commit is contained in:
Marc-André Moreau 2013-01-14 12:24:39 -08:00
commit 912d9e8f26
19 changed files with 429 additions and 178 deletions

View File

@ -520,7 +520,7 @@ void wf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
wf_invalidate_region(wfi, surface_bits_command->destLeft, surface_bits_command->destTop,
surface_bits_command->width, surface_bits_command->height);
}
else if (surface_bits_command->codecID == CODEC_ID_NONE)
else if (surface_bits_command->codecID == RDP_CODEC_ID_NONE)
{
ZeroMemory(&bitmap_info, sizeof(bitmap_info));
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

View File

@ -230,7 +230,7 @@ static BOOL fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32
break;
case FASTPATH_UPDATETYPE_SURFCMDS:
if (!update_recv_surfcmds(update, size, s))
if (update_recv_surfcmds(update, size, s) < 0)
return FALSE;
break;

View File

@ -119,7 +119,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc)
{
if (rpc->VirtualConnection->State >= VIRTUAL_CONNECTION_STATE_OPENED)
{
printf("Receiving Out-of-Sequence RTS PDU\n");
//printf("Receiving Out-of-Sequence RTS PDU\n");
rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length);
rpc_client_fragment_pool_return(rpc, fragment);

View File

@ -841,9 +841,11 @@ int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
offset += rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset,
&BytesReceived, &AvailableWindow, (BYTE*) &ChannelCookie) + 4;
#if 0
printf("BytesReceived: %d AvailableWindow: %d\n",
BytesReceived, AvailableWindow);
printf("ChannelCookie: " RPC_UUID_FORMAT_STRING "\n", RPC_UUID_FORMAT_ARGUMENTS(ChannelCookie));
#endif
rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
@ -880,9 +882,11 @@ int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buffer, UI
offset += rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset,
&BytesReceived, &AvailableWindow, (BYTE*) &ChannelCookie) + 4;
#if 0
printf("Destination: %d BytesReceived: %d AvailableWindow: %d\n",
Destination, BytesReceived, AvailableWindow);
printf("ChannelCookie: " RPC_UUID_FORMAT_STRING "\n", RPC_UUID_FORMAT_ARGUMENTS(ChannelCookie));
#endif
rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
@ -999,7 +1003,6 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
rts = (rpcconn_rts_hdr_t*) buffer;
rts_extract_pdu_signature(rpc, &signature, rts);
rts_print_pdu_signature(rpc, &signature);
SignatureId = rts_identify_pdu_signature(rpc, &signature, NULL);
if (SignatureId == RTS_PDU_FLOW_CONTROL_ACK)
@ -1017,6 +1020,7 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
else
{
printf("Unimplemented signature id: 0x%08X\n", SignatureId);
rts_print_pdu_signature(rpc, &signature);
}
return 0;

View File

@ -181,8 +181,11 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg)
*
* Using reduced capabilities appears to trigger
* TSG_PACKET_TYPE_QUARENC_RESPONSE instead of TSG_PACKET_TYPE_CAPS_RESPONSE
*
* However, reduced capabilities may break connectivity with servers enforcing features, such as
* "Only allow connections from Remote Desktop Services clients that support RD Gateway messaging"
*/
NapCapabilities = TSG_NAP_CAPABILITY_IDLE_TIMEOUT;
//NapCapabilities = TSG_NAP_CAPABILITY_IDLE_TIMEOUT;
*((UINT32*) &buffer[44]) = NapCapabilities; /* capabilities */

View File

@ -85,7 +85,7 @@ BOOL nego_connect(rdpNego* nego)
nego->state = NEGO_STATE_FAIL;
}
if (!nego->NegotiateSecurityLayer_enabled)
if (!nego->NegotiateSecurityLayer)
{
DEBUG_NEGO("Security Layer Negotiation is disabled");
/* attempt only the highest enabled protocol (see nego_attempt_*) */
@ -222,7 +222,7 @@ BOOL nego_transport_connect(rdpNego* nego)
{
nego_tcp_connect(nego);
if (nego->tcp_connected && !nego->NegotiateSecurityLayer_enabled)
if (nego->tcp_connected && !nego->NegotiateSecurityLayer)
return nego_security_connect(nego);
return nego->tcp_connected;
@ -947,10 +947,10 @@ void nego_set_target(rdpNego* nego, char* hostname, int port)
* @param enable_rdp whether to enable security layer negotiation (TRUE for enabled, FALSE for disabled)
*/
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer_enabled)
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer)
{
DEBUG_NEGO("Enabling security layer negotiation: %s", NegotiateSecurityLayer_enabled ? "TRUE" : "FALSE");
nego->NegotiateSecurityLayer_enabled = NegotiateSecurityLayer_enabled;
DEBUG_NEGO("Enabling security layer negotiation: %s", NegotiateSecurityLayer ? "TRUE" : "FALSE");
nego->NegotiateSecurityLayer = NegotiateSecurityLayer;
}
/**

View File

@ -100,7 +100,7 @@ struct rdp_nego
UINT32 selected_protocol;
UINT32 requested_protocols;
BOOL NegotiateSecurityLayer_enabled;
BOOL NegotiateSecurityLayer;
BYTE enabled_protocols[16];
rdpTransport* transport;

View File

@ -153,8 +153,8 @@ BOOL transport_connect_nla(rdpTransport* transport)
if (credssp_authenticate(transport->credssp) < 0)
{
if (!connectErrorCode)
connectErrorCode = AUTHENTICATIONERROR;
if (!connectErrorCode)
connectErrorCode = AUTHENTICATIONERROR;
printf("Authentication failure, check credentials.\n"
"If credentials are valid, the NTLMSSP implementation may be to blame.\n");

View File

@ -59,50 +59,6 @@ static void tls_free_certificate(CryptoCert cert)
free(cert);
}
static void tls_md5_update_uint32_be(MD5_CTX* md5, UINT32 num)
{
BYTE be32[4];
be32[0] = (num >> 0) & 0xFF;
be32[1] = (num >> 8) & 0xFF;
be32[2] = (num >> 16) & 0xFF;
be32[3] = (num >> 24) & 0xFF;
MD5_Update(md5, be32, 4);
}
BYTE* tls_get_channel_bindings_hash(SecPkgContext_Bindings* Bindings)
{
MD5_CTX md5;
BYTE* ChannelBindingToken;
UINT32 ChannelBindingTokenLength;
BYTE* ChannelBindingsHash;
UINT32 ChannelBindingsHashLength;
SEC_CHANNEL_BINDINGS* ChannelBindings;
ChannelBindings = Bindings->Bindings;
ChannelBindingTokenLength = Bindings->BindingsLength - sizeof(SEC_CHANNEL_BINDINGS);
ChannelBindingToken = &((BYTE*) ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
ChannelBindingsHashLength = 16;
ChannelBindingsHash = (BYTE*) malloc(ChannelBindingsHashLength);
ZeroMemory(ChannelBindingsHash, ChannelBindingsHashLength);
MD5_Init(&md5);
tls_md5_update_uint32_be(&md5, ChannelBindings->dwInitiatorAddrType);
tls_md5_update_uint32_be(&md5, ChannelBindings->cbInitiatorLength);
tls_md5_update_uint32_be(&md5, ChannelBindings->dwAcceptorAddrType);
tls_md5_update_uint32_be(&md5, ChannelBindings->cbAcceptorLength);
tls_md5_update_uint32_be(&md5, ChannelBindings->cbApplicationDataLength);
MD5_Update(&md5, (void*) ChannelBindingToken, ChannelBindingTokenLength);
MD5_Final(ChannelBindingsHash, &md5);
return ChannelBindingsHash;
}
#define TLS_SERVER_END_POINT "tls-server-end-point:"
SecPkgContext_Bindings* tls_get_channel_bindings(X509* cert)

View File

@ -30,5 +30,20 @@ typedef struct _LSA_UNICODE_STRING
PWSTR Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
/**
* Windows Integrity Mechanism Design:
* http://msdn.microsoft.com/en-us/library/bb625963.aspx
*/
#ifndef _WIN32
#define SECURITY_MANDATORY_UNTRUSTED_RID 0x0000
#define SECURITY_MANDATORY_LOW_RID 0x1000
#define SECURITY_MANDATORY_MEDIUM_RID 0x2000
#define SECURITY_MANDATORY_HIGH_RID 0x3000
#define SECURITY_MANDATORY_SYSTEM_RID 0x4000
#endif
#endif /* WINPR_SECURITY_H */

View File

@ -112,6 +112,7 @@ NTLM_CONTEXT* ntlm_ContextNew()
context->NTLMv2 = TRUE;
context->UseMIC = FALSE;
context->SendVersionInfo = TRUE;
context->SendSingleHostData = FALSE;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
@ -126,6 +127,9 @@ NTLM_CONTEXT* ntlm_ContextNew()
if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
context->SendVersionInfo = dwValue ? 1 : 0;
if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
context->SendSingleHostData = dwValue ? 1 : 0;
RegCloseKey(hKey);
}
@ -337,9 +341,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
if (pInput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
input_buffer = &pInput->pBuffers[0];
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
if (input_buffer->BufferType != SECBUFFER_TOKEN)
if (!input_buffer)
return SEC_E_INVALID_TOKEN;
if (input_buffer->cbBuffer < 1)
@ -355,9 +359,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
if (pOutput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
output_buffer = &pOutput->pBuffers[0];
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
if (output_buffer->BufferType != SECBUFFER_TOKEN)
if (!output_buffer->BufferType)
return SEC_E_INVALID_TOKEN;
if (output_buffer->cbBuffer < 1)
@ -376,9 +380,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
if (pInput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
input_buffer = &pInput->pBuffers[0];
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
if (input_buffer->BufferType != SECBUFFER_TOKEN)
if (!input_buffer)
return SEC_E_INVALID_TOKEN;
if (input_buffer->cbBuffer < 1)
@ -450,9 +454,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
if (pOutput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
output_buffer = &pOutput->pBuffers[0];
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
if (output_buffer->BufferType != SECBUFFER_TOKEN)
if (!output_buffer)
return SEC_E_INVALID_TOKEN;
if (output_buffer->cbBuffer < 1)
@ -471,19 +475,15 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
if (pInput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
input_buffer = &pInput->pBuffers[0];
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
if (input_buffer->BufferType != SECBUFFER_TOKEN)
if (!input_buffer)
return SEC_E_INVALID_TOKEN;
if (input_buffer->cbBuffer < 1)
return SEC_E_INVALID_TOKEN;
if (pInput->cBuffers > 1)
{
if (pInput->pBuffers[1].BufferType == SECBUFFER_CHANNEL_BINDINGS)
channel_bindings = &pInput->pBuffers[1];
}
channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
if (channel_bindings)
{
@ -501,9 +501,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
if (pOutput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
output_buffer = &pOutput->pBuffers[0];
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
if (output_buffer->BufferType != SECBUFFER_TOKEN)
if (!output_buffer)
return SEC_E_INVALID_TOKEN;
if (output_buffer->cbBuffer < 1)

View File

@ -92,7 +92,7 @@ enum _NTLM_AV_ID
MsvAvDnsTreeName,
MsvAvFlags,
MsvAvTimestamp,
MsvAvRestrictions,
MsvAvSingleHost,
MsvAvTargetName,
MsvChannelBindings
};
@ -126,15 +126,15 @@ struct _NTLM_VERSION_INFO
};
typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO;
struct _NTLM_RESTRICTION_ENCODING
struct _NTLM_SINGLE_HOST_DATA
{
UINT32 Size;
UINT32 Z4;
UINT32 IntegrityLevel;
UINT32 SubjectIntegrityLevel;
UINT32 DataPresent;
UINT32 CustomData;
BYTE MachineID[32];
};
typedef struct _NTLM_RESTRICTION_ENCODING NTLM_RESTRICTION_ENCODING;
typedef struct _NTLM_SINGLE_HOST_DATA NTLM_SINGLE_HOST_DATA;
struct _NTLM_RESPONSE
{
@ -244,6 +244,8 @@ struct _NTLM_CONTEXT
BYTE* ChannelBindingToken;
BYTE ChannelBindingsHash[16];
SecPkgContext_Bindings Bindings;
BOOL SendSingleHostData;
NTLM_SINGLE_HOST_DATA SingleHostData;
SecBuffer NegotiateMessage;
SecBuffer ChallengeMessage;
SecBuffer AuthenticateMessage;

View File

@ -279,6 +279,24 @@ void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
MD5_Final(context->ChannelBindingsHash, &md5);
}
void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
{
/**
* The Single_Host_Data structure allows a client to send machine-specific information
* within an authentication exchange to services on the same machine. The client can
* produce additional information to be processed in an implementation-specific way when
* the client and server are on the same host. If the server and client platforms are
* different or if they are on different hosts, then the information MUST be ignored.
* Any fields after the MachineID field MUST be ignored on receipt.
*/
context->SingleHostData.Size = 48;
context->SingleHostData.Z4 = 0;
context->SingleHostData.DataPresent = 1;
context->SingleHostData.CustomData = SECURITY_MANDATORY_MEDIUM_RID;
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
}
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
{
int length;
@ -390,8 +408,12 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
AvPairsValueLength += 4;
}
//AvPairsCount++; /* MsvAvRestrictions */
//AvPairsValueLength += 48;
if (context->SendSingleHostData)
{
AvPairsCount++; /* MsvAvSingleHost */
ntlm_compute_single_host_data(context);
AvPairsValueLength += context->SingleHostData.Size;
}
/**
* Extended Protection for Authentication:
@ -450,6 +472,12 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvFlags, (PBYTE) &flags, 4);
}
if (context->SendSingleHostData)
{
ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvSingleHost,
(PBYTE) &context->SingleHostData, context->SingleHostData.Size);
}
if (!context->SuppressExtendedProtection)
{
ntlm_av_pair_add(AuthenticateTargetInfo, MsvChannelBindings, context->ChannelBindingsHash, 16);

View File

@ -228,13 +228,11 @@ SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(PCredHandle phCred
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) SCHANNEL_PACKAGE_NAME);
schannel_openssl_client_init(context->openssl);
status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
return status;
}
return SEC_E_OK;
status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
return status;
}
SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
@ -267,6 +265,7 @@ SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(PCredHandle phCredentia
SCHANNEL_CONTEXT* context;
SCHANNEL_CREDENTIALS* credentials;
status = SEC_E_OK;
context = (SCHANNEL_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
if (!context)
@ -284,13 +283,11 @@ SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(PCredHandle phCredentia
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) SCHANNEL_PACKAGE_NAME);
schannel_openssl_server_init(context->openssl);
status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
return status;
}
return SEC_E_OK;
status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
return status;
}
SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
@ -342,12 +339,22 @@ SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(PCtxtHandle phContext, PSecBu
SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
{
return SEC_E_OK;
SECURITY_STATUS status;
SCHANNEL_CONTEXT* context;
context = (SCHANNEL_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
if (!context)
return SEC_E_INVALID_HANDLE;
status = schannel_openssl_encrypt_message(context->openssl, pMessage);
return status;
}
SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
{
return SEC_E_OK;
return SEC_E_UNSUPPORTED_FUNCTION;
}
const SecurityFunctionTableA SCHANNEL_SecurityFunctionTableA =

View File

@ -138,7 +138,8 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
int status;
long options = 0;
context->ctx = SSL_CTX_new(SSLv23_server_method());
//context->ctx = SSL_CTX_new(SSLv23_server_method());
context->ctx = SSL_CTX_new(TLSv1_server_method());
if (!context->ctx)
{
@ -185,6 +186,12 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
SSL_CTX_set_options(context->ctx, options);
if (SSL_CTX_use_RSAPrivateKey_file(context->ctx, "/tmp/localhost.key", SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_RSAPrivateKey_file failed\n");
return -1;
}
context->ssl = SSL_new(context->ctx);
if (!context->ssl)
@ -193,12 +200,6 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
return -1;
}
if (SSL_CTX_use_RSAPrivateKey_file(context->ctx, "/tmp/localhost.key", SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_RSAPrivateKey_file failed\n");
return -1;
}
if (SSL_use_certificate_file(context->ssl, "/tmp/localhost.crt", SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_use_certificate_file failed\n");
@ -248,9 +249,9 @@ SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context
if (pInput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
pBuffer = &pInput->pBuffers[0];
pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
if (pBuffer->BufferType != SECBUFFER_TOKEN)
if (!pBuffer)
return SEC_E_INVALID_TOKEN;
status = BIO_write(context->bioRead, pBuffer->pvBuffer, pBuffer->cbBuffer);
@ -266,26 +267,29 @@ SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context
status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
if (status >= 0)
{
winpr_HexDump(context->ReadBuffer, status);
}
if (pOutput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
pBuffer = &pOutput->pBuffers[0];
pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
if (pBuffer->BufferType != SECBUFFER_TOKEN)
if (!pBuffer)
return SEC_E_INVALID_TOKEN;
if (pBuffer->cbBuffer < status)
return SEC_E_INSUFFICIENT_MEMORY;
if (status > 0)
{
if (pBuffer->cbBuffer < status)
return SEC_E_INSUFFICIENT_MEMORY;
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
pBuffer->cbBuffer = status;
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
pBuffer->cbBuffer = status;
return SEC_I_CONTINUE_NEEDED;
return SEC_I_CONTINUE_NEEDED;
}
else
{
pBuffer->cbBuffer = 0;
return SEC_E_OK;
}
}
return SEC_E_OK;
@ -302,12 +306,11 @@ SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context
if (pInput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
pBuffer = &pInput->pBuffers[0];
pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
if (pBuffer->BufferType != SECBUFFER_TOKEN)
if (!pBuffer)
return SEC_E_INVALID_TOKEN;
printf("Server input: %ld\n", pBuffer->cbBuffer);
status = BIO_write(context->bioRead, pBuffer->pvBuffer, pBuffer->cbBuffer);
status = SSL_accept(context->ssl);
@ -320,31 +323,76 @@ SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context
status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
if (status >= 0)
{
winpr_HexDump(context->ReadBuffer, status);
}
if (pOutput->cBuffers < 1)
return SEC_E_INVALID_TOKEN;
pBuffer = &pOutput->pBuffers[0];
pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
if (pBuffer->BufferType != SECBUFFER_TOKEN)
if (!pBuffer)
return SEC_E_INVALID_TOKEN;
if (pBuffer->cbBuffer < status)
return SEC_E_INSUFFICIENT_MEMORY;
if (status > 0)
{
if (pBuffer->cbBuffer < status)
return SEC_E_INSUFFICIENT_MEMORY;
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
pBuffer->cbBuffer = status;
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
pBuffer->cbBuffer = status;
return SEC_I_CONTINUE_NEEDED;
return SEC_I_CONTINUE_NEEDED;
}
else
{
pBuffer->cbBuffer = 0;
return SEC_E_OK;
}
}
return SEC_E_OK;
}
SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
{
int status;
int ssl_error;
PSecBuffer pStreamBodyBuffer;
PSecBuffer pStreamHeaderBuffer;
PSecBuffer pStreamTrailerBuffer;
pStreamHeaderBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_HEADER);
pStreamBodyBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
pStreamTrailerBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_TRAILER);
if ((!pStreamHeaderBuffer) || (!pStreamBodyBuffer) || (!pStreamTrailerBuffer))
return SEC_E_INVALID_TOKEN;
status = SSL_write(context->ssl, pStreamBodyBuffer->pvBuffer, pStreamBodyBuffer->cbBuffer);
if (status < 0)
{
ssl_error = SSL_get_error(context->ssl, status);
printf("SSL_write: %s\n", openssl_get_ssl_error_string(ssl_error));
}
status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
return SEC_E_UNSUPPORTED_FUNCTION;
}
SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
{
//int status;
//int ssl_error;
PSecBuffer pBuffer;
pBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
if (!pBuffer)
return SEC_E_INVALID_TOKEN;
return SEC_E_UNSUPPORTED_FUNCTION;
}
SCHANNEL_OPENSSL* schannel_openssl_new()
{
SCHANNEL_OPENSSL* context;

View File

@ -49,6 +49,9 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context);
SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context, PSecBufferDesc pInput, PSecBufferDesc pOutput);
SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context, PSecBufferDesc pInput, PSecBufferDesc pOutput);
SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage);
SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage);
SCHANNEL_OPENSSL* schannel_openssl_new();
void schannel_openssl_free(SCHANNEL_OPENSSL* context);

View File

@ -371,6 +371,23 @@ void sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDE
}
}
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType)
{
int index;
PSecBuffer pSecBuffer = NULL;
for (index = 0; index < pMessage->cBuffers; index++)
{
if (pMessage->pBuffers[index].BufferType == BufferType)
{
pSecBuffer = &pMessage->pBuffers[index];
break;
}
}
return pSecBuffer;
}
static BOOL sspi_initialized = FALSE;
void sspi_GlobalInit()

View File

@ -33,6 +33,8 @@ typedef struct _CREDENTIALS CREDENTIALS;
CREDENTIALS* sspi_CredentialsNew();
void sspi_CredentialsFree(CREDENTIALS* credentials);
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType);
SecHandle* sspi_SecureHandleAlloc();
void sspi_SecureHandleInit(SecHandle* handle);
void sspi_SecureHandleInvalidate(SecHandle* handle);

View File

@ -10,8 +10,6 @@
#include <winpr/crypto.h>
#include <winpr/schannel.h>
HANDLE g_ClientEvent = NULL;
HANDLE g_ServerEvent = NULL;
BOOL g_ClientWait = FALSE;
BOOL g_ServerWait = FALSE;
@ -20,6 +18,145 @@ HANDLE g_ClientWritePipe = NULL;
HANDLE g_ServerReadPipe = NULL;
HANDLE g_ServerWritePipe = NULL;
BYTE test_DummyMessage[64] =
{
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD
};
int schannel_send(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phContext, BYTE* buffer, UINT32 length)
{
BYTE* ioBuffer;
UINT32 ioBufferLength;
BYTE* pMessageBuffer;
SecBuffer Buffers[4];
SecBufferDesc Message;
SECURITY_STATUS status;
DWORD NumberOfBytesWritten;
SecPkgContext_StreamSizes StreamSizes;
ZeroMemory(&StreamSizes, sizeof(SecPkgContext_StreamSizes));
status = table->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &StreamSizes);
ioBufferLength = StreamSizes.cbHeader + StreamSizes.cbMaximumMessage + StreamSizes.cbTrailer;
ioBuffer = (BYTE*) malloc(ioBufferLength);
ZeroMemory(ioBuffer, ioBufferLength);
pMessageBuffer = ioBuffer + StreamSizes.cbHeader;
CopyMemory(pMessageBuffer, buffer, length);
Buffers[0].pvBuffer = ioBuffer;
Buffers[0].cbBuffer = StreamSizes.cbHeader;
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
Buffers[1].pvBuffer = pMessageBuffer;
Buffers[1].cbBuffer = length;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[2].pvBuffer = pMessageBuffer + length;
Buffers[2].cbBuffer = StreamSizes.cbTrailer;
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
Buffers[3].pvBuffer = NULL;
Buffers[3].cbBuffer = 0;
Buffers[3].BufferType = SECBUFFER_EMPTY;
Message.ulVersion = SECBUFFER_VERSION;
Message.cBuffers = 4;
Message.pBuffers = Buffers;
ioBufferLength = Message.pBuffers[0].cbBuffer + Message.pBuffers[1].cbBuffer + Message.pBuffers[2].cbBuffer;
status = table->EncryptMessage(phContext, 0, &Message, 0);
printf("EncryptMessage status: 0x%08X\n", status);
printf("EncryptMessage output: cBuffers: %d [0]: %d / %d [1]: %d / %d [2]: %d / %d [3]: %d / %d\n", Message.cBuffers,
Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType);
if (status != SEC_E_OK)
return -1;
printf("Client > Server (%d)\n", ioBufferLength);
winpr_HexDump(ioBuffer, ioBufferLength);
if (!WriteFile(hPipe, ioBuffer, ioBufferLength, &NumberOfBytesWritten, NULL))
{
printf("schannel_send: failed to write to pipe\n");
return -1;
}
return 0;
}
int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phContext)
{
BYTE* ioBuffer;
UINT32 ioBufferLength;
BYTE* pMessageBuffer;
SecBuffer Buffers[4];
SecBufferDesc Message;
SECURITY_STATUS status;
DWORD NumberOfBytesRead;
SecPkgContext_StreamSizes StreamSizes;
ZeroMemory(&StreamSizes, sizeof(SecPkgContext_StreamSizes));
status = table->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &StreamSizes);
ioBufferLength = StreamSizes.cbHeader + StreamSizes.cbMaximumMessage + StreamSizes.cbTrailer;
ioBuffer = (BYTE*) malloc(ioBufferLength);
ZeroMemory(ioBuffer, ioBufferLength);
if (!ReadFile(hPipe, ioBuffer, ioBufferLength, &NumberOfBytesRead, NULL))
{
printf("schannel_recv: failed to read from pipe\n");
return -1;
}
Buffers[0].pvBuffer = ioBuffer;
Buffers[0].cbBuffer = NumberOfBytesRead;
Buffers[0].BufferType = SECBUFFER_DATA;
Buffers[1].pvBuffer = NULL;
Buffers[1].cbBuffer = 0;
Buffers[1].BufferType = SECBUFFER_EMPTY;
Buffers[2].pvBuffer = NULL;
Buffers[2].cbBuffer = 0;
Buffers[2].BufferType = SECBUFFER_EMPTY;
Buffers[3].pvBuffer = NULL;
Buffers[3].cbBuffer = 0;
Buffers[3].BufferType = SECBUFFER_EMPTY;
Message.ulVersion = SECBUFFER_VERSION;
Message.cBuffers = 4;
Message.pBuffers = Buffers;
status = table->DecryptMessage(phContext, &Message, 0, NULL);
printf("DecryptMessage status: 0x%08X\n", status);
printf("DecryptMessage output: cBuffers: %d [0]: %d / %d [1]: %d / %d [2]: %d / %d [3]: %d / %d\n", Message.cBuffers,
Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType);
if (status != SEC_E_OK)
return -1;
printf("Decrypted Message (%d)\n", Message.pBuffers[1].cbBuffer);
winpr_HexDump((BYTE*) Message.pBuffers[1].pvBuffer, Message.pBuffers[1].cbBuffer);
return 0;
}
static void* schannel_test_server_thread(void* arg)
{
BOOL extraData;
@ -72,7 +209,11 @@ static void* schannel_test_server_thread(void* arg)
//return NULL;
}
#ifdef CERT_FIND_HAS_PRIVATE_KEY
pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HAS_PRIVATE_KEY, NULL, NULL);
#else
pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL);
#endif
if (!pCertContext)
{
@ -110,6 +251,8 @@ static void* schannel_test_server_thread(void* arg)
}
extraData = FALSE;
g_ServerWait = TRUE;
lpTokenIn = (BYTE*) malloc(cbMaxToken);
lpTokenOut = (BYTE*) malloc(cbMaxToken);
@ -121,9 +264,6 @@ static void* schannel_test_server_thread(void* arg)
{
if (!extraData)
{
WaitForSingleObject(g_ServerEvent, INFINITE);
ResetEvent(g_ServerEvent);
if (g_ServerWait)
{
if (!ReadFile(g_ServerReadPipe, lpTokenIn, cbMaxToken, &NumberOfBytesRead, NULL))
@ -137,10 +277,9 @@ static void* schannel_test_server_thread(void* arg)
NumberOfBytesRead = 0;
}
}
extraData = FALSE;
printf("Server Received %d bytes:\n", NumberOfBytesRead);
winpr_HexDump(lpTokenIn, NumberOfBytesRead);
extraData = FALSE;
g_ServerWait = TRUE;
SecBuffer_in[0].BufferType = SECBUFFER_TOKEN;
SecBuffer_in[0].pvBuffer = lpTokenIn;
@ -165,13 +304,7 @@ static void* schannel_test_server_thread(void* arg)
status = table->AcceptSecurityContext(&credentials, SecIsValidHandle(&context) ? &context : NULL,
&SecBufferDesc_in, fContextReq, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry);
if (status == SEC_E_OK)
{
printf("AcceptSecurityContext SEC_E_OK, TLS connection complete\n");
break;
}
if ((status != SEC_I_CONTINUE_NEEDED) && (status != SEC_E_INCOMPLETE_MESSAGE))
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED) && (status != SEC_E_INCOMPLETE_MESSAGE))
{
printf("AcceptSecurityContext unexpected status: 0x%08X\n", status);
return NULL;
@ -179,7 +312,9 @@ static void* schannel_test_server_thread(void* arg)
NumberOfBytesWritten = 0;
if (status == SEC_I_CONTINUE_NEEDED)
if (status == SEC_E_OK)
printf("AcceptSecurityContext status: SEC_E_OK\n");
else if (status == SEC_I_CONTINUE_NEEDED)
printf("AcceptSecurityContext status: SEC_I_CONTINUE_NEEDED\n");
else if (status == SEC_E_INCOMPLETE_MESSAGE)
printf("AcceptSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
@ -201,27 +336,35 @@ static void* schannel_test_server_thread(void* arg)
if (status != SEC_E_INCOMPLETE_MESSAGE)
{
pSecBuffer = &SecBufferDesc_out.pBuffers[0];
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
g_ClientWait = TRUE;
SetEvent(g_ClientEvent);
if (!WriteFile(g_ClientWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
if (pSecBuffer->cbBuffer > 0)
{
printf("failed to write to client pipe\n");
return NULL;
printf("Server > Client (%d)\n", pSecBuffer->cbBuffer);
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
if (!WriteFile(g_ClientWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
{
printf("failed to write to client pipe\n");
return NULL;
}
}
}
else
{
g_ClientWait = FALSE;
SetEvent(g_ClientEvent);
}
printf("Server wrote %d bytes\n", NumberOfBytesWritten);
if (status == SEC_E_OK)
{
printf("Server Handshake Complete\n");
break;
}
}
while (1);
do
{
if (schannel_recv(table, g_ServerReadPipe, &context) < 0)
break;
}
while(1);
return NULL;
}
@ -255,9 +398,6 @@ int TestSchannel(int argc, char* argv[])
sspi_GlobalInit();
g_ClientEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
g_ServerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
SecInvalidateHandle(&context);
SecInvalidateHandle(&credentials);
@ -377,13 +517,9 @@ int TestSchannel(int argc, char* argv[])
ZeroMemory(&SecBufferDesc_out, sizeof(SecBufferDesc));
g_ClientWait = FALSE;
SetEvent(g_ClientEvent);
do
{
WaitForSingleObject(g_ClientEvent, INFINITE);
ResetEvent(g_ClientEvent);
if (g_ClientWait)
{
if (!ReadFile(g_ClientReadPipe, lpTokenIn, cbMaxToken, &NumberOfBytesRead, NULL))
@ -397,6 +533,7 @@ int TestSchannel(int argc, char* argv[])
NumberOfBytesRead = 0;
}
g_ClientWait = TRUE;
printf("NumberOfBytesRead: %d\n", NumberOfBytesRead);
SecBuffer_in[0].BufferType = SECBUFFER_TOKEN;
@ -422,7 +559,7 @@ int TestSchannel(int argc, char* argv[])
status = table->InitializeSecurityContext(&credentials, SecIsValidHandle(&context) ? &context : NULL, _T("localhost"),
fContextReq, 0, 0, &SecBufferDesc_in, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry);
if ((status != SEC_I_CONTINUE_NEEDED) && (status != SEC_E_INCOMPLETE_MESSAGE))
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED) && (status != SEC_E_INCOMPLETE_MESSAGE))
{
printf("InitializeSecurityContext unexpected status: 0x%08X\n", status);
return -1;
@ -430,7 +567,9 @@ int TestSchannel(int argc, char* argv[])
NumberOfBytesWritten = 0;
if (status == SEC_I_CONTINUE_NEEDED)
if (status == SEC_E_OK)
printf("InitializeSecurityContext status: SEC_E_OK\n");
else if (status == SEC_I_CONTINUE_NEEDED)
printf("InitializeSecurityContext status: SEC_I_CONTINUE_NEEDED\n");
else if (status == SEC_E_INCOMPLETE_MESSAGE)
printf("InitializeSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
@ -443,24 +582,51 @@ int TestSchannel(int argc, char* argv[])
if (status != SEC_E_INCOMPLETE_MESSAGE)
{
pSecBuffer = &SecBufferDesc_out.pBuffers[0];
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
g_ServerWait = TRUE;
SetEvent(g_ServerEvent);
if (!WriteFile(g_ServerWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
if (pSecBuffer->cbBuffer > 0)
{
printf("failed to write to server pipe\n");
return -1;
printf("Client > Server (%d)\n", pSecBuffer->cbBuffer);
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
if (!WriteFile(g_ServerWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
{
printf("failed to write to server pipe\n");
return -1;
}
}
}
else
if (status == SEC_E_OK)
{
g_ServerWait = FALSE;
SetEvent(g_ServerEvent);
printf("Client Handshake Complete\n");
break;
}
}
while(1);
do
{
if (schannel_send(table, g_ServerWritePipe, &context, test_DummyMessage, sizeof(test_DummyMessage)) < 0)
break;
for (index = 0; index < sizeof(test_DummyMessage); index++)
{
BYTE b, ln, hn;
b = test_DummyMessage[index];
ln = (b & 0x0F);
hn = ((b & 0xF0) >> 4);
ln = (ln + 1) % 0xF;
hn = (ln + 1) % 0xF;
b = (ln | (hn << 4));
test_DummyMessage[index] = b;
}
printf("Client wrote %d bytes\n", NumberOfBytesWritten);
Sleep(1000 * 10);
}
while(1);