Merge pull request #1562 from dbungert/tlstls

Enable NLA and TLS negotiation with Gateway
This commit is contained in:
Marc-André Moreau 2013-10-28 17:11:10 -07:00
commit c44591d363
9 changed files with 185 additions and 22 deletions

View File

@ -832,6 +832,10 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
if (file->GatewayUsageMethod == TSC_PROXY_MODE_DIRECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DETECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DEFAULT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
}

View File

@ -39,9 +39,12 @@ typedef struct rdp_tls rdpTls;
struct rdp_tls
{
SSL* ssl;
BIO* bio;
void* tsg;
int sockfd;
SSL_CTX* ctx;
BYTE* PublicKey;
BIO_METHOD* methods;
DWORD PublicKeyLength;
rdpSettings* settings;
SecPkgContext_Bindings* Bindings;

View File

@ -209,14 +209,6 @@ BOOL rdp_client_connect(rdpRdp* rdp)
nego_set_cookie(rdp->nego, cookie);
free(cookie);
settings->RdpSecurity = TRUE;
settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE;
//settings->TlsSecurity = TRUE;
//settings->NlaSecurity = TRUE;
}
else
{

View File

@ -161,7 +161,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc)
if (StubLength == 4)
{
//fprintf(stderr, "Ignoring TsProxySendToServer Response\n");
printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id);
//printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id);
/* received a disconnect request from the server? */
if ((header->common.call_id == rpc->PipeCallId) && (header->common.pfc_flags & PFC_LAST_FRAG))

View File

@ -43,11 +43,16 @@ static const char* const NEGO_STATE_STRINGS[] =
"NEGO_STATE_FINAL"
};
static const char PROTOCOL_SECURITY_STRINGS[4][4] =
static const char PROTOCOL_SECURITY_STRINGS[9][4] =
{
"RDP",
"TLS",
"NLA",
"UNK",
"UNK",
"UNK",
"UNK",
"UNK",
"EXT"
};

View File

@ -137,8 +137,18 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
(char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password);
#endif
sspi_SecBufferAlloc(&credssp->PublicKey, credssp->transport->TlsIn->PublicKeyLength);
CopyMemory(credssp->PublicKey.pvBuffer, credssp->transport->TlsIn->PublicKey, credssp->transport->TlsIn->PublicKeyLength);
rdpTls *tls = NULL;
if(credssp->transport->layer == TRANSPORT_LAYER_TLS) {
tls = credssp->transport->TlsIn;
} else if(credssp->transport->layer == TRANSPORT_LAYER_TSG_TLS) {
tls = credssp->transport->TsgTls;
} else {
fprintf(stderr, "Unknown NLA transport layer\n");
return 0;
}
sspi_SecBufferAlloc(&credssp->PublicKey, tls->PublicKeyLength);
CopyMemory(credssp->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength);
length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->ServerHostname);

View File

@ -77,7 +77,7 @@ BOOL transport_disconnect(rdpTransport* transport)
if (transport->layer == TRANSPORT_LAYER_TLS)
status &= tls_disconnect(transport->TlsIn);
if (transport->layer == TRANSPORT_LAYER_TSG)
if (transport->layer == TRANSPORT_LAYER_TSG || transport->layer == TRANSPORT_LAYER_TSG_TLS)
{
tsg_disconnect(transport->tsg);
}
@ -104,10 +104,126 @@ BOOL transport_connect_rdp(rdpTransport* transport)
return TRUE;
}
long transport_bio_tsg_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
{
return 1;
}
static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
{
int status;
rdpTsg* tsg;
tsg = (rdpTsg*) bio->ptr;
status = tsg_write(tsg, (BYTE*) buf, num);
BIO_clear_retry_flags(bio);
if (status <= 0)
{
BIO_set_retry_write(bio);
}
return num;
}
static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
{
int status;
rdpTsg* tsg;
tsg = (rdpTsg*) bio->ptr;
status = tsg_read(bio->ptr, (BYTE*) buf, size);
BIO_clear_retry_flags(bio);
if (status <= 0)
{
BIO_set_retry_read(bio);
}
return status > 0 ? status : -1;
}
static int transport_bio_tsg_puts(BIO* bio, const char* str)
{
return 1;
}
static int transport_bio_tsg_gets(BIO* bio, char* str, int size)
{
return 1;
}
static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
if(cmd == BIO_CTRL_FLUSH) {
return 1;
}
return 0;
}
static int transport_bio_tsg_new(BIO* bio)
{
bio->init = 1;
bio->num = 0;
bio->ptr = NULL;
bio->flags = 0;
return 1;
}
static int transport_bio_tsg_free(BIO* bio)
{
return 1;
}
#define BIO_TYPE_TSG 65
static BIO_METHOD transport_bio_tsg_methods =
{
BIO_TYPE_TSG,
"TSGateway",
transport_bio_tsg_write,
transport_bio_tsg_read,
transport_bio_tsg_puts,
transport_bio_tsg_gets,
transport_bio_tsg_ctrl,
transport_bio_tsg_new,
transport_bio_tsg_free,
NULL,
};
BIO_METHOD* BIO_s_tsg(void)
{
return &transport_bio_tsg_methods;
}
BOOL transport_connect_tls(rdpTransport* transport)
{
if (transport->layer == TRANSPORT_LAYER_TSG)
{
transport->TsgTls = tls_new(transport->settings);
transport->TsgTls->methods = BIO_s_tsg();
transport->TsgTls->tsg = (void*) transport->tsg;
transport->layer = TRANSPORT_LAYER_TSG_TLS;
if (tls_connect(transport->TsgTls) != TRUE)
{
if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR;
tls_free(transport->TsgTls);
transport->TsgTls = NULL;
return FALSE;
}
return TRUE;
}
if (transport->TlsIn == NULL)
transport->TlsIn = tls_new(transport->settings);
@ -141,9 +257,6 @@ BOOL transport_connect_nla(rdpTransport* transport)
freerdp* instance;
rdpSettings* settings;
if (transport->layer == TRANSPORT_LAYER_TSG)
return TRUE;
if (!transport_connect_tls(transport))
return FALSE;
@ -385,6 +498,9 @@ int transport_read_layer(rdpTransport* transport, UINT8* data, int bytes)
status = tcp_read(transport->TcpIn, data + read, bytes - read);
else if (transport->layer == TRANSPORT_LAYER_TSG)
status = tsg_read(transport->tsg, data + read, bytes - read);
else if (transport->layer == TRANSPORT_LAYER_TSG_TLS) {
status = tls_read(transport->TsgTls, data + read, bytes - read);
}
/* blocking means that we can't continue until this is read */
@ -540,6 +656,8 @@ int transport_write(rdpTransport* transport, wStream* s)
status = tcp_write(transport->TcpOut, Stream_Pointer(s), length);
else if (transport->layer == TRANSPORT_LAYER_TSG)
status = tsg_write(transport->tsg, Stream_Pointer(s), length);
else if (transport->layer == TRANSPORT_LAYER_TSG_TLS)
status = tls_write(transport->TsgTls, Stream_Pointer(s), length);
if (status < 0)
break; /* error occurred */
@ -558,6 +676,8 @@ int transport_write(rdpTransport* transport, wStream* s)
tls_wait_write(transport->TlsOut);
else if (transport->layer == TRANSPORT_LAYER_TCP)
tcp_wait_write(transport->TcpOut);
else if (transport->layer == TRANSPORT_LAYER_TSG_TLS)
tls_wait_write(transport->TsgTls);
else
USleep(transport->SleepInterval);
}
@ -784,7 +904,7 @@ BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking)
status &= tcp_set_blocking_mode(transport->TcpIn, blocking);
}
if (transport->layer == TRANSPORT_LAYER_TSG)
if (transport->layer == TRANSPORT_LAYER_TSG || transport->layer == TRANSPORT_LAYER_TSG_TLS)
{
tsg_set_blocking_mode(transport->tsg, blocking);
}

View File

@ -25,6 +25,7 @@ typedef enum
TRANSPORT_LAYER_TCP,
TRANSPORT_LAYER_TLS,
TRANSPORT_LAYER_TSG,
TRANSPORT_LAYER_TSG_TLS,
TRANSPORT_LAYER_CLOSED
} TRANSPORT_LAYER;
@ -57,6 +58,7 @@ struct rdp_transport
rdpTcp* TcpOut;
rdpTls* TlsIn;
rdpTls* TlsOut;
rdpTls* TsgTls;
rdpCredssp* credssp;
rdpSettings* settings;
UINT32 SleepInterval;

View File

@ -97,6 +97,14 @@ SecPkgContext_Bindings* tls_get_channel_bindings(X509* cert)
return ContextBindings;
}
static void tls_ssl_info_callback(const SSL* ssl, int type, int val)
{
if (type & SSL_CB_HANDSHAKE_START)
{
}
}
BOOL tls_connect(rdpTls* tls)
{
CryptoCert cert;
@ -106,7 +114,7 @@ BOOL tls_connect(rdpTls* tls)
tls->ctx = SSL_CTX_new(TLSv1_client_method());
if (tls->ctx == NULL)
if (!tls->ctx)
{
fprintf(stderr, "SSL_CTX_new failed\n");
return FALSE;
@ -147,16 +155,35 @@ BOOL tls_connect(rdpTls* tls)
tls->ssl = SSL_new(tls->ctx);
if (tls->ssl == NULL)
if (!tls->ssl)
{
fprintf(stderr, "SSL_new failed\n");
return FALSE;
}
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
if (tls->tsg)
{
fprintf(stderr, "SSL_set_fd failed\n");
return FALSE;
tls->bio = BIO_new(tls->methods);
if (!tls->bio)
{
fprintf(stderr, "BIO_new failed\n");
return FALSE;
}
tls->bio->ptr = tls->tsg;
SSL_set_bio(tls->ssl, tls->bio, tls->bio);
SSL_CTX_set_info_callback(tls->ctx, tls_ssl_info_callback);
}
else
{
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
{
fprintf(stderr, "SSL_set_fd failed\n");
return FALSE;
}
}
connection_status = SSL_connect(tls->ssl);