From feea87b42f09cfa50d89ba3d644f941954096cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 1 Apr 2014 16:23:27 -0400 Subject: [PATCH] libfreerdp-crypto: make distinction between TLS connection error and user cancellation --- include/freerdp/crypto/tls.h | 2 +- libfreerdp/core/transport.c | 88 ++++++++++++++++++++++++++++++------ libfreerdp/crypto/tls.c | 48 +++++++++++--------- 3 files changed, 101 insertions(+), 37 deletions(-) diff --git a/include/freerdp/crypto/tls.h b/include/freerdp/crypto/tls.h index 486db2bd6..abd5e6dd7 100644 --- a/include/freerdp/crypto/tls.h +++ b/include/freerdp/crypto/tls.h @@ -84,7 +84,7 @@ struct rdp_tls int alertDescription; }; -FREERDP_API BOOL tls_connect(rdpTls* tls); +FREERDP_API int tls_connect(rdpTls* tls); FREERDP_API BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file); FREERDP_API BOOL tls_disconnect(rdpTls* tls); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 77cc559ae..ceb19c96d 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -224,6 +224,7 @@ BIO_METHOD* BIO_s_tsg(void) BOOL transport_connect_tls(rdpTransport* transport) { + int tls_status; freerdp* instance; rdpContext* context; @@ -245,13 +246,23 @@ BOOL transport_connect_tls(rdpTransport* transport) if (transport->TsgTls->port == 0) transport->TsgTls->port = 3389; - if (!tls_connect(transport->TsgTls)) - { - if (!connectErrorCode) - connectErrorCode = TLSCONNECTERROR; + tls_status = tls_connect(transport->TsgTls); - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!connectErrorCode) + connectErrorCode = TLSCONNECTERROR; + + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } tls_free(transport->TsgTls); transport->TsgTls = NULL; @@ -277,13 +288,23 @@ BOOL transport_connect_tls(rdpTransport* transport) if (transport->TlsIn->port == 0) transport->TlsIn->port = 3389; - if (!tls_connect(transport->TlsIn)) - { - if (!connectErrorCode) - connectErrorCode = TLSCONNECTERROR; + tls_status = tls_connect(transport->TlsIn); - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!connectErrorCode) + connectErrorCode = TLSCONNECTERROR; + + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } tls_free(transport->TlsIn); @@ -355,6 +376,13 @@ BOOL transport_connect_nla(rdpTransport* transport) BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port) { + int tls_status; + freerdp* instance; + rdpContext* context; + + instance = (freerdp*) transport->settings->instance; + context = instance->context; + rdpTsg* tsg = tsg_new(transport); tsg->transport = transport; @@ -381,11 +409,41 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 if (transport->TlsOut->port == 0) transport->TlsOut->port = 443; - if (!tls_connect(transport->TlsIn)) - return FALSE; + tls_status = tls_connect(transport->TlsIn); + + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } - if (!tls_connect(transport->TlsOut)) return FALSE; + } + + tls_status = tls_connect(transport->TlsOut); + + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } + + return FALSE; + } if (!tsg_connect(tsg, hostname, port)) return FALSE; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 805105097..ea98e2812 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -105,10 +105,11 @@ static void tls_ssl_info_callback(const SSL* ssl, int type, int val) } } -BOOL tls_connect(rdpTls* tls) +int tls_connect(rdpTls* tls) { CryptoCert cert; long options = 0; + int verify_status; int connection_status; tls->ctx = SSL_CTX_new(TLSv1_client_method()); @@ -116,7 +117,7 @@ BOOL tls_connect(rdpTls* tls) if (!tls->ctx) { fprintf(stderr, "SSL_CTX_new failed\n"); - return FALSE; + return -1; } //SSL_CTX_set_mode(tls->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); @@ -157,7 +158,7 @@ BOOL tls_connect(rdpTls* tls) if (!tls->ssl) { fprintf(stderr, "SSL_new failed\n"); - return FALSE; + return -1; } if (tls->tsg) @@ -167,7 +168,7 @@ BOOL tls_connect(rdpTls* tls) if (!tls->bio) { fprintf(stderr, "BIO_new failed\n"); - return FALSE; + return -1; } tls->bio->ptr = tls->tsg; @@ -181,7 +182,7 @@ BOOL tls_connect(rdpTls* tls) if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) { fprintf(stderr, "SSL_set_fd failed\n"); - return FALSE; + return -1; } } @@ -191,7 +192,7 @@ BOOL tls_connect(rdpTls* tls) { if (tls_print_error("SSL_connect", tls->ssl, connection_status)) { - return FALSE; + return -1; } } @@ -200,7 +201,7 @@ BOOL tls_connect(rdpTls* tls) if (!cert) { fprintf(stderr, "tls_connect: tls_get_certificate failed to return the server certificate.\n"); - return FALSE; + return -1; } tls->Bindings = tls_get_channel_bindings(cert->px509); @@ -209,20 +210,22 @@ BOOL tls_connect(rdpTls* tls) { fprintf(stderr, "tls_connect: crypto_cert_get_public_key failed to return the server public key.\n"); tls_free_certificate(cert); - return FALSE; + return -1; } - if (!tls_verify_certificate(tls, cert, tls->hostname, tls->port)) + verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port); + + if (verify_status < 1) { fprintf(stderr, "tls_connect: certificate not trusted, aborting.\n"); tls_disconnect(tls); tls_free_certificate(cert); - return FALSE; + return verify_status; } tls_free_certificate(cert); - return TRUE; + return (verify_status == 0) ? 0 : 1; } BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file) @@ -612,7 +615,7 @@ BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname) return FALSE; } -BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port) +int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port) { int match; int index; @@ -644,7 +647,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (!bio) { fprintf(stderr, "tls_verify_certificate: BIO_new() failure\n"); - return FALSE; + return -1; } status = PEM_write_bio_X509(bio, cert->px509); @@ -652,7 +655,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (status < 0) { fprintf(stderr, "tls_verify_certificate: PEM_write_bio_X509 failure: %d\n", status); - return FALSE; + return -1; } offset = 0; @@ -664,7 +667,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (status < 0) { fprintf(stderr, "tls_verify_certificate: failed to read certificate\n"); - return FALSE; + return -1; } offset += status; @@ -685,7 +688,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (status < 0) { fprintf(stderr, "tls_verify_certificate: failed to read certificate\n"); - return FALSE; + return -1; } length = offset; @@ -704,12 +707,15 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po free(pemCert); BIO_free(bio); - return (status < 0) ? FALSE : TRUE; + if (status < 0) + return -1; + + return (status == 0) ? 0 : 1; } /* ignore certificate verification if user explicitly required it (discouraged) */ if (tls->settings->IgnoreCertificate) - return TRUE; /* success! */ + return 1; /* success! */ /* if user explicitly specified a certificate name, use it instead of the hostname */ if (tls->settings->CertificateName) @@ -727,7 +733,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po /* compare against common name */ - if (common_name != NULL) + if (common_name) { if (tls_match_hostname(common_name, common_name_length, hostname)) hostname_match = TRUE; @@ -735,7 +741,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po /* compare against alternative names */ - if (alt_names != NULL) + if (alt_names) { for (index = 0; index < alt_names_count; index++) { @@ -851,7 +857,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths, alt_names); - return verification_status; + return (verification_status == 0) ? 0 : 1; } void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file)