Esempio n. 1
0
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout)
{
	int status;
	UINT32 option_value;
	socklen_t option_len;

	if (!hostname)
		return FALSE;

	if (hostname[0] == '/')
		tcp->ipcSocket = TRUE;

	if (tcp->ipcSocket)
	{
		tcp->sockfd = freerdp_uds_connect(hostname);

		if (tcp->sockfd < 0)
			return FALSE;

		tcp->socketBio = BIO_new(BIO_s_simple_socket());

		if (!tcp->socketBio)
			return FALSE;

		BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
	}
	else
	{
#ifdef HAVE_POLL_H
		struct pollfd pollfds;
#else
		fd_set cfds;
		struct timeval tv;
#endif

#ifdef NO_IPV6
		tcp->socketBio = BIO_new(BIO_s_connect());

		if (!tcp->socketBio)
			return FALSE;

		if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0)
			return FALSE;

		BIO_set_nbio(tcp->socketBio, 1);

		status = BIO_do_connect(tcp->socketBio);

		if ((status <= 0) && !BIO_should_retry(tcp->socketBio))
			return FALSE;

		tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL);

		if (tcp->sockfd < 0)
			return FALSE;
#else /* NO_IPV6 */
		struct addrinfo hints = {0};
		struct addrinfo *result;
		struct addrinfo *tmp;
		char port_str[11];

		//ZeroMemory(&hints, sizeof(struct addrinfo));
		hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
		hints.ai_socktype = SOCK_STREAM;
		/*
		 * FIXME: the following is a nasty workaround. Find a cleaner way:
		 * Either set port manually afterwards or get it passed as string?
		 */
		sprintf_s(port_str, 11, "%u", port);

		status = getaddrinfo(hostname, port_str, &hints, &result);
		if (status) {
			fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
			return FALSE;
		}

		/* For now prefer IPv4 over IPv6. */
		tmp = result;
		if (tmp->ai_family == AF_INET6 && tmp->ai_next != 0)
		{
			while ((tmp = tmp->ai_next))
			{
				if (tmp->ai_family == AF_INET)
					break;
			}
			if (!tmp)
				tmp = result;
		}
		tcp->sockfd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);

		if (tcp->sockfd  < 0) {
			freeaddrinfo(result);
			return FALSE;
		}

		if (connect(tcp->sockfd, tmp->ai_addr, tmp->ai_addrlen) < 0) {
			fprintf(stderr, "connect: %s\n", strerror(errno));
			freeaddrinfo(result);
			return FALSE;
		}
		freeaddrinfo(result);
		tcp->socketBio = BIO_new_socket(tcp->sockfd, BIO_NOCLOSE);

		/* TODO: make sure the handshake is done by querying the bio */
		//		if (BIO_should_retry(tcp->socketBio))
		//          return FALSE;
#endif /* NO_IPV6 */

		if (status <= 0)
		{
#ifdef HAVE_POLL_H
			pollfds.fd = tcp->sockfd;
			pollfds.events = POLLOUT;
			pollfds.revents = 0;
			do
			{
				status = poll(&pollfds, 1, timeout * 1000);
			}
			while ((status < 0) && (errno == EINTR));
#else
			FD_ZERO(&cfds);
			FD_SET(tcp->sockfd, &cfds);

			tv.tv_sec = timeout;
			tv.tv_usec = 0;

			status = _select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv);
#endif
			if (status == 0)
			{
				return FALSE; /* timeout */
			}
		}

		(void)BIO_set_close(tcp->socketBio, BIO_NOCLOSE);
		BIO_free(tcp->socketBio);

		tcp->socketBio = BIO_new(BIO_s_simple_socket());

		if (!tcp->socketBio)
			return FALSE;

		BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
	}

	SetEventFileDescriptor(tcp->event, tcp->sockfd);

	tcp_get_ip_address(tcp);
	tcp_get_mac_address(tcp);

	option_value = 1;
	option_len = sizeof(option_value);

	if (!tcp->ipcSocket)
	{
		if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0)
			WLog_ERR(TAG,  "unable to set TCP_NODELAY");
	}

	/* receive buffer must be a least 32 K */
	if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0)
	{
		if (option_value < (1024 * 32))
		{
			option_value = 1024 * 32;
			option_len = sizeof(option_value);

			if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0)
			{
				WLog_ERR(TAG,  "unable to set receive buffer len");
				return FALSE;
			}
		}
	}

	if (!tcp->ipcSocket)
	{
		if (!tcp_set_keep_alive_mode(tcp))
			return FALSE;
	}

	tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());

	if (!tcp->bufferedBio)
		return FALSE;

	tcp->bufferedBio->ptr = tcp;

	tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);

	return TRUE;
}
Esempio n. 2
0
void *netConnectHttpsThread(void *threadParam)
/* use a thread to run socket back to user */
{
/* child */

struct netConnectHttpsParams *params = threadParam;

pthread_detach(params->thread);  // this thread will never join back with it's progenitor

int fd=0;

char hostnameProto[256];

BIO *sbio;
SSL_CTX *ctx;
SSL *ssl;

openSslInit();

ctx = SSL_CTX_new(SSLv23_client_method());

fd_set readfds;
fd_set writefds;
int err;
struct timeval tv;


/* TODO checking certificates 

char *certFile = NULL;
char *certPath = NULL;
if (certFile || certPath)
    {
    SSL_CTX_load_verify_locations(ctx,certFile,certPath);
#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
    SSL_CTX_set_verify_depth(ctx,1);
#endif
    }

// verify paths and mode.

*/


sbio = BIO_new_ssl_connect(ctx);

BIO_get_ssl(sbio, &ssl);
if(!ssl) 
    {
    xerr("Can't locate SSL pointer");
    goto cleanup;
    }

/* Don't want any retries since we are non-blocking bio now */
//SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);


safef(hostnameProto,sizeof(hostnameProto),"%s:%d",params->hostName,params->port);
BIO_set_conn_hostname(sbio, hostnameProto);

BIO_set_nbio(sbio, 1);     /* non-blocking mode */

while (1) 
    {
    if (BIO_do_connect(sbio) == 1) 
	{
	break;  /* Connected */
	}
    if (! BIO_should_retry(sbio)) 
	{
	xerr("BIO_do_connect() failed");
	char s[256];	
	safef(s, sizeof s, "SSL error: %s", ERR_reason_error_string(ERR_get_error()));
	xerr(s);
	goto cleanup;
	}

    fd = BIO_get_fd(sbio, NULL);
    if (fd == -1) 
	{
	xerr("unable to get BIO descriptor");
	goto cleanup;
	}
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    if (BIO_should_read(sbio)) 
	{
	FD_SET(fd, &readfds);
	}
    else if (BIO_should_write(sbio)) 
	{
	FD_SET(fd, &writefds);
	}
    else 
	{  /* BIO_should_io_special() */
	FD_SET(fd, &readfds);
	FD_SET(fd, &writefds);
	}
    tv.tv_sec = (long) (DEFAULTCONNECTTIMEOUTMSEC/1000);  // timeout default 10 seconds
    tv.tv_usec = (long) (((DEFAULTCONNECTTIMEOUTMSEC/1000)-tv.tv_sec)*1000000);

    err = select(fd + 1, &readfds, &writefds, NULL, &tv);
    if (err < 0) 
	{
	xerr("select() error");
	goto cleanup;
	}

    if (err == 0) 
	{
	char s[256];	
	safef(s, sizeof s, "connection timeout to %s", params->hostName);
	xerr(s);
	goto cleanup;
	}
    }


/* TODO checking certificates 

if (certFile || certPath)
    if (!check_cert(ssl, host))
	return -1;

*/

/* we need to wait on both the user's socket and the BIO SSL socket 
 * to see if we need to ferry data from one to the other */


char sbuf[32768];  // socket buffer sv[1] to user
char bbuf[32768];  // bio buffer
int srd = 0;
int swt = 0;
int brd = 0;
int bwt = 0;
while (1) 
    {

    // Do NOT move this outside the while loop. 
    /* Get underlying file descriptor, needed for select call */
    fd = BIO_get_fd(sbio, NULL);
    if (fd == -1) 
	{
	xerr("BIO doesn't seem to be initialized in https, unable to get descriptor.");
	goto cleanup;
	}


    FD_ZERO(&readfds);
    FD_ZERO(&writefds);

    if (brd == 0)
	FD_SET(fd, &readfds);
    if (swt < srd)
	FD_SET(fd, &writefds);
    if (srd == 0)
	FD_SET(params->sv[1], &readfds);

    tv.tv_sec = (long) (DEFAULTCONNECTTIMEOUTMSEC/1000);  // timeout default 10 seconds
    tv.tv_usec = (long) (((DEFAULTCONNECTTIMEOUTMSEC/1000)-tv.tv_sec)*1000000);

    err = select(max(fd,params->sv[1]) + 1, &readfds, &writefds, NULL, &tv);

    /* Evaluate select() return code */
    if (err < 0) 
	{
	xerr("error during select()");
	goto cleanup;
	}
    else if (err == 0) 
	{
	/* Timed out - just quit */
	xerr("https timeout expired");
	goto cleanup;
	}

    else 
	{
	if (FD_ISSET(params->sv[1], &readfds))
	    {
	    swt = 0;
	    srd = read(params->sv[1], sbuf, 32768);
	    if (srd == -1)
		{
		if (errno != 104) // udcCache often closes causing "Connection reset by peer"
		    xerrno("error reading https socket");
		goto cleanup;
		}
	    if (srd == 0) 
		break;  // user closed socket, we are done
	    }

	if (FD_ISSET(fd, &writefds))
	    {
	    int swtx = BIO_write(sbio, sbuf+swt, srd-swt);
	    if (swtx <= 0)
		{
		if (!BIO_should_write(sbio))
		    {
		    ERR_print_errors_fp(stderr);
		    xerr("Error writing SSL connection");
		    goto cleanup;
		    }
		}
	    else
		{
		swt += swtx;
		if (swt >= srd)
		    {
		    swt = 0;
		    srd = 0;
		    }
		}
	    }

	if (FD_ISSET(fd, &readfds))
	    {
	    bwt = 0;
	    brd = BIO_read(sbio, bbuf, 32768);

	    if (brd <= 0)
		{
		if (BIO_should_read(sbio))
		    {
		    brd = 0;
		    continue;
		    }
		else
		    {
		    if (brd == 0) break;
		    ERR_print_errors_fp(stderr);
		    xerr("Error reading SSL connection");
		    goto cleanup;
		    }
		}
	    // write the https data received immediately back on socket to user, and it's ok if it blocks.
	    while(bwt < brd)
		{
		int bwtx = write(params->sv[1], bbuf+bwt, brd-bwt);
		if (bwtx == -1)
		    {
		    if ((errno != 104)  // udcCache often closes causing "Connection reset by peer"
		     && (errno !=  32)) // udcCache often closes causing "Broken pipe"
			xerrno("error writing https data back to user socket");
		    goto cleanup;
		    }
		bwt += bwtx;
		}
	    brd = 0;
	    bwt = 0;
	    }
	}
    }

cleanup:

BIO_free_all(sbio);
close(params->sv[1]);  /* we are done with it */

return NULL;
}
netsnmp_transport *
netsnmp_tlstcp_open(netsnmp_transport *t)
{
    _netsnmpTLSBaseData *tlsdata;
    BIO *bio;
    SSL_CTX *ctx;
    SSL *ssl;
    int rc = 0;
    _netsnmp_verify_info *verify_info;

    netsnmp_assert_or_return(t != NULL, NULL);
    netsnmp_assert_or_return(t->data != NULL, NULL);
    netsnmp_assert_or_return(sizeof(_netsnmpTLSBaseData) == t->data_length,
                             NULL);

    tlsdata = t->data;
    
    if (tlsdata->flags & NETSNMP_TLSBASE_IS_CLIENT) {
        /* Is the client */

        /* RFC5953 Section 5.3.1:  Establishing a Session as a Client
         *    1)  The snmpTlstmSessionOpens counter is incremented.
         */
        snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENS);

        /* RFC5953 Section 5.3.1:  Establishing a Session as a Client
          2)  The client selects the appropriate certificate and cipher_suites
              for the key agreement based on the tmSecurityName and the
              tmRequestedSecurityLevel for the session.  For sessions being
              established as a result of a SNMP-TARGET-MIB based operation, the
              certificate will potentially have been identified via the
              snmpTlstmParamsTable mapping and the cipher_suites will have to
              be taken from system-wide or implementation-specific
              configuration.  If no row in the snmpTlstmParamsTable exists then
              implementations MAY choose to establish the connection using a
              default client certificate available to the application.
              Otherwise, the certificate and appropriate cipher_suites will
              need to be passed to the openSession() ASI as supplemental
              information or configured through an implementation-dependent
              mechanism.  It is also implementation-dependent and possibly
              policy-dependent how tmRequestedSecurityLevel will be used to
              influence the security capabilities provided by the (D)TLS
              connection.  However this is done, the security capabilities
              provided by (D)TLS MUST be at least as high as the level of
              security indicated by the tmRequestedSecurityLevel parameter.
              The actual security level of the session is reported in the
              tmStateReference cache as tmSecurityLevel.  For (D)TLS to provide
              strong authentication, each principal acting as a command
              generator SHOULD have its own certificate.
        */
        /*
          Implementation notes: we do most of this in the
          sslctx_client_setup The transport should have been
          f_config()ed with the proper fingerprints to use (which is
          stored in tlsdata), or we'll use the default identity
          fingerprint if that can be found.
        */

        /* XXX: check securityLevel and ensure no NULL fingerprints are used */

        /* set up the needed SSL context */
        tlsdata->ssl_context = ctx =
            sslctx_client_setup(TLSv1_method(), tlsdata);
        if (!ctx) {
            snmp_log(LOG_ERR, "failed to create TLS context\n");
            return NULL;
        }

        /* RFC5953 Section 5.3.1:  Establishing a Session as a Client
           3)  Using the destTransportDomain and destTransportAddress values,
               the client will initiate the (D)TLS handshake protocol to
               establish session keys for message integrity and encryption.
        */
        /* Implementation note:
           The transport domain and address are pre-processed by this point
        */

        /* Create a BIO connection for it */
        DEBUGMSGTL(("tlstcp", "connecting to tlstcp %s\n",
		    tlsdata->addr_string));
        t->remote = (void *) strdup(tlsdata->addr_string);
        t->remote_length = strlen(tlsdata->addr_string) + 1;

        bio = BIO_new_connect(tlsdata->addr_string);

        /* RFC5953 Section 5.3.1:  Establishing a Session as a Client
           3) continued:
              If the attempt to establish a session is unsuccessful, then
              snmpTlstmSessionOpenErrors is incremented, an error indication is
              returned, and processing stops.
        */

        if (NULL == bio) {
            snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
            snmp_log(LOG_ERR, "tlstcp: failed to create bio\n");
            _openssl_log_error(rc, NULL, "BIO creation");
            SNMP_FREE(tlsdata);
            SNMP_FREE(t);
            return NULL;
        }
            

        /* Tell the BIO to actually do the connection */
        if ((rc = BIO_do_connect(bio)) <= 0) {
            snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
            snmp_log(LOG_ERR, "tlstcp: failed to connect to %s\n",
		     tlsdata->addr_string);
            _openssl_log_error(rc, NULL, "BIO_do_connect");
            BIO_free(bio);
            SNMP_FREE(tlsdata);
            SNMP_FREE(t);
            return NULL;
        }

        /* Create the SSL layer on top of the socket bio */
        ssl = tlsdata->ssl = SSL_new(ctx);
        if (NULL == ssl) {
            snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
            snmp_log(LOG_ERR, "tlstcp: failed to create a SSL connection\n");
            BIO_free(bio);
            SNMP_FREE(tlsdata);
            SNMP_FREE(t);
            return NULL;
        }
        
        /* Bind the SSL layer to the BIO */ 
        SSL_set_bio(ssl, bio, bio);
        SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

        verify_info = SNMP_MALLOC_TYPEDEF(_netsnmp_verify_info);
        if (NULL == verify_info) {
            snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
            snmp_log(LOG_ERR, "tlstcp: failed to create a SSL connection\n");
            SSL_shutdown(ssl);
            BIO_free(bio);
            SNMP_FREE(tlsdata);
            SNMP_FREE(t);
            return NULL;
        }

        SSL_set_ex_data(ssl, tls_get_verify_info_index(), verify_info);

        /* Then have SSL do it's connection over the BIO */
        if ((rc = SSL_connect(ssl)) <= 0) {
            snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
            snmp_log(LOG_ERR, "tlstcp: failed to ssl_connect\n");
            BIO_free(bio);
            SNMP_FREE(tlsdata);
            SNMP_FREE(t);
            return NULL;
        }

        /* RFC5953 Section 5.3.1: Establishing a Session as a Client
           3) continued:
              If the session failed to open because the presented
              server certificate was unknown or invalid then the
              snmpTlstmSessionUnknownServerCertificate or
              snmpTlstmSessionInvalidServerCertificates MUST be
              incremented and a snmpTlstmServerCertificateUnknown or
              snmpTlstmServerInvalidCertificate notification SHOULD be
              sent as appropriate.  Reasons for server certificate
              invalidation includes, but is not limited to,
              cryptographic validation failures and an unexpected
              presented certificate identity.
        */

        /* RFC5953 Section 5.3.1: Establishing a Session as a Client
           4)  The (D)TLS client MUST then verify that the (D)TLS server's
               presented certificate is the expected certificate.  The (D)TLS
               client MUST NOT transmit SNMP messages until the server
               certificate has been authenticated, the client certificate has
               been transmitted and the TLS connection has been fully
               established.

               If the connection is being established from configuration based
               on SNMP-TARGET-MIB configuration, then the snmpTlstmAddrTable
               DESCRIPTION clause describes how the verification is done (using
               either a certificate fingerprint, or an identity authenticated
               via certification path validation).

               If the connection is being established for reasons other than
               configuration found in the SNMP-TARGET-MIB then configuration and
               procedures outside the scope of this document should be followed.
               Configuration mechanisms SHOULD be similar in nature to those
               defined in the snmpTlstmAddrTable to ensure consistency across
               management configuration systems.  For example, a command-line
               tool for generating SNMP GETs might support specifying either the
               server's certificate fingerprint or the expected host name as a
               command line argument.
        */

        /* Implementation notes:
           - All remote certificate fingerprints are expected to be
             stored in the transport's config information.  This is
             true both for CLI clients and TARGET-MIB sessions.
           - netsnmp_tlsbase_verify_server_cert implements these checks
        */
        if (netsnmp_tlsbase_verify_server_cert(ssl, tlsdata) != SNMPERR_SUCCESS) {
            /* XXX: unknown vs invalid; two counters */
            snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONUNKNOWNSERVERCERTIFICATE);
            snmp_log(LOG_ERR, "tlstcp: failed to verify ssl certificate\n");
            SSL_shutdown(ssl);
            BIO_free(bio);
            SNMP_FREE(tlsdata);
            SNMP_FREE(t);
            return NULL;
        }

        /* RFC5953 Section 5.3.1: Establishing a Session as a Client
           5)  (D)TLS provides assurance that the authenticated identity has
               been signed by a trusted configured certification authority.  If
               verification of the server's certificate fails in any way (for
               example because of failures in cryptographic verification or the
               presented identity did not match the expected named entity) then
               the session establishment MUST fail, the
               snmpTlstmSessionInvalidServerCertificates object is incremented.
               If the session can not be opened for any reason at all, including
               cryptographic verification failures, then the
               snmpTlstmSessionOpenErrors counter is incremented and processing
               stops.

        */
        /* XXX: add snmpTlstmSessionInvalidServerCertificates on
           crypto failure */

        /* RFC5953 Section 5.3.1: Establishing a Session as a Client
           6)  The TLSTM-specific session identifier (tlstmSessionID) is set in
           the tmSessionID of the tmStateReference passed to the TLS
           Transport Model to indicate that the session has been established
           successfully and to point to a specific (D)TLS connection for
           future use.  The tlstmSessionID is also stored in the LCD for
           later lookup during processing of incoming messages
           (Section 5.1.2).
        */
        /* Implementation notes:
           - the tlsdata pointer is used as our session identifier, as
             noted in the netsnmp_tlstcp_recv() function comments.
        */

        t->sock = BIO_get_fd(bio, NULL);

    } else {
        /* Is the server */
        
        /* Create the socket bio */
        DEBUGMSGTL(("tlstcp", "listening on tlstcp port %s\n",
		    tlsdata->addr_string));
        tlsdata->accept_bio = BIO_new_accept(tlsdata->addr_string);
        t->local = (void *) strdup(tlsdata->addr_string);
        t->local_length = strlen(tlsdata->addr_string)+1;
        if (NULL == tlsdata->accept_bio) {
            SNMP_FREE(t);
            SNMP_FREE(tlsdata);
            snmp_log(LOG_ERR, "TLSTCP: Falied to create a accept BIO\n");
            return NULL;
        }

        /* openssl requires an initial accept to bind() the socket */
        if (BIO_do_accept(tlsdata->accept_bio) <= 0) {
	    _openssl_log_error(rc, tlsdata->ssl, "BIO_do__accept");
            SNMP_FREE(t);
            SNMP_FREE(tlsdata);
            snmp_log(LOG_ERR, "TLSTCP: Falied to do first accept on the TLS accept BIO\n");
            return NULL;
        }

        /* create the OpenSSL TLS context */
        tlsdata->ssl_context =
            sslctx_server_setup(TLSv1_method());

        t->sock = BIO_get_fd(tlsdata->accept_bio, NULL);
        t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
    }
    return t;
}
Esempio n. 4
0
/**
 * oh_ssl_connect
 * @hostname:   Name of target host.  Format:
 *                  "hostname:port" or "IPaddress:port"
 * @ctx:        pointer to SSL_CTX as returned by oh_ssl_ctx_init()
 * @timeout:    maximum number of seconds to wait for a connection to
 *              hostname, or zero to wait forever
 *
 * Create and open a new ssl conection to the specified host.
 *
 * Return value: pointer to BIO, or NULL for failure
 **/
BIO             *oh_ssl_connect(char *hostname, SSL_CTX *ctx, long timeout)
{
        BIO             *bio;
        SSL             *ssl;
        fd_set          readfds;
        fd_set          writefds;
        struct timeval  tv;
        int             fd;
        int             err;

        if (hostname == NULL) {
                err("NULL hostname in oh_ssl_connect()");
                return(NULL);
        }
        if (ctx == NULL) {
                err("NULL ctx in oh_ssl_connect()");
                return(NULL);
        }
        if (timeout < 0) {
                err("inappropriate timeout in oh_ssl_connect()");
                return(NULL);
        }

        /* Start with a new SSL BIO */
        bio = BIO_new_ssl_connect(ctx);
        if (bio == NULL) {
                err("BIO_new_ssl_connect() failed");
                return(NULL);
        }

        /* Set up connection parameters for this BIO */
        BIO_set_conn_hostname(bio, hostname);
        BIO_set_nbio(bio, 1);           /* Set underlying socket to
                                         * non-blocking mode
                                         */

        /* Set up SSL session parameters */
        BIO_get_ssl(bio, &ssl);
        if (ssl == NULL) {
                err("BIO_get_ssl() failed");
                BIO_free_all(bio);
                return(NULL);
        }
        SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);

        /* Ready to open the connection.  Note that this call will probably
         * take a while, so we need to retry it, watching for a timeout.
         */
        while (1) {
                if (BIO_do_connect(bio) == 1) {
                        break;          /* Connection established */
                }
                if (! BIO_should_retry(bio)) { /* Hard error? */
                        err("BIO_do_connect() failed");
                        err("SSL error: %s",
                            ERR_reason_error_string(ERR_get_error()));
                        BIO_free_all(bio);
                        return(NULL);
                }

                /* Wait until there's a change in the socket's status or until
                 * the timeout period.
                 *
                 * Get underlying file descriptor, needed for the select call.
                 */
                fd = BIO_get_fd(bio, NULL);
                if (fd == -1) {
                        err("BIO isn't initialized in oh_ssl_connect()");
                        BIO_free_all(bio);
                        return(NULL);
                }

                FD_ZERO(&readfds);
                FD_ZERO(&writefds);
                if (BIO_should_read(bio)) {
                        FD_SET(fd, &readfds);
                }
                else if (BIO_should_write(bio)) {
                        FD_SET(fd, &writefds);
                }
                else {                  /* This is BIO_should_io_special().
                                         * Not sure what "special" needs to
                                         * wait for, but both read and write
                                         * seems to work without unnecessary
                                         * retries.
                                         */
                        FD_SET(fd, &readfds);
                        FD_SET(fd, &writefds);
                }
                if (timeout) {
                        tv.tv_sec = timeout;
                        tv.tv_usec = 0;
                        err = select(fd + 1, &readfds, &writefds, NULL, &tv);
                }
                else {                  /* No timeout */
                        err = select(fd + 1, &readfds, &writefds, NULL, NULL);
                }

                /* Evaluate select() return code */
                if (err < 0) {
                        err("error during select()");
                        BIO_free_all(bio);
                        return(NULL);
                }
                if (err == 0) {
                        err("connection timeout to %s", hostname);
                        BIO_free_all(bio);
                        return(NULL);   /* Timeout */
                }
        }

        /* TODO: Do I need to set the client or server mode here?  I don't
         * think so.
         */

        return(bio);
}
Esempio n. 5
0
int main(int argc, char **argv)
{
    BIO *sbio = NULL, *out = NULL;
    int i, len, rv;
    char tmpbuf[1024];
    SSL_CTX *ctx = NULL;
    SSL_CONF_CTX *cctx = NULL;
    SSL *ssl = NULL;
    CONF *conf = NULL;
    STACK_OF(CONF_VALUE) *sect = NULL;
    CONF_VALUE *cnf;
    const char *connect_str = "localhost:4433";
    long errline = -1;

    ERR_load_crypto_strings();
    ERR_load_SSL_strings();
    SSL_library_init();

    conf = NCONF_new(NULL);

    if (NCONF_load(conf, "connect.cnf", &errline) <= 0) {
        if (errline <= 0)
            fprintf(stderr, "Error processing config file\n");
        else
            fprintf(stderr, "Error on line %ld\n", errline);
        goto end;
    }

    sect = NCONF_get_section(conf, "default");

    if (sect == NULL) {
        fprintf(stderr, "Error retrieving default section\n");
        goto end;
    }

    ctx = SSL_CTX_new(SSLv23_client_method());
    cctx = SSL_CONF_CTX_new();
    SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
    SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE);
    SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
    for (i = 0; i < sk_CONF_VALUE_num(sect); i++) {
        cnf = sk_CONF_VALUE_value(sect, i);
        rv = SSL_CONF_cmd(cctx, cnf->name, cnf->value);
        if (rv > 0)
            continue;
        if (rv != -2) {
            fprintf(stderr, "Error processing %s = %s\n",
                    cnf->name, cnf->value);
            ERR_print_errors_fp(stderr);
            goto end;
        }
        if (!strcmp(cnf->name, "Connect")) {
            connect_str = cnf->value;
        } else {
            fprintf(stderr, "Unknown configuration option %s\n", cnf->name);
            goto end;
        }
    }

    if (!SSL_CONF_CTX_finish(cctx)) {
        fprintf(stderr, "Finish error\n");
        ERR_print_errors_fp(stderr);
        goto err;
    }

    /*
     * We'd normally set some stuff like the verify paths and * mode here
     * because as things stand this will connect to * any server whose
     * certificate is signed by any CA.
     */

    sbio = BIO_new_ssl_connect(ctx);

    BIO_get_ssl(sbio, &ssl);

    if (!ssl) {
        fprintf(stderr, "Can't locate SSL pointer\n");
        goto end;
    }

    /* Don't want any retries */
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

    /* We might want to do other things with ssl here */

    BIO_set_conn_hostname(sbio, connect_str);

    out = BIO_new_fp(stdout, BIO_NOCLOSE);
    if (BIO_do_connect(sbio) <= 0) {
        fprintf(stderr, "Error connecting to server\n");
        ERR_print_errors_fp(stderr);
        goto end;
    }

    if (BIO_do_handshake(sbio) <= 0) {
        fprintf(stderr, "Error establishing SSL connection\n");
        ERR_print_errors_fp(stderr);
        goto end;
    }

    /* Could examine ssl here to get connection info */

    BIO_puts(sbio, "GET / HTTP/1.0\n\n");
    for (;;) {
        len = BIO_read(sbio, tmpbuf, 1024);
        if (len <= 0)
            break;
        BIO_write(out, tmpbuf, len);
    }
 end:
    SSL_CONF_CTX_free(cctx);
    BIO_free_all(sbio);
    BIO_free(out);
    NCONF_free(conf);
    return 0;
}
Esempio n. 6
0
struct dyString *bio(char *host, char *url, char *certFile, char *certPath)
/*
This SSL/TLS client example, attempts to retrieve a page from an SSL/TLS web server. 
The I/O routines are identical to those of the unencrypted example in BIO_s_connect(3).
*/
{
struct dyString *dy = dyStringNew(0);
char hostnameProto[256];
char requestLine[4096];

BIO *sbio;
int len;
char tmpbuf[1024];
SSL_CTX *ctx;
SSL *ssl;

SSL_library_init();
ERR_load_crypto_strings();
ERR_load_SSL_strings();
OpenSSL_add_all_algorithms();

/* We would seed the PRNG here if the platform didn't
* do it automatically
*/

ctx = SSL_CTX_new(SSLv23_client_method());
if (certFile || certPath)
    {
    SSL_CTX_load_verify_locations(ctx,certFile,certPath);
#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
    SSL_CTX_set_verify_depth(ctx,1);
#endif
    }

/* We'd normally set some stuff like the verify paths and
* mode here because as things stand this will connect to
* any server whose certificate is signed by any CA.
*/

sbio = BIO_new_ssl_connect(ctx);

BIO_get_ssl(sbio, &ssl);

if(!ssl) 
    {
    fprintf(stderr, "Can't locate SSL pointer\n");
    return NULL;
    }

/* Don't want any retries */
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

/* We might want to do other things with ssl here */

safef(hostnameProto,sizeof(hostnameProto),"%s:https",host);
BIO_set_conn_hostname(sbio, hostnameProto);

if(BIO_do_connect(sbio) <= 0) 
    {
    fprintf(stderr, "Error connecting to server\n");
    ERR_print_errors_fp(stderr);
    return NULL;
    }

if(BIO_do_handshake(sbio) <= 0) 
    {
    fprintf(stderr, "Error establishing SSL connection\n");
    ERR_print_errors_fp(stderr);
    return NULL;
    }

if (certFile || certPath)
    if (!check_cert(ssl, host))
	return NULL;

/* Could examine ssl here to get connection info */

safef(requestLine,sizeof(requestLine),"GET %s HTTP/1.0\n\n",url);
BIO_puts(sbio, requestLine);
for(;;) 
    {
    len = BIO_read(sbio, tmpbuf, 1024);
    if(len <= 0) break;
    dyStringAppendN(dy, tmpbuf, len);
    }
BIO_free_all(sbio);

return dy;
}
Esempio n. 7
0
int proxy_null(BIO **cbio, BIO **sbio, char *header)
{
   char data[READ_BUFF_SIZE];
   int len, written;
   char *host, *p;

   /* retrieve the host tag */
   host = strcasestr(header, HTTP_HOST_TAG);

   if (host == NULL)
      return -EINVALID;

   SAFE_STRDUP(host, host + strlen(HTTP_HOST_TAG));

   /* trim the eol */
   if ((p = strchr(host, '\r')) != NULL)
      *p = 0;
   if ((p = strchr(host, '\n')) != NULL)
      *p = 0;

   /* connect to the real server */
   *sbio = BIO_new(BIO_s_connect());
   BIO_set_conn_hostname(*sbio, host);
   BIO_set_conn_port(*sbio, "http");

   if (BIO_do_connect(*sbio) <= 0) {
      DEBUG_MSG(D_ERROR, "Cannot connect to [%s]", host);
      SAFE_FREE(host);
      return -ENOADDRESS;
   }

   DEBUG_MSG(D_INFO, "Connection to [%s]", host);

   /*
    * sanitize the header to avoid strange reply from the server.
    * we don't want to cope with keep-alive !!!
    */
   sanitize_header(header);

   /* send the request to the server */
   BIO_puts(*sbio, header);

   memset(data, 0, sizeof(data));
   written = 0;

   /* read the reply header from the server */
   LOOP {
      len = BIO_read(*sbio, data + written, sizeof(char));
      if (len <= 0)
         break;

      written += len;
      if (strstr(data, CR LF CR LF) || strstr(data, LF LF))
         break;
   }

   /* send the headers to the client, the data will be sent in the callee function */
   BIO_write(*cbio, data, written);

   SAFE_FREE(host);

   return ESUCCESS;
}
Esempio n. 8
0
//--------------------------------------------------
// sends an OCSP_REQUES object to remore server and
// retrieves the OCSP_RESPONSE object
// resp - buffer to store the new responses pointer
// req - request objects pointer
// url - OCSP responder URL
//--------------------------------------------------
int ddocPullUrl(const char* url, DigiDocMemBuf* pSendData, DigiDocMemBuf* pRecvData, 
		const char* proxyHost, const char* proxyPort)
{	
  BIO* cbio = 0, *sbio = 0;
  SSL_CTX *ctx = NULL;
  char *host = NULL, *port = NULL, *path = "/", buf[200];
  int err = ERR_OK, use_ssl = -1, rc;
  long e;

  //RETURN_IF_NULL_PARAM(pSendData); // may be null if nothing to send?
  RETURN_IF_NULL_PARAM(pRecvData);
  RETURN_IF_NULL_PARAM(url);

  ddocDebug(3, "ddocPullUrl", "URL: %s, in: %d bytes", url, pSendData->nLen);
  //there is an HTTP proxy - connect to that instead of the target host
  if (proxyHost != 0 && *proxyHost != '\0') {
    host = (char*)proxyHost;
    if(proxyPort != 0 && *proxyPort != '\0')
      port = (char*)proxyPort;
    path = (char*)url;
  } else {
    if(OCSP_parse_url((char*)url, &host, &port, &path, &use_ssl) == 0) {
      ddocDebug(1, "ddocPullUrl", "Failed to parse the URL");
      return ERR_WRONG_URL_OR_PROXY; 
    }
  }
	
  if((cbio = BIO_new_connect(host)) != 0) {
    if(port != NULL) 
      BIO_set_conn_port(cbio, port);
    if(use_ssl == 1) {
      ctx = SSL_CTX_new(SSLv23_client_method());
      SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
      sbio = BIO_new_ssl(ctx, 1);
      cbio = BIO_push(sbio, cbio);
    }
    if ((rc = BIO_do_connect(cbio)) > 0) {
      ddocDebug(4, "ddocPullUrl", "Connected: %d", rc);
      if(pSendData && pSendData->nLen && pSendData->pMem) {
	rc = BIO_write(cbio, pSendData->pMem, pSendData->nLen);
	ddocDebug(4, "ddocPullUrl", "Sent: %d bytes, got: %d", pSendData->nLen, rc);
      }
      do {
	memset(buf, 0, sizeof(buf));
	rc = BIO_read(cbio, buf, sizeof(buf)-1);
	ddocDebug(4, "ddocPullUrl", "Received: %d bytes\n", rc);
	if(rc > 0)
	  err = ddocMemAppendData(pRecvData, buf, rc);
      } while(rc > 0);
      ddocDebug(4, "ddocPullUrl", "Total received: %d bytes\n", pRecvData->nLen);
    } else {
      //if no connection
	  e = checkErrors();
	  if(ERR_GET_REASON(e) == BIO_R_BAD_HOSTNAME_LOOKUP ||
		 ERR_GET_REASON(e) == OCSP_R_SERVER_WRITE_ERROR)
		  err = ERR_CONNECTION_FAILURE;
	  else
		  err = (host != NULL) ? ERR_WRONG_URL_OR_PROXY : ERR_CONNECTION_FAILURE;
    }
    BIO_free_all(cbio);
    if (use_ssl != -1) {
      OPENSSL_free(host);
      OPENSSL_free(port);
      OPENSSL_free(path);
      SSL_CTX_free(ctx);
    }
  }
  else
    err = ERR_CONNECTION_FAILURE;
  return(err);
}
int ssl_transport_insecure_send(option_block *opts, void *d, int i)
{
  FILE *log = stdout;
  char spec[2048] = {0};
  struct timeval tv;
  int sockfd;
  fd_set fds;
  unsigned long int to = MAX(100, opts->time_out);
  int ret;

  if(opts->fp_log)
    log = opts->fp_log;

  if(ssl_bio == NULL)
    {
      snprintf(spec, 2048, "%s:%d", opts->host_spec, opts->port);
      ssl_bio = BIO_new_connect(spec);
      if(ssl_bio == NULL)
	{
	  fprintf(stderr, "<ssl_transport:i-send> failure to acquire BIO: [%s]\n",
		  spec);
	  return -1;
	}
      
      if(BIO_do_connect(ssl_bio) <= 0)
	{
	  fprintf(stderr, "<ssl_transport:i-send> failure to simple connect to: [%s]\n",
		  spec);
	  return -1;
	}
    }
  
 retx:
  if(BIO_write(ssl_bio, d, i) <= 0)
    {
      if(!BIO_should_retry(ssl_bio))
	{
	  fprintf(stderr, "<ssl_transport:i-send> failure to transmit!\n");
	  ssl_transport_close();
	}
      goto retx;
    }
  
  if(opts->verbosity != QUIET)
    fprintf(log, "[%s] <ssl_transport:send> tx fuzz - scanning for reply.\n",
	    get_time_as_log());

    BIO_get_fd(ssl_bio, &sockfd);

    FD_ZERO(&fds);
    FD_SET(sockfd, &fds);

    tv.tv_sec  = to / 1000;
    tv.tv_usec = (to % 1000) * 1000; /*time out*/

    ret = select(sockfd+1, &fds, NULL, NULL, &tv);
    if(ret > 0)
    {
        if(FD_ISSET(sockfd, &fds))
        {
            char buf[8192] = {0};
            int r_len = 0;

	    ret = BIO_read(ssl_bio, buf, 8192);
	    if(ret == 0)
	      {
		fprintf(stderr, "<ssl_transport:send> remote closed xon\n");
		ssl_transport_close();
	      }
	    else if(ret > 0)
	      {
		if(opts->verbosity != QUIET)
		  fprintf(log, 
			  "[%s] read:\n%s\n===============================================================================\n", 
			  get_time_as_log(),
			  buf);
	      }
	}
    }
    
    if((opts->close_conn) || ((opts->close_conn) && (!opts->forget_conn)))
      {
	ssl_transport_close();
      }
    
    mssleep(opts->reqw_inms);
    return 0;
}
Esempio n. 10
0
int redisContextConnectSSL(redisContext *c, const char *addr, int port, char* certfile, char* certdir, struct timeval *timeout) {
    struct timeval  start_time;
    int             has_timeout = 0;
    int             is_nonblocking = 0;

    c->ssl.sd = -1;
    c->ssl.ctx = NULL;
    c->ssl.ssl = NULL;
    c->ssl.bio = NULL;

    // Set up a SSL_CTX object, which will tell our BIO object how to do its work
    SSL_CTX* ctx = SSL_CTX_new(TLSv1_1_client_method());
    c->ssl.ctx = ctx;

    // Create a SSL object pointer, which our BIO object will provide.
    SSL* ssl;

    // Create our BIO object for SSL connections.
    BIO* bio = BIO_new_ssl_connect(ctx);
    c->ssl.bio = bio;

    // Failure?
    if (bio == NULL) {
        char errorbuf[1024];
        __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Error creating BIO!\n");

        ERR_error_string(1024,errorbuf);
        __redisSetError(c,REDIS_ERR_OTHER,errorbuf);

        // We need to free up the SSL_CTX before we leave.
        cleanupSSL( &c->ssl );
        return REDIS_ERR;
    }

    // Makes ssl point to bio's SSL object.
    BIO_get_ssl(bio, &ssl);
    c->ssl.ssl = ssl;

    // Set the SSL to automatically retry on failure.
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

    char* connect_str = (char *)calloc( 1, strlen( addr ) + 10 );
    sprintf( connect_str, "%s:%d", addr, port );
    c->ssl.conn_str = connect_str;

    // We're connection to the REDIS server at host:port
    BIO_set_conn_hostname(bio, connect_str);

    SSL_CTX_load_verify_locations(ctx, certfile, certdir);

    // Are we supposed to be blocking or non-blocking?
    if( (c->flags & REDIS_BLOCK) == 0) {
        is_nonblocking = 1;
        BIO_set_nbio(bio,1);
    }

    // What about a timeout?
    // If we're blocking and have a timeout, we need to handle that specially
    if( NULL != timeout ) {
        BIO_set_nbio(bio,1);
        has_timeout = 1;
        gettimeofday(&start_time, NULL);
    }

    while(1) {
        struct timeval	cur_time,
                    elapsed_time;

        if (has_timeout) {
            gettimeofday(&cur_time, NULL);
            elapsed_time = subtractTimeval( cur_time, start_time );

            if (compareTimeval( elapsed_time, *timeout) > 0) {
                char errorbuf[1024];

                __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Connection timed out.");
                ERR_error_string(1024,errorbuf);
                __redisSetError(c,REDIS_ERR_OTHER,errorbuf);
                cleanupSSL( &(c->ssl) );
                return REDIS_ERR;
            }
        }

        // Same as before, try to connect.
        if (BIO_do_connect(bio) <= 0 ) {
            if( BIO_should_retry( bio ) ) {
                // We need to retry.
            } else {
                char errorbuf[1024];
                __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Failed to connect");
                ERR_error_string(1024,errorbuf);
                __redisSetError(c,REDIS_ERR_OTHER,errorbuf);
                cleanupSSL( &(c->ssl) );
                return REDIS_ERR;
            }
        } else {
            // connect is done...
            break;
        }

        if( has_timeout ) {
            // Do select and seelct on it
            int result;
            int fd = BIO_get_fd( bio, NULL );
            struct timeval time_left;

            if (has_timeout) {
                time_left = subtractTimeval( *timeout, elapsed_time );
            }

            fd_set readset, writeset;
            FD_ZERO(&readset);
            FD_SET(fd, &readset);
            FD_ZERO(&writeset);
            FD_SET(fd, &writeset);

            do {
                result = select( fd+1, &readset, &writeset, NULL, &time_left);
            } while( result == -1 && errno == EINTR );
        }

    }

    while(1) {
        struct timeval	cur_time,
                    elapsed_time;

        if (has_timeout) {
            gettimeofday(&cur_time, NULL);
            elapsed_time = subtractTimeval( cur_time, start_time );

            if (compareTimeval( elapsed_time, *timeout) > 0) {
                char errorbuf[1024];

                __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Connection timed out.");
                ERR_error_string(1024,errorbuf);
                __redisSetError(c,REDIS_ERR_OTHER,errorbuf);
                cleanupSSL( &(c->ssl) );
                return REDIS_ERR;
            }
        }

        // Now we need to do the SSL handshake, so we can communicate.
        if (BIO_do_handshake(bio) <= 0) {
            if( BIO_should_retry( bio ) ) {
                // We need to retry.
            } else {
                char errorbuf[1024];
                __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: handshake failure");
                ERR_error_string(1024,errorbuf);
                __redisSetError(c,REDIS_ERR_OTHER,errorbuf);
                cleanupSSL( &(c->ssl) );
                return REDIS_ERR;
            }
        } else {
            // handshake is done...
            break;
        }

        if( has_timeout ) {
            // Do select and seelct on it
            int result;
            int fd = BIO_get_fd( bio, NULL );
            struct timeval time_left;

            if (has_timeout) {
                time_left = subtractTimeval( *timeout, elapsed_time );
            }

            fd_set readset, writeset;
            FD_ZERO(&readset);
            FD_SET(fd, &readset);
            FD_ZERO(&writeset);
            FD_SET(fd, &writeset);

            do {
                result = select( fd+1, &readset, &writeset, NULL, &time_left);
            } while( result == -1 && errno == EINTR );
        }

    }

    long verify_result = SSL_get_verify_result(ssl);
    if( verify_result == X509_V_OK) {
        X509* peerCertificate = SSL_get_peer_certificate(ssl);

        char commonName [512];
        X509_NAME * name = X509_get_subject_name(peerCertificate);
        X509_NAME_get_text_by_NID(name, NID_commonName, commonName, 512);

        // TODO: Add a redis config parameter for the common name to check for.
        //       Since Redis connections are generally done with an IP address directly,
        //       we can't just assume that the name we get on the addr is an actual name.
        //
        //    if(strcasecmp(commonName, "BradBroerman") != 0) {
        //      __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Error validating cert common name.\n\n" );
        //      cleanupSSL( &(c->ssl) );
        //      return REDIS_ERR;

    } else {
        char errorbuf[1024];
        __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Error retrieving peer certificate.\n" );
        ERR_error_string(1024,errorbuf);
        __redisSetError(c,REDIS_ERR_OTHER,errorbuf);
        cleanupSSL( &(c->ssl) );
        return REDIS_ERR;
    }

    BIO_set_nbio(bio,is_nonblocking);

    return REDIS_OK;
}
Esempio n. 11
0
int main(int argc, char **argv)
{
    BIO *sbio = NULL, *out = NULL;
    int len;
    char tmpbuf[1024];
    SSL_CTX *ctx;
    SSL_CONF_CTX *cctx;
    SSL *ssl;
    char **args = argv + 1;
    const char *connect_str = "localhost:4433";
    int nargs = argc - 1;

    ERR_load_crypto_strings();
    ERR_load_SSL_strings();
    SSL_library_init();

    ctx = SSL_CTX_new(TLS_client_method());
    cctx = SSL_CONF_CTX_new();
    SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
    SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
    while (*args && **args == '-') {
        int rv;
        /* Parse standard arguments */
        rv = SSL_CONF_cmd_argv(cctx, &nargs, &args);
        if (rv == -3) {
            fprintf(stderr, "Missing argument for %s\n", *args);
            goto end;
        }
        if (rv < 0) {
            fprintf(stderr, "Error in command %s\n", *args);
            ERR_print_errors_fp(stderr);
            goto end;
        }
        /* If rv > 0 we processed something so proceed to next arg */
        if (rv > 0)
            continue;
        /* Otherwise application specific argument processing */
        if (strcmp(*args, "-connect") == 0) {
            connect_str = args[1];
            if (connect_str == NULL) {
                fprintf(stderr, "Missing -connect argument\n");
                goto end;
            }
            args += 2;
            nargs -= 2;
            continue;
        } else {
            fprintf(stderr, "Unknown argument %s\n", *args);
            goto end;
        }
    }

    if (!SSL_CONF_CTX_finish(cctx)) {
        fprintf(stderr, "Finish error\n");
        ERR_print_errors_fp(stderr);
        goto end;
    }

    /*
     * We'd normally set some stuff like the verify paths and * mode here
     * because as things stand this will connect to * any server whose
     * certificate is signed by any CA.
     */

    sbio = BIO_new_ssl_connect(ctx);

    BIO_get_ssl(sbio, &ssl);

    if (!ssl) {
        fprintf(stderr, "Can't locate SSL pointer\n");
        goto end;
    }

    /* Don't want any retries */
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

    /* We might want to do other things with ssl here */

    BIO_set_conn_hostname(sbio, connect_str);

    out = BIO_new_fp(stdout, BIO_NOCLOSE);
    if (BIO_do_connect(sbio) <= 0) {
        fprintf(stderr, "Error connecting to server\n");
        ERR_print_errors_fp(stderr);
        goto end;
    }

    if (BIO_do_handshake(sbio) <= 0) {
        fprintf(stderr, "Error establishing SSL connection\n");
        ERR_print_errors_fp(stderr);
        goto end;
    }

    /* Could examine ssl here to get connection info */

    BIO_puts(sbio, "GET / HTTP/1.0\n\n");
    for (;;) {
        len = BIO_read(sbio, tmpbuf, 1024);
        if (len <= 0)
            break;
        BIO_write(out, tmpbuf, len);
    }
 end:
    SSL_CONF_CTX_free(cctx);
    BIO_free_all(sbio);
    BIO_free(out);
    return 0;
}
Esempio n. 12
0
int main(int argc, char** argv){

    int sock = 0; // declaración del socket e inicializado a 0
    int error = 0; /** declaramos una variable que nos servirá para detectar
                    * errores
                    */
    int serverTalk = 0;
    //socklen_t length = (socklen_t) sizeof (struct sockaddr_in); // tamaño del paquete
    //struct sockaddr_in addr; // definimos el contenedor de la dirección
    unsigned int port = 5678; /** creamos la variable que identifica el puerto
                               * de conexión, siendo el puerto por defecto 5678
                               */
    char dir[DIM] = "localhost"; /** definimos la cadena que contendrá a la
                                  * dirección del servidor, la cual, será por
                                  * defecto localhost
                                  */
    //struct hostent*  server; // estructura utilizada para la gestión de direcciones
    sms auxMsj;
    char name[DIM] = {0};
    int nbytes = 0; // contador de bytes leidos y escritos
    char aux[DIM] = {0};
    // inicializamos las variables de SSL
    BIO* bio = NULL;
    SSL_CTX* ctx = NULL;
    SSL* ssl = NULL;
    char cert[DIM] = "/usr/share/doc/libssl-dev/demos/sign/cert.pem";

    //analizamos los parámetros de entrada
    int i = 0;
    for(; i < argc; i++){
        if(strcmp(argv[i], "-p") == 0){ // leemos el puerto
            if(argc <= i + 1 || isNum(argv[i+1]) == 0){
                perror("Se esperaba un número después de -p");
                exit(-1);
            }else{
                PDEBUG("INFO: Puerto identificado\n");
                i++;
                port = atoi(argv[i]);
            }
            continue;
        }else if(strcmp(argv[i], "-d") == 0){ // dirección de destino
            if(argc <= i + 1){
                perror("Se esperaba una dirección después de -d");
                exit(-1);
            }else{
                PDEBUG("INFO: Destino identificado");
                i++;
                strcpy(dir, argv[i]);
            }
            continue;
        }else if(strcmp(argv[i], "-cert") == 0){ // dirección de destino
            if(argc <= i + 1){
                perror("Se esperaba una ruta de certificado después de -cert");
                exit(-1);
            }else{
                PDEBUG("INFO: Destino identificado");
                i++;
                strcpy(cert, argv[i]);
            }
            continue;
        }
    }

    /***********************************SSL************************************/
    PDEBUG("INFO: Iniciamos la librería SSL\n");
    SSL_load_error_strings(); // strings de error
    SSL_library_init(); // iniciams la libreria en sí
    ERR_load_BIO_strings(); // strings de error de BIO
    OpenSSL_add_all_algorithms(); // inicializamos los algoritmos de la librería

    PDEBUG("INFO: Conectando...\n");
    PDEBUG("INFO: Inicializando los punteros\n");
    ctx = SSL_CTX_new(SSLv23_client_method());
    ssl = NULL;
    PDEBUG("INFO: Cargamos el certificado\n");
    if(SSL_CTX_load_verify_locations(ctx, cert, NULL) == 0){
        char aux[] = "ERROR: No se pudo comprobar el certificado\n";
        write(WRITE, aux, strlen(aux));
        exit(-1);
    }
    PDEBUG("INFO: Inicializando BIO\n");
    bio = BIO_new_ssl_connect(ctx);
    BIO_get_ssl(bio, &ssl);
    if(ssl == 0){
        char aux[] = "ERROR: Error al crear el objeto ssl\n";
        write(WRITE, aux, strlen(aux));
        exit(-1);
    }
    PDEBUG("INFO: Estableciendo el modo de trabajo, no queremos reintentos\n");
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    PDEBUG("INFO: Intentando realizar la conexión\n");
    PDEBUG("INFO: Conectando a -> ");
    sprintf(aux, "%s:%i", dir, port);
    PDEBUG(aux);PDEBUG("\n");
    BIO_set_conn_hostname(bio, aux);
    PDEBUG("INFO: Verificando la conexión\n");
    if (BIO_do_connect(bio) < 1){
        char aux[] = "ERROR: al conectar el BIO\n";
        write(WRITE, aux, strlen(aux));
        exit(-1);
    }
    //PDEBUG("INFO: Verificando el resultado de la conexión\n");
    //printf("--%i-%i--\n", X509_V_OK, SSL_get_verify_result(ssl));
    //if (SSL_get_verify_result(ssl) != X509_V_OK) {
    //    char aux[] = "ERROR: verificar el resultado de la conexión\n";
    //    write(WRITE, aux, strlen(aux));
    //    exit(-1);
    //}

    PDEBUG("INFO: Conectado\n");
    /***********************************SSL************************************/

    ////Creamos el socket
    //PDEBUG("INFO: Creando el socket\n");
    //sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    ////Comprobamos si ha ocurrido un error al crear el socket
    //if(sock < 0){
    //    char aux[] = "ERROR: creación del socket {{socket()}}:\n";
    //    write(WRITE, aux, strlen(aux));
    //    exit(-1);
    //}
    //
    //
    //addr.sin_family = AF_INET; // familia AF_INET
    //addr.sin_port = htons(port); // definimos el puerto de conexión
    //PDEBUG("INFO: Traducimos la dirección del servidor\n");
    //server = gethostbyname(dir); /** convertimos la dirección dada
    //                              * en una dirección válida para el
    //                              * equipo y la metemos en addr
    //                              */
    ////Comprobamos si ha ocurrido un error obtener el host
    //if(server == NULL){
    //    write(WRITE, "ERROR: Host inválido\n", DIM);
    //    // terminamos la ejecución del programa
    //    exit(-1);
    //}
    //// copiamos el contenido correspondiente a la dirección de server en addr
    //bcopy(server->h_addr, &(addr.sin_addr.s_addr), server->h_length);
    //
    //// realizamos la conexión al servidor
    //PDEBUG("INFO: Nos conectamos al servidor\n");
    //error = connect(sock, (struct sockaddr*) &addr, length);
    //if(error < 0){
    //    char aux[] = "ERROR: al establecer la conexion con el servidor {{connect()}}: \n";
    //    write(WRITE, aux, strlen(aux));
    //    // terminamos la ejecución del programa
    //    exit(-1);
    //}
    //
    //PDEBUG("INFO: Conexión establecida\n");
    PDEBUG("INFO: Esperando mensaje de bienvenida\n");

    memset(&auxMsj, 0, sizeof(sms));
    if(client_read(bio, &auxMsj, sizeof(sms)) <= 0){
        PDEBUG("INFO: El socket está cerrado\n");
        perror("Error al leer contenido del socket porque está cerrado\n");
        perror("El cliente se parará\n");
        exit(-1);
    }


    // atendemos la autentificación del cliente
    do{
        bzero(aux, DIM);
        sprintf(aux, "%s ~$> %s\n", auxMsj.name, auxMsj.text);
        write(WRITE, aux, DIM);
        bzero(&auxMsj.text, SMS_LEN);

        if(auxMsj.flag == MSJ){ // si es un mensaje, solo imprimimos por la salida estandar

            memset(&auxMsj, 0, sizeof(sms));
            if(client_read(bio, &auxMsj, sizeof(sms)) <= 0){
                PDEBUG("INFO: El socket está cerrado\n");
                perror("Error al leer contenido del socket porque está cerrado\n");
                perror("El cliente se parará\n");
                exit(-1);
            }
            continue;

        }

        if(auxMsj.flag == REQ_PASS){ // si es password desactivamos el echo
            echo_off();
        }
        nbytes = read(READ, &auxMsj.text, SMS_LEN);
        if(auxMsj.flag == REQ_PASS){// si es password activamos el echo
            echo_on();
        }
        auxMsj.text[nbytes - 1] = '\0'; // eliminamos el retorno de carro
        
        // nos salimos?
        if(strcmp(auxMsj.text, "-x") == 0){
            PDEBUG("EXIT: Cerrando el cliente, avisando al servidor...\n");
            auxMsj.flag = CLI_EXIT;
            client_write(bio, &auxMsj, sizeof(sms));
            PDEBUG("EXIT: Cerrando el socket\n");
            shutdown(sock, 2);
            PDEBUG("EXIT: Cerrando el cliente\n");
            exit(0);
        }else{ // es un mensaje
            strcpy(name, auxMsj.text); // hacemos una copia del nombre introducido para no perderlo
            if(auxMsj.flag == REQ_TEXT){
                auxMsj.flag = REQ_AUTH;
            }else if(auxMsj.flag == REQ_PASS){ // entonces REQ_PASS
                auxMsj.flag = CHECK_PASS;
            }else if(auxMsj.flag == REQ_ROOM){ // entonces REQ_ROOM
                auxMsj.flag = CHECK_ROOM;
            }
            client_write(bio, &auxMsj, sizeof(sms));
            memset(&auxMsj, 0, sizeof(sms));
            if(client_read(bio, &auxMsj, sizeof(sms)) <= 0){
                PDEBUG("INFO: El socket está cerrado\n");
                perror("Error al leer contenido del socket porque está cerrado\n");
                perror("El cliente se parará\n");
                exit(-1);
            }
        }
    }while(auxMsj.flag != OK);

    PDEBUG("INFO: Usuario conectado\n");
    printf("Usuario conectado...\n");
    
    fd_set desc, descCopy; // definimos un descriptor que contendrá nuestros descriptores
    //inicializamos la lista de conexiones
    FD_ZERO(&desc);
    // Inicio del bit descriptor sock con el valor de sock
    int fd;
	if(BIO_get_fd(bio, &fd) < 0){
            write(WRITE, "ERROR: crear le descriptor %s\n", DIM);
            // terminamos la ejecución del programa
            exit(-1);
	}
    FD_SET (fd, &desc);
    // Inicio del bit descriptor connList con el valor del descriptor de entrada estándar
    FD_SET (READ, &desc);

    while(1){
        // hacemos una copia de seguridad para asegurarnos de no perder los datos
        descCopy = desc;
        // ¿Hay algún socket listo para leer?
        PDEBUG("INFO: ¿Hay algún socket listo para leer?\n");
        error = select(fd + 1, &descCopy, NULL, NULL, NULL);
        //Comprobamos si ha ocurrido un error al ponernos a escuchar
        if(error < 0){
            write(WRITE, "ERROR: al realizar la selección {{select()}}: %s\n", DIM);
            // terminamos la ejecución del programa
            exit(-1);
        }

        // recorriendo los sockets para ver los que están activos
        PDEBUG("INFO: recorriendo los sockets para ver los que están activos\n");
        if(FD_ISSET(fd, &descCopy)){
            PDEBUG("INFO: Nuevo mensaje recibido\n");
            if(client_read(bio, &auxMsj, sizeof(sms)) <= 0){
                PDEBUG("INFO: El socket está cerrado\n");
                perror("Error al leer contenido del socket porque está cerrado\n");
                perror("El cliente se parará\n");
                exit(-1);
            }

            switch(auxMsj.flag){
                case OK: // mensaje de aceptacion, mismo comportamiento que msj
                case MSJ:  // mensaje recibido
                    if(serverTalk != 1 || strcmp(auxMsj.name, SERVER) == 0){
                        PDEBUG("INFO: Recibido mensaje\n");
                        sprintf(aux, "%s ~$> %s\n", auxMsj.name, auxMsj.text);
                        write(WRITE, aux, strlen(aux));
                        sync();
                    }
                    break;
                case SERV_EXIT: // el servidor se va a cerrar
                    PDEBUG("EXIT: El servidor se está cerrando, se dejará de leer\n");
                    shutdown(sock, SHUT_RDWR);
                    sprintf(aux, "%s ~$> Servidor desconectado\n", SERVER);
                    write(WRITE, aux, strlen(aux));
                    sprintf(aux, "El proceso cliente se cerrará\n");
                    write(WRITE, aux, strlen(aux));
                    exit(0);
                    break;
                default:
                    sprintf(aux, "Recibido un mensaje mal formado\n");
                    write(WRITE, aux, strlen(aux));
                    sync();
                    break;
            }
        }else if(FD_ISSET(READ, &descCopy)){
            PDEBUG("INFO: Nuevo mensaje escrito\n");

            bzero(&auxMsj.text, SMS_LEN); // inicializamos el array
            nbytes = read(READ, &auxMsj.text, SMS_LEN); // leemos de la entrada estándar
            auxMsj.text[nbytes - 1] = 0; // eliminamos el retorno de carro

            // nos salimos?
            if(strcmp(auxMsj.text, "-x") == 0 && serverTalk != 1){

                PDEBUG("EXIT: Cerrando el cliente, avisando al servidor...\n");
                auxMsj.flag = CLI_EXIT;

            }else if(strcmp(auxMsj.text, "--serv") == 0){ // queremos hablar con el servidor

                PDEBUG("SERV_ADMIN: Iniciando la comunicación directa con el servidor\n");
                sprintf(aux, "%s ~$> Iniciada conversación con el servidor\n", SERVER);
                write(WRITE, aux, strlen(aux));
                serverTalk = 1;
                continue;

            }else if(sscanf(auxMsj.text, "--mp %s", aux) == 1){ // queremos hablar con el servidor

                PDEBUG("MP: Mensaje privado detectado\n");
                strcpy(auxMsj.to, aux);
                sprintf(aux, "%s ~$> Inserte el mensaje privado\n", SERVER);
                write(WRITE, aux, strlen(aux));
                auxMsj.flag = MP;
                nbytes = read(READ, &auxMsj.text, SMS_LEN); // leemos de la entrada estándar
                auxMsj.text[nbytes - 1] = 0; // eliminamos el retorno de carro

            }else{ // es un mensaje

                if(serverTalk == 1){

                    PDEBUG("SERV_ADMIN: Enviando mensaje al servidor\n");
                    auxMsj.flag = SERV_ADMIN;

                    if(strcmp(auxMsj.text, "exit") == 0){

                        serverTalk = 0;
                        sprintf(aux, "%s ~$> Envio de mensajes de configuración terminada:\n", SERVER);
                        write(WRITE, aux, strlen(aux));
                        continue;

                    }

                }else{

                    auxMsj.flag = MSJ;

                }
            }

            strcpy(auxMsj.name, name); // hacemos una copia del nombre introducido para no perderlo
            PDEBUG("INFO: Enviando mensaje...\n");
            client_write(bio, &auxMsj, sizeof(sms));
            PDEBUG("INFO: Mensaje Enviado\n");

            // nos salimos?
            if(auxMsj.flag == CLI_EXIT){

                PDEBUG("EXIT: Cerrando el socket\n");
                shutdown(sock, SHUT_RDWR);
                PDEBUG("EXIT: Cerrando el cliente\n");
                exit(0);
                
            }
        }
    }
    
    return 0;
}
Esempio n. 13
0
//--------------------------------------------------------------------------------------------------
le_result_t secSocket_Connect
(
    secSocket_Ctx_t* ctxPtr,     ///< [INOUT] Secure socket context pointer
    char*            hostPtr,    ///< [IN] Host to connect on
    uint16_t         port,       ///< [IN] Port to connect on
    SocketType_t     type,       ///< [IN] Socket type (TCP, UDP)
    int*             fdPtr       ///< [OUT] Socket file descriptor
)
{
    SSL* sslPtr = NULL;
    BIO* bioPtr = NULL;
    char hostAndPort[HOST_ADDR_LEN + PORT_STR_LEN + 1];
    le_result_t status = LE_FAULT;
    unsigned long code;

    if ((!ctxPtr) || (!hostPtr) || (!fdPtr))
    {
        LE_ERROR("Invalid argument: ctxPtr %p, hostPtr %p fdPtr %p", ctxPtr, hostPtr, fdPtr);
        return LE_BAD_PARAMETER;
    }

    OpensslCtx_t* contextPtr = GetContext(ctxPtr);
    if (!contextPtr)
    {
        return LE_BAD_PARAMETER;
    }

    // Start the connection
    snprintf(hostAndPort, sizeof(hostAndPort), "%s:%d", hostPtr, port);
    LE_INFO("Connecting to %d/%s:%d - %s...", type, hostPtr, port, hostAndPort);

    // Clear the current thread's OpenSSL error queue
    ERR_clear_error();

    // Setting up the BIO abstraction layer
    bioPtr = BIO_new_ssl_connect(contextPtr->sslCtxPtr);
    if (!bioPtr)
    {
        LE_ERROR("Unable to allocate and connect BIO");
        goto err;
    }

    BIO_get_ssl(bioPtr, &sslPtr);
    if (!sslPtr)
    {
        LE_ERROR("Unable to locate SSL pointer");
        goto err;
    }

    // Set the SSL_MODE_AUTO_RETRY flag: it will cause read/write operations to only return after
    // the handshake and successful completion
    SSL_set_mode(sslPtr, SSL_MODE_AUTO_RETRY);

    BIO_set_conn_hostname(bioPtr, hostAndPort);

    // Attempt to connect the supplied BIO and perform the handshake.
    // This function returns 1 if the connection was successfully established and 0 or -1 if the
    // connection failed.
    if (BIO_do_connect(bioPtr) != 1)
    {
        LE_ERROR("Unable to connect BIO to %s", hostAndPort);
        goto err;
    }

    // Get the FD linked to the BIO
    BIO_get_fd(bioPtr, fdPtr);
    BIO_socket_nbio(*fdPtr, 1);

    contextPtr->bioPtr = bioPtr;
    return LE_OK;

err:
    code = ERR_peek_last_error();

    if ((ERR_GET_LIB(code) == ERR_LIB_BIO) || (ERR_GET_LIB(code) == ERR_LIB_SSL))
    {
        switch (ERR_GET_REASON(code))
        {
            case ERR_R_MALLOC_FAILURE:
                status = LE_NO_MEMORY;
                break;

            case BIO_R_NULL_PARAMETER:
                status = LE_BAD_PARAMETER;
                break;

#if defined(BIO_R_BAD_HOSTNAME_LOOKUP)
            case BIO_R_BAD_HOSTNAME_LOOKUP:
                status = LE_UNAVAILABLE;
                break;
#endif

            case BIO_R_CONNECT_ERROR:
                status = LE_COMM_ERROR;
                break;

#if defined(BIO_R_EOF_ON_MEMORY_BIO)
            case BIO_R_EOF_ON_MEMORY_BIO:
                status = LE_CLOSED;
                break;
#endif

            default:
                status = LE_FAULT;
                break;
        }
     }

    return status;
}
enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb)
{
    SSL *ssl = NULL;
    int rslt;
    char const* origin = PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN;

    PUBNUB_ASSERT(pb_valid_ctx_ptr(pb));
    PUBNUB_ASSERT_OPT((pb->state == PBS_READY) || (pb->state == PBS_WAIT_CONNECT));

    if (!pb->options.useSSL) {
        return resolv_and_connect_wout_SSL(pb);
    }

    if (NULL == pb->pal.ctx) {
        PUBNUB_LOG_TRACE("pb=%p: Don't have SSL_CTX\n", pb);
        pb->pal.ctx = SSL_CTX_new(SSLv23_client_method());
        if (NULL == pb->pal.ctx) {
            ERR_print_errors_cb(print_to_pubnub_log, NULL);
            PUBNUB_LOG_ERROR("pb=%p SSL_CTX_new failed\n", pb);
            return pbpal_resolv_resource_failure;
        }
        PUBNUB_LOG_TRACE("pb=%p: Got SSL_CTX\n", pb);
        add_pubnub_cert(pb->pal.ctx);
    }

    if (NULL == pb->pal.socket) {
        PUBNUB_LOG_TRACE("pb=%p: Don't have BIO\n", pb);
        pb->pal.socket = BIO_new_ssl_connect(pb->pal.ctx);
        if (PUBNUB_TIMERS_API) {
            pb->pal.connect_timeout = time(NULL)  + pb->transaction_timeout_ms/1000;
        }
    }
    else {
        BIO_get_ssl(pb->pal.socket, &ssl);
        if (NULL == ssl) {
            return resolv_and_connect_wout_SSL(pb);
        }
        ssl = NULL;
    }
    if (NULL == pb->pal.socket) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        return pbpal_resolv_resource_failure;
    }

    PUBNUB_LOG_TRACE("pb=%p: Using BIO == %p\n", pb, pb->pal.socket);

    BIO_get_ssl(pb->pal.socket, &ssl);
    PUBNUB_ASSERT(NULL != ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* maybe not auto_retry? */
    if (pb->pal.session != NULL) {
        SSL_set_session(ssl, pb->pal.session);
    }

    BIO_set_conn_hostname(pb->pal.socket, origin);
    BIO_set_conn_port(pb->pal.socket, "https");
    if (pb->pal.ip_timeout != 0) {
        if (pb->pal.ip_timeout < time(NULL)) {
            pb->pal.ip_timeout = 0;
        }
        else {
            PUBNUB_LOG_TRACE("SSL re-connect to: %d.%d.%d.%d\n", pb->pal.ip[0], pb->pal.ip[1], pb->pal.ip[2], pb->pal.ip[3]);
            BIO_set_conn_ip(pb->pal.socket, pb->pal.ip);
        }
    }
    
    BIO_set_nbio(pb->pal.socket, !pb->options.use_blocking_io);
    
    WATCH_ENUM(pb->options.use_blocking_io);
    if (BIO_do_connect(pb->pal.socket) <= 0) {
        if (BIO_should_retry(pb->pal.socket) && PUBNUB_TIMERS_API && (pb->pal.connect_timeout > time(NULL))) {
            PUBNUB_LOG_TRACE("pb=%p: BIO_should_retry\n", pb);
            return pbpal_connect_wouldblock;
        }
        /* Expire the IP for the next connect */
        pb->pal.ip_timeout = 0;
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        if (pb->pal.session != NULL) {
            SSL_SESSION_free(pb->pal.session);
            pb->pal.session = NULL;
        }
        PUBNUB_LOG_ERROR("pb=%p: BIO_do_connect failed\n", pb);
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_TRACE("pb=%p: BIO connected\n", pb);
    {
        int fd = BIO_get_fd(pb->pal.socket, NULL);
        socket_set_rcv_timeout(fd, pb->transaction_timeout_ms);
    }

    rslt = SSL_get_verify_result(ssl);
    if (rslt != X509_V_OK) {
        PUBNUB_LOG_WARNING("pb=%p: SSL_get_verify_result() failed == %d(%s)\n", pb, rslt, X509_verify_cert_error_string(rslt));
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        if (pb->options.fallbackSSL) {
            BIO_free_all(pb->pal.socket);
            pb->pal.socket = NULL;
            return resolv_and_connect_wout_SSL(pb);
        }
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_INFO("pb=%p: SSL session reused: %s\n", pb, SSL_session_reused(ssl) ? "yes" : "no");
    if (pb->pal.session != NULL) {
        SSL_SESSION_free(pb->pal.session);
    }
    pb->pal.session = SSL_get1_session(ssl);
    if (0 == pb->pal.ip_timeout) {
        pb->pal.ip_timeout = SSL_SESSION_get_time(pb->pal.session) + SSL_SESSION_get_timeout(pb->pal.session);
        memcpy(pb->pal.ip, BIO_get_conn_ip(pb->pal.socket), 4);
    }
    PUBNUB_LOG_TRACE("pb=%p: SSL connected to IP: %d.%d.%d.%d\n", pb, pb->pal.ip[0], pb->pal.ip[1], pb->pal.ip[2], pb->pal.ip[3]);

    return pbpal_connect_success;
}
Esempio n. 15
0
int main(int argc, const char* argv[]) {
	
	if(argc != 4) {
		printf("Usage: %s <server> <port> <certificate>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	// Setting up buffer for receiving data
	char buf[MAXDATASIZE];
	memset(buf, 0, MAXDATASIZE*sizeof(char));

	// Init SSL
	SSL_library_init();
	SSL_load_error_strings();
	ERR_load_BIO_strings();
	OpenSSL_add_all_algorithms();

	// Make connection
	struct addrinfo hints, *results, *i;
	int status;
	char ipstr[INET6_ADDRSTRLEN];
	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	// Try to get addrinfo, exiting on error
	if ((status = getaddrinfo(argv[1], argv[2], &hints, &results)) != 0) {
		fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
		exit(EXIT_FAILURE);
	}

	printf("IP addresses for %s:\n", argv[1]);
	for (i = results; i != NULL; i = i->ai_next) {
		void* addr;
		char* ipver;
		if (i->ai_family == AF_INET6) {
			struct sockaddr_in6* ipv6 = (struct sockaddr_in6*) i->ai_addr;
			addr = &(ipv6->sin6_addr);
			ipver = "IPv6";
		}
		else {
			struct sockaddr_in* ipv4 = (struct sockaddr_in*) i->ai_addr;
			addr = &(ipv4->sin_addr);
			ipver = "IPv4";
	}

	inet_ntop(i->ai_family, addr, ipstr, INET6_ADDRSTRLEN);
	printf(" %s: %s\n\n", ipver, ipstr);	
	}

	// SSL
	BIO* b;
	char ipp[20];
	memset(ipp, 0, 20*sizeof(char));
	strcat(ipp, ipstr);
	strcat(ipp, ":");
	strcat(ipp, argv[2]);

	printf("Connecting to %s\n", ipp);

	SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
	SSL* ssl;

	b = BIO_new_ssl_connect(ctx);
	BIO_get_ssl(b, &ssl);
	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

	if(!b)
		printf("Error loading bio\n");


	if(!SSL_CTX_load_verify_locations(ctx, argv[3], NULL)) {
		printf("Error loading trust store %s\n", argv[3]);
		exit(EXIT_FAILURE);
	}

	// Connect SSL
	BIO_set_conn_hostname(b, ipp);
	if(BIO_do_connect(b) <= 0) {
		printf("Error with making SSL connection\n");
		exit(EXIT_FAILURE);
	}
	
	printf("Successful SSL connection\n");

	// Check the certificate
	if(SSL_get_verify_result(ssl) != X509_V_OK) {
		printf("Certificate not valid\n");
		exit(EXIT_FAILURE);
	}

	// Printing out the used cipher
	printf("SSL uses cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
	

	// Checking the commonName matches the hostname
	X509* p;
	char p_CN[256];
	p = SSL_get_peer_certificate(ssl);
	X509_NAME_get_text_by_NID(X509_get_subject_name(p), NID_commonName, p_CN, 256);

	printf("commonName: %s", p_CN);

	if(!strcmp(argv[1], p_CN))
		printf("...OK\n");
	else {
		printf("...FAILED\n");
		exit(EXIT_FAILURE);
	}


	// Read validation code
	BIO_read(b, buf, 3);	

	printf("Validation code: %s\n", buf); 

	// Send validation:226143
	strcat(buf, ":226143");
	printf("Sending \"%s\"\n", buf);
	BIO_write(b, buf, 10);

	// Read response
	BIO_read(b, buf, MAXDATASIZE);

	printf("Received \"%s\"\n", buf);	

	// Free structures and close
	BIO_free_all(b);
	SSL_CTX_free(ctx);
	return 0;
}