int tls_do_handshake(rdpTls* tls, BOOL clientMode) { CryptoCert cert; int verify_status; do { #ifdef HAVE_POLL_H int fd; int status; struct pollfd pollfds; #elif !defined(_WIN32) int fd; int status; fd_set rset; struct timeval tv; #else HANDLE event; DWORD status; #endif status = BIO_do_handshake(tls->bio); if (status == 1) break; if (!BIO_should_retry(tls->bio)) return -1; #ifndef _WIN32 /* we select() only for read even if we should test both read and write * depending of what have blocked */ fd = BIO_get_fd(tls->bio, NULL); if (fd < 0) { WLog_ERR(TAG, "unable to retrieve BIO fd"); return -1; } #else BIO_get_event(tls->bio, &event); if (!event) { WLog_ERR(TAG, "unable to retrieve BIO event"); return -1; } #endif #ifdef HAVE_POLL_H pollfds.fd = fd; pollfds.events = POLLIN; pollfds.revents = 0; do { status = poll(&pollfds, 1, 10 * 1000); } while ((status < 0) && (errno == EINTR)); #elif !defined(_WIN32) FD_ZERO(&rset); FD_SET(fd, &rset); tv.tv_sec = 0; tv.tv_usec = 10 * 1000; /* 10ms */ status = _select(fd + 1, &rset, NULL, NULL, &tv); #else status = WaitForSingleObject(event, 10); #endif #ifndef _WIN32 if (status < 0) { WLog_ERR(TAG, "error during select()"); return -1; } #else if ((status != WAIT_OBJECT_0) && (status != WAIT_TIMEOUT)) { WLog_ERR(TAG, "error during WaitForSingleObject(): 0x%04X", status); return -1; } #endif } while (TRUE); cert = tls_get_certificate(tls, clientMode); if (!cert) { WLog_ERR(TAG, "tls_get_certificate failed to return the server certificate."); return -1; } tls->Bindings = tls_get_channel_bindings(cert->px509); if (!tls->Bindings) { WLog_ERR(TAG, "unable to retrieve bindings"); verify_status = -1; goto out; } if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { WLog_ERR(TAG, "crypto_cert_get_public_key failed to return the server public key."); verify_status = -1; goto out; } /* server-side NLA needs public keys (keys from us, the server) but no certificate verify */ verify_status = 1; if (clientMode) { verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port); if (verify_status < 1) { WLog_ERR(TAG, "certificate not trusted, aborting."); tls_send_alert(tls); verify_status = 0; } } out: tls_free_certificate(cert); return verify_status; }
BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file) { CryptoCert cert; long options = 0; int connection_status; tls->ctx = SSL_CTX_new(SSLv23_server_method()); if (tls->ctx == NULL) { fprintf(stderr, "SSL_CTX_new failed\n"); return FALSE; } /* * SSL_OP_NO_SSLv2: * * We only want SSLv3 and TLSv1, so disable SSLv2. * SSLv3 is used by, eg. Microsoft RDC for Mac OS X. */ options |= SSL_OP_NO_SSLv2; /** * SSL_OP_NO_COMPRESSION: * * The Microsoft RDP server does not advertise support * for TLS compression, but alternative servers may support it. * This was observed between early versions of the FreeRDP server * and the FreeRDP client, and caused major performance issues, * which is why we're disabling it. */ #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif /** * SSL_OP_TLS_BLOCK_PADDING_BUG: * * The Microsoft RDP server does *not* support TLS padding. * It absolutely needs to be disabled otherwise it won't work. */ options |= SSL_OP_TLS_BLOCK_PADDING_BUG; /** * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: * * Just like TLS padding, the Microsoft RDP server does not * support empty fragments. This needs to be disabled. */ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; SSL_CTX_set_options(tls->ctx, options); if (SSL_CTX_use_RSAPrivateKey_file(tls->ctx, privatekey_file, SSL_FILETYPE_PEM) <= 0) { fprintf(stderr, "SSL_CTX_use_RSAPrivateKey_file failed\n"); fprintf(stderr, "PrivateKeyFile: %s\n", privatekey_file); return FALSE; } tls->ssl = SSL_new(tls->ctx); if (!tls->ssl) { fprintf(stderr, "SSL_new failed\n"); return FALSE; } if (SSL_use_certificate_file(tls->ssl, cert_file, SSL_FILETYPE_PEM) <= 0) { fprintf(stderr, "SSL_use_certificate_file failed\n"); return FALSE; } if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) { fprintf(stderr, "SSL_set_fd failed\n"); return FALSE; } while (1) { connection_status = SSL_accept(tls->ssl); if (connection_status <= 0) { switch (SSL_get_error(tls->ssl, connection_status)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: break; default: if (tls_print_error("SSL_accept", tls->ssl, connection_status)) return FALSE; break; } } else { break; } } cert = tls_get_certificate(tls, FALSE); if (!cert) { fprintf(stderr, "tls_connect: tls_get_certificate failed to return the server certificate.\n"); return FALSE; } if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { fprintf(stderr, "tls_connect: crypto_cert_get_public_key failed to return the server public key.\n"); tls_free_certificate(cert); return FALSE; } free(cert); fprintf(stderr, "TLS connection accepted\n"); return TRUE; }
int tls_do_handshake(rdpTls* tls, BOOL clientMode) { CryptoCert cert; int verify_status, status; do { #ifdef HAVE_POLL_H struct pollfd pollfds; #else struct timeval tv; fd_set rset; #endif int fd; status = BIO_do_handshake(tls->bio); if (status == 1) break; if (!BIO_should_retry(tls->bio)) return -1; /* we select() only for read even if we should test both read and write * depending of what have blocked */ fd = BIO_get_fd(tls->bio, NULL); if (fd < 0) { DEBUG_WARN( "%s: unable to retrieve BIO fd\n", __FUNCTION__); return -1; } #ifdef HAVE_POLL_H pollfds.fd = fd; pollfds.events = POLLIN; pollfds.revents = 0; do { status = poll(&pollfds, 1, 10 * 1000); } while ((status < 0) && (errno == EINTR)); #else FD_ZERO(&rset); FD_SET(fd, &rset); tv.tv_sec = 0; tv.tv_usec = 10 * 1000; /* 10ms */ status = _select(fd + 1, &rset, NULL, NULL, &tv); #endif if (status < 0) { DEBUG_WARN( "%s: error during select()\n", __FUNCTION__); return -1; } } while (TRUE); cert = tls_get_certificate(tls, clientMode); if (!cert) { DEBUG_WARN( "%s: tls_get_certificate failed to return the server certificate.\n", __FUNCTION__); return -1; } tls->Bindings = tls_get_channel_bindings(cert->px509); if (!tls->Bindings) { DEBUG_WARN( "%s: unable to retrieve bindings\n", __FUNCTION__); verify_status = -1; goto out; } if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { DEBUG_WARN( "%s: crypto_cert_get_public_key failed to return the server public key.\n", __FUNCTION__); verify_status = -1; goto out; } /* Note: server-side NLA needs public keys (keys from us, the server) but no * certificate verify */ verify_status = 1; if (clientMode) { verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port); if (verify_status < 1) { DEBUG_WARN( "%s: certificate not trusted, aborting.\n", __FUNCTION__); tls_disconnect(tls); verify_status = 0; } } out: tls_free_certificate(cert); return verify_status; }
BOOL tls_connect(rdpTls* tls) { CryptoCert cert; long options = 0; int connection_status; tls->ctx = SSL_CTX_new(TLSv1_client_method()); if (!tls->ctx) { fprintf(stderr, "SSL_CTX_new failed\n"); return FALSE; } //SSL_CTX_set_mode(tls->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); /** * SSL_OP_NO_COMPRESSION: * * The Microsoft RDP server does not advertise support * for TLS compression, but alternative servers may support it. * This was observed between early versions of the FreeRDP server * and the FreeRDP client, and caused major performance issues, * which is why we're disabling it. */ #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif /** * SSL_OP_TLS_BLOCK_PADDING_BUG: * * The Microsoft RDP server does *not* support TLS padding. * It absolutely needs to be disabled otherwise it won't work. */ options |= SSL_OP_TLS_BLOCK_PADDING_BUG; /** * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: * * Just like TLS padding, the Microsoft RDP server does not * support empty fragments. This needs to be disabled. */ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; SSL_CTX_set_options(tls->ctx, options); tls->ssl = SSL_new(tls->ctx); if (!tls->ssl) { fprintf(stderr, "SSL_new failed\n"); return FALSE; } if (tls->tsg) { tls->bio = BIO_new(tls->methods); if (!tls->bio) { fprintf(stderr, "BIO_new failed\n"); return FALSE; } tls->bio->ptr = tls->tsg; SSL_set_bio(tls->ssl, tls->bio, tls->bio); SSL_CTX_set_info_callback(tls->ctx, tls_ssl_info_callback); } else { if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) { fprintf(stderr, "SSL_set_fd failed\n"); return FALSE; } } connection_status = SSL_connect(tls->ssl); if (connection_status <= 0) { if (tls_print_error("SSL_connect", tls->ssl, connection_status)) { return FALSE; } } cert = tls_get_certificate(tls, TRUE); if (!cert) { fprintf(stderr, "tls_connect: tls_get_certificate failed to return the server certificate.\n"); return FALSE; } tls->Bindings = tls_get_channel_bindings(cert->px509); if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { fprintf(stderr, "tls_connect: crypto_cert_get_public_key failed to return the server public key.\n"); tls_free_certificate(cert); return FALSE; } if (!tls_verify_certificate(tls, cert, tls->hostname, tls->port)) { fprintf(stderr, "tls_connect: certificate not trusted, aborting.\n"); tls_disconnect(tls); tls_free_certificate(cert); return FALSE; } tls_free_certificate(cert); return TRUE; }
BOOL tls_connect(rdpTls* tls) { CryptoCert cert; long options = 0; int connection_status; tls->ctx = SSL_CTX_new(TLSv1_client_method()); if (tls->ctx == NULL) { printf("SSL_CTX_new failed\n"); return FALSE; } /** * SSL_OP_NO_COMPRESSION: * * The Microsoft RDP server does not advertise support * for TLS compression, but alternative servers may support it. * This was observed between early versions of the FreeRDP server * and the FreeRDP client, and caused major performance issues, * which is why we're disabling it. */ #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif /** * SSL_OP_TLS_BLOCK_PADDING_BUG: * * The Microsoft RDP server does *not* support TLS padding. * It absolutely needs to be disabled otherwise it won't work. */ options |= SSL_OP_TLS_BLOCK_PADDING_BUG; /** * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: * * Just like TLS padding, the Microsoft RDP server does not * support empty fragments. This needs to be disabled. */ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; SSL_CTX_set_options(tls->ctx, options); 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; } connection_status = SSL_connect(tls->ssl); if (connection_status <= 0) { if (tls_print_error("SSL_connect", tls->ssl, connection_status)) { return FALSE; } } cert = tls_get_certificate(tls, TRUE); if (cert == NULL) { printf("tls_connect: tls_get_certificate failed to return the server certificate.\n"); return FALSE; } if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { printf("tls_connect: crypto_cert_get_public_key failed to return the server public key.\n"); tls_free_certificate(cert); return FALSE; } if (!tls_verify_certificate(tls, cert, tls->settings->hostname)) { printf("tls_connect: certificate not trusted, aborting.\n"); tls_disconnect(tls); tls_free_certificate(cert); return FALSE; } tls_free_certificate(cert); return TRUE; }