зеркало из https://github.com/mozilla/pjs.git
bug 111384, Support OCSP requests through a proxy
combined r= by darin / rrelyea
This commit is contained in:
Родитель
86cc076b77
Коммит
18f6a01631
|
@ -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 \
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsISMimeVerificationListener;
|
||||
|
||||
[ptr] native UnsignedCharPtr(unsigned char);
|
||||
|
||||
/*
|
||||
* This interface is currently not marked scriptable,
|
||||
* because its verification functions are meant to look like those
|
||||
* in nsICMSMessage. At the time the ptr type is eliminated in both
|
||||
* interfaces, both should be made scriptable.
|
||||
*/
|
||||
|
||||
[uuid(a99a3203-39e3-45e1-909c-175b0e471c2b)]
|
||||
interface nsICMSMessage2 : nsISupports
|
||||
{
|
||||
/**
|
||||
* Async version of nsICMSMessage::VerifySignature.
|
||||
* Code will be executed on a background thread and
|
||||
* availability of results will be notified using a
|
||||
* call to nsISMimeVerificationListener.
|
||||
*/
|
||||
void asyncVerifySignature(in nsISMimeVerificationListener listener);
|
||||
|
||||
/**
|
||||
* Async version of nsICMSMessage::VerifyDetachedSignature.
|
||||
* Code will be executed on a background thread and
|
||||
* availability of results will be notified using a
|
||||
* call to nsISMimeVerificationListener.
|
||||
*
|
||||
* We are using "native unsigned char" ptr, because the function
|
||||
* signatures of this one and nsICMSMessage::verifyDetachedSignature
|
||||
* should be the identical. Cleaning up nsICMSMessages needs to be
|
||||
* postponed, because this async version is needed on MOZILLA_1_8_BRANCH.
|
||||
*
|
||||
* Once both interfaces get cleaned up, the function signature should
|
||||
* look like:
|
||||
* [array, length_is(aDigestDataLen)]
|
||||
* in octet aDigestData,
|
||||
* in unsigned long aDigestDataLen);
|
||||
*/
|
||||
void asyncVerifyDetachedSignature(in nsISMimeVerificationListener listener,
|
||||
in UnsignedCharPtr aDigestData,
|
||||
in unsigned long aDigestDataLen);
|
||||
};
|
||||
|
||||
[uuid(56310af6-dffc-48b4-abca-85eae4059064)]
|
||||
interface nsISMimeVerificationListener : nsISupports {
|
||||
|
||||
/**
|
||||
* Notify that results are ready, that have been requested
|
||||
* using nsICMSMessage2::asyncVerify[Detached]Signature()
|
||||
*
|
||||
* verificationResultCode matches synchronous result code from
|
||||
* nsICMSMessage::verify[Detached]Signature
|
||||
*/
|
||||
void notify(in nsICMSMessage2 verifiedMessage,
|
||||
in nsresult verificationResultCode);
|
||||
};
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIX509Cert;
|
||||
interface nsICertVerificationListener;
|
||||
|
||||
/**
|
||||
* Extending nsIX509Cert
|
||||
*
|
||||
* TODO: nsIX509Cert3 should be derived from nsIX509Cert2
|
||||
* (and nsIX509Cert2 derived from nsIX509Cert)
|
||||
*/
|
||||
[scriptable, uuid(402aee39-653c-403f-8be1-6d1824223bf9)]
|
||||
interface nsIX509Cert3 : nsISupports {
|
||||
|
||||
/**
|
||||
* Async version of nsIX509Cert::getUsagesArray()
|
||||
*
|
||||
* Will not block, will request results asynchronously,
|
||||
* availability of results will be notified.
|
||||
*/
|
||||
void requestUsagesArrayAsync(in nsICertVerificationListener cvl);
|
||||
};
|
||||
|
||||
[scriptable, uuid(2fd0a785-9f2d-4327-8871-8c3e0783891d)]
|
||||
interface nsICertVerificationResult : nsISupports {
|
||||
|
||||
/**
|
||||
* This interface reflects a container of
|
||||
* verification results. Call will not block.
|
||||
*
|
||||
* Obtain an array of human readable strings describing
|
||||
* the certificate's certified usages.
|
||||
*
|
||||
* Mirrors the results produced by
|
||||
* nsIX509Cert::getUsagesArray()
|
||||
*
|
||||
* As of today, this function is a one-shot object,
|
||||
* only the first call will succeed.
|
||||
* This allows an optimization in the implementation,
|
||||
* ownership of result data will be transfered to caller.
|
||||
*
|
||||
* @param cert The certificate that was verified.
|
||||
* @param verified The certificate verification result,
|
||||
* see constants in nsIX509Cert.
|
||||
* @param count The number of human readable usages returned.
|
||||
* @param usages The array of human readable usages.
|
||||
*/
|
||||
void getUsagesArrayResult(out PRUint32 verified,
|
||||
out PRUint32 count,
|
||||
[array, size_is(count)] out wstring usages);
|
||||
};
|
||||
|
||||
|
||||
[scriptable, uuid(6684bce9-50db-48e1-81b7-98102bf81357)]
|
||||
interface nsICertVerificationListener : nsISupports {
|
||||
|
||||
/**
|
||||
* Notify that results are ready, that have been requested
|
||||
* using nsIX509Cert3::requestUsagesArrayAsync()
|
||||
*/
|
||||
void notify(in nsIX509Cert3 verifiedCert,
|
||||
in nsICertVerificationResult result);
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsMemory.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCertVerificationThread.h"
|
||||
|
||||
nsCertVerificationThread *nsCertVerificationThread::verification_thread_singleton;
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsCertVerificationResult, nsICertVerificationResult)
|
||||
|
||||
void nsCertVerificationJob::Run()
|
||||
{
|
||||
if (!mListener || !mCert)
|
||||
return;
|
||||
|
||||
PRUint32 verified;
|
||||
PRUint32 count;
|
||||
PRUnichar **usages;
|
||||
|
||||
nsCOMPtr<nsICertVerificationResult> ires;
|
||||
nsRefPtr<nsCertVerificationResult> vres = new nsCertVerificationResult;
|
||||
if (vres)
|
||||
{
|
||||
nsresult rv = mCert->GetUsagesArray(PR_FALSE, // do not ignore OCSP
|
||||
&verified,
|
||||
&count,
|
||||
&usages);
|
||||
vres->mRV = rv;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
vres->mVerified = verified;
|
||||
vres->mCount = count;
|
||||
vres->mUsages = usages;
|
||||
}
|
||||
|
||||
ires = vres;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509Cert3> c3 = do_QueryInterface(mCert);
|
||||
mListener->Notify(c3, ires);
|
||||
}
|
||||
|
||||
void nsSMimeVerificationJob::Run()
|
||||
{
|
||||
if (!mMessage || !mListener)
|
||||
return;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (digest_data)
|
||||
rv = mMessage->VerifyDetachedSignature(digest_data, digest_len);
|
||||
else
|
||||
rv = mMessage->VerifySignature();
|
||||
|
||||
nsCOMPtr<nsICMSMessage2> m2 = do_QueryInterface(mMessage);
|
||||
mListener->Notify(m2, rv);
|
||||
}
|
||||
|
||||
nsCertVerificationThread::nsCertVerificationThread()
|
||||
: mJobQ(nsnull)
|
||||
{
|
||||
NS_ASSERTION(!verification_thread_singleton,
|
||||
"nsCertVerificationThread is a singleton, caller attempts"
|
||||
" to create another instance!");
|
||||
|
||||
verification_thread_singleton = this;
|
||||
|
||||
NS_ASSERTION(mThreadHandle, "Could not create nsThreadRunner thread\n");
|
||||
}
|
||||
|
||||
nsCertVerificationThread::~nsCertVerificationThread()
|
||||
{
|
||||
verification_thread_singleton = nsnull;
|
||||
}
|
||||
|
||||
nsresult nsCertVerificationThread::addJob(nsBaseVerificationJob *aJob)
|
||||
{
|
||||
if (!aJob || !verification_thread_singleton)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!verification_thread_singleton->mThreadHandle)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsAutoLock threadLock(verification_thread_singleton->mMutex);
|
||||
|
||||
verification_thread_singleton->mJobQ.Push(aJob);
|
||||
PR_NotifyAllCondVar(verification_thread_singleton->mCond);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define CONDITION_WAIT_TIME PR_TicksPerSecond() / 4
|
||||
|
||||
void nsCertVerificationThread::Run(void)
|
||||
{
|
||||
const PRIntervalTime wait_time = CONDITION_WAIT_TIME;
|
||||
|
||||
while (PR_TRUE) {
|
||||
|
||||
nsBaseVerificationJob *job = nsnull;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(verification_thread_singleton->mMutex);
|
||||
|
||||
while (!mExitRequested && (0 == verification_thread_singleton->mJobQ.GetSize())) {
|
||||
// no work to do ? let's wait a moment
|
||||
|
||||
PR_WaitCondVar(mCond, wait_time);
|
||||
}
|
||||
|
||||
if (mExitRequested)
|
||||
break;
|
||||
|
||||
job = NS_STATIC_CAST(nsBaseVerificationJob*, mJobQ.PopFront());
|
||||
}
|
||||
|
||||
if (job)
|
||||
{
|
||||
job->Run();
|
||||
delete job;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(verification_thread_singleton->mMutex);
|
||||
|
||||
while (verification_thread_singleton->mJobQ.GetSize()) {
|
||||
nsCertVerificationJob *job =
|
||||
NS_STATIC_CAST(nsCertVerificationJob*, mJobQ.PopFront());
|
||||
delete job;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCertVerificationResult::nsCertVerificationResult()
|
||||
: mRV(0),
|
||||
mVerified(0),
|
||||
mCount(0),
|
||||
mUsages(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsCertVerificationResult::~nsCertVerificationResult()
|
||||
{
|
||||
if (mUsages)
|
||||
{
|
||||
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mUsages);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCertVerificationResult::GetUsagesArrayResult(PRUint32 *aVerified,
|
||||
PRUint32 *aCount,
|
||||
PRUnichar ***aUsages)
|
||||
{
|
||||
if (NS_FAILED(mRV))
|
||||
return mRV;
|
||||
|
||||
// transfer ownership
|
||||
|
||||
*aVerified = mVerified;
|
||||
*aCount = mCount;
|
||||
*aUsages = mUsages;
|
||||
|
||||
mVerified = 0;
|
||||
mCount = 0;
|
||||
mUsages = 0;
|
||||
|
||||
nsresult rv = mRV;
|
||||
|
||||
mRV = NS_ERROR_FAILURE; // this object works only once...
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _NSCERTVERIFICATIONTHREAD_H_
|
||||
#define _NSCERTVERIFICATIONTHREAD_H_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsPSMBackgroundThread.h"
|
||||
#include "nsVerificationJob.h"
|
||||
|
||||
class nsCertVerificationThread : public nsPSMBackgroundThread
|
||||
{
|
||||
private:
|
||||
nsDeque mJobQ;
|
||||
|
||||
virtual void Run(void);
|
||||
|
||||
public:
|
||||
nsCertVerificationThread();
|
||||
~nsCertVerificationThread();
|
||||
|
||||
static nsCertVerificationThread *verification_thread_singleton;
|
||||
|
||||
static nsresult addJob(nsBaseVerificationJob *aJob);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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"
|
||||
|
@ -289,15 +292,34 @@ nsNSSComponent::nsNSSComponent()
|
|||
mTimer = nsnull;
|
||||
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),
|
||||
|
@ -145,11 +182,14 @@ nsNSSSocketInfo::nsNSSSocketInfo()
|
|||
mHandshakeInProgress(PR_FALSE),
|
||||
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;
|
||||
|
||||
if (SECSuccess != SSL_ResetHandshake(mFd, PR_FALSE))
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = nsSSLThread::requestActivateSSL(this);
|
||||
|
||||
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;
|
||||
|
@ -916,24 +947,33 @@ nsSSLIOLayerClose(PRFileDesc *fd)
|
|||
return PR_FAILURE;
|
||||
|
||||
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,
|
||||
|
@ -103,7 +163,9 @@ 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,
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsPSMBackgroundThread.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
void PR_CALLBACK nsPSMBackgroundThread::nsThreadRunner(void *arg)
|
||||
{
|
||||
nsPSMBackgroundThread *self = NS_STATIC_CAST(nsPSMBackgroundThread *, arg);
|
||||
self->Run();
|
||||
}
|
||||
|
||||
nsPSMBackgroundThread::nsPSMBackgroundThread()
|
||||
: mThreadHandle(nsnull),
|
||||
mMutex(nsnull),
|
||||
mCond(nsnull),
|
||||
mExitRequested(PR_FALSE)
|
||||
{
|
||||
mMutex = PR_NewLock();
|
||||
mCond = PR_NewCondVar(mMutex);
|
||||
|
||||
if (mMutex && mCond)
|
||||
{
|
||||
mThreadHandle = PR_CreateThread(PR_USER_THREAD, nsThreadRunner, NS_STATIC_CAST(void*, this),
|
||||
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
|
||||
NS_ASSERTION(mThreadHandle, "Could not create nsPSMBackgroundThread\n");
|
||||
}
|
||||
}
|
||||
|
||||
nsPSMBackgroundThread::~nsPSMBackgroundThread()
|
||||
{
|
||||
if (mCond)
|
||||
PR_DestroyCondVar(mCond);
|
||||
|
||||
if (mMutex)
|
||||
PR_DestroyLock(mMutex);
|
||||
}
|
||||
|
||||
void nsPSMBackgroundThread::requestExit()
|
||||
{
|
||||
if (!mThreadHandle)
|
||||
return;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(mMutex);
|
||||
|
||||
if (mExitRequested)
|
||||
return;
|
||||
|
||||
mExitRequested = PR_TRUE;
|
||||
PR_NotifyAllCondVar(mCond);
|
||||
}
|
||||
|
||||
PR_JoinThread(mThreadHandle);
|
||||
mThreadHandle = nsnull;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _NSPSMBACKGROUNDTHREAD_H_
|
||||
#define _NSPSMBACKGROUNDTHREAD_H_
|
||||
|
||||
#include "nspr.h"
|
||||
|
||||
class nsPSMBackgroundThread
|
||||
{
|
||||
protected:
|
||||
static void PR_CALLBACK nsThreadRunner(void *arg);
|
||||
virtual void Run(void) = 0;
|
||||
|
||||
// used to join the thread
|
||||
PRThread *mThreadHandle;
|
||||
|
||||
// Shared mutex used for condition variables,
|
||||
// and to protect access to mExitRequested.
|
||||
// Derived classes may use it to protect additional
|
||||
// resources.
|
||||
PRLock *mMutex;
|
||||
|
||||
// Used to signal the thread's Run loop
|
||||
PRCondVar *mCond;
|
||||
|
||||
// Has termination of the SSL thread been requested?
|
||||
PRBool mExitRequested;
|
||||
|
||||
public:
|
||||
nsPSMBackgroundThread();
|
||||
virtual ~nsPSMBackgroundThread();
|
||||
|
||||
void requestExit();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,891 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIThread.h"
|
||||
#include "nsSSLThread.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
|
||||
#include "ssl.h"
|
||||
|
||||
nsSSLThread::nsSSLThread()
|
||||
: mBusySocket(nsnull),
|
||||
mSocketScheduledToBeDestroyed(nsnull),
|
||||
mPendingHTTPRequest(nsnull)
|
||||
{
|
||||
NS_ASSERTION(!ssl_thread_singleton, "nsSSLThread is a singleton, caller attempts to create another instance!");
|
||||
|
||||
ssl_thread_singleton = this;
|
||||
|
||||
NS_ASSERTION(mThreadHandle, "Could not create nsSSLThreadRunner thread\n");
|
||||
}
|
||||
|
||||
nsSSLThread::~nsSSLThread()
|
||||
{
|
||||
ssl_thread_singleton = nsnull;
|
||||
}
|
||||
|
||||
PRFileDesc *nsSSLThread::getRealSSLFD(nsNSSSocketInfo *si)
|
||||
{
|
||||
if (!ssl_thread_singleton || !si || !ssl_thread_singleton->mThreadHandle)
|
||||
return nsnull;
|
||||
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (si->mThreadData->mReplacedSSLFileDesc)
|
||||
{
|
||||
return si->mThreadData->mReplacedSSLFileDesc;
|
||||
}
|
||||
else
|
||||
{
|
||||
return si->mFd->lower;
|
||||
}
|
||||
}
|
||||
|
||||
PRStatus nsSSLThread::requestGetsockname(nsNSSSocketInfo *si, PRNetAddr *addr)
|
||||
{
|
||||
PRFileDesc *fd = getRealSSLFD(si);
|
||||
if (!fd)
|
||||
return PR_FAILURE;
|
||||
|
||||
return fd->methods->getsockname(fd, addr);
|
||||
}
|
||||
|
||||
PRStatus nsSSLThread::requestGetpeername(nsNSSSocketInfo *si, PRNetAddr *addr)
|
||||
{
|
||||
PRFileDesc *fd = getRealSSLFD(si);
|
||||
if (!fd)
|
||||
return PR_FAILURE;
|
||||
|
||||
return fd->methods->getpeername(fd, addr);
|
||||
}
|
||||
|
||||
PRStatus nsSSLThread::requestGetsocketoption(nsNSSSocketInfo *si,
|
||||
PRSocketOptionData *data)
|
||||
{
|
||||
PRFileDesc *fd = getRealSSLFD(si);
|
||||
if (!fd)
|
||||
return PR_FAILURE;
|
||||
|
||||
return fd->methods->getsocketoption(fd, data);
|
||||
}
|
||||
|
||||
PRStatus nsSSLThread::requestSetsocketoption(nsNSSSocketInfo *si,
|
||||
const PRSocketOptionData *data)
|
||||
{
|
||||
PRFileDesc *fd = getRealSSLFD(si);
|
||||
if (!fd)
|
||||
return PR_FAILURE;
|
||||
|
||||
return fd->methods->setsocketoption(fd, data);
|
||||
}
|
||||
|
||||
PRStatus nsSSLThread::requestConnectcontinue(nsNSSSocketInfo *si,
|
||||
PRInt16 out_flags)
|
||||
{
|
||||
PRFileDesc *fd = getRealSSLFD(si);
|
||||
if (!fd)
|
||||
return PR_FAILURE;
|
||||
|
||||
return fd->methods->connectcontinue(fd, out_flags);
|
||||
}
|
||||
|
||||
PRInt32 nsSSLThread::requestRecvMsgPeek(nsNSSSocketInfo *si, void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRIntervalTime timeout)
|
||||
{
|
||||
if (!ssl_thread_singleton || !si || !ssl_thread_singleton->mThreadHandle)
|
||||
{
|
||||
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRFileDesc *realSSLFD;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (si == ssl_thread_singleton->mBusySocket)
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (si->mThreadData->mSSLState)
|
||||
{
|
||||
case nsSSLSocketThreadData::ssl_idle:
|
||||
break;
|
||||
|
||||
case nsSSLSocketThreadData::ssl_reading_done:
|
||||
{
|
||||
// we have data available that we can return
|
||||
|
||||
// if there was a failure, just return the failure,
|
||||
// but do not yet clear our state, that should happen
|
||||
// in the call to "read".
|
||||
|
||||
if (si->mThreadData->mSSLResultRemainingBytes < 0) {
|
||||
if (si->mThreadData->mPRErrorCode != PR_SUCCESS) {
|
||||
PR_SetError(si->mThreadData->mPRErrorCode, 0);
|
||||
}
|
||||
|
||||
return si->mThreadData->mSSLResultRemainingBytes;
|
||||
}
|
||||
|
||||
PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
|
||||
|
||||
memcpy(buf, si->mThreadData->mSSLRemainingReadResultData, return_amount);
|
||||
|
||||
return return_amount;
|
||||
}
|
||||
|
||||
case nsSSLSocketThreadData::ssl_writing_done:
|
||||
case nsSSLSocketThreadData::ssl_pending_write:
|
||||
case nsSSLSocketThreadData::ssl_pending_read:
|
||||
|
||||
// for safety reasons, also return would_block on any other state,
|
||||
// although this switch statement should be complete and list
|
||||
// the appropriate behaviour for each state.
|
||||
default:
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (si->mThreadData->mReplacedSSLFileDesc)
|
||||
{
|
||||
realSSLFD = si->mThreadData->mReplacedSSLFileDesc;
|
||||
}
|
||||
else
|
||||
{
|
||||
realSSLFD = si->mFd->lower;
|
||||
}
|
||||
}
|
||||
|
||||
return realSSLFD->methods->recv(realSSLFD, buf, amount, flags, timeout);
|
||||
}
|
||||
|
||||
nsresult nsSSLThread::requestActivateSSL(nsNSSSocketInfo *si)
|
||||
{
|
||||
PRFileDesc *fd = getRealSSLFD(si);
|
||||
if (!fd)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, PR_TRUE))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (SECSuccess != SSL_ResetHandshake(fd, PR_FALSE))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt16 nsSSLThread::requestPoll(nsNSSSocketInfo *si, PRInt16 in_flags, PRInt16 *out_flags)
|
||||
{
|
||||
if (!ssl_thread_singleton || !si || !ssl_thread_singleton->mThreadHandle)
|
||||
return 0;
|
||||
|
||||
*out_flags = 0;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (si == ssl_thread_singleton->mBusySocket)
|
||||
{
|
||||
switch (si->mThreadData->mSSLState)
|
||||
{
|
||||
case nsSSLSocketThreadData::ssl_writing_done:
|
||||
{
|
||||
if (in_flags & PR_POLL_WRITE)
|
||||
{
|
||||
*out_flags |= PR_POLL_WRITE;
|
||||
}
|
||||
|
||||
return in_flags;
|
||||
}
|
||||
break;
|
||||
|
||||
case nsSSLSocketThreadData::ssl_reading_done:
|
||||
{
|
||||
if (in_flags & PR_POLL_READ)
|
||||
{
|
||||
*out_flags |= PR_POLL_READ;
|
||||
}
|
||||
|
||||
return in_flags;
|
||||
}
|
||||
break;
|
||||
|
||||
case nsSSLSocketThreadData::ssl_pending_write:
|
||||
case nsSSLSocketThreadData::ssl_pending_read:
|
||||
{
|
||||
// The lower layer of the socket is currently the pollable event,
|
||||
// which signals the readable state.
|
||||
|
||||
return PR_POLL_READ;
|
||||
}
|
||||
|
||||
case nsSSLSocketThreadData::ssl_idle:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return si->mFd->lower->methods->poll(si->mFd->lower, in_flags, out_flags);
|
||||
}
|
||||
|
||||
PRStatus nsSSLThread::requestClose(nsNSSSocketInfo *si)
|
||||
{
|
||||
if (!ssl_thread_singleton || !si)
|
||||
return PR_FAILURE;
|
||||
|
||||
PRBool close_later = PR_FALSE;
|
||||
nsIRequest* requestToCancel = nsnull;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (ssl_thread_singleton->mBusySocket == si) {
|
||||
|
||||
// That's tricky, SSL thread is currently busy with this socket,
|
||||
// and might even be blocked on it (UI or OCSP).
|
||||
// We should not close the socket directly, but rather
|
||||
// schedule closing it, at the time the SSL thread is done.
|
||||
// If there is indeed a depending OCSP request pending,
|
||||
// we should cancel it now.
|
||||
|
||||
if (ssl_thread_singleton->mPendingHTTPRequest)
|
||||
{
|
||||
requestToCancel = ssl_thread_singleton->mPendingHTTPRequest;
|
||||
ssl_thread_singleton->mPendingHTTPRequest = nsnull;
|
||||
}
|
||||
|
||||
close_later = PR_TRUE;
|
||||
ssl_thread_singleton->mSocketScheduledToBeDestroyed = si;
|
||||
}
|
||||
}
|
||||
|
||||
if (requestToCancel)
|
||||
{
|
||||
if (nsIThread::IsMainThread())
|
||||
{
|
||||
requestToCancel->Cancel(NS_ERROR_ABORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_WARNING("Attempt to close SSL socket from a thread that is not the main thread. Can not cancel pending HTTP request from NSS");
|
||||
}
|
||||
|
||||
NS_RELEASE(requestToCancel);
|
||||
}
|
||||
|
||||
if (!close_later)
|
||||
{
|
||||
return si->CloseSocketAndDestroy();
|
||||
}
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
void nsSSLThread::restoreOriginalSocket_locked(nsNSSSocketInfo *si)
|
||||
{
|
||||
if (si->mThreadData->mReplacedSSLFileDesc)
|
||||
{
|
||||
if (nsSSLIOLayerHelpers::mPollableEventCurrentlySet)
|
||||
{
|
||||
nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_FALSE;
|
||||
PR_WaitForPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent);
|
||||
}
|
||||
|
||||
// need to restore
|
||||
si->mFd->lower = si->mThreadData->mReplacedSSLFileDesc;
|
||||
si->mThreadData->mReplacedSSLFileDesc = nsnull;
|
||||
nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 nsSSLThread::requestRead(nsNSSSocketInfo *si, void *buf, PRInt32 amount)
|
||||
{
|
||||
if (!ssl_thread_singleton || !si || !buf || !amount || !ssl_thread_singleton->mThreadHandle)
|
||||
{
|
||||
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRBool this_socket_is_busy = PR_FALSE;
|
||||
PRBool some_other_socket_is_busy = PR_FALSE;
|
||||
nsSSLSocketThreadData::ssl_state my_ssl_state;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (ssl_thread_singleton->mExitRequested) {
|
||||
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
my_ssl_state = si->mThreadData->mSSLState;
|
||||
|
||||
if (ssl_thread_singleton->mBusySocket == si)
|
||||
{
|
||||
this_socket_is_busy = PR_TRUE;
|
||||
|
||||
if (my_ssl_state == nsSSLSocketThreadData::ssl_reading_done)
|
||||
{
|
||||
// we will now care for the data that's ready,
|
||||
// the socket is no longer busy on the ssl thread
|
||||
|
||||
restoreOriginalSocket_locked(si);
|
||||
|
||||
ssl_thread_singleton->mBusySocket = nsnull;
|
||||
|
||||
// We'll handle the results further down,
|
||||
// while not holding the lock.
|
||||
}
|
||||
}
|
||||
else if (ssl_thread_singleton->mBusySocket)
|
||||
{
|
||||
some_other_socket_is_busy = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (my_ssl_state)
|
||||
{
|
||||
case nsSSLSocketThreadData::ssl_idle:
|
||||
{
|
||||
NS_ASSERTION(!this_socket_is_busy, "oops, unexpected incosistency");
|
||||
|
||||
if (some_other_socket_is_busy)
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ssl thread is not busy, we'll continue below
|
||||
}
|
||||
break;
|
||||
|
||||
case nsSSLSocketThreadData::ssl_reading_done:
|
||||
// there has been a previous request to read, that is now done!
|
||||
{
|
||||
// failure ?
|
||||
if (si->mThreadData->mSSLResultRemainingBytes < 0) {
|
||||
if (si->mThreadData->mPRErrorCode != PR_SUCCESS) {
|
||||
PR_SetError(si->mThreadData->mPRErrorCode, 0);
|
||||
si->mThreadData->mPRErrorCode = PR_SUCCESS;
|
||||
}
|
||||
|
||||
si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
|
||||
return si->mThreadData->mSSLResultRemainingBytes;
|
||||
}
|
||||
|
||||
PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
|
||||
|
||||
memcpy(buf, si->mThreadData->mSSLRemainingReadResultData, return_amount);
|
||||
|
||||
si->mThreadData->mSSLResultRemainingBytes -= return_amount;
|
||||
|
||||
if (!si->mThreadData->mSSLResultRemainingBytes) {
|
||||
si->mThreadData->mSSLRemainingReadResultData = nsnull;
|
||||
si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
|
||||
}
|
||||
else {
|
||||
si->mThreadData->mSSLRemainingReadResultData += return_amount;
|
||||
}
|
||||
|
||||
return return_amount;
|
||||
}
|
||||
// we never arrive here, see return statement above
|
||||
break;
|
||||
|
||||
|
||||
// We should not see the following events here,
|
||||
// because we have not yet signaled Necko that we are
|
||||
// readable/writable again, so if we end up here,
|
||||
// it means that Necko decided to try read/write again,
|
||||
// for whatever reason. No problem, just return would_block,
|
||||
case nsSSLSocketThreadData::ssl_pending_write:
|
||||
case nsSSLSocketThreadData::ssl_pending_read:
|
||||
|
||||
// We should not see this state here, because Necko has previously
|
||||
// requested us to write, Necko is not yet aware that it's done,
|
||||
// (although it meanwhile is), but Necko now tries to read?
|
||||
// If that ever happens, it's confusing, but not a problem,
|
||||
// just let Necko know we can not do that now and return would_block.
|
||||
case nsSSLSocketThreadData::ssl_writing_done:
|
||||
|
||||
// for safety reasons, also return would_block on any other state,
|
||||
// although this switch statement should be complete and list
|
||||
// the appropriate behaviour for each state.
|
||||
default:
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
// we never arrive here, see return statement above
|
||||
break;
|
||||
}
|
||||
|
||||
if (si->isPK11LoggedOut() || si->isAlreadyShutDown()) {
|
||||
PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (si->GetCanceled()) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
// si is idle and good, and no other socket is currently busy,
|
||||
// so it's fine to continue with the request.
|
||||
|
||||
if (!si->mThreadData->ensure_buffer_size(amount))
|
||||
{
|
||||
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
si->mThreadData->mSSLRequestedTransferAmount = amount;
|
||||
si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_pending_read;
|
||||
|
||||
// Remember we are operating on a layered file descriptor, that consists of
|
||||
// a PSM code layer (nsNSSIOLayer), a NSS code layer (SSL protocol logic),
|
||||
// and the raw socket at the bottommost layer.
|
||||
//
|
||||
// We don't want to call the SSL layer read/write directly on this thread,
|
||||
// because it might block, should a callback to UI (for user confirmation)
|
||||
// or Necko (for retrieving OCSP verification data) be necessary.
|
||||
// As Necko is single threaded, it is currently waiting for this
|
||||
// function to return, and a callback into Necko from NSS couldn't succeed.
|
||||
//
|
||||
// Therefore we must defer the request to read/write to a separate SSL thread.
|
||||
// We will return WOULD_BLOCK to Necko, and will return the real results
|
||||
// once the I/O operation on the SSL thread is ready.
|
||||
//
|
||||
// The tricky part is to wake up Necko, as soon as the I/O operation
|
||||
// on the SSL thread is done.
|
||||
//
|
||||
// In order to achieve that, we manipulate the layering of the file
|
||||
// descriptor. Usually the PSM layer points to the SSL layer as its lower
|
||||
// layer. We change that to a pollable event file descriptor.
|
||||
//
|
||||
// Once we return from this original read/write function, Necko will
|
||||
// poll/select on the file descriptor. As result data is not yet ready, we will
|
||||
// instruct Necko to select on the bottommost file descriptor
|
||||
// (by using appropriate flags in PSM's layer implementation of the
|
||||
// poll method), which is the pollable event.
|
||||
//
|
||||
// Once the SSL thread is done with the call to the SSL layer, it will
|
||||
// "set" the pollable event, causing Necko to wake up on the file descriptor
|
||||
// and call read/write again. Now that the file descriptor is in the done state,
|
||||
// we'll arrive in this read/write function again. We'll detect the socket is
|
||||
// in the done state, and restore the original SSL level file descriptor.
|
||||
// Finally, we return the data obtained on the SSL thread back to our caller.
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
NS_ASSERTION(!nsSSLIOLayerHelpers::mSocketOwningPollableEvent,
|
||||
"oops, some other socket still owns our shared pollable event");
|
||||
NS_ASSERTION(!si->mThreadData->mReplacedSSLFileDesc, "oops");
|
||||
|
||||
si->mThreadData->mReplacedSSLFileDesc = si->mFd->lower;
|
||||
si->mFd->lower = nsSSLIOLayerHelpers::mSharedPollableEvent;
|
||||
nsSSLIOLayerHelpers::mSocketOwningPollableEvent = si;
|
||||
ssl_thread_singleton->mBusySocket = si;
|
||||
|
||||
// notify the thread
|
||||
PR_NotifyAllCondVar(ssl_thread_singleton->mCond);
|
||||
}
|
||||
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRInt32 nsSSLThread::requestWrite(nsNSSSocketInfo *si, const void *buf, PRInt32 amount)
|
||||
{
|
||||
if (!ssl_thread_singleton || !si || !buf || !amount || !ssl_thread_singleton->mThreadHandle)
|
||||
{
|
||||
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRBool this_socket_is_busy = PR_FALSE;
|
||||
PRBool some_other_socket_is_busy = PR_FALSE;
|
||||
nsSSLSocketThreadData::ssl_state my_ssl_state;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (ssl_thread_singleton->mExitRequested) {
|
||||
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
my_ssl_state = si->mThreadData->mSSLState;
|
||||
|
||||
if (ssl_thread_singleton->mBusySocket == si)
|
||||
{
|
||||
this_socket_is_busy = PR_TRUE;
|
||||
|
||||
if (my_ssl_state == nsSSLSocketThreadData::ssl_writing_done)
|
||||
{
|
||||
// we will now care for the data that's ready,
|
||||
// the socket is no longer busy on the ssl thread
|
||||
|
||||
restoreOriginalSocket_locked(si);
|
||||
|
||||
ssl_thread_singleton->mBusySocket = nsnull;
|
||||
|
||||
// We'll handle the results further down,
|
||||
// while not holding the lock.
|
||||
}
|
||||
}
|
||||
else if (ssl_thread_singleton->mBusySocket)
|
||||
{
|
||||
some_other_socket_is_busy = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (my_ssl_state)
|
||||
{
|
||||
case nsSSLSocketThreadData::ssl_idle:
|
||||
{
|
||||
NS_ASSERTION(!this_socket_is_busy, "oops, unexpected incosistency");
|
||||
|
||||
if (some_other_socket_is_busy)
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ssl thread is not busy, we'll continue below
|
||||
}
|
||||
break;
|
||||
|
||||
case nsSSLSocketThreadData::ssl_writing_done:
|
||||
// there has been a previous request to write, that is now done!
|
||||
{
|
||||
// failure ?
|
||||
if (si->mThreadData->mSSLResultRemainingBytes < 0) {
|
||||
if (si->mThreadData->mPRErrorCode != PR_SUCCESS) {
|
||||
PR_SetError(si->mThreadData->mPRErrorCode, 0);
|
||||
si->mThreadData->mPRErrorCode = PR_SUCCESS;
|
||||
}
|
||||
|
||||
si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
|
||||
return si->mThreadData->mSSLResultRemainingBytes;
|
||||
}
|
||||
|
||||
PRInt32 return_amount = NS_MIN(amount, si->mThreadData->mSSLResultRemainingBytes);
|
||||
|
||||
si->mThreadData->mSSLResultRemainingBytes -= return_amount;
|
||||
|
||||
if (!si->mThreadData->mSSLResultRemainingBytes) {
|
||||
si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
|
||||
}
|
||||
|
||||
return return_amount;
|
||||
}
|
||||
break;
|
||||
|
||||
// We should not see the following events here,
|
||||
// because we have not yet signaled Necko that we are
|
||||
// readable/writable again, so if we end up here,
|
||||
// it means that Necko decided to try read/write again,
|
||||
// for whatever reason. No problem, just return would_block,
|
||||
case nsSSLSocketThreadData::ssl_pending_write:
|
||||
case nsSSLSocketThreadData::ssl_pending_read:
|
||||
|
||||
// We should not see this state here, because Necko has previously
|
||||
// requested us to read, Necko is not yet aware that it's done,
|
||||
// (although it meanwhile is), but Necko now tries to write?
|
||||
// If that ever happens, it's confusing, but not a problem,
|
||||
// just let Necko know we can not do that now and return would_block.
|
||||
case nsSSLSocketThreadData::ssl_reading_done:
|
||||
|
||||
// for safety reasons, also return would_block on any other state,
|
||||
// although this switch statement should be complete and list
|
||||
// the appropriate behaviour for each state.
|
||||
default:
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
// we never arrive here, see return statement above
|
||||
break;
|
||||
}
|
||||
|
||||
if (si->isPK11LoggedOut() || si->isAlreadyShutDown()) {
|
||||
PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (si->GetCanceled()) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
// si is idle and good, and no other socket is currently busy,
|
||||
// so it's fine to continue with the request.
|
||||
|
||||
if (!si->mThreadData->ensure_buffer_size(amount))
|
||||
{
|
||||
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(si->mThreadData->mSSLDataBuffer, buf, amount);
|
||||
si->mThreadData->mSSLRequestedTransferAmount = amount;
|
||||
si->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_pending_write;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
NS_ASSERTION(!nsSSLIOLayerHelpers::mSocketOwningPollableEvent,
|
||||
"oops, some other socket still owns our shared pollable event");
|
||||
NS_ASSERTION(!si->mThreadData->mReplacedSSLFileDesc, "oops");
|
||||
|
||||
si->mThreadData->mReplacedSSLFileDesc = si->mFd->lower;
|
||||
si->mFd->lower = nsSSLIOLayerHelpers::mSharedPollableEvent;
|
||||
nsSSLIOLayerHelpers::mSocketOwningPollableEvent = si;
|
||||
ssl_thread_singleton->mBusySocket = si;
|
||||
|
||||
PR_NotifyAllCondVar(ssl_thread_singleton->mCond);
|
||||
}
|
||||
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void nsSSLThread::Run(void)
|
||||
{
|
||||
// Helper variable, we don't want to call destroy
|
||||
// while holding the mutex.
|
||||
nsNSSSocketInfo *socketToDestroy = nsnull;
|
||||
|
||||
while (PR_TRUE)
|
||||
{
|
||||
if (socketToDestroy)
|
||||
{
|
||||
socketToDestroy->CloseSocketAndDestroy();
|
||||
socketToDestroy = nsnull;
|
||||
}
|
||||
|
||||
// remember whether we'll write or read
|
||||
nsSSLSocketThreadData::ssl_state busy_socket_ssl_state;
|
||||
|
||||
{
|
||||
// In this scope we need mutex protection,
|
||||
// as we find out what needs to be done.
|
||||
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (mSocketScheduledToBeDestroyed)
|
||||
{
|
||||
if (mBusySocket == mSocketScheduledToBeDestroyed)
|
||||
{
|
||||
// That's rare, but it happens.
|
||||
// We have received a request to close the socket,
|
||||
// although I/O results have not yet been consumed.
|
||||
|
||||
restoreOriginalSocket_locked(mBusySocket);
|
||||
|
||||
mBusySocket->mThreadData->mSSLState = nsSSLSocketThreadData::ssl_idle;
|
||||
mBusySocket = nsnull;
|
||||
}
|
||||
|
||||
socketToDestroy = mSocketScheduledToBeDestroyed;
|
||||
mSocketScheduledToBeDestroyed = nsnull;
|
||||
continue; // go back and finally destroy it, before doing anything else
|
||||
}
|
||||
|
||||
if (mExitRequested)
|
||||
break;
|
||||
|
||||
PRBool pending_work = PR_FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
if (mBusySocket
|
||||
&&
|
||||
(mBusySocket->mThreadData->mSSLState == nsSSLSocketThreadData::ssl_pending_read
|
||||
||
|
||||
mBusySocket->mThreadData->mSSLState == nsSSLSocketThreadData::ssl_pending_write))
|
||||
{
|
||||
pending_work = PR_TRUE;
|
||||
}
|
||||
|
||||
if (!pending_work)
|
||||
{
|
||||
// no work to do ? let's wait a moment
|
||||
|
||||
PRIntervalTime wait_time = PR_TicksPerSecond() / 4;
|
||||
PR_WaitCondVar(mCond, wait_time);
|
||||
}
|
||||
|
||||
} while (!pending_work && !mExitRequested && !mSocketScheduledToBeDestroyed);
|
||||
|
||||
if (mSocketScheduledToBeDestroyed)
|
||||
continue;
|
||||
|
||||
if (mExitRequested)
|
||||
break;
|
||||
|
||||
if (!pending_work)
|
||||
continue;
|
||||
|
||||
busy_socket_ssl_state = mBusySocket->mThreadData->mSSLState;
|
||||
}
|
||||
|
||||
{
|
||||
// In this scope we need to make sure NSS does not go away
|
||||
// while we are busy.
|
||||
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
|
||||
if (nsSSLSocketThreadData::ssl_pending_write == busy_socket_ssl_state)
|
||||
{
|
||||
PRInt32 bytesWritten = mBusySocket->mThreadData->mReplacedSSLFileDesc->methods
|
||||
->write(mBusySocket->mThreadData->mReplacedSSLFileDesc,
|
||||
mBusySocket->mThreadData->mSSLDataBuffer,
|
||||
mBusySocket->mThreadData->mSSLRequestedTransferAmount);
|
||||
|
||||
#ifdef DEBUG_SSL_VERBOSE
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n", (void*)fd, bytesWritten));
|
||||
#endif
|
||||
|
||||
bytesWritten = checkHandshake(bytesWritten, mBusySocket->mThreadData->mReplacedSSLFileDesc, mBusySocket);
|
||||
if (bytesWritten < 0) {
|
||||
// give the error back to caller
|
||||
mBusySocket->mThreadData->mPRErrorCode = PR_GetError();
|
||||
}
|
||||
|
||||
mBusySocket->mThreadData->mSSLResultRemainingBytes = bytesWritten;
|
||||
busy_socket_ssl_state = nsSSLSocketThreadData::ssl_writing_done;
|
||||
}
|
||||
else if (nsSSLSocketThreadData::ssl_pending_read == busy_socket_ssl_state)
|
||||
{
|
||||
PRInt32 bytesRead = mBusySocket->mThreadData->mReplacedSSLFileDesc->methods
|
||||
->read(mBusySocket->mThreadData->mReplacedSSLFileDesc,
|
||||
mBusySocket->mThreadData->mSSLDataBuffer,
|
||||
mBusySocket->mThreadData->mSSLRequestedTransferAmount);
|
||||
|
||||
#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
|
||||
bytesRead = checkHandshake(bytesRead, mBusySocket->mThreadData->mReplacedSSLFileDesc, mBusySocket);
|
||||
if (bytesRead < 0) {
|
||||
// give the error back to caller
|
||||
mBusySocket->mThreadData->mPRErrorCode = PR_GetError();
|
||||
}
|
||||
|
||||
mBusySocket->mThreadData->mSSLResultRemainingBytes = bytesRead;
|
||||
mBusySocket->mThreadData->mSSLRemainingReadResultData =
|
||||
mBusySocket->mThreadData->mSSLDataBuffer;
|
||||
busy_socket_ssl_state = nsSSLSocketThreadData::ssl_reading_done;
|
||||
}
|
||||
}
|
||||
|
||||
// avoid setting event repeatedly
|
||||
PRBool needToSetPollableEvent = PR_FALSE;
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
mBusySocket->mThreadData->mSSLState = busy_socket_ssl_state;
|
||||
|
||||
if (!nsSSLIOLayerHelpers::mPollableEventCurrentlySet)
|
||||
{
|
||||
needToSetPollableEvent = PR_TRUE;
|
||||
nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (needToSetPollableEvent)
|
||||
{
|
||||
// Wake up the file descriptor on the Necko thread,
|
||||
// so it can fetch the results from the SSL I/O call
|
||||
// that we just completed.
|
||||
PR_SetPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
if (mBusySocket)
|
||||
{
|
||||
restoreOriginalSocket_locked(mBusySocket);
|
||||
mBusySocket = nsnull;
|
||||
}
|
||||
if (!nsSSLIOLayerHelpers::mPollableEventCurrentlySet)
|
||||
{
|
||||
nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_TRUE;
|
||||
PR_SetPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsSSLThread::rememberPendingHTTPRequest(nsIRequest *aRequest)
|
||||
{
|
||||
if (!ssl_thread_singleton)
|
||||
return;
|
||||
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
NS_IF_ADDREF(aRequest);
|
||||
ssl_thread_singleton->mPendingHTTPRequest = aRequest;
|
||||
}
|
||||
|
||||
void nsSSLThread::cancelPendingHTTPRequest()
|
||||
{
|
||||
if (!ssl_thread_singleton)
|
||||
return;
|
||||
|
||||
nsAutoLock threadLock(ssl_thread_singleton->mMutex);
|
||||
|
||||
if (ssl_thread_singleton->mPendingHTTPRequest)
|
||||
{
|
||||
ssl_thread_singleton->mPendingHTTPRequest->Cancel(NS_ERROR_ABORT);
|
||||
|
||||
NS_RELEASE(ssl_thread_singleton->mPendingHTTPRequest);
|
||||
|
||||
ssl_thread_singleton->mPendingHTTPRequest = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsSSLThread *nsSSLThread::ssl_thread_singleton = nsnull;
|
|
@ -0,0 +1,146 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _NSSSLTHREAD_H_
|
||||
#define _NSSSLTHREAD_H_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "nsPSMBackgroundThread.h"
|
||||
|
||||
class nsNSSSocketInfo;
|
||||
class nsIHttpChannel;
|
||||
|
||||
class nsSSLThread : public nsPSMBackgroundThread
|
||||
{
|
||||
private:
|
||||
// We use mMutex contained in our base class
|
||||
// to protect access to these variables:
|
||||
// mBusySocket, mSocketScheduledToBeDestroyed
|
||||
// and to nsSSLSocketThreadData::mSSLState
|
||||
// while a socket is the busy socket.
|
||||
|
||||
// We use mCond contained in our base class
|
||||
// to notify the SSL thread that a new SSL I/O
|
||||
// request has been queued for processing.
|
||||
// It can be found in the mBusySocket variable,
|
||||
// containing all details in its member.
|
||||
|
||||
// A socket that is currently owned by the SSL thread
|
||||
// and has pending SSL I/O activity or I/O results
|
||||
// not yet fetched by the original caller.
|
||||
nsNSSSocketInfo *mBusySocket;
|
||||
|
||||
// A socket that should be closed and destroyed
|
||||
// as soon as possible. The request was initiated by
|
||||
// Necko, but it happened at a time when the SSL
|
||||
// thread had ownership of the socket, so the request
|
||||
// was delayed. It's now the responsibility of the
|
||||
// SSL thread to close and destroy this socket.
|
||||
nsNSSSocketInfo *mSocketScheduledToBeDestroyed;
|
||||
|
||||
// Did we receive a request from NSS to fetch HTTP
|
||||
// data on behalf of NSS? (Most likely this is a OCSP request)
|
||||
// We track a handle to the HTTP request sent to Necko.
|
||||
// As this HTTP request depends on some original SSL socket,
|
||||
// we can use this handle to cancel the dependent HTTP request,
|
||||
// should we be asked to close the original SSL socket.
|
||||
nsIRequest* mPendingHTTPRequest;
|
||||
|
||||
virtual void Run(void);
|
||||
|
||||
// Called from SSL thread only
|
||||
static PRInt32 checkHandshake(PRInt32 bytesTransfered,
|
||||
PRFileDesc* fd,
|
||||
nsNSSSocketInfo *socketInfo);
|
||||
|
||||
// Function can be called from either Necko or SSL thread
|
||||
// Caller must lock mMutex before this call.
|
||||
static void restoreOriginalSocket_locked(nsNSSSocketInfo *si);
|
||||
|
||||
// Helper for requestSomething functions,
|
||||
// caled from the Necko thread only.
|
||||
static PRFileDesc *getRealSSLFD(nsNSSSocketInfo *si);
|
||||
|
||||
|
||||
public:
|
||||
nsSSLThread();
|
||||
~nsSSLThread();
|
||||
|
||||
static nsSSLThread *ssl_thread_singleton;
|
||||
|
||||
// All requestSomething functions are called from
|
||||
// the Necko thread only.
|
||||
|
||||
static PRInt32 requestRead(nsNSSSocketInfo *si,
|
||||
void *buf,
|
||||
PRInt32 amount);
|
||||
|
||||
static PRInt32 requestWrite(nsNSSSocketInfo *si,
|
||||
const void *buf,
|
||||
PRInt32 amount);
|
||||
|
||||
static PRInt16 requestPoll(nsNSSSocketInfo *si,
|
||||
PRInt16 in_flags,
|
||||
PRInt16 *out_flags);
|
||||
|
||||
static PRInt32 requestRecvMsgPeek(nsNSSSocketInfo *si, void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRIntervalTime timeout);
|
||||
|
||||
static PRStatus requestClose(nsNSSSocketInfo *si);
|
||||
|
||||
static PRStatus requestGetsockname(nsNSSSocketInfo *si, PRNetAddr *addr);
|
||||
|
||||
static PRStatus requestGetpeername(nsNSSSocketInfo *si, PRNetAddr *addr);
|
||||
|
||||
static PRStatus requestGetsocketoption(nsNSSSocketInfo *si,
|
||||
PRSocketOptionData *data);
|
||||
|
||||
static PRStatus requestSetsocketoption(nsNSSSocketInfo *si,
|
||||
const PRSocketOptionData *data);
|
||||
|
||||
static PRStatus requestConnectcontinue(nsNSSSocketInfo *si,
|
||||
PRInt16 out_flags);
|
||||
|
||||
static nsresult requestActivateSSL(nsNSSSocketInfo *si);
|
||||
|
||||
// Called from either Necko or SSL thread.
|
||||
static void rememberPendingHTTPRequest(nsIRequest *aRequest);
|
||||
static void cancelPendingHTTPRequest();
|
||||
};
|
||||
|
||||
#endif //_NSSSLTHREAD_H_
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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 the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _INC_NSVERIFICATIONJOB_H
|
||||
#define _INC_NSVERIFICATIONJOB_H
|
||||
|
||||
#include "nspr.h"
|
||||
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsICMSMessage.h"
|
||||
#include "nsICMSMessage2.h"
|
||||
|
||||
class nsBaseVerificationJob
|
||||
{
|
||||
public:
|
||||
virtual void Run() = 0;
|
||||
};
|
||||
|
||||
class nsCertVerificationJob : public nsBaseVerificationJob
|
||||
{
|
||||
public:
|
||||
nsCOMPtr<nsIX509Cert> mCert;
|
||||
nsCOMPtr<nsICertVerificationListener> mListener;
|
||||
|
||||
void Run();
|
||||
};
|
||||
|
||||
class nsCertVerificationResult : public nsICertVerificationResult
|
||||
{
|
||||
public:
|
||||
nsCertVerificationResult();
|
||||
virtual ~nsCertVerificationResult();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICERTVERIFICATIONRESULT
|
||||
|
||||
private:
|
||||
nsresult mRV;
|
||||
PRUint32 mVerified;
|
||||
PRUint32 mCount;
|
||||
PRUnichar **mUsages;
|
||||
|
||||
friend class nsCertVerificationJob;
|
||||
};
|
||||
|
||||
class nsSMimeVerificationJob : public nsBaseVerificationJob
|
||||
{
|
||||
public:
|
||||
nsSMimeVerificationJob() { digest_data = nsnull; digest_len = 0; }
|
||||
~nsSMimeVerificationJob() { delete [] digest_data; }
|
||||
|
||||
nsCOMPtr<nsICMSMessage> mMessage;
|
||||
nsCOMPtr<nsISMimeVerificationListener> mListener;
|
||||
|
||||
unsigned char *digest_data;
|
||||
PRUint32 digest_len;
|
||||
|
||||
void Run();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче