зеркало из https://github.com/mozilla/gecko-dev.git
bug 111384, Support OCSP requests through a proxy
combined r= by darin / rrelyea second checkin attempt
This commit is contained in:
Родитель
ef483b51d5
Коммит
9b7392ffd9
|
@ -306,6 +306,7 @@ OCSPUnauthorizedResponse=Error trying to validate certificate from %S using OCSP
|
|||
OCSPUnknownCert=Error trying to validate certificate from %S using OCSP - unknown certificate.
|
||||
OCSPNoDefaultResponder=Error trying to validate certificate from %S using OCSP - no default responder specified.
|
||||
OCSPDirLookup=Error trying to validate certificate from %S using OCSP - directory lookup error.
|
||||
OCSPDeadlock=An internal failure has been detected. It is not possible to complete the requested OCSP operation.
|
||||
CertInfoIssuedFor=Issued to:
|
||||
CertInfoIssuedBy=Issued by:
|
||||
CertInfoValid=Valid
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Bob Lord <lord@netscape.com>
|
||||
* Ian McGreer <mcgreer@netscape.com>
|
||||
* Javier Delgadillo <javi@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -38,6 +39,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const nsIX509Cert = Components.interfaces.nsIX509Cert;
|
||||
const nsIX509Cert3 = Components.interfaces.nsIX509Cert3;
|
||||
const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
|
||||
const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
|
||||
const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
|
||||
|
@ -121,6 +123,13 @@ function setWindowName()
|
|||
AddCertChain("treesetDump", chain, "dump_");
|
||||
DisplayGeneralDataFromCert(cert);
|
||||
BuildPrettyPrint(cert);
|
||||
|
||||
if (cert instanceof nsIX509Cert3)
|
||||
{
|
||||
cert.requestUsagesArrayAsync(
|
||||
getProxyOnUIThread(new listener(),
|
||||
Components.interfaces.nsICertVerificationListener));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,14 +190,44 @@ function addAttributeFromCert(nodeName, value)
|
|||
node.setAttribute('value',value)
|
||||
}
|
||||
|
||||
function DisplayGeneralDataFromCert(cert)
|
||||
|
||||
|
||||
function listener() {
|
||||
}
|
||||
|
||||
listener.prototype.QueryInterface =
|
||||
function(iid) {
|
||||
if (iid.equals(Components.interfaces.nsISupports) ||
|
||||
iid.equals(Components.interfaces.nsICertVerificationListener))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
listener.prototype.notify =
|
||||
function(cert, result) {
|
||||
DisplayVerificationData(cert, result);
|
||||
}
|
||||
|
||||
function DisplayVerificationData(cert, result)
|
||||
{
|
||||
if (!result || !cert)
|
||||
return; // no results could be produced
|
||||
|
||||
if (!(cert instanceof Components.interfaces.nsIX509Cert))
|
||||
return;
|
||||
|
||||
// Verification and usage
|
||||
var verifystr = "";
|
||||
var o1 = {};
|
||||
var o2 = {};
|
||||
var o3 = {};
|
||||
cert.getUsagesArray(false, o1, o2, o3); // do not ignore OCSP when checking
|
||||
|
||||
if (!(result instanceof Components.interfaces.nsICertVerificationResult))
|
||||
return;
|
||||
|
||||
result.getUsagesArrayResult(o1, o2, o3);
|
||||
|
||||
var verifystate = o1.value;
|
||||
var count = o2.value;
|
||||
var usageList = o3.value;
|
||||
|
@ -217,7 +256,10 @@ function DisplayGeneralDataFromCert(cert)
|
|||
AddUsage(usageList[i],verifyInfoBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DisplayGeneralDataFromCert(cert)
|
||||
{
|
||||
// Common Name
|
||||
addAttributeFromCert('commonname', cert.commonName);
|
||||
// Organization
|
||||
|
@ -263,3 +305,21 @@ function updateCertDump()
|
|||
}
|
||||
displaySelected();
|
||||
}
|
||||
|
||||
function getProxyOnUIThread(aObject, aInterface) {
|
||||
var eventQSvc = Components.
|
||||
classes["@mozilla.org/event-queue-service;1"].
|
||||
getService(Components.interfaces.nsIEventQueueService);
|
||||
|
||||
var uiQueue = eventQSvc.
|
||||
getSpecialEventQueue(Components.interfaces.
|
||||
nsIEventQueueService.UI_THREAD_EVENT_QUEUE);
|
||||
|
||||
var proxyMgr = Components.
|
||||
classes["@mozilla.org/xpcomproxy;1"].
|
||||
getService(Components.interfaces.nsIProxyObjectManager);
|
||||
|
||||
return proxyMgr.getProxyForObject(uiQueue,
|
||||
aInterface, aObject, 5);
|
||||
// 5 == PROXY_ALWAYS | PROXY_SYNC
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ SDK_XPIDLSRCS = \
|
|||
nsICertificateDialogs.idl \
|
||||
nsICRLInfo.idl \
|
||||
nsIX509Cert.idl \
|
||||
nsIX509Cert3.idl \
|
||||
nsIX509CertDB.idl \
|
||||
nsIX509CertValidity.idl \
|
||||
$(NULL)
|
||||
|
@ -82,6 +83,7 @@ XPIDLSRCS = \
|
|||
nsICMSEncoder.idl \
|
||||
nsICMSMessageErrors.idl \
|
||||
nsICMSMessage.idl \
|
||||
nsICMSMessage2.idl \
|
||||
nsINSSCertCache.idl \
|
||||
nsIOCSPResponder.idl \
|
||||
nsIPK11Token.idl \
|
||||
|
|
|
@ -57,6 +57,9 @@ LIBXUL_LIBRARY = 1
|
|||
PACKAGE_FILE = pipnss.pkg
|
||||
|
||||
CPPSRCS = \
|
||||
nsPSMBackgroundThread.cpp \
|
||||
nsSSLThread.cpp \
|
||||
nsCertVerificationThread.cpp \
|
||||
nsCipherInfo.cpp \
|
||||
nsNSSCallbacks.cpp \
|
||||
nsNSSComponent.cpp \
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): David Drinan <ddrinan@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -43,6 +44,7 @@
|
|||
#include "cms.h"
|
||||
#include "nsICMSMessageErrors.h"
|
||||
#include "nsArray.h"
|
||||
#include "nsCertVerificationThread.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -52,7 +54,9 @@ extern PRLogModuleInfo* gPIPNSSLog;
|
|||
#include "nsNSSCleaner.h"
|
||||
|
||||
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsCMSMessage, nsICMSMessage)
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsCMSMessage, nsICMSMessage,
|
||||
nsICMSMessage2)
|
||||
|
||||
nsCMSMessage::nsCMSMessage()
|
||||
{
|
||||
|
@ -224,10 +228,6 @@ NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert)
|
|||
|
||||
NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (!aDigestData || !aDigestDataLen)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -340,6 +340,56 @@ loser:
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCMSMessage::AsyncVerifySignature(
|
||||
nsISMimeVerificationListener *aListener)
|
||||
{
|
||||
return CommonAsyncVerifySignature(aListener, nsnull, 0);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCMSMessage::AsyncVerifyDetachedSignature(
|
||||
nsISMimeVerificationListener *aListener,
|
||||
unsigned char* aDigestData, PRUint32 aDigestDataLen)
|
||||
{
|
||||
if (!aDigestData || !aDigestDataLen)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return CommonAsyncVerifySignature(aListener, aDigestData, aDigestDataLen);
|
||||
}
|
||||
|
||||
nsresult nsCMSMessage::CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener,
|
||||
unsigned char* aDigestData, PRUint32 aDigestDataLen)
|
||||
{
|
||||
nsSMimeVerificationJob *job = new nsSMimeVerificationJob;
|
||||
if (!job)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (aDigestData)
|
||||
{
|
||||
job->digest_data = new unsigned char[aDigestDataLen];
|
||||
if (!job->digest_data)
|
||||
{
|
||||
delete job;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(job->digest_data, aDigestData, aDigestDataLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
job->digest_data = nsnull;
|
||||
}
|
||||
|
||||
job->digest_len = aDigestDataLen;
|
||||
job->mMessage = this;
|
||||
job->mListener = aListener;
|
||||
|
||||
nsresult rv = nsCertVerificationThread::addJob(job);
|
||||
if (NS_FAILED(rv))
|
||||
delete job;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
class nsZeroTerminatedCertArray : public nsNSSShutDownObject
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): David Drinan <ddrinan@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -40,8 +41,12 @@
|
|||
|
||||
#include "nsISupports.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsICMSMessage.h"
|
||||
#include "nsICMSMessage2.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsVerificationJob.h"
|
||||
#include "nsICMSEncoder.h"
|
||||
#include "nsICMSDecoder.h"
|
||||
#include "sechash.h"
|
||||
|
@ -53,11 +58,13 @@
|
|||
{ 0xa4557478, 0xae16, 0x11d5, { 0xba,0x4b,0x00,0x10,0x83,0x03,0xb1,0x17 } }
|
||||
|
||||
class nsCMSMessage : public nsICMSMessage,
|
||||
public nsICMSMessage2,
|
||||
public nsNSSShutDownObject
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICMSMESSAGE
|
||||
NS_DECL_NSICMSMESSAGE2
|
||||
|
||||
nsCMSMessage();
|
||||
nsCMSMessage(NSSCMSMessage* aCMSMsg);
|
||||
|
@ -70,10 +77,15 @@ private:
|
|||
NSSCMSMessage * m_cmsMsg;
|
||||
NSSCMSSignerInfo* GetTopLevelSignerInfo();
|
||||
nsresult CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen);
|
||||
|
||||
nsresult CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener,
|
||||
unsigned char* aDigestData, PRUint32 aDigestDataLen);
|
||||
|
||||
virtual void virtualDestroyNSSReference();
|
||||
void destructorSafeDestroyNSSReference();
|
||||
};
|
||||
|
||||
friend class nsSMimeVerificationJob;
|
||||
};
|
||||
|
||||
// ===============================================
|
||||
// nsCMSDecoder - implementation of nsICMSDecoder
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Terry Hayes <thayes@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -54,13 +55,516 @@
|
|||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsNSSEvent.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsSSLThread.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIPrompt.h"
|
||||
|
||||
#include "ssl.h"
|
||||
#include "cert.h"
|
||||
|
||||
#include "ocsp.h"
|
||||
|
||||
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
||||
|
||||
struct nsHTTPDownloadEvent : PLEvent {
|
||||
nsHTTPDownloadEvent();
|
||||
~nsHTTPDownloadEvent();
|
||||
|
||||
nsNSSHttpRequestSession *mRequestSession; // no ownership
|
||||
|
||||
nsCOMPtr<nsHTTPListener> mListener;
|
||||
PRBool mResponsibleForDoneSignal;
|
||||
};
|
||||
|
||||
nsHTTPDownloadEvent::nsHTTPDownloadEvent()
|
||||
:mResponsibleForDoneSignal(PR_TRUE)
|
||||
{
|
||||
}
|
||||
|
||||
nsHTTPDownloadEvent::~nsHTTPDownloadEvent()
|
||||
{
|
||||
if (mResponsibleForDoneSignal && mListener)
|
||||
mListener->send_done_signal();
|
||||
}
|
||||
|
||||
static void PR_CALLBACK HandleHTTPDownloadPLEvent(nsHTTPDownloadEvent *aEvent)
|
||||
{
|
||||
if((!aEvent) || (!aEvent->mListener))
|
||||
return;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIChannel> chan;
|
||||
ios->NewChannel(aEvent->mRequestSession->mURL, nsnull, nsnull, getter_AddRefs(chan));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
// Create a loadgroup for this new channel. This way if the channel
|
||||
// is redirected, we'll have a way to cancel the resulting channel.
|
||||
nsCOMPtr<nsILoadGroup> loadGroup =
|
||||
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
|
||||
chan->SetLoadGroup(loadGroup);
|
||||
|
||||
if (aEvent->mRequestSession->mHasPostData)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> uploadStream;
|
||||
rv = NS_NewPostDataStream(getter_AddRefs(uploadStream),
|
||||
PR_FALSE,
|
||||
aEvent->mRequestSession->mPostData,
|
||||
0, ios);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(chan, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
rv = uploadChannel->SetUploadStream(uploadStream,
|
||||
aEvent->mRequestSession->mPostContentType,
|
||||
-1);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
rv = hchan->SetRequestMethod(aEvent->mRequestSession->mRequestMethod);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsSSLThread::rememberPendingHTTPRequest(loadGroup);
|
||||
|
||||
aEvent->mResponsibleForDoneSignal = PR_FALSE;
|
||||
aEvent->mListener->mResponsibleForDoneSignal = PR_TRUE;
|
||||
|
||||
rv = NS_NewStreamLoader(getter_AddRefs(aEvent->mListener->mLoader),
|
||||
hchan,
|
||||
aEvent->mListener,
|
||||
nsnull);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aEvent->mListener->mResponsibleForDoneSignal = PR_FALSE;
|
||||
aEvent->mResponsibleForDoneSignal = PR_TRUE;
|
||||
|
||||
nsSSLThread::rememberPendingHTTPRequest(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
static void PR_CALLBACK DestroyHTTPDownloadPLEvent(nsHTTPDownloadEvent* aEvent)
|
||||
{
|
||||
delete aEvent;
|
||||
}
|
||||
|
||||
struct nsCancelHTTPDownloadEvent : PLEvent {
|
||||
};
|
||||
|
||||
static void PR_CALLBACK HandleCancelHTTPDownloadPLEvent(nsCancelHTTPDownloadEvent *aEvent)
|
||||
{
|
||||
nsSSLThread::cancelPendingHTTPRequest();
|
||||
}
|
||||
|
||||
static void PR_CALLBACK DestroyCancelHTTPDownloadPLEvent(nsCancelHTTPDownloadEvent* aEvent)
|
||||
{
|
||||
delete aEvent;
|
||||
}
|
||||
|
||||
SECStatus nsNSSHttpServerSession::createSessionFcn(const char *host,
|
||||
PRUint16 portnum,
|
||||
SEC_HTTP_SERVER_SESSION *pSession)
|
||||
{
|
||||
if (!host || !pSession)
|
||||
return SECFailure;
|
||||
|
||||
nsNSSHttpServerSession *hss = new nsNSSHttpServerSession;
|
||||
if (!hss)
|
||||
return SECFailure;
|
||||
|
||||
hss->mHost = host;
|
||||
hss->mPort = portnum;
|
||||
|
||||
*pSession = hss;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session,
|
||||
const char *http_protocol_variant,
|
||||
const char *path_and_query_string,
|
||||
const char *http_request_method,
|
||||
const PRIntervalTime timeout,
|
||||
SEC_HTTP_REQUEST_SESSION *pRequest)
|
||||
{
|
||||
if (!session || !http_protocol_variant || !path_and_query_string ||
|
||||
!http_request_method || !pRequest)
|
||||
return SECFailure;
|
||||
|
||||
nsNSSHttpServerSession* hss = NS_STATIC_CAST(nsNSSHttpServerSession*, session);
|
||||
if (!hss)
|
||||
return SECFailure;
|
||||
|
||||
nsNSSHttpRequestSession *rs = new nsNSSHttpRequestSession;
|
||||
if (!rs)
|
||||
return SECFailure;
|
||||
|
||||
rs->mTimeoutInterval = timeout;
|
||||
|
||||
rs->mURL.Append(nsDependentCString(http_protocol_variant));
|
||||
rs->mURL.AppendLiteral("://");
|
||||
rs->mURL.Append(hss->mHost);
|
||||
rs->mURL.AppendLiteral(":");
|
||||
rs->mURL.AppendInt(hss->mPort);
|
||||
rs->mURL.Append(path_and_query_string);
|
||||
|
||||
rs->mRequestMethod = nsDependentCString(http_request_method);
|
||||
|
||||
*pRequest = (void*)rs;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus nsNSSHttpRequestSession::setPostDataFcn(const char *http_data,
|
||||
const PRUint32 http_data_len,
|
||||
const char *http_content_type)
|
||||
{
|
||||
mHasPostData = PR_TRUE;
|
||||
mPostData.Assign(http_data, http_data_len);
|
||||
mPostContentType.Assign(http_content_type);
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus nsNSSHttpRequestSession::addHeaderFcn(const char *http_header_name,
|
||||
const char *http_header_value)
|
||||
{
|
||||
return SECFailure; // not yet implemented
|
||||
|
||||
// All http code needs to be postponed to the UI thread.
|
||||
// Once this gets implemented, we need to add a string list member to
|
||||
// nsNSSHttpRequestSession and queue up the headers,
|
||||
// so they can be added in HandleHTTPDownloadPLEvent.
|
||||
//
|
||||
// The header will need to be set using
|
||||
// mHttpChannel->SetRequestHeader(nsDependentCString(http_header_name),
|
||||
// nsDependentCString(http_header_value),
|
||||
// PR_FALSE)));
|
||||
}
|
||||
|
||||
#define CONDITION_WAIT_TIME PR_MillisecondsToInterval(250)
|
||||
|
||||
SECStatus nsNSSHttpRequestSession::trySendAndReceiveFcn(PRPollDesc **pPollDesc,
|
||||
PRUint16 *http_response_code,
|
||||
const char **http_response_content_type,
|
||||
const char **http_response_headers,
|
||||
const char **http_response_data,
|
||||
PRUint32 *http_response_data_len)
|
||||
{
|
||||
if (nsIThread::IsMainThread())
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return SECFailure;
|
||||
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
|
||||
if (wwatch){
|
||||
nsCOMPtr<nsIPrompt> prompter;
|
||||
wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
|
||||
|
||||
nsString message;
|
||||
nssComponent->GetPIPNSSBundleString("OCSPDeadlock", message);
|
||||
|
||||
if(prompter) {
|
||||
nsPSMUITracker tracker;
|
||||
if (!tracker.isUIForbidden()) {
|
||||
prompter->Alert(0, message.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (pPollDesc) *pPollDesc = nsnull;
|
||||
if (http_response_code) *http_response_code = 0;
|
||||
if (http_response_content_type) *http_response_content_type = 0;
|
||||
if (http_response_headers) *http_response_headers = 0;
|
||||
if (http_response_data) *http_response_data = 0;
|
||||
|
||||
PRUint32 acceptableResultSize = 0;
|
||||
|
||||
if (http_response_data_len)
|
||||
{
|
||||
acceptableResultSize = *http_response_data_len;
|
||||
*http_response_data_len = 0;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventQueue> uiQueue = nsNSSEventGetUIEventQueue();
|
||||
if (!uiQueue)
|
||||
return SECFailure;
|
||||
|
||||
if (!mListener)
|
||||
return SECFailure;
|
||||
|
||||
if (NS_FAILED(mListener->InitLocks()))
|
||||
return SECFailure;
|
||||
|
||||
PRLock *waitLock = mListener->mLock;
|
||||
PRCondVar *waitCondition = mListener->mCondition;
|
||||
volatile PRBool &waitFlag = mListener->mWaitFlag;
|
||||
waitFlag = PR_TRUE;
|
||||
|
||||
nsHTTPDownloadEvent *event = new nsHTTPDownloadEvent;
|
||||
if (!event)
|
||||
return SECFailure;
|
||||
|
||||
event->mListener = mListener;
|
||||
event->mRequestSession = this;
|
||||
|
||||
PL_InitEvent(event, nsnull, (PLHandleEventProc)HandleHTTPDownloadPLEvent,
|
||||
(PLDestroyEventProc)DestroyHTTPDownloadPLEvent);
|
||||
nsresult rv = uiQueue->PostEvent(event);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
event->mResponsibleForDoneSignal = PR_FALSE;
|
||||
delete event;
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
PRBool request_canceled = PR_FALSE;
|
||||
PRBool aborted_wait = PR_FALSE;
|
||||
|
||||
{
|
||||
nsAutoLock locker(waitLock);
|
||||
|
||||
const PRIntervalTime start_time = PR_IntervalNow();
|
||||
const PRIntervalTime wait_interval = CONDITION_WAIT_TIME;
|
||||
|
||||
while (waitFlag)
|
||||
{
|
||||
PR_WaitCondVar(waitCondition, wait_interval);
|
||||
|
||||
if (!waitFlag)
|
||||
break;
|
||||
|
||||
if (!request_canceled)
|
||||
{
|
||||
if ((PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval)
|
||||
{
|
||||
request_canceled = PR_TRUE;
|
||||
// but we'll to continue to wait for waitFlag
|
||||
|
||||
nsCancelHTTPDownloadEvent *cancelevent = new nsCancelHTTPDownloadEvent;
|
||||
PL_InitEvent(cancelevent, nsnull, (PLHandleEventProc)HandleCancelHTTPDownloadPLEvent,
|
||||
(PLDestroyEventProc)DestroyCancelHTTPDownloadPLEvent);
|
||||
rv = uiQueue->PostEvent(cancelevent);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_WARNING("cannot post cancel event");
|
||||
delete cancelevent;
|
||||
aborted_wait = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aborted_wait)
|
||||
{
|
||||
// we couldn't cancel it, let's no longer reference it
|
||||
nsSSLThread::rememberPendingHTTPRequest(nsnull);
|
||||
}
|
||||
|
||||
if (request_canceled)
|
||||
return SECFailure;
|
||||
|
||||
if (NS_FAILED(mListener->mResultCode))
|
||||
return SECFailure;
|
||||
|
||||
if (http_response_code)
|
||||
*http_response_code = mListener->mHttpResponseCode;
|
||||
|
||||
if (mListener->mHttpRequestSucceeded && http_response_data && http_response_data_len) {
|
||||
|
||||
*http_response_data_len = mListener->mResultLen;
|
||||
|
||||
// acceptableResultSize == 0 means: any size is acceptable
|
||||
if (acceptableResultSize != 0
|
||||
&&
|
||||
acceptableResultSize < mListener->mResultLen)
|
||||
{
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// return data by reference, result data will be valid
|
||||
// until "this" gets destroyed by NSS
|
||||
*http_response_data = (const char*)mListener->mResultData;
|
||||
}
|
||||
|
||||
if (mListener->mHttpRequestSucceeded && http_response_content_type) {
|
||||
if (mListener->mHttpResponseContentType.Length()) {
|
||||
*http_response_content_type = mListener->mHttpResponseContentType.get();
|
||||
}
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus nsNSSHttpRequestSession::cancelFcn()
|
||||
{
|
||||
// As of today, only the blocking variant of the http interface
|
||||
// has been implemented. Implementing cancelFcn will be necessary
|
||||
// as soon as we implement the nonblocking variant.
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus nsNSSHttpRequestSession::freeFcn()
|
||||
{
|
||||
delete this;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
nsNSSHttpRequestSession::nsNSSHttpRequestSession()
|
||||
: mHasPostData(PR_FALSE),
|
||||
mTimeoutInterval(0),
|
||||
mListener(new nsHTTPListener)
|
||||
{
|
||||
}
|
||||
|
||||
nsNSSHttpRequestSession::~nsNSSHttpRequestSession()
|
||||
{
|
||||
}
|
||||
|
||||
SEC_HttpClientFcn nsNSSHttpInterface::sNSSInterfaceTable;
|
||||
|
||||
void nsNSSHttpInterface::initTable()
|
||||
{
|
||||
sNSSInterfaceTable.version = 1;
|
||||
SEC_HttpClientFcnV1 &v1 = sNSSInterfaceTable.fcnTable.ftable1;
|
||||
v1.createSessionFcn = createSessionFcn;
|
||||
v1.keepAliveSessionFcn = keepAliveFcn;
|
||||
v1.freeSessionFcn = freeSessionFcn;
|
||||
v1.createFcn = createFcn;
|
||||
v1.setPostDataFcn = setPostDataFcn;
|
||||
v1.addHeaderFcn = addHeaderFcn;
|
||||
v1.trySendAndReceiveFcn = trySendAndReceiveFcn;
|
||||
v1.cancelFcn = cancelFcn;
|
||||
v1.freeFcn = freeFcn;
|
||||
}
|
||||
|
||||
void nsNSSHttpInterface::registerHttpClient()
|
||||
{
|
||||
SEC_RegisterDefaultHttpClient(&sNSSInterfaceTable);
|
||||
}
|
||||
|
||||
void nsNSSHttpInterface::unregisterHttpClient()
|
||||
{
|
||||
SEC_RegisterDefaultHttpClient(nsnull);
|
||||
}
|
||||
|
||||
nsHTTPListener::nsHTTPListener()
|
||||
: mResultData(nsnull),
|
||||
mResultLen(0),
|
||||
mLock(nsnull),
|
||||
mCondition(nsnull),
|
||||
mWaitFlag(PR_TRUE),
|
||||
mResponsibleForDoneSignal(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult nsHTTPListener::InitLocks()
|
||||
{
|
||||
mLock = PR_NewLock();
|
||||
if (!mLock)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mCondition = PR_NewCondVar(mLock);
|
||||
if (!mCondition)
|
||||
{
|
||||
PR_DestroyLock(mLock);
|
||||
mLock = nsnull;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsHTTPListener::~nsHTTPListener()
|
||||
{
|
||||
if (mResponsibleForDoneSignal)
|
||||
send_done_signal();
|
||||
|
||||
if (mCondition)
|
||||
PR_DestroyCondVar(mCondition);
|
||||
|
||||
if (mLock)
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsHTTPListener, nsIStreamLoaderObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
PRUint32 stringLen,
|
||||
const PRUint8* string)
|
||||
{
|
||||
mResultCode = aStatus;
|
||||
|
||||
nsCOMPtr<nsIRequest> req;
|
||||
nsCOMPtr<nsIHttpChannel> hchan;
|
||||
|
||||
nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
hchan = do_QueryInterface(req, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
|
||||
if (NS_FAILED(rv))
|
||||
mHttpRequestSucceeded = PR_FALSE;
|
||||
|
||||
mResultLen = stringLen;
|
||||
mResultData = string; // reference. Make sure loader lives as long as this
|
||||
|
||||
unsigned int rcode;
|
||||
rv = hchan->GetResponseStatus(&rcode);
|
||||
if (NS_FAILED(rv))
|
||||
mHttpResponseCode = 500;
|
||||
else
|
||||
mHttpResponseCode = rcode;
|
||||
|
||||
hchan->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
|
||||
mHttpResponseContentType);
|
||||
}
|
||||
|
||||
if (mResponsibleForDoneSignal)
|
||||
send_done_signal();
|
||||
|
||||
return aStatus;
|
||||
}
|
||||
|
||||
void nsHTTPListener::send_done_signal()
|
||||
{
|
||||
nsSSLThread::rememberPendingHTTPRequest(nsnull);
|
||||
|
||||
mResponsibleForDoneSignal = PR_FALSE;
|
||||
|
||||
{
|
||||
nsAutoLock locker(mLock);
|
||||
mWaitFlag = PR_FALSE;
|
||||
PR_NotifyAllCondVar(mCondition);
|
||||
}
|
||||
}
|
||||
|
||||
/* Implementation of nsISSLStatus */
|
||||
class nsSSLStatus
|
||||
: public nsISSLStatus
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -42,6 +43,8 @@
|
|||
|
||||
#include "pk11func.h"
|
||||
#include "nspr.h"
|
||||
#include "ocspt.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
|
||||
char* PR_CALLBACK
|
||||
PK11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void* arg);
|
||||
|
@ -50,6 +53,180 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc *fd, void *client_data);
|
|||
SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
|
||||
PRBool checksig, PRBool isServer);
|
||||
|
||||
class nsHTTPListener : public nsIStreamLoaderObserver
|
||||
{
|
||||
private:
|
||||
// For XPCOM implementations that are not a base class for some other
|
||||
// class, it is good practice to make the destructor non-virtual and
|
||||
// private. Then the only way to delete the object is via Release.
|
||||
~nsHTTPListener();
|
||||
|
||||
public:
|
||||
nsHTTPListener();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMLOADEROBSERVER
|
||||
|
||||
nsCOMPtr<nsIStreamLoader> mLoader;
|
||||
|
||||
nsresult mResultCode;
|
||||
|
||||
PRBool mHttpRequestSucceeded;
|
||||
PRUint16 mHttpResponseCode;
|
||||
nsCString mHttpResponseContentType;
|
||||
|
||||
const PRUint8* mResultData; // not owned, refers to mLoader
|
||||
PRUint32 mResultLen;
|
||||
|
||||
nsresult InitLocks();
|
||||
|
||||
PRLock *mLock;
|
||||
PRCondVar *mCondition;
|
||||
volatile PRBool mWaitFlag;
|
||||
|
||||
PRBool mResponsibleForDoneSignal;
|
||||
void send_done_signal();
|
||||
};
|
||||
|
||||
class nsNSSHttpServerSession
|
||||
{
|
||||
public:
|
||||
nsCString mHost;
|
||||
PRUint16 mPort;
|
||||
|
||||
static SECStatus createSessionFcn(const char *host,
|
||||
PRUint16 portnum,
|
||||
SEC_HTTP_SERVER_SESSION *pSession);
|
||||
};
|
||||
|
||||
class nsNSSHttpRequestSession
|
||||
{
|
||||
public:
|
||||
static SECStatus createFcn(SEC_HTTP_SERVER_SESSION session,
|
||||
const char *http_protocol_variant,
|
||||
const char *path_and_query_string,
|
||||
const char *http_request_method,
|
||||
const PRIntervalTime timeout,
|
||||
SEC_HTTP_REQUEST_SESSION *pRequest);
|
||||
|
||||
SECStatus setPostDataFcn(const char *http_data,
|
||||
const PRUint32 http_data_len,
|
||||
const char *http_content_type);
|
||||
|
||||
SECStatus addHeaderFcn(const char *http_header_name,
|
||||
const char *http_header_value);
|
||||
|
||||
SECStatus trySendAndReceiveFcn(PRPollDesc **pPollDesc,
|
||||
PRUint16 *http_response_code,
|
||||
const char **http_response_content_type,
|
||||
const char **http_response_headers,
|
||||
const char **http_response_data,
|
||||
PRUint32 *http_response_data_len);
|
||||
|
||||
SECStatus cancelFcn();
|
||||
SECStatus freeFcn();
|
||||
|
||||
nsCString mURL;
|
||||
nsCString mRequestMethod;
|
||||
|
||||
PRBool mHasPostData;
|
||||
nsCString mPostData;
|
||||
nsCString mPostContentType;
|
||||
|
||||
PRIntervalTime mTimeoutInterval;
|
||||
|
||||
nsCOMPtr<nsHTTPListener> mListener;
|
||||
|
||||
protected:
|
||||
nsNSSHttpRequestSession();
|
||||
~nsNSSHttpRequestSession();
|
||||
};
|
||||
|
||||
class nsNSSHttpInterface
|
||||
{
|
||||
public:
|
||||
static SECStatus createSessionFcn(const char *host,
|
||||
PRUint16 portnum,
|
||||
SEC_HTTP_SERVER_SESSION *pSession)
|
||||
{
|
||||
return nsNSSHttpServerSession::createSessionFcn(host, portnum, pSession);
|
||||
}
|
||||
|
||||
static SECStatus keepAliveFcn(SEC_HTTP_SERVER_SESSION session,
|
||||
PRPollDesc **pPollDesc)
|
||||
{
|
||||
// Not yet implemented, however, Necko does transparent keep-alive
|
||||
// anyway, when enabled in Necko's prefs.
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus freeSessionFcn(SEC_HTTP_SERVER_SESSION session)
|
||||
{
|
||||
delete NS_STATIC_CAST(nsNSSHttpServerSession*, session);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus createFcn(SEC_HTTP_SERVER_SESSION session,
|
||||
const char *http_protocol_variant,
|
||||
const char *path_and_query_string,
|
||||
const char *http_request_method,
|
||||
const PRIntervalTime timeout,
|
||||
SEC_HTTP_REQUEST_SESSION *pRequest)
|
||||
{
|
||||
return nsNSSHttpRequestSession::createFcn(session, http_protocol_variant,
|
||||
path_and_query_string, http_request_method,
|
||||
timeout, pRequest);
|
||||
}
|
||||
|
||||
static SECStatus setPostDataFcn(SEC_HTTP_REQUEST_SESSION request,
|
||||
const char *http_data,
|
||||
const PRUint32 http_data_len,
|
||||
const char *http_content_type)
|
||||
{
|
||||
return NS_STATIC_CAST(nsNSSHttpRequestSession*, request)
|
||||
->setPostDataFcn(http_data, http_data_len, http_content_type);
|
||||
}
|
||||
|
||||
static SECStatus addHeaderFcn(SEC_HTTP_REQUEST_SESSION request,
|
||||
const char *http_header_name,
|
||||
const char *http_header_value)
|
||||
{
|
||||
return NS_STATIC_CAST(nsNSSHttpRequestSession*, request)
|
||||
->addHeaderFcn(http_header_name, http_header_value);
|
||||
}
|
||||
|
||||
static SECStatus trySendAndReceiveFcn(SEC_HTTP_REQUEST_SESSION request,
|
||||
PRPollDesc **pPollDesc,
|
||||
PRUint16 *http_response_code,
|
||||
const char **http_response_content_type,
|
||||
const char **http_response_headers,
|
||||
const char **http_response_data,
|
||||
PRUint32 *http_response_data_len)
|
||||
{
|
||||
return NS_STATIC_CAST(nsNSSHttpRequestSession*, request)
|
||||
->trySendAndReceiveFcn(pPollDesc, http_response_code, http_response_content_type,
|
||||
http_response_headers, http_response_data, http_response_data_len);
|
||||
}
|
||||
|
||||
static SECStatus cancelFcn(SEC_HTTP_REQUEST_SESSION request)
|
||||
{
|
||||
return NS_STATIC_CAST(nsNSSHttpRequestSession*, request)
|
||||
->cancelFcn();
|
||||
}
|
||||
|
||||
static SECStatus freeFcn(SEC_HTTP_REQUEST_SESSION request)
|
||||
{
|
||||
return NS_STATIC_CAST(nsNSSHttpRequestSession*, request)
|
||||
->freeFcn();
|
||||
}
|
||||
|
||||
static void initTable();
|
||||
static SEC_HttpClientFcn sNSSInterfaceTable;
|
||||
|
||||
void registerHttpClient();
|
||||
void unregisterHttpClient();
|
||||
};
|
||||
|
||||
#endif // _NSNSSCALLBACKS_H_
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Ian McGreer <mcgreer@netscape.com>
|
||||
* Javier Delgadillo <javi@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "nsPKCS12Blob.h"
|
||||
#include "nsPK11TokenDB.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsISMimeCert.h"
|
||||
#include "nsNSSASN1Object.h"
|
||||
#include "nsString.h"
|
||||
|
@ -64,6 +66,7 @@
|
|||
#include "nsNSSCertHelper.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsCertVerificationThread.h"
|
||||
|
||||
#include "nspr.h"
|
||||
extern "C" {
|
||||
|
@ -88,8 +91,9 @@ static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|||
|
||||
/* nsNSSCertificate */
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(nsNSSCertificate, nsIX509Cert,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS4(nsNSSCertificate, nsIX509Cert,
|
||||
nsIX509Cert2,
|
||||
nsIX509Cert3,
|
||||
nsISMimeCert)
|
||||
|
||||
nsNSSCertificate*
|
||||
|
@ -1052,6 +1056,26 @@ nsNSSCertificate::GetUsagesArray(PRBool ignoreOcsp,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificate::RequestUsagesArrayAsync(nsICertVerificationListener *aResultListener)
|
||||
{
|
||||
if (!aResultListener)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCertVerificationJob *job = new nsCertVerificationJob;
|
||||
if (!job)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
job->mCert = this;
|
||||
job->mListener = aResultListener;
|
||||
|
||||
nsresult rv = nsCertVerificationThread::addJob(job);
|
||||
if (NS_FAILED(rv))
|
||||
delete job;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
|
||||
PRUint32 *_verified,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Ian McGreer <mcgreer@netscape.com>
|
||||
* Javier Delgadillo <javi@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -41,6 +42,7 @@
|
|||
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509Cert2.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsIX509CertDB.h"
|
||||
#include "nsIX509CertList.h"
|
||||
#include "nsIASN1Object.h"
|
||||
|
@ -56,6 +58,7 @@ class nsIASN1Sequence;
|
|||
/* Certificate */
|
||||
class nsNSSCertificate : public nsIX509Cert,
|
||||
public nsIX509Cert2,
|
||||
public nsIX509Cert3,
|
||||
public nsISMimeCert,
|
||||
public nsNSSShutDownObject
|
||||
{
|
||||
|
@ -63,6 +66,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIX509CERT
|
||||
NS_DECL_NSIX509CERT2
|
||||
NS_DECL_NSIX509CERT3
|
||||
NS_DECL_NSISMIMECERT
|
||||
|
||||
nsNSSCertificate(CERTCertificate *cert);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
* Mitch Stoltz <mstoltz@netscape.com>
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Kai Engert <kaie@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -44,6 +45,8 @@
|
|||
#include "nsNSSComponent.h"
|
||||
#include "nsNSSCallbacks.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
#include "nsSSLThread.h"
|
||||
#include "nsCertVerificationThread.h"
|
||||
#include "nsNSSEvent.h"
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -290,14 +293,33 @@ nsNSSComponent::nsNSSComponent()
|
|||
mCrlTimerLock = nsnull;
|
||||
mObserversRegistered = PR_FALSE;
|
||||
|
||||
nsSSLIOLayerHelpers::Init();
|
||||
|
||||
NS_ASSERTION( (0 == mInstanceCount), "nsNSSComponent is a singleton, but instantiated multiple times!");
|
||||
++mInstanceCount;
|
||||
hashTableCerts = nsnull;
|
||||
mShutdownObjectList = nsNSSShutDownList::construct();
|
||||
mIsNetworkDown = PR_FALSE;
|
||||
mSSLThread = new nsSSLThread();
|
||||
mCertVerificationThread = new nsCertVerificationThread();
|
||||
}
|
||||
|
||||
nsNSSComponent::~nsNSSComponent()
|
||||
{
|
||||
if (mSSLThread)
|
||||
{
|
||||
mSSLThread->requestExit();
|
||||
delete mSSLThread;
|
||||
mSSLThread = nsnull;
|
||||
}
|
||||
|
||||
if (mCertVerificationThread)
|
||||
{
|
||||
mCertVerificationThread->requestExit();
|
||||
delete mCertVerificationThread;
|
||||
mCertVerificationThread = nsnull;
|
||||
}
|
||||
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor\n"));
|
||||
|
||||
if(mUpdateTimerInitialized == PR_TRUE){
|
||||
|
@ -319,7 +341,7 @@ nsNSSComponent::~nsNSSComponent()
|
|||
// All cleanup code requiring services needs to happen in xpcom_shutdown
|
||||
|
||||
ShutdownNSS();
|
||||
nsSSLIOLayerFreeTLSIntolerantSites();
|
||||
nsSSLIOLayerHelpers::Cleanup();
|
||||
--mInstanceCount;
|
||||
delete mShutdownObjectList;
|
||||
|
||||
|
@ -1455,6 +1477,9 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
|
|||
// Set up OCSP //
|
||||
setOCSPOptions(mPrefBranch);
|
||||
|
||||
mHttpForNSS.initTable();
|
||||
mHttpForNSS.registerHttpClient();
|
||||
|
||||
InstallLoadableRoots();
|
||||
|
||||
LaunchSmartCardThreads();
|
||||
|
@ -1499,6 +1524,7 @@ nsNSSComponent::ShutdownNSS()
|
|||
mNSSInitialized = PR_FALSE;
|
||||
|
||||
PK11_SetPasswordFunc((PK11PasswordFunc)nsnull);
|
||||
mHttpForNSS.unregisterHttpClient();
|
||||
|
||||
if (mPrefBranch) {
|
||||
nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
|
||||
|
@ -1530,6 +1556,14 @@ nsNSSComponent::Init()
|
|||
nsresult rv = NS_OK;
|
||||
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Beginning NSS initialization\n"));
|
||||
|
||||
if (!mutex || !mShutdownObjectList ||
|
||||
!mSSLThread || !mCertVerificationThread)
|
||||
{
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, out of memory in constructor\n"));
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = InitializePIPNSSBundle();
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to create pipnss bundle.\n"));
|
||||
|
@ -1744,13 +1778,8 @@ nsNSSComponent::RandomUpdate(void *entropy, PRInt32 bufLen)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#define DEBUG_PSM_PROFILE
|
||||
|
||||
#ifdef DEBUG_PSM_PROFILE
|
||||
#define PROFILE_CHANGE_NET_TEARDOWN_TOPIC "profile-change-net-teardown"
|
||||
#define PROFILE_CHANGE_NET_RESTORE_TOPIC "profile-change-net-restore"
|
||||
#endif
|
||||
|
||||
#define PROFILE_APPROVE_CHANGE_TOPIC "profile-approve-change"
|
||||
#define PROFILE_CHANGE_TEARDOWN_TOPIC "profile-change-teardown"
|
||||
#define PROFILE_CHANGE_TEARDOWN_VETO_TOPIC "profile-change-teardown-veto"
|
||||
|
@ -1762,10 +1791,6 @@ NS_IMETHODIMP
|
|||
nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
const PRUnichar *someData)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
static PRBool isNetworkDown = PR_FALSE;
|
||||
#endif
|
||||
|
||||
if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) {
|
||||
if (mShutdownObjectList->isUIActive()) {
|
||||
ShowAlert(ai_crypto_ui_active);
|
||||
|
@ -1801,9 +1826,7 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
|||
}
|
||||
else if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) {
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving profile change topic\n"));
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(isNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
|
||||
#endif
|
||||
NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
|
||||
|
||||
PRBool needsCleanup = PR_TRUE;
|
||||
|
||||
|
@ -1918,17 +1941,22 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
|
||||
isNetworkDown = PR_TRUE;
|
||||
if (mSSLThread)
|
||||
mSSLThread->requestExit();
|
||||
if (mCertVerificationThread)
|
||||
mCertVerificationThread->requestExit();
|
||||
mIsNetworkDown = PR_TRUE;
|
||||
}
|
||||
else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_RESTORE_TOPIC) == 0) {
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network restore topic\n"));
|
||||
isNetworkDown = PR_FALSE;
|
||||
delete mSSLThread;
|
||||
mSSLThread = new nsSSLThread();
|
||||
delete mCertVerificationThread;
|
||||
mCertVerificationThread = new nsCertVerificationThread();
|
||||
mIsNetworkDown = PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2019,10 +2047,8 @@ nsNSSComponent::RegisterObservers()
|
|||
observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, PR_FALSE);
|
||||
observerService->AddObserver(this, PROFILE_AFTER_CHANGE_TOPIC, PR_FALSE);
|
||||
observerService->AddObserver(this, SESSION_LOGOUT_TOPIC, PR_FALSE);
|
||||
#ifdef DEBUG
|
||||
observerService->AddObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC, PR_FALSE);
|
||||
observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, PR_FALSE);
|
||||
#endif
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2370,8 +2396,8 @@ PSMContentDownloader::OnDataAvailable(nsIRequest* request,
|
|||
do {
|
||||
err = aIStream->Read(mByteData+mBufferOffset,
|
||||
aLength, &amt);
|
||||
if (amt == 0) break;
|
||||
if (NS_FAILED(err)) return err;
|
||||
if (amt == 0) break;
|
||||
|
||||
aLength -= amt;
|
||||
mBufferOffset += amt;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* Doug Turner <dougt@netscape.com>
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Kai Engert <kaie@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -63,6 +64,7 @@
|
|||
#include "prlock.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "hasht.h"
|
||||
#include "nsNSSCallbacks.h"
|
||||
|
||||
#include "nsNSSHelper.h"
|
||||
|
||||
|
@ -177,6 +179,8 @@ private:
|
|||
|
||||
struct PRLock;
|
||||
class nsNSSShutDownList;
|
||||
class nsSSLThread;
|
||||
class nsCertVerificationThread;
|
||||
|
||||
// Implementation of the PSM component interface.
|
||||
class nsNSSComponent : public nsISignatureVerifier,
|
||||
|
@ -269,6 +273,10 @@ private:
|
|||
static int mInstanceCount;
|
||||
nsNSSShutDownList *mShutdownObjectList;
|
||||
SmartCardThreadList *mThreadList;
|
||||
PRBool mIsNetworkDown;
|
||||
nsSSLThread *mSSLThread;
|
||||
nsCertVerificationThread *mCertVerificationThread;
|
||||
nsNSSHttpInterface mHttpForNSS;
|
||||
};
|
||||
|
||||
class PSMContentListener : public nsIURIContentListener,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Javier Delgadillo <javi@netscape.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -63,6 +64,8 @@
|
|||
#include "nsHashSets.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsSSLThread.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsNSSCertHelper.h"
|
||||
|
||||
|
@ -99,11 +102,6 @@ nsNSS_SSLGetClientAuthData(void *arg, PRFileDesc *socket,
|
|||
CERTDistNames *caNames,
|
||||
CERTCertificate **pRetCert,
|
||||
SECKEYPrivateKey **pRetKey);
|
||||
static PRBool firstTime = PR_TRUE;
|
||||
static PRDescIdentity nsSSLIOLayerIdentity;
|
||||
static PRIOMethods nsSSLIOLayerMethods;
|
||||
static nsCStringHashSet *gTLSIntolerantSites = nsnull;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gPIPNSSLog;
|
||||
#endif
|
||||
|
@ -135,6 +133,45 @@ void MyLogFunction(const char *fmt, ...)
|
|||
#endif
|
||||
|
||||
|
||||
nsSSLSocketThreadData::nsSSLSocketThreadData()
|
||||
: mSSLState(ssl_idle)
|
||||
, mPRErrorCode(PR_SUCCESS)
|
||||
, mSSLDataBuffer(nsnull)
|
||||
, mSSLDataBufferAllocatedSize(0)
|
||||
, mSSLRequestedTransferAmount(0)
|
||||
, mSSLRemainingReadResultData(nsnull)
|
||||
, mSSLResultRemainingBytes(0)
|
||||
, mReplacedSSLFileDesc(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
nsSSLSocketThreadData::~nsSSLSocketThreadData()
|
||||
{
|
||||
NS_ASSERTION(mSSLState != ssl_pending_write
|
||||
&&
|
||||
mSSLState != ssl_pending_read,
|
||||
"oops??? ssl socket is not idle at the time it is being destroyed");
|
||||
}
|
||||
|
||||
PRBool nsSSLSocketThreadData::ensure_buffer_size(PRInt32 amount)
|
||||
{
|
||||
if (amount > mSSLDataBufferAllocatedSize) {
|
||||
if (mSSLDataBuffer) {
|
||||
mSSLDataBuffer = (char*)nsMemory::Realloc(mSSLDataBuffer, amount);
|
||||
}
|
||||
else {
|
||||
mSSLDataBuffer = (char*)nsMemory::Alloc(amount);
|
||||
}
|
||||
|
||||
if (!mSSLDataBuffer)
|
||||
return PR_FALSE;
|
||||
|
||||
mSSLDataBufferAllocatedSize = amount;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo::nsNSSSocketInfo()
|
||||
: mFd(nsnull),
|
||||
mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
|
||||
|
@ -146,10 +183,13 @@ nsNSSSocketInfo::nsNSSSocketInfo()
|
|||
mPort(0),
|
||||
mCAChain(nsnull)
|
||||
{
|
||||
mThreadData = new nsSSLSocketThreadData;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo::~nsNSSSocketInfo()
|
||||
{
|
||||
delete mThreadData;
|
||||
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown())
|
||||
return;
|
||||
|
@ -369,11 +409,10 @@ nsresult nsNSSSocketInfo::ActivateSSL()
|
|||
if (isAlreadyShutDown())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, PR_TRUE))
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = nsSSLThread::requestActivateSSL(this);
|
||||
|
||||
if (SECSuccess != SSL_ResetHandshake(mFd, PR_FALSE))
|
||||
return NS_ERROR_FAILURE;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mHandshakePending = PR_TRUE;
|
||||
|
||||
|
@ -422,14 +461,18 @@ nsresult nsNSSSocketInfo::SetSSLStatus(nsISSLStatus *aSSLStatus)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSSLIOLayerFreeTLSIntolerantSites()
|
||||
void nsSSLIOLayerHelpers::Cleanup()
|
||||
{
|
||||
if (gTLSIntolerantSites) {
|
||||
delete gTLSIntolerantSites;
|
||||
gTLSIntolerantSites = nsnull;
|
||||
if (mTLSIntolerantSites) {
|
||||
delete mTLSIntolerantSites;
|
||||
mTLSIntolerantSites = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
if (mSharedPollableEvent)
|
||||
PR_DestroyPollableEvent(mSharedPollableEvent);
|
||||
|
||||
if (mutex)
|
||||
PR_DestroyLock(mutex);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
|
@ -873,26 +916,14 @@ nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
|
|||
return status;
|
||||
}
|
||||
|
||||
static PRInt32 PR_CALLBACK
|
||||
nsSSLIOLayerAvailable(PRFileDesc *fd)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower)
|
||||
return PR_FAILURE;
|
||||
|
||||
PRInt32 bytesAvailable = SSL_DataPending(fd->lower);
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] available %d bytes\n", (void*)fd, bytesAvailable));
|
||||
return bytesAvailable;
|
||||
}
|
||||
|
||||
// Call this function to report a site that is possibly TLS intolerant.
|
||||
// This function will return true, if the given socket is currently using TLS.
|
||||
static PRBool
|
||||
rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo)
|
||||
PRBool
|
||||
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
|
||||
{
|
||||
PRBool currentlyUsesTLS = PR_FALSE;
|
||||
|
||||
SSL_OptionGet(fd->lower, SSL_ENABLE_TLS, ¤tlyUsesTLS);
|
||||
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, ¤tlyUsesTLS);
|
||||
if (currentlyUsesTLS) {
|
||||
// Add this site to the list of TLS intolerant sites.
|
||||
PRInt32 port;
|
||||
|
@ -901,8 +932,8 @@ rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo)
|
|||
socketInfo->GetHostName(getter_Copies(host));
|
||||
nsCAutoString key;
|
||||
key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
|
||||
// If it's in the set, that means it's TLS intolerant.
|
||||
gTLSIntolerantSites->Put(key);
|
||||
|
||||
addIntolerantSite(key);
|
||||
}
|
||||
|
||||
return currentlyUsesTLS;
|
||||
|
@ -917,23 +948,32 @@ nsSSLIOLayerClose(PRFileDesc *fd)
|
|||
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestClose(socketInfo);
|
||||
}
|
||||
|
||||
PRStatus nsNSSSocketInfo::CloseSocketAndDestroy()
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
|
||||
nsNSSShutDownList::trackSSLSocketClose();
|
||||
|
||||
PRFileDesc* popped = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
|
||||
nsNSSSocketInfo *infoObject = (nsNSSSocketInfo *)popped->secret;
|
||||
PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
|
||||
|
||||
if (infoObject->GetHandshakeInProgress()) {
|
||||
rememberPossibleTLSProblemSite(fd, infoObject);
|
||||
if (GetHandshakeInProgress()) {
|
||||
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(mFd->lower, this);
|
||||
}
|
||||
|
||||
PRStatus status = fd->methods->close(fd);
|
||||
PRStatus status = mFd->methods->close(mFd);
|
||||
if (status != PR_SUCCESS) return status;
|
||||
|
||||
popped->identity = PR_INVALID_IO_LAYER;
|
||||
NS_RELEASE(infoObject);
|
||||
NS_RELEASE_THIS();
|
||||
popped->dtor(popped);
|
||||
|
||||
return status;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
|
||||
|
@ -1021,8 +1061,8 @@ isTLSIntoleranceError(PRInt32 err, PRBool withInitialCleartext)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
static PRInt32
|
||||
checkHandshake(PRInt32 bytesTransfered, PRFileDesc* fd, nsNSSSocketInfo *socketInfo)
|
||||
PRInt32
|
||||
nsSSLThread::checkHandshake(PRInt32 bytesTransfered, PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
|
||||
{
|
||||
// This is where we work around all of those SSL servers that don't
|
||||
// conform to the SSL spec and shutdown a connection when we request
|
||||
|
@ -1062,7 +1102,7 @@ checkHandshake(PRInt32 bytesTransfered, PRFileDesc* fd, nsNSSSocketInfo *socketI
|
|||
// to retry without TLS.
|
||||
|
||||
if (isTLSIntoleranceError(err, withInitialCleartext)) {
|
||||
wantRetry = rememberPossibleTLSProblemSite(fd, socketInfo);
|
||||
wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
|
||||
|
||||
if (wantRetry) {
|
||||
// We want to cause the network layer to retry the connection.
|
||||
|
@ -1087,6 +1127,26 @@ checkHandshake(PRInt32 bytesTransfered, PRFileDesc* fd, nsNSSSocketInfo *socketI
|
|||
return bytesTransfered;
|
||||
}
|
||||
|
||||
static PRInt16 PR_CALLBACK
|
||||
nsSSLIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
|
||||
if (out_flags)
|
||||
*out_flags = 0;
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
NS_WARNING("nsSSLIOLayerPoll called with null fd");
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestPoll(socketInfo, in_flags, out_flags);
|
||||
}
|
||||
|
||||
static PRInt32 PR_CALLBACK
|
||||
nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
|
||||
{
|
||||
|
@ -1095,26 +1155,10 @@ nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
|
|||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = nsnull;
|
||||
socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
if (socketInfo->isPK11LoggedOut() || socketInfo->isAlreadyShutDown()) {
|
||||
PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (socketInfo->GetCanceled()) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
PRInt32 bytesRead = fd->lower->methods->read(fd->lower, buf, amount);
|
||||
#ifdef DEBUG_SSL_VERBOSE
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*)fd, bytesRead));
|
||||
DEBUG_DUMP_BUFFER((unsigned char*)buf, bytesRead);
|
||||
#endif
|
||||
|
||||
return checkHandshake(bytesRead, fd, socketInfo);
|
||||
return nsSSLThread::requestRead(socketInfo, buf, amount);
|
||||
}
|
||||
|
||||
static PRInt32 PR_CALLBACK
|
||||
|
@ -1128,37 +1172,213 @@ nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, PRInt32 amount)
|
|||
#ifdef DEBUG_SSL_VERBOSE
|
||||
DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
|
||||
#endif
|
||||
nsNSSSocketInfo *socketInfo = nsnull;
|
||||
socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
if (socketInfo->isPK11LoggedOut() || socketInfo->isAlreadyShutDown()) {
|
||||
PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
return nsSSLThread::requestWrite(socketInfo, buf, amount);
|
||||
}
|
||||
|
||||
if (socketInfo->GetCanceled()) {
|
||||
PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
|
||||
PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
|
||||
PRLock *nsSSLIOLayerHelpers::mutex = nsnull;
|
||||
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
|
||||
PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull;
|
||||
nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
|
||||
PRBool nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_FALSE;
|
||||
|
||||
static PRIntn _PSM_InvalidInt(void)
|
||||
{
|
||||
PR_ASSERT(!"I/O method is invalid");
|
||||
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PRInt64 _PSM_InvalidInt64(void)
|
||||
{
|
||||
PR_ASSERT(!"I/O method is invalid");
|
||||
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PRStatus _PSM_InvalidStatus(void)
|
||||
{
|
||||
PR_ASSERT(!"I/O method is invalid");
|
||||
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
static PRFileDesc *_PSM_InvalidDesc(void)
|
||||
{
|
||||
PR_ASSERT(!"I/O method is invalid");
|
||||
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PRStatus PR_CALLBACK PSMGetsockname(PRFileDesc *fd, PRNetAddr *addr)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
PRInt32 bytesWritten = fd->lower->methods->write(fd->lower, buf, amount);
|
||||
#ifdef DEBUG_SSL_VERBOSE
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n", (void*)fd, bytesWritten));
|
||||
#endif
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return checkHandshake(bytesWritten, fd, socketInfo);
|
||||
return nsSSLThread::requestGetsockname(socketInfo, addr);
|
||||
}
|
||||
|
||||
static void InitNSSMethods()
|
||||
static PRStatus PR_CALLBACK PSMGetpeername(PRFileDesc *fd, PRNetAddr *addr)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestGetpeername(socketInfo, addr);
|
||||
}
|
||||
|
||||
static PRStatus PR_CALLBACK PSMGetsocketoption(PRFileDesc *fd,
|
||||
PRSocketOptionData *data)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestGetsocketoption(socketInfo, data);
|
||||
}
|
||||
|
||||
static PRStatus PR_CALLBACK PSMSetsocketoption(PRFileDesc *fd,
|
||||
const PRSocketOptionData *data)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestSetsocketoption(socketInfo, data);
|
||||
}
|
||||
|
||||
static PRInt32 PR_CALLBACK PSMRecv(PRFileDesc *fd, void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRIntervalTime timeout)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags != PR_MSG_PEEK)
|
||||
{
|
||||
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestRecvMsgPeek(socketInfo, buf, amount, flags, timeout);
|
||||
}
|
||||
|
||||
static PRInt32 PR_CALLBACK PSMSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRIntervalTime timeout)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PRStatus PR_CALLBACK PSMConnectcontinue(PRFileDesc *fd, PRInt16 out_flags)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!fd || !fd->lower) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||
|
||||
return nsSSLThread::requestConnectcontinue(socketInfo, out_flags);
|
||||
}
|
||||
|
||||
nsresult nsSSLIOLayerHelpers::Init()
|
||||
{
|
||||
nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
|
||||
nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
|
||||
|
||||
nsSSLIOLayerMethods.available = (PRAvailableFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.available64 = (PRAvailable64FN)_PSM_InvalidInt64;
|
||||
nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
|
||||
nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
|
||||
nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
|
||||
nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
|
||||
nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
|
||||
nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
|
||||
nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
|
||||
nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
|
||||
nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
|
||||
nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
|
||||
|
||||
nsSSLIOLayerMethods.getsockname = PSMGetsockname;
|
||||
nsSSLIOLayerMethods.getpeername = PSMGetpeername;
|
||||
nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
|
||||
nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
|
||||
nsSSLIOLayerMethods.recv = PSMRecv;
|
||||
nsSSLIOLayerMethods.send = PSMSend;
|
||||
nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
|
||||
|
||||
nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
|
||||
nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
|
||||
nsSSLIOLayerMethods.available = nsSSLIOLayerAvailable;
|
||||
nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
|
||||
nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
|
||||
nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
|
||||
|
||||
mutex = PR_NewLock();
|
||||
if (!mutex)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mSharedPollableEvent = PR_NewPollableEvent();
|
||||
if (!mSharedPollableEvent)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mTLSIntolerantSites = new nsCStringHashSet();
|
||||
if (!mTLSIntolerantSites)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mTLSIntolerantSites->Init(1);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
|
||||
{
|
||||
nsAutoLock lock(mutex);
|
||||
nsSSLIOLayerHelpers::mTLSIntolerantSites->Put(str);
|
||||
}
|
||||
|
||||
PRBool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
|
||||
{
|
||||
nsAutoLock lock(mutex);
|
||||
return mTLSIntolerantSites->Contains(str);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1171,15 +1391,6 @@ nsSSLIOLayerNewSocket(PRInt32 family,
|
|||
nsISupports** info,
|
||||
PRBool forSTARTTLS)
|
||||
{
|
||||
// XXX - this code is duplicated in nsSSLIOLayerAddToSocket
|
||||
if (firstTime) {
|
||||
InitNSSMethods();
|
||||
gTLSIntolerantSites = new nsCStringHashSet();
|
||||
if (!gTLSIntolerantSites)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
gTLSIntolerantSites->Init(1);
|
||||
firstTime = PR_FALSE;
|
||||
}
|
||||
|
||||
PRFileDesc* sock = PR_OpenTCPSocket(family);
|
||||
if (!sock) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -2280,7 +2491,8 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, PRBool forSTARTTLS,
|
|||
// TLS intolerant.
|
||||
nsCAutoString key;
|
||||
key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
|
||||
if (gTLSIntolerantSites->Contains(key) &&
|
||||
|
||||
if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key) &&
|
||||
SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, PR_FALSE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2318,16 +2530,6 @@ nsSSLIOLayerAddToSocket(PRInt32 family,
|
|||
PRFileDesc* layer = nsnull;
|
||||
nsresult rv;
|
||||
|
||||
// XXX - this code is duplicated in nsSSLIONewSocket
|
||||
if (firstTime) {
|
||||
InitNSSMethods();
|
||||
gTLSIntolerantSites = new nsCStringHashSet();
|
||||
if (!gTLSIntolerantSites)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
gTLSIntolerantSites->Init(1);
|
||||
firstTime = PR_FALSE;
|
||||
}
|
||||
|
||||
nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
|
||||
if (!infoObject) return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -2351,8 +2553,8 @@ nsSSLIOLayerAddToSocket(PRInt32 family,
|
|||
goto loser;
|
||||
|
||||
/* Now, layer ourselves on top of the SSL socket... */
|
||||
layer = PR_CreateIOLayerStub(nsSSLIOLayerIdentity,
|
||||
&nsSSLIOLayerMethods);
|
||||
layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
|
||||
&nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
|
||||
if (!layer)
|
||||
goto loser;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Kai Engert <kengert@redhat.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -54,6 +55,65 @@
|
|||
#include "nsNSSShutDown.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsSSLThread;
|
||||
|
||||
/*
|
||||
* This class is used to store SSL socket I/O state information,
|
||||
* that is not being executed directly, but defered to
|
||||
* the separate SSL thread.
|
||||
*/
|
||||
class nsSSLSocketThreadData
|
||||
{
|
||||
public:
|
||||
nsSSLSocketThreadData();
|
||||
~nsSSLSocketThreadData();
|
||||
|
||||
PRBool ensure_buffer_size(PRInt32 amount);
|
||||
|
||||
enum ssl_state {
|
||||
ssl_idle, // not in use by SSL thread, no activity pending
|
||||
ssl_pending_write, // waiting for SSL thread to complete writing
|
||||
ssl_pending_read, // waiting for SSL thread to complete reading
|
||||
ssl_writing_done, // SSL write completed, results are ready
|
||||
ssl_reading_done // SSL read completed, results are ready
|
||||
};
|
||||
|
||||
ssl_state mSSLState;
|
||||
|
||||
// Used to transport I/O error codes between SSL thread
|
||||
// and initial caller thread.
|
||||
PRErrorCode mPRErrorCode;
|
||||
|
||||
// A buffer used to transfer I/O data between threads
|
||||
char *mSSLDataBuffer;
|
||||
PRInt32 mSSLDataBufferAllocatedSize;
|
||||
|
||||
// The amount requested to read or write by the caller.
|
||||
PRInt32 mSSLRequestedTransferAmount;
|
||||
|
||||
// A pointer into our buffer, to the first byte
|
||||
// that has not yet been delivered to the caller.
|
||||
// Necessary, as the caller of the read function
|
||||
// might request smaller chunks.
|
||||
const char *mSSLRemainingReadResultData;
|
||||
|
||||
// The caller previously requested to read or write.
|
||||
// As the initial request to read or write is defered,
|
||||
// the caller might (in theory) request smaller chunks
|
||||
// in subsequent calls.
|
||||
// This variable stores the amount of bytes successfully
|
||||
// transfered, that have not yet been reported to the caller.
|
||||
PRInt32 mSSLResultRemainingBytes;
|
||||
|
||||
// When defering SSL read/write activity to another thread,
|
||||
// we switch the SSL level file descriptor of the original
|
||||
// layered file descriptor to a pollable event,
|
||||
// so we can wake up the original caller of the I/O function
|
||||
// as soon as data is ready.
|
||||
// This variable is used to save the SSL level file descriptor,
|
||||
// to allow us to restore the original file descriptor layering.
|
||||
PRFileDesc *mReplacedSSLFileDesc;
|
||||
};
|
||||
|
||||
class nsNSSSocketInfo : public nsITransportSecurityInfo,
|
||||
public nsISSLSocketControl,
|
||||
|
@ -104,6 +164,8 @@ public:
|
|||
/* Set SSL Status values */
|
||||
nsresult SetSSLStatus(nsISSLStatus *aSSLStatus);
|
||||
|
||||
PRStatus CloseSocketAndDestroy();
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
PRFileDesc* mFd;
|
||||
|
@ -122,9 +184,39 @@ protected:
|
|||
nsCOMPtr<nsISSLStatus> mSSLStatus;
|
||||
|
||||
nsresult ActivateSSL();
|
||||
|
||||
nsSSLSocketThreadData *mThreadData;
|
||||
|
||||
private:
|
||||
virtual void virtualDestroyNSSReference();
|
||||
void destructorSafeDestroyNSSReference();
|
||||
|
||||
friend class nsSSLThread;
|
||||
};
|
||||
|
||||
class nsCStringHashSet;
|
||||
|
||||
class nsSSLIOLayerHelpers
|
||||
{
|
||||
public:
|
||||
static nsresult Init();
|
||||
static void Cleanup();
|
||||
|
||||
static PRDescIdentity nsSSLIOLayerIdentity;
|
||||
static PRIOMethods nsSSLIOLayerMethods;
|
||||
|
||||
static PRLock *mutex;
|
||||
static nsCStringHashSet *mTLSIntolerantSites;
|
||||
|
||||
static PRBool rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo);
|
||||
|
||||
static void addIntolerantSite(const nsCString &str);
|
||||
static PRBool isKnownAsIntolerantSite(const nsCString &str);
|
||||
|
||||
static PRFileDesc *mSharedPollableEvent;
|
||||
static nsNSSSocketInfo *mSocketOwningPollableEvent;
|
||||
|
||||
static PRBool mPollableEventCurrentlySet;
|
||||
};
|
||||
|
||||
nsresult nsSSLIOLayerNewSocket(PRInt32 family,
|
||||
|
|
Загрузка…
Ссылка в новой задаче