diff options
| author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
|---|---|---|
| committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
| commit | aa4d426b4d3527d7e166df1a05058c9a4a0f6683 (patch) | |
| tree | 4ff17ce8b89a2321b9d0ed4bcfc37c447bcb6820 /vmime-master/src/vmime/net/tls | |
| download | smtps-and-pop3s-console-program-master.tar.gz smtps-and-pop3s-console-program-master.zip | |
Diffstat (limited to 'vmime-master/src/vmime/net/tls')
22 files changed, 3454 insertions, 0 deletions
| diff --git a/vmime-master/src/vmime/net/tls/TLSProperties.cpp b/vmime-master/src/vmime/net/tls/TLSProperties.cpp new file mode 100644 index 0000000..f7721d4 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSProperties.cpp @@ -0,0 +1,44 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/net/tls/TLSProperties.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + diff --git a/vmime-master/src/vmime/net/tls/TLSProperties.hpp b/vmime-master/src/vmime/net/tls/TLSProperties.hpp new file mode 100644 index 0000000..94341ca --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSProperties.hpp @@ -0,0 +1,105 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED +#define VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/types.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +/** Holds options for a TLS session. +  */ +class VMIME_EXPORT TLSProperties : public object { + +public: + +	TLSProperties(); +	TLSProperties(const TLSProperties&); + + +	/** Predefined generic cipher suites (work with all TLS libraries). */ +	enum GenericCipherSuite { + +		CIPHERSUITE_HIGH,           /**< High encryption cipher suites (> 128 bits). */ +		CIPHERSUITE_MEDIUM,         /**< Medium encryption cipher suites (>= 128 bits). */ +		CIPHERSUITE_LOW,            /**< Low encryption cipher suites (>= 64 bits). */ + +		CIPHERSUITE_DEFAULT         /**< Default cipher suite. */ +	}; + +	/** Sets the cipher suite preferences for a SSL/TLS session, using +	  * predefined, generic suites. This works with all underlying TLS +	  * libraries (OpenSSL and GNU TLS). +	  * +	  * @param cipherSuite predefined cipher suite +	  */ +	void setCipherSuite(const GenericCipherSuite cipherSuite); + +	/** Sets the cipher suite preferences for a SSL/TLS session, using +	  * a character string. The format and meaning of the string depend +	  * on the underlying TLS library. +	  * +	  * For GNU TLS, read this: +	  * http://gnutls.org/manual/html_node/Priority-Strings.html +	  * +	  * For OpenSSL, read this: +	  * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS +	  * +	  * @param cipherSuite cipher suite as a string +	  */ +	void setCipherSuite(const string& cipherSuite); + +	/** Returns the cipher suite preferences for a SSL/TLS session, as +	  * a character string. The format and meaning of the string depend +	  * on the underlying TLS library (see setCipherSuite() method). +	  * +	  * @return cipher suite string +	  */ +	const string getCipherSuite() const; + +private: + +	shared_ptr <object> m_data; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + +#endif // VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp new file mode 100644 index 0000000..055dfea --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp @@ -0,0 +1,77 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/net/tls/TLSSecuredConnectionInfos.hpp" +#include "vmime/net/tls/TLSSession.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +TLSSecuredConnectionInfos::TLSSecuredConnectionInfos( +	const string& host, +	const port_t port, +	const shared_ptr <TLSSession>& tlsSession, +	const shared_ptr <TLSSocket>& tlsSocket +) +	: m_host(host), +	  m_port(port), +	  m_tlsSession(tlsSession), +	  m_tlsSocket(tlsSocket) { + +} + + +const string TLSSecuredConnectionInfos::getHost() const { + +	return m_host; +} + + +port_t TLSSecuredConnectionInfos::getPort() const { + +	return m_port; +} + + +shared_ptr <const security::cert::certificateChain> TLSSecuredConnectionInfos::getPeerCertificates() const { + +	return m_tlsSocket->getPeerCertificates(); +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + diff --git a/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp new file mode 100644 index 0000000..c65e9d2 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp @@ -0,0 +1,88 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED +#define VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/net/securedConnectionInfos.hpp" + +#include "vmime/security/cert/certificateChain.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession; +class TLSSocket; + + +/** Information about a TLS-secured connection used by a service. +  */ +class VMIME_EXPORT TLSSecuredConnectionInfos : public securedConnectionInfos { + +public: + +	TLSSecuredConnectionInfos( +		const string& host, +		const port_t port, +		const shared_ptr <TLSSession>& tlsSession, +		const shared_ptr <TLSSocket>& tlsSocket +	); + +	const string getHost() const; +	port_t getPort() const; + +	/** Return the peer's certificate (chain) as sent by the peer. +	  * +	  * @return server certificate chain +	  */ +	shared_ptr <const security::cert::certificateChain> getPeerCertificates() const; + +private: + +	string m_host; +	port_t m_port; + +	shared_ptr <TLSSession> m_tlsSession; +	shared_ptr <TLSSocket> m_tlsSocket; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + +#endif // VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/tls/TLSSession.cpp b/vmime-master/src/vmime/net/tls/TLSSession.cpp new file mode 100644 index 0000000..ab8b7c3 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSSession.cpp @@ -0,0 +1,48 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/net/tls/TLSSession.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +TLSSession::TLSSession() { + +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT diff --git a/vmime-master/src/vmime/net/tls/TLSSession.hpp b/vmime-master/src/vmime/net/tls/TLSSession.hpp new file mode 100644 index 0000000..9e84fe7 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSSession.hpp @@ -0,0 +1,96 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED +#define VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/types.hpp" + +#include "vmime/net/tls/TLSSocket.hpp" +#include "vmime/net/tls/TLSProperties.hpp" + +#include "vmime/security/cert/certificateVerifier.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +/** Describe a TLS connection between a client and a server. +  */ +class VMIME_EXPORT TLSSession : public object, public enable_shared_from_this <TLSSession> { + +public: + +	/** Create and initialize a new TLS session. +	  * +	  * @param cv object responsible for verifying certificates +	  * sent by the server +	  * @param props TLS properties for this session +	  * @return a new TLS session +	  */ +	static shared_ptr <TLSSession> create( +		const shared_ptr <security::cert::certificateVerifier>& cv, +		const shared_ptr <TLSProperties>& props +	); + +	/** Create a new socket that adds a TLS security layer around +	  * an existing socket. You should create only one socket +	  * per session. +	  * +	  * @param sok socket to wrap +	  * @return TLS socket wrapper +	  */ +	virtual shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok) = 0; + +	/** Get the object responsible for verifying certificates when +	  * using secured connections (TLS/SSL). +	  */ +	virtual shared_ptr <security::cert::certificateVerifier> getCertificateVerifier() = 0; + +protected: + +	TLSSession(); + +private: + +	TLSSession(const TLSSession&); +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + +#endif // VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/tls/TLSSocket.cpp b/vmime-master/src/vmime/net/tls/TLSSocket.cpp new file mode 100644 index 0000000..fbca082 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSSocket.cpp @@ -0,0 +1,44 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/net/tls/TLSSocket.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + diff --git a/vmime-master/src/vmime/net/tls/TLSSocket.hpp b/vmime-master/src/vmime/net/tls/TLSSocket.hpp new file mode 100644 index 0000000..ca50aa8 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/TLSSocket.hpp @@ -0,0 +1,88 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED +#define VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + + +#include "vmime/exception.hpp" + +#include "vmime/net/socket.hpp" +#include "vmime/net/timeoutHandler.hpp" + +#include "vmime/security/cert/certificateChain.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession; + + +/** Add a TLS security layer to an existing socket. +  */ +class VMIME_EXPORT TLSSocket : public socket { + +public: + +	/** Create a new socket object that adds a security layer +	  * around an existing socket. +	  * +	  * @param session TLS session +	  * @param sok socket to wrap +	  */ +	static shared_ptr <TLSSocket> wrap(const shared_ptr <TLSSession>& session, const shared_ptr <socket>& sok); + +	/** Starts a TLS handshake on this connection. +	  * +	  * @throw exceptions::tls_exception if a fatal error occurs +	  * during the negociation process, exceptions::operation_timed_out +	  * if a time-out occurs +	  */ +	virtual void handshake() = 0; + +	/** Return the peer's certificate (chain) as sent by the peer. +	  * +	  * @return server certificate chain, or NULL if the handshake +	  * has not been performed yet +	  */ +	virtual shared_ptr <security::cert::certificateChain> getPeerCertificates() = 0; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT + +#endif // VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp new file mode 100644 index 0000000..b2996fb --- /dev/null +++ b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp @@ -0,0 +1,113 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + + +#include "vmime/base.hpp" +#include "vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp" + +#include <gnutls/gnutls.h> +#if GNUTLS_VERSION_NUMBER < 0x030000 +#include <gnutls/extra.h> +#endif + + +namespace vmime { +namespace net { +namespace tls { + + +TLSProperties::TLSProperties() +	: m_data(make_shared <TLSProperties_GnuTLS>()) { + +	setCipherSuite(CIPHERSUITE_DEFAULT); +} + + +TLSProperties::TLSProperties(const TLSProperties& props) +	: object(), +	  m_data(make_shared <TLSProperties_GnuTLS>()) { + +	*dynamicCast <TLSProperties_GnuTLS>(m_data) = *dynamicCast <TLSProperties_GnuTLS>(props.m_data); +} + + +void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) { + +	switch (cipherSuite) { + +		case CIPHERSUITE_HIGH: + +			setCipherSuite("SECURE256:%SSL3_RECORD_VERSION"); +			break; + +		case CIPHERSUITE_MEDIUM: + +			setCipherSuite("SECURE128:%SSL3_RECORD_VERSION"); +			break; + +		case CIPHERSUITE_LOW: + +			setCipherSuite("NORMAL:%SSL3_RECORD_VERSION"); +			break; + +		default: +		case CIPHERSUITE_DEFAULT: + +			setCipherSuite("NORMAL:%SSL3_RECORD_VERSION"); +			break; +	} +} + + +void TLSProperties::setCipherSuite(const string& cipherSuite) { + +	dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite = cipherSuite; +} + + +const string TLSProperties::getCipherSuite() const { + +	return dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite; +} + + + +TLSProperties_GnuTLS& TLSProperties_GnuTLS::operator=(const TLSProperties_GnuTLS& other) { + +	cipherSuite = other.cipherSuite; + +	return *this; +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp new file mode 100644 index 0000000..96bbaea --- /dev/null +++ b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp @@ -0,0 +1,68 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED +#define VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + + +#include "vmime/types.hpp" + +#include "vmime/net/tls/TLSProperties.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSProperties_GnuTLS : public object { + +public: + +	TLSProperties_GnuTLS& operator=(const TLSProperties_GnuTLS& other); + + +	string cipherSuite; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp new file mode 100644 index 0000000..8586537 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp @@ -0,0 +1,313 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + + +#include <gnutls/gnutls.h> +#if GNUTLS_VERSION_NUMBER < 0x030000 +#include <gnutls/extra.h> +#endif + + +// Dependency on gcrypt is not needed since GNU TLS version 2.12. +// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651 +#if GNUTLS_VERSION_NUMBER <= 0x020b00 +#	define VMIME_GNUTLS_NEEDS_GCRYPT  1 +#endif + +#if VMIME_HAVE_PTHREAD +#	include <pthread.h> +#	if VMIME_GNUTLS_NEEDS_GCRYPT +#		include <gcrypt.h> +#	endif +#	include <errno.h> +#endif // VMIME_HAVE_PTHREAD + +#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp" +#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp" +#include "vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp" + +#include "vmime/exception.hpp" + + +// Enable GnuTLS debugging by defining GNUTLS_DEBUG +//#define GNUTLS_DEBUG 1 + + +#include <sstream> +#include <iomanip> + +#if VMIME_DEBUG && GNUTLS_DEBUG +	#include <iostream> +#endif // VMIME_DEBUG && GNUTLS_DEBUG + + +#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) +extern "C" +{ +	GCRY_THREAD_OPTION_PTHREAD_IMPL; +} +#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL + + +namespace vmime { +namespace net { +namespace tls { + + +#ifndef VMIME_BUILDING_DOC + +// Initialize GNU TLS library +struct TLSGlobal { + +	TLSGlobal() { + +#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) +	#if VMIME_GNUTLS_NEEDS_GCRYPT +		gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); +	#endif // VMIME_GNUTLS_NEEDS_GCRYPT +#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL + +		gnutls_global_init(); +		//gnutls_global_init_extra(); + +#if VMIME_DEBUG && GNUTLS_DEBUG +		gnutls_global_set_log_function(TLSLogFunc); +		gnutls_global_set_log_level(10); +#endif // VMIME_DEBUG && GNUTLS_DEBUG + +		gnutls_anon_allocate_client_credentials(&anonCred); +		gnutls_certificate_allocate_credentials(&certCred); +	} + +	~TLSGlobal() { + +		gnutls_anon_free_client_credentials(anonCred); +		gnutls_certificate_free_credentials(certCred); + +		gnutls_global_deinit(); +	} + +#if VMIME_DEBUG && GNUTLS_DEBUG + +	static void TLSLogFunc(int level, const char *str) { + +		std::cerr << "GNUTLS: [" << level << "] " << str << std::endl; +	} + +#endif // VMIME_DEBUG && GNUTLS_DEBUG + + +	gnutls_anon_client_credentials_t anonCred; +	gnutls_certificate_credentials_t certCred; +}; + +static TLSGlobal g_gnutlsGlobal; + + +#endif // VMIME_BUILDING_DOC + + + +// static +shared_ptr <TLSSession> TLSSession::create( +	const shared_ptr <security::cert::certificateVerifier>& cv, +	const shared_ptr <TLSProperties>& props +) { + +	return make_shared <TLSSession_GnuTLS>(cv, props); +} + + +TLSSession_GnuTLS::TLSSession_GnuTLS( +	const shared_ptr <security::cert::certificateVerifier>& cv, +	const shared_ptr <TLSProperties>& props +) +	: m_certVerifier(cv), +	  m_props(props) { + +	int res; + +	m_gnutlsSession = new gnutls_session_t; + +	if (gnutls_init(m_gnutlsSession, GNUTLS_CLIENT) != 0) { +		throw std::bad_alloc(); +	} + +	// Sets some default priority on the ciphers, key exchange methods, +	// macs and compression methods. +#ifdef VMIME_HAVE_GNUTLS_PRIORITY_FUNCS +	gnutls_dh_set_prime_bits(*m_gnutlsSession, 128); + +	if ((res = gnutls_priority_set_direct +		(*m_gnutlsSession, m_props->getCipherSuite().c_str(), NULL)) != 0) { + +		throwTLSException("gnutls_priority_set_direct", res); +	} + +#else  // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS + +	gnutls_set_default_priority(*m_gnutlsSession); + +	// Sets the priority on the certificate types supported by gnutls. +	// Priority is higher for types specified before others. After +	// specifying the types you want, you must append a 0. +	const int certTypePriority[] = { GNUTLS_CRT_X509, 0 }; + +	res = gnutls_certificate_type_set_priority(*m_gnutlsSession, certTypePriority); + +	if (res < 0) { +		throwTLSException("gnutls_certificate_type_set_priority", res); +	} + +	// Sets the priority on the protocol types +	const int protoPriority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; + +	res = gnutls_protocol_set_priority(*m_gnutlsSession, protoPriority); + +	if (res < 0) { +		throwTLSException("gnutls_certificate_type_set_priority", res); +	} + +	// Priority on the ciphers +	const int cipherPriority[] = { +		GNUTLS_CIPHER_ARCFOUR_128, +		GNUTLS_CIPHER_3DES_CBC, +		GNUTLS_CIPHER_AES_128_CBC, +		GNUTLS_CIPHER_AES_256_CBC, +		GNUTLS_CIPHER_ARCFOUR_40, +		GNUTLS_CIPHER_RC2_40_CBC, +		GNUTLS_CIPHER_DES_CBC, +		0 +	}; + +	gnutls_cipher_set_priority(*m_gnutlsSession, cipherPriority); + +	// Priority on MACs +	const int macPriority[] = { +		GNUTLS_MAC_SHA, +		GNUTLS_MAC_MD5, +		0 +	}; + +	gnutls_mac_set_priority(*m_gnutlsSession, macPriority); + +	// Priority on key exchange methods +	const int kxPriority[] = { +		GNUTLS_KX_RSA, +		GNUTLS_KX_DHE_DSS, +		GNUTLS_KX_DHE_RSA, +		GNUTLS_KX_ANON_DH, +		GNUTLS_KX_SRP, +		GNUTLS_KX_RSA_EXPORT, +		GNUTLS_KX_SRP_RSA, +		GNUTLS_KX_SRP_DSS, +		0 +	}; + +	gnutls_kx_set_priority(*m_gnutlsSession, kxPriority); + +	// Priority on compression methods +	const int compressionPriority[] = { +		GNUTLS_COMP_ZLIB, +		//GNUTLS_COMP_LZO, +		GNUTLS_COMP_NULL, +		0 +	}; + +	gnutls_compression_set_priority(*m_gnutlsSession, compressionPriority); + +#endif // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS + +	// Initialize credentials +	gnutls_credentials_set( +		*m_gnutlsSession, GNUTLS_CRD_ANON, g_gnutlsGlobal.anonCred +	); + +	gnutls_credentials_set( +		*m_gnutlsSession, GNUTLS_CRD_CERTIFICATE, g_gnutlsGlobal.certCred +	); +} + + +TLSSession_GnuTLS::TLSSession_GnuTLS(const TLSSession_GnuTLS&) +	: TLSSession() { + +	// Not used +} + + +TLSSession_GnuTLS::~TLSSession_GnuTLS() { + +	try { + +		if (m_gnutlsSession) { + +			gnutls_deinit(*m_gnutlsSession); + +			delete m_gnutlsSession; +			m_gnutlsSession = NULL; +		} + +	} catch (...) { + +		// Don't throw in destructor +	} +} + + +shared_ptr <TLSSocket> TLSSession_GnuTLS::getSocket(const shared_ptr <socket>& sok) { + +	return TLSSocket::wrap(dynamicCast <TLSSession>(shared_from_this()), sok); +} + + +shared_ptr <security::cert::certificateVerifier> TLSSession_GnuTLS::getCertificateVerifier() { + +	return m_certVerifier; +} + + +void TLSSession_GnuTLS::throwTLSException(const string& fname, const int code) { + +	std::ostringstream msg; + +	msg << fname + "() returned code "; +	msg << std::hex << code; +	msg << ": "; +	msg << gnutls_strerror(code); + +	throw exceptions::tls_exception(msg.str()); +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp new file mode 100644 index 0000000..2a7f9d7 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp @@ -0,0 +1,95 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED +#define VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + + +#include "vmime/types.hpp" + +#include "vmime/net/tls/TLSSession.hpp" +#include "vmime/net/tls/TLSSocket.hpp" +#include "vmime/net/tls/TLSProperties.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession_GnuTLS : public TLSSession { + +	friend class TLSSocket_GnuTLS; + +public: + +	TLSSession_GnuTLS( +		const shared_ptr <security::cert::certificateVerifier>& cv, +		const shared_ptr <TLSProperties>& props +	); + +	~TLSSession_GnuTLS(); + + +	shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok); + +	shared_ptr <security::cert::certificateVerifier> getCertificateVerifier(); + +private: + +	TLSSession_GnuTLS(const TLSSession_GnuTLS&); + +	static void throwTLSException(const string& fname, const int code); + + +#ifdef LIBGNUTLS_VERSION +	gnutls_session_t* m_gnutlsSession; +#else +	void* m_gnutlsSession; +#endif // LIBGNUTLS_VERSION + +	shared_ptr <security::cert::certificateVerifier> m_certVerifier; +	shared_ptr <TLSProperties> m_props; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp new file mode 100644 index 0000000..53e4eae --- /dev/null +++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp @@ -0,0 +1,548 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include <errno.h> + +#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp" +#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp" + +#include "vmime/platform.hpp" + +#include "vmime/security/cert/X509Certificate.hpp" + +#include "vmime/utility/stringUtils.hpp" + +#include <cstring> + + +namespace vmime { +namespace net { +namespace tls { + + +// static +shared_ptr <TLSSocket> TLSSocket::wrap( +	const shared_ptr <TLSSession>& session, +	const shared_ptr <socket>& sok +) +{ +	return make_shared <TLSSocket_GnuTLS>(dynamicCast <TLSSession_GnuTLS>(session), sok); +} + + +TLSSocket_GnuTLS::TLSSocket_GnuTLS( +	const shared_ptr <TLSSession_GnuTLS>& session, +	const shared_ptr <socket>& sok +) +	: m_session(session), +	  m_wrapped(sok), +	  m_connected(false), +	  m_ex(NULL), +	  m_status(0), +	  m_errno(0) { + +	gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this); + +	gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc); +	gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc); +	gnutls_transport_set_errno_function(*m_session->m_gnutlsSession, gnutlsErrnoFunc); +} + + +TLSSocket_GnuTLS::~TLSSocket_GnuTLS() { + +	resetException(); + +	try { +		disconnect(); +	} catch (...) { +		// Don't throw exception in destructor +	} +} + + +void TLSSocket_GnuTLS::connect(const string& address, const port_t port) { + +	try { + +		m_wrapped->connect(address, port); + +		handshake(); + +	} catch (...) { + +		disconnect(); +		throw; +	} +} + + +void TLSSocket_GnuTLS::disconnect() { + +	if (m_connected) { + +		gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR); + +		m_wrapped->disconnect(); + +		m_connected = false; +	} +} + + +bool TLSSocket_GnuTLS::isConnected() const { + +	return m_wrapped->isConnected() && m_connected; +} + + +size_t TLSSocket_GnuTLS::getBlockSize() const { + +	return 16384;  // 16 KB +} + + +const string TLSSocket_GnuTLS::getPeerName() const { + +	return m_wrapped->getPeerName(); +} + + +const string TLSSocket_GnuTLS::getPeerAddress() const { + +	return m_wrapped->getPeerAddress(); +} + + +shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler() { + +	return m_wrapped->getTimeoutHandler(); +} + + +void TLSSocket_GnuTLS::setTracer(const shared_ptr <net::tracer>& tracer) { + +	m_wrapped->setTracer(tracer); +} + + +shared_ptr <net::tracer> TLSSocket_GnuTLS::getTracer() { + +	return m_wrapped->getTracer(); +} + + +bool TLSSocket_GnuTLS::waitForRead(const int msecs) { + +	return m_wrapped->waitForRead(msecs); +} + + +bool TLSSocket_GnuTLS::waitForWrite(const int msecs) { + +	return m_wrapped->waitForWrite(msecs); +} + + +void TLSSocket_GnuTLS::receive(string& buffer) { + +	const size_t size = receiveRaw(m_buffer, sizeof(m_buffer)); +	buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size); +} + + +void TLSSocket_GnuTLS::send(const string& buffer) { + +	sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length()); +} + + +void TLSSocket_GnuTLS::send(const char* str) { + +	sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str)); +} + + +size_t TLSSocket_GnuTLS::receiveRaw(byte_t* buffer, const size_t count) { + +	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ); + +	resetException(); + +	const ssize_t ret = gnutls_record_recv( +		*m_session->m_gnutlsSession, +		buffer, static_cast <size_t>(count) +	); + +	throwException(); + +	if (ret < 0) { + +		if (ret == GNUTLS_E_AGAIN) { + +			if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { +				m_status |= STATUS_WANT_READ; +			} else { +				m_status |= STATUS_WANT_WRITE; +			} + +			return 0; +		} + +		TLSSession_GnuTLS::throwTLSException("gnutls_record_recv", static_cast <int>(ret)); +	} + +	return static_cast <size_t>(ret); +} + + +void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) { + +	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ); + +	for (size_t size = count ; size > 0 ; ) { + +		resetException(); + +		ssize_t ret = gnutls_record_send( +			*m_session->m_gnutlsSession, +			buffer, static_cast <size_t>(size) +		); + +		throwException(); + +		if (ret < 0) { + +			if (ret == GNUTLS_E_AGAIN) { + +				if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { +					m_wrapped->waitForRead(); +				} else { +					m_wrapped->waitForWrite(); +				} + +				continue; +			} + +			TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret)); + +		} else { + +			buffer += ret; +			size -= ret; +		} +	} +} + + +size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t count) { + +	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ); + +	resetException(); + +	ssize_t ret = gnutls_record_send( +		*m_session->m_gnutlsSession, +		buffer, static_cast <size_t>(count) +	); + +	throwException(); + +	if (ret < 0) { + +		if (ret == GNUTLS_E_AGAIN) { + +			if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { +				m_status |= STATUS_WANT_READ; +			} else { +				m_status |= STATUS_WANT_WRITE; +			} + +			return 0; +		} + +		TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret)); +	} + +	return static_cast <size_t>(ret); +} + + +unsigned int TLSSocket_GnuTLS::getStatus() const { + +	return m_status | m_wrapped->getStatus(); +} + + +void TLSSocket_GnuTLS::handshake() { + +	shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler(); + +	if (toHandler) { +		toHandler->resetTimeOut(); +	} + +	if (getTracer()) { +		getTracer()->traceSend("Beginning SSL/TLS handshake"); +	} + +	// Start handshaking process +	try { +		string peerName = getPeerName(); +		 +		gnutls_server_name_set(*m_session->m_gnutlsSession, GNUTLS_NAME_DNS, peerName.c_str(), peerName.size()); + +		while (true) { + +			resetException(); + +			const int ret = gnutls_handshake(*m_session->m_gnutlsSession); + +			throwException(); + +			if (ret < 0) { + +				if (ret == GNUTLS_E_AGAIN) { + +					if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { +						m_wrapped->waitForRead(); +					} else { +						m_wrapped->waitForWrite(); +					} + +				} else if (ret == GNUTLS_E_INTERRUPTED) { + +					// Non-fatal error + +				} else { + +					TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret); +				} + +			} else { + +				// Successful handshake +				break; +			} +		} + +	} catch (...) { + +		throw; +	} + +	// Verify server's certificate(s) +	shared_ptr <security::cert::certificateChain> certs = getPeerCertificates(); + +	if (certs == NULL) { +		throw exceptions::tls_exception("No peer certificate."); +	} + +	m_session->getCertificateVerifier()->verify(certs, getPeerName()); + +	m_connected = true; +} + + +int TLSSocket_GnuTLS::gnutlsErrnoFunc(gnutls_transport_ptr_t trspt) { + +	TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt); +	return sok->m_errno; +} + + +ssize_t TLSSocket_GnuTLS::gnutlsPushFunc( +	gnutls_transport_ptr_t trspt, +	const void* data, +	size_t len +) { + +	TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt); + +	try { + +		const ssize_t ret = static_cast <ssize_t>( +			sok->m_wrapped->sendRawNonBlocking(reinterpret_cast <const byte_t*>(data), len) +		); + +		if (ret == 0) { + +			gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN); +			sok->m_errno = EAGAIN; +			return -1; +		} + +		return ret; + +	} catch (exception& e) { + +		// Workaround for non-portable behaviour when throwing C++ exceptions +		// from C functions (GNU TLS) +		sok->m_ex = e.clone(); +		return -1; +	} +} + + +ssize_t TLSSocket_GnuTLS::gnutlsPullFunc( +	gnutls_transport_ptr_t trspt, +	void* data, +	size_t len +) { + +	TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt); + +	try { + +		const ssize_t n = static_cast <ssize_t>( +			sok->m_wrapped->receiveRaw(reinterpret_cast <byte_t*>(data), len) +		); + +		if (n == 0) { + +			gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN); +			sok->m_errno = EAGAIN; +			return -1; +		} + +		return n; + +	} catch (exception& e) { + +		// Workaround for non-portable behaviour when throwing C++ exceptions +		// from C functions (GNU TLS) +		sok->m_ex = e.clone(); +		return -1; +	} +} + + +shared_ptr <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertificates() { + +	if (getTracer()) { +		getTracer()->traceSend("Getting peer certificates"); +	} + +	unsigned int certCount = 0; +	const gnutls_datum_t* rawData = gnutls_certificate_get_peers( +		*m_session->m_gnutlsSession, &certCount +	); + +	if (rawData == NULL) { +		return null; +	} + +	// Try X.509 +	gnutls_x509_crt_t* x509Certs = new gnutls_x509_crt_t[certCount]; + +	for (unsigned int i = 0; i < certCount; ++i) { + +		gnutls_x509_crt_init(x509Certs + i); + +		int res = gnutls_x509_crt_import(x509Certs[i], rawData + i, GNUTLS_X509_FMT_DER); + +		if (res < 0) { + +			for (unsigned int j = 0 ; j <= i ; ++j) { +				gnutls_x509_crt_deinit(x509Certs[j]); +			} + +			// XXX more fine-grained error reporting? +			delete [] x509Certs; +			return null; +		} +	} + +	std::vector <shared_ptr <security::cert::certificate> > certs; +	bool error = false; + +	for (unsigned int i = 0 ; i < certCount ; ++i) { + +		size_t dataSize = 0; + +		gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, NULL, &dataSize); + +		std::vector <byte_t> data(dataSize); + +		gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, &data[0], &dataSize); + +		shared_ptr <security::cert::X509Certificate> cert = +			security::cert::X509Certificate::import(&data[0], dataSize); + +		if (cert != NULL) { +			certs.push_back(cert); +		} else { +			error = true; +		} + +		gnutls_x509_crt_deinit(x509Certs[i]); +	} + +	delete [] x509Certs; + +	if (error) { +		return null; +	} + +	return make_shared <security::cert::certificateChain>(certs); +} + + +// Following is a workaround for C++ exceptions to pass correctly between +// C and C++ calls. +// +// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions +// thrown by the socket can not be caught. + +void TLSSocket_GnuTLS::throwException() { + +	if (m_ex) { +		throw *m_ex; +	} +} + + +void TLSSocket_GnuTLS::resetException() { + +	if (m_ex) { +		delete m_ex; +		m_ex = NULL; +	} +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp new file mode 100644 index 0000000..0ac3e70 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp @@ -0,0 +1,129 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED +#define VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + + +#include "vmime/net/tls/TLSSocket.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession; +class TLSSession_GnuTLS; + + +class TLSSocket_GnuTLS : public TLSSocket { + +public: + +	TLSSocket_GnuTLS(const shared_ptr <TLSSession_GnuTLS>& session, const shared_ptr <socket>& sok); +	~TLSSocket_GnuTLS(); + + +	void handshake(); + +	shared_ptr <security::cert::certificateChain> getPeerCertificates(); + +	// Implementation of 'socket' +	void connect(const string& address, const port_t port); +	void disconnect(); +	bool isConnected() const; + +	bool waitForRead(const int msecs = 30000); +	bool waitForWrite(const int msecs = 30000); + +	void receive(string& buffer); +	size_t receiveRaw(byte_t* buffer, const size_t count); + +	void send(const string& buffer); +	void send(const char* str); +	void sendRaw(const byte_t* buffer, const size_t count); +	size_t sendRawNonBlocking(const byte_t* buffer, const size_t count); + +	size_t getBlockSize() const; + +	unsigned int getStatus() const; + +	const string getPeerName() const; +	const string getPeerAddress() const; + +	shared_ptr <timeoutHandler> getTimeoutHandler(); + +	void setTracer(const shared_ptr <net::tracer>& tracer); +	shared_ptr <net::tracer> getTracer(); + +private: + +	void resetException(); +	void throwException(); + +#ifdef LIBGNUTLS_VERSION +	static ssize_t gnutlsPushFunc(gnutls_transport_ptr_t trspt, const void* data, size_t len); +	static ssize_t gnutlsPullFunc(gnutls_transport_ptr_t trspt, void* data, size_t len); +	static int gnutlsErrnoFunc(gnutls_transport_ptr_t trspt); +#else +	static int gnutlsPushFunc(void* trspt, const void* data, size_t len); +	static int gnutlsPullFunc(void* trspt, void* data, size_t len); +	static int gnutlsErrnoFunc(void* trspt); +#endif // LIBGNUTLS_VERSION + + +	shared_ptr <TLSSession_GnuTLS> m_session; +	shared_ptr <socket> m_wrapped; + +	bool m_connected; + +	byte_t m_buffer[65536]; + +	exception* m_ex; + +	unsigned int m_status; +	int m_errno; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp new file mode 100644 index 0000000..c7b1013 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp @@ -0,0 +1,169 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp" + +#include "vmime/platform.hpp" + +#include <openssl/opensslv.h> + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#	define OPENSSL_API_COMPAT 0x10100000L +#endif + +#include <openssl/ssl.h> +#include <openssl/rand.h> +#include <openssl/crypto.h> +#include <openssl/err.h> + +#if OPENSSL_VERSION_NUMBER >= 0x0907000L +#	include <openssl/conf.h> +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#	include "vmime/utility/sync/autoLock.hpp" +#	include "vmime/utility/sync/criticalSection.hpp" +#endif + + +// OpenSSL locking callbacks for multithreading support (< v1.1 only) +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +namespace { + +vmime::shared_ptr <vmime::utility::sync::criticalSection >* g_openSSLMutexes = NULL; + +extern "C" void VMime_OpenSSLCallback_lock(int mode, int n, const char* /* file */, int /* line */) { + +	if (mode & CRYPTO_LOCK) { +		g_openSSLMutexes[n]->lock(); +	} else { +		g_openSSLMutexes[n]->unlock(); +	} +} + +extern "C" unsigned long VMime_OpenSSLCallback_id() { + +	return vmime::platform::getHandler()->getThreadId(); +} + +} + +#endif + + +namespace vmime { +namespace net { +namespace tls { + + +OpenSSLInitializer::autoInitializer::autoInitializer() { + +	// The construction of this unique 'oneTimeInitializer' object will be triggered +	// by the 'autoInitializer' objects from the other translation units +	static OpenSSLInitializer::oneTimeInitializer oneTimeInitializer; +} + + +OpenSSLInitializer::autoInitializer::~autoInitializer() { + +} + + +OpenSSLInitializer::oneTimeInitializer::oneTimeInitializer() { + +	initialize(); +} + + +OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer() { + +	uninitialize(); +} + + +// static +void OpenSSLInitializer::initialize() { + +#if OPENSSL_VERSION_NUMBER >= 0x0907000L && OPENSSL_VERSION_NUMBER < 0x10100000L +	OPENSSL_config(NULL); +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +	SSL_load_error_strings(); +	SSL_library_init(); +	OpenSSL_add_all_algorithms(); + +	int numMutexes = CRYPTO_num_locks(); +	g_openSSLMutexes = new shared_ptr <vmime::utility::sync::criticalSection>[numMutexes]; + +	for (int i = 0 ; i < numMutexes ; ++i) { +		g_openSSLMutexes[i] = vmime::platform::getHandler()->createCriticalSection(); +	} + +	CRYPTO_set_locking_callback(VMime_OpenSSLCallback_lock); +	CRYPTO_set_id_callback(VMime_OpenSSLCallback_id); +#endif + +	// Seed the RNG, in case /dev/urandom is not available. Explicitely calling +	// RAND_seed() even though /dev/urandom is available is harmless. +	enum { +		SEEDSIZE = 256 +	}; + +	unsigned char seed[SEEDSIZE]; +	vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE); +	RAND_seed(seed, SEEDSIZE); +} + + +// static +void OpenSSLInitializer::uninitialize() { + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +	EVP_cleanup(); +	ERR_free_strings(); + +	CRYPTO_set_locking_callback(NULL); +	CRYPTO_set_id_callback(NULL); + +	delete [] g_openSSLMutexes; +	g_openSSLMutexes = NULL; +#endif + +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + diff --git a/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp new file mode 100644 index 0000000..3b8496d --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp @@ -0,0 +1,90 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED +#define VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + +#include <vector> + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/utility/sync/criticalSection.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +/** Class responsible for setting up OpenSSL +  */ +class OpenSSLInitializer { + +public: + +	/** Automatically initialize OpenSSL +	  */ +	struct autoInitializer { + +		autoInitializer(); +		~autoInitializer(); +	}; + +protected: + +	struct oneTimeInitializer { + +		oneTimeInitializer(); +		~oneTimeInitializer(); +	}; + + +	/** Initializes the OpenSSL lib +	  */ +	static void initialize(); + +	/** Shutdown the OpenSSL lib +	  */ +	static void uninitialize(); +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp new file mode 100644 index 0000000..ea22f1c --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp @@ -0,0 +1,112 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/base.hpp" +#include "vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp" + +#include <openssl/ssl.h> +#include <openssl/err.h> + + +namespace vmime { +namespace net { +namespace tls { + + +TLSProperties::TLSProperties() +	: m_data(make_shared <TLSProperties_OpenSSL>()) { + +	setCipherSuite(CIPHERSUITE_DEFAULT); +} + + +TLSProperties::TLSProperties(const TLSProperties& props) +	: object(), +	  m_data(make_shared <TLSProperties_OpenSSL>()) { + +	*dynamicCast <TLSProperties_OpenSSL>(m_data) = *dynamicCast <TLSProperties_OpenSSL>(props.m_data); +} + + +void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) { + +	switch (cipherSuite) { + +		case CIPHERSUITE_HIGH: + +			setCipherSuite("HIGH:!ADH:@STRENGTH"); +			break; + +		case CIPHERSUITE_MEDIUM: + +			setCipherSuite("MEDIUM:!ADH:@STRENGTH"); +			break; + +		case CIPHERSUITE_LOW: + +			setCipherSuite("LOW:!ADH:@STRENGTH"); +			break; + +		default: +		case CIPHERSUITE_DEFAULT: + +			setCipherSuite("DEFAULT:!ADH:@STRENGTH"); +			break; +	} +} + + +void TLSProperties::setCipherSuite(const string& cipherSuite) { + +	dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite = cipherSuite; +} + + +const string TLSProperties::getCipherSuite() const { + +	return dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite; +} + + + +TLSProperties_OpenSSL& TLSProperties_OpenSSL::operator=(const TLSProperties_OpenSSL& other) { + +	cipherSuite = other.cipherSuite; + +	return *this; +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp new file mode 100644 index 0000000..8304df2 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp @@ -0,0 +1,68 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED +#define VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/types.hpp" + +#include "vmime/net/tls/TLSProperties.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSProperties_OpenSSL : public object { + +public: + +	TLSProperties_OpenSSL& operator=(const TLSProperties_OpenSSL& other); + + +	string cipherSuite; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp new file mode 100644 index 0000000..019341c --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp @@ -0,0 +1,147 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp" +#include "vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp" +#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp" + +#include "vmime/security/cert/certificateException.hpp" + +#include <openssl/ssl.h> +#include <openssl/err.h> + + +namespace vmime { +namespace net { +namespace tls { + + +static OpenSSLInitializer::autoInitializer openSSLInitializer; + + +// static +shared_ptr <TLSSession> TLSSession::create( +	const shared_ptr <security::cert::certificateVerifier>& cv, +	const shared_ptr <TLSProperties>& props +) { + +	return make_shared <TLSSession_OpenSSL>(cv, props); +} + + +TLSSession_OpenSSL::TLSSession_OpenSSL( +	const shared_ptr <vmime::security::cert::certificateVerifier>& cv, +	const shared_ptr <TLSProperties>& props +) +	: m_sslctx(0), +	  m_certVerifier(cv), +	  m_props(props) { + +	m_sslctx = SSL_CTX_new(SSLv23_client_method()); +	SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2); +	SSL_CTX_set_mode(m_sslctx, SSL_MODE_AUTO_RETRY); +	SSL_CTX_set_cipher_list(m_sslctx, m_props->getCipherSuite().c_str()); +	SSL_CTX_set_session_cache_mode(m_sslctx, SSL_SESS_CACHE_OFF); +} + + +TLSSession_OpenSSL::TLSSession_OpenSSL(const TLSSession_OpenSSL&) +	: TLSSession() { + +	// Not used +} + + +TLSSession_OpenSSL::~TLSSession_OpenSSL() { + +	SSL_CTX_free(m_sslctx); +} + + +shared_ptr <TLSSocket> TLSSession_OpenSSL::getSocket(const shared_ptr <socket>& sok) { + +	return TLSSocket::wrap(dynamicCast <TLSSession>(shared_from_this()), sok); +} + + +shared_ptr <security::cert::certificateVerifier> TLSSession_OpenSSL::getCertificateVerifier() { + +	return m_certVerifier; +} + + +void TLSSession_OpenSSL::usePrivateKeyFile(const vmime::string& keyfile) { + +	ERR_clear_error(); + +	if (SSL_CTX_use_PrivateKey_file(m_sslctx, keyfile.c_str(), SSL_FILETYPE_PEM) != 1) { + +		unsigned long errCode = ERR_get_error(); +		char buffer[256]; +		ERR_error_string_n(errCode, buffer, sizeof(buffer)); +		vmime::string sslErr(buffer); +		std::ostringstream oss; +		oss << "Error loading private key from file " << keyfile; +		oss << " - msg: " << sslErr; +		throw security::cert::certificateException(oss.str()); +	} +} + + +void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) { + +	ERR_clear_error(); + +	if (SSL_CTX_use_certificate_chain_file(m_sslctx, chainFile.c_str()) != 1) { + +		unsigned long errCode = ERR_get_error(); +		char buffer[256]; +		ERR_error_string_n(errCode, buffer, sizeof(buffer)); +		vmime::string sslErr(buffer); +		std::ostringstream oss; +		oss << "Error loading certificate from file " << chainFile; +		oss << " - msg: " << sslErr; +		throw security::cert::certificateException(oss.str()); +	} +} + + +SSL_CTX* TLSSession_OpenSSL::getContext() const { + +	return m_sslctx; +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp new file mode 100644 index 0000000..518216b --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp @@ -0,0 +1,109 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED +#define VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/types.hpp" + +#include "vmime/net/tls/TLSSession.hpp" +#include "vmime/net/tls/TLSSocket.hpp" +#include "vmime/net/tls/TLSProperties.hpp" + + +#include <openssl/ssl.h> + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession_OpenSSL : public TLSSession { + +	friend class TLSSocket_OpenSSL; + +public: + +	TLSSession_OpenSSL( +		const shared_ptr <security::cert::certificateVerifier>& cv, +		const shared_ptr <TLSProperties>& props +	); + +	~TLSSession_OpenSSL(); + + +	shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok); + +	shared_ptr <security::cert::certificateVerifier> getCertificateVerifier(); + + +	/** Set the private key to use if server requires a client certificate. +	 * +	 * @param keyfile path to the private key in PEM format +	*/ +	void usePrivateKeyFile(const vmime::string& keyfile); + +	/** Supply the certificate chain to present if requested by server. +	 * +	 * @param chainFile	File in PEM format holding certificate chain +	 */ +	void useCertificateChainFile(const vmime::string& chainFile); + +	/** Get a pointer to the SSL_CTX used for this session. +	 * +	 * @return the SSL_CTX used for all connections created with this session +	 */ +	SSL_CTX* getContext() const; + +private: + +	TLSSession_OpenSSL(const TLSSession_OpenSSL&); + +	SSL_CTX* m_sslctx; + +	shared_ptr <security::cert::certificateVerifier> m_certVerifier; +	shared_ptr <TLSProperties> m_props; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp new file mode 100644 index 0000000..978f0ca --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp @@ -0,0 +1,761 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include <openssl/ssl.h> +#include <openssl/err.h> + +#include "vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp" +#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp" +#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp" + +#include "vmime/platform.hpp" + +#include "vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp" + +#include "vmime/utility/stringUtils.hpp" + +#include <vector> +#include <cstring> + + +namespace vmime { +namespace net { +namespace tls { + + +static OpenSSLInitializer::autoInitializer openSSLInitializer; + + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +// static +BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = { +	100 | BIO_TYPE_SOURCE_SINK, +	"vmime::socket glue", +	TLSSocket_OpenSSL::bio_write, +	TLSSocket_OpenSSL::bio_read, +	TLSSocket_OpenSSL::bio_puts, +	NULL,  // gets +	TLSSocket_OpenSSL::bio_ctrl, +	TLSSocket_OpenSSL::bio_create, +	TLSSocket_OpenSSL::bio_destroy, +	0 +}; + +#define BIO_set_init(b, val) b->init = val +#define BIO_set_data(b, val) b->ptr = val +#define BIO_set_num(b, val) b->num = val +#define BIO_set_flags(b, val) b->flags = val +#define BIO_set_shutdown(b, val) b->shutdown = val +#define BIO_get_init(b) b->init +#define BIO_get_data(b) b->ptr +#define BIO_get_shutdown(b) b->shutdown + +#else + +#define BIO_set_num(b, val) + +#endif + + + +// static +shared_ptr <TLSSocket> TLSSocket::wrap( +	const shared_ptr <TLSSession>& session, +	const shared_ptr <socket>& sok +) { + +	return make_shared <TLSSocket_OpenSSL>(dynamicCast <TLSSession_OpenSSL>(session), sok); +} + + +TLSSocket_OpenSSL::TLSSocket_OpenSSL( +	const shared_ptr <TLSSession_OpenSSL>& session, +	const shared_ptr <socket>& sok +) +	: m_session(session), +	  m_wrapped(sok), +	  m_connected(false), +	  m_ssl(0), +	  m_status(0), +	  m_ex() { + +} + + +TLSSocket_OpenSSL::~TLSSocket_OpenSSL() { + +	try { +		disconnect(); +	} catch (...) { +		// Don't throw in destructor +	} +} + + +void TLSSocket_OpenSSL::createSSLHandle() { + +	if (m_wrapped->isConnected()) { +		string peerName = getPeerName(); +		 +		if (peerName.empty()) { +			throw exceptions::tls_exception("Unknown host name, will not be able to set SNI"); +		} + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +		BIO* sockBio = BIO_new(&sm_customBIOMethod); +		sockBio->ptr = this; +		sockBio->init = 1; + +#else + +		BIO_METHOD* bioMeth = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "vmime::socket glue"); + +		if (!bioMeth) { +			BIO_meth_free(bioMeth); +			throw exceptions::tls_exception("BIO_meth_new() failed"); +		} + +		BIO_meth_set_write(bioMeth, TLSSocket_OpenSSL::bio_write); +		BIO_meth_set_read(bioMeth, TLSSocket_OpenSSL::bio_read); +		BIO_meth_set_puts(bioMeth, TLSSocket_OpenSSL::bio_puts); +		BIO_meth_set_ctrl(bioMeth, TLSSocket_OpenSSL::bio_ctrl); +		BIO_meth_set_create(bioMeth, TLSSocket_OpenSSL::bio_create); +		BIO_meth_set_destroy(bioMeth, TLSSocket_OpenSSL::bio_destroy); + +		BIO* sockBio = BIO_new(bioMeth); +		BIO_set_data(sockBio, this); +		BIO_set_init(sockBio, 1); + +#endif + +		if (!sockBio) { +			throw exceptions::tls_exception("BIO_new() failed"); +		} + +		m_ssl = SSL_new(m_session->getContext()); + +		if (!m_ssl) { +			BIO_free(sockBio); +			throw exceptions::tls_exception("Cannot create SSL object"); +		} + +		SSL_set_bio(m_ssl, sockBio, sockBio); +		SSL_set_tlsext_host_name(m_ssl, peerName.c_str()); +		SSL_set_connect_state(m_ssl); +		SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + +	} else { + +		throw exceptions::tls_exception("Unconnected socket error"); +	} +} + + +void TLSSocket_OpenSSL::connect(const string& address, const port_t port) { + +	try { + +		m_wrapped->connect(address, port); +		 +		createSSLHandle(); + +		handshake(); + +	} catch (...) { + +		disconnect(); +		throw; +	} +} + + +void TLSSocket_OpenSSL::disconnect() { + +	if (m_ssl) { + +		// Don't shut down the socket more than once. +		int shutdownState = SSL_get_shutdown(m_ssl); +		bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN; + +		if (!shutdownSent) { +			SSL_shutdown(m_ssl); +		} + +		SSL_free(m_ssl); +		m_ssl = 0; +	} + +	if (m_connected) { +		m_connected = false; +		m_wrapped->disconnect(); +	} +} + + +bool TLSSocket_OpenSSL::isConnected() const { + +	return m_wrapped->isConnected() && m_connected; +} + + +size_t TLSSocket_OpenSSL::getBlockSize() const { + +	return 16384;  // 16 KB +} + + +const string TLSSocket_OpenSSL::getPeerName() const { + +	return m_wrapped->getPeerName(); +} + + +const string TLSSocket_OpenSSL::getPeerAddress() const { + +	return m_wrapped->getPeerAddress(); +} + + +shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler() { + +	return m_wrapped->getTimeoutHandler(); +} + + +void TLSSocket_OpenSSL::setTracer(const shared_ptr <net::tracer>& tracer) { + +	m_wrapped->setTracer(tracer); +} + + +shared_ptr <net::tracer> TLSSocket_OpenSSL::getTracer() { + +	return m_wrapped->getTracer(); +} + + +bool TLSSocket_OpenSSL::waitForRead(const int msecs) { + +	return m_wrapped->waitForRead(msecs); +} + + +bool TLSSocket_OpenSSL::waitForWrite(const int msecs) { + +	return m_wrapped->waitForWrite(msecs); +} + + +void TLSSocket_OpenSSL::receive(string& buffer) { + +	const size_t size = receiveRaw(m_buffer, sizeof(m_buffer)); + +	if (size != 0) { +		buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size); +	} else { +		buffer.clear(); +	} +} + + +void TLSSocket_OpenSSL::send(const string& buffer) { + +	sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length()); +} + + +void TLSSocket_OpenSSL::send(const char* str) { + +	sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str)); +} + + +size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count) { + +	if (!m_ssl) { +		throw exceptions::socket_not_connected_exception(); +	} + +	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ); + +	ERR_clear_error(); +	int rc = SSL_read(m_ssl, buffer, static_cast <int>(count)); + +	if (m_ex.get()) { +		internalThrow(); +	} + +	if (rc <= 0) { + +		int error = SSL_get_error(m_ssl, rc); + +		if (error == SSL_ERROR_WANT_WRITE) { +			m_status |= STATUS_WANT_WRITE; +			return 0; +		} else if (error == SSL_ERROR_WANT_READ) { +			m_status |= STATUS_WANT_READ; +			return 0; +		} + +		handleError(rc); +	} + +	return rc; +} + + +void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) { + +	if (!m_ssl) { +		throw exceptions::socket_not_connected_exception(); +	} + +	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ); + +	for (size_t size = count ; size > 0 ; ) { + +		ERR_clear_error(); +		int rc = SSL_write(m_ssl, buffer, static_cast <int>(size)); + +		if (rc <= 0) { + +			int error = SSL_get_error(m_ssl, rc); + +			if (error == SSL_ERROR_WANT_READ) { +				m_wrapped->waitForRead(); +				continue; +			} else if (error == SSL_ERROR_WANT_WRITE) { +				m_wrapped->waitForWrite(); +				continue; +			} + +			handleError(rc); + +		} else { + +			buffer += rc; +			size -= rc; +		} +	} +} + + +size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count) { + +	if (!m_ssl) { +		throw exceptions::socket_not_connected_exception(); +	} + +	m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ); + +	ERR_clear_error(); +	int rc = SSL_write(m_ssl, buffer, static_cast <int>(count)); + +	if (m_ex.get()) { +		internalThrow(); +	} + +	if (rc <= 0) { + +		int error = SSL_get_error(m_ssl, rc); + +		if (error == SSL_ERROR_WANT_WRITE) { +			m_status |= STATUS_WANT_WRITE; +			return 0; +		} else if (error == SSL_ERROR_WANT_READ) { +			m_status |= STATUS_WANT_READ; +			return 0; +		} + +		handleError(rc); +	} + +	return rc; +} + + +void TLSSocket_OpenSSL::handshake() { + +	shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler(); + +	if (toHandler) { +		toHandler->resetTimeOut(); +	} + +	if (getTracer()) { +		getTracer()->traceSend("Beginning SSL/TLS handshake"); +	} + +	// Start handshaking process +	if (!m_ssl) { +		createSSLHandle(); +	} + +	try { + +		int rc; + +		ERR_clear_error(); + +		while ((rc = SSL_do_handshake(m_ssl)) <= 0) { + +			const int err = SSL_get_error(m_ssl, rc); + +			if (err == SSL_ERROR_WANT_READ) { +				m_wrapped->waitForRead(); +			} else if (err == SSL_ERROR_WANT_WRITE) { +				m_wrapped->waitForWrite(); +			} else { +				handleError(rc); +			} + +			// Check whether the time-out delay is elapsed +			if (toHandler && toHandler->isTimeOut()) { + +				if (!toHandler->handleTimeOut()) { +					throw exceptions::operation_timed_out(); +				} + +				toHandler->resetTimeOut(); +			} + +			ERR_clear_error(); +		} + +	} catch (...) { + +		throw; +	} + +	// Verify server's certificate(s) +	shared_ptr <security::cert::certificateChain> certs = getPeerCertificates(); + +	if (!certs) { +		throw exceptions::tls_exception("No peer certificate."); +	} + +	m_session->getCertificateVerifier()->verify(certs, getPeerName()); + +	m_connected = true; +} + + +shared_ptr <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates() { + +	if (getTracer()) { +		getTracer()->traceSend("Getting peer certificates"); +	} + +	STACK_OF(X509)* chain = SSL_get_peer_cert_chain(m_ssl); + +	if (chain == NULL) { +		return null; +	} + +	int certCount = sk_X509_num(chain); + +	if (certCount == 0) { +		return null; +	} + +	bool error = false; +	std::vector <shared_ptr <security::cert::certificate> > certs; + +	for (int i = 0; i < certCount && !error; i++) { + +		shared_ptr <vmime::security::cert::X509Certificate> cert = +			vmime::security::cert::X509Certificate_OpenSSL::importInternal(sk_X509_value(chain, i)); + +		if (cert) { +			certs.push_back(cert); +		} else { +			error = true; +		} +	} + +	if (error) { +		return null; +	} + +	return make_shared <security::cert::certificateChain>(certs); +} + + +void TLSSocket_OpenSSL::internalThrow() { + +	if (m_ex.get()) { +		throw *m_ex; +	} +} + + +void TLSSocket_OpenSSL::handleError(int rc) { + +	if (rc > 0) { +		return; +	} + +	internalThrow(); + +	int  sslError   = SSL_get_error(m_ssl, rc); +	long lastError  = ERR_get_error(); + +	switch (sslError) { + +		case SSL_ERROR_ZERO_RETURN: + +			disconnect(); +			return; + +		case SSL_ERROR_SYSCALL: { + +			if (lastError == 0) { + +				if (rc == 0) { + +					throw exceptions::tls_exception("SSL connection unexpectedly closed"); + +				} else { + +					std::ostringstream oss; +					oss << "The BIO reported an error: " << rc; +					oss.flush(); +					throw exceptions::tls_exception(oss.str()); +				} +			} + +			break; +		} + +		case SSL_ERROR_WANT_READ: + +			BIO_set_retry_read(SSL_get_rbio(m_ssl)); +			break; + +		case SSL_ERROR_WANT_WRITE: + +			BIO_set_retry_write(SSL_get_wbio(m_ssl)); +			break; + +		// This happens only for BIOs of type BIO_s_connect() or BIO_s_accept() +		case SSL_ERROR_WANT_CONNECT: +		case SSL_ERROR_WANT_ACCEPT: +		// SSL_CTX_set_client_cert_cb related, not used +		case SSL_ERROR_WANT_X509_LOOKUP: +		case SSL_ERROR_SSL: +		default: + +			if (lastError == 0) { + +				throw exceptions::tls_exception("Unexpected SSL IO error"); + +			} else { + +				char buffer[256]; +				ERR_error_string_n(lastError, buffer, sizeof(buffer)); +				vmime::string msg(buffer); +				throw exceptions::tls_exception(msg); +			} + +			break; +	} +} + + +unsigned int TLSSocket_OpenSSL::getStatus() const { + +	return m_status; +} + + +// Implementation of custom BIO methods + + +// static +int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len) { + +	BIO_clear_retry_flags(bio); + +	if (buf == NULL || len <= 0) { +		return -1; +	} + +	TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio)); + +	if (!BIO_get_init(bio) || !sok) { +		return -1; +	} + +	try { + +		const size_t n = sok->m_wrapped->sendRawNonBlocking( +			reinterpret_cast <const byte_t*>(buf), len +		); + +		if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) { +			BIO_set_retry_write(bio); +			return -1; +		} + +		return static_cast <int>(n); + +	} catch (exception& e) { + +		// Workaround for passing C++ exceptions from C BIO functions +		sok->m_ex.reset(e.clone()); +		return -1; +	} +} + + +// static +int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len) { + +	BIO_clear_retry_flags(bio); + +	if (buf == NULL || len <= 0) { +		return -1; +	} + +	TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio)); + +	if (!BIO_get_init(bio) || !sok) { +		return -1; +	} + +	try { + +		const size_t n = sok->m_wrapped->receiveRaw( +			reinterpret_cast <byte_t*>(buf), len +		); + +		if (n == 0 || sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) { +			BIO_set_retry_read(bio); +			return -1; +		} + +		return static_cast <int>(n); + +	} catch (exception& e) { + +		// Workaround for passing C++ exceptions from C BIO functions +		sok->m_ex.reset(e.clone()); +		return -1; +	} +} + + +// static +int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str) { + +	return bio_write(bio, str, static_cast <int>(strlen(str))); +} + + +// static +long TLSSocket_OpenSSL::bio_ctrl(BIO* bio, int cmd, long num, void* /* ptr */) { + +	long ret = 1; + +	switch (cmd) { + +		case BIO_CTRL_INFO: + +			ret = 0; +			break; + +		case BIO_CTRL_GET_CLOSE: + +			ret = BIO_get_shutdown(bio); +			break; + +		case BIO_CTRL_SET_CLOSE: + +			BIO_set_shutdown(bio, static_cast <int>(num)); +			break; + +		case BIO_CTRL_PENDING: +		case BIO_CTRL_WPENDING: + +			ret = 0; +			break; + +		case BIO_CTRL_DUP: +		case BIO_CTRL_FLUSH: + +			ret = 1; +			break; + +		default: + +			ret = 0; +			break; +	} + +	return ret; +} + + +// static +int TLSSocket_OpenSSL::bio_create(BIO* bio) { + +	BIO_set_init(bio, 0); +	BIO_set_num(bio, 0); +	BIO_set_data(bio, NULL); +	BIO_set_flags(bio, 0); + +	return 1; +} + + +// static +int TLSSocket_OpenSSL::bio_destroy(BIO* bio) { + +	if (!bio) { +		return 0; +	} + +	if (BIO_get_shutdown(bio)) { +		BIO_set_data(bio, NULL); +		BIO_set_init(bio, 0); +		BIO_set_flags(bio, 0); +	} + +	return 1; +} + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp new file mode 100644 index 0000000..e30df68 --- /dev/null +++ b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp @@ -0,0 +1,142 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED +#define VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED + + +#ifndef VMIME_BUILDING_DOC + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + + +#include "vmime/net/tls/TLSSocket.hpp" + +#include <memory> + +#include <openssl/ssl.h> + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession; +class TLSSession_OpenSSL; + + +class TLSSocket_OpenSSL : public TLSSocket { + +public: + +	TLSSocket_OpenSSL( +		const shared_ptr <TLSSession_OpenSSL>& session, +		const shared_ptr <socket>& sok +	); + +	~TLSSocket_OpenSSL(); + + +	void handshake(); + +	shared_ptr <security::cert::certificateChain> getPeerCertificates(); + +	// Implementation of 'socket' +	void connect(const string& address, const port_t port); +	void disconnect(); +	bool isConnected() const; + +	bool waitForRead(const int msecs = 30000); +	bool waitForWrite(const int msecs = 30000); + +	void receive(string& buffer); +	size_t receiveRaw(byte_t* buffer, const size_t count); + +	void send(const string& buffer); +	void send(const char* str); +	void sendRaw(const byte_t* buffer, const size_t count); +	size_t sendRawNonBlocking(const byte_t* buffer, const size_t count); + +	size_t getBlockSize() const; + +	unsigned int getStatus() const; + +	const string getPeerName() const; +	const string getPeerAddress() const; + +	shared_ptr <timeoutHandler> getTimeoutHandler(); + +	void setTracer(const shared_ptr <net::tracer>& tracer); +	shared_ptr <net::tracer> getTracer(); + +private: + +	static BIO_METHOD sm_customBIOMethod; + +	static int bio_write(BIO* bio, const char* buf, int len); +	static int bio_read(BIO* bio, char* buf, int len); +	static int bio_puts(BIO* bio, const char* str); +	static int bio_gets(BIO* bio, char* buf, int len); +	static long bio_ctrl(BIO* bio, int cmd, long num, void* ptr); +	static int bio_create(BIO* bio); +	static int bio_destroy(BIO* bio); + +	void createSSLHandle(); + +	void internalThrow(); +	void handleError(int rc); + + +	shared_ptr <TLSSession_OpenSSL> m_session; + +	shared_ptr <socket> m_wrapped; + +	bool m_connected; + +	byte_t m_buffer[65536]; + +	SSL* m_ssl; + +	unsigned int m_status; + +	// Last exception thrown from C BIO functions +	scoped_ptr <exception> m_ex; +}; + + +} // tls +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL + +#endif // VMIME_BUILDING_DOC + +#endif // VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED + | 
