fix for secure smtp bug 30321 r=mscott for the smtp part and r=bryner for the rest

This commit is contained in:
pavlov%netscape.com 2000-09-01 09:00:37 +00:00
Родитель bf208e29cb
Коммит b956215375
12 изменённых файлов: 307 добавлений и 57 удалений

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

@ -50,5 +50,6 @@ interface nsIPSMSocketInfo : nsISupports {
void getPickledStatus(out charPtr pickledStatus);
void proxyStepUp();
void TLSStepUp();
};

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

@ -36,4 +36,8 @@ interface nsISSLSocketProvider : nsISocketProvider {
#define NS_ISSLFHSOCKETPROVIDER_PROGID NS_NETWORK_SOCKET_PROGID_PREFIX "ssl-forcehandshake"
#define NS_ISSLFHSOCKETPROVIDER_CLASSNAME "Mozilla SSL-FH Socket Provider Component"
/* this code behaves just like the above, but has to force a handshake */
#define NS_TLSSOCKETPROVIDER_PROGID NS_NETWORK_SOCKET_PROGID_PREFIX "tls"
#define NS_TLSSOCKETPROVIDER_CLASSNAME "Mozilla TLS Socket Provider Component"
%}

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

@ -41,6 +41,7 @@ CPPSRCS = \
nsPSMComponent.cpp \
nsPSMUICallbacks.cpp \
nsSSLSocketProvider.cpp \
nsTLSSocketProvider.cpp \
nsPSMModule.cpp \
nsSSLIOLayer.cpp \
nsSecureBrowserUIImpl.cpp \

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

@ -32,6 +32,7 @@
#include "nsSecureBrowserUIImpl.h"
#include "nsSSLSocketProvider.h"
#include "nsTLSSocketProvider.h"
#include "nsSDR.h"
#include "nsFSDR.h"
@ -126,6 +127,13 @@ static nsModuleComponentInfo components[] =
nsSSLSocketProvider::Create
},
{
NS_TLSSOCKETPROVIDER_CLASSNAME,
NS_TLSSOCKETPROVIDER_CID,
NS_TLSSOCKETPROVIDER_PROGID,
nsTLSSocketProvider::Create
},
{
NS_SDR_CLASSNAME,
NS_SDR_CID,

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

@ -56,6 +56,9 @@ public:
nsresult SetHostPort(PRInt32 aPort);
nsresult SetProxyPort(PRInt32 aPort);
nsresult SetPickledStatus();
nsresult SetUseTLS(PRBool useTLS);
nsresult GetUseTLS(PRBool *useTLS);
protected:
CMT_CONTROL* mControl;
@ -69,6 +72,7 @@ protected:
PRInt32 mProxyPort;
PRBool mForceHandshake;
PRBool mUseTLS;
unsigned char* mPickledStatus;
};
@ -124,26 +128,15 @@ nsSSLIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeou
PRInt32 proxyPort;
PRInt32 hostPort;
PRBool forceHandshake;
PRBool useTLS;
infoObject->GetProxyName(&proxyName);
infoObject->GetHostName(&hostName);
infoObject->GetProxyPort(&proxyPort);
infoObject->GetHostPort(&hostPort);
infoObject->GetForceHandshake(&forceHandshake);
if (!proxyName)
{
CMBool handshake = forceHandshake ? CM_TRUE : CM_FALSE;
// Direct connection
status = CMT_OpenSSLConnection(control,
cmsock,
SSM_REQUEST_SSL_DATA_SSL,
PR_ntohs(addr->inet.port),
ipBuffer,
(hostName ? hostName : ipBuffer),
handshake,
nsnull);
}
else
infoObject->GetUseTLS(&useTLS);
if (proxyName)
{
PRInt32 destPort;
@ -157,6 +150,27 @@ nsSSLIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeou
ipBuffer,
proxyName);
}
else if (useTLS)
{
status = CMT_OpenTLSConnection(control,
cmsock,
PR_ntohs(addr->inet.port),
ipBuffer,
(hostName ? hostName : ipBuffer));
}
else
{
CMBool handshake = forceHandshake ? CM_TRUE : CM_FALSE;
// Direct connection
status = CMT_OpenSSLConnection(control,
cmsock,
SSM_REQUEST_SSL_DATA_SSL,
PR_ntohs(addr->inet.port),
ipBuffer,
(hostName ? hostName : ipBuffer),
handshake,
nsnull);
}
if (hostName) Recycle(hostName);
if (proxyName) Recycle(proxyName);
@ -318,6 +332,7 @@ nsPSMSocketInfo::nsPSMSocketInfo()
mSocket = nsnull;
mPickledStatus = nsnull;
mForceHandshake = PR_FALSE;
mUseTLS = PR_FALSE;
}
nsPSMSocketInfo::~nsPSMSocketInfo()
@ -338,6 +353,12 @@ nsPSMSocketInfo::ProxyStepUp()
return CMT_ProxyStepUp(mControl, mSocket, nsnull, hostName);
}
NS_IMETHODIMP
nsPSMSocketInfo::TLSStepUp()
{
return CMT_TLSStepUp(mControl, mSocket, nsnull);
}
NS_IMETHODIMP
nsPSMSocketInfo::GetControlPtr(CMT_CONTROL * *aControlPtr)
{
@ -413,7 +434,6 @@ nsPSMSocketInfo::SetHostPort(PRInt32 aPort)
return NS_OK;
}
NS_IMETHODIMP
nsPSMSocketInfo::GetProxyName(char * *aName)
{
@ -461,6 +481,20 @@ nsPSMSocketInfo::SetForceHandshake(PRBool forceHandshake)
return NS_OK;
}
nsresult
nsPSMSocketInfo::GetUseTLS(PRBool *aResult)
{
*aResult = mUseTLS;
return NS_OK;
}
nsresult
nsPSMSocketInfo::SetUseTLS(PRBool useTLS)
{
mUseTLS = useTLS;
return NS_OK;
}
nsresult
nsPSMSocketInfo::SetPickledStatus()
@ -511,7 +545,8 @@ nsSSLIOLayerNewSocket( const char *host,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc **fd,
nsISupports** info)
nsISupports** info,
PRBool useTLS)
{
if (firstTime)
{
@ -572,6 +607,7 @@ nsSSLIOLayerNewSocket( const char *host,
infoObject->SetHostPort(port);
infoObject->SetProxyName(proxyHost);
infoObject->SetProxyPort(proxyPort);
infoObject->SetUseTLS(useTLS);
layer->secret = (PRFilePrivate*) infoObject;
rv = PR_PushIOLayer(sock, PR_GetLayersIdentity(sock), layer);
@ -596,7 +632,8 @@ nsSSLIOLayerAddToSocket( const char *host,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc *fd,
nsISupports** info)
nsISupports** info,
PRBool useTLS)
{
if (firstTime)
{
@ -650,6 +687,7 @@ nsSSLIOLayerAddToSocket( const char *host,
infoObject->SetHostPort(port);
infoObject->SetProxyName(proxyHost);
infoObject->SetProxyPort(proxyPort);
infoObject->SetUseTLS(useTLS);
layer->secret = (PRFilePrivate*) infoObject;
rv = PR_PushIOLayer(fd, PR_GetLayersIdentity(fd), layer);

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

@ -35,12 +35,14 @@ nsresult nsSSLIOLayerNewSocket(const char *host,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc **fd,
nsISupports **securityInfo);
nsISupports **securityInfo,
PRBool useTLS);
nsresult nsSSLIOLayerAddToSocket(const char *host,
PRInt32 port,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc *fd,
nsISupports **securityInfo);
PRInt32 port,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc *fd,
nsISupports **securityInfo,
PRBool useTLS);
#endif /* _NSSSLIOLAYER_H */

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

@ -88,7 +88,8 @@ nsSSLSocketProvider::NewSocket(const char *host,
proxyHost,
proxyPort,
_result,
securityInfo);
securityInfo,
PR_FALSE);
return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
}
@ -107,7 +108,8 @@ nsSSLSocketProvider::AddToSocket(const char *host,
proxyHost,
proxyPort,
socket,
securityInfo);
securityInfo,
PR_FALSE);
return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
}

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

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsTLSSocketProvider.h"
#include "nsSSLIOLayer.h"
////////////////////////////////////////////////////////////////////////////////
nsTLSSocketProvider::nsTLSSocketProvider()
{
NS_INIT_REFCNT();
}
nsresult
nsTLSSocketProvider::Init()
{
nsresult rv = NS_OK;
return rv;
}
nsTLSSocketProvider::~nsTLSSocketProvider()
{
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsTLSSocketProvider, nsISocketProvider, nsISSLSocketProvider);
NS_METHOD
nsTLSSocketProvider::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
nsresult rv;
nsTLSSocketProvider * inst;
if (NULL == aResult) {
rv = NS_ERROR_NULL_POINTER;
return rv;
}
*aResult = NULL;
if (NULL != aOuter) {
rv = NS_ERROR_NO_AGGREGATION;
return rv;
}
NS_NEWXPCOM(inst, nsTLSSocketProvider);
if (NULL == inst) {
rv = NS_ERROR_OUT_OF_MEMORY;
return rv;
}
NS_ADDREF(inst);
rv = inst->QueryInterface(aIID, aResult);
NS_RELEASE(inst);
return rv;
}
NS_IMETHODIMP
nsTLSSocketProvider::NewSocket(const char *host,
PRInt32 port,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc **_result,
nsISupports **securityInfo)
{
nsresult rv = nsSSLIOLayerNewSocket(host,
port,
proxyHost,
proxyPort,
_result,
securityInfo,
PR_TRUE);
return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
}
// Add the SSL IO layer to an existing socket
NS_IMETHODIMP
nsTLSSocketProvider::AddToSocket(const char *host,
PRInt32 port,
const char *proxyHost,
PRInt32 proxyPort,
PRFileDesc *socket,
nsISupports **securityInfo)
{
nsresult rv = nsSSLIOLayerAddToSocket(host,
port,
proxyHost,
proxyPort,
socket,
securityInfo,
PR_TRUE);
return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
}

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

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef _NSTLSSOCKETPROVIDER_H_
#define _NSTLSSOCKETPROVIDER_H_
#include "nsISSLSocketProvider.h"
/* 274418d0-5437-11d3-bbc8-0000861d1237 */
#define NS_TLSSOCKETPROVIDER_CID \
{ /* 88f2df38-1dd2-11b2-97fd-ac6da6bfab7f */ \
0x88f2df38, \
0x1dd2, \
0x11b2, \
{0x97, 0xfd, 0xac, 0x6d, 0xa6, 0xbf, 0xab, 0x7f} \
}
class nsTLSSocketProvider : public nsISSLSocketProvider
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISOCKETPROVIDER
NS_DECL_NSISSLSOCKETPROVIDER
// nsTLSSocketProvider methods:
nsTLSSocketProvider();
virtual ~nsTLSSocketProvider();
static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
nsresult Init();
protected:
};
#endif /* _NSTLSSOCKETPROVIDER_H_ */

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

@ -48,6 +48,8 @@
#include "plbase64.h"
#include "nsEscape.h"
#include "nsIPSMSocketInfo.h"
#ifndef XP_UNIX
#include <stdarg.h>
#endif /* !XP_UNIX */
@ -308,7 +310,7 @@ void nsSmtpProtocol::Initialize(nsIURI * aURL)
m_responseCode = 0;
m_previousResponseCode = 0;
m_continuationResponse = -1;
m_tlsEnabled = PR_FALSE;
m_tlsEnabled = PR_FALSE;
m_addressCopy = nsnull;
m_addresses = nsnull;
m_addressesLeft = nsnull;
@ -333,8 +335,12 @@ void nsSmtpProtocol::Initialize(nsIURI * aURL)
nsXPIDLCString hostName;
aURL->GetHost(getter_Copies(hostName));
PR_LOG(SMTPLogModule, PR_LOG_ALWAYS, ("SMTP Connecting to: %s", (const char *) hostName));
// pass in "ssl" for the last arg if you want this to be over SSL
rv = OpenNetworkSocket(aURL, nsnull);
// pass in "ssl" for the last arg if you want this to be over SSL
if (m_prefAuthMethod == PREF_AUTH_TLS_ONLY)
rv = OpenNetworkSocket(aURL, "tls");
else
rv = OpenNetworkSocket(aURL, nsnull);
}
}
@ -511,7 +517,7 @@ PRInt32 nsSmtpProtocol::SmtpResponse(nsIInputStream * inputStream, PRUint32 leng
m_responseText += line+4;
}
if (m_responseCode == 220 && nsCRT::strlen(m_responseText))
if (m_responseCode == 220 && nsCRT::strlen(m_responseText) && !m_tlsInitiated)
{ // check for the greeting if it is a ESMTP server set capability accordingly
if (m_responseText.Find("ESMTP", PR_TRUE) != -1)
{
@ -745,18 +751,29 @@ PRInt32 nsSmtpProtocol::SendTLSResponse()
// only tear down our existing connection and open a new one if we received a 220 response
// from the smtp server after we issued the STARTTLS
nsresult rv = NS_OK;
if (m_responseCode == 220 )
if (m_responseCode == 220)
{
CloseSocket();
// now clear a bunch of internal state data...
// now re-open the connection
rv = OpenNetworkSocket(m_url, "ssl-forcehandshake");
m_nextState = SMTP_RESPONSE;
m_nextStateAfterResponse = SMTP_START_CONNECT;
m_tlsInitiated = PR_TRUE;
nsCOMPtr<nsISupports> secInfo;
rv = m_channel->GetSecurityInfo(getter_AddRefs(secInfo));
if (NS_SUCCEEDED(rv) && secInfo) {
nsCOMPtr<nsIPSMSocketInfo> securityInfo = do_QueryInterface(secInfo, &rv);
if (NS_SUCCEEDED(rv) && securityInfo) {
rv = securityInfo->TLSStepUp();
}
}
if (NS_FAILED(rv)) {
// if we fail, should we close the connection?
return rv;
}
m_nextState = SMTP_EXTN_LOGIN_RESPONSE;
m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE;
m_tlsEnabled = PR_TRUE;
m_flags = 0;
SetFlag(SMTP_PAUSE_FOR_READ);
}
return rv;
@ -812,7 +829,7 @@ PRInt32 nsSmtpProtocol::ProcessAuth()
{
if (TestFlag(SMTP_AUTH_EXTERNAL_ENABLED))
{
buffer = "AUTH EXTERNAL";
buffer = "AUTH EXTERNAL =";
buffer += CRLF;
SendData(url, buffer);
m_nextState = SMTP_RESPONSE;
@ -1319,8 +1336,8 @@ nsresult nsSmtpProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer )
{
char *addrs1 = 0;
char *addrs2 = 0;
m_nextState = SMTP_RESPONSE;
m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE;
m_nextState = SMTP_RESPONSE;
m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE;
/* Remove duplicates from the list, to prevent people from getting
more than one copy (the SMTP host may do this too, or it may not.)
@ -1395,17 +1412,18 @@ nsresult nsSmtpProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp
case SMTP_START_CONNECT:
SetFlag(SMTP_PAUSE_FOR_READ);
m_nextState = SMTP_RESPONSE;
m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE;
break;
m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE;
break;
case SMTP_FINISH_CONNECT:
SetFlag(SMTP_PAUSE_FOR_READ);
break;
case SMTP_LOGIN_RESPONSE:
case SMTP_LOGIN_RESPONSE:
if (inputStream == nsnull)
SetFlag(SMTP_PAUSE_FOR_READ);
else
status = LoginResponse(inputStream, length);
case SMTP_TLS_RESPONSE:
break;
case SMTP_TLS_RESPONSE:
if (inputStream == nsnull)
SetFlag(SMTP_PAUSE_FOR_READ);
else
@ -1430,15 +1448,18 @@ nsresult nsSmtpProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp
else
status = SendEhloResponse(inputStream, length);
break;
case SMTP_AUTH_PROCESS_STATE:
status = ProcessAuth();
break;
case SMTP_AUTH_PROCESS_STATE:
status = ProcessAuth();
break;
case SMTP_AUTH_EXTERNAL_RESPONSE:
case SMTP_AUTH_LOGIN_RESPONSE:
if (inputStream == nsnull)
SetFlag(SMTP_PAUSE_FOR_READ);
else
status = AuthLoginResponse(inputStream, length);
break;
case SMTP_SEND_AUTH_LOGIN_USERNAME:
status = AuthLoginUsername();
break;
@ -1446,7 +1467,7 @@ nsresult nsSmtpProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp
case SMTP_SEND_AUTH_LOGIN_PASSWORD:
status = AuthLoginPassword();
break;
case SMTP_SEND_VRFY_RESPONSE:
if (inputStream == nsnull)
SetFlag(SMTP_PAUSE_FOR_READ);
@ -1494,20 +1515,20 @@ nsresult nsSmtpProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp
break;
case SMTP_ERROR_DONE:
{
{
nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(m_runningURL);
// propagate the right error code
mailNewsUrl->SetUrlState(PR_FALSE, m_urlErrorState);
m_nextState = SMTP_FREE;
}
m_nextState = SMTP_FREE;
break;
m_nextState = SMTP_FREE;
break;
case SMTP_FREE:
// smtp is a one time use connection so kill it if we get here...
CloseSocket();
return NS_OK; /* final end */
return NS_OK; /* final end */
default: /* should never happen !!! */
m_nextState = SMTP_ERROR_DONE;

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

@ -204,7 +204,7 @@ private:
PRInt32 AuthLoginPassword();
PRInt32 AuthLoginResponse(nsIInputStream * stream, PRUint32 length);
PRInt32 SendTLSResponse();
PRInt32 SendTLSResponse();
PRInt32 SendVerifyResponse(); // mscott: this one is apparently unimplemented...
PRInt32 SendMailResponse();
PRInt32 SendRecipientResponse();

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

@ -863,7 +863,8 @@ nsresult nsSocketTransport::doConnection(PRInt16 aSelectFlags)
if (!NS_SUCCEEDED(rv) || !mSocketFD) break;
// if the service was ssl, we want to hold onto the socket info
if (nsCRT::strcmp(mSocketTypes[type], "ssl") == 0) {
if (nsCRT::strcmp(mSocketTypes[type], "ssl") == 0 ||
nsCRT::strcmp(mSocketTypes[type], "tls") == 0) {
mSecurityInfo = socketInfo;
}
else if (nsCRT::strcmp(mSocketTypes[type], "ssl-forcehandshake") == 0) {