Bug 1622640 - (CVE-2020-15685) Preclude malicious STARTTLS response injections. r=benc

This commit is contained in:
Gene Smith 2020-12-18 12:15:03 +02:00
Родитель 688984af7b
Коммит 4af22df686
1 изменённых файлов: 49 добавлений и 8 удалений

Просмотреть файл

@ -1724,17 +1724,58 @@ bool nsImapProtocol::ProcessCurrentURL() {
if (NS_SUCCEEDED(rv) && sslControl) {
rv = sslControl->StartTLS();
if (NS_SUCCEEDED(rv)) {
if (m_socketType == nsMsgSocketType::trySTARTTLS)
m_imapServerSink->UpdateTrySTARTTLSPref(true);
// force re-issue of "capability", because servers may
// Transition to secure state is now enabled but handshakes and
// negotiation has not yet occurred. Make sure that
// the stream input response buffer is drained to avoid false
// responses to subsequent commands (capability, login etc),
// i.e., due to possible MitM attack doing pre-TLS response
// injection. We are discarding any possible malicious data
// stored prior to sslControl->StartTLS().
// Note: If any non-TLS related data arrives while transitioning
// to secure state (after sslControl->StartTLS()), it will cause
// the TLS negotiation to fail so any injected data is never
// accessed since the transport connection will be dropped.
char discardBuf[80];
uint64_t numBytesInStream = 0;
uint32_t numBytesRead;
rv = m_inputStream->Available(&numBytesInStream);
nsCOMPtr<nsIInputStream> kungFuGrip = m_inputStream;
// Read and discard any data available in socket buffer.
while (numBytesInStream > 0 && NS_SUCCEEDED(rv)) {
rv = m_inputStream->Read(
discardBuf,
std::min(uint64_t(sizeof discardBuf), numBytesInStream),
&numBytesRead);
numBytesInStream -= numBytesRead;
}
kungFuGrip = nullptr;
// Discard any data lines previously read from socket buffer.
m_inputStreamBuffer->ClearBuffer();
// Force re-issue of "capability", because servers may
// enable other auth features (e.g. remove LOGINDISABLED
// and add AUTH=PLAIN) after we upgraded to SSL.
// and add AUTH=PLAIN). Sending imap data here first triggers
// the TLS negotiation handshakes.
Capability();
eIMAPCapabilityFlags capabilityFlag =
GetServerStateParser().GetCapabilityFlag();
// If user has set pref mail.server.serverX.socketType to 1
// (trySTARTTLS, now depricated in UI) and Capability()
// succeeds, indicating TLS handshakes succeeded, set and
// latch the socketType to 2 (alwaysSTARTTLS) for this server.
if ((m_socketType == nsMsgSocketType::trySTARTTLS) &&
GetServerStateParser().LastCommandSuccessful())
m_imapServerSink->UpdateTrySTARTTLSPref(true);
// Courier imap doesn't return STARTTLS capability if we've done
// a STARTTLS! But we need to remember this capability so we'll
// try to use STARTTLS next time.
// Update: This may not be a problem since "next time" will be
// on a new connection that is not yet in secure state. So the
// capability greeting *will* contain STARTTLS. I observed and
// tested this on Courier imap server. But keep this to be sure.
eIMAPCapabilityFlags capabilityFlag =
GetServerStateParser().GetCapabilityFlag();
if (!(capabilityFlag & kHasStartTLSCapability)) {
capabilityFlag |= kHasStartTLSCapability;
GetServerStateParser().SetCapabilityFlag(capabilityFlag);
@ -1744,12 +1785,12 @@ bool nsImapProtocol::ProcessCurrentURL() {
}
}
if (NS_FAILED(rv)) {
nsAutoCString logLine("STARTTLS negotiation failed. Error 0x");
nsAutoCString logLine("Enable of STARTTLS failed. Error 0x");
logLine.AppendInt(static_cast<uint32_t>(rv), 16);
Log("ProcessCurrentURL", nullptr, logLine.get());
if (m_socketType == nsMsgSocketType::alwaysSTARTTLS) {
SetConnectionStatus(rv); // stop netlib
m_transport->Close(rv);
if (m_transport) m_transport->Close(rv);
} else if (m_socketType == nsMsgSocketType::trySTARTTLS)
m_imapServerSink->UpdateTrySTARTTLSPref(false);
}