Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}