mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 674147 (Remove the SSL Thread) Part 2: Everything else, r=honzab
This commit is contained in:
parent
c17a7182ed
commit
20c388403c
@ -54,6 +54,14 @@
|
||||
|
||||
#include "mozilla/FunctionTimer.h"
|
||||
|
||||
// XXX: There is no good header file to put these in. :(
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
void InitializeSSLServerCertVerificationThreads();
|
||||
void StopSSLServerCertVerificationThreads();
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
@ -609,6 +617,8 @@ nsSocketTransportService::Run()
|
||||
{
|
||||
SOCKET_LOG(("STS thread init\n"));
|
||||
|
||||
psm::InitializeSSLServerCertVerificationThreads();
|
||||
|
||||
gSocketThread = PR_GetCurrentThread();
|
||||
|
||||
// add thread event to poll list (mThreadEvent may be NULL)
|
||||
@ -665,6 +675,8 @@ nsSocketTransportService::Run()
|
||||
|
||||
gSocketThread = nsnull;
|
||||
|
||||
psm::StopSSLServerCertVerificationThreads();
|
||||
|
||||
SOCKET_LOG(("STS thread exit\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -60,7 +60,6 @@ CPPSRCS = \
|
||||
nsRecentBadCerts.cpp \
|
||||
nsClientAuthRemember.cpp \
|
||||
nsPSMBackgroundThread.cpp \
|
||||
nsSSLThread.cpp \
|
||||
nsCertVerificationThread.cpp \
|
||||
nsProtectedAuthThread.cpp \
|
||||
nsNSSCallbacks.cpp \
|
||||
|
@ -40,44 +40,213 @@
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* All I/O is done on the socket transport thread, including all calls into
|
||||
* libssl. That is, all SSL_* functions must be called on the socket transport
|
||||
* thread. This also means that all SSL callback functions will be called on
|
||||
* the socket transport thread, including in particular the auth certificate
|
||||
* hook.
|
||||
*
|
||||
* During certificate authentication, we call CERT_PKIXVerifyCert or
|
||||
* CERT_VerifyCert. These functions may make zero or more HTTP requests
|
||||
* for OCSP responses, CRLs, intermediate certificates, etc.
|
||||
*
|
||||
* If our cert auth hook were to call the CERT_*Verify* functions directly,
|
||||
* there would be a deadlock: The CERT_*Verify* function would cause an event
|
||||
* to be asynchronously posted to the socket transport thread, and then it
|
||||
* would block the socket transport thread waiting to be notified of the HTTP
|
||||
* response. However, the HTTP request would never actually be processed
|
||||
* because the socket transport thread would be blocked and so it wouldn't be
|
||||
* able process HTTP requests. (i.e. Deadlock.)
|
||||
*
|
||||
* Consequently, we must always call the CERT_*Verify* cert functions off the
|
||||
* socket transport thread. To accomplish this, our auth cert hook dispatches a
|
||||
* SSLServerCertVerificationJob to a pool of background threads, and then
|
||||
* immediatley return SECWouldBlock to libssl. These jobs are where the
|
||||
* CERT_*Verify* functions are actually called.
|
||||
*
|
||||
* When our auth cert hook returns SECWouldBlock, libssl will carry on the
|
||||
* handshake while we validate the certificate. This will free up the socket
|
||||
* transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
|
||||
* requests needed for cert verification as mentioned above--can be processed.
|
||||
*
|
||||
* Once the CERT_*Verify* function returns, the cert verification job
|
||||
* dispatches a SSLServerCertVerificationResult to the socket transport thread;
|
||||
* the SSLServerCertVerificationResult will notify libssl that the certificate
|
||||
* authentication is complete. Once libssl is notified that the authentication
|
||||
* is complete, it will continue the SSL handshake (if it hasn't already
|
||||
* finished) and it will begin allowing us to send/receive data on the
|
||||
* connection.
|
||||
*
|
||||
* Timeline of events:
|
||||
*
|
||||
* * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
|
||||
* transport thread.
|
||||
* * SSLServerCertVerificationJob::Dispatch queues a job
|
||||
* (instance of SSLServerCertVerificationJob) to its background thread
|
||||
* pool and returns.
|
||||
* * One of the background threads calls CERT_*Verify*, which may enqueue
|
||||
* some HTTP request(s) onto the socket transport thread, and then
|
||||
* blocks that background thread waiting for the responses and/or timeouts
|
||||
* or errors for those requests.
|
||||
* * Once those HTTP responses have all come back or failed, the
|
||||
* CERT_*Verify* function returns a result indicating that the validation
|
||||
* succeeded or failed.
|
||||
* * If the validation succeeded, then a SSLServerCertVerificationResult
|
||||
* event is posted to the socket transport thread, and the cert
|
||||
* verification thread becomes free to verify other certificates.
|
||||
* * Otherwise, a CertErrorRunnable is posted to the socket transport thread
|
||||
* and then to the main thread (blocking both, see CertErrorRunnable) to
|
||||
* do cert override processing and bad cert listener notification. Then
|
||||
* the cert verification thread becomes free to verify other certificates.
|
||||
* * After processing cert overrides, the CertErrorRunnable will dispatch a
|
||||
* SSLServerCertVerificationResult event to the socket transport thread to
|
||||
* notify it of the result of the override processing; then it returns,
|
||||
* freeing up the main thread.
|
||||
* * The SSLServerCertVerificationResult event will either wake up the
|
||||
* socket (using SSL_RestartHandshakeAfterServerCert) if validation
|
||||
* succeeded or there was an error override, or it will set an error flag
|
||||
* so that the next I/O operation on the socket will fail, causing the
|
||||
* socket transport thread to close the connection.
|
||||
*
|
||||
* Cert override processing must happen on the main thread because it accesses
|
||||
* the nsICertOverrideService, and that service must be accessed on the main
|
||||
* thread because some extensions (Selenium, in particular) replace it with a
|
||||
* Javascript implementation, and chrome JS must always be run on the main
|
||||
* thread.
|
||||
*
|
||||
* SSLServerCertVerificationResult must be dispatched to the socket transport
|
||||
* thread because we must only call SSL_* functions on the socket transport
|
||||
* thread since they may do I/O, because many parts of nsNSSSocketInfo and
|
||||
* the PSM NSS I/O layer are not thread-safe, and because we need the event to
|
||||
* interrupt the PR_Poll that may waiting for I/O on the socket for which we
|
||||
* are validating the cert.
|
||||
*/
|
||||
|
||||
#include "SSLServerCertVerification.h"
|
||||
#include "nsNSSComponent.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsNSSCleaner.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
|
||||
#include "nsIThreadPool.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "ssl.h"
|
||||
#include "cert.h"
|
||||
#include "secerr.h"
|
||||
#include "sslerr.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
||||
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gPIPNSSLog;
|
||||
#endif
|
||||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
namespace {
|
||||
// do not use a nsCOMPtr to avoid static initializer/destructor
|
||||
nsIThreadPool * gCertVerificationThreadPool = nsnull;
|
||||
} // unnamed namespace
|
||||
|
||||
// Called when the socket transport thread starts, to initialize the SSL cert
|
||||
// verification thread pool. By tying the thread pool startup/shutdown directly
|
||||
// to the STS thread's lifetime, we ensure that they are *always* available for
|
||||
// SSL connections and that there are no races during startup and especially
|
||||
// shutdown. (Previously, we have had multiple problems with races in PSM
|
||||
// background threads, and the race-prevention/shutdown logic used there is
|
||||
// brittle. Since this service is critical to things like downloading updates,
|
||||
// we take no chances.) Also, by doing things this way, we avoid the need for
|
||||
// locks, since gCertVerificationThreadPool is only ever accessed on the socket
|
||||
// transport thread.
|
||||
void
|
||||
InitializeSSLServerCertVerificationThreads()
|
||||
{
|
||||
// TODO: tuning, make parameters preferences
|
||||
// XXX: instantiate nsThreadPool directly, to make this more bulletproof.
|
||||
// Currently, the nsThreadPool.h header isn't exported for us to do so.
|
||||
nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID,
|
||||
&gCertVerificationThreadPool);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to create SSL cert verification threads.");
|
||||
return;
|
||||
}
|
||||
|
||||
(void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
|
||||
(void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
|
||||
(void) gCertVerificationThreadPool->SetThreadLimit(5);
|
||||
}
|
||||
|
||||
// Called when the socket transport thread finishes, to destroy the thread
|
||||
// pool. Since the socket transport service has stopped processing events, it
|
||||
// will not attempt any more SSL I/O operations, so it is clearly safe to shut
|
||||
// down the SSL cert verification infrastructure. Also, the STS will not
|
||||
// dispatch many SSL verification result events at this point, so any pending
|
||||
// cert verifications will (correctly) fail at the point they are dispatched.
|
||||
//
|
||||
// The other shutdown race condition that is possible is a race condition with
|
||||
// shutdown of the nsNSSComponent service. We use the
|
||||
// nsNSSShutdownPreventionLock where needed (not here) to prevent that.
|
||||
void StopSSLServerCertVerificationThreads()
|
||||
{
|
||||
if (gCertVerificationThreadPool) {
|
||||
gCertVerificationThreadPool->Shutdown();
|
||||
NS_RELEASE(gCertVerificationThreadPool);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class SSLServerCertVerificationJob : public nsRunnable
|
||||
{
|
||||
public:
|
||||
// Must be called only on the socket transport thread
|
||||
static SECStatus Dispatch(const void * fdForLogging,
|
||||
nsNSSSocketInfo * infoObject,
|
||||
CERTCertificate * serverCert);
|
||||
private:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
// Must be called only on the socket transport thread
|
||||
SSLServerCertVerificationJob(const void * fdForLogging,
|
||||
nsNSSSocketInfo & socketInfo,
|
||||
CERTCertificate & cert);
|
||||
~SSLServerCertVerificationJob();
|
||||
|
||||
// Runs on one of the background threads
|
||||
SECStatus AuthCertificate(const nsNSSShutDownPreventionLock & proofOfLock);
|
||||
|
||||
const void * const mFdForLogging;
|
||||
const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
|
||||
CERTCertificate * const mCert;
|
||||
};
|
||||
|
||||
SSLServerCertVerificationJob::SSLServerCertVerificationJob(
|
||||
const void * fdForLogging, nsNSSSocketInfo & socketInfo,
|
||||
CERTCertificate & cert)
|
||||
: mFdForLogging(fdForLogging)
|
||||
, mSocketInfo(&socketInfo)
|
||||
, mCert(CERT_DupCertificate(&cert))
|
||||
{
|
||||
}
|
||||
|
||||
SSLServerCertVerificationJob::~SSLServerCertVerificationJob()
|
||||
{
|
||||
CERT_DestroyCertificate(mCert);
|
||||
}
|
||||
|
||||
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
||||
|
||||
SECStatus
|
||||
PSM_SSL_PKIX_AuthCertificate(PRFileDesc *fd, CERTCertificate *peerCert, bool checksig, bool isServer)
|
||||
PSM_SSL_PKIX_AuthCertificate(CERTCertificate *peerCert, void * pinarg,
|
||||
const char * hostname,
|
||||
const nsNSSShutDownPreventionLock & /*proofOfLock*/)
|
||||
{
|
||||
SECStatus rv;
|
||||
SECCertUsage certUsage;
|
||||
SECCertificateUsage certificateusage;
|
||||
void * pinarg;
|
||||
char * hostname;
|
||||
|
||||
pinarg = SSL_RevealPinArg(fd);
|
||||
hostname = SSL_RevealURL(fd);
|
||||
|
||||
/* this may seem backwards, but isn't. */
|
||||
certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
|
||||
certificateusage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
|
||||
|
||||
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
|
||||
rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, checksig, certUsage,
|
||||
pinarg);
|
||||
rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, true,
|
||||
certUsageSSLServer, pinarg);
|
||||
}
|
||||
else {
|
||||
nsresult nsrv;
|
||||
@ -91,12 +260,12 @@ PSM_SSL_PKIX_AuthCertificate(PRFileDesc *fd, CERTCertificate *peerCert, bool che
|
||||
CERTValOutParam cvout[1];
|
||||
cvout[0].type = cert_po_end;
|
||||
|
||||
rv = CERT_PKIXVerifyCert(peerCert, certificateusage,
|
||||
rv = CERT_PKIXVerifyCert(peerCert, certificateUsageSSLServer,
|
||||
survivingParams->GetRawPointerForNSS(),
|
||||
cvout, pinarg);
|
||||
}
|
||||
|
||||
if ( rv == SECSuccess && !isServer ) {
|
||||
if (rv == SECSuccess) {
|
||||
/* cert is OK. This is the client side of an SSL connection.
|
||||
* Now check the name field in the cert against the desired hostname.
|
||||
* NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
|
||||
@ -109,7 +278,6 @@ PSM_SSL_PKIX_AuthCertificate(PRFileDesc *fd, CERTCertificate *peerCert, bool che
|
||||
PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
}
|
||||
|
||||
PORT_Free(hostname);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -197,22 +365,17 @@ PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
|
||||
PRBool checksig, PRBool isServer) {
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
|
||||
CERTCertificate *serverCert = SSL_PeerCertificate(fd);
|
||||
CERTCertificateCleaner serverCertCleaner(serverCert);
|
||||
|
||||
if (serverCert &&
|
||||
serverCert->serialNumber.data &&
|
||||
serverCert->issuerName &&
|
||||
!strcmp(serverCert->issuerName,
|
||||
SECStatus
|
||||
SSLServerCertVerificationJob::AuthCertificate(
|
||||
nsNSSShutDownPreventionLock const & nssShutdownPreventionLock)
|
||||
{
|
||||
if (mCert->serialNumber.data &&
|
||||
mCert->issuerName &&
|
||||
!strcmp(mCert->issuerName,
|
||||
"CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) {
|
||||
|
||||
unsigned char *server_cert_comparison_start = (unsigned char*)serverCert->serialNumber.data;
|
||||
unsigned int server_cert_comparison_len = serverCert->serialNumber.len;
|
||||
unsigned char *server_cert_comparison_start = mCert->serialNumber.data;
|
||||
unsigned int server_cert_comparison_len = mCert->serialNumber.len;
|
||||
|
||||
while (server_cert_comparison_len) {
|
||||
if (*server_cert_comparison_start != 0)
|
||||
@ -244,87 +407,85 @@ SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
|
||||
}
|
||||
}
|
||||
|
||||
SECStatus rv = PSM_SSL_PKIX_AuthCertificate(fd, serverCert, checksig, isServer);
|
||||
SECStatus rv = PSM_SSL_PKIX_AuthCertificate(mCert, mSocketInfo,
|
||||
mSocketInfo->GetHostName(),
|
||||
nssShutdownPreventionLock);
|
||||
|
||||
// We want to remember the CA certs in the temp db, so that the application can find the
|
||||
// complete chain at any time it might need it.
|
||||
// But we keep only those CA certs in the temp db, that we didn't already know.
|
||||
|
||||
if (serverCert) {
|
||||
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
|
||||
nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus();
|
||||
nsRefPtr<nsNSSCertificate> nsc;
|
||||
nsRefPtr<nsSSLStatus> status = mSocketInfo->SSLStatus();
|
||||
nsRefPtr<nsNSSCertificate> nsc;
|
||||
|
||||
if (!status || !status->mServerCert) {
|
||||
nsc = nsNSSCertificate::Create(serverCert);
|
||||
if (!status || !status->mServerCert) {
|
||||
nsc = nsNSSCertificate::Create(mCert);
|
||||
}
|
||||
|
||||
CERTCertList *certList = nsnull;
|
||||
certList = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLCA);
|
||||
if (!certList) {
|
||||
rv = SECFailure;
|
||||
} else {
|
||||
PRErrorCode blacklistErrorCode;
|
||||
if (rv == SECSuccess) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
|
||||
blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(mCert, certList);
|
||||
} else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
|
||||
PRErrorCode savedErrorCode = PORT_GetError();
|
||||
// Check if we want to worsen the error code to "revoked".
|
||||
blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(mCert, certList);
|
||||
if (blacklistErrorCode == 0) {
|
||||
// we don't worsen the code, let's keep the original error code from NSS
|
||||
PORT_SetError(savedErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
CERTCertList *certList = nsnull;
|
||||
certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA);
|
||||
if (!certList) {
|
||||
|
||||
if (blacklistErrorCode != 0) {
|
||||
mSocketInfo->SetCertIssuerBlacklisted();
|
||||
PORT_SetError(blacklistErrorCode);
|
||||
rv = SECFailure;
|
||||
} else {
|
||||
PRErrorCode blacklistErrorCode;
|
||||
if (rv == SECSuccess) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
|
||||
blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(serverCert, certList);
|
||||
} else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
|
||||
PRErrorCode savedErrorCode = PORT_GetError();
|
||||
// Check if we want to worsen the error code to "revoked".
|
||||
blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(serverCert, certList);
|
||||
if (blacklistErrorCode == 0) {
|
||||
// we don't worsen the code, let's keep the original error code from NSS
|
||||
PORT_SetError(savedErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (blacklistErrorCode != 0) {
|
||||
infoObject->SetCertIssuerBlacklisted();
|
||||
PORT_SetError(blacklistErrorCode);
|
||||
rv = SECFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
if (nsc) {
|
||||
bool dummyIsEV;
|
||||
nsc->GetIsExtendedValidation(&dummyIsEV); // the nsc object will cache the status
|
||||
}
|
||||
if (rv == SECSuccess) {
|
||||
if (nsc) {
|
||||
bool dummyIsEV;
|
||||
nsc->GetIsExtendedValidation(&dummyIsEV); // the nsc object will cache the status
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINSSComponent> nssComponent;
|
||||
nsCOMPtr<nsINSSComponent> nssComponent;
|
||||
|
||||
for (CERTCertListNode *node = CERT_LIST_HEAD(certList);
|
||||
!CERT_LIST_END(node, certList);
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
for (CERTCertListNode *node = CERT_LIST_HEAD(certList);
|
||||
!CERT_LIST_END(node, certList);
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
|
||||
if (node->cert->slot) {
|
||||
// This cert was found on a token, no need to remember it in the temp db.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->cert->isperm) {
|
||||
// We don't need to remember certs already stored in perm db.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->cert == serverCert) {
|
||||
// We don't want to remember the server cert,
|
||||
// the code that cares for displaying page info does this already.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have found a signer cert that we want to remember.
|
||||
char* nickname = nsNSSCertificate::defaultServerNickname(node->cert);
|
||||
if (nickname && *nickname) {
|
||||
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
|
||||
if (slot) {
|
||||
PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE,
|
||||
nickname, false);
|
||||
PK11_FreeSlot(slot);
|
||||
}
|
||||
}
|
||||
PR_FREEIF(nickname);
|
||||
if (node->cert->slot) {
|
||||
// This cert was found on a token, no need to remember it in the temp db.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->cert->isperm) {
|
||||
// We don't need to remember certs already stored in perm db.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->cert == mCert) {
|
||||
// We don't want to remember the server cert,
|
||||
// the code that cares for displaying page info does this already.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have found a signer cert that we want to remember.
|
||||
char* nickname = nsNSSCertificate::defaultServerNickname(node->cert);
|
||||
if (nickname && *nickname) {
|
||||
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
|
||||
if (slot) {
|
||||
PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE,
|
||||
nickname, false);
|
||||
PK11_FreeSlot(slot);
|
||||
}
|
||||
}
|
||||
PR_FREEIF(nickname);
|
||||
}
|
||||
|
||||
if (certList) {
|
||||
@ -336,27 +497,186 @@ SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
|
||||
// to the caller that contains at least the cert and its status.
|
||||
if (!status) {
|
||||
status = new nsSSLStatus();
|
||||
infoObject->SetSSLStatus(status);
|
||||
mSocketInfo->SetSSLStatus(status);
|
||||
}
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
// Certificate verification succeeded delete any potential record
|
||||
// of certificate error bits.
|
||||
nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
|
||||
infoObject, nsnull, rv);
|
||||
mSocketInfo, nsnull, rv);
|
||||
}
|
||||
else {
|
||||
// Certificate verification failed, update the status' bits.
|
||||
nsSSLIOLayerHelpers::mHostsWithCertErrors->LookupCertErrorBits(
|
||||
infoObject, status);
|
||||
mSocketInfo, status);
|
||||
}
|
||||
|
||||
if (status && !status->mServerCert) {
|
||||
status->mServerCert = nsc;
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
("AuthCertificateCallback setting NEW cert %p\n", status->mServerCert.get()));
|
||||
("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*static*/ SECStatus
|
||||
SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
|
||||
nsNSSSocketInfo * socketInfo,
|
||||
CERTCertificate * serverCert)
|
||||
{
|
||||
// Runs on the socket transport thread
|
||||
|
||||
if (!socketInfo || !serverCert) {
|
||||
NS_ERROR("Invalid parameters for SSL server cert validation");
|
||||
socketInfo->SetCertVerificationResult(PR_INVALID_STATE_ERROR,
|
||||
PlainErrorMessage);
|
||||
PR_SetError(PR_INVALID_STATE_ERROR, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
nsRefPtr<SSLServerCertVerificationJob> job
|
||||
= new SSLServerCertVerificationJob(fdForLogging, *socketInfo, *serverCert);
|
||||
|
||||
socketInfo->SetCertVerificationWaiting();
|
||||
nsresult nrv;
|
||||
if (!gCertVerificationThreadPool) {
|
||||
nrv = NS_ERROR_NOT_INITIALIZED;
|
||||
} else {
|
||||
nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
if (NS_FAILED(nrv)) {
|
||||
PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
|
||||
? SEC_ERROR_NO_MEMORY
|
||||
: PR_INVALID_STATE_ERROR;
|
||||
socketInfo->SetCertVerificationResult(error, PlainErrorMessage);
|
||||
PORT_SetError(error);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECWouldBlock;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SSLServerCertVerificationJob::Run()
|
||||
{
|
||||
// Runs on a cert verification thread
|
||||
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
("[%p] SSLServerCertVerificationJob::Run\n", mSocketInfo.get()));
|
||||
|
||||
PRErrorCode error;
|
||||
|
||||
nsNSSShutDownPreventionLock nssShutdownPrevention;
|
||||
if (mSocketInfo->isAlreadyShutDown()) {
|
||||
error = SEC_ERROR_USER_CANCELLED;
|
||||
} else {
|
||||
// Reset the error code here so we can detect if AuthCertificate fails to
|
||||
// set the error code if/when it fails.
|
||||
PR_SetError(0, 0);
|
||||
SECStatus rv = AuthCertificate(nssShutdownPrevention);
|
||||
if (rv == SECSuccess) {
|
||||
nsRefPtr<SSLServerCertVerificationResult> restart
|
||||
= new SSLServerCertVerificationResult(*mSocketInfo, 0);
|
||||
restart->Dispatch();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
error = PR_GetError();
|
||||
if (error != 0) {
|
||||
rv = HandleBadCertificate(error, mSocketInfo, *mCert, mFdForLogging,
|
||||
nssShutdownPrevention);
|
||||
if (rv == SECSuccess) {
|
||||
// The CertErrorRunnable will run on the main thread and it will dispatch
|
||||
// the cert verification result to the socket transport thread, so we
|
||||
// don't have to. This way, this verification thread doesn't need to
|
||||
// wait for the CertErrorRunnable to complete.
|
||||
return NS_OK;
|
||||
}
|
||||
// DispatchCertErrorRunnable set a new error code.
|
||||
error = PR_GetError();
|
||||
}
|
||||
}
|
||||
|
||||
if (error == 0) {
|
||||
NS_NOTREACHED("no error set during certificate validation failure");
|
||||
error = PR_INVALID_STATE_ERROR;
|
||||
}
|
||||
|
||||
nsRefPtr<SSLServerCertVerificationResult> failure
|
||||
= new SSLServerCertVerificationResult(*mSocketInfo, error);
|
||||
failure->Dispatch();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
// Extracts whatever information we need out of fd (using SSL_*) and passes it
|
||||
// to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
|
||||
// never do anything with fd except logging.
|
||||
SECStatus
|
||||
AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
|
||||
{
|
||||
// Runs on the socket transport thread
|
||||
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
("[%p] starting AuthCertificateHook\n", fd));
|
||||
|
||||
// Modern libssl always passes PR_TRUE for checkSig, and we have no means of
|
||||
// doing verification without checking signatures.
|
||||
NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
|
||||
|
||||
// PSM never causes libssl to call this function with PR_TRUE for isServer,
|
||||
// and many things in PSM assume that we are a client.
|
||||
NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
|
||||
|
||||
if (!checkSig || isServer) {
|
||||
PR_SetError(PR_INVALID_STATE_ERROR, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
CERTCertificate *serverCert = SSL_PeerCertificate(fd);
|
||||
|
||||
nsNSSSocketInfo *socketInfo = static_cast<nsNSSSocketInfo*>(arg);
|
||||
SECStatus rv = SSLServerCertVerificationJob::Dispatch(
|
||||
static_cast<const void *>(fd), socketInfo, serverCert);
|
||||
|
||||
CERT_DestroyCertificate(serverCert);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
SSLServerCertVerificationResult::SSLServerCertVerificationResult(
|
||||
nsNSSSocketInfo & socketInfo, PRErrorCode errorCode,
|
||||
SSLErrorMessageType errorMessageType)
|
||||
: mSocketInfo(&socketInfo)
|
||||
, mErrorCode(errorCode)
|
||||
, mErrorMessageType(errorMessageType)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SSLServerCertVerificationResult::Dispatch()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIEventTarget> stsTarget
|
||||
= do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
NS_ASSERTION(stsTarget,
|
||||
"Failed to get socket transport service event target");
|
||||
rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to dispatch SSLServerCertVerificationResult");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SSLServerCertVerificationResult::Run()
|
||||
{
|
||||
// TODO: Assert that we're on the socket transport thread
|
||||
mSocketInfo->SetCertVerificationResult(mErrorCode, mErrorMessageType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
89
security/manager/ssl/src/SSLServerCertVerification.h
Normal file
89
security/manager/ssl/src/SSLServerCertVerification.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- 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) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 _SSLSERVERCERTVERIFICATION_H
|
||||
#define _SSLSERVERCERTVERIFICATION_H
|
||||
|
||||
#include "seccomon.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "prerror.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
|
||||
typedef struct PRFileDesc PRFileDesc;
|
||||
typedef struct CERTCertificateStr CERTCertificate;
|
||||
class nsNSSSocketInfo;
|
||||
class nsNSSShutDownPreventionLock;
|
||||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
SECStatus AuthCertificateHook(void *arg, PRFileDesc *fd,
|
||||
PRBool checkSig, PRBool isServer);
|
||||
|
||||
SECStatus HandleBadCertificate(PRErrorCode defaultErrorCodeToReport,
|
||||
nsNSSSocketInfo * socketInfo,
|
||||
CERTCertificate & cert,
|
||||
const void * fdForLogging,
|
||||
const nsNSSShutDownPreventionLock &);
|
||||
|
||||
// Dispatched from a cert verification thread to the STS thread to notify the
|
||||
// socketInfo of the verification result.
|
||||
//
|
||||
// This will cause the PR_Poll in the STS thread to return, so things work
|
||||
// correctly even if the STS thread is blocked polling (only) on the file
|
||||
// descriptor that is waiting for this result.
|
||||
class SSLServerCertVerificationResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
SSLServerCertVerificationResult(nsNSSSocketInfo & socketInfo,
|
||||
PRErrorCode errorCode,
|
||||
SSLErrorMessageType errorMessageType =
|
||||
PlainErrorMessage);
|
||||
|
||||
void Dispatch();
|
||||
private:
|
||||
const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
|
||||
const PRErrorCode mErrorCode;
|
||||
const SSLErrorMessageType mErrorMessageType;
|
||||
};
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
||||
#endif
|
@ -48,7 +48,6 @@
|
||||
#include "nsITokenDialogs.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsSSLThread.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsProxyRelease.h"
|
||||
@ -420,11 +419,10 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
|
||||
|
||||
if (!request_canceled)
|
||||
{
|
||||
bool wantExit = nsSSLThread::stoppedOrStopping();
|
||||
bool timeout =
|
||||
(PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval;
|
||||
|
||||
if (wantExit || timeout)
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
request_canceled = true;
|
||||
|
||||
@ -821,6 +819,12 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
|
||||
nsresult rv;
|
||||
PRInt32 encryptBits;
|
||||
|
||||
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
|
||||
|
||||
// If the handshake completed, then we know the site is TLS tolerant (if this
|
||||
// was a TLS connection).
|
||||
nsSSLIOLayerHelpers::rememberTolerantSite(fd, infoObject);
|
||||
|
||||
if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
|
||||
&encryptBits, &signer, nsnull)) {
|
||||
return;
|
||||
@ -842,7 +846,6 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
|
||||
|
||||
bool wantWarning = (nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746() > 0);
|
||||
|
||||
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
|
||||
nsCOMPtr<nsIConsoleService> console;
|
||||
if (infoObject && wantWarning) {
|
||||
console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
|
@ -52,11 +52,6 @@ char* PR_CALLBACK
|
||||
PK11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void* arg);
|
||||
|
||||
void PR_CALLBACK HandshakeCallback(PRFileDesc *fd, void *client_data);
|
||||
SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
|
||||
PRBool checksig, PRBool isServer);
|
||||
|
||||
PRErrorCode PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert,
|
||||
CERTCertList * serverCertChain);
|
||||
|
||||
SECStatus RegisterMyOCSPAIAInfoCallback();
|
||||
SECStatus UnregisterMyOCSPAIAInfoCallback();
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "nsNSSComponent.h"
|
||||
#include "nsNSSCallbacks.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
#include "nsSSLThread.h"
|
||||
#include "nsCertVerificationThread.h"
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
@ -364,7 +363,7 @@ nsNSSComponent::nsNSSComponent()
|
||||
mNSSInitialized(false),
|
||||
mCrlTimerLock("nsNSSComponent.mCrlTimerLock"),
|
||||
mThreadList(nsnull),
|
||||
mSSLThread(NULL), mCertVerificationThread(NULL)
|
||||
mCertVerificationThread(NULL)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gPIPNSSLog)
|
||||
@ -391,12 +390,6 @@ nsNSSComponent::nsNSSComponent()
|
||||
void
|
||||
nsNSSComponent::deleteBackgroundThreads()
|
||||
{
|
||||
if (mSSLThread)
|
||||
{
|
||||
mSSLThread->requestExit();
|
||||
delete mSSLThread;
|
||||
mSSLThread = nsnull;
|
||||
}
|
||||
if (mCertVerificationThread)
|
||||
{
|
||||
mCertVerificationThread->requestExit();
|
||||
@ -408,20 +401,11 @@ nsNSSComponent::deleteBackgroundThreads()
|
||||
void
|
||||
nsNSSComponent::createBackgroundThreads()
|
||||
{
|
||||
NS_ASSERTION(mSSLThread == nsnull, "SSL thread already created.");
|
||||
NS_ASSERTION(mCertVerificationThread == nsnull,
|
||||
"Cert verification thread already created.");
|
||||
|
||||
mSSLThread = new nsSSLThread;
|
||||
nsresult rv = mSSLThread->startThread();
|
||||
if (NS_FAILED(rv)) {
|
||||
delete mSSLThread;
|
||||
mSSLThread = nsnull;
|
||||
return;
|
||||
}
|
||||
|
||||
mCertVerificationThread = new nsCertVerificationThread;
|
||||
rv = mCertVerificationThread->startThread();
|
||||
nsresult rv = mCertVerificationThread->startThread();
|
||||
if (NS_FAILED(rv)) {
|
||||
delete mCertVerificationThread;
|
||||
mCertVerificationThread = nsnull;
|
||||
@ -1999,7 +1983,7 @@ nsNSSComponent::Init()
|
||||
mClientAuthRememberService->Init();
|
||||
|
||||
createBackgroundThreads();
|
||||
if (!mSSLThread || !mCertVerificationThread)
|
||||
if (!mCertVerificationThread)
|
||||
{
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, could not create threads\n"));
|
||||
|
||||
@ -2549,8 +2533,6 @@ nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject)
|
||||
void
|
||||
nsNSSComponent::DoProfileChangeNetTeardown()
|
||||
{
|
||||
if (mSSLThread)
|
||||
mSSLThread->requestExit();
|
||||
if (mCertVerificationThread)
|
||||
mCertVerificationThread->requestExit();
|
||||
mIsNetworkDown = true;
|
||||
|
@ -237,7 +237,6 @@ private:
|
||||
};
|
||||
|
||||
class nsNSSShutDownList;
|
||||
class nsSSLThread;
|
||||
class nsCertVerificationThread;
|
||||
|
||||
// Implementation of the PSM component interface.
|
||||
@ -357,7 +356,6 @@ private:
|
||||
|
||||
void deleteBackgroundThreads();
|
||||
void createBackgroundThreads();
|
||||
nsSSLThread *mSSLThread;
|
||||
nsCertVerificationThread *mCertVerificationThread;
|
||||
|
||||
nsNSSHttpInterface mHttpForNSS;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -60,73 +60,21 @@
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsSSLThread;
|
||||
class ::mozilla::MutexAutoLock;
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* 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();
|
||||
class MutexAutoLock;
|
||||
|
||||
bool ensure_buffer_size(PRInt32 amount);
|
||||
|
||||
enum ssl_state {
|
||||
ssl_invalid, // used for initializating, should never occur
|
||||
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;
|
||||
namespace psm {
|
||||
|
||||
// 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;
|
||||
|
||||
bool mOneBytePendingFromEarlierWrite;
|
||||
unsigned char mThePendingByte;
|
||||
PRInt32 mOriginalRequestedTransferAmount;
|
||||
enum SSLErrorMessageType {
|
||||
OverridableCertErrorMessage = 1, // for *overridable* certificate errors
|
||||
PlainErrorMessage = 2 // all other errors (or "no error")
|
||||
};
|
||||
|
||||
} // namespace psm
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
class nsNSSSocketInfo : public nsITransportSecurityInfo,
|
||||
public nsISSLSocketControl,
|
||||
public nsIInterfaceRequestor,
|
||||
@ -164,6 +112,9 @@ public:
|
||||
nsresult GetHandshakePending(bool *aHandshakePending);
|
||||
nsresult SetHandshakePending(bool aHandshakePending);
|
||||
|
||||
const char * GetHostName() const {
|
||||
return mHostName.get();
|
||||
}
|
||||
nsresult GetHostName(char **aHostName);
|
||||
nsresult SetHostName(const char *aHostName);
|
||||
|
||||
@ -172,12 +123,9 @@ public:
|
||||
|
||||
void GetPreviousCert(nsIX509Cert** _result);
|
||||
|
||||
enum ErrorMessageType {
|
||||
OverridableCertErrorMessage = 1, // for *overridable* certificate errors
|
||||
PlainErrorMessage = 2, // all other errors
|
||||
};
|
||||
void SetCanceled(PRErrorCode errorCode, ErrorMessageType errorMessageType);
|
||||
PRErrorCode GetErrorCode() const;
|
||||
void SetCanceled(PRErrorCode errorCode,
|
||||
::mozilla::psm::SSLErrorMessageType errorMessageType);
|
||||
|
||||
void SetHasCleartextPhase(bool aHasCleartextPhase);
|
||||
bool GetHasCleartextPhase();
|
||||
@ -193,8 +141,10 @@ public:
|
||||
/* Set SSL Status values */
|
||||
nsresult SetSSLStatus(nsSSLStatus *aSSLStatus);
|
||||
nsSSLStatus* SSLStatus() { return mSSLStatus; }
|
||||
|
||||
PRStatus CloseSocketAndDestroy();
|
||||
void SetStatusErrorBits(nsIX509Cert & cert, PRUint32 collected_errors);
|
||||
|
||||
PRStatus CloseSocketAndDestroy(
|
||||
const nsNSSShutDownPreventionLock & proofOfLock);
|
||||
|
||||
bool IsCertIssuerBlacklisted() const {
|
||||
return mIsCertIssuerBlacklisted;
|
||||
@ -202,14 +152,32 @@ public:
|
||||
void SetCertIssuerBlacklisted() {
|
||||
mIsCertIssuerBlacklisted = true;
|
||||
}
|
||||
|
||||
// XXX: These are only used on for diagnostic purposes
|
||||
enum CertVerificationState {
|
||||
before_cert_verification,
|
||||
waiting_for_cert_verification,
|
||||
after_cert_verification
|
||||
};
|
||||
void SetCertVerificationWaiting();
|
||||
// Use errorCode == 0 to indicate success; in that case, errorMessageType is
|
||||
// ignored.
|
||||
void SetCertVerificationResult(PRErrorCode errorCode,
|
||||
::mozilla::psm::SSLErrorMessageType errorMessageType);
|
||||
|
||||
// for logging only
|
||||
PRBool IsWaitingForCertVerification() const
|
||||
{
|
||||
return mCertVerificationState == waiting_for_cert_verification;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
mutable ::mozilla::Mutex mMutex;
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
PRFileDesc* mFd;
|
||||
enum {
|
||||
blocking_state_unknown, is_nonblocking_socket, is_blocking_socket
|
||||
} mBlockingState;
|
||||
CertVerificationState mCertVerificationState;
|
||||
PRUint32 mSecurityState;
|
||||
PRInt32 mSubRequestsHighSecurity;
|
||||
PRInt32 mSubRequestsLowSecurity;
|
||||
@ -218,7 +186,7 @@ protected:
|
||||
nsString mShortDesc;
|
||||
|
||||
PRErrorCode mErrorCode;
|
||||
ErrorMessageType mErrorMessageType;
|
||||
::mozilla::psm::SSLErrorMessageType mErrorMessageType;
|
||||
nsString mErrorMessageCached;
|
||||
nsresult formatErrorMessage(::mozilla::MutexAutoLock const & proofOfLock);
|
||||
|
||||
@ -240,13 +208,9 @@ protected:
|
||||
|
||||
nsresult ActivateSSL();
|
||||
|
||||
nsSSLSocketThreadData *mThreadData;
|
||||
|
||||
private:
|
||||
virtual void virtualDestroyNSSReference();
|
||||
void destructorSafeDestroyNSSReference();
|
||||
|
||||
friend class nsSSLThread;
|
||||
};
|
||||
|
||||
class nsCStringHashSet;
|
||||
@ -311,11 +275,6 @@ public:
|
||||
|
||||
static void setRenegoUnrestrictedSites(const nsCString &str);
|
||||
static bool isRenegoUnrestrictedSite(const nsCString &str);
|
||||
|
||||
static PRFileDesc *mSharedPollableEvent;
|
||||
static nsNSSSocketInfo *mSocketOwningPollableEvent;
|
||||
|
||||
static bool mPollableEventCurrentlySet;
|
||||
};
|
||||
|
||||
nsresult nsSSLIOLayerNewSocket(PRInt32 family,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,158 +0,0 @@
|
||||
/* ***** 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.
|
||||
nsCOMPtr<nsIRequest> mPendingHTTPRequest;
|
||||
|
||||
virtual void Run(void);
|
||||
|
||||
// Called from SSL thread only
|
||||
static PRInt32 checkHandshake(PRInt32 bytesTransfered,
|
||||
bool wasReading,
|
||||
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);
|
||||
|
||||
// Support of blocking sockets is very rudimentary.
|
||||
// We only support it because Mozilla's LDAP code requires blocking I/O.
|
||||
// We do not support switching the blocking mode of a socket.
|
||||
// We require the blocking state has been set prior to the first
|
||||
// read/write call, and will stay that way for the remainder of the socket's lifetime.
|
||||
// This function must be called while holding the lock.
|
||||
// If the socket is a blocking socket, out_fd will contain the real FD,
|
||||
// on a non-blocking socket out_fd will be nsnull.
|
||||
// If there is a failure in obtaining the status of the socket,
|
||||
// the function will return PR_FAILURE.
|
||||
static PRStatus getRealFDIfBlockingSocket_locked(nsNSSSocketInfo *si,
|
||||
PRFileDesc *&out_fd);
|
||||
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,
|
||||
PRIntervalTime timeout);
|
||||
|
||||
static PRInt32 requestWrite(nsNSSSocketInfo *si,
|
||||
const void *buf,
|
||||
PRInt32 amount,
|
||||
PRIntervalTime timeout);
|
||||
|
||||
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);
|
||||
|
||||
static bool stoppedOrStopping();
|
||||
};
|
||||
|
||||
#endif //_NSSSLTHREAD_H_
|
Loading…
Reference in New Issue
Block a user