diff options
| author | Vincent Richard <[email protected]> | 2013-12-29 10:02:12 +0100 |
|---|---|---|
| committer | Vincent Richard <[email protected]> | 2013-12-29 10:02:12 +0100 |
| commit | 152c6bed75598a6ca5efb7914701157270155833 (patch) | |
| tree | 8faced1d75a45c819630323da256248415992ed0 /src/net/tls | |
| parent | Merge branch 'master' of https://github.com/kisli/vmime (diff) | |
| download | vmime-152c6bed75598a6ca5efb7914701157270155833.tar.gz vmime-152c6bed75598a6ca5efb7914701157270155833.zip | |
Merged source and header files in directory structure. Got rid of SConstruct build.
Diffstat (limited to 'src/net/tls')
| -rw-r--r-- | src/net/tls/TLSProperties.cpp | 44 | ||||
| -rw-r--r-- | src/net/tls/TLSSecuredConnectionInfos.cpp | 72 | ||||
| -rw-r--r-- | src/net/tls/TLSSession.cpp | 48 | ||||
| -rw-r--r-- | src/net/tls/TLSSocket.cpp | 44 | ||||
| -rw-r--r-- | src/net/tls/gnutls/TLSProperties_GnuTLS.cpp | 113 | ||||
| -rw-r--r-- | src/net/tls/gnutls/TLSSession_GnuTLS.cpp | 300 | ||||
| -rw-r--r-- | src/net/tls/gnutls/TLSSocket_GnuTLS.cpp | 490 | ||||
| -rw-r--r-- | src/net/tls/openssl/OpenSSLInitializer.cpp | 142 | ||||
| -rw-r--r-- | src/net/tls/openssl/TLSProperties_OpenSSL.cpp | 112 | ||||
| -rw-r--r-- | src/net/tls/openssl/TLSSession_OpenSSL.cpp | 135 | ||||
| -rw-r--r-- | src/net/tls/openssl/TLSSocket_OpenSSL.cpp | 601 |
11 files changed, 0 insertions, 2101 deletions
diff --git a/src/net/tls/TLSProperties.cpp b/src/net/tls/TLSProperties.cpp deleted file mode 100644 index 1986db79..00000000 --- a/src/net/tls/TLSProperties.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/src/net/tls/TLSSecuredConnectionInfos.cpp b/src/net/tls/TLSSecuredConnectionInfos.cpp deleted file mode 100644 index 4856e9af..00000000 --- a/src/net/tls/TLSSecuredConnectionInfos.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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, - shared_ptr <TLSSession> tlsSession, 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/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp deleted file mode 100644 index a46f07ca..00000000 --- a/src/net/tls/TLSSession.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/src/net/tls/TLSSocket.cpp b/src/net/tls/TLSSocket.cpp deleted file mode 100644 index 0419a571..00000000 --- a/src/net/tls/TLSSocket.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/src/net/tls/gnutls/TLSProperties_GnuTLS.cpp b/src/net/tls/gnutls/TLSProperties_GnuTLS.cpp deleted file mode 100644 index 36ab7d7a..00000000 --- a/src/net/tls/gnutls/TLSProperties_GnuTLS.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/src/net/tls/gnutls/TLSSession_GnuTLS.cpp b/src/net/tls/gnutls/TLSSession_GnuTLS.cpp deleted file mode 100644 index 1c520ed1..00000000 --- a/src/net/tls/gnutls/TLSSession_GnuTLS.cpp +++ /dev/null @@ -1,300 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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 anonCred; - gnutls_certificate_credentials certCred; -}; - -static TLSGlobal g_gnutlsGlobal; - - -#endif // VMIME_BUILDING_DOC - - - -// static -shared_ptr <TLSSession> TLSSession::create(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) -{ - return make_shared <TLSSession_GnuTLS>(cv, props); -} - - -TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) - : m_certVerifier(cv), m_props(props) -{ - int res; - - m_gnutlsSession = new gnutls_session; - - 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() -{ - if (m_gnutlsSession) - { - gnutls_deinit(*m_gnutlsSession); - - delete m_gnutlsSession; - m_gnutlsSession = NULL; - } -} - - -shared_ptr <TLSSocket> TLSSession_GnuTLS::getSocket(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/src/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/src/net/tls/gnutls/TLSSocket_GnuTLS.cpp deleted file mode 100644 index 5a90565b..00000000 --- a/src/net/tls/gnutls/TLSSocket_GnuTLS.cpp +++ /dev/null @@ -1,490 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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 "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(shared_ptr <TLSSession> session, shared_ptr <socket> sok) -{ - return make_shared <TLSSocket_GnuTLS> - (dynamicCast <TLSSession_GnuTLS>(session), sok); -} - - -TLSSocket_GnuTLS::TLSSocket_GnuTLS(shared_ptr <TLSSession_GnuTLS> session, shared_ptr <socket> sok) - : m_session(session), m_wrapped(sok), m_connected(false), - m_handshaking(false), m_ex(NULL), m_status(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); -} - - -TLSSocket_GnuTLS::~TLSSocket_GnuTLS() -{ - if (m_ex) - { - delete m_ex; - m_ex = NULL; - } - - try - { - disconnect(); - } - catch (...) - { - // Don't throw exception in destructor - } -} - - -void TLSSocket_GnuTLS::connect(const string& address, const port_t port) -{ - m_wrapped->connect(address, port); - - handshake(null); - - m_connected = true; -} - - -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(); -} - - -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_WOULDBLOCK; - - const ssize_t ret = gnutls_record_recv - (*m_session->m_gnutlsSession, - buffer, static_cast <size_t>(count)); - - if (m_ex) - internalThrow(); - - if (ret < 0) - { - if (ret == GNUTLS_E_AGAIN) - { - m_status |= STATUS_WOULDBLOCK; - 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) -{ - ssize_t ret = gnutls_record_send - (*m_session->m_gnutlsSession, - buffer, static_cast <size_t>(count)); - - if (m_ex) - internalThrow(); - - if (ret < 0) - { - if (ret == GNUTLS_E_AGAIN) - { - m_status |= STATUS_WOULDBLOCK; - return; - } - - TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret)); - } -} - - -size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t count) -{ - ssize_t ret = gnutls_record_send - (*m_session->m_gnutlsSession, - buffer, static_cast <size_t>(count)); - - if (m_ex) - internalThrow(); - - if (ret < 0) - { - if (ret == GNUTLS_E_AGAIN) - { - m_status |= STATUS_WOULDBLOCK; - 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) -{ - if (toHandler) - toHandler->resetTimeOut(); - - // Start handshaking process - m_handshaking = true; - m_toHandler = toHandler; - - try - { - while (true) - { - const int ret = gnutls_handshake(*m_session->m_gnutlsSession); - - if (m_ex) - internalThrow(); - - if (ret < 0) - { - if (ret == GNUTLS_E_AGAIN || - ret == GNUTLS_E_INTERRUPTED) - { - // Non-fatal error - platform::getHandler()->wait(); - } - else - { - TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret); - } - } - else - { - // Successful handshake - break; - } - } - } - catch (...) - { - m_handshaking = false; - m_toHandler = null; - - throw; - } - - m_handshaking = false; - m_toHandler = null; - - // 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; -} - - -ssize_t TLSSocket_GnuTLS::gnutlsPushFunc - (gnutls_transport_ptr trspt, const void* data, size_t len) -{ - TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt); - - try - { - sok->m_wrapped->sendRaw - (reinterpret_cast <const byte_t*>(data), len); - } - catch (exception& e) - { - // Workaround for bad behaviour when throwing C++ exceptions - // from C functions (GNU TLS) - sok->m_ex = e.clone(); - return -1; - } - - return len; -} - - -ssize_t TLSSocket_GnuTLS::gnutlsPullFunc - (gnutls_transport_ptr trspt, void* data, size_t len) -{ - TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt); - - try - { - // Workaround for cross-platform asynchronous handshaking: - // gnutls_handshake() only returns GNUTLS_E_AGAIN if recv() - // returns -1 and errno is set to EGAIN... - if (sok->m_handshaking) - { - while (true) - { - const ssize_t ret = static_cast <ssize_t> - (sok->m_wrapped->receiveRaw - (reinterpret_cast <byte_t*>(data), len)); - - if (ret == 0) - { - // No data available yet - platform::getHandler()->wait(); - } - else - { - return ret; - } - - // Check whether the time-out delay is elapsed - if (sok->m_toHandler && sok->m_toHandler->isTimeOut()) - { - if (!sok->m_toHandler->handleTimeOut()) - throw exceptions::operation_timed_out(); - - sok->m_toHandler->resetTimeOut(); - } - } - } - else - { - const ssize_t n = static_cast <ssize_t> - (sok->m_wrapped->receiveRaw - (reinterpret_cast <byte_t*>(data), len)); - - if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) - return GNUTLS_E_AGAIN; - - return n; - } - } - catch (exception& e) - { - // Workaround for bad 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() const -{ - unsigned int certCount = 0; - const gnutls_datum* rawData = gnutls_certificate_get_peers - (*m_session->m_gnutlsSession, &certCount); - - if (rawData == NULL) - return null; - - // Try X.509 - gnutls_x509_crt* x509Certs = new gnutls_x509_crt[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) - { - // 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); - } - - delete [] x509Certs; - - return null; -} - - -// 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. - -#ifndef VMIME_BUILDING_DOC - -class TLSSocket_DeleteExWrapper : public object -{ -public: - - TLSSocket_DeleteExWrapper(exception* ex) : m_ex(ex) { } - ~TLSSocket_DeleteExWrapper() { delete m_ex; } - -private: - - exception* m_ex; -}; - -#endif // VMIME_BUILDING_DOC - - -void TLSSocket_GnuTLS::internalThrow() -{ - static std::vector <shared_ptr <TLSSocket_DeleteExWrapper> > exToDelete; - - if (m_ex) - { - // Reset the current exception pointer to prevent the same - // exception from being thrown again later - exception* ex = m_ex; - m_ex = NULL; - - // To avoid memory leaks - exToDelete.push_back(make_shared <TLSSocket_DeleteExWrapper>(ex)); - - throw *ex; - } -} - - -} // tls -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS diff --git a/src/net/tls/openssl/OpenSSLInitializer.cpp b/src/net/tls/openssl/OpenSSLInitializer.cpp deleted file mode 100644 index 1bbb9ee5..00000000 --- a/src/net/tls/openssl/OpenSSLInitializer.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/utility/sync/autoLock.hpp" -#include "vmime/utility/sync/criticalSection.hpp" - -#include "vmime/platform.hpp" - -#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 - - -namespace vmime { -namespace net { -namespace tls { - - -shared_ptr <vmime::utility::sync::criticalSection >* OpenSSLInitializer::sm_mutexes; - - -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_config(NULL); -#endif - - SSL_load_error_strings(); - SSL_library_init(); - OpenSSL_add_all_algorithms(); - - unsigned char seed[SEEDSIZE]; - vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE); - RAND_seed(seed, SEEDSIZE); - - int numMutexes = CRYPTO_num_locks(); - sm_mutexes = new shared_ptr <vmime::utility::sync::criticalSection>[numMutexes]; - - for (int i = 0 ; i < numMutexes ; ++i) - sm_mutexes[i] = vmime::platform::getHandler()->createCriticalSection(); - - CRYPTO_set_locking_callback(&OpenSSLInitializer::lock); - CRYPTO_set_id_callback(&OpenSSLInitializer::id); -} - - -// static -void OpenSSLInitializer::uninitialize() -{ - EVP_cleanup(); - ERR_free_strings(); - - CRYPTO_set_locking_callback(NULL); - CRYPTO_set_id_callback(NULL); - - delete [] sm_mutexes; -} - - -// static -void OpenSSLInitializer::lock(int mode, int n, const char* /* file */, int /* line */) -{ - if (mode & CRYPTO_LOCK) - sm_mutexes[n]->lock(); - else - sm_mutexes[n]->unlock(); -} - - -// static -unsigned long OpenSSLInitializer::id() -{ - return vmime::platform::getHandler()->getThreadId(); -} - - -} // tls -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL - diff --git a/src/net/tls/openssl/TLSProperties_OpenSSL.cpp b/src/net/tls/openssl/TLSProperties_OpenSSL.cpp deleted file mode 100644 index 932477df..00000000 --- a/src/net/tls/openssl/TLSProperties_OpenSSL.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/src/net/tls/openssl/TLSSession_OpenSSL.cpp b/src/net/tls/openssl/TLSSession_OpenSSL.cpp deleted file mode 100644 index cf600a63..00000000 --- a/src/net/tls/openssl/TLSSession_OpenSSL.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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/exception.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(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) -{ - return make_shared <TLSSession_OpenSSL>(cv, props); -} - - -TLSSession_OpenSSL::TLSSession_OpenSSL(shared_ptr <vmime::security::cert::certificateVerifier> cv, 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(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) -{ - 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 exceptions::certificate_exception(oss.str()); - } -} - - -void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) -{ - 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 exceptions::certificate_exception(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/src/net/tls/openssl/TLSSocket_OpenSSL.cpp b/src/net/tls/openssl/TLSSocket_OpenSSL.cpp deleted file mode 100644 index ef6647d6..00000000 --- a/src/net/tls/openssl/TLSSocket_OpenSSL.cpp +++ /dev/null @@ -1,601 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> -// -// 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; - - -// 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 -}; - - -// static -shared_ptr <TLSSocket> TLSSocket::wrap(shared_ptr <TLSSession> session, shared_ptr <socket> sok) -{ - return make_shared <TLSSocket_OpenSSL> - (dynamicCast <TLSSession_OpenSSL>(session), sok); -} - - -TLSSocket_OpenSSL::TLSSocket_OpenSSL(shared_ptr <TLSSession_OpenSSL> session, shared_ptr <socket> sok) - : m_session(session), m_wrapped(sok), m_connected(false), m_ssl(0), m_status(0), m_ex(NULL) -{ -} - - -TLSSocket_OpenSSL::~TLSSocket_OpenSSL() -{ - try - { - disconnect(); - - if (m_ssl) - { - SSL_free(m_ssl); - m_ssl = 0; - } - } - catch (...) - { - // Don't throw in destructor - } -} - - -void TLSSocket_OpenSSL::createSSLHandle() -{ - if (m_wrapped->isConnected()) - { - BIO* sockBio = BIO_new(&sm_customBIOMethod); - sockBio->ptr = this; - sockBio->init = 1; - - 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_connect_state(m_ssl); - } - else - { - throw exceptions::tls_exception("Unconnected socket error"); - } -} - - -void TLSSocket_OpenSSL::connect(const string& address, const port_t port) -{ - m_wrapped->connect(address, port); - - createSSLHandle(); - - handshake(null); - - m_connected = true; -} - - -void TLSSocket_OpenSSL::disconnect() -{ - if (m_connected) - { - 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); - } - - m_wrapped->disconnect(); - m_connected = false; - } -} - - -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(); -} - - -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) -{ - m_status &= ~STATUS_WOULDBLOCK; - - 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 || error == SSL_ERROR_WANT_READ) - { - m_status |= STATUS_WOULDBLOCK; - return 0; - } - - handleError(rc); - } - - return rc; -} - - -void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) -{ - sendRawNonBlocking(buffer, count); -} - - -size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count) -{ - m_status &= ~STATUS_WOULDBLOCK; - - 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 || error == SSL_ERROR_WANT_READ) - { - m_status |= STATUS_WOULDBLOCK; - return 0; - } - - handleError(rc); - } - - return rc; -} - - -void TLSSocket_OpenSSL::handshake(shared_ptr <timeoutHandler> toHandler) -{ - if (toHandler) - toHandler->resetTimeOut(); - - // Start handshaking process - m_toHandler = toHandler; - - if (!m_ssl) - createSSLHandle(); - - try - { - int rc; - - while ((rc = SSL_do_handshake(m_ssl)) <= 0) - { - const int err = SSL_get_error(m_ssl, rc); - - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) - { - // No data available yet - platform::getHandler()->wait(); - } - else - { - handleError(rc); - } - - // Check whether the time-out delay is elapsed - if (m_toHandler && m_toHandler->isTimeOut()) - { - if (!m_toHandler->handleTimeOut()) - throw exceptions::operation_timed_out(); - - m_toHandler->resetTimeOut(); - } - } - } - catch (...) - { - SSL_free(m_ssl); - m_ssl = 0; - m_toHandler = null; - throw; - } - - m_toHandler = null; - - // 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; -} - - -shared_ptr <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates() const -{ - 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: - return; - - case SSL_ERROR_SYSCALL: - { - if (lastError == 0) - { - if (rc == 0) - { - throw exceptions::tls_exception("SSL connection unexpectedly closed"); - } - else - { - vmime::string msg; - std::ostringstream oss(msg); - 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->ptr); - - if (!bio->init || !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>(len); - } - 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->ptr); - - if (!bio->init || !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->shutdown; - break; - - case BIO_CTRL_SET_CLOSE: - - bio->shutdown = 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->init = 0; - bio->num = 0; - bio->ptr = NULL; - bio->flags = 0; - - return 1; -} - - -// static -int TLSSocket_OpenSSL::bio_destroy(BIO* bio) -{ - if (bio == NULL) - return 0; - - if (bio->shutdown) - { - bio->ptr = NULL; - bio->init = 0; - bio->flags = 0; - } - - return 1; -} - - -} // tls -} // net -} // vmime - - -#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL |
