diff options
Diffstat (limited to '')
25 files changed, 2409 insertions, 396 deletions
diff --git a/src/exception.cpp b/src/exception.cpp index f2106e89..9620a310 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -719,6 +719,60 @@ const char* no_auth_information::name() const throw() { return "no_auth_informat #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + + +// +// tls_exception +// + +tls_exception::~tls_exception() throw() {} +tls_exception::tls_exception(const string& what, const exception& other) + : exception(what, other) {} + +exception* tls_exception::clone() const { return new tls_exception(*this); } +const char* tls_exception::name() const throw() { return "tls_exception"; } + + +// +// certificate_exception +// + +certificate_exception::~certificate_exception() throw() {} +certificate_exception::certificate_exception(const string& what, const exception& other) + : tls_exception(what, other) {} + +exception* certificate_exception::clone() const { return new certificate_exception(*this); } +const char* certificate_exception::name() const throw() { return "certificate_exception"; } + + +// +// certificate_verification_exception +// + +certificate_verification_exception::~certificate_verification_exception() throw() {} +certificate_verification_exception::certificate_verification_exception(const string& what, const exception& other) + : certificate_exception(what, other) {} + +exception* certificate_verification_exception::clone() const { return new certificate_verification_exception(*this); } +const char* certificate_verification_exception::name() const throw() { return "certificate_verification_exception"; } + + +// +// unsupported_certificate_type +// + +unsupported_certificate_type::~unsupported_certificate_type() throw() {} +unsupported_certificate_type::unsupported_certificate_type(const string& type, const exception& other) + : certificate_exception("Unsupported certificate type: '" + type + "'", other) {} + +exception* unsupported_certificate_type::clone() const { return new unsupported_certificate_type(*this); } +const char* unsupported_certificate_type::name() const throw() { return "unsupported_certificate_type"; } + + +#endif // VMIME_HAVE_TLS_SUPPORT + + } // exceptions diff --git a/src/net/authHelper.cpp b/src/net/authHelper.cpp deleted file mode 100644 index e9c217f3..00000000 --- a/src/net/authHelper.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 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 2 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 along -// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. -// - -#include "vmime/net/authHelper.hpp" - -#include "vmime/config.hpp" -#include "vmime/security/digest/messageDigestFactory.hpp" - - -namespace vmime { -namespace net { - - -// -// This code is based on the Sample Code published in the Appendix of -// the RFC-2104: "HMAC: Keyed-Hashing for Message Authentication". -// - -void hmac_md5(const string& text, const string& key, string& hexDigest) -{ - vmime_uint8 digest[16]; - - unsigned char ipad[65]; // inner padding - key XORd with ipad - unsigned char opad[65]; // outer padding - key XORd with opad - - unsigned char tkey[16]; - int tkeyLen; - - ref <security::digest::messageDigest> md5 = - security::digest::messageDigestFactory::getInstance()->create("md5"); - - // If key is longer than 64 bytes reset it to key = MD5(key) - if (key.length() > 64) - { - md5->reset(); - md5->update(reinterpret_cast <const vmime_uint8*>(key.data()), key.length()); - md5->finalize(); - - std::copy(md5->getDigest(), md5->getDigest() + 16, tkey); - tkeyLen = 16; - } - else - { - std::copy(key.begin(), key.end(), tkey); - tkeyLen = key.length(); - } - - // - // the HMAC_MD5 transform looks like: - // - // MD5(K XOR opad, MD5(K XOR ipad, text)) - // - // where K is an n byte key - // ipad is the byte 0x36 repeated 64 times - // - // opad is the byte 0x5c repeated 64 times - // and text is the data being protected - // - - // Start out by storing key in pads - std::fill(ipad, ipad + sizeof(ipad), 0); - std::fill(opad, opad + sizeof(opad), 0); - - std::copy(tkey, tkey + tkeyLen, ipad); - std::copy(tkey, tkey + tkeyLen, opad); - - // XOR key with ipad and opad values - for (int i = 0 ; i < 64 ; ++i) - { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - // Perform inner MD5 - md5->reset(); - md5->update(ipad, 64); - md5->update(text); - md5->finalize(); - - std::copy(md5->getDigest(), md5->getDigest() + 16, digest); - - // Perform outer MD5 - md5->reset(); - md5->update(opad, 64); - md5->update(digest, 16); - md5->finalize(); - - //std::copy(outerMD5.hash(), outerMD5.hash() + 16, digest); - - hexDigest = md5->getHexDigest(); -} - - -} // net -} // vmime diff --git a/src/net/builtinServices.inl b/src/net/builtinServices.inl index 88578e4b..803371ac 100644 --- a/src/net/builtinServices.inl +++ b/src/net/builtinServices.inl @@ -24,36 +24,52 @@ #ifndef VMIME_BUILDING_DOC -#define REGISTER_SERVICE(p_class, p_name) \ - vmime::net::service::initializer <vmime::net::p_class> p_name(#p_name) +#define REGISTER_SERVICE(p_class, p_name, p_type) \ + vmime::net::service::initializer <vmime::net::p_class> \ + p_name(#p_name, vmime::net::service::p_type) #if VMIME_BUILTIN_MESSAGING_PROTO_POP3 #include "vmime/net/pop3/POP3Store.hpp" - REGISTER_SERVICE(pop3::POP3Store, pop3); + REGISTER_SERVICE(pop3::POP3Store, pop3, TYPE_STORE); + + #if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/pop3/POP3SStore.hpp" + REGISTER_SERVICE(pop3::POP3SStore, pop3s, TYPE_STORE); + #endif // VMIME_HAVE_TLS_SUPPORT #endif #if VMIME_BUILTIN_MESSAGING_PROTO_SMTP #include "vmime/net/smtp/SMTPTransport.hpp" - REGISTER_SERVICE(smtp::SMTPTransport, smtp); + REGISTER_SERVICE(smtp::SMTPTransport, smtp, TYPE_TRANSPORT); + + #if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/smtp/SMTPSTransport.hpp" + REGISTER_SERVICE(smtp::SMTPSTransport, smtps, TYPE_TRANSPORT); + #endif // VMIME_HAVE_TLS_SUPPORT #endif #if VMIME_BUILTIN_MESSAGING_PROTO_IMAP #include "vmime/net/imap/IMAPStore.hpp" - REGISTER_SERVICE(imap::IMAPStore, imap); + REGISTER_SERVICE(imap::IMAPStore, imap, TYPE_STORE); + + #if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/imap/IMAPSStore.hpp" + REGISTER_SERVICE(imap::IMAPSStore, imaps, TYPE_STORE); + #endif // VMIME_HAVE_TLS_SUPPORT #endif #if VMIME_BUILTIN_MESSAGING_PROTO_MAILDIR #include "vmime/net/maildir/maildirStore.hpp" - REGISTER_SERVICE(maildir::maildirStore, maildir); + REGISTER_SERVICE(maildir::maildirStore, maildir, TYPE_STORE); #endif #if VMIME_BUILTIN_MESSAGING_PROTO_SENDMAIL #include "vmime/net/sendmail/sendmailTransport.hpp" - REGISTER_SERVICE(sendmail::sendmailTransport, sendmail); + REGISTER_SERVICE(sendmail::sendmailTransport, sendmail, TYPE_TRANSPORT); #endif diff --git a/src/net/imap/IMAPConnection.cpp b/src/net/imap/IMAPConnection.cpp index 6d2a4a4e..b0716f45 100644 --- a/src/net/imap/IMAPConnection.cpp +++ b/src/net/imap/IMAPConnection.cpp @@ -29,16 +29,20 @@ #include "vmime/security/sasl/SASLContext.hpp" #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/tls/TLSSession.hpp" +#endif // VMIME_HAVE_TLS_SUPPORT + #include <sstream> // Helpers for service properties #define GET_PROPERTY(type, prop) \ (m_store->getInfos().getPropertyValue <type>(getSession(), \ - dynamic_cast <const IMAPStore::_infos&>(m_store->getInfos()).getProperties().prop)) + dynamic_cast <const IMAPServiceInfos&>(m_store->getInfos()).getProperties().prop)) #define HAS_PROPERTY(prop) \ (m_store->getInfos().hasProperty(getSession(), \ - dynamic_cast <const IMAPStore::_infos&>(m_store->getInfos()).getProperties().prop)) + dynamic_cast <const IMAPServiceInfos&>(m_store->getInfos()).getProperties().prop)) namespace vmime { @@ -94,6 +98,20 @@ void IMAPConnection::connect() getSocketFactory(GET_PROPERTY(string, PROPERTY_SERVER_SOCKETFACTORY)); m_socket = sf->create(); + +#if VMIME_HAVE_TLS_SUPPORT + if (m_store->isSecuredConnection()) // dedicated port/IMAPS + { + ref <tls::TLSSession> tlsSession = + vmime::create <tls::TLSSession>(m_store->getCertificateVerifier()); + + ref <tls::TLSSocket> tlsSocket = + tlsSession->getSocket(m_socket); + + m_socket = tlsSocket; + } +#endif // VMIME_HAVE_TLS_SUPPORT + m_socket->connect(address, port); @@ -110,6 +128,7 @@ void IMAPConnection::connect() // --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready utility::auto_ptr <IMAPParser::greeting> greet(m_parser->readGreeting()); + bool needAuth = false; if (greet->resp_cond_bye()) { @@ -118,6 +137,47 @@ void IMAPConnection::connect() } else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH) { + needAuth = true; + } + +#if VMIME_HAVE_TLS_SUPPORT + // Setup secured connection, if requested + const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS) + && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS); + const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED) + && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED); + + if (!m_store->isSecuredConnection() && tls) // only if not IMAPS + { + try + { + startTLS(); + } + // Non-fatal error + catch (exceptions::command_error&) + { + if (tlsRequired) + { + m_state = STATE_NONE; + throw; + } + else + { + // TLS is not required, so don't bother + } + } + // Fatal error + catch (...) + { + m_state = STATE_NONE; + throw; + } + } +#endif // VMIME_HAVE_TLS_SUPPORT + + // Authentication + if (needAuth) + { try { authenticate(); @@ -287,17 +347,19 @@ void IMAPConnection::authenticateSASL() respDataList = resp->continue_req_or_response_data(); string response; + bool hasResponse = false; for (unsigned int i = 0 ; i < respDataList.size() ; ++i) { if (respDataList[i]->continue_req()) { response = respDataList[i]->continue_req()->resp_text()->text(); + hasResponse = true; break; } } - if (response.empty()) + if (!hasResponse) { cont = false; continue; @@ -365,6 +427,50 @@ void IMAPConnection::authenticateSASL() #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + +void IMAPConnection::startTLS() +{ + try + { + send(true, "STARTTLS", true); + + utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); + + if (resp->isBad() || resp->response_done()->response_tagged()-> + resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) + { + throw exceptions::command_error + ("STARTTLS", m_parser->lastLine(), "bad response"); + } + + ref <tls::TLSSession> tlsSession = + vmime::create <tls::TLSSession>(m_store->getCertificateVerifier()); + + ref <tls::TLSSocket> tlsSocket = + tlsSession->getSocket(m_socket); + + tlsSocket->handshake(m_timeoutHandler); + + m_socket = tlsSocket; + m_parser->setSocket(m_socket); + } + catch (exceptions::command_error&) + { + // Non-fatal error + throw; + } + catch (exception&) + { + // Fatal error + internalDisconnect(); + throw; + } +} + +#endif // VMIME_HAVE_TLS_SUPPORT + + const std::vector <string> IMAPConnection::getCapabilities() { send(true, "CAPABILITY", true); diff --git a/src/net/imap/IMAPSStore.cpp b/src/net/imap/IMAPSStore.cpp new file mode 100644 index 00000000..ed637c43 --- /dev/null +++ b/src/net/imap/IMAPSStore.cpp @@ -0,0 +1,65 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/imap/IMAPSStore.hpp" + + +namespace vmime { +namespace net { +namespace imap { + + +IMAPSStore::IMAPSStore(ref <session> sess, ref <security::authenticator> auth) + : IMAPStore(sess, auth, true) +{ +} + + +IMAPSStore::~IMAPSStore() +{ +} + + +const string IMAPSStore::getProtocolName() const +{ + return "imaps"; +} + + + +// Service infos + +IMAPServiceInfos IMAPSStore::sm_infos(true); + + +const serviceInfos& IMAPSStore::getInfosInstance() +{ + return sm_infos; +} + + +const serviceInfos& IMAPSStore::getInfos() const +{ + return sm_infos; +} + + +} // imap +} // net +} // vmime diff --git a/src/net/imap/IMAPServiceInfos.cpp b/src/net/imap/IMAPServiceInfos.cpp new file mode 100644 index 00000000..d8164ce1 --- /dev/null +++ b/src/net/imap/IMAPServiceInfos.cpp @@ -0,0 +1,133 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/imap/IMAPServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace imap { + + +IMAPServiceInfos::IMAPServiceInfos(const bool imaps) + : m_imaps(imaps) +{ +} + + +const string IMAPServiceInfos::getPropertyPrefix() const +{ + if (m_imaps) + return "store.imaps."; + else + return "store.imap."; +} + + +const IMAPServiceInfos::props& IMAPServiceInfos::getProperties() const +{ + static props imapProps = + { + // IMAP-specific options +#if VMIME_HAVE_SASL_SUPPORT + property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), + property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"), +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT + property(serviceInfos::property::CONNECTION_TLS), + property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + + property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::SERVER_PORT, "143"), + property(serviceInfos::property::SERVER_SOCKETFACTORY), + + property(serviceInfos::property::TIMEOUT_FACTORY) + }; + + static props imapsProps = + { + // IMAP-specific options +#if VMIME_HAVE_SASL_SUPPORT + property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), + property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"), +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT + property(serviceInfos::property::CONNECTION_TLS), + property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + + property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::SERVER_PORT, "993"), + property(serviceInfos::property::SERVER_SOCKETFACTORY), + + property(serviceInfos::property::TIMEOUT_FACTORY) + }; + + return m_imaps ? imapsProps : imapProps; +} + + +const std::vector <serviceInfos::property> IMAPServiceInfos::getAvailableProperties() const +{ + std::vector <property> list; + const props& p = getProperties(); + + // IMAP-specific options +#if VMIME_HAVE_SASL_SUPPORT + list.push_back(p.PROPERTY_OPTIONS_SASL); + list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + list.push_back(p.PROPERTY_AUTH_USERNAME); + list.push_back(p.PROPERTY_AUTH_PASSWORD); + +#if VMIME_HAVE_TLS_SUPPORT + if (!m_imaps) + { + list.push_back(p.PROPERTY_CONNECTION_TLS); + list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED); + } +#endif // VMIME_HAVE_TLS_SUPPORT + + list.push_back(p.PROPERTY_SERVER_ADDRESS); + list.push_back(p.PROPERTY_SERVER_PORT); + list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY); + + list.push_back(p.PROPERTY_TIMEOUT_FACTORY); + + return list; +} + + +} // imap +} // net +} // vmime + diff --git a/src/net/imap/IMAPStore.cpp b/src/net/imap/IMAPStore.cpp index d4f18e7c..95f96276 100644 --- a/src/net/imap/IMAPStore.cpp +++ b/src/net/imap/IMAPStore.cpp @@ -32,8 +32,8 @@ namespace net { namespace imap { -IMAPStore::IMAPStore(ref <session> sess, ref <security::authenticator> auth) - : store(sess, getInfosInstance(), auth), m_connection(NULL) +IMAPStore::IMAPStore(ref <session> sess, ref <security::authenticator> auth, const bool secured) + : store(sess, getInfosInstance(), auth), m_connection(NULL), m_secured(secured) { } @@ -91,6 +91,12 @@ const bool IMAPStore::isValidFolderName(const folder::path::component& /* name * } +const bool IMAPStore::isSecuredConnection() const +{ + return m_secured; +} + + void IMAPStore::connect() { if (isConnected()) @@ -189,78 +195,21 @@ const int IMAPStore::getCapabilities() const // Service infos -IMAPStore::_infos IMAPStore::sm_infos; +IMAPServiceInfos IMAPStore::sm_infos(false); const serviceInfos& IMAPStore::getInfosInstance() { - return (sm_infos); + return sm_infos; } const serviceInfos& IMAPStore::getInfos() const { - return (sm_infos); -} - - -const string IMAPStore::_infos::getPropertyPrefix() const -{ - return "store.imap."; + return sm_infos; } -const IMAPStore::_infos::props& IMAPStore::_infos::getProperties() const -{ - static props p = - { - // IMAP-specific options -#if VMIME_HAVE_SASL_SUPPORT - property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), - property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"), -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), - - property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::SERVER_PORT, "143"), - property(serviceInfos::property::SERVER_SOCKETFACTORY), - - property(serviceInfos::property::TIMEOUT_FACTORY) - }; - - return p; -} - - -const std::vector <serviceInfos::property> IMAPStore::_infos::getAvailableProperties() const -{ - std::vector <property> list; - const props& p = getProperties(); - - // IMAP-specific options -#if VMIME_HAVE_SASL_SUPPORT - list.push_back(p.PROPERTY_OPTIONS_SASL); - list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - list.push_back(p.PROPERTY_AUTH_USERNAME); - list.push_back(p.PROPERTY_AUTH_PASSWORD); - - list.push_back(p.PROPERTY_SERVER_ADDRESS); - list.push_back(p.PROPERTY_SERVER_PORT); - list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY); - - list.push_back(p.PROPERTY_TIMEOUT_FACTORY); - - return (list); -} - - - } // imap } // net } // vmime diff --git a/src/net/maildir/maildirServiceInfos.cpp b/src/net/maildir/maildirServiceInfos.cpp new file mode 100644 index 00000000..f6487103 --- /dev/null +++ b/src/net/maildir/maildirServiceInfos.cpp @@ -0,0 +1,64 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/maildir/maildirServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirServiceInfos::maildirServiceInfos() +{ +} + + +const string maildirServiceInfos::getPropertyPrefix() const +{ + return "store.maildir."; +} + + +const maildirServiceInfos::props& maildirServiceInfos::getProperties() const +{ + static props maildirProps = + { + property(serviceInfos::property::SERVER_ROOTPATH, serviceInfos::property::FLAG_REQUIRED) + }; + + return maildirProps; +} + + +const std::vector <serviceInfos::property> maildirServiceInfos::getAvailableProperties() const +{ + std::vector <property> list; + const props& p = getProperties(); + + list.push_back(p.PROPERTY_SERVER_ROOTPATH); + + return list; +} + + +} // maildir +} // net +} // vmime + diff --git a/src/net/maildir/maildirStore.cpp b/src/net/maildir/maildirStore.cpp index bbb95624..d1baf8dd 100644 --- a/src/net/maildir/maildirStore.cpp +++ b/src/net/maildir/maildirStore.cpp @@ -29,9 +29,11 @@ // Helpers for service properties #define GET_PROPERTY(type, prop) \ - (sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop)) + (getInfos().getPropertyValue <type>(getSession(), \ + dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop)) #define HAS_PROPERTY(prop) \ - (sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop)) + (getInfos().hasProperty(getSession(), \ + dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop)) namespace vmime { @@ -205,50 +207,20 @@ const int maildirStore::getCapabilities() const - // Service infos -maildirStore::_infos maildirStore::sm_infos; +maildirServiceInfos maildirStore::sm_infos; const serviceInfos& maildirStore::getInfosInstance() { - return (sm_infos); + return sm_infos; } const serviceInfos& maildirStore::getInfos() const { - return (sm_infos); -} - - -const string maildirStore::_infos::getPropertyPrefix() const -{ - return "store.maildir."; -} - - -const maildirStore::_infos::props& maildirStore::_infos::getProperties() const -{ - static props p = - { - property(serviceInfos::property::SERVER_ROOTPATH, serviceInfos::property::FLAG_REQUIRED) - }; - - return p; -} - - -const std::vector <serviceInfos::property> maildirStore::_infos::getAvailableProperties() const -{ - std::vector <property> list; - const props& p = getProperties(); - - // Maildir-specific properties - list.push_back(p.PROPERTY_SERVER_ROOTPATH); - - return (list); + return sm_infos; } diff --git a/src/net/pop3/POP3SStore.cpp b/src/net/pop3/POP3SStore.cpp new file mode 100644 index 00000000..760ddd86 --- /dev/null +++ b/src/net/pop3/POP3SStore.cpp @@ -0,0 +1,66 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/pop3/POP3SStore.hpp" + + +namespace vmime { +namespace net { +namespace pop3 { + + +POP3SStore::POP3SStore(ref <session> sess, ref <security::authenticator> auth) + : POP3Store(sess, auth, true) +{ +} + + +POP3SStore::~POP3SStore() +{ +} + + +const string POP3SStore::getProtocolName() const +{ + return "pop3s"; +} + + + +// Service infos + +POP3ServiceInfos POP3SStore::sm_infos(true); + + +const serviceInfos& POP3SStore::getInfosInstance() +{ + return sm_infos; +} + + +const serviceInfos& POP3SStore::getInfos() const +{ + return sm_infos; +} + + +} // pop3 +} // net +} // vmime + diff --git a/src/net/pop3/POP3ServiceInfos.cpp b/src/net/pop3/POP3ServiceInfos.cpp new file mode 100644 index 00000000..52387c5d --- /dev/null +++ b/src/net/pop3/POP3ServiceInfos.cpp @@ -0,0 +1,139 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/pop3/POP3ServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace pop3 { + + +POP3ServiceInfos::POP3ServiceInfos(const bool pop3s) + : m_pop3s(pop3s) +{ +} + + +const string POP3ServiceInfos::getPropertyPrefix() const +{ + if (m_pop3s) + return "store.pop3s."; + else + return "store.pop3."; +} + + +const POP3ServiceInfos::props& POP3ServiceInfos::getProperties() const +{ + static props pop3Props = + { + // POP3-specific options + property("options.apop", serviceInfos::property::TYPE_BOOL, "true"), + property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "true"), +#if VMIME_HAVE_SASL_SUPPORT + property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), + property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"), +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT + property(serviceInfos::property::CONNECTION_TLS), + property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + + property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::SERVER_PORT, "110"), + property(serviceInfos::property::SERVER_SOCKETFACTORY), + + property(serviceInfos::property::TIMEOUT_FACTORY) + }; + + static props pop3sProps = + { + // POP3-specific options + property("options.apop", serviceInfos::property::TYPE_BOOL, "true"), + property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "true"), +#if VMIME_HAVE_SASL_SUPPORT + property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), + property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"), +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT + property(serviceInfos::property::CONNECTION_TLS), + property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + + property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::SERVER_PORT, "995"), + property(serviceInfos::property::SERVER_SOCKETFACTORY), + + property(serviceInfos::property::TIMEOUT_FACTORY) + }; + + return m_pop3s ? pop3sProps : pop3Props; +} + + +const std::vector <serviceInfos::property> POP3ServiceInfos::getAvailableProperties() const +{ + std::vector <property> list; + const props& p = getProperties(); + + // POP3-specific options + list.push_back(p.PROPERTY_OPTIONS_APOP); + list.push_back(p.PROPERTY_OPTIONS_APOP_FALLBACK); +#if VMIME_HAVE_SASL_SUPPORT + list.push_back(p.PROPERTY_OPTIONS_SASL); + list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + list.push_back(p.PROPERTY_AUTH_USERNAME); + list.push_back(p.PROPERTY_AUTH_PASSWORD); + +#if VMIME_HAVE_TLS_SUPPORT + if (!m_pop3s) + { + list.push_back(p.PROPERTY_CONNECTION_TLS); + list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED); + } +#endif // VMIME_HAVE_TLS_SUPPORT + + list.push_back(p.PROPERTY_SERVER_ADDRESS); + list.push_back(p.PROPERTY_SERVER_PORT); + list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY); + + list.push_back(p.PROPERTY_TIMEOUT_FACTORY); + + return list; +} + + +} // pop3 +} // net +} // vmime + diff --git a/src/net/pop3/POP3Store.cpp b/src/net/pop3/POP3Store.cpp index cabd81f0..4f373268 100644 --- a/src/net/pop3/POP3Store.cpp +++ b/src/net/pop3/POP3Store.cpp @@ -31,14 +31,20 @@ #include "vmime/security/sasl/SASLContext.hpp" #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/tls/TLSSession.hpp" +#endif // VMIME_HAVE_TLS_SUPPORT + #include <algorithm> // Helpers for service properties #define GET_PROPERTY(type, prop) \ - (sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop)) + (getInfos().getPropertyValue <type>(getSession(), \ + dynamic_cast <const POP3ServiceInfos&>(getInfos()).getProperties().prop)) #define HAS_PROPERTY(prop) \ - (sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop)) + (getInfos().hasProperty(getSession(), \ + dynamic_cast <const POP3ServiceInfos&>(getInfos()).getProperties().prop)) namespace vmime { @@ -46,9 +52,9 @@ namespace net { namespace pop3 { -POP3Store::POP3Store(ref <session> sess, ref <security::authenticator> auth) +POP3Store::POP3Store(ref <session> sess, ref <security::authenticator> auth, const bool secured) : store(sess, getInfosInstance(), auth), m_socket(NULL), - m_authentified(false), m_timeoutHandler(NULL) + m_authentified(false), m_timeoutHandler(NULL), m_secured(secured) { } @@ -130,6 +136,20 @@ void POP3Store::connect() getSocketFactory(GET_PROPERTY(string, PROPERTY_SERVER_SOCKETFACTORY)); m_socket = sf->create(); + +#if VMIME_HAVE_TLS_SUPPORT + if (m_secured) // dedicated port/POP3S + { + ref <tls::TLSSession> tlsSession = + vmime::create <tls::TLSSession>(getCertificateVerifier()); + + ref <tls::TLSSocket> tlsSocket = + tlsSession->getSocket(m_socket); + + m_socket = tlsSocket; + } +#endif // VMIME_HAVE_TLS_SUPPORT + m_socket->connect(address, port); // Connection @@ -146,6 +166,39 @@ void POP3Store::connect() throw exceptions::connection_greeting_error(response); } +#if VMIME_HAVE_TLS_SUPPORT + // Setup secured connection, if requested + const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS) + && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS); + const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED) + && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED); + + if (!m_secured && tls) // only if not POP3S + { + try + { + startTLS(); + } + // Non-fatal error + catch (exceptions::command_error&) + { + if (tlsRequired) + { + throw; + } + else + { + // TLS is not required, so don't bother + } + } + // Fatal error + catch (...) + { + throw; + } + } +#endif // VMIME_HAVE_TLS_SUPPORT + // Start authentication process authenticate(messageId(response)); } @@ -235,6 +288,18 @@ void POP3Store::authenticate(const messageId& randomMID) internalDisconnect(); throw exceptions::authentication_error(response); } + + // Ensure connection is valid (cf. note above) + try + { + string response2; + sendRequest("NOOP"); + readResponse(response2, false); + } + catch (exceptions::socket_exception&) + { + throw exceptions::authentication_error(response); + } } } else @@ -453,6 +518,46 @@ void POP3Store::authenticateSASL() #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + +void POP3Store::startTLS() +{ + try + { + sendRequest("STLS"); + + string response; + readResponse(response, false); + + if (getResponseCode(response) != RESPONSE_OK) + throw exceptions::command_error("STLS", response); + + ref <tls::TLSSession> tlsSession = + vmime::create <tls::TLSSession>(getCertificateVerifier()); + + ref <tls::TLSSocket> tlsSocket = + tlsSession->getSocket(m_socket); + + tlsSocket->handshake(m_timeoutHandler); + + m_socket = tlsSocket; + } + catch (exceptions::command_error&) + { + // Non-fatal error + throw; + } + catch (exception&) + { + // Fatal error + internalDisconnect(); + throw; + } +} + +#endif // VMIME_HAVE_TLS_SUPPORT + + const bool POP3Store::isConnected() const { return (m_socket && m_socket->isConnected() && m_authentified); @@ -478,8 +583,14 @@ void POP3Store::internalDisconnect() m_folders.clear(); - - sendRequest("QUIT"); + try + { + sendRequest("QUIT"); + } + catch (exception&) + { + // Not important + } m_socket->disconnect(); m_socket = NULL; @@ -627,6 +738,8 @@ void POP3Store::readResponse(string& buffer, const bool multiLine, { if (!m_timeoutHandler->handleTimeOut()) throw exceptions::operation_timed_out(); + + m_timeoutHandler->resetTimeOut(); } // Receive data from the socket @@ -844,78 +957,18 @@ const int POP3Store::getCapabilities() const // Service infos -POP3Store::_infos POP3Store::sm_infos; +POP3ServiceInfos POP3Store::sm_infos(false); const serviceInfos& POP3Store::getInfosInstance() { - return (sm_infos); + return sm_infos; } const serviceInfos& POP3Store::getInfos() const { - return (sm_infos); -} - - -const string POP3Store::_infos::getPropertyPrefix() const -{ - return "store.pop3."; -} - - -const POP3Store::_infos::props& POP3Store::_infos::getProperties() const -{ - static props p = - { - // POP3-specific options - property("options.apop", serviceInfos::property::TYPE_BOOL, "true"), - property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "true"), -#if VMIME_HAVE_SASL_SUPPORT - property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), - property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"), -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), - - property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::SERVER_PORT, "110"), - property(serviceInfos::property::SERVER_SOCKETFACTORY), - - property(serviceInfos::property::TIMEOUT_FACTORY) - }; - - return p; -} - - -const std::vector <serviceInfos::property> POP3Store::_infos::getAvailableProperties() const -{ - std::vector <property> list; - const props& p = getProperties(); - - // POP3-specific options - list.push_back(p.PROPERTY_OPTIONS_APOP); - list.push_back(p.PROPERTY_OPTIONS_APOP_FALLBACK); -#if VMIME_HAVE_SASL_SUPPORT - list.push_back(p.PROPERTY_OPTIONS_SASL); - list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - list.push_back(p.PROPERTY_AUTH_USERNAME); - list.push_back(p.PROPERTY_AUTH_PASSWORD); - - list.push_back(p.PROPERTY_SERVER_ADDRESS); - list.push_back(p.PROPERTY_SERVER_PORT); - list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY); - - list.push_back(p.PROPERTY_TIMEOUT_FACTORY); - - return (list); + return sm_infos; } diff --git a/src/net/sendmail/sendmailServiceInfos.cpp b/src/net/sendmail/sendmailServiceInfos.cpp new file mode 100644 index 00000000..f0f2fa59 --- /dev/null +++ b/src/net/sendmail/sendmailServiceInfos.cpp @@ -0,0 +1,65 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/sendmail/sendmailServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace sendmail { + + +sendmailServiceInfos::sendmailServiceInfos() +{ +} + + +const string sendmailServiceInfos::getPropertyPrefix() const +{ + return "transport.sendmail."; +} + + +const sendmailServiceInfos::props& sendmailServiceInfos::getProperties() const +{ + static props sendmailProps = + { + // Path to sendmail (override default) + property("binpath", serviceInfos::property::TYPE_STRING, string(VMIME_SENDMAIL_PATH)) + }; + + return sendmailProps; +} + + +const std::vector <serviceInfos::property> sendmailServiceInfos::getAvailableProperties() const +{ + std::vector <property> list; + const props& p = getProperties(); + + list.push_back(p.PROPERTY_BINPATH); + + return list; +} + + +} // sendmail +} // net +} // vmime + diff --git a/src/net/sendmail/sendmailTransport.cpp b/src/net/sendmail/sendmailTransport.cpp index 4a077465..853f4eec 100644 --- a/src/net/sendmail/sendmailTransport.cpp +++ b/src/net/sendmail/sendmailTransport.cpp @@ -33,9 +33,11 @@ // Helpers for service properties #define GET_PROPERTY(type, prop) \ - (sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop)) + (getInfos().getPropertyValue <type>(getSession(), \ + dynamic_cast <const sendmailServiceInfos&>(getInfos()).getProperties().prop)) #define HAS_PROPERTY(prop) \ - (sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop)) + (getInfos().hasProperty(getSession(), \ + dynamic_cast <const sendmailServiceInfos&>(getInfos()).getProperties().prop)) #if VMIME_BUILTIN_PLATFORM_POSIX @@ -177,47 +179,18 @@ void sendmailTransport::internalSend // Service infos -sendmailTransport::_infos sendmailTransport::sm_infos; +sendmailServiceInfos sendmailTransport::sm_infos; const serviceInfos& sendmailTransport::getInfosInstance() { - return (sm_infos); + return sm_infos; } const serviceInfos& sendmailTransport::getInfos() const { - return (sm_infos); -} - - -const string sendmailTransport::_infos::getPropertyPrefix() const -{ - return "transport.sendmail."; -} - - -const sendmailTransport::_infos::props& sendmailTransport::_infos::getProperties() const -{ - static props p = - { - // Path to sendmail (override default) - property("binpath", serviceInfos::property::TYPE_STRING, string(VMIME_SENDMAIL_PATH)) - }; - - return p; -} - - -const std::vector <serviceInfos::property> sendmailTransport::_infos::getAvailableProperties() const -{ - std::vector <property> list; - const props& p = getProperties(); - - list.push_back(p.PROPERTY_BINPATH); - - return (list); + return sm_infos; } diff --git a/src/net/service.cpp b/src/net/service.cpp index acdfb390..35e8aa55 100644 --- a/src/net/service.cpp +++ b/src/net/service.cpp @@ -26,6 +26,10 @@ #include "vmime/security/defaultAuthenticator.hpp" #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/tls/defaultCertificateVerifier.hpp" +#endif // VMIME_HAVE_TLS_SUPPORT + namespace vmime { namespace net { @@ -45,6 +49,11 @@ service::service(ref <session> sess, const serviceInfos& /* infos */, <security::defaultAuthenticator>(); #endif // VMIME_HAVE_SASL_SUPPORT } + +#if VMIME_HAVE_TLS_SUPPORT + m_certVerifier = vmime::create <tls::defaultCertificateVerifier>(); +#endif // VMIME_HAVE_TLS_SUPPORT + } @@ -83,5 +92,21 @@ void service::setAuthenticator(ref <security::authenticator> auth) } +#if VMIME_HAVE_TLS_SUPPORT + +void service::setCertificateVerifier(ref <tls::certificateVerifier> cv) +{ + m_certVerifier = cv; +} + + +ref <tls::certificateVerifier> service::getCertificateVerifier() +{ + return m_certVerifier; +} + +#endif // VMIME_HAVE_TLS_SUPPORT + + } // net } // vmime diff --git a/src/net/serviceInfos.cpp b/src/net/serviceInfos.cpp index 68d78c73..306c1ec3 100644 --- a/src/net/serviceInfos.cpp +++ b/src/net/serviceInfos.cpp @@ -46,6 +46,16 @@ const serviceInfos::property serviceInfos::property::AUTH_PASSWORD const serviceInfos::property serviceInfos::property::TIMEOUT_FACTORY ("timeout.factory", serviceInfos::property::TYPE_STRING); +#if VMIME_HAVE_TLS_SUPPORT + +const serviceInfos::property serviceInfos::property::CONNECTION_TLS + ("connection.tls", serviceInfos::property::TYPE_BOOL, "false"); + +const serviceInfos::property serviceInfos::property::CONNECTION_TLS_REQUIRED + ("connection.tls.required", serviceInfos::property::TYPE_BOOL, "false"); + +#endif // VMIME_HAVE_TLS_SUPPORT + // serviceInfos diff --git a/src/net/smtp/SMTPSTransport.cpp b/src/net/smtp/SMTPSTransport.cpp new file mode 100644 index 00000000..22bf4e4b --- /dev/null +++ b/src/net/smtp/SMTPSTransport.cpp @@ -0,0 +1,66 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/smtp/SMTPSTransport.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPSTransport::SMTPSTransport(ref <session> sess, ref <security::authenticator> auth) + : SMTPTransport(sess, auth, true) +{ +} + + +SMTPSTransport::~SMTPSTransport() +{ +} + + +const string SMTPSTransport::getProtocolName() const +{ + return "smtps"; +} + + + +// Service infos + +SMTPServiceInfos SMTPSTransport::sm_infos(true); + + +const serviceInfos& SMTPSTransport::getInfosInstance() +{ + return sm_infos; +} + + +const serviceInfos& SMTPSTransport::getInfos() const +{ + return sm_infos; +} + + +} // smtp +} // net +} // vmime + diff --git a/src/net/smtp/SMTPServiceInfos.cpp b/src/net/smtp/SMTPServiceInfos.cpp new file mode 100644 index 00000000..1f0bca6c --- /dev/null +++ b/src/net/smtp/SMTPServiceInfos.cpp @@ -0,0 +1,136 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 along +// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. +// + +#include "vmime/net/smtp/SMTPServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPServiceInfos::SMTPServiceInfos(const bool smtps) + : m_smtps(smtps) +{ +} + + +const string SMTPServiceInfos::getPropertyPrefix() const +{ + if (m_smtps) + return "transport.smtps."; + else + return "transport.smtp."; +} + + +const SMTPServiceInfos::props& SMTPServiceInfos::getProperties() const +{ + static props smtpProps = + { + // SMTP-specific options + property("options.need-authentication", serviceInfos::property::TYPE_BOOL, "false"), +#if VMIME_HAVE_SASL_SUPPORT + property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), + property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "false"), +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT + property(serviceInfos::property::CONNECTION_TLS), + property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + + property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::SERVER_PORT, "25"), + property(serviceInfos::property::SERVER_SOCKETFACTORY), + + property(serviceInfos::property::TIMEOUT_FACTORY) + }; + + static props smtpsProps = + { + // SMTP-specific options + property("options.need-authentication", serviceInfos::property::TYPE_BOOL, "false"), +#if VMIME_HAVE_SASL_SUPPORT + property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), + property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "false"), +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT + property(serviceInfos::property::CONNECTION_TLS), + property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + + property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), + property(serviceInfos::property::SERVER_PORT, "465"), + property(serviceInfos::property::SERVER_SOCKETFACTORY), + + property(serviceInfos::property::TIMEOUT_FACTORY) + }; + + return m_smtps ? smtpsProps : smtpProps; +} + + +const std::vector <serviceInfos::property> SMTPServiceInfos::getAvailableProperties() const +{ + std::vector <property> list; + const props& p = getProperties(); + + // SMTP-specific options + list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH); +#if VMIME_HAVE_SASL_SUPPORT + list.push_back(p.PROPERTY_OPTIONS_SASL); + list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); +#endif // VMIME_HAVE_SASL_SUPPORT + + // Common properties + list.push_back(p.PROPERTY_AUTH_USERNAME); + list.push_back(p.PROPERTY_AUTH_PASSWORD); + +#if VMIME_HAVE_TLS_SUPPORT + if (!m_smtps) + { + list.push_back(p.PROPERTY_CONNECTION_TLS); + list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED); + } +#endif // VMIME_HAVE_TLS_SUPPORT + + list.push_back(p.PROPERTY_SERVER_ADDRESS); + list.push_back(p.PROPERTY_SERVER_PORT); + list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY); + + list.push_back(p.PROPERTY_TIMEOUT_FACTORY); + + return list; +} + + +} // smtp +} // net +} // vmime + diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index 1aa15c13..d0c72a13 100644 --- a/src/net/smtp/SMTPTransport.cpp +++ b/src/net/smtp/SMTPTransport.cpp @@ -24,8 +24,6 @@ #include "vmime/encoderB64.hpp" #include "vmime/mailboxList.hpp" -#include "vmime/net/authHelper.hpp" - #include "vmime/utility/filteredStream.hpp" #include "vmime/utility/stringUtils.hpp" @@ -33,12 +31,18 @@ #include "vmime/security/sasl/SASLContext.hpp" #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + #include "vmime/net/tls/TLSSession.hpp" +#endif // VMIME_HAVE_TLS_SUPPORT + // Helpers for service properties #define GET_PROPERTY(type, prop) \ - (sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop)) + (getInfos().getPropertyValue <type>(getSession(), \ + dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().prop)) #define HAS_PROPERTY(prop) \ - (sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop)) + (getInfos().hasProperty(getSession(), \ + dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().prop)) namespace vmime { @@ -46,9 +50,10 @@ namespace net { namespace smtp { -SMTPTransport::SMTPTransport(ref <session> sess, ref <security::authenticator> auth) +SMTPTransport::SMTPTransport(ref <session> sess, ref <security::authenticator> auth, const bool secured) : transport(sess, getInfosInstance(), auth), m_socket(NULL), - m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL) + m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL), + m_secured(secured) { } @@ -97,6 +102,20 @@ void SMTPTransport::connect() getSocketFactory(GET_PROPERTY(string, PROPERTY_SERVER_SOCKETFACTORY)); m_socket = sf->create(); + +#if VMIME_HAVE_TLS_SUPPORT + if (m_secured) // dedicated port/SMTPS + { + ref <tls::TLSSession> tlsSession = + vmime::create <tls::TLSSession>(getCertificateVerifier()); + + ref <tls::TLSSocket> tlsSocket = + tlsSession->getSocket(m_socket); + + m_socket = tlsSocket; + } +#endif // VMIME_HAVE_TLS_SUPPORT + m_socket->connect(address, port); m_responseBuffer.clear(); @@ -146,6 +165,39 @@ void SMTPTransport::connect() m_extendedSMTPResponse = response; } +#if VMIME_HAVE_TLS_SUPPORT + // Setup secured connection, if requested + const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS) + && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS); + const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED) + && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED); + + if (!m_secured && tls) // only if not POP3S + { + try + { + startTLS(); + } + // Non-fatal error + catch (exceptions::command_error&) + { + if (tlsRequired) + { + throw; + } + else + { + // TLS is not required, so don't bother + } + } + // Fatal error + catch (...) + { + throw; + } + } +#endif // VMIME_HAVE_TLS_SUPPORT + // Authentication if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH)) authenticate(); @@ -369,6 +421,45 @@ void SMTPTransport::authenticateSASL() #endif // VMIME_HAVE_SASL_SUPPORT +#if VMIME_HAVE_TLS_SUPPORT + +void SMTPTransport::startTLS() +{ + try + { + sendRequest("STARTTLS"); + + string response; + + if (readAllResponses(response) != 220) + throw exceptions::command_error("STARTTLS", response); + + ref <tls::TLSSession> tlsSession = + vmime::create <tls::TLSSession>(getCertificateVerifier()); + + ref <tls::TLSSocket> tlsSocket = + tlsSession->getSocket(m_socket); + + tlsSocket->handshake(m_timeoutHandler); + + m_socket = tlsSocket; + } + catch (exceptions::command_error&) + { + // Non-fatal error + throw; + } + catch (exception&) + { + // Fatal error + internalDisconnect(); + throw; + } +} + +#endif // VMIME_HAVE_TLS_SUPPORT + + const bool SMTPTransport::isConnected() const { return (m_socket && m_socket->isConnected() && m_authentified); @@ -516,6 +607,8 @@ const string SMTPTransport::readResponseLine() { if (!m_timeoutHandler->handleTimeOut()) throw exceptions::operation_timed_out(); + + m_timeoutHandler->resetTimeOut(); } // Receive data from the socket @@ -589,76 +682,18 @@ const int SMTPTransport::readAllResponses(string& outText, const bool allText) // Service infos -SMTPTransport::_infos SMTPTransport::sm_infos; +SMTPServiceInfos SMTPTransport::sm_infos(false); const serviceInfos& SMTPTransport::getInfosInstance() { - return (sm_infos); + return sm_infos; } const serviceInfos& SMTPTransport::getInfos() const { - return (sm_infos); -} - - -const string SMTPTransport::_infos::getPropertyPrefix() const -{ - return "transport.smtp."; -} - - -const SMTPTransport::_infos::props& SMTPTransport::_infos::getProperties() const -{ - static props p = - { - // SMTP-specific options - property("options.need-authentication", serviceInfos::property::TYPE_BOOL, "false"), -#if VMIME_HAVE_SASL_SUPPORT - property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"), - property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "false"), -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - property(serviceInfos::property::AUTH_USERNAME), - property(serviceInfos::property::AUTH_PASSWORD), - - property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), - property(serviceInfos::property::SERVER_PORT, "25"), - property(serviceInfos::property::SERVER_SOCKETFACTORY), - - property(serviceInfos::property::TIMEOUT_FACTORY) - }; - - return p; -} - - -const std::vector <serviceInfos::property> SMTPTransport::_infos::getAvailableProperties() const -{ - std::vector <property> list; - const props& p = getProperties(); - - // SMTP-specific options - list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH); -#if VMIME_HAVE_SASL_SUPPORT - list.push_back(p.PROPERTY_OPTIONS_SASL); - list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); -#endif // VMIME_HAVE_SASL_SUPPORT - - // Common properties - list.push_back(p.PROPERTY_AUTH_USERNAME); - list.push_back(p.PROPERTY_AUTH_PASSWORD); - - list.push_back(p.PROPERTY_SERVER_ADDRESS); - list.push_back(p.PROPERTY_SERVER_PORT); - list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY); - - list.push_back(p.PROPERTY_TIMEOUT_FACTORY); - - return (list); + return sm_infos; } diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp new file mode 100644 index 00000000..fb84714c --- /dev/null +++ b/src/net/tls/TLSSession.cpp @@ -0,0 +1,342 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 <gnutls/gnutls.h> +#include <gnutls/extra.h> + +#include "vmime/net/tls/TLSSession.hpp" + +#include "vmime/exception.hpp" + + +// Enable GnuTLS debugging by defining GNUTLS_DEBUG +//#define GNUTLS_DEBUG 1 + + +#if VMIME_DEBUG && GNUTLS_DEBUG + #include <iostream> +#endif // VMIME_DEBUG && GNUTLS_DEBUG + + +namespace vmime { +namespace net { +namespace tls { + + +#ifndef VMIME_BUILDING_DOC + +// Initialize GNU TLS library +struct TLSGlobal +{ + TLSGlobal() + { + 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 + + + +TLSSession::TLSSession(ref <certificateVerifier> cv) + : m_certVerifier(cv) +{ + 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. + 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); + + // 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::TLSSession(const TLSSession&) + : object() +{ + // Not used +} + + +TLSSession::~TLSSession() +{ + if (m_gnutlsSession) + { + gnutls_deinit(*m_gnutlsSession); + + delete m_gnutlsSession; + m_gnutlsSession = NULL; + } +} + + +ref <TLSSocket> TLSSession::getSocket(ref <socket> sok) +{ + return vmime::create <TLSSocket> + (thisRef().dynamicCast <TLSSession>(), sok); +} + + +ref <tls::certificateVerifier> TLSSession::getCertificateVerifier() +{ + return m_certVerifier; +} + + +void TLSSession::throwTLSException(const string& fname, const int code) +{ + string msg = fname + "() returned "; + +#define ERROR(x) \ + case x: msg += #x; break; + + switch (code) + { + ERROR(GNUTLS_E_SUCCESS) + ERROR(GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM) + ERROR(GNUTLS_E_UNKNOWN_CIPHER_TYPE) + ERROR(GNUTLS_E_LARGE_PACKET) + ERROR(GNUTLS_E_UNSUPPORTED_VERSION_PACKET) + ERROR(GNUTLS_E_UNEXPECTED_PACKET_LENGTH) + ERROR(GNUTLS_E_INVALID_SESSION) + ERROR(GNUTLS_E_FATAL_ALERT_RECEIVED) + ERROR(GNUTLS_E_UNEXPECTED_PACKET) + ERROR(GNUTLS_E_WARNING_ALERT_RECEIVED) + ERROR(GNUTLS_E_ERROR_IN_FINISHED_PACKET) + ERROR(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) + ERROR(GNUTLS_E_UNKNOWN_CIPHER_SUITE) + ERROR(GNUTLS_E_UNWANTED_ALGORITHM) + ERROR(GNUTLS_E_MPI_SCAN_FAILED) + ERROR(GNUTLS_E_DECRYPTION_FAILED) + ERROR(GNUTLS_E_MEMORY_ERROR) + ERROR(GNUTLS_E_DECOMPRESSION_FAILED) + ERROR(GNUTLS_E_COMPRESSION_FAILED) + ERROR(GNUTLS_E_AGAIN) + ERROR(GNUTLS_E_EXPIRED) + ERROR(GNUTLS_E_DB_ERROR) + ERROR(GNUTLS_E_SRP_PWD_ERROR) + ERROR(GNUTLS_E_INSUFFICIENT_CREDENTIALS) + ERROR(GNUTLS_E_HASH_FAILED) + ERROR(GNUTLS_E_BASE64_DECODING_ERROR) + ERROR(GNUTLS_E_MPI_PRINT_FAILED) + ERROR(GNUTLS_E_REHANDSHAKE) + ERROR(GNUTLS_E_GOT_APPLICATION_DATA) + ERROR(GNUTLS_E_RECORD_LIMIT_REACHED) + ERROR(GNUTLS_E_ENCRYPTION_FAILED) + ERROR(GNUTLS_E_PK_ENCRYPTION_FAILED) + ERROR(GNUTLS_E_PK_DECRYPTION_FAILED) + ERROR(GNUTLS_E_PK_SIGN_FAILED) + ERROR(GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION) + ERROR(GNUTLS_E_KEY_USAGE_VIOLATION) + ERROR(GNUTLS_E_NO_CERTIFICATE_FOUND) + ERROR(GNUTLS_E_INVALID_REQUEST) + ERROR(GNUTLS_E_SHORT_MEMORY_BUFFER) + ERROR(GNUTLS_E_INTERRUPTED) + ERROR(GNUTLS_E_PUSH_ERROR) + ERROR(GNUTLS_E_PULL_ERROR) + ERROR(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER) + ERROR(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + ERROR(GNUTLS_E_PKCS1_WRONG_PAD) + ERROR(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION) + ERROR(GNUTLS_E_INTERNAL_ERROR) + ERROR(GNUTLS_E_DH_PRIME_UNACCEPTABLE) + ERROR(GNUTLS_E_FILE_ERROR) + ERROR(GNUTLS_E_TOO_MANY_EMPTY_PACKETS) + ERROR(GNUTLS_E_UNKNOWN_PK_ALGORITHM) + ERROR(GNUTLS_E_INIT_LIBEXTRA) + ERROR(GNUTLS_E_LIBRARY_VERSION_MISMATCH) + ERROR(GNUTLS_E_NO_TEMPORARY_RSA_PARAMS) + ERROR(GNUTLS_E_LZO_INIT_FAILED) + ERROR(GNUTLS_E_NO_COMPRESSION_ALGORITHMS) + ERROR(GNUTLS_E_NO_CIPHER_SUITES) + ERROR(GNUTLS_E_OPENPGP_GETKEY_FAILED) + ERROR(GNUTLS_E_PK_SIG_VERIFY_FAILED) + ERROR(GNUTLS_E_ILLEGAL_SRP_USERNAME) + ERROR(GNUTLS_E_SRP_PWD_PARSING_ERROR) + ERROR(GNUTLS_E_NO_TEMPORARY_DH_PARAMS) + ERROR(GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) + ERROR(GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND) + ERROR(GNUTLS_E_ASN1_DER_ERROR) + ERROR(GNUTLS_E_ASN1_VALUE_NOT_FOUND) + ERROR(GNUTLS_E_ASN1_GENERIC_ERROR) + ERROR(GNUTLS_E_ASN1_VALUE_NOT_VALID) + ERROR(GNUTLS_E_ASN1_TAG_ERROR) + ERROR(GNUTLS_E_ASN1_TAG_IMPLICIT) + ERROR(GNUTLS_E_ASN1_TYPE_ANY_ERROR) + ERROR(GNUTLS_E_ASN1_SYNTAX_ERROR) + ERROR(GNUTLS_E_ASN1_DER_OVERFLOW) + ERROR(GNUTLS_E_OPENPGP_TRUSTDB_VERSION_UNSUPPORTED) + ERROR(GNUTLS_E_OPENPGP_UID_REVOKED) + ERROR(GNUTLS_E_CERTIFICATE_ERROR) + //ERROR(GNUTLS_E_X509_CERTIFICATE_ERROR) + ERROR(GNUTLS_E_CERTIFICATE_KEY_MISMATCH) + ERROR(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE) + ERROR(GNUTLS_E_X509_UNKNOWN_SAN) + ERROR(GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED) + ERROR(GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE) + ERROR(GNUTLS_E_UNKNOWN_HASH_ALGORITHM) + ERROR(GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE) + ERROR(GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE) + ERROR(GNUTLS_E_INVALID_PASSWORD) + ERROR(GNUTLS_E_MAC_VERIFY_FAILED) + ERROR(GNUTLS_E_CONSTRAINT_ERROR) + ERROR(GNUTLS_E_BASE64_ENCODING_ERROR) + ERROR(GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY) + //ERROR(GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY) + ERROR(GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY) + ERROR(GNUTLS_E_OPENPGP_KEYRING_ERROR) + ERROR(GNUTLS_E_X509_UNSUPPORTED_OID) + //ERROR(GNUTLS_E_RANDOM_FAILED) + ERROR(GNUTLS_E_UNIMPLEMENTED_FEATURE) + + default: + + msg += "unknown error"; + break; + } + +#undef ERROR + + throw exceptions::tls_exception(msg); +} + + +} // tls +} // net +} // vmime + diff --git a/src/net/tls/TLSSocket.cpp b/src/net/tls/TLSSocket.cpp new file mode 100644 index 00000000..ebf3214b --- /dev/null +++ b/src/net/tls/TLSSocket.cpp @@ -0,0 +1,391 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include "vmime/net/tls/TLSSocket.hpp" +#include "vmime/net/tls/TLSSession.hpp" + +#include "vmime/platformDependant.hpp" + +#include "vmime/net/tls/X509Certificate.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +TLSSocket::TLSSocket(ref <TLSSession> session, ref <socket> sok) + : m_session(session), m_wrapped(sok), m_connected(false), + m_handshaking(false), m_ex(NULL) +{ + 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::~TLSSocket() +{ + try + { + disconnect(); + } + catch (...) + { + // Don't throw exception in destructor + } +} + + +void TLSSocket::connect(const string& address, const port_t port) +{ + m_wrapped->connect(address, port); + + handshake(NULL); + + m_connected = true; +} + + +void TLSSocket::disconnect() +{ + if (m_connected) + { + gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR); + + m_wrapped->disconnect(); + + m_connected = false; + } +} + + +const bool TLSSocket::isConnected() const +{ + return m_wrapped->isConnected() && m_connected; +} + + +void TLSSocket::receive(string& buffer) +{ + const int size = receiveRaw(m_buffer, sizeof(m_buffer)); + buffer = vmime::string(m_buffer, size); +} + + +void TLSSocket::send(const string& buffer) +{ + sendRaw(buffer.data(), buffer.length()); +} + + +const int TLSSocket::receiveRaw(char* buffer, const int count) +{ + 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) + return 0; + + TLSSession::throwTLSException("gnutls_record_recv", ret); + } + + return static_cast <int>(ret); +} + + +void TLSSocket::sendRaw(const char* buffer, const int count) +{ + gnutls_record_send + (*m_session->m_gnutlsSession, + buffer, static_cast <size_t>(count)); + + if (m_ex) + internalThrow(); +} + + +void TLSSocket::handshake(ref <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 + platformDependant::getHandler()->wait(); + } + else + { + TLSSession::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) + ref <certificateChain> certs = getPeerCertificates(); + + if (certs == NULL) + throw exceptions::tls_exception("No peer certificate."); + + m_session->getCertificateVerifier()->verify(certs); + + m_connected = true; +} + + +ssize_t TLSSocket::gnutlsPushFunc + (gnutls_transport_ptr trspt, const void* data, size_t len) +{ + TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt); + + try + { + sok->m_wrapped->sendRaw + (reinterpret_cast <const char*>(data), static_cast <int>(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::gnutlsPullFunc + (gnutls_transport_ptr trspt, void* data, size_t len) +{ + TLSSocket* sok = reinterpret_cast <TLSSocket*>(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 <char*>(data), + static_cast <int>(len))); + + if (ret == 0) + { + // No data available yet + platformDependant::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 <char*>(data), + static_cast <int>(len))); + + if (n == 0) + return GNUTLS_E_AGAIN; // This seems like a hack, really... + + 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; + } +} + + +ref <certificateChain> TLSSocket::getPeerCertificates() +{ + unsigned int certCount = 0; + const gnutls_datum* rawData = gnutls_certificate_get_peers + (*m_session->m_gnutlsSession, &certCount); + + // Try X.509 + gnutls_x509_crt* x509Certs = new gnutls_x509_crt[certCount]; + + unsigned int count = certCount; + + int res = gnutls_x509_crt_list_import + (x509Certs, &count, rawData, GNUTLS_X509_FMT_PEM, 0); + + if (res <= 0) + { + count = certCount; + + res = gnutls_x509_crt_list_import + (x509Certs, &count, rawData, GNUTLS_X509_FMT_DER, 0); + } + + if (res >= 1) + { + std::vector <ref <certificate> > certs; + bool error = false; + + count = static_cast <unsigned int>(res); + + for (unsigned int i = 0 ; i < count ; ++i) + { + size_t dataSize = 0; + + gnutls_x509_crt_export(x509Certs[i], + GNUTLS_X509_FMT_DER, NULL, &dataSize); + + byte* data = new byte[dataSize]; + + gnutls_x509_crt_export(x509Certs[i], + GNUTLS_X509_FMT_DER, data, &dataSize); + + ref <X509Certificate> cert = + X509Certificate::import(data, dataSize); + + if (cert != NULL) + certs.push_back(cert); + else + error = true; + + delete [] data; + + gnutls_x509_crt_deinit(x509Certs[i]); + } + + delete [] x509Certs; + + if (error) + return NULL; + + return vmime::create <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 not catched. + +#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::internalThrow() +{ + static std::vector <ref <TLSSocket_DeleteExWrapper> > exToDelete; + + if (m_ex) + { + // To avoid memory leaks + exToDelete.push_back(vmime::create <TLSSocket_DeleteExWrapper>(m_ex)); + + throw *m_ex; + } +} + + +} // tls +} // net +} // vmime + diff --git a/src/net/tls/X509Certificate.cpp b/src/net/tls/X509Certificate.cpp new file mode 100644 index 00000000..cfb52a1d --- /dev/null +++ b/src/net/tls/X509Certificate.cpp @@ -0,0 +1,273 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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 <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include <ctime> + +#include "vmime/net/tls/X509Certificate.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +#ifndef VMIME_BUILDING_DOC + +struct X509CertificateInternalData +{ + X509CertificateInternalData() + { + gnutls_x509_crt_init(&cert); + } + + ~X509CertificateInternalData() + { + gnutls_x509_crt_deinit(cert); + } + + + gnutls_x509_crt cert; +}; + +#endif // VMIME_BUILDING_DOC + + +X509Certificate::X509Certificate() + : m_data(new X509CertificateInternalData) +{ +} + + +X509Certificate::X509Certificate(const X509Certificate&) + : certificate(), m_data(NULL) +{ + // Not used +} + + +X509Certificate::~X509Certificate() +{ + delete m_data; +} + + +// static +ref <X509Certificate> X509Certificate::import(utility::inputStream& is) +{ + byteArray bytes; + utility::stream::value_type chunk[4096]; + + while (!is.eof()) + { + const int len = is.read(chunk, sizeof(chunk)); + bytes.insert(bytes.end(), chunk, chunk + len); + } + + return import(&bytes[0], bytes.size()); +} + + +// static +ref <X509Certificate> X509Certificate::import + (const byte* data, const unsigned int length) +{ + ref <X509Certificate> cert = vmime::create <X509Certificate>(); + + gnutls_datum buffer; + buffer.data = const_cast <byte*>(data); + buffer.size = length; + + // Try DER format + if (gnutls_x509_crt_import(cert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0) + return cert; + + // Try PEM format + if (gnutls_x509_crt_import(cert->m_data->cert, &buffer, GNUTLS_X509_FMT_PEM) >= 0) + return cert; + + return NULL; +} + + +void X509Certificate::write + (utility::outputStream& os, const Format format) const +{ + size_t dataSize = 0; + gnutls_x509_crt_fmt fmt = GNUTLS_X509_FMT_DER; + + switch (format) + { + case FORMAT_DER: fmt = GNUTLS_X509_FMT_DER; break; + case FORMAT_PEM: fmt = GNUTLS_X509_FMT_PEM; break; + } + + gnutls_x509_crt_export(m_data->cert, fmt, NULL, &dataSize); + + byte* data = new byte[dataSize]; + + gnutls_x509_crt_export(m_data->cert, fmt, data, &dataSize); + + try + { + os.write(reinterpret_cast <utility::stream::value_type*>(data), dataSize); + } + catch (...) + { + delete [] data; + throw; + } +} + + +const byteArray X509Certificate::getSerialNumber() const +{ + char serial[64]; + size_t serialSize = sizeof(serial); + + gnutls_x509_crt_get_serial(m_data->cert, serial, &serialSize); + + return byteArray(serial, serial + serialSize); +} + + +const bool X509Certificate::checkIssuer + (ref <const X509Certificate> issuer) const +{ + return (gnutls_x509_crt_check_issuer + (m_data->cert, issuer->m_data->cert) >= 1); +} + + +const bool X509Certificate::verify(ref <const X509Certificate> caCert) const +{ + unsigned int verify = 0; + + const int res = gnutls_x509_crt_verify + (m_data->cert, &(caCert->m_data->cert), 1, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, + &verify); + + return (res == 0 && verify == 0); +} + + +const datetime X509Certificate::getActivationDate() const +{ + const time_t t = gnutls_x509_crt_get_activation_time(m_data->cert); + return datetime(t); +} + + +const datetime X509Certificate::getExpirationDate() const +{ + const time_t t = gnutls_x509_crt_get_expiration_time(m_data->cert); + return datetime(t); +} + + +const byteArray X509Certificate::getFingerprint(const DigestAlgorithm algo) const +{ + gnutls_digest_algorithm galgo; + + switch (algo) + { + case DIGEST_MD5: + + galgo = GNUTLS_DIG_MD5; + break; + + default: + case DIGEST_SHA1: + + galgo = GNUTLS_DIG_SHA; + break; + } + + size_t bufferSize = 0; + gnutls_x509_crt_get_fingerprint + (m_data->cert, galgo, NULL, &bufferSize); + + byte* buffer = new byte[bufferSize]; + + if (gnutls_x509_crt_get_fingerprint + (m_data->cert, galgo, buffer, &bufferSize) == 0) + { + byteArray res; + res.insert(res.end(), buffer, buffer + bufferSize); + + delete [] buffer; + + return res; + } + + delete [] buffer; + + return byteArray(); +} + + +const byteArray X509Certificate::getEncoded() const +{ + byteArray bytes; + utility::outputStreamByteArrayAdapter os(bytes); + + write(os, FORMAT_DER); + + return bytes; +} + + +const string X509Certificate::getType() const +{ + return "X.509"; +} + + +const int X509Certificate::getVersion() const +{ + return gnutls_x509_crt_get_version(m_data->cert); +} + + +const bool X509Certificate::equals(ref <const certificate> other) const +{ + ref <const X509Certificate> otherX509 = + other.dynamicCast <const X509Certificate>(); + + if (!otherX509) + return false; + + const byteArray fp1 = getFingerprint(DIGEST_MD5); + const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5); + + return fp1 == fp2; +} + + +} // tls +} // net +} // vmime + diff --git a/vmime/net/authHelper.hpp b/src/net/tls/certificateChain.cpp index 54487fbe..52855cc2 100644 --- a/vmime/net/authHelper.hpp +++ b/src/net/tls/certificateChain.cpp @@ -21,22 +21,33 @@ // the GNU General Public License cover the whole combination. // -#ifndef VMIME_NET_AUTHHELPER_HPP_INCLUDED -#define VMIME_NET_AUTHHELPER_HPP_INCLUDED - - -#include "vmime/types.hpp" +#include "vmime/net/tls/certificateChain.hpp" namespace vmime { namespace net { +namespace tls { + + +certificateChain::certificateChain(const std::vector <ref <certificate> >& certs) + : m_certs(certs) +{ +} -void hmac_md5(const string& text, const string& key, string& hexDigest); +const unsigned int certificateChain::getCount() const +{ + return static_cast <unsigned int>(m_certs.size()); +} +ref <certificate> certificateChain::getAt(const unsigned int index) +{ + return m_certs[index]; +} + + +} // tls } // net } // vmime - -#endif // VMIME_NET_AUTHHELPER_HPP_INCLUDED diff --git a/src/net/tls/defaultCertificateVerifier.cpp b/src/net/tls/defaultCertificateVerifier.cpp new file mode 100644 index 00000000..de0c6e45 --- /dev/null +++ b/src/net/tls/defaultCertificateVerifier.cpp @@ -0,0 +1,164 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 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 2 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/net/tls/defaultCertificateVerifier.hpp" + +#include "vmime/net/tls/X509Certificate.hpp" + +#include "vmime/exception.hpp" + + +namespace vmime { +namespace net { +namespace tls { + + +defaultCertificateVerifier::defaultCertificateVerifier() +{ +} + + +defaultCertificateVerifier::~defaultCertificateVerifier() +{ +} + + +defaultCertificateVerifier::defaultCertificateVerifier(const defaultCertificateVerifier&) + : certificateVerifier() +{ + // Not used +} + + +void defaultCertificateVerifier::verify(ref <certificateChain> chain) +{ + if (chain->getCount() == 0) + return; + + const string type = chain->getAt(0)->getType(); + + if (type == "X.509") + verifyX509(chain); + else + throw exceptions::unsupported_certificate_type(type); +} + + +void defaultCertificateVerifier::verifyX509(ref <certificateChain> chain) +{ + // For every certificate in the chain, verify that the certificate + // has been issued by the next certificate in the chain + if (chain->getCount() >= 2) + { + for (unsigned int i = 0 ; i < chain->getCount() - 1 ; ++i) + { + ref <X509Certificate> cert = + chain->getAt(i).dynamicCast <X509Certificate>(); + + ref <X509Certificate> next = + chain->getAt(i + 1).dynamicCast <X509Certificate>(); + + if (!cert->checkIssuer(next)) + { + throw exceptions::certificate_verification_exception + ("Subject/issuer verification failed."); + } + } + } + + // For every certificate in the chain, verify that the certificate + // is valid at the current time + const datetime now = datetime::now(); + + for (unsigned int i = 0 ; i < chain->getCount() ; ++i) + { + ref <X509Certificate> cert = + chain->getAt(i).dynamicCast <X509Certificate>(); + + const datetime begin = cert->getActivationDate(); + const datetime end = cert->getExpirationDate(); + + if (now < begin || now > end) + { + throw exceptions::certificate_verification_exception + ("Validity date check failed."); + } + } + + // Check whether the certificate can be trusted + + // -- First, verify that the the last certificate in the chain was + // -- issued by a third-party that we trust + ref <X509Certificate> lastCert = + chain->getAt(chain->getCount() - 1).dynamicCast <X509Certificate>(); + + bool trusted = false; + + for (unsigned int i = 0 ; !trusted && i < m_x509RootCAs.size() ; ++i) + { + ref <X509Certificate> rootCa = m_x509RootCAs[i]; + + if (lastCert->verify(rootCa)) + trusted = true; + } + + // -- Next, if the issuer certificate cannot be verified against + // -- root CAs, compare the subject's certificate against the + // -- trusted certificates + ref <X509Certificate> firstCert = + chain->getAt(0).dynamicCast <X509Certificate>(); + + for (unsigned int i = 0 ; !trusted && i < m_x509TrustedCerts.size() ; ++i) + { + ref <X509Certificate> cert = m_x509TrustedCerts[i]; + + if (firstCert->equals(cert)) + trusted = true; + } + + if (!trusted) + { + throw exceptions::certificate_verification_exception + ("Cannot verify certificate against trusted certificates."); + } +} + + +void defaultCertificateVerifier::setX509RootCAs + (const std::vector <ref <X509Certificate> >& caCerts) +{ + m_x509RootCAs = caCerts; +} + + +void defaultCertificateVerifier::setX509TrustedCerts + (const std::vector <ref <X509Certificate> >& trustedCerts) +{ + m_x509TrustedCerts = trustedCerts; +} + + +} // tls +} // net +} // vmime + diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp index 2941e5f2..04fa3308 100644 --- a/src/utility/stream.cpp +++ b/src/utility/stream.cpp @@ -117,6 +117,22 @@ void outputStreamStringAdapter::write(const value_type* const data, const size_t +// outputStreamByteArrayAdapter + +outputStreamByteArrayAdapter::outputStreamByteArrayAdapter(byteArray& array) + : m_array(array) +{ + m_array.clear(); +} + + +void outputStreamByteArrayAdapter::write(const value_type* const data, const size_type count) +{ + m_array.insert(m_array.end(), data, data + count); +} + + + // inputStreamAdapter inputStreamAdapter::inputStreamAdapter(std::istream& is) |