⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sslsocket.cpp

📁 LINUX下发送邮件的库,测试很好用,有各种发送测试的例子
💻 CPP
字号:
/************************************************************************* *                                                                       * * This program is free software; you can redistribute it and/or modify  * * it under the terms of the GNU General Public License as published by  * * the Free Software Foundation; either version 2 of the License, or     * * (at your option) any later version.                                   * *                                                                       * *************************************************************************/#include "sslsocket.h"/** * Constructor. * * @param host The host this socket is connected to. */SSLSocket::SSLSocket (const string &host) : Socket (host) {	this->negotiated  = false;	this->ssl         = NULL;	this->ctx         = NULL;	this->verify      = SSL_VERIFY_PEER;	this->ca_file     = "";	this->ca_dir      = "";	SSLeay_add_ssl_algorithms ();		ERR_load_crypto_strings ();	SSL_load_error_strings ();}/** * Constructor. * * @param host The host this socket is connected to. * @param fd   The file descriptor this socket uses for IO. */SSLSocket::SSLSocket (const string &host, int fd) : Socket (host,fd) {	this->negotiated  = false;	this->ssl         = NULL;	this->ctx         = NULL;	this->verify      = SSL_VERIFY_PEER;	this->ca_file     = "";	this->ca_dir      = "";	SSLeay_add_ssl_algorithms ();		ERR_load_crypto_strings ();	SSL_load_error_strings ();}/** * Destructor. */SSLSocket::~SSLSocket () {	if (this->ssl != NULL)	{		SSL_shutdown (this->ssl);		SSL_free (this->ssl);	}	if (this->ctx != NULL)	{		SSL_CTX_free (this->ctx);	}}/** * Reads one line from the socket. * * @returns One line read from the socket. * * @throws TransferException  *             On any uncommon event that occurs while receiving *             the data. * @throws SSLException *                On any uncommon event that occurs while receiving *                data from the encrypted socket. */string SSLSocket::readSocket (){	if (this->negotiated)	{		return (ssl_readSocket ());	}	else	{		return (Socket::readSocket ());	}}/** * Writes data to the socket. * * @param data The data string that should be written to  *             the socket. * * @throws TransferException  *             On any uncommon event that occurs while sending *             the data. * @throws SSLException *                On any uncommon event that occurs while sending *                data through the encrypted socket. */void SSLSocket::writeSocket (const string &data){	if (this->negotiated)	{		ssl_writeSocket (data);	}	else	{		Socket::writeSocket (data);	}}/** * Reads one line from the socket. * * @returns One line read from the socket. * * @throws SSLException *                On any uncommon event that occurs while receiving *                data from the encrypted socket. */string SSLSocket::ssl_readSocket (){	string data;	if (this->sockfd != -1)	{		bool EOL = false;		while (!EOL)		{			char b;			int bytes = ssl_read (this->ssl, &b, 1);						if (bytes < 1)			{				throw (SSLException (ssl_error (bytes), "SSLSocket::ssl_readSocket()", 1));			}    			else if (b != '\n')			{				data += b;			}			else			{				EOL = true;			}		}	}	else	{    		throw		( 		 	SSLException			(			 	LIBSMTP_I18N_1 ("Socket is closed."),				"SSLSocket::ssl_readSocket()",				2			)		);	}	LOG_VERBOSE << this->host << ":\t" << data << endl;	return (data);}/** * Writes data to the socket. * * @param data The data string that should be written to  *             the socket. * * @throws SSLException *                On any uncommon event that occurs while sending *                data through the encrypted socket. */void SSLSocket::ssl_writeSocket (const string &data){	if (this->sockfd != -1)	{		int ret = ssl_write (this->ssl, data.c_str (), data.length ());				if (ret < 1)		{			throw			( 			 	SSLException				(				 	ssl_error (ret),					"SSLSocket::ssl_writeSocket()",					1				)			);		}	}	else	{		throw		( 		 	SSLException			(			 	LIBSMTP_I18N_1 ("Socket is closed."),				"SSLSocket::ssl_writeSocket()",				2			)		);	}	LOG_VERBOSE << localhost () << ":\t" << data;}/** * his method wraps around SSL_read and handles the  * following error conditions: SSL_ERROR_WANT_WRITE, * SSL_ERROR_WANT_READ, SSL_ERROR_WANT_CONNECT and  * SSL_ERROR_WANT_X509_LOOKUP. */int SSLSocket::ssl_read (SSL * ssl, void * buf, int num){	int bytes = SSL_read (ssl, (char*)buf, num);	while	( 		SSL_get_error (this->ssl, bytes) == SSL_ERROR_WANT_WRITE   ||		SSL_get_error (this->ssl, bytes) == SSL_ERROR_WANT_READ    ||		SSL_get_error (this->ssl, bytes) == SSL_ERROR_WANT_CONNECT ||		SSL_get_error (this->ssl, bytes) == SSL_ERROR_WANT_X509_LOOKUP 	)	{		LOG_ERROR << LIBSMTP_I18N_1		(			"SSL_read() operation did not complete. I try it again.\n"		);		bytes = SSL_read (ssl, (char*)buf, num);		usleep (100);	}	return (bytes);}/** * this method wraps around SSL_write and handles the  * following error conditions: SSL_ERROR_WANT_WRITE, * SSL_ERROR_WANT_READ, SSL_ERROR_WANT_CONNECT and  * SSL_ERROR_WANT_X509_LOOKUP. */int SSLSocket::ssl_write (SSL * ssl, const void * buf, int num){	int ret = SSL_write (ssl, (char*)buf, num);	while	( 		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_WRITE   ||		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_READ    ||		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_CONNECT ||		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_X509_LOOKUP 	)	{		LOG_ERROR << LIBSMTP_I18N_1		(			"SSL_write() operation did not complete. I try it again.\n"		);		ret = SSL_write (ssl, (char*)buf, num);		usleep (100);	}	return (ret);}/** * this method wraps around SSL_connect and handles the  * following error conditions: SSL_ERROR_WANT_WRITE, * SSL_ERROR_WANT_READ, SSL_ERROR_WANT_CONNECT and  * SSL_ERROR_WANT_X509_LOOKUP. */int SSLSocket::ssl_connect (SSL * ssl){	int ret = SSL_connect (ssl);	while	( 		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_WRITE   ||		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_READ    ||		SSL_get_error (this->ssl, ret) == SSL_ERROR_WANT_CONNECT ||		SSL_get_error ( this->ssl, ret) == SSL_ERROR_WANT_X509_LOOKUP 	)	{		LOG_ERROR << LIBSMTP_I18N_1		(			"SSL_connect() operation did not complete. I try it again.\n"		);		ret = SSL_connect (ssl);		usleep (100);	}	return (ret);}/** * Start the SSL handshake. * * @throws SSLException  *                 If the handshake fails for some reason. * @throws IOException *                 If one of ca_file or ca_dir is not accessible. */void SSLSocket::negotiate (){	if (this->sockfd != -1)	{   		this->ctx  = SSL_CTX_new (SSLv23_client_method ());		if (this->ctx == NULL) { throw (SSLException (ssl_error (), "SSLSocket::negotiate()", 1)); };		this->ssl = SSL_new (this->ctx);		if (this->ssl == NULL) { throw (SSLException (ssl_error (), "SSLSocket::negotiate()", 2)); };				int ret = 1;		if (this->ca_file.length () || this->ca_dir.length ())		{			// check accessability of this->ca_file			if (this->ca_file.length ())			{				if (access (this->ca_file.c_str (), F_OK) != 0)				{					string msg = LIBSMTP_I18N_2 ("$0 does not exist.", this->ca_file);					throw (IOException (msg, "SSLSocket::negotiate()", 7));				}				else if (access (this->ca_file.c_str (), R_OK) != 0)				{					string msg = LIBSMTP_I18N_2 ("$0 is not readable.", this->ca_file);					throw (IOException (msg, "SSLSocket::negotiate()", 8));				}			}							// check accessability of this->ca_dir			if (this->ca_dir.length ())			{				if (this->ca_dir != "" && access (this->ca_dir.c_str (), F_OK) != 0)				{					string msg = LIBSMTP_I18N_2 ("$0 does not exist.", this->ca_dir);					throw (IOException (msg, "SSLSocket::negotiate()", 9));				}				else if (this->ca_file != "" && access (this->ca_file.c_str (), R_OK) != 0)				{					string msg = LIBSMTP_I18N_2 ("$0 is not readable.", this->ca_file);					throw (IOException (msg, "SSLSocket::negotiate()", 10));				}			}							ret = SSL_CTX_load_verify_locations			( 				this->ctx, 				this->ca_file == "" ? NULL : this->ca_file.c_str (),				this->ca_dir  == "" ? NULL : this->ca_dir.c_str ()			);			if (ret != 1) { throw (SSLException (ssl_error (), "SSLSocket::negotiate()", 3)); };		}		SSL_set_verify (this->ssl, this->verify , 0);		SSL_set_fd (this->ssl, this->sockfd);				ret = ssl_connect (this->ssl);		if (ret < 1) { throw (SSLException (ssl_error (ret), "SSLSocket::negotiate()", 4)); };		if (this->verify != SSL_VERIFY_NONE)		{			if			( 			 	SSL_get_verify_result (this->ssl) != X509_V_OK ||				SSL_get_peer_certificate (this->ssl) == NULL  			)			{				throw (SSLException (ssl_error (), "SSLSocket::negotiate()", 5));			}		}	}	else	{   		throw (SSLException (LIBSMTP_I18N_1 ("Socket is closed."), "SSLSocket::negotiate()", 6));	}	dumpSSLInfo ();	this->negotiated = true;}/** * Set some SSL specific options. * * @param opts The option that should be set. */void SSLSocket::setSSLOpts (SSL_OPTS opts){	if (opts == VERIFY_NONE)	{		this->verify = SSL_VERIFY_NONE;	}	else if (opts == VERIFY_PEER)	{		this->verify = SSL_VERIFY_PEER;	}}/** * Returns the last error on the SSL error stack as a  * string.  * * @param ret The return code of the last openssl function that *            was called. * @returns The error description. */string SSLSocket::ssl_error (int ret){	string str_error = LIBSMTP_I18N_1 ("An unknown error occured.");	if (SSL_get_error (this->ssl, ret) == SSL_ERROR_SYSCALL && ERR_get_error () == 0)	{		if (ret == 0)		{			str_error = LIBSMTP_I18N_1 ("Socket was closed.");		}		else if (ret == -1)		{			str_error = strerror (errno);		}	}	else	{		char error[1024];		ERR_error_string_n (ERR_get_error (), error, 1024);		str_error = error;	}		return (str_error);}/** * Set the locations of the certificate files. * ca_file points to a file containing PEM * certs, ca_dir points to a directory containing * PEM certs. "man 3 SSL_CTX_load_verify_locations" * will give you more info on that topic. * * @param ca_file A file that contains PEM certificates. *                The file  can  contain several CA certificates  *                identified by *                 *                -----BEGIN CERTIFICATE----- *                 *                ... [CA certificate in base64 encoding] ... *                 *                -----END CERTIFICATE----- *                 *                sequences.  Before,  between, and after the  *                certificates text is allowed which *                can be used e.g. for descriptions of the  *                certificates. *                 *                Take a look in the openssl documentation to  *                get more infos on that topic. * @param ca_dir  A directory that contains PEM certificates. *                The files each contain one CA certificate.  The files  *                are looked up by the CA subject name hash value, which  *                must hence be available.  If more than one CA certificate  *                with the same name hash value exist, the extension must be  *                different (e.g. 9d66eef0.0, 9d66eef0.1 etc).  The search  *                is performed in the ordering of the extension number,  *                regardless of other properties of the certificates.   *                Use the c_rehash utility to create the necessary links.   *                 *                Take a look in the openssl documentation to  *                get more infos on that topic. */void SSLSocket::setVerifyLocations (const string &ca_file, const string &ca_dir){	this->ca_file = ca_file;	this->ca_dir  = ca_dir;}/** * Dump various X509 Infos. */void SSLSocket::dumpSSLInfo (){	char * str = NULL;	str = (char*)SSL_get_cipher (this->ssl);	if (str == NULL) { return; }	LOG_VERBOSE << LIBSMTP_I18N_2 ("SSLInfo:\tSSL connection using $0 ", str) << endl;  	X509 * server_cert = SSL_get_peer_certificate (this->ssl);	if (server_cert == NULL)	LOG_VERBOSE << LIBSMTP_I18N_1 ("SSLInfo:\tserver certificate - subject:") << endl;	LOG_VERBOSE << "SSLInfo:\t=============================" << endl;		// X509_NAME_oneline should not be used according to the manual page,	// but i dunno any other way to get the X509 infos 	str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0);	if (str == NULL) { return; }	vector<string> tokens = String::string2tokens (str, '/');	for (unsigned int idx = 0; idx < tokens.size (); idx++)	{		vector<string> value = String::string2tokens (tokens[idx], '=');		if (value.size () > 1)		{			LOG_VERBOSE << "SSLInfo:\t" << value[0] << "\t=\t" << value[1] << endl;		}	}	free (str);	LOG_VERBOSE << LIBSMTP_I18N_1 ("SSLInfo:\tServer certificate - issuer:") << endl;	LOG_VERBOSE << "SSLInfo:\t=============================" << endl;	// X509_NAME_oneline should not be used according to the manual page,	// but i dunno any other way to get the X509 infos 	str = X509_NAME_oneline (X509_get_issuer_name (server_cert), 0, 0);	if (str == NULL) { return; }	tokens = String::string2tokens (str, '/');	for (unsigned int idx = 0; idx < tokens.size (); idx++)	{		vector<string> value = String::string2tokens (tokens[idx], '=');		if (value.size () > 1)		{			LOG_VERBOSE << "SSLInfo:\t" << value[0] << "\t=\t" << value[1] << endl;		}	}	free (str);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -