server: accept TLS connection from the client.

This commit is contained in:
Vic Lee 2011-08-19 13:35:29 +08:00
parent 601254727f
commit 10f8aab40b
10 changed files with 195 additions and 36 deletions

View File

@ -203,6 +203,9 @@ struct rdp_settings
char* directory;
uint32 performance_flags;
char* cert_file;
char* privatekey_file;
boolean autologon;
boolean compression;

View File

@ -110,6 +110,10 @@ boolean rdp_client_connect(rdpRdp* rdp)
boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
{
boolean ret;
transport_set_blocking_mode(rdp->transport, True);
if (!nego_recv_request(rdp->nego, s))
return False;
if (rdp->nego->requested_protocols == PROTOCOL_RDP)
@ -145,6 +149,19 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
nego_send_negotiation_response(rdp->nego);
ret = False;
if (rdp->nego->selected_protocol & PROTOCOL_NLA)
ret = transport_accept_nla(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_TLS)
ret = transport_accept_tls(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_RDP)
ret = transport_accept_rdp(rdp->transport);
if (!ret)
return False;
transport_set_blocking_mode(rdp->transport, False);
rdp->state = CONNECTION_STATE_NEGO;
return True;

View File

@ -136,6 +136,8 @@ void settings_free(rdpSettings* settings)
xfree(settings->shell);
xfree(settings->directory);
xfree(settings->client_dir);
xfree(settings->cert_file);
xfree(settings->privatekey_file);
xfree(settings);
}
}

View File

@ -26,6 +26,24 @@ boolean tls_connect(rdpTls* tls)
{
int connection_status;
tls->ctx = SSL_CTX_new(TLSv1_client_method());
if (tls->ctx == NULL)
{
printf("SSL_CTX_new failed\n");
return False;
}
/*
* This is necessary, because the Microsoft TLS implementation is not perfect.
* SSL_OP_ALL enables a couple of workarounds for buggy TLS implementations,
* but the most important workaround being SSL_OP_TLS_BLOCK_PADDING_BUG.
* As the size of the encrypted payload may give hints about its contents,
* block padding is normally used, but the Microsoft TLS implementation
* won't recognize it and will disconnect you after sending a TLS alert.
*/
SSL_CTX_set_options(tls->ctx, SSL_OP_ALL);
tls->ssl = SSL_new(tls->ctx);
if (tls->ssl == NULL)
@ -40,24 +58,9 @@ boolean tls_connect(rdpTls* tls)
return False;
}
while (1)
{
connection_status = SSL_connect(tls->ssl);
connection_status = SSL_connect(tls->ssl);
/*
* SSL_WANT_READ and SSL_WANT_WRITE errors are normal,
* just try again if it happens
*/
if (connection_status == SSL_ERROR_WANT_READ)
continue;
else if (connection_status == SSL_ERROR_WANT_WRITE)
continue;
else
break;
}
if (connection_status < 0)
if (connection_status <= 0)
{
if (tls_print_error("SSL_connect", tls->ssl, connection_status))
return False;
@ -68,6 +71,57 @@ boolean tls_connect(rdpTls* tls)
return True;
}
boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file)
{
int connection_status;
tls->ctx = SSL_CTX_new(TLSv1_server_method());
if (tls->ctx == NULL)
{
printf("SSL_CTX_new failed\n");
return False;
}
if (SSL_CTX_use_RSAPrivateKey_file(tls->ctx, privatekey_file, SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_RSAPrivateKey_file failed\n");
return False;
}
tls->ssl = SSL_new(tls->ctx);
if (tls->ssl == NULL)
{
printf("SSL_new failed\n");
return False;
}
if (SSL_use_certificate_file(tls->ssl, cert_file, SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_use_certificate_file failed\n");
return False;
}
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
{
printf("SSL_set_fd failed\n");
return False;
}
connection_status = SSL_accept(tls->ssl);
if (connection_status <= 0)
{
if (tls_print_error("SSL_accept", tls->ssl, connection_status))
return False;
}
printf("TLS connection accepted\n");
return True;
}
boolean tls_disconnect(rdpTls* tls)
{
return True;
@ -85,10 +139,12 @@ int tls_read(rdpTls* tls, uint8* data, int length)
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
status = 0;
break;
default:
tls_print_error("SSL_read", tls->ssl, status);
status = -1;
break;
}
@ -107,6 +163,7 @@ int tls_write(rdpTls* tls, uint8* data, int length)
case SSL_ERROR_NONE:
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
status = 0;
break;
@ -180,29 +237,11 @@ rdpTls* tls_new()
if (tls != NULL)
{
tls->connect = tls_connect;
tls->accept = tls_accept;
tls->disconnect = tls_disconnect;
SSL_load_error_strings();
SSL_library_init();
tls->ctx = SSL_CTX_new(TLSv1_client_method());
if (tls->ctx == NULL)
{
printf("SSL_CTX_new failed\n");
return NULL;
}
/*
* This is necessary, because the Microsoft TLS implementation is not perfect.
* SSL_OP_ALL enables a couple of workarounds for buggy TLS implementations,
* but the most important workaround being SSL_OP_TLS_BLOCK_PADDING_BUG.
* As the size of the encrypted payload may give hints about its contents,
* block padding is normally used, but the Microsoft TLS implementation
* won't recognize it and will disconnect you after sending a TLS alert.
*/
SSL_CTX_set_options(tls->ctx, SSL_OP_ALL);
}
return tls;

View File

@ -30,6 +30,7 @@
typedef struct rdp_tls rdpTls;
typedef boolean (*TlsConnect) (rdpTls* tls);
typedef boolean (*TlsAccept) (rdpTls* tls, const char* cert_file, const char* privatekey_file);
typedef boolean (*TlsDisconnect) (rdpTls* tls);
struct rdp_tls
@ -38,10 +39,12 @@ struct rdp_tls
int sockfd;
SSL_CTX* ctx;
TlsConnect connect;
TlsAccept accept;
TlsDisconnect disconnect;
};
boolean tls_connect(rdpTls* tls);
boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file);
boolean tls_disconnect(rdpTls* tls);
int tls_read(rdpTls* tls, uint8* data, int length);
int tls_write(rdpTls* tls, uint8* data, int length);

View File

@ -131,6 +131,52 @@ boolean transport_connect_nla(rdpTransport* transport)
return True;
}
boolean transport_accept_rdp(rdpTransport* transport)
{
transport->state = TRANSPORT_STATE_RDP;
/* RDP encryption */
return True;
}
boolean transport_accept_tls(rdpTransport* transport)
{
if (transport->tls == NULL)
transport->tls = tls_new();
transport->layer = TRANSPORT_LAYER_TLS;
transport->state = TRANSPORT_STATE_TLS;
transport->tls->sockfd = transport->tcp->sockfd;
if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) != True)
return False;
return True;
}
boolean transport_accept_nla(rdpTransport* transport)
{
if (transport->tls == NULL)
transport->tls = tls_new();
transport->layer = TRANSPORT_LAYER_TLS;
transport->state = TRANSPORT_STATE_NLA;
transport->tls->sockfd = transport->tcp->sockfd;
if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) != True)
return False;
/* Network Level Authentication */
if (transport->settings->authentication != True)
return True;
/* Blocking here until NLA is complete */
return True;
}
int transport_read(rdpTransport* transport, STREAM* s)
{
int status = -1;

View File

@ -74,6 +74,9 @@ boolean transport_disconnect(rdpTransport* transport);
boolean transport_connect_rdp(rdpTransport* transport);
boolean transport_connect_tls(rdpTransport* transport);
boolean transport_connect_nla(rdpTransport* transport);
boolean transport_accept_rdp(rdpTransport* transport);
boolean transport_accept_tls(rdpTransport* transport);
boolean transport_accept_nla(rdpTransport* transport);
int transport_read(rdpTransport* transport, STREAM* s);
int transport_write(rdpTransport* transport, STREAM* s);
int transport_check_fds(rdpTransport* transport);

View File

@ -40,6 +40,8 @@ static void* test_peer_mainloop(void* arg)
printf("We've got a client %s\n", client->settings->hostname);
client->settings->cert_file = xstrdup("server.crt");
client->settings->privatekey_file = xstrdup("server.key");
client->Initialize(client);
while (1)

17
server/test/server.crt Normal file
View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICyzCCAbOgAwIBAgIJANbqtAWwlQZuMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMTB0ZyZWVSRFAwHhcNMDkxMDI5MDA0MTQ5WhcNMDkxMTI4MDA0MTQ5WjASMRAw
DgYDVQQDEwdGcmVlUkRQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
q7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1TptzXTcmfDrDslTGwcEY
hTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2SXvTiaV26VPPxddGb
o6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJLd2SU4ItWHj8zjz1f
eGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsjgvz4yP7I3TL8+GsN
MjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdymrulJSIhoOVfKkwi
ptTe43FgwxVRIygJP9HjHQIDAQABoyQwIjATBgNVHSUEDDAKBggrBgEFBQcDATAL
BgNVHQ8EBAMCBDAwDQYJKoZIhvcNAQEFBQADggEBAIOdEDhOX2kbl02znltd9hCr
nV4kRPKm979RKwBNkrEuwYSlcsjAHg5MZ5itH3wFOUo2s5pjt7/vMOAg+6rOBbIa
nqr22/gKBtOmuaJLG1yjxDC2vfez7f3B26pKgxa/krM8oxiFdT9n8QbdxdkN7/D9
3RLU/aCfgrMzXxRus7eq3kR00jnSs6ggnAfE1E9gric3vFgr1wCzdcriRXmXDfUb
hRq+4VG+ZWk16TwCofV5GVU39XWCv5HNO2swAdjkNXgI5e3tQbV3wWLZLqqYzBco
iWulAXtoCGmE81+u1Ms7hLLzpXitLZSGPu1r+sDdkKPLCmOvkAaljDQ4nBz7fIA=
-----END CERTIFICATE-----

27
server/test/server.key Normal file
View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAq7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1Tptz
XTcmfDrDslTGwcEYhTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2S
XvTiaV26VPPxddGbo6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJL
d2SU4ItWHj8zjz1feGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsj
gvz4yP7I3TL8+GsNMjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdy
mrulJSIhoOVfKkwiptTe43FgwxVRIygJP9HjHQIDAQABAoIBAAVv5K54xtc1JtBR
1lfdPbSqDlnjx8aOnVIPg5TnqMp3sR8jBt0NsPc/+RA9ZOmfjoIxFAEJaZ9zSDJC
5BqmnxC5R1mfCQkSd2haQ+4pdFvWyrv4Bblh8YU6hXrJGn0LfO0KlIcywtAvKpsi
LtTyZkWmaW2HeF/+pO32jYygw38R1wd8Tl6GwjOXwTF6lFACJXOT4YAzcfp3FKSB
AiKBIGuMzozoSND7KPFNRrhGhNumJpdS5A8Fb8D2c/ZMv6Cq5IbwOgTfKun+Bz+s
mFbnzeb1uWRqQbsVXOBBW/zHfuG3SU5qeZsaAyuu4DTy+LE1oAHF9uhBSHuT5C6i
vCJ8A8ECgYEA1iaOmiEJYBrs25iAc4SjCKqhY0mwR3wtu3I06vmgUoML5fhPMv36
SvYQIqDyNw3p7TE6mZtw9+G+kK3PqhuJhogwSwg0a6o51RdKnhXH3/68oNWtKCLC
1AmR8q/Gd3FwAR3b49CuOIZ9uOiJrc/ejzKdFEJTDR1/TX1frWfZznECgYEAzUiz
XxFf7YrGel7JgmfRD2eZRYngOoteFlg5Tee42UjeAY2Pt2aiDLk+2TqQEdI9+Xg7
LcFdBqcSNd8bh33xSzgNthIkX+lTDzx0SmKGfyxfFBJcY8nzsLvvnNt3YeuMeaJQ
CPszwoZ0jcD46jTCjbrKhaLyEWmUkDp1O71NTW0CgYAXKF49Xpsz8FVyvcAOPeaf
dkwzf3F3mX8ciRId4taqdY9g1AREgGCDoK5IAF2RBIkqZCtxFvUVaS0BWjpdq9Ko
YKvQQVfh2KueVoF0LOjLWTGutsydzXyCD3Lf6pAstHCnPkJcFWHxrOGFkGfrCtKH
a7K+0RlIDsuIZqllCBjukQKBgA31+MTpYJW+D1t5IMkumEgs6n6RLt+sZLyuSU9k
B+03CGogn3qAj1rAKmcJlYywuKhDpfqpoNL3/8QMJUokpYlRCZWtTC39pzltCheY
9b6mXNz3lrLupBUL4vLO9iKBq28GO90wgEelbz3ItuTuq6CJ6IYIG+BVRtY8M4bZ
i+1NAoGANXZjYnJYDnh8Je9SDxDSc5byzK7ddkQoId64RCIfNHqNKH63P81vjgnH
YBIPtagY75ZVVNxujCF7m8Rety+d8tEFwfQKDin2EVI7PD2rOJra385/izp7HuBR
vqxvLzG9Xv3cNOU2l7PttVw4Pa2i5E37atKi3V3Zp2kMW+KaKPQ=
-----END RSA PRIVATE KEY-----