mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
bug 111384, Support OCSP requests through a proxy
combined r= by darin / rrelyea
This commit is contained in:
parent
03038ad819
commit
b5aaffdfeb
@ -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.
|
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.
|
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.
|
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:
|
CertInfoIssuedFor=Issued to:
|
||||||
CertInfoIssuedBy=Issued by:
|
CertInfoIssuedBy=Issued by:
|
||||||
CertInfoValid=Valid
|
CertInfoValid=Valid
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
* Bob Lord <lord@netscape.com>
|
* Bob Lord <lord@netscape.com>
|
||||||
* Ian McGreer <mcgreer@netscape.com>
|
* Ian McGreer <mcgreer@netscape.com>
|
||||||
* Javier Delgadillo <javi@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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -38,6 +39,7 @@
|
|||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
const nsIX509Cert = Components.interfaces.nsIX509Cert;
|
const nsIX509Cert = Components.interfaces.nsIX509Cert;
|
||||||
|
const nsIX509Cert3 = Components.interfaces.nsIX509Cert3;
|
||||||
const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
|
const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
|
||||||
const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
|
const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
|
||||||
const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
|
const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
|
||||||
@ -121,6 +123,13 @@ function setWindowName()
|
|||||||
AddCertChain("treesetDump", chain, "dump_");
|
AddCertChain("treesetDump", chain, "dump_");
|
||||||
DisplayGeneralDataFromCert(cert);
|
DisplayGeneralDataFromCert(cert);
|
||||||
BuildPrettyPrint(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)
|
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
|
// Verification and usage
|
||||||
var verifystr = "";
|
var verifystr = "";
|
||||||
var o1 = {};
|
var o1 = {};
|
||||||
var o2 = {};
|
var o2 = {};
|
||||||
var o3 = {};
|
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 verifystate = o1.value;
|
||||||
var count = o2.value;
|
var count = o2.value;
|
||||||
var usageList = o3.value;
|
var usageList = o3.value;
|
||||||
@ -217,7 +256,10 @@ function DisplayGeneralDataFromCert(cert)
|
|||||||
AddUsage(usageList[i],verifyInfoBox);
|
AddUsage(usageList[i],verifyInfoBox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function DisplayGeneralDataFromCert(cert)
|
||||||
|
{
|
||||||
// Common Name
|
// Common Name
|
||||||
addAttributeFromCert('commonname', cert.commonName);
|
addAttributeFromCert('commonname', cert.commonName);
|
||||||
// Organization
|
// Organization
|
||||||
@ -263,3 +305,21 @@ function updateCertDump()
|
|||||||
}
|
}
|
||||||
displaySelected();
|
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 \
|
nsICertificateDialogs.idl \
|
||||||
nsICRLInfo.idl \
|
nsICRLInfo.idl \
|
||||||
nsIX509Cert.idl \
|
nsIX509Cert.idl \
|
||||||
|
nsIX509Cert3.idl \
|
||||||
nsIX509CertDB.idl \
|
nsIX509CertDB.idl \
|
||||||
nsIX509CertValidity.idl \
|
nsIX509CertValidity.idl \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
@ -82,6 +83,7 @@ XPIDLSRCS = \
|
|||||||
nsICMSEncoder.idl \
|
nsICMSEncoder.idl \
|
||||||
nsICMSMessageErrors.idl \
|
nsICMSMessageErrors.idl \
|
||||||
nsICMSMessage.idl \
|
nsICMSMessage.idl \
|
||||||
|
nsICMSMessage2.idl \
|
||||||
nsINSSCertCache.idl \
|
nsINSSCertCache.idl \
|
||||||
nsIOCSPResponder.idl \
|
nsIOCSPResponder.idl \
|
||||||
nsIPK11Token.idl \
|
nsIPK11Token.idl \
|
||||||
|
97
security/manager/ssl/public/nsICMSMessage2.idl
Normal file
97
security/manager/ssl/public/nsICMSMessage2.idl
Normal file
@ -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);
|
||||||
|
};
|
||||||
|
|
100
security/manager/ssl/public/nsIX509Cert3.idl
Normal file
100
security/manager/ssl/public/nsIX509Cert3.idl
Normal file
@ -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
|
PACKAGE_FILE = pipnss.pkg
|
||||||
|
|
||||||
CPPSRCS = \
|
CPPSRCS = \
|
||||||
|
nsPSMBackgroundThread.cpp \
|
||||||
|
nsSSLThread.cpp \
|
||||||
|
nsCertVerificationThread.cpp \
|
||||||
nsCipherInfo.cpp \
|
nsCipherInfo.cpp \
|
||||||
nsNSSCallbacks.cpp \
|
nsNSSCallbacks.cpp \
|
||||||
nsNSSComponent.cpp \
|
nsNSSComponent.cpp \
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s): David Drinan <ddrinan@netscape.com>
|
* 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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -43,6 +44,7 @@
|
|||||||
#include "cms.h"
|
#include "cms.h"
|
||||||
#include "nsICMSMessageErrors.h"
|
#include "nsICMSMessageErrors.h"
|
||||||
#include "nsArray.h"
|
#include "nsArray.h"
|
||||||
|
#include "nsCertVerificationThread.h"
|
||||||
|
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
@ -52,7 +54,9 @@ extern PRLogModuleInfo* gPIPNSSLog;
|
|||||||
#include "nsNSSCleaner.h"
|
#include "nsNSSCleaner.h"
|
||||||
|
|
||||||
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsCMSMessage, nsICMSMessage)
|
|
||||||
|
NS_IMPL_THREADSAFE_ISUPPORTS2(nsCMSMessage, nsICMSMessage,
|
||||||
|
nsICMSMessage2)
|
||||||
|
|
||||||
nsCMSMessage::nsCMSMessage()
|
nsCMSMessage::nsCMSMessage()
|
||||||
{
|
{
|
||||||
@ -224,10 +228,6 @@ NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert)
|
|||||||
|
|
||||||
NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
|
NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
|
||||||
{
|
{
|
||||||
nsNSSShutDownPreventionLock locker;
|
|
||||||
if (isAlreadyShutDown())
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
if (!aDigestData || !aDigestDataLen)
|
if (!aDigestData || !aDigestDataLen)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
@ -340,6 +340,56 @@ loser:
|
|||||||
return rv;
|
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
|
class nsZeroTerminatedCertArray : public nsNSSShutDownObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s): David Drinan <ddrinan@netscape.com>
|
* 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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -40,8 +41,12 @@
|
|||||||
|
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsXPIDLString.h"
|
||||||
#include "nsIInterfaceRequestor.h"
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "nsICMSMessage.h"
|
#include "nsICMSMessage.h"
|
||||||
|
#include "nsICMSMessage2.h"
|
||||||
|
#include "nsIX509Cert3.h"
|
||||||
|
#include "nsVerificationJob.h"
|
||||||
#include "nsICMSEncoder.h"
|
#include "nsICMSEncoder.h"
|
||||||
#include "nsICMSDecoder.h"
|
#include "nsICMSDecoder.h"
|
||||||
#include "sechash.h"
|
#include "sechash.h"
|
||||||
@ -53,11 +58,13 @@
|
|||||||
{ 0xa4557478, 0xae16, 0x11d5, { 0xba,0x4b,0x00,0x10,0x83,0x03,0xb1,0x17 } }
|
{ 0xa4557478, 0xae16, 0x11d5, { 0xba,0x4b,0x00,0x10,0x83,0x03,0xb1,0x17 } }
|
||||||
|
|
||||||
class nsCMSMessage : public nsICMSMessage,
|
class nsCMSMessage : public nsICMSMessage,
|
||||||
|
public nsICMSMessage2,
|
||||||
public nsNSSShutDownObject
|
public nsNSSShutDownObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSICMSMESSAGE
|
NS_DECL_NSICMSMESSAGE
|
||||||
|
NS_DECL_NSICMSMESSAGE2
|
||||||
|
|
||||||
nsCMSMessage();
|
nsCMSMessage();
|
||||||
nsCMSMessage(NSSCMSMessage* aCMSMsg);
|
nsCMSMessage(NSSCMSMessage* aCMSMsg);
|
||||||
@ -70,10 +77,15 @@ private:
|
|||||||
NSSCMSMessage * m_cmsMsg;
|
NSSCMSMessage * m_cmsMsg;
|
||||||
NSSCMSSignerInfo* GetTopLevelSignerInfo();
|
NSSCMSSignerInfo* GetTopLevelSignerInfo();
|
||||||
nsresult CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen);
|
nsresult CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen);
|
||||||
|
|
||||||
|
nsresult CommonAsyncVerifySignature(nsISMimeVerificationListener *aListener,
|
||||||
|
unsigned char* aDigestData, PRUint32 aDigestDataLen);
|
||||||
|
|
||||||
virtual void virtualDestroyNSSReference();
|
virtual void virtualDestroyNSSReference();
|
||||||
void destructorSafeDestroyNSSReference();
|
void destructorSafeDestroyNSSReference();
|
||||||
};
|
|
||||||
|
|
||||||
|
friend class nsSMimeVerificationJob;
|
||||||
|
};
|
||||||
|
|
||||||
// ===============================================
|
// ===============================================
|
||||||
// nsCMSDecoder - implementation of nsICMSDecoder
|
// nsCMSDecoder - implementation of nsICMSDecoder
|
||||||
|
210
security/manager/ssl/src/nsCertVerificationThread.cpp
Normal file
210
security/manager/ssl/src/nsCertVerificationThread.cpp
Normal file
@ -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;
|
||||||
|
}
|
62
security/manager/ssl/src/nsCertVerificationThread.h
Normal file
62
security/manager/ssl/src/nsCertVerificationThread.h
Normal file
@ -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):
|
* Contributor(s):
|
||||||
* Brian Ryner <bryner@brianryner.com>
|
* Brian Ryner <bryner@brianryner.com>
|
||||||
* Terry Hayes <thayes@netscape.com>
|
* Terry Hayes <thayes@netscape.com>
|
||||||
|
* Kai Engert <kengert@redhat.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -54,13 +55,516 @@
|
|||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
#include "nsNSSShutDown.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 "ssl.h"
|
||||||
#include "cert.h"
|
#include "cert.h"
|
||||||
|
#include "ocsp.h"
|
||||||
|
|
||||||
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
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 */
|
/* Implementation of nsISSLStatus */
|
||||||
class nsSSLStatus
|
class nsSSLStatus
|
||||||
: public nsISSLStatus
|
: public nsISSLStatus
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Brian Ryner <bryner@brianryner.com>
|
* Brian Ryner <bryner@brianryner.com>
|
||||||
|
* Kai Engert <kengert@redhat.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -42,6 +43,8 @@
|
|||||||
|
|
||||||
#include "pk11func.h"
|
#include "pk11func.h"
|
||||||
#include "nspr.h"
|
#include "nspr.h"
|
||||||
|
#include "ocspt.h"
|
||||||
|
#include "nsIStreamLoader.h"
|
||||||
|
|
||||||
char* PR_CALLBACK
|
char* PR_CALLBACK
|
||||||
PK11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void* arg);
|
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,
|
SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
|
||||||
PRBool checksig, PRBool isServer);
|
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_
|
#endif // _NSNSSCALLBACKS_H_
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Ian McGreer <mcgreer@netscape.com>
|
* Ian McGreer <mcgreer@netscape.com>
|
||||||
* Javier Delgadillo <javi@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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -48,6 +49,7 @@
|
|||||||
#include "nsPKCS12Blob.h"
|
#include "nsPKCS12Blob.h"
|
||||||
#include "nsPK11TokenDB.h"
|
#include "nsPK11TokenDB.h"
|
||||||
#include "nsIX509Cert.h"
|
#include "nsIX509Cert.h"
|
||||||
|
#include "nsIX509Cert3.h"
|
||||||
#include "nsISMimeCert.h"
|
#include "nsISMimeCert.h"
|
||||||
#include "nsNSSASN1Object.h"
|
#include "nsNSSASN1Object.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
@ -64,6 +66,7 @@
|
|||||||
#include "nsNSSCertHelper.h"
|
#include "nsNSSCertHelper.h"
|
||||||
#include "nsISupportsPrimitives.h"
|
#include "nsISupportsPrimitives.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
|
#include "nsCertVerificationThread.h"
|
||||||
|
|
||||||
#include "nspr.h"
|
#include "nspr.h"
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -88,8 +91,9 @@ static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|||||||
|
|
||||||
/* nsNSSCertificate */
|
/* nsNSSCertificate */
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS3(nsNSSCertificate, nsIX509Cert,
|
NS_IMPL_THREADSAFE_ISUPPORTS4(nsNSSCertificate, nsIX509Cert,
|
||||||
nsIX509Cert2,
|
nsIX509Cert2,
|
||||||
|
nsIX509Cert3,
|
||||||
nsISMimeCert)
|
nsISMimeCert)
|
||||||
|
|
||||||
nsNSSCertificate*
|
nsNSSCertificate*
|
||||||
@ -1052,6 +1056,26 @@ nsNSSCertificate::GetUsagesArray(PRBool ignoreOcsp,
|
|||||||
return NS_OK;
|
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
|
NS_IMETHODIMP
|
||||||
nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
|
nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
|
||||||
PRUint32 *_verified,
|
PRUint32 *_verified,
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Ian McGreer <mcgreer@netscape.com>
|
* Ian McGreer <mcgreer@netscape.com>
|
||||||
* Javier Delgadillo <javi@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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -41,6 +42,7 @@
|
|||||||
|
|
||||||
#include "nsIX509Cert.h"
|
#include "nsIX509Cert.h"
|
||||||
#include "nsIX509Cert2.h"
|
#include "nsIX509Cert2.h"
|
||||||
|
#include "nsIX509Cert3.h"
|
||||||
#include "nsIX509CertDB.h"
|
#include "nsIX509CertDB.h"
|
||||||
#include "nsIX509CertList.h"
|
#include "nsIX509CertList.h"
|
||||||
#include "nsIASN1Object.h"
|
#include "nsIASN1Object.h"
|
||||||
@ -56,6 +58,7 @@ class nsIASN1Sequence;
|
|||||||
/* Certificate */
|
/* Certificate */
|
||||||
class nsNSSCertificate : public nsIX509Cert,
|
class nsNSSCertificate : public nsIX509Cert,
|
||||||
public nsIX509Cert2,
|
public nsIX509Cert2,
|
||||||
|
public nsIX509Cert3,
|
||||||
public nsISMimeCert,
|
public nsISMimeCert,
|
||||||
public nsNSSShutDownObject
|
public nsNSSShutDownObject
|
||||||
{
|
{
|
||||||
@ -63,6 +66,7 @@ public:
|
|||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIX509CERT
|
NS_DECL_NSIX509CERT
|
||||||
NS_DECL_NSIX509CERT2
|
NS_DECL_NSIX509CERT2
|
||||||
|
NS_DECL_NSIX509CERT3
|
||||||
NS_DECL_NSISMIMECERT
|
NS_DECL_NSISMIMECERT
|
||||||
|
|
||||||
nsNSSCertificate(CERTCertificate *cert);
|
nsNSSCertificate(CERTCertificate *cert);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
* Mitch Stoltz <mstoltz@netscape.com>
|
* Mitch Stoltz <mstoltz@netscape.com>
|
||||||
* Brian Ryner <bryner@brianryner.com>
|
* Brian Ryner <bryner@brianryner.com>
|
||||||
* Kai Engert <kaie@netscape.com>
|
* Kai Engert <kaie@netscape.com>
|
||||||
|
* Kai Engert <kengert@redhat.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -44,6 +45,8 @@
|
|||||||
#include "nsNSSComponent.h"
|
#include "nsNSSComponent.h"
|
||||||
#include "nsNSSCallbacks.h"
|
#include "nsNSSCallbacks.h"
|
||||||
#include "nsNSSIOLayer.h"
|
#include "nsNSSIOLayer.h"
|
||||||
|
#include "nsSSLThread.h"
|
||||||
|
#include "nsCertVerificationThread.h"
|
||||||
#include "nsNSSEvent.h"
|
#include "nsNSSEvent.h"
|
||||||
|
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
@ -290,14 +293,33 @@ nsNSSComponent::nsNSSComponent()
|
|||||||
mCrlTimerLock = nsnull;
|
mCrlTimerLock = nsnull;
|
||||||
mObserversRegistered = PR_FALSE;
|
mObserversRegistered = PR_FALSE;
|
||||||
|
|
||||||
|
nsSSLIOLayerHelpers::Init();
|
||||||
|
|
||||||
NS_ASSERTION( (0 == mInstanceCount), "nsNSSComponent is a singleton, but instantiated multiple times!");
|
NS_ASSERTION( (0 == mInstanceCount), "nsNSSComponent is a singleton, but instantiated multiple times!");
|
||||||
++mInstanceCount;
|
++mInstanceCount;
|
||||||
hashTableCerts = nsnull;
|
hashTableCerts = nsnull;
|
||||||
mShutdownObjectList = nsNSSShutDownList::construct();
|
mShutdownObjectList = nsNSSShutDownList::construct();
|
||||||
|
mIsNetworkDown = PR_FALSE;
|
||||||
|
mSSLThread = new nsSSLThread();
|
||||||
|
mCertVerificationThread = new nsCertVerificationThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNSSComponent::~nsNSSComponent()
|
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"));
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor\n"));
|
||||||
|
|
||||||
if(mUpdateTimerInitialized == PR_TRUE){
|
if(mUpdateTimerInitialized == PR_TRUE){
|
||||||
@ -319,7 +341,7 @@ nsNSSComponent::~nsNSSComponent()
|
|||||||
// All cleanup code requiring services needs to happen in xpcom_shutdown
|
// All cleanup code requiring services needs to happen in xpcom_shutdown
|
||||||
|
|
||||||
ShutdownNSS();
|
ShutdownNSS();
|
||||||
nsSSLIOLayerFreeTLSIntolerantSites();
|
nsSSLIOLayerHelpers::Cleanup();
|
||||||
--mInstanceCount;
|
--mInstanceCount;
|
||||||
delete mShutdownObjectList;
|
delete mShutdownObjectList;
|
||||||
|
|
||||||
@ -1455,6 +1477,9 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
|
|||||||
// Set up OCSP //
|
// Set up OCSP //
|
||||||
setOCSPOptions(mPrefBranch);
|
setOCSPOptions(mPrefBranch);
|
||||||
|
|
||||||
|
mHttpForNSS.initTable();
|
||||||
|
mHttpForNSS.registerHttpClient();
|
||||||
|
|
||||||
InstallLoadableRoots();
|
InstallLoadableRoots();
|
||||||
|
|
||||||
LaunchSmartCardThreads();
|
LaunchSmartCardThreads();
|
||||||
@ -1499,6 +1524,7 @@ nsNSSComponent::ShutdownNSS()
|
|||||||
mNSSInitialized = PR_FALSE;
|
mNSSInitialized = PR_FALSE;
|
||||||
|
|
||||||
PK11_SetPasswordFunc((PK11PasswordFunc)nsnull);
|
PK11_SetPasswordFunc((PK11PasswordFunc)nsnull);
|
||||||
|
mHttpForNSS.unregisterHttpClient();
|
||||||
|
|
||||||
if (mPrefBranch) {
|
if (mPrefBranch) {
|
||||||
nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
|
nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
|
||||||
@ -1530,6 +1556,14 @@ nsNSSComponent::Init()
|
|||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Beginning NSS initialization\n"));
|
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();
|
rv = InitializePIPNSSBundle();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to create pipnss bundle.\n"));
|
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;
|
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_TEARDOWN_TOPIC "profile-change-net-teardown"
|
||||||
#define PROFILE_CHANGE_NET_RESTORE_TOPIC "profile-change-net-restore"
|
#define PROFILE_CHANGE_NET_RESTORE_TOPIC "profile-change-net-restore"
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PROFILE_APPROVE_CHANGE_TOPIC "profile-approve-change"
|
#define PROFILE_APPROVE_CHANGE_TOPIC "profile-approve-change"
|
||||||
#define PROFILE_CHANGE_TEARDOWN_TOPIC "profile-change-teardown"
|
#define PROFILE_CHANGE_TEARDOWN_TOPIC "profile-change-teardown"
|
||||||
#define PROFILE_CHANGE_TEARDOWN_VETO_TOPIC "profile-change-teardown-veto"
|
#define PROFILE_CHANGE_TEARDOWN_VETO_TOPIC "profile-change-teardown-veto"
|
||||||
@ -1762,10 +1791,6 @@ NS_IMETHODIMP
|
|||||||
nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
||||||
const PRUnichar *someData)
|
const PRUnichar *someData)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
|
||||||
static PRBool isNetworkDown = PR_FALSE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) {
|
if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) {
|
||||||
if (mShutdownObjectList->isUIActive()) {
|
if (mShutdownObjectList->isUIActive()) {
|
||||||
ShowAlert(ai_crypto_ui_active);
|
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) {
|
else if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) {
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving profile change topic\n"));
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving profile change topic\n"));
|
||||||
#ifdef DEBUG
|
NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
|
||||||
NS_ASSERTION(isNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PRBool needsCleanup = PR_TRUE;
|
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) {
|
else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
|
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) {
|
else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_RESTORE_TOPIC) == 0) {
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network restore topic\n"));
|
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -2019,10 +2047,8 @@ nsNSSComponent::RegisterObservers()
|
|||||||
observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, PR_FALSE);
|
observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, PR_FALSE);
|
||||||
observerService->AddObserver(this, PROFILE_AFTER_CHANGE_TOPIC, PR_FALSE);
|
observerService->AddObserver(this, PROFILE_AFTER_CHANGE_TOPIC, PR_FALSE);
|
||||||
observerService->AddObserver(this, SESSION_LOGOUT_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_TEARDOWN_TOPIC, PR_FALSE);
|
||||||
observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, PR_FALSE);
|
observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, PR_FALSE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -2370,8 +2396,8 @@ PSMContentDownloader::OnDataAvailable(nsIRequest* request,
|
|||||||
do {
|
do {
|
||||||
err = aIStream->Read(mByteData+mBufferOffset,
|
err = aIStream->Read(mByteData+mBufferOffset,
|
||||||
aLength, &amt);
|
aLength, &amt);
|
||||||
if (amt == 0) break;
|
|
||||||
if (NS_FAILED(err)) return err;
|
if (NS_FAILED(err)) return err;
|
||||||
|
if (amt == 0) break;
|
||||||
|
|
||||||
aLength -= amt;
|
aLength -= amt;
|
||||||
mBufferOffset += amt;
|
mBufferOffset += amt;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
* Doug Turner <dougt@netscape.com>
|
* Doug Turner <dougt@netscape.com>
|
||||||
* Brian Ryner <bryner@brianryner.com>
|
* Brian Ryner <bryner@brianryner.com>
|
||||||
* Kai Engert <kaie@netscape.com>
|
* Kai Engert <kaie@netscape.com>
|
||||||
|
* Kai Engert <kengert@redhat.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -63,6 +64,7 @@
|
|||||||
#include "prlock.h"
|
#include "prlock.h"
|
||||||
#include "nsICryptoHash.h"
|
#include "nsICryptoHash.h"
|
||||||
#include "hasht.h"
|
#include "hasht.h"
|
||||||
|
#include "nsNSSCallbacks.h"
|
||||||
|
|
||||||
#include "nsNSSHelper.h"
|
#include "nsNSSHelper.h"
|
||||||
|
|
||||||
@ -177,6 +179,8 @@ private:
|
|||||||
|
|
||||||
struct PRLock;
|
struct PRLock;
|
||||||
class nsNSSShutDownList;
|
class nsNSSShutDownList;
|
||||||
|
class nsSSLThread;
|
||||||
|
class nsCertVerificationThread;
|
||||||
|
|
||||||
// Implementation of the PSM component interface.
|
// Implementation of the PSM component interface.
|
||||||
class nsNSSComponent : public nsISignatureVerifier,
|
class nsNSSComponent : public nsISignatureVerifier,
|
||||||
@ -269,6 +273,10 @@ private:
|
|||||||
static int mInstanceCount;
|
static int mInstanceCount;
|
||||||
nsNSSShutDownList *mShutdownObjectList;
|
nsNSSShutDownList *mShutdownObjectList;
|
||||||
SmartCardThreadList *mThreadList;
|
SmartCardThreadList *mThreadList;
|
||||||
|
PRBool mIsNetworkDown;
|
||||||
|
nsSSLThread *mSSLThread;
|
||||||
|
nsCertVerificationThread *mCertVerificationThread;
|
||||||
|
nsNSSHttpInterface mHttpForNSS;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PSMContentListener : public nsIURIContentListener,
|
class PSMContentListener : public nsIURIContentListener,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Brian Ryner <bryner@brianryner.com>
|
* Brian Ryner <bryner@brianryner.com>
|
||||||
* Javier Delgadillo <javi@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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -63,6 +64,8 @@
|
|||||||
#include "nsHashSets.h"
|
#include "nsHashSets.h"
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
|
#include "nsAutoLock.h"
|
||||||
|
#include "nsSSLThread.h"
|
||||||
#include "nsNSSShutDown.h"
|
#include "nsNSSShutDown.h"
|
||||||
#include "nsNSSCertHelper.h"
|
#include "nsNSSCertHelper.h"
|
||||||
|
|
||||||
@ -99,11 +102,6 @@ nsNSS_SSLGetClientAuthData(void *arg, PRFileDesc *socket,
|
|||||||
CERTDistNames *caNames,
|
CERTDistNames *caNames,
|
||||||
CERTCertificate **pRetCert,
|
CERTCertificate **pRetCert,
|
||||||
SECKEYPrivateKey **pRetKey);
|
SECKEYPrivateKey **pRetKey);
|
||||||
static PRBool firstTime = PR_TRUE;
|
|
||||||
static PRDescIdentity nsSSLIOLayerIdentity;
|
|
||||||
static PRIOMethods nsSSLIOLayerMethods;
|
|
||||||
static nsCStringHashSet *gTLSIntolerantSites = nsnull;
|
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
extern PRLogModuleInfo* gPIPNSSLog;
|
extern PRLogModuleInfo* gPIPNSSLog;
|
||||||
#endif
|
#endif
|
||||||
@ -135,6 +133,45 @@ void MyLogFunction(const char *fmt, ...)
|
|||||||
#endif
|
#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()
|
nsNSSSocketInfo::nsNSSSocketInfo()
|
||||||
: mFd(nsnull),
|
: mFd(nsnull),
|
||||||
mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
|
mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
|
||||||
@ -146,10 +183,13 @@ nsNSSSocketInfo::nsNSSSocketInfo()
|
|||||||
mPort(0),
|
mPort(0),
|
||||||
mCAChain(nsnull)
|
mCAChain(nsnull)
|
||||||
{
|
{
|
||||||
|
mThreadData = new nsSSLSocketThreadData;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNSSSocketInfo::~nsNSSSocketInfo()
|
nsNSSSocketInfo::~nsNSSSocketInfo()
|
||||||
{
|
{
|
||||||
|
delete mThreadData;
|
||||||
|
|
||||||
nsNSSShutDownPreventionLock locker;
|
nsNSSShutDownPreventionLock locker;
|
||||||
if (isAlreadyShutDown())
|
if (isAlreadyShutDown())
|
||||||
return;
|
return;
|
||||||
@ -369,11 +409,10 @@ nsresult nsNSSSocketInfo::ActivateSSL()
|
|||||||
if (isAlreadyShutDown())
|
if (isAlreadyShutDown())
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, PR_TRUE))
|
nsresult rv = nsSSLThread::requestActivateSSL(this);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
if (SECSuccess != SSL_ResetHandshake(mFd, PR_FALSE))
|
if (NS_FAILED(rv))
|
||||||
return NS_ERROR_FAILURE;
|
return rv;
|
||||||
|
|
||||||
mHandshakePending = PR_TRUE;
|
mHandshakePending = PR_TRUE;
|
||||||
|
|
||||||
@ -422,14 +461,18 @@ nsresult nsNSSSocketInfo::SetSSLStatus(nsISSLStatus *aSSLStatus)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
void nsSSLIOLayerHelpers::Cleanup()
|
||||||
nsSSLIOLayerFreeTLSIntolerantSites()
|
|
||||||
{
|
{
|
||||||
if (gTLSIntolerantSites) {
|
if (mTLSIntolerantSites) {
|
||||||
delete gTLSIntolerantSites;
|
delete mTLSIntolerantSites;
|
||||||
gTLSIntolerantSites = nsnull;
|
mTLSIntolerantSites = nsnull;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
|
||||||
|
if (mSharedPollableEvent)
|
||||||
|
PR_DestroyPollableEvent(mSharedPollableEvent);
|
||||||
|
|
||||||
|
if (mutex)
|
||||||
|
PR_DestroyLock(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
@ -873,26 +916,14 @@ nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
|
|||||||
return status;
|
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.
|
// 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.
|
// This function will return true, if the given socket is currently using TLS.
|
||||||
static PRBool
|
PRBool
|
||||||
rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo)
|
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
|
||||||
{
|
{
|
||||||
PRBool currentlyUsesTLS = PR_FALSE;
|
PRBool currentlyUsesTLS = PR_FALSE;
|
||||||
|
|
||||||
SSL_OptionGet(fd->lower, SSL_ENABLE_TLS, ¤tlyUsesTLS);
|
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, ¤tlyUsesTLS);
|
||||||
if (currentlyUsesTLS) {
|
if (currentlyUsesTLS) {
|
||||||
// Add this site to the list of TLS intolerant sites.
|
// Add this site to the list of TLS intolerant sites.
|
||||||
PRInt32 port;
|
PRInt32 port;
|
||||||
@ -901,8 +932,8 @@ rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo)
|
|||||||
socketInfo->GetHostName(getter_Copies(host));
|
socketInfo->GetHostName(getter_Copies(host));
|
||||||
nsCAutoString key;
|
nsCAutoString key;
|
||||||
key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
|
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;
|
return currentlyUsesTLS;
|
||||||
@ -917,23 +948,32 @@ nsSSLIOLayerClose(PRFileDesc *fd)
|
|||||||
|
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
|
||||||
|
|
||||||
|
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||||
|
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||||
|
|
||||||
|
return nsSSLThread::requestClose(socketInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRStatus nsNSSSocketInfo::CloseSocketAndDestroy()
|
||||||
|
{
|
||||||
|
nsNSSShutDownPreventionLock locker;
|
||||||
|
|
||||||
nsNSSShutDownList::trackSSLSocketClose();
|
nsNSSShutDownList::trackSSLSocketClose();
|
||||||
|
|
||||||
PRFileDesc* popped = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
|
PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
|
||||||
nsNSSSocketInfo *infoObject = (nsNSSSocketInfo *)popped->secret;
|
|
||||||
|
|
||||||
if (infoObject->GetHandshakeInProgress()) {
|
if (GetHandshakeInProgress()) {
|
||||||
rememberPossibleTLSProblemSite(fd, infoObject);
|
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(mFd->lower, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRStatus status = fd->methods->close(fd);
|
PRStatus status = mFd->methods->close(mFd);
|
||||||
if (status != PR_SUCCESS) return status;
|
if (status != PR_SUCCESS) return status;
|
||||||
|
|
||||||
popped->identity = PR_INVALID_IO_LAYER;
|
popped->identity = PR_INVALID_IO_LAYER;
|
||||||
NS_RELEASE(infoObject);
|
NS_RELEASE_THIS();
|
||||||
popped->dtor(popped);
|
popped->dtor(popped);
|
||||||
|
|
||||||
return status;
|
return PR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
|
#if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
|
||||||
@ -1021,8 +1061,8 @@ isTLSIntoleranceError(PRInt32 err, PRBool withInitialCleartext)
|
|||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PRInt32
|
PRInt32
|
||||||
checkHandshake(PRInt32 bytesTransfered, PRFileDesc* fd, nsNSSSocketInfo *socketInfo)
|
nsSSLThread::checkHandshake(PRInt32 bytesTransfered, PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
|
||||||
{
|
{
|
||||||
// This is where we work around all of those SSL servers that don't
|
// 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
|
// 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.
|
// to retry without TLS.
|
||||||
|
|
||||||
if (isTLSIntoleranceError(err, withInitialCleartext)) {
|
if (isTLSIntoleranceError(err, withInitialCleartext)) {
|
||||||
wantRetry = rememberPossibleTLSProblemSite(fd, socketInfo);
|
wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
|
||||||
|
|
||||||
if (wantRetry) {
|
if (wantRetry) {
|
||||||
// We want to cause the network layer to retry the connection.
|
// We want to cause the network layer to retry the connection.
|
||||||
@ -1087,6 +1127,26 @@ checkHandshake(PRInt32 bytesTransfered, PRFileDesc* fd, nsNSSSocketInfo *socketI
|
|||||||
return bytesTransfered;
|
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
|
static PRInt32 PR_CALLBACK
|
||||||
nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
|
nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
|
||||||
{
|
{
|
||||||
@ -1095,26 +1155,10 @@ nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
|
|||||||
return PR_FAILURE;
|
return PR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNSSSocketInfo *socketInfo = nsnull;
|
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||||
socketInfo = (nsNSSSocketInfo*)fd->secret;
|
|
||||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||||
|
|
||||||
if (socketInfo->isPK11LoggedOut() || socketInfo->isAlreadyShutDown()) {
|
return nsSSLThread::requestRead(socketInfo, buf, amount);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PRInt32 PR_CALLBACK
|
static PRInt32 PR_CALLBACK
|
||||||
@ -1128,37 +1172,213 @@ nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, PRInt32 amount)
|
|||||||
#ifdef DEBUG_SSL_VERBOSE
|
#ifdef DEBUG_SSL_VERBOSE
|
||||||
DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
|
DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
|
||||||
#endif
|
#endif
|
||||||
nsNSSSocketInfo *socketInfo = nsnull;
|
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||||
socketInfo = (nsNSSSocketInfo*)fd->secret;
|
|
||||||
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||||
|
|
||||||
if (socketInfo->isPK11LoggedOut() || socketInfo->isAlreadyShutDown()) {
|
return nsSSLThread::requestWrite(socketInfo, buf, amount);
|
||||||
PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
return PR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt32 bytesWritten = fd->lower->methods->write(fd->lower, buf, amount);
|
nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
|
||||||
#ifdef DEBUG_SSL_VERBOSE
|
NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
|
||||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n", (void*)fd, bytesWritten));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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");
|
nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
|
||||||
nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
|
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.connect = nsSSLIOLayerConnect;
|
||||||
nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
|
nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
|
||||||
nsSSLIOLayerMethods.available = nsSSLIOLayerAvailable;
|
|
||||||
nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
|
nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
|
||||||
nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
|
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
|
nsresult
|
||||||
@ -1171,15 +1391,6 @@ nsSSLIOLayerNewSocket(PRInt32 family,
|
|||||||
nsISupports** info,
|
nsISupports** info,
|
||||||
PRBool forSTARTTLS)
|
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);
|
PRFileDesc* sock = PR_OpenTCPSocket(family);
|
||||||
if (!sock) return NS_ERROR_OUT_OF_MEMORY;
|
if (!sock) return NS_ERROR_OUT_OF_MEMORY;
|
||||||
@ -2280,7 +2491,8 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, PRBool forSTARTTLS,
|
|||||||
// TLS intolerant.
|
// TLS intolerant.
|
||||||
nsCAutoString key;
|
nsCAutoString key;
|
||||||
key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
|
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)) {
|
SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, PR_FALSE)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -2318,16 +2530,6 @@ nsSSLIOLayerAddToSocket(PRInt32 family,
|
|||||||
PRFileDesc* layer = nsnull;
|
PRFileDesc* layer = nsnull;
|
||||||
nsresult rv;
|
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();
|
nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
|
||||||
if (!infoObject) return NS_ERROR_FAILURE;
|
if (!infoObject) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
@ -2351,8 +2553,8 @@ nsSSLIOLayerAddToSocket(PRInt32 family,
|
|||||||
goto loser;
|
goto loser;
|
||||||
|
|
||||||
/* Now, layer ourselves on top of the SSL socket... */
|
/* Now, layer ourselves on top of the SSL socket... */
|
||||||
layer = PR_CreateIOLayerStub(nsSSLIOLayerIdentity,
|
layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
|
||||||
&nsSSLIOLayerMethods);
|
&nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
|
||||||
if (!layer)
|
if (!layer)
|
||||||
goto loser;
|
goto loser;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Brian Ryner <bryner@brianryner.com>
|
* Brian Ryner <bryner@brianryner.com>
|
||||||
|
* Kai Engert <kengert@redhat.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -54,6 +55,65 @@
|
|||||||
#include "nsNSSShutDown.h"
|
#include "nsNSSShutDown.h"
|
||||||
|
|
||||||
class nsIChannel;
|
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,
|
class nsNSSSocketInfo : public nsITransportSecurityInfo,
|
||||||
public nsISSLSocketControl,
|
public nsISSLSocketControl,
|
||||||
@ -104,6 +164,8 @@ public:
|
|||||||
/* Set SSL Status values */
|
/* Set SSL Status values */
|
||||||
nsresult SetSSLStatus(nsISSLStatus *aSSLStatus);
|
nsresult SetSSLStatus(nsISSLStatus *aSSLStatus);
|
||||||
|
|
||||||
|
PRStatus CloseSocketAndDestroy();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||||
PRFileDesc* mFd;
|
PRFileDesc* mFd;
|
||||||
@ -122,9 +184,39 @@ protected:
|
|||||||
nsCOMPtr<nsISSLStatus> mSSLStatus;
|
nsCOMPtr<nsISSLStatus> mSSLStatus;
|
||||||
|
|
||||||
nsresult ActivateSSL();
|
nsresult ActivateSSL();
|
||||||
|
|
||||||
|
nsSSLSocketThreadData *mThreadData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void virtualDestroyNSSReference();
|
virtual void virtualDestroyNSSReference();
|
||||||
void destructorSafeDestroyNSSReference();
|
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,
|
nsresult nsSSLIOLayerNewSocket(PRInt32 family,
|
||||||
|
91
security/manager/ssl/src/nsPSMBackgroundThread.cpp
Normal file
91
security/manager/ssl/src/nsPSMBackgroundThread.cpp
Normal file
@ -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;
|
||||||
|
}
|
72
security/manager/ssl/src/nsPSMBackgroundThread.h
Normal file
72
security/manager/ssl/src/nsPSMBackgroundThread.h
Normal file
@ -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
|
891
security/manager/ssl/src/nsSSLThread.cpp
Normal file
891
security/manager/ssl/src/nsSSLThread.cpp
Normal file
@ -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;
|
146
security/manager/ssl/src/nsSSLThread.h
Normal file
146
security/manager/ssl/src/nsSSLThread.h
Normal file
@ -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_
|
100
security/manager/ssl/src/nsVerificationJob.h
Normal file
100
security/manager/ssl/src/nsVerificationJob.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user