diff --git a/src/net/imap/IMAPConnection.cpp b/src/net/imap/IMAPConnection.cpp index 7ad5a7a7..6aa129be 100644 --- a/src/net/imap/IMAPConnection.cpp +++ b/src/net/imap/IMAPConnection.cpp @@ -66,7 +66,7 @@ namespace imap { IMAPConnection::IMAPConnection(ref store, ref auth) : m_store(store), m_auth(auth), m_socket(NULL), m_parser(NULL), m_tag(NULL), m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(NULL), - m_secured(false), m_firstTag(true) + m_secured(false), m_firstTag(true), m_capabilitiesFetched(false) { } @@ -473,6 +473,13 @@ void IMAPConnection::startTLS() m_secured = true; m_cntInfos = vmime::create (m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket); + + // " Once TLS has been started, the client MUST discard cached + // information about server capabilities and SHOULD re-issue the + // CAPABILITY command. This is necessary to protect against + // man-in-the-middle attacks which alter the capabilities list prior + // to STARTTLS. " (RFC-2595) + invalidateCapabilities(); } catch (exceptions::command_error&) { @@ -491,6 +498,22 @@ void IMAPConnection::startTLS() const std::vector IMAPConnection::getCapabilities() +{ + if (!m_capabilitiesFetched) + fetchCapabilities(); + + return m_capabilities; +} + + +void IMAPConnection::invalidateCapabilities() +{ + m_capabilities.clear(); + m_capabilitiesFetched = false; +} + + +void IMAPConnection::fetchCapabilities() { send(true, "CAPABILITY", true); @@ -527,7 +550,8 @@ const std::vector IMAPConnection::getCapabilities() } } - return res; + m_capabilities = res; + m_capabilitiesFetched = true; } diff --git a/src/net/pop3/POP3Connection.cpp b/src/net/pop3/POP3Connection.cpp index 96717620..846d31e9 100644 --- a/src/net/pop3/POP3Connection.cpp +++ b/src/net/pop3/POP3Connection.cpp @@ -65,7 +65,7 @@ namespace pop3 { POP3Connection::POP3Connection(ref store, ref auth) : m_store(store), m_auth(auth), m_socket(NULL), m_timeoutHandler(NULL), - m_authenticated(false), m_secured(false) + m_authenticated(false), m_secured(false), m_capabilitiesFetched(false) { } @@ -550,6 +550,13 @@ void POP3Connection::startTLS() m_secured = true; m_cntInfos = vmime::create (m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket); + + // " Once TLS has been started, the client MUST discard cached + // information about server capabilities and SHOULD re-issue + // the CAPA command. This is necessary to protect against + // man-in-the-middle attacks which alter the capabilities list + // prior to STLS. " (RFC-2595) + invalidateCapabilities(); } catch (exceptions::command_error&) { @@ -568,6 +575,22 @@ void POP3Connection::startTLS() const std::vector POP3Connection::getCapabilities() +{ + if (!m_capabilitiesFetched) + fetchCapabilities(); + + return m_capabilities; +} + + +void POP3Connection::invalidateCapabilities() +{ + m_capabilities.clear(); + m_capabilitiesFetched = false; +} + + +void POP3Connection::fetchCapabilities() { POP3Command::CAPA()->send(thisRef().dynamicCast ()); @@ -582,7 +605,8 @@ const std::vector POP3Connection::getCapabilities() res.push_back(response->getLineAt(i)); } - return res; + m_capabilities = res; + m_capabilitiesFetched = true; } diff --git a/vmime/net/imap/IMAPConnection.hpp b/vmime/net/imap/IMAPConnection.hpp index cb22b416..257e60d3 100644 --- a/vmime/net/imap/IMAPConnection.hpp +++ b/vmime/net/imap/IMAPConnection.hpp @@ -93,6 +93,8 @@ public: ref getSession(); + void fetchCapabilities(); + void invalidateCapabilities(); const std::vector getCapabilities(); ref getAuthenticator(); @@ -135,6 +137,9 @@ private: bool m_firstTag; + std::vector m_capabilities; + bool m_capabilitiesFetched; + void internalDisconnect(); diff --git a/vmime/net/pop3/POP3Connection.hpp b/vmime/net/pop3/POP3Connection.hpp index 8a900cb2..96916bab 100644 --- a/vmime/net/pop3/POP3Connection.hpp +++ b/vmime/net/pop3/POP3Connection.hpp @@ -94,6 +94,8 @@ private: void startTLS(); #endif // VMIME_HAVE_TLS_SUPPORT + void fetchCapabilities(); + void invalidateCapabilities(); const std::vector getCapabilities(); void internalDisconnect(); @@ -109,6 +111,9 @@ private: bool m_secured; ref m_cntInfos; + + std::vector m_capabilities; + bool m_capabilitiesFetched; };