☠☠ backed out by 5e09d599229c ☠ ☠ | |
author | Brian Smith <bsmith@mozilla.com> |
Fri, 13 Jul 2012 15:44:24 -0700 | |
changeset 114678 | 84bf2e19c701a63b1bd7275e97f40ad2d5754791 |
parent 114677 | 7ac3f15637410dbb730d9e0c02b6c786d62f4db8 |
child 114679 | c966b16e4fb5c1028d205ce23ec5840220c1cda7 |
push id | 18919 |
push user | bsmith@mozilla.com |
push date | Sat, 01 Dec 2012 02:13:53 +0000 |
treeherder | mozilla-inbound@329da1081148 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | honzab |
bugs | 804663 |
milestone | 20.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/security/manager/ssl/src/CryptoTask.cpp @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CryptoTask.h" + +namespace mozilla { + +CryptoTask::~CryptoTask() +{ + MOZ_ASSERT(mReleasedNSSResources); + + nsNSSShutDownPreventionLock lock; + if (!isAlreadyShutDown()) { + shutdown(calledFromObject); + } +} + +nsresult +CryptoTask::Dispatch(const nsACString & taskThreadName) +{ + nsCOMPtr<nsIThread> thread; + nsresult rv = NS_NewThread(getter_AddRefs(thread), this); + if (thread) { + NS_SetThreadName(thread, taskThreadName); + } + return rv; +} + +NS_IMETHODIMP +CryptoTask::Run() +{ + if (!NS_IsMainThread()) { + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown()) { + mRv = NS_ERROR_NOT_AVAILABLE; + } else { + mRv = CalculateResult(); + } + NS_DispatchToMainThread(this); + } else { + // back on the main thread + + // call ReleaseNSSResources now, before calling CallCallback, so that + // CryptoTasks have consistent behavior regardless of whether NSS is shut + // down between CalculateResult being called and CallCallback being called. + if (!mReleasedNSSResources) { + mReleasedNSSResources = true; + ReleaseNSSResources(); + } + + CallCallback(mRv); + } + + return NS_OK; +} + +void +CryptoTask::virtualDestroyNSSReference() +{ + NS_ABORT_IF_FALSE(NS_IsMainThread(), + "virtualDestroyNSSReference called off the main thread"); + if (!mReleasedNSSResources) { + mReleasedNSSResources = true; + ReleaseNSSResources(); + } +} + +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/security/manager/ssl/src/CryptoTask.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla__CryptoTask_h +#define mozilla__CryptoTask_h + +#include "mozilla/Attributes.h" +#include "nsThreadUtils.h" +#include "nsNSSShutDown.h" + +namespace mozilla { + +/** + * Frequently we need to run a task on a background thread without blocking + * the main thread, and then call a callback on the main thread with the + * result. This class provides the framework for that. Subclasses must: + * + * (1) Override CalculateResult for the off-the-main-thread computation. + * NSS functionality may only be accessed within CalculateResult. + * (2) Override ReleaseNSSResources to release references to all NSS + * resources (that do implement nsNSSShutDownObject themselves). + * (3) Override CallCallback() for the on-the-main-thread call of the + * callback. + * + * CalculateResult, ReleaseNSSResources, and CallCallback are called in order, + * except CalculateResult might be skipped if NSS is shut down before it can + * be called; in that case ReleaseNSSResources will be called and then + * CallCallback will be called with an error code. + */ +class CryptoTask : public nsRunnable, + public nsNSSShutDownObject +{ +public: + template <size_t LEN> + nsresult Dispatch(const char (&taskThreadName)[LEN]) + { + MOZ_STATIC_ASSERT(LEN <= 15, + "Thread name must be no more than 15 characters"); + return Dispatch(nsDependentCString(taskThreadName)); + } + +protected: + CryptoTask() + : mRv(NS_ERROR_NOT_INITIALIZED), + mReleasedNSSResources(false) + { + } + + virtual ~CryptoTask(); + + /** + * Called on a background thread (never the main thread). If CalculateResult + * is called, then its result will be passed to CallCallback on the main + * thread. + */ + virtual nsresult CalculateResult() = 0; + + /** + * Called on the main thread during NSS shutdown or just before CallCallback + * has been called. All NSS resources must be released. Usually, this just + * means assigning nullptr to the ScopedNSSType-based memory variables. + */ + virtual void ReleaseNSSResources() = 0; + + /** + * Called on the main thread with the result from CalculateResult() or + * with an error code if NSS was shut down before CalculateResult could + * be called. + */ + virtual void CallCallback(nsresult rv) = 0; + +private: + NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL; + virtual void virtualDestroyNSSReference() MOZ_OVERRIDE MOZ_FINAL; + + nsresult Dispatch(const nsACString & taskThreadName); + + nsresult mRv; + bool mReleasedNSSResources; +}; + +} // namespace mozilla + +#endif // mozilla__CryptoTask_h
--- a/security/manager/ssl/src/Makefile.in +++ b/security/manager/ssl/src/Makefile.in @@ -15,16 +15,17 @@ MODULE = pipnss LIBRARY_NAME = pipnss IS_COMPONENT = 1 MODULE_NAME = NSS EXPORT_LIBRARY = 1 GRE_MODULE = 1 LIBXUL_LIBRARY = 1 CPPSRCS = \ + CryptoTask.cpp \ nsCERTValInParamWrapper.cpp \ nsNSSCleaner.cpp \ nsCertOverrideService.cpp \ nsRecentBadCerts.cpp \ nsClientAuthRemember.cpp \ nsPSMBackgroundThread.cpp \ nsCertVerificationThread.cpp \ nsProtectedAuthThread.cpp \ @@ -85,14 +86,15 @@ EXTRA_DEPS = $(NSS_DEP_LIBS) DEFINES += \ -DNSS_ENABLE_ECC \ -DDLL_PREFIX=\"$(DLL_PREFIX)\" \ -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" \ $(NULL) EXPORTS += \ + CryptoTask.h \ nsNSSShutDown.h \ ScopedNSSTypes.h \ $(NULL) include $(topsrcdir)/config/rules.mk
--- a/security/manager/ssl/src/ScopedNSSTypes.h +++ b/security/manager/ssl/src/ScopedNSSTypes.h @@ -2,27 +2,82 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_ScopedNSSTypes_h #define mozilla_ScopedNSSTypes_h +#include "mozilla/Likely.h" +#include "mozilla/mozalloc_oom.h" #include "mozilla/Scoped.h" #include "prio.h" #include "cert.h" #include "cms.h" #include "keyhi.h" #include "pk11pub.h" #include "sechash.h" +#include "secpkcs7.h" +#include "prerror.h" namespace mozilla { +// It is very common to cast between char* and uint8_t* when doing crypto stuff. +// Here, we provide more type-safe wrappers around reinterpret_cast so you don't +// shoot yourself in the foot by reinterpret_casting completely unrelated types. + +inline char * +char_ptr_cast(uint8_t * p) { return reinterpret_cast<char *>(p); } + +inline const char * +char_ptr_cast(const uint8_t * p) { return reinterpret_cast<const char *>(p); } + +inline uint8_t * +uint8_t_ptr_cast(char * p) { return reinterpret_cast<uint8_t*>(p); } + +inline const uint8_t * +uint8_t_ptr_cast(const char * p) { return reinterpret_cast<const uint8_t*>(p); } + +// NSPR APIs use PRStatus/PR_GetError and NSS APIs use SECStatus/PR_GetError to +// report success/failure. These funtions make it more convenient and *safer* +// to translate NSPR/NSS results to nsresult. They are safer because they +// refuse to traslate any bad PRStatus/SECStatus into an NS_OK, even when the +// NSPR/NSS function forgot to call PR_SetError. + +// IMPORTANT: This must be called immediately after the function that set the +// error code. Prefer using MapSECStatus to this. +inline nsresult +PRErrorCode_to_nsresult(PRErrorCode error) +{ + if (!error) { + MOZ_NOT_REACHED("Function failed without calling PR_GetError"); + return NS_ERROR_UNEXPECTED; + } + + // From NSSErrorsService::GetXPCOMFromNSSError + // XXX Don't make up nsresults, it's supposed to be an enum (bug 778113) + return (nsresult)NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, + -1 * error); +} + +// IMPORTANT: This must be called immediately after the function returning the +// SECStatus result. The recommended usage is: +// nsresult rv = MapSECStatus(f(x, y, z)); +inline nsresult +MapSECStatus(SECStatus rv) +{ + if (rv == SECSuccess) + return NS_OK; + + PRErrorCode error = PR_GetError(); + return PRErrorCode_to_nsresult(error); +} + // Alphabetical order by NSS type MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificate, CERTCertificate, CERT_DestroyCertificate) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateList, @@ -42,38 +97,174 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLAT CERT_FreeNicknames) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTSubjectPublicKeyInfo, CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTValidity, CERTValidity, CERT_DestroyValidity) -MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedHASHContext, - HASHContext, - HASH_Destroy) - MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedNSSCMSMessage, NSSCMSMessage, NSS_CMSMessage_Destroy) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedNSSCMSSignedData, NSSCMSSignedData, NSS_CMSSignedData_Destroy) +namespace psm { + +inline void +PK11_DestroyContext_true(PK11Context * ctx) { + PK11_DestroyContext(ctx, true); +} + +} // namespace mozilla::psm + +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11Context, + PK11Context, + mozilla::psm::PK11_DestroyContext_true) + +/** A more convenient way of dealing with digests calculated into + * stack-allocated buffers. + * + * Typical usage, for digesting a buffer in memory: + * + * Digest digest; + * nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mybuffer, myBufferLen); + * NS_ENSURE_SUCCESS(rv, rv); + * rv = MapSECStatus(SomeNSSFunction(..., digest.get(), ...)); + * + * Less typical usage, for digesting while doing streaming I/O and similar: + * + * Digest digest; + * ScopedPK11Context digestContext(PK11_CreateDigestContext(SEC_OID_SHA1)); + * NS_ENSURE_TRUE(digestContext, NS_ERROR_OUT_OF_MEMORY); + * rv = MapSECStatus(PK11_DigestBegin(digestContext)); + * NS_ENSURE_SUCCESS(rv, rv); + * for (...) { + * rv = MapSECStatus(PK11_DigestOp(digestContext, ...)); + * NS_ENSURE_SUCCESS(rv, rv); + * } + * rv = digestContext.End(SEC_OID_SHA1, digestContext); + * NS_ENSURE_SUCCESS(rv, rv) + */ +class Digest +{ +public: + Digest() + { + item.type = siBuffer; + item.data = buf; + item.len = 0; + } + + nsresult DigestBuf(SECOidTag hashAlg, const uint8_t * buf, uint32_t len) + { + nsresult rv = SetLength(hashAlg); + NS_ENSURE_SUCCESS(rv, rv); + return MapSECStatus(PK11_HashBuf(hashAlg, item.data, buf, len)); + } + + nsresult End(SECOidTag hashAlg, ScopedPK11Context & context) + { + nsresult rv = SetLength(hashAlg); + NS_ENSURE_SUCCESS(rv, rv); + uint32_t len; + rv = MapSECStatus(PK11_DigestFinal(context, item.data, &len, item.len)); + NS_ENSURE_SUCCESS(rv, rv); + context = nullptr; + NS_ENSURE_TRUE(len == item.len, NS_ERROR_UNEXPECTED); + return NS_OK; + } + + const SECItem & get() const { return item; } + +private: + nsresult SetLength(SECOidTag hashType) + { + switch (hashType) + { + case SEC_OID_SHA1: item.len = SHA1_LENGTH; break; + case SEC_OID_SHA256: item.len = SHA256_LENGTH; break; + case SEC_OID_SHA384: item.len = SHA384_LENGTH; break; + case SEC_OID_SHA512: item.len = SHA512_LENGTH; break; + default: + return NS_ERROR_INVALID_ARG; + } + + return NS_OK; + } + + uint8_t buf[HASH_LENGTH_MAX]; + SECItem item; +}; MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SlotInfo, PK11SlotInfo, PK11_FreeSlot) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SlotList, PK11SlotList, PK11_FreeSlotList) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SymKey, PK11SymKey, PK11_FreeSymKey) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSEC_PKCS7ContentInfo, + SEC_PKCS7ContentInfo, + SEC_PKCS7DestroyContentInfo) + +// Wrapper around NSS's SECItem_AllocItem that handles OOM the same way as +// other allocators. +inline void +SECITEM_AllocItem(SECItem & item, uint32_t len) +{ + if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) { + mozalloc_handle_oom(len); + if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) { + MOZ_CRASH(); + } + } +} + +class ScopedAutoSECItem MOZ_FINAL : public SECItem +{ +public: + ScopedAutoSECItem(uint32_t initialAllocatedLen = 0) + { + data = NULL; + len = 0; + if (initialAllocatedLen > 0) { + SECITEM_AllocItem(*this, initialAllocatedLen); + } + } + + void reset() + { + SECITEM_FreeItem(this, false); + } + + ~ScopedAutoSECItem() + { + reset(); + } +}; + +namespace psm { + +inline void SECITEM_FreeItem_true(SECItem * s) +{ + return SECITEM_FreeItem(s, true); +} + +} // namespace impl + +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECItem, + ::SECItem, + ::mozilla::psm::SECITEM_FreeItem_true) + MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPrivateKey, SECKEYPrivateKey, SECKEY_DestroyPrivateKey) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPublicKey, SECKEYPublicKey, SECKEY_DestroyPublicKey) } // namespace mozilla
--- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -50,16 +50,17 @@ #include "nsIBufEntropyCollector.h" #include "nsIServiceManager.h" #include "nsIFile.h" #include "nsITokenPasswordDialogs.h" #include "nsICRLManager.h" #include "nsNSSShutDown.h" #include "nsSmartCardEvent.h" #include "nsIKeyModule.h" +#include "ScopedNSSTypes.h" #include "nss.h" #include "pk11func.h" #include "ssl.h" #include "sslproto.h" #include "secmod.h" #include "sechash.h" #include "secmime.h" @@ -2023,17 +2024,17 @@ nsNSSComponent::VerifySignature(const ch if (!aPrincipal || !aErrorCode) { return NS_ERROR_NULL_POINTER; } *aErrorCode = 0; *aPrincipal = nullptr; nsNSSShutDownPreventionLock locker; - SEC_PKCS7ContentInfo * p7_info = nullptr; + ScopedSEC_PKCS7ContentInfo p7_info; unsigned char hash[SHA1_LENGTH]; SECItem item; item.type = siEncodedCertBuffer; item.data = (unsigned char*)aRSABuf; item.len = aRSABufLen; p7_info = SEC_PKCS7DecodeItem(&item, ContentCallback, nullptr, @@ -2122,18 +2123,16 @@ nsNSSComponent::VerifySignature(const ch NS_ConvertUTF16toUTF8(subjectName), NS_ConvertUTF16toUTF8(orgName), pCert); certPrincipal.swap(*aPrincipal); } while (0); } - SEC_PKCS7DestroyContentInfo(p7_info); - return rv2; } NS_IMETHODIMP nsNSSComponent::RandomUpdate(void *entropy, int32_t bufLen) { nsNSSShutDownPreventionLock locker;
--- a/toolkit/identity/IdentityCryptoService.cpp +++ b/toolkit/identity/IdentityCryptoService.cpp @@ -8,16 +8,17 @@ #include "mozilla/ModuleUtils.h" #include "nsServiceManagerUtils.h" #include "nsNSSShutDown.h" #include "nsIThread.h" #include "nsThreadUtils.h" #include "nsCOMPtr.h" #include "nsStringGlue.h" #include "mozilla/Base64.h" +#include "ScopedNSSTypes.h" #include "nss.h" #include "pk11pub.h" #include "secmod.h" #include "secerr.h" #include "keyhi.h" #include "cryptohi.h" @@ -55,44 +56,16 @@ Base64UrlEncodeImpl(const nsACString & u } else if (out[i] == '/') { out[i] = '_'; } } return NS_OK; } - -nsresult -PRErrorCode_to_nsresult(PRErrorCode error) -{ - if (!error) { - MOZ_NOT_REACHED("Function failed without calling PR_GetError"); - return NS_ERROR_UNEXPECTED; - } - - // From NSSErrorsService::GetXPCOMFromNSSError - // XXX Don't make up nsresults, it's supposed to be an enum (bug 778113) - return (nsresult)NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, - -1 * error); -} - -// IMPORTANT: This must be called immediately after the function returning the -// SECStatus result. The recommended usage is: -// nsresult rv = MapSECStatus(f(x, y, z)); -nsresult -MapSECStatus(SECStatus rv) -{ - if (rv == SECSuccess) - return NS_OK; - - PRErrorCode error = PR_GetError(); - return PRErrorCode_to_nsresult(error); -} - #define DSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("DS160")) #define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256")) class KeyPair : public nsIIdentityKeyPair, public nsNSSShutDownObject { public: NS_DECL_ISUPPORTS NS_DECL_NSIIDENTITYKEYPAIR