diff --git a/.gitignore b/.gitignore index 6fa607586..cc307d880 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ Makefile *.so *.so.* cunit/test_freerdp +freerdp-ui/test/freerdp-test diff --git a/freerdp-ui/test/freerdp-test b/freerdp-ui/test/freerdp-test deleted file mode 100755 index 49e46d006..000000000 Binary files a/freerdp-ui/test/freerdp-test and /dev/null differ diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt index 0d86742b0..b2894a769 100644 --- a/libfreerdp-core/CMakeLists.txt +++ b/libfreerdp-core/CMakeLists.txt @@ -32,6 +32,8 @@ set(LIBFREERDP_CORE_SRCS # ntlmssp.h tcp.c tcp.h + tls.c + tls.h tpdu.c tpdu.h tpkt.c @@ -42,4 +44,6 @@ set(LIBFREERDP_CORE_SRCS add_library(freerdp-core SHARED ${LIBFREERDP_CORE_SRCS}) +target_link_libraries(freerdp-core ssl) + install(TARGETS freerdp-core DESTINATION lib) diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c new file mode 100644 index 000000000..9e92c7961 --- /dev/null +++ b/libfreerdp-core/tls.c @@ -0,0 +1,204 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Transport Layer Security + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "tls.h" + +FRDP_BOOL +tls_connect(rdpTls * tls) +{ + int connection_status; + + tls->ssl = SSL_new(tls->ctx); + + if (tls->ssl == NULL) + { + printf("SSL_new failed\n"); + return False; + } + + if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) + { + printf("SSL_set_fd failed\n"); + return False; + } + + do + { + /* SSL_WANT_READ errors are normal, just try again if it happens */ + connection_status = SSL_connect(tls->ssl); + } + while (SSL_get_error(tls->ssl, connection_status) == SSL_ERROR_WANT_READ); + + if (connection_status < 0) + { + if (tls_print_error("SSL_connect", tls->ssl, connection_status)) + return False; + } + + printf("TLS connection established\n"); + + return True; +} + +FRDP_BOOL +tls_disconnect(rdpTls * tls) +{ + return True; +} + +int +tls_read(rdpTls * tls, char* data, int length) +{ + int status; + + while (True) + { + status = SSL_read(tls->ssl, data, length); + + switch (SSL_get_error(tls->ssl, status)) + { + case SSL_ERROR_NONE: + return status; + break; + + case SSL_ERROR_WANT_READ: + nanosleep(&tls->ts, NULL); + break; + + default: + tls_print_error("SSL_read", tls->ssl, status); + return -1; + break; + } + } + + return 0; +} + +int +tls_write(rdpTls * tls, char* data, int length) +{ + int write_status; + int bytes = 0; + + while (bytes < length) + { + write_status = SSL_write(tls->ssl, data, length); + + switch (SSL_get_error(tls->ssl, write_status)) + { + case SSL_ERROR_NONE: + bytes += write_status; + break; + + case SSL_ERROR_WANT_WRITE: + nanosleep(&tls->ts, NULL); + break; + + default: + tls_print_error("SSL_write", tls->ssl, write_status); + return -1; + break; + } + } + return bytes; +} + +FRDP_BOOL +tls_print_error(char *func, SSL *connection, int value) +{ + switch (SSL_get_error(connection, value)) + { + case SSL_ERROR_ZERO_RETURN: + printf("%s: Server closed TLS connection\n", func); + return True; + + case SSL_ERROR_WANT_READ: + printf("SSL_ERROR_WANT_READ\n"); + return False; + + case SSL_ERROR_WANT_WRITE: + printf("SSL_ERROR_WANT_WRITE\n"); + return False; + + case SSL_ERROR_SYSCALL: + printf("%s: I/O error\n", func); + return True; + + case SSL_ERROR_SSL: + printf("%s: Failure in SSL library (protocol error?)\n", func); + return True; + + default: + printf("%s: Unknown error\n", func); + return True; + } +} + +rdpTls* +tls_new() +{ + rdpTls *tls = (rdpTls*) xzalloc(sizeof(rdpTls)); + + if (tls != NULL) + { + tls->connect = tls_connect; + 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); + + /* a small 0.1ms delay when network blocking happens. */ + tls->ts.tv_sec = 0; + tls->ts.tv_nsec = 100000; + } + + return tls; +} + +void +tls_free(rdpTls* tls) +{ + if (tls != NULL) + { + xfree(tls); + } +} diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h new file mode 100644 index 000000000..525262725 --- /dev/null +++ b/libfreerdp-core/tls.h @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Transport Layer Security + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TLS_H +#define __TLS_H + +#include +#include +#include + +#include +#include + +typedef struct rdp_tls rdpTls; +typedef FRDP_BOOL (*TlsConnect) (rdpTls * tls); +typedef FRDP_BOOL (*TlsDisconnect) (rdpTls * tls); + +struct rdp_tls +{ + SSL * ssl; + int sockfd; + SSL_CTX * ctx; + struct timespec ts; + TlsConnect connect; + TlsDisconnect disconnect; +}; + +FRDP_BOOL +tls_connect(rdpTls * tls); +FRDP_BOOL +tls_disconnect(rdpTls * tls); +int +tls_read(rdpTls * tls, char* data, int length); +int +tls_write(rdpTls * tls, char* data, int length); +FRDP_BOOL +tls_print_error(char *func, SSL *connection, int value); + +rdpTls* +tls_new(); +void +tls_free(rdpTls* tls); + +#endif /* __TLS_H */