Exemple #1
0
long TLS_SOCKET_CLASS::postConnectionCheck(SSL* ssl_ptr)

//  DESCRIPTION     : Performs checks after the connection is made to insure all is well.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           : 
//<<===========================================================================
{
	long result;

	if (checkRemoteCertificateM)
	{
		X509* cert_ptr;

		// No error will be generated by the OpenSSL library during the connection if the client 
		// does not send a certificate, even if one was requested.  We check here to make sure the 
		// certificate was sent if we required it.  If it was sent, OpenSSL will have verified it, 
		// so we don't need to do that here.  

		// Another thing that can be checked is to make sure that the certificate is for the node 
		// we think we are talking to, since the library will validate any certificate that is 
		// signed by a trusted Certificate Authority.  DVT does not perform this check since a 
		// failure here is not a connectivity problem but just a matter of getting the correct 
		// certificate installed on the unit under test.

		// To fully meet the IHE requirements, the certificate should be checked to make sure the 
		// sender is on a list of authorized nodes.  This is where that check would be performed.  
		// DVT does not support this functionality.

		// get the peer's certificate
		cert_ptr = SSL_get_peer_certificate(ssl_ptr);
		if (cert_ptr == NULL)
		{
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Error peer certificate was not received");
			}

			return X509_V_ERR_APPLICATION_VERIFICATION;
		}
 
		X509_free(cert_ptr);

		// get the result of the OpenSSL verification
		result = SSL_get_verify_result(ssl_ptr);
		if (result != X509_V_OK)
		{
			openSslError("in post connection check");
		}

		return result;
	}
	else
	{
		// not checking remote certificates, nothing to do here
		return X509_V_OK;
	}
}
Exemple #2
0
OsStatus OsEncryption::crypto(Direction direction)
{
    OsStatus retval = init(direction);

#if defined(OSENCRYPTION)
    if (retval == OS_SUCCESS)
    {
        if (sIgnoreEncryption)
        {
            memcpy(mResults, mData, mDataLen);
            mResultsLen = mDataLen;
        }
        else
        {
            retval = OS_FAILED;
            unsigned char *in = mData;
            int inLen = mDataLen;
            unsigned char *out = mResults;
            int outLen = 0;

            if (mHeaderLen > 0)
            {
                if (direction == ENCRYPT)
                {
                    // copy in header
                    memcpy(out, mHeader, mHeaderLen);
                    out += mHeaderLen;
                    outLen += mHeaderLen;
                }
                else
                {
                    // ignore header
                    in += mHeaderLen;
                    inLen -= mHeaderLen;
                }
            }

            int outLenPart1 = 0;
            if (EVP_CipherUpdate(&(mContext), out, &outLenPart1, in, inLen))
            {
                out += outLenPart1;
                int outLenPart2 = 0;
                if (EVP_CipherFinal(&(mContext), out, &outLenPart2))
                {
                    outLen += outLenPart1 + outLenPart2;
                    retval = OS_SUCCESS;
                    mResults[outLen] = 0;
                    mResultsLen = outLen;
                }
            }
        }
    }

    if (retval != OS_SUCCESS)
    {
        openSslError();
        release();
    }

#endif
   return retval;
}
Exemple #3
0
bool TLS_SOCKET_CLASS::writeBinary(const BYTE *buffer_ptr, UINT length)

//  DESCRIPTION     : Write given data to socket.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           :
//<<===========================================================================
{
	int written_bytes = 0;
	int readFileDesc;
	int writeFileDesc;
	struct fd_set readFds;
	struct fd_set writeFds;
	bool waitOnWrite;
	int timeoutRemaining; // the amount of time left in the timeout period
	struct timeval tv = {1, 0}; // always timeout in 1 second

	if (terminatingM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating.  Cannot write.");
		}

		// return - in process of termintating
		return false;
	}

	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::write(%d bytes)", length);
	}

	if (!connectedM) 
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Not connected to peer - can't write data");
		}

		return false;
	}

	// get the file descriptors and set up the file descriptor sets for select()
	readFileDesc = SSL_get_rfd(sslM_ptr);
	if (readFileDesc == -1)
	{
		openSslError("getting read socket file descriptor");
		return false;
	}

	writeFileDesc = SSL_get_wfd(sslM_ptr);
	if (writeFileDesc == -1)
	{
		openSslError("getting write socket file descriptor");
		return false;
	}

	waitOnWrite = true;
	timeoutRemaining = socketTimeoutM;

	// write the buffer contents to socket
	while (written_bytes < (int) length)
	{
		int bytes;
		int sel;

		if (waitOnWrite)
		{
			FD_ZERO(&writeFds);
			FD_SET(writeFileDesc, &writeFds);

			// wait for something to write
			sel = select(writeFileDesc + 1, NULL, &writeFds, NULL, &tv);
		}
		else
		{
			FD_ZERO(&readFds);
			FD_SET(readFileDesc, &readFds);

			// wait for something to read
			sel = select(readFileDesc + 1, &readFds, NULL, NULL, &tv);
		}

		if (terminatingM)
		{
			return false;
		}

		waitOnWrite = true;

		if (sel == 1)
		{
			// data read to write (or possibly read - but use the same call)
			bytes = SSL_write(sslM_ptr, (char *)(buffer_ptr + written_bytes), (length - written_bytes));
			if (bytes > 0)
			{
				// wrote some data
				written_bytes += bytes;
				timeoutRemaining = socketTimeoutM; // reset the timeout
			}
			else if (bytes == 0)
			{
				// socket closed
				if (loggerM_ptr)
				{
					loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Secure connection closed during socket write");
				}
				return false;
			}
			else
			{
				// operation did not complete, see what happened
				int err = SSL_get_error(sslM_ptr, bytes);
				if (err == SSL_ERROR_WANT_READ)
				{
					// need to wait for data to be available for reading, and then retry the same operation
					waitOnWrite = false;
					timeoutRemaining = socketTimeoutM; // reset the timeout
				}
				if (err == SSL_ERROR_WANT_WRITE)
				{
					// need to wait for the write file descriptor to be able to write and then try again
					timeoutRemaining = socketTimeoutM; // reset the timeout
				}
				else
				{
					// an error occured
					if ((err == SSL_ERROR_SYSCALL) && (ERR_peek_error() == 0) && (bytes == -1))
					{
						// an error in the system call occured
						openSslError("writing to secure socket");
						if (loggerM_ptr && (loggerM_ptr->getLogMask() & LOG_ERROR))
						{
							loggerM_ptr->text(LOG_NONE, 1, "    write() error code = %d", WSAGetLastError());
						}
					}
					else
					{
						openSslError("reading from secure socket");
					}
					return false;
				}
			}
		}
		else if (sel == 0)
		{
			// no data at the end of the timeout
			if (--timeoutRemaining > 0)
			{
				// still have time left on the timeout, go back and wait some more
			}
			else
			{
				// timeout expired
				if (loggerM_ptr)
				{
					loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Connection timed-out while waiting to send data");
				}
				return false;
			}
		}
		else if (sel == SOCKET_ERROR)
		{
			// socket error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Error waiting to send data (error code %d)", WSAGetLastError());
			}
			return false;
		}
		else
		{
			// unknown error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Unknown error while waiting to send data (select returned %d)", sel);
			}
			return false;
		}
	}

	return (written_bytes == (int) length) ? true : false;
}
Exemple #4
0
void TLS_SOCKET_CLASS::close()

//  DESCRIPTION     : Close socket down.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           :
//<<===========================================================================
{
	if (ownerThreadIdM != getThreadId())
	{
		// this thread does not own the socket, just set the terminatng flag and let the owning 
		// thread take care of the close
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::close() - starting to terminate connection");
		}

		terminatingM = true;
		return;
	}

	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::close()");
	}

	if (connectedM)
	{
		if (cacheTlsSessionsM)
		{
			if (savedClientSessionM_ptr != NULL)
			{
				SSL_SESSION_free(savedClientSessionM_ptr);
			}

			// cache the session
			savedClientSessionM_ptr = SSL_get1_session(sslM_ptr);
		}

		// shutdown the connection - send our shutdown message
		if (SSL_shutdown(sslM_ptr) == 0)
		{
			// don't wait for the peer shutdwon message - they may not respond, which will cause us to block
		}

		connectedM = false;
	}
	
	if (listeningM)
	{
		// the freeing of the acceptBio below closes the socket
		listeningM = false;
	}
	
	if (acceptBioM_ptr != NULL)
	{
		BIO_free(acceptBioM_ptr);
		acceptBioM_ptr = NULL;
	}

	if (sslM_ptr != NULL)
	{
		SSL_free(sslM_ptr);
		sslM_ptr = NULL;
	}

	// report any outstanding SSL errors
	if (ERR_peek_error() != 0)
	{
		openSslError("closing socket");
	}

	// free the OpenSSL error state.  This really needs to be done on a per thread basis.
	ERR_remove_state(0);

	connectedM = false;
	listeningM = false;
	terminatingM = false;
}
Exemple #5
0
bool TLS_SOCKET_CLASS::accept(BASE_SOCKET_CLASS** acceptedSocket_ptr_ptr)

//  DESCRIPTION     : Accept connection from listen socket.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           : The returned socket was new'ed so it must be deleted by the caller
//<<===========================================================================
{
	*acceptedSocket_ptr_ptr = NULL;
	BIO* acceptedBio_ptr;
	SSL* acceptedSsl_ptr;
	long error;
	int fileDesc;
	struct fd_set fds;
	struct timeval tv = {1, 0}; // always timeout in 1 second
	int sel;

	if (terminatingM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating.  Cannot accept.");
		}

		// return - in process of termintating
		return false;
	}

	// make sure we are listening to the port
	if (!listeningM)
	{
		if (loggerM_ptr)
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Socket is not listening to port %d.  Cannot accept a connection.", 
				localListenPortM);
		}
		return false;
	}
	if (acceptBioM_ptr == NULL)
	{
		if (loggerM_ptr)
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Socket is listening to port %d, but not bound.", 
				localListenPortM);
		}
		listeningM = false;
		return false;
	}

	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::accept()");
	}

	// get the file descriptor and set up the file descriptor set for select()
	fileDesc = BIO_get_fd(acceptBioM_ptr, NULL);
	if (fileDesc == -1)
	{
		openSslError("getting listen socket file descriptor");
		return false;
	}

	// wait for a connection
	do
	{
		FD_ZERO(&fds);
		FD_SET(fileDesc, &fds);

		sel = select(fileDesc + 1, &fds, NULL, NULL, &tv);
		if (sel == 0)
		{
			// no data at the end of the timeout - check for terminating
			if (terminatingM)
			{
				return false;
			}
		}
		else if (sel == SOCKET_ERROR)
		{
			// socket error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Error waiting to accept connection (error code %d)", WSAGetLastError());
			}
			return false;
		}
		else if (sel != 1)
		{
			// unknown error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Unknown error while waiting to accept connection (select returned %d)", sel);
			}
			return false;
		}

	} while (sel != 1);

	// accept a connection
	if (BIO_do_accept(acceptBioM_ptr) <= 0)
	{
		openSslError(LOG_DEBUG, "accepting connection on port %d", localListenPortM);
		close();
		return false;
	}

	// get the new connection
	acceptedBio_ptr = BIO_pop(acceptBioM_ptr);

	// setup the socket structure
	acceptedSsl_ptr = SSL_new(ctxM_ptr);
	if (acceptedSsl_ptr == NULL)
	{
		openSslError("creating accepted secure socket object");
		BIO_free(acceptedBio_ptr);
		return false;
	}

	// set the 'this' pointer for the callbacks openSslMsgCallback and openSslVerifyCallback
	SSL_set_msg_callback_arg(acceptedSsl_ptr, static_cast<void*>(this));

	SSL_set_accept_state(acceptedSsl_ptr);
	SSL_set_bio(acceptedSsl_ptr, acceptedBio_ptr, acceptedBio_ptr); // the ssl takes over the BIO memory
	if (SSL_accept(acceptedSsl_ptr) <= 0)
	{
		openSslError("accepting secure connection to port %d", localListenPortM);
		SSL_free(acceptedSsl_ptr);
		return false;
	}

	// make sure everything is OK
	error = postConnectionCheck(acceptedSsl_ptr);
	if (error != X509_V_OK)
	{
		openSslError("checking connection parameters after accepting from port %d", localListenPortM);
		SSL_free(acceptedSsl_ptr);
		return false;
	}

	// create a socket for the new connection
	*acceptedSocket_ptr_ptr = new TLS_SOCKET_CLASS(*this, acceptedSsl_ptr);

	if (loggerM_ptr && (loggerM_ptr->getLogMask() & LOG_DEBUG))
	{
		char buffer[128];

		SSL_CIPHER_description(SSL_get_current_cipher(acceptedSsl_ptr), buffer, 128);
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - %s connection opened using cipher %s",
			SSL_get_version(acceptedSsl_ptr), buffer);
	}

	return true;
}
Exemple #6
0
bool TLS_SOCKET_CLASS::listen()

//  DESCRIPTION     : Setup the listen port.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           :
//<<===========================================================================
{
	ostringstream listenPort;

	// make sure the socket is not already in use
	if (terminatingM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating.  Cannot listen.");
		}

		// return - in process of termintating
		return false;
	}
	if (connectedM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Already connected to \"%s\".  Cannot listen to port %d.", 
				remoteHostnameM.c_str(), localListenPortM);
		}

		// return - already connected
		return false;
	}
	else if (listeningM)
	{
		if (loggerM_ptr)
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Socket is already listening to port %d.  Cannot listen again.", 
				localListenPortM);
		}

		// return - socket is already being used to listen
		return false;
	}
	listeningM = false;

	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::listen(%d)", localListenPortM);
	}
 
	if (acceptBioM_ptr != NULL)
	{
		BIO_free(acceptBioM_ptr);
		acceptBioM_ptr = NULL;
	}

	// create the socket
	listenPort << localListenPortM;
	acceptBioM_ptr = BIO_new_accept(const_cast<char *>(listenPort.str().c_str()));
	if (acceptBioM_ptr == NULL)
	{
		openSslError("creating server socket to port %d", localListenPortM);
		return false;
	}

	// bind to the port
	if (BIO_do_accept(acceptBioM_ptr) <= 0)
	{
		openSslError("binding server socket to port %d", localListenPortM);
		BIO_free(acceptBioM_ptr);
		acceptBioM_ptr = NULL;
		return false;
	}
 
	// listen socket set up
	listeningM = true;

	// return whether listening or not
	return listeningM;
}
Exemple #7
0
bool TLS_SOCKET_CLASS::connect()

//  DESCRIPTION     : Set up connection to the remote host.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           :
//<<===========================================================================
{
	BIO* bio_ptr;
	long error;
	ostringstream remoteHost;

	// make sure the socket is not already in use
	if (terminatingM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating.  Cannot connect.");
		}

		// return - in process of termintating
		return false;
	}
	if (connectedM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Already connected to \"%s\".  Cannot connect again.", remoteHostnameM.c_str());
		}

		// return - already connected
		return false;
	}
	else if (listeningM)
	{
		if (loggerM_ptr)
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Socket is already listening to port %d.  Cannot connect to \"%s\".", 
				localListenPortM, remoteHostnameM.c_str());
		}

		// return - socket is already being used to listen
		return false;
	}
	connectedM = false;
	
	if (remoteHostnameM.length() == 0)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - No Remote Hostname defined. Can't make connection.");
		}

		// return - don't know what to connect to
		return false;
	}

	// create the transport object
	remoteHost << remoteHostnameM << ':' << remoteConnectPortM;
	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::connect(%s)", remoteHost.str().c_str());
	}
	bio_ptr = BIO_new_connect(const_cast<char *>(remoteHost.str().c_str()));
	if (!bio_ptr)
	{
		openSslError("creating connection");
		return false;
	}

	if (BIO_do_connect(bio_ptr) <= 0)
	{
		openSslError("connecting to remote machine");
		BIO_free(bio_ptr);
		return false;
	}

	// create the secure socket object
	if (sslM_ptr != NULL)
	{
		SSL_free(sslM_ptr);
	}
	sslM_ptr = SSL_new(ctxM_ptr);
	if (sslM_ptr == NULL)
	{
		openSslError("creating secure socket object");
		BIO_free(bio_ptr);
		return false;
	}

	// set the 'this' pointer for the callbacks openSslMsgCallback and openSslVerifyCallback
	SSL_set_msg_callback_arg(sslM_ptr, static_cast<void*>(this));

	// restore the session
	if (cacheTlsSessionsM && (savedClientSessionM_ptr != NULL))
	{
		SSL_set_session(sslM_ptr, savedClientSessionM_ptr);
		SSL_SESSION_free(savedClientSessionM_ptr); // we're done with the saved session now, we'll 
													// get a new one when the session is closed.
		savedClientSessionM_ptr = NULL;
	}

	// make the SSL connection
	SSL_set_bio(sslM_ptr, bio_ptr, bio_ptr); // the ssl takes over the mangement of the bio memory
	if (SSL_connect(sslM_ptr) <= 0)
	{
		openSslError("connecting to %s", remoteHost.str().c_str());
		SSL_free(sslM_ptr);
		sslM_ptr = NULL;
		return false;
	}

	// make sure everything is OK
	error = postConnectionCheck(sslM_ptr);
	if (error != X509_V_OK)
	{
		openSslError("checking connection parameters after connecting to %s", remoteHost.str().c_str());
		SSL_free(sslM_ptr);
		sslM_ptr = NULL;
		return false;
	}

	// socket connected to peer
	connectedM = true;

	if (loggerM_ptr && (loggerM_ptr->getLogMask() & LOG_DEBUG))
	{
		char buffer[128];

		SSL_CIPHER_description(SSL_get_current_cipher(sslM_ptr), buffer, 128);
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - %s connection opened using cipher %s",
			SSL_get_version(sslM_ptr), buffer);
	}

	// return whether connected or not
	return connectedM;
}
Exemple #8
0
bool TLS_SOCKET_CLASS::openSslInitialize()

//  DESCRIPTION     : Called to initialize the OpenSSL library for this session.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           : 
//<<===========================================================================
{
	int verify_mode;
	long ssl_options;

	openSslM_ptr = OPENSSL_CLASS::getInstance();
	if (openSslM_ptr == NULL)
	{
		if (loggerM_ptr)
		{
			loggerM_ptr->text(LOG_ERROR, 1, "OpenSSL library not initialized when initializing Secure Socket");
		}
		return false;
	}

	// setup the connection factory for this session
	if (tlsVersionM == TLS_VERSION_TLSv1)
	{
		ctxM_ptr = SSL_CTX_new(TLSv1_method());
	}
	else if (tlsVersionM == TLS_VERSION_SSLv3)
	{
		ctxM_ptr = SSL_CTX_new(SSLv3_method());
	}
	else
	{
		ctxM_ptr = SSL_CTX_new(SSLv23_method());
	}

	if (ctxM_ptr == NULL)
	{
		openSslError("initializing connection factory");
		return false;
	}

	SSL_CTX_set_default_passwd_cb(ctxM_ptr, OPENSSL_CLASS::openSslPasswordCallback);
	char *password = new char[certificateFilePasswordM.length() + 1]; // create a buffer to store the password
																	  // this is freed in the destructor
	strcpy(password, certificateFilePasswordM.c_str());
	SSL_CTX_set_default_passwd_cb_userdata(ctxM_ptr, (void *)password);

	if (SSL_CTX_load_verify_locations(ctxM_ptr, certificateFilenameM.c_str(), NULL) != 1)
	{
		openSslError("loading trusted certificate file");
	}

	SSL_CTX_set_client_CA_list(ctxM_ptr, SSL_load_client_CA_file(certificateFilenameM.c_str()));
	ERR_clear_error(); // the last call leaves an error in the stack

	if (!readCredentials(ctxM_ptr))
	{
		openSslError("loading credentials");
	}

	if (checkRemoteCertificateM)
	{
		verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
	}
	else
	{
		verify_mode = SSL_VERIFY_NONE;
	}
	SSL_CTX_set_verify(ctxM_ptr, verify_mode, openSslVerifyCallback);

	if ((loggerM_ptr != NULL) && ((loggerM_ptr->getLogMask() & LOG_DEBUG) != 0))
	{
		SSL_CTX_set_msg_callback(ctxM_ptr, openSslMsgCallback);
		// the 'this' pointer needed by openSslMsgCallback and openSslVerfyCallback must be set by 
		// SSL_set_msg_callback_arg for each SSL created
	}

	ssl_options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE;
	if (tlsVersionM.find(TLS_VERSION_SSLv2) == string::npos)
	{
		ssl_options |= SSL_OP_NO_SSLv2;
	}
	if (tlsVersionM.find(TLS_VERSION_SSLv3) == string::npos)
	{
		ssl_options |= SSL_OP_NO_SSLv3;
	}
	if (tlsVersionM.find(TLS_VERSION_TLSv1) == string::npos)
	{
		ssl_options |= SSL_OP_NO_TLSv1;
	}
	SSL_CTX_set_options(ctxM_ptr, ssl_options);

	SSL_CTX_set_timeout(ctxM_ptr, tlsCacheTimeoutM);
	SSL_CTX_set_session_id_context(ctxM_ptr, (const unsigned char *)"DVT", 3);
	if (cacheTlsSessionsM)
	{
		SSL_CTX_set_session_cache_mode(ctxM_ptr, SSL_SESS_CACHE_BOTH);
	}
	else
	{
		SSL_CTX_set_session_cache_mode(ctxM_ptr, SSL_SESS_CACHE_OFF);
	}

	SSL_CTX_set_tmp_dh_callback(ctxM_ptr, OPENSSL_CLASS::tmpDhCallback);

	if (SSL_CTX_set_cipher_list(ctxM_ptr, cipherListM.c_str()) != 1)
	{
		openSslError("initializing cipher list (no valid ciphers)");
	}
	
	return true;
}
Exemple #9
0
INT	TLS_SOCKET_CLASS::readBinary(BYTE *buffer_ptr, UINT length)

//  DESCRIPTION     : Read data from socket to given buffer.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           : Blocks until all of the requested data is read or a timeout occurs.
//<<===========================================================================
{
	int read_bytes = 0; // number of bytes read from the socket
	int readFileDesc;
	int writeFileDesc;
	struct fd_set readFds;
	struct fd_set writeFds;
	bool sslWaitOnRead; // indicates that the OpenSSL library is waiting for data to be sent on the socket
	bool sslWaitOnWrite; // indicates that the OpenSSL library is waiting to be able to write to the socket interface
	int timeoutRemaining; // the amount of time left in the timeout period
	struct timeval tv = {1, 0}; // always timeout in 1 second

	if (terminatingM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating.  Cannot read.");
		}

		// return - in process of termintating
		return -1;
	}

	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::read(%d bytes)", length);
	}

	if (!connectedM) 
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Not connected to peer - can't read data");
		}

		return -1;
	}

	// get the file descriptors and set up the file descriptor sets for select()
	readFileDesc = SSL_get_rfd(sslM_ptr);
	if (readFileDesc == -1)
	{
		openSslError("getting read socket file descriptor");
		return -1;
	}

	writeFileDesc = SSL_get_wfd(sslM_ptr);
	if (writeFileDesc == -1)
	{
		openSslError("getting write socket file descriptor");
		return -1;
	}

	sslWaitOnRead = false;
	sslWaitOnWrite = false;
	timeoutRemaining = socketTimeoutM;

	// fill the buffer from the socket
	while (read_bytes < (int) length)
	{
		int bytes;
		int sel;

		if (sslWaitOnWrite)
		{
			FD_ZERO(&writeFds);
			FD_SET(writeFileDesc, &writeFds);

			// wait for the socket to be able to accept a write operation
			sel = select(writeFileDesc + 1, NULL, &writeFds, NULL, &tv);
		}
		else if (sslWaitOnRead || // OpenSSL asked us to wait
				(SSL_pending(sslM_ptr) == 0)) // there is no data in the SSL buffer
		{
			FD_ZERO(&readFds);
			FD_SET(readFileDesc, &readFds);

			// wait for something on the socket
			sel = select(readFileDesc + 1, &readFds, NULL, NULL, &tv);
		}
		else
		{
			// don't wait, there is data to be read from the SSL buffer
			sel = 1;
		}

		if (terminatingM)
		{
			return -1;
		}

		sslWaitOnRead = false;
		sslWaitOnWrite = false;

		if (sel == 1)
		{
			// data ready to be read (or possibly write - but use the same call)
			bytes = SSL_read(sslM_ptr, (char *)(buffer_ptr + read_bytes), (length - read_bytes));
			if (bytes > 0)
			{
				// read some data
				read_bytes += bytes;
				timeoutRemaining = socketTimeoutM; // reset the timeout
			}
			else if (bytes == 0)
			{
				// socket closed
				if (loggerM_ptr)
				{
					loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Secure connection closed during socket read");
				}
				return -1;
			}
			else
			{
				// operation did not complete, see what happened
				int err = SSL_get_error(sslM_ptr, bytes);
				if (err == SSL_ERROR_WANT_READ)
				{
					// need to wait for data to be available for reading, and then retry the same operation
					sslWaitOnRead = true;
					timeoutRemaining = socketTimeoutM; // reset the timeout
				}
				if (err == SSL_ERROR_WANT_WRITE)
				{
					// need to wait for the write file descriptor to be able to write and then try again
					sslWaitOnWrite = true;
					timeoutRemaining = socketTimeoutM; // reset the timeout
				}
				else
				{
					// an error occured
					if ((err == SSL_ERROR_SYSCALL) && (ERR_peek_error() == 0) && (bytes == -1))
					{
						// an error in the system call occured
						openSslError("reading from secure socket");
						if (loggerM_ptr && (loggerM_ptr->getLogMask() & LOG_ERROR))
						{
							loggerM_ptr->text(LOG_NONE, 1, "    read() error code = %d", WSAGetLastError());
						}
					}
					else
					{
						openSslError("reading from secure socket");
					}
					return -1;
				}
			}
		}
		else if (sel == 0)
		{
			// no data at the end of the timeout
			if (--timeoutRemaining > 0)
			{
				// still have time left on the timeout, go back and wait some more
			}
			else
			{
				// timeout expired
				if (loggerM_ptr)
				{
					loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Connection timed-out while waiting to receive data");
				}
				return -1;
			}
		}
		else if (sel == SOCKET_ERROR)
		{
			// socket error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Error waiting to receive data (error code %d)", WSAGetLastError());
			}
			return -1;
		}
		else
		{
			// unknown error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Unknown error while waiting to receive data (select returned %d)", sel);
			}
			return -1;
		}
	}

	return read_bytes;
}