From 10f8aab40bd85102ed31b10c8f6c747cf50217a6 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Fri, 19 Aug 2011 13:35:29 +0800 Subject: [PATCH] server: accept TLS connection from the client. --- include/freerdp/settings.h | 3 ++ libfreerdp-core/connection.c | 17 +++++++ libfreerdp-core/settings.c | 2 + libfreerdp-core/tls.c | 107 +++++++++++++++++++++++++++++-------------- libfreerdp-core/tls.h | 3 ++ libfreerdp-core/transport.c | 46 +++++++++++++++++++ libfreerdp-core/transport.h | 3 ++ server/test/freerdp_server.c | 2 + server/test/server.crt | 17 +++++++ server/test/server.key | 27 +++++++++++ 10 files changed, 193 insertions(+), 34 deletions(-) create mode 100644 server/test/server.crt create mode 100644 server/test/server.key diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 926f6a9..7310305 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -203,6 +203,9 @@ struct rdp_settings char* directory; uint32 performance_flags; + char* cert_file; + char* privatekey_file; + boolean autologon; boolean compression; diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c index fa8dacf..bd56fd1 100644 --- a/libfreerdp-core/connection.c +++ b/libfreerdp-core/connection.c @@ -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; diff --git a/libfreerdp-core/settings.c b/libfreerdp-core/settings.c index 8c6b05e..ba13022 100644 --- a/libfreerdp-core/settings.c +++ b/libfreerdp-core/settings.c @@ -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); } } diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c index 016596a..ce30ad4 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -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,30 +58,66 @@ boolean tls_connect(rdpTls* tls) return False; } - while (1) + connection_status = SSL_connect(tls->ssl); + + if (connection_status <= 0) { - connection_status = SSL_connect(tls->ssl); + if (tls_print_error("SSL_connect", tls->ssl, connection_status)) + return False; + } - /* - * SSL_WANT_READ and SSL_WANT_WRITE errors are normal, - * just try again if it happens - */ + printf("TLS connection established\n"); - if (connection_status == SSL_ERROR_WANT_READ) - continue; - else if (connection_status == SSL_ERROR_WANT_WRITE) - continue; - else - break; + 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 (connection_status < 0) + if (SSL_CTX_use_RSAPrivateKey_file(tls->ctx, privatekey_file, SSL_FILETYPE_PEM) <= 0) { - if (tls_print_error("SSL_connect", tls->ssl, connection_status)) + 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 established\n"); + printf("TLS connection accepted\n"); 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; diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h index c777a6d..9a7da59 100644 --- a/libfreerdp-core/tls.h +++ b/libfreerdp-core/tls.h @@ -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); diff --git a/libfreerdp-core/transport.c b/libfreerdp-core/transport.c index da99f1d..17ba421 100644 --- a/libfreerdp-core/transport.c +++ b/libfreerdp-core/transport.c @@ -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; diff --git a/libfreerdp-core/transport.h b/libfreerdp-core/transport.h index 65b8511..76f31c4 100644 --- a/libfreerdp-core/transport.h +++ b/libfreerdp-core/transport.h @@ -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); diff --git a/server/test/freerdp_server.c b/server/test/freerdp_server.c index f302dfb..ca83f57 100644 --- a/server/test/freerdp_server.c +++ b/server/test/freerdp_server.c @@ -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) diff --git a/server/test/server.crt b/server/test/server.crt new file mode 100644 index 0000000..7ce931c --- /dev/null +++ b/server/test/server.crt @@ -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----- diff --git a/server/test/server.key b/server/test/server.key new file mode 100644 index 0000000..5c2f2c8 --- /dev/null +++ b/server/test/server.key @@ -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----- -- 2.7.4