From 5c21c8491d20d1ae5acf683c7bd0b87882251fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 3 Jul 2011 17:29:09 -0400 Subject: [PATCH] libfreerdp-core: TLS support --- .gitignore | 1 + freerdp-ui/test/freerdp-test | Bin 13402 -> 0 bytes libfreerdp-core/CMakeLists.txt | 4 + libfreerdp-core/tls.c | 204 +++++++++++++++++++++++++++++++++ libfreerdp-core/tls.h | 60 ++++++++++ 5 files changed, 269 insertions(+) delete mode 100755 freerdp-ui/test/freerdp-test create mode 100644 libfreerdp-core/tls.c create mode 100644 libfreerdp-core/tls.h 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 49e46d006570b4ca95ca461774edd7c83c7aadd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13402 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 R+J)y7e)CsETE#Q({twbX-O&I5 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 */