diff options
Diffstat (limited to 'src/vmime/net/tls')
22 files changed, 797 insertions, 678 deletions
diff --git a/src/vmime/net/tls/TLSProperties.cpp b/src/vmime/net/tls/TLSProperties.cpp index 1986db79..f7721d40 100644 --- a/src/vmime/net/tls/TLSProperties.cpp +++ b/src/vmime/net/tls/TLSProperties.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 diff --git a/src/vmime/net/tls/TLSProperties.hpp b/src/vmime/net/tls/TLSProperties.hpp index 0dbc8f05..94341cae 100644 --- a/src/vmime/net/tls/TLSProperties.hpp +++ b/src/vmime/net/tls/TLSProperties.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -41,8 +41,8 @@ namespace tls { /** Holds options for a TLS session. */ -class VMIME_EXPORT TLSProperties : public object -{ +class VMIME_EXPORT TLSProperties : public object { + public: TLSProperties(); @@ -50,8 +50,8 @@ public: /** Predefined generic cipher suites (work with all TLS libraries). */ - enum GenericCipherSuite - { + 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). */ diff --git a/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp b/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp index 4856e9af..055dfea0 100644 --- a/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp +++ b/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -36,29 +36,34 @@ 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) -{ +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 -{ +const string TLSSecuredConnectionInfos::getHost() const { + return m_host; } -port_t TLSSecuredConnectionInfos::getPort() const -{ +port_t TLSSecuredConnectionInfos::getPort() const { + return m_port; } -shared_ptr <const security::cert::certificateChain> TLSSecuredConnectionInfos::getPeerCertificates() const -{ +shared_ptr <const security::cert::certificateChain> TLSSecuredConnectionInfos::getPeerCertificates() const { + return m_tlsSocket->getPeerCertificates(); } diff --git a/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp b/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp index e552d6f9..c65e9d26 100644 --- a/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp +++ b/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -47,12 +47,16 @@ class TLSSocket; /** Information about a TLS-secured connection used by a service. */ -class VMIME_EXPORT TLSSecuredConnectionInfos : public securedConnectionInfos -{ +class VMIME_EXPORT TLSSecuredConnectionInfos : public securedConnectionInfos { + public: - TLSSecuredConnectionInfos(const string& host, const port_t port, - shared_ptr <TLSSession> tlsSession, shared_ptr <TLSSocket> tlsSocket); + 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; diff --git a/src/vmime/net/tls/TLSSession.cpp b/src/vmime/net/tls/TLSSession.cpp index a46f07ca..ab8b7c3a 100644 --- a/src/vmime/net/tls/TLSSession.cpp +++ b/src/vmime/net/tls/TLSSession.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -35,8 +35,8 @@ namespace net { namespace tls { -TLSSession::TLSSession() -{ +TLSSession::TLSSession() { + } diff --git a/src/vmime/net/tls/TLSSession.hpp b/src/vmime/net/tls/TLSSession.hpp index 8951ffa4..9e84fe76 100644 --- a/src/vmime/net/tls/TLSSession.hpp +++ b/src/vmime/net/tls/TLSSession.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -46,8 +46,8 @@ namespace tls { /** Describe a TLS connection between a client and a server. */ -class VMIME_EXPORT TLSSession : public object, public enable_shared_from_this <TLSSession> -{ +class VMIME_EXPORT TLSSession : public object, public enable_shared_from_this <TLSSession> { + public: /** Create and initialize a new TLS session. @@ -57,7 +57,10 @@ public: * @param props TLS properties for this session * @return a new TLS session */ - static shared_ptr <TLSSession> create(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props); + 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 @@ -66,7 +69,7 @@ public: * @param sok socket to wrap * @return TLS socket wrapper */ - virtual shared_ptr <TLSSocket> getSocket(shared_ptr <socket> sok) = 0; + virtual shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok) = 0; /** Get the object responsible for verifying certificates when * using secured connections (TLS/SSL). diff --git a/src/vmime/net/tls/TLSSocket.cpp b/src/vmime/net/tls/TLSSocket.cpp index 0419a571..fbca0820 100644 --- a/src/vmime/net/tls/TLSSocket.cpp +++ b/src/vmime/net/tls/TLSSocket.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 diff --git a/src/vmime/net/tls/TLSSocket.hpp b/src/vmime/net/tls/TLSSocket.hpp index be27d1d0..ca50aa8e 100644 --- a/src/vmime/net/tls/TLSSocket.hpp +++ b/src/vmime/net/tls/TLSSocket.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -49,8 +49,8 @@ class TLSSession; /** Add a TLS security layer to an existing socket. */ -class VMIME_EXPORT TLSSocket : public socket -{ +class VMIME_EXPORT TLSSocket : public socket { + public: /** Create a new socket object that adds a security layer @@ -59,7 +59,7 @@ public: * @param session TLS session * @param sok socket to wrap */ - static shared_ptr <TLSSocket> wrap(shared_ptr <TLSSession> session, shared_ptr <socket> sok); + static shared_ptr <TLSSocket> wrap(const shared_ptr <TLSSession>& session, const shared_ptr <socket>& sok); /** Starts a TLS handshake on this connection. * diff --git a/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp b/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp index 36ab7d7a..b2996fb3 100644 --- a/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp +++ b/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -42,63 +42,63 @@ namespace tls { TLSProperties::TLSProperties() - : m_data(make_shared <TLSProperties_GnuTLS>()) -{ + : m_data(make_shared <TLSProperties_GnuTLS>()) { + setCipherSuite(CIPHERSUITE_DEFAULT); } TLSProperties::TLSProperties(const TLSProperties& props) : object(), - m_data(make_shared <TLSProperties_GnuTLS>()) -{ + 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: +void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) { + + switch (cipherSuite) { + + case CIPHERSUITE_HIGH: - setCipherSuite("SECURE256:%SSL3_RECORD_VERSION"); - break; + setCipherSuite("SECURE256:%SSL3_RECORD_VERSION"); + break; - case CIPHERSUITE_MEDIUM: + case CIPHERSUITE_MEDIUM: - setCipherSuite("SECURE128:%SSL3_RECORD_VERSION"); - break; + setCipherSuite("SECURE128:%SSL3_RECORD_VERSION"); + break; - case CIPHERSUITE_LOW: + case CIPHERSUITE_LOW: - setCipherSuite("NORMAL:%SSL3_RECORD_VERSION"); - break; + setCipherSuite("NORMAL:%SSL3_RECORD_VERSION"); + break; - default: - case CIPHERSUITE_DEFAULT: + default: + case CIPHERSUITE_DEFAULT: - setCipherSuite("NORMAL:%SSL3_RECORD_VERSION"); - break; + setCipherSuite("NORMAL:%SSL3_RECORD_VERSION"); + break; } } -void TLSProperties::setCipherSuite(const string& cipherSuite) -{ +void TLSProperties::setCipherSuite(const string& cipherSuite) { + dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite = cipherSuite; } -const string TLSProperties::getCipherSuite() const -{ +const string TLSProperties::getCipherSuite() const { + return dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite; } -TLSProperties_GnuTLS& TLSProperties_GnuTLS::operator=(const TLSProperties_GnuTLS& other) -{ +TLSProperties_GnuTLS& TLSProperties_GnuTLS::operator=(const TLSProperties_GnuTLS& other) { + cipherSuite = other.cipherSuite; return *this; diff --git a/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp b/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp index 2038778a..96bbaead 100644 --- a/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp +++ b/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -44,8 +44,8 @@ namespace net { namespace tls { -class TLSProperties_GnuTLS : public object -{ +class TLSProperties_GnuTLS : public object { + public: TLSProperties_GnuTLS& operator=(const TLSProperties_GnuTLS& other); diff --git a/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp b/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp index 2a6450eb..8586537e 100644 --- a/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp +++ b/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -82,10 +82,10 @@ namespace tls { #ifndef VMIME_BUILDING_DOC // Initialize GNU TLS library -struct TLSGlobal -{ - TLSGlobal() - { +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); @@ -104,8 +104,8 @@ struct TLSGlobal gnutls_certificate_allocate_credentials(&certCred); } - ~TLSGlobal() - { + ~TLSGlobal() { + gnutls_anon_free_client_credentials(anonCred); gnutls_certificate_free_credentials(certCred); @@ -114,8 +114,8 @@ struct TLSGlobal #if VMIME_DEBUG && GNUTLS_DEBUG - static void TLSLogFunc(int level, const char *str) - { + static void TLSLogFunc(int level, const char *str) { + std::cerr << "GNUTLS: [" << level << "] " << str << std::endl; } @@ -134,21 +134,29 @@ static TLSGlobal g_gnutlsGlobal; // static -shared_ptr <TLSSession> TLSSession::create(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) -{ +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(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) - : m_certVerifier(cv), m_props(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) + 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. @@ -156,8 +164,8 @@ TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVeri gnutls_dh_set_prime_bits(*m_gnutlsSession, 128); if ((res = gnutls_priority_set_direct - (*m_gnutlsSession, m_props->getCipherSuite().c_str(), NULL)) != 0) - { + (*m_gnutlsSession, m_props->getCipherSuite().c_str(), NULL)) != 0) { + throwTLSException("gnutls_priority_set_direct", res); } @@ -170,13 +178,10 @@ TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVeri // 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); + res = gnutls_certificate_type_set_priority(*m_gnutlsSession, certTypePriority); - if (res < 0) - { - throwTLSException - ("gnutls_certificate_type_set_priority", res); + if (res < 0) { + throwTLSException("gnutls_certificate_type_set_priority", res); } // Sets the priority on the protocol types @@ -184,15 +189,12 @@ TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVeri res = gnutls_protocol_set_priority(*m_gnutlsSession, protoPriority); - if (res < 0) - { - throwTLSException - ("gnutls_certificate_type_set_priority", res); + if (res < 0) { + throwTLSException("gnutls_certificate_type_set_priority", res); } // Priority on the ciphers - const int cipherPriority[] = - { + const int cipherPriority[] = { GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_AES_128_CBC, @@ -206,13 +208,16 @@ TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVeri gnutls_cipher_set_priority(*m_gnutlsSession, cipherPriority); // Priority on MACs - const int macPriority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0}; + 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[] = - { + const int kxPriority[] = { GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, @@ -227,8 +232,7 @@ TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVeri gnutls_kx_set_priority(*m_gnutlsSession, kxPriority); // Priority on compression methods - const int compressionPriority[] = - { + const int compressionPriority[] = { GNUTLS_COMP_ZLIB, //GNUTLS_COMP_LZO, GNUTLS_COMP_NULL, @@ -240,54 +244,56 @@ TLSSession_GnuTLS::TLSSession_GnuTLS(shared_ptr <security::cert::certificateVeri #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_ANON, g_gnutlsGlobal.anonCred + ); - gnutls_credentials_set(*m_gnutlsSession, - GNUTLS_CRD_CERTIFICATE, g_gnutlsGlobal.certCred); + gnutls_credentials_set( + *m_gnutlsSession, GNUTLS_CRD_CERTIFICATE, g_gnutlsGlobal.certCred + ); } TLSSession_GnuTLS::TLSSession_GnuTLS(const TLSSession_GnuTLS&) - : TLSSession() -{ + : TLSSession() { + // Not used } -TLSSession_GnuTLS::~TLSSession_GnuTLS() -{ - try - { - if (m_gnutlsSession) - { +TLSSession_GnuTLS::~TLSSession_GnuTLS() { + + try { + + if (m_gnutlsSession) { + gnutls_deinit(*m_gnutlsSession); delete m_gnutlsSession; m_gnutlsSession = NULL; } - } - catch (...) - { + + } catch (...) { + // Don't throw in destructor } } -shared_ptr <TLSSocket> TLSSession_GnuTLS::getSocket(shared_ptr <socket> sok) -{ +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() -{ +shared_ptr <security::cert::certificateVerifier> TLSSession_GnuTLS::getCertificateVerifier() { + return m_certVerifier; } -void TLSSession_GnuTLS::throwTLSException(const string& fname, const int code) -{ +void TLSSession_GnuTLS::throwTLSException(const string& fname, const int code) { + std::ostringstream msg; msg << fname + "() returned code "; diff --git a/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp b/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp index 14172ee0..2a7f9d7f 100644 --- a/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp +++ b/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -46,17 +46,21 @@ namespace net { namespace tls { -class TLSSession_GnuTLS : public TLSSession -{ +class TLSSession_GnuTLS : public TLSSession { + friend class TLSSocket_GnuTLS; public: - TLSSession_GnuTLS(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props); + TLSSession_GnuTLS( + const shared_ptr <security::cert::certificateVerifier>& cv, + const shared_ptr <TLSProperties>& props + ); + ~TLSSession_GnuTLS(); - shared_ptr <TLSSocket> getSocket(shared_ptr <socket> sok); + shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok); shared_ptr <security::cert::certificateVerifier> getCertificateVerifier(); diff --git a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp index 16dabb66..73d52231 100644 --- a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp +++ b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -50,17 +50,26 @@ namespace tls { // static -shared_ptr <TLSSocket> TLSSocket::wrap(shared_ptr <TLSSession> session, shared_ptr <socket> sok) +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); + 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_ex(NULL), m_status(0), m_errno(0) -{ +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); @@ -69,41 +78,38 @@ TLSSocket_GnuTLS::TLSSocket_GnuTLS(shared_ptr <TLSSession_GnuTLS> session, share } -TLSSocket_GnuTLS::~TLSSocket_GnuTLS() -{ +TLSSocket_GnuTLS::~TLSSocket_GnuTLS() { + resetException(); - try - { + try { disconnect(); - } - catch (...) - { + } catch (...) { // Don't throw exception in destructor } } -void TLSSocket_GnuTLS::connect(const string& address, const port_t port) -{ - try - { +void TLSSocket_GnuTLS::connect(const string& address, const port_t port) { + + try { + m_wrapped->connect(address, port); handshake(); - } - catch (...) - { + + } catch (...) { + disconnect(); throw; } } -void TLSSocket_GnuTLS::disconnect() -{ - if (m_connected) - { +void TLSSocket_GnuTLS::disconnect() { + + if (m_connected) { + gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR); m_wrapped->disconnect(); @@ -113,99 +119,101 @@ void TLSSocket_GnuTLS::disconnect() } -bool TLSSocket_GnuTLS::isConnected() const -{ +bool TLSSocket_GnuTLS::isConnected() const { + return m_wrapped->isConnected() && m_connected; } -size_t TLSSocket_GnuTLS::getBlockSize() const -{ +size_t TLSSocket_GnuTLS::getBlockSize() const { + return 16384; // 16 KB } -const string TLSSocket_GnuTLS::getPeerName() const -{ +const string TLSSocket_GnuTLS::getPeerName() const { + return m_wrapped->getPeerName(); } -const string TLSSocket_GnuTLS::getPeerAddress() const -{ +const string TLSSocket_GnuTLS::getPeerAddress() const { + return m_wrapped->getPeerAddress(); } -shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler() -{ +shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler() { + return m_wrapped->getTimeoutHandler(); } -void TLSSocket_GnuTLS::setTracer(shared_ptr <net::tracer> tracer) -{ +void TLSSocket_GnuTLS::setTracer(const shared_ptr <net::tracer>& tracer) { + m_wrapped->setTracer(tracer); } -shared_ptr <net::tracer> TLSSocket_GnuTLS::getTracer() -{ +shared_ptr <net::tracer> TLSSocket_GnuTLS::getTracer() { + return m_wrapped->getTracer(); } -bool TLSSocket_GnuTLS::waitForRead(const int msecs) -{ +bool TLSSocket_GnuTLS::waitForRead(const int msecs) { + return m_wrapped->waitForRead(msecs); } -bool TLSSocket_GnuTLS::waitForWrite(const int msecs) -{ +bool TLSSocket_GnuTLS::waitForWrite(const int msecs) { + return m_wrapped->waitForWrite(msecs); } -void TLSSocket_GnuTLS::receive(string& buffer) -{ +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) -{ +void TLSSocket_GnuTLS::send(const string& buffer) { + sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length()); } -void TLSSocket_GnuTLS::send(const char* str) -{ +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) -{ +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)); + 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) + if (ret < 0) { + + if (ret == GNUTLS_E_AGAIN) { + + if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { m_status |= STATUS_WANT_READ; - else + } else { m_status |= STATUS_WANT_WRITE; + } return 0; } @@ -217,36 +225,38 @@ size_t TLSSocket_GnuTLS::receiveRaw(byte_t* buffer, const size_t count) } -void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) -{ +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 ; ) - { + for (size_t size = count ; size > 0 ; ) { + resetException(); - ssize_t ret = gnutls_record_send - (*m_session->m_gnutlsSession, - buffer, static_cast <size_t>(size)); + 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) + if (ret < 0) { + + if (ret == GNUTLS_E_AGAIN) { + + if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { m_wrapped->waitForRead(); - else + } else { m_wrapped->waitForWrite(); + } continue; } TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret)); - } - else - { + + } else { + buffer += ret; size -= ret; } @@ -254,26 +264,28 @@ void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) } -size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t count) -{ +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)); + 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) + if (ret < 0) { + + if (ret == GNUTLS_E_AGAIN) { + + if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { m_status |= STATUS_WANT_READ; - else + } else { m_status |= STATUS_WANT_WRITE; + } return 0; } @@ -285,68 +297,72 @@ size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t c } -unsigned int TLSSocket_GnuTLS::getStatus() const -{ +unsigned int TLSSocket_GnuTLS::getStatus() const { + return m_status | m_wrapped->getStatus(); } -void TLSSocket_GnuTLS::handshake() -{ +void TLSSocket_GnuTLS::handshake() { + shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler(); - if (toHandler) + if (toHandler) { toHandler->resetTimeOut(); + } - if (getTracer()) + if (getTracer()) { getTracer()->traceSend("Beginning SSL/TLS handshake"); + } // Start handshaking process - try - { - while (true) - { + try { + + 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) + if (ret < 0) { + + if (ret == GNUTLS_E_AGAIN) { + + if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) { m_wrapped->waitForRead(); - else + } else { m_wrapped->waitForWrite(); - } - else if (ret == GNUTLS_E_INTERRUPTED) - { + } + + } else if (ret == GNUTLS_E_INTERRUPTED) { + // Non-fatal error - } - else - { + + } else { + TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret); } - } - else - { + + } else { + // Successful handshake break; } } - } - catch (...) - { + + } catch (...) { + throw; } // Verify server's certificate(s) shared_ptr <security::cert::certificateChain> certs = getPeerCertificates(); - if (certs == NULL) + if (certs == NULL) { throw exceptions::tls_exception("No peer certificate."); + } m_session->getCertificateVerifier()->verify(certs, getPeerName()); @@ -354,35 +370,38 @@ void TLSSocket_GnuTLS::handshake() } -int TLSSocket_GnuTLS::gnutlsErrnoFunc(gnutls_transport_ptr_t trspt) -{ +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) -{ +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)); + try { + + const ssize_t ret = static_cast <ssize_t>( + sok->m_wrapped->sendRawNonBlocking(reinterpret_cast <const byte_t*>(data), len) + ); + + if (ret == 0) { - if (ret == 0) - { gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN); sok->m_errno = EAGAIN; return -1; } return ret; - } - catch (exception& e) - { + + } catch (exception& e) { + // Workaround for non-portable behaviour when throwing C++ exceptions // from C functions (GNU TLS) sok->m_ex = e.clone(); @@ -391,28 +410,31 @@ ssize_t TLSSocket_GnuTLS::gnutlsPushFunc } -ssize_t TLSSocket_GnuTLS::gnutlsPullFunc - (gnutls_transport_ptr_t trspt, void* data, size_t len) -{ +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)); + try { + + const ssize_t n = static_cast <ssize_t>( + sok->m_wrapped->receiveRaw(reinterpret_cast <byte_t*>(data), len) + ); + + if (n == 0) { - if (n == 0) - { gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN); sok->m_errno = EAGAIN; return -1; } return n; - } - catch (exception& e) - { + + } catch (exception& e) { + // Workaround for non-portable behaviour when throwing C++ exceptions // from C functions (GNU TLS) sok->m_ex = e.clone(); @@ -421,74 +443,74 @@ ssize_t TLSSocket_GnuTLS::gnutlsPullFunc } -shared_ptr <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertificates() -{ - if (getTracer()) +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); + const gnutls_datum_t* rawData = gnutls_certificate_get_peers( + *m_session->m_gnutlsSession, &certCount + ); - if (rawData == NULL) + 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) - { + 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); + 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]); + } - if (res < 0) - { // XXX more fine-grained error reporting? delete [] x509Certs; return null; } } - { - std::vector <shared_ptr <security::cert::certificate> > certs; - bool error = false; + std::vector <shared_ptr <security::cert::certificate> > certs; + bool error = false; - for (unsigned int i = 0 ; i < certCount ; ++i) - { - size_t dataSize = 0; + for (unsigned int i = 0 ; i < certCount ; ++i) { - gnutls_x509_crt_export(x509Certs[i], - GNUTLS_X509_FMT_DER, NULL, &dataSize); + size_t dataSize = 0; - std::vector <byte_t> data(dataSize); + gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, NULL, &dataSize); - gnutls_x509_crt_export(x509Certs[i], - GNUTLS_X509_FMT_DER, &data[0], &dataSize); + std::vector <byte_t> data(dataSize); - shared_ptr <security::cert::X509Certificate> cert = - security::cert::X509Certificate::import(&data[0], dataSize); + gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, &data[0], &dataSize); - if (cert != NULL) - certs.push_back(cert); - else - error = true; + shared_ptr <security::cert::X509Certificate> cert = + security::cert::X509Certificate::import(&data[0], dataSize); - gnutls_x509_crt_deinit(x509Certs[i]); + if (cert != NULL) { + certs.push_back(cert); + } else { + error = true; } - delete [] x509Certs; - - if (error) - return null; - - return make_shared <security::cert::certificateChain>(certs); + gnutls_x509_crt_deinit(x509Certs[i]); } delete [] x509Certs; - return null; + if (error) { + return null; + } + + return make_shared <security::cert::certificateChain>(certs); } @@ -498,19 +520,17 @@ shared_ptr <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertifica // gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions // thrown by the socket can not be caught. -void TLSSocket_GnuTLS::throwException() -{ - if (m_ex) - { +void TLSSocket_GnuTLS::throwException() { + + if (m_ex) { throw *m_ex; } } -void TLSSocket_GnuTLS::resetException() -{ - if (m_ex) - { +void TLSSocket_GnuTLS::resetException() { + + if (m_ex) { delete m_ex; m_ex = NULL; } diff --git a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp index 931cb993..0ac3e700 100644 --- a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp +++ b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -46,11 +46,11 @@ class TLSSession; class TLSSession_GnuTLS; -class TLSSocket_GnuTLS : public TLSSocket -{ +class TLSSocket_GnuTLS : public TLSSocket { + public: - TLSSocket_GnuTLS(shared_ptr <TLSSession_GnuTLS> session, shared_ptr <socket> sok); + TLSSocket_GnuTLS(const shared_ptr <TLSSession_GnuTLS>& session, const shared_ptr <socket>& sok); ~TLSSocket_GnuTLS(); @@ -83,7 +83,7 @@ public: shared_ptr <timeoutHandler> getTimeoutHandler(); - void setTracer(shared_ptr <net::tracer> tracer); + void setTracer(const shared_ptr <net::tracer>& tracer); shared_ptr <net::tracer> getTracer(); private: diff --git a/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp b/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp index 1bbb9ee5..74474480 100644 --- a/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp +++ b/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -52,34 +52,34 @@ namespace tls { shared_ptr <vmime::utility::sync::criticalSection >* OpenSSLInitializer::sm_mutexes; -OpenSSLInitializer::autoInitializer::autoInitializer() -{ +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::autoInitializer::~autoInitializer() { + } -OpenSSLInitializer::oneTimeInitializer::oneTimeInitializer() -{ +OpenSSLInitializer::oneTimeInitializer::oneTimeInitializer() { + initialize(); } -OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer() -{ +OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer() { + uninitialize(); } // static -void OpenSSLInitializer::initialize() -{ +void OpenSSLInitializer::initialize() { + #if OPENSSL_VERSION_NUMBER >= 0x0907000L OPENSSL_config(NULL); #endif @@ -95,8 +95,9 @@ void OpenSSLInitializer::initialize() int numMutexes = CRYPTO_num_locks(); sm_mutexes = new shared_ptr <vmime::utility::sync::criticalSection>[numMutexes]; - for (int i = 0 ; i < numMutexes ; ++i) + 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); @@ -104,8 +105,8 @@ void OpenSSLInitializer::initialize() // static -void OpenSSLInitializer::uninitialize() -{ +void OpenSSLInitializer::uninitialize() { + EVP_cleanup(); ERR_free_strings(); @@ -117,18 +118,19 @@ void OpenSSLInitializer::uninitialize() // static -void OpenSSLInitializer::lock(int mode, int n, const char* /* file */, int /* line */) -{ - if (mode & CRYPTO_LOCK) +void OpenSSLInitializer::lock(int mode, int n, const char* /* file */, int /* line */) { + + if (mode & CRYPTO_LOCK) { sm_mutexes[n]->lock(); - else + } else { sm_mutexes[n]->unlock(); + } } // static -unsigned long OpenSSLInitializer::id() -{ +unsigned long OpenSSLInitializer::id() { + return vmime::platform::getHandler()->getThreadId(); } diff --git a/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp b/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp index d7595aa8..b07c2e61 100644 --- a/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp +++ b/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -46,15 +46,13 @@ namespace tls { /** Class responsible for setting up OpenSSL */ -class OpenSSLInitializer -{ +class OpenSSLInitializer { + public: /** Automatically initialize OpenSSL */ - class autoInitializer - { - public: + struct autoInitializer { autoInitializer(); ~autoInitializer(); @@ -62,9 +60,7 @@ public: protected: - class oneTimeInitializer - { - public: + struct oneTimeInitializer { oneTimeInitializer(); ~oneTimeInitializer(); @@ -82,8 +78,7 @@ protected: static shared_ptr <vmime::utility::sync::criticalSection> getMutex(); - enum - { + enum { SEEDSIZE = 256 }; diff --git a/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp b/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp index 932477df..ea22f1cd 100644 --- a/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp +++ b/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -40,63 +40,63 @@ namespace tls { TLSProperties::TLSProperties() - : m_data(make_shared <TLSProperties_OpenSSL>()) -{ + : m_data(make_shared <TLSProperties_OpenSSL>()) { + setCipherSuite(CIPHERSUITE_DEFAULT); } TLSProperties::TLSProperties(const TLSProperties& props) : object(), - m_data(make_shared <TLSProperties_OpenSSL>()) -{ + 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: +void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) { + + switch (cipherSuite) { + + case CIPHERSUITE_HIGH: - setCipherSuite("HIGH:!ADH:@STRENGTH"); - break; + setCipherSuite("HIGH:!ADH:@STRENGTH"); + break; - case CIPHERSUITE_MEDIUM: + case CIPHERSUITE_MEDIUM: - setCipherSuite("MEDIUM:!ADH:@STRENGTH"); - break; + setCipherSuite("MEDIUM:!ADH:@STRENGTH"); + break; - case CIPHERSUITE_LOW: + case CIPHERSUITE_LOW: - setCipherSuite("LOW:!ADH:@STRENGTH"); - break; + setCipherSuite("LOW:!ADH:@STRENGTH"); + break; - default: - case CIPHERSUITE_DEFAULT: + default: + case CIPHERSUITE_DEFAULT: - setCipherSuite("DEFAULT:!ADH:@STRENGTH"); - break; + setCipherSuite("DEFAULT:!ADH:@STRENGTH"); + break; } } -void TLSProperties::setCipherSuite(const string& cipherSuite) -{ +void TLSProperties::setCipherSuite(const string& cipherSuite) { + dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite = cipherSuite; } -const string TLSProperties::getCipherSuite() const -{ +const string TLSProperties::getCipherSuite() const { + return dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite; } -TLSProperties_OpenSSL& TLSProperties_OpenSSL::operator=(const TLSProperties_OpenSSL& other) -{ +TLSProperties_OpenSSL& TLSProperties_OpenSSL::operator=(const TLSProperties_OpenSSL& other) { + cipherSuite = other.cipherSuite; return *this; diff --git a/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp b/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp index 5d2f075a..8304df23 100644 --- a/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp +++ b/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -44,8 +44,8 @@ namespace net { namespace tls { -class TLSProperties_OpenSSL : public object -{ +class TLSProperties_OpenSSL : public object { + public: TLSProperties_OpenSSL& operator=(const TLSProperties_OpenSSL& other); diff --git a/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp b/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp index 7892de65..019341c7 100644 --- a/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp +++ b/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -46,15 +46,23 @@ static OpenSSLInitializer::autoInitializer openSSLInitializer; // static -shared_ptr <TLSSession> TLSSession::create(shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) -{ +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(shared_ptr <vmime::security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props) - : m_sslctx(0), m_certVerifier(cv), m_props(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); @@ -64,36 +72,36 @@ TLSSession_OpenSSL::TLSSession_OpenSSL(shared_ptr <vmime::security::cert::certif TLSSession_OpenSSL::TLSSession_OpenSSL(const TLSSession_OpenSSL&) - : TLSSession() -{ + : TLSSession() { + // Not used } -TLSSession_OpenSSL::~TLSSession_OpenSSL() -{ +TLSSession_OpenSSL::~TLSSession_OpenSSL() { + SSL_CTX_free(m_sslctx); } -shared_ptr <TLSSocket> TLSSession_OpenSSL::getSocket(shared_ptr <socket> sok) -{ +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() -{ +shared_ptr <security::cert::certificateVerifier> TLSSession_OpenSSL::getCertificateVerifier() { + return m_certVerifier; } -void TLSSession_OpenSSL::usePrivateKeyFile(const vmime::string& keyfile) -{ +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) - { + 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)); @@ -106,12 +114,12 @@ void TLSSession_OpenSSL::usePrivateKeyFile(const vmime::string& keyfile) } -void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) -{ +void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) { + ERR_clear_error(); - if (SSL_CTX_use_certificate_chain_file(m_sslctx, chainFile.c_str()) != 1) - { + 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)); @@ -124,8 +132,8 @@ void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) } -SSL_CTX* TLSSession_OpenSSL::getContext() const -{ +SSL_CTX* TLSSession_OpenSSL::getContext() const { + return m_sslctx; } diff --git a/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp b/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp index 5a2b60a8..518216bc 100644 --- a/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp +++ b/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -49,30 +49,32 @@ namespace net { namespace tls { -class TLSSession_OpenSSL : public TLSSession -{ +class TLSSession_OpenSSL : public TLSSession { + friend class TLSSocket_OpenSSL; public: - TLSSession_OpenSSL(const shared_ptr <security::cert::certificateVerifier> cv, shared_ptr <TLSProperties> props); + TLSSession_OpenSSL( + const shared_ptr <security::cert::certificateVerifier>& cv, + const shared_ptr <TLSProperties>& props + ); + ~TLSSession_OpenSSL(); - shared_ptr <TLSSocket> getSocket(shared_ptr <socket> sok); + 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 - * @param passwd_callback If the private key is stored encrypted the + * @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. + /** Supply the certificate chain to present if requested by server. * * @param chainFile File in PEM format holding certificate chain */ @@ -105,4 +107,3 @@ private: #endif // VMIME_BUILDING_DOC #endif // VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED - diff --git a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp index a663f196..db782bb2 100644 --- a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp +++ b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -52,9 +52,10 @@ namespace tls { static OpenSSLInitializer::autoInitializer openSSLInitializer; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + // static -BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = -{ +BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = { 100 | BIO_TYPE_SOURCE_SINK, "vmime::socket glue", TLSSocket_OpenSSL::bio_write, @@ -67,46 +68,96 @@ BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = 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(shared_ptr <TLSSession> session, shared_ptr <socket> sok) -{ - return make_shared <TLSSocket_OpenSSL> - (dynamicCast <TLSSession_OpenSSL>(session), sok); +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(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() -{ +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 - { +TLSSocket_OpenSSL::~TLSSocket_OpenSSL() { + + try { disconnect(); - } - catch (...) - { + } catch (...) { // Don't throw in destructor } } -void TLSSocket_OpenSSL::createSSLHandle() -{ - if (m_wrapped->isConnected()) - { +void TLSSocket_OpenSSL::createSSLHandle() { + + if (m_wrapped->isConnected()) { + +#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) - { + if (!m_ssl) { BIO_free(sockBio); throw exceptions::tls_exception("Cannot create SSL object"); } @@ -114,156 +165,156 @@ void TLSSocket_OpenSSL::createSSLHandle() SSL_set_bio(m_ssl, sockBio, sockBio); 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 - { + + } else { + throw exceptions::tls_exception("Unconnected socket error"); } } -void TLSSocket_OpenSSL::connect(const string& address, const port_t port) -{ - try - { +void TLSSocket_OpenSSL::connect(const string& address, const port_t port) { + + try { + m_wrapped->connect(address, port); createSSLHandle(); handshake(); - } - catch (...) - { + + } catch (...) { + disconnect(); throw; } } -void TLSSocket_OpenSSL::disconnect() -{ - if (m_ssl) - { +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) + if (!shutdownSent) { SSL_shutdown(m_ssl); + } SSL_free(m_ssl); m_ssl = 0; } - if (m_connected) - { + if (m_connected) { m_connected = false; m_wrapped->disconnect(); } } -bool TLSSocket_OpenSSL::isConnected() const -{ +bool TLSSocket_OpenSSL::isConnected() const { + return m_wrapped->isConnected() && m_connected; } -size_t TLSSocket_OpenSSL::getBlockSize() const -{ +size_t TLSSocket_OpenSSL::getBlockSize() const { + return 16384; // 16 KB } -const string TLSSocket_OpenSSL::getPeerName() const -{ +const string TLSSocket_OpenSSL::getPeerName() const { + return m_wrapped->getPeerName(); } -const string TLSSocket_OpenSSL::getPeerAddress() const -{ +const string TLSSocket_OpenSSL::getPeerAddress() const { + return m_wrapped->getPeerAddress(); } -shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler() -{ +shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler() { + return m_wrapped->getTimeoutHandler(); } -void TLSSocket_OpenSSL::setTracer(shared_ptr <net::tracer> tracer) -{ +void TLSSocket_OpenSSL::setTracer(const shared_ptr <net::tracer>& tracer) { + m_wrapped->setTracer(tracer); } -shared_ptr <net::tracer> TLSSocket_OpenSSL::getTracer() -{ +shared_ptr <net::tracer> TLSSocket_OpenSSL::getTracer() { + return m_wrapped->getTracer(); } -bool TLSSocket_OpenSSL::waitForRead(const int msecs) -{ +bool TLSSocket_OpenSSL::waitForRead(const int msecs) { + return m_wrapped->waitForRead(msecs); } -bool TLSSocket_OpenSSL::waitForWrite(const int msecs) -{ +bool TLSSocket_OpenSSL::waitForWrite(const int msecs) { + return m_wrapped->waitForWrite(msecs); } -void TLSSocket_OpenSSL::receive(string& buffer) -{ +void TLSSocket_OpenSSL::receive(string& buffer) { + const size_t size = receiveRaw(m_buffer, sizeof(m_buffer)); - if (size != 0) + if (size != 0) { buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size); - else + } else { buffer.clear(); + } } -void TLSSocket_OpenSSL::send(const string& buffer) -{ +void TLSSocket_OpenSSL::send(const string& buffer) { + sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length()); } -void TLSSocket_OpenSSL::send(const char* str) -{ +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) +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()) + if (m_ex.get()) { internalThrow(); + } + + if (rc <= 0) { - if (rc <= 0) - { int error = SSL_get_error(m_ssl, rc); - if (error == SSL_ERROR_WANT_WRITE) - { + if (error == SSL_ERROR_WANT_WRITE) { m_status |= STATUS_WANT_WRITE; return 0; - } - else if (error == SSL_ERROR_WANT_READ) - { + } else if (error == SSL_ERROR_WANT_READ) { m_status |= STATUS_WANT_READ; return 0; } @@ -275,37 +326,35 @@ size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count) } -void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) -{ - if (!m_ssl) +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 ; ) - { + for (size_t size = count ; size > 0 ; ) { + ERR_clear_error(); int rc = SSL_write(m_ssl, buffer, static_cast <int>(size)); - if (rc <= 0) - { + if (rc <= 0) { + int error = SSL_get_error(m_ssl, rc); - if (error == SSL_ERROR_WANT_READ) - { + if (error == SSL_ERROR_WANT_READ) { m_wrapped->waitForRead(); continue; - } - else if (error == SSL_ERROR_WANT_WRITE) - { + } else if (error == SSL_ERROR_WANT_WRITE) { m_wrapped->waitForWrite(); continue; } handleError(rc); - } - else - { + + } else { + buffer += rc; size -= rc; } @@ -313,30 +362,29 @@ void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) } -size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count) -{ - if (!m_ssl) +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()) + if (m_ex.get()) { internalThrow(); + } + + if (rc <= 0) { - if (rc <= 0) - { int error = SSL_get_error(m_ssl, rc); - if (error == SSL_ERROR_WANT_WRITE) - { + if (error == SSL_ERROR_WANT_WRITE) { m_status |= STATUS_WANT_WRITE; return 0; - } - else if (error == SSL_ERROR_WANT_READ) - { + } else if (error == SSL_ERROR_WANT_READ) { m_status |= STATUS_WANT_READ; return 0; } @@ -348,59 +396,65 @@ size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t } -void TLSSocket_OpenSSL::handshake() -{ +void TLSSocket_OpenSSL::handshake() { + shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler(); - if (toHandler) + if (toHandler) { toHandler->resetTimeOut(); + } - if (getTracer()) + if (getTracer()) { getTracer()->traceSend("Beginning SSL/TLS handshake"); + } // Start handshaking process - if (!m_ssl) + if (!m_ssl) { createSSLHandle(); + } + + try { - try - { int rc; ERR_clear_error(); - while ((rc = SSL_do_handshake(m_ssl)) <= 0) - { + while ((rc = SSL_do_handshake(m_ssl)) <= 0) { + const int err = SSL_get_error(m_ssl, rc); - if (err == SSL_ERROR_WANT_READ) + if (err == SSL_ERROR_WANT_READ) { m_wrapped->waitForRead(); - else if (err == SSL_ERROR_WANT_WRITE) + } else if (err == SSL_ERROR_WANT_WRITE) { m_wrapped->waitForWrite(); - else + } else { handleError(rc); + } // Check whether the time-out delay is elapsed - if (toHandler && toHandler->isTimeOut()) - { - if (!toHandler->handleTimeOut()) + if (toHandler && toHandler->isTimeOut()) { + + if (!toHandler->handleTimeOut()) { throw exceptions::operation_timed_out(); + } toHandler->resetTimeOut(); } ERR_clear_error(); } - } - catch (...) - { + + } catch (...) { + throw; } // Verify server's certificate(s) shared_ptr <security::cert::certificateChain> certs = getPeerCertificates(); - if (certs == NULL) + if (!certs) { throw exceptions::tls_exception("No peer certificate."); + } m_session->getCertificateVerifier()->verify(certs, getPeerName()); @@ -408,121 +462,130 @@ void TLSSocket_OpenSSL::handshake() } -shared_ptr <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates() -{ - if (getTracer()) +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) + if (chain == NULL) { return null; + } int certCount = sk_X509_num(chain); - if (certCount == 0) + if (certCount == 0) { return null; + } bool error = false; std::vector <shared_ptr <security::cert::certificate> > certs; - for (int i = 0; i < certCount && !error; i++) - { + 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) + if (cert) { certs.push_back(cert); - else + } else { error = true; + } } - if (error) + if (error) { return null; + } return make_shared <security::cert::certificateChain>(certs); } -void TLSSocket_OpenSSL::internalThrow() -{ - if (m_ex.get()) +void TLSSocket_OpenSSL::internalThrow() { + + if (m_ex.get()) { throw *m_ex; + } } -void TLSSocket_OpenSSL::handleError(int rc) -{ - if (rc > 0) return; +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: + switch (sslError) { - disconnect(); - return; + case SSL_ERROR_ZERO_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()); + 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; } - break; - } - case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_READ: - BIO_set_retry_read(SSL_get_rbio(m_ssl)); - break; + BIO_set_retry_read(SSL_get_rbio(m_ssl)); + break; - case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_WRITE: - BIO_set_retry_write(SSL_get_wbio(m_ssl)); - break; + 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: + // 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); - } + if (lastError == 0) { + + throw exceptions::tls_exception("Unexpected SSL IO error"); + + } else { - break; + 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 -{ +unsigned int TLSSocket_OpenSSL::getStatus() const { + return m_status; } @@ -531,33 +594,35 @@ unsigned int TLSSocket_OpenSSL::getStatus() const // static -int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len) -{ +int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len) { + BIO_clear_retry_flags(bio); - if (buf == NULL || len <= 0) + if (buf == NULL || len <= 0) { return -1; + } - TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr); + TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio)); - if (!bio->init || !sok) + if (!BIO_get_init(bio) || !sok) { return -1; + } - try - { - const size_t n = sok->m_wrapped->sendRawNonBlocking - (reinterpret_cast <const byte_t*>(buf), len); + try { - if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) - { + 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) - { + + } catch (exception& e) { + // Workaround for passing C++ exceptions from C BIO functions sok->m_ex.reset(e.clone()); return -1; @@ -566,33 +631,35 @@ int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len) // static -int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len) -{ +int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len) { + BIO_clear_retry_flags(bio); - if (buf == NULL || len <= 0) + if (buf == NULL || len <= 0) { return -1; + } - TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr); + TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio)); - if (!bio->init || !sok) + if (!BIO_get_init(bio) || !sok) { return -1; + } + + try { - try - { - const size_t n = sok->m_wrapped->receiveRaw - (reinterpret_cast <byte_t*>(buf), len); + const size_t n = sok->m_wrapped->receiveRaw( + reinterpret_cast <byte_t*>(buf), len + ); - if (n == 0 || sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) - { + 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) - { + + } catch (exception& e) { + // Workaround for passing C++ exceptions from C BIO functions sok->m_ex.reset(e.clone()); return -1; @@ -601,50 +668,50 @@ int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len) // static -int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str) -{ +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 TLSSocket_OpenSSL::bio_ctrl(BIO* bio, int cmd, long num, void* /* ptr */) { + long ret = 1; - switch (cmd) - { - case BIO_CTRL_INFO: + switch (cmd) { + + case BIO_CTRL_INFO: - ret = 0; - break; + ret = 0; + break; - case BIO_CTRL_GET_CLOSE: + case BIO_CTRL_GET_CLOSE: - ret = bio->shutdown; - break; + ret = BIO_get_shutdown(bio); + break; - case BIO_CTRL_SET_CLOSE: + case BIO_CTRL_SET_CLOSE: - bio->shutdown = static_cast <int>(num); - break; + BIO_set_shutdown(bio, static_cast <int>(num)); + break; - case BIO_CTRL_PENDING: - case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: - ret = 0; - break; + ret = 0; + break; - case BIO_CTRL_DUP: - case BIO_CTRL_FLUSH: + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: - ret = 1; - break; + ret = 1; + break; - default: + default: - ret = 0; - break; + ret = 0; + break; } return ret; @@ -652,28 +719,28 @@ long TLSSocket_OpenSSL::bio_ctrl(BIO* bio, int cmd, long num, void* /* ptr */) // static -int TLSSocket_OpenSSL::bio_create(BIO* bio) -{ - bio->init = 0; - bio->num = 0; - bio->ptr = NULL; - bio->flags = 0; +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 == NULL) +int TLSSocket_OpenSSL::bio_destroy(BIO* bio) { + + if (!bio) { return 0; + } - if (bio->shutdown) - { - bio->ptr = NULL; - bio->init = 0; - bio->flags = 0; + if (BIO_get_shutdown(bio)) { + BIO_set_data(bio, NULL); + BIO_set_init(bio, 0); + BIO_set_flags(bio, 0); } return 1; diff --git a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp index 34324b8c..e30df680 100644 --- a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp +++ b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -50,11 +50,15 @@ class TLSSession; class TLSSession_OpenSSL; -class TLSSocket_OpenSSL : public TLSSocket -{ +class TLSSocket_OpenSSL : public TLSSocket { + public: - TLSSocket_OpenSSL(shared_ptr <TLSSession_OpenSSL> session, shared_ptr <socket> sok); + TLSSocket_OpenSSL( + const shared_ptr <TLSSession_OpenSSL>& session, + const shared_ptr <socket>& sok + ); + ~TLSSocket_OpenSSL(); @@ -87,7 +91,7 @@ public: shared_ptr <timeoutHandler> getTimeoutHandler(); - void setTracer(shared_ptr <net::tracer> tracer); + void setTracer(const shared_ptr <net::tracer>& tracer); shared_ptr <net::tracer> getTracer(); private: |