From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- security/manager/ssl/ScopedNSSTypes.h | 405 ++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 security/manager/ssl/ScopedNSSTypes.h (limited to 'security/manager/ssl/ScopedNSSTypes.h') diff --git a/security/manager/ssl/ScopedNSSTypes.h b/security/manager/ssl/ScopedNSSTypes.h new file mode 100644 index 000000000..d36f84c97 --- /dev/null +++ b/security/manager/ssl/ScopedNSSTypes.h @@ -0,0 +1,405 @@ +/* -*- 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/. */ + +// This header provides smart pointers and various helpers for code that needs +// to interact with NSS. + +#ifndef ScopedNSSTypes_h +#define ScopedNSSTypes_h + +#include +#include + +#include "cert.h" +#include "cms.h" +#include "cryptohi.h" +#include "keyhi.h" +#include "mozilla/Likely.h" +#include "mozilla/Scoped.h" +#include "mozilla/UniquePtr.h" +#include "nsDebug.h" +#include "nsError.h" +#include "NSSErrorsService.h" +#include "pk11pub.h" +#include "pkcs12.h" +#include "prerror.h" +#include "prio.h" +#include "sechash.h" +#include "secmod.h" +#include "secpkcs7.h" +#include "secport.h" + +#ifndef MOZ_NO_MOZALLOC +#include "mozilla/mozalloc_oom.h" +#endif + +namespace mozilla { + +// NSPR APIs use PRStatus/PR_GetError and NSS APIs use SECStatus/PR_GetError to +// report success/failure. This function makes it more convenient and *safer* +// to translate NSPR/NSS results to nsresult. It is safer because it +// refuses to translate any bad PRStatus/SECStatus into an NS_OK, even when the +// NSPR/NSS function forgot to call PR_SetError. The actual enforcement of +// this happens in mozilla::psm::GetXPCOMFromNSSError. +// 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; + } + + return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); +} + +// Alphabetical order by NSS type +// Deprecated: use the equivalent UniquePtr templates instead. +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificate, + CERTCertificate, + CERT_DestroyCertificate) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateList, + CERTCertificateList, + CERT_DestroyCertificateList) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateRequest, + CERTCertificateRequest, + CERT_DestroyCertificateRequest) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTName, + CERTName, + CERT_DestroyName) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTSubjectPublicKeyInfo, + CERTSubjectPublicKeyInfo, + SECKEY_DestroySubjectPublicKeyInfo) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTValidity, + CERTValidity, + CERT_DestroyValidity) +// Deprecated: use the equivalent UniquePtr templates instead. + +namespace internal { + +inline void +PK11_DestroyContext_true(PK11Context * ctx) { + PK11_DestroyContext(ctx, true); +} + +} // namespace internal + +// Deprecated: use the equivalent UniquePtr templates instead. +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSGNDigestInfo, + SGNDigestInfo, + SGN_DestroyDigestInfo) + +// Emulates MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE, but for UniquePtrs. +#define MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(name, Type, Deleter) \ +struct name##DeletePolicy \ +{ \ + void operator()(Type* aValue) { Deleter(aValue); } \ +}; \ +typedef std::unique_ptr name; + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11Context, + PK11Context, + internal::PK11_DestroyContext_true) + +/** A more convenient way of dealing with digests calculated into + * stack-allocated buffers. NSS must be initialized on the main thread before + * use, and the caller must ensure NSS isn't shut down, typically by + * subclassing nsNSSShutDownObject, while Digest is in use. + * + * Typical usage, for digesting a buffer in memory: + * + * nsCOMPtr nssDummy = do_GetService("@mozilla.org/psm;1", &rv); + * 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; + * UniquePK11Context digestContext(PK11_CreateDigestContext(SEC_OID_SHA256)); + * NS_ENSURE_TRUE(digestContext, NS_ERROR_OUT_OF_MEMORY); + * rv = MapSECStatus(PK11_DigestBegin(digestContext.get())); + * NS_ENSURE_SUCCESS(rv, rv); + * for (...) { + * rv = MapSECStatus(PK11_DigestOp(digestContext.get(), ...)); + * NS_ENSURE_SUCCESS(rv, rv); + * } + * rv = digest.End(SEC_OID_SHA256, digestContext); + * NS_ENSURE_SUCCESS(rv, rv) + */ +class Digest +{ +public: + Digest() + { + mItem.type = siBuffer; + mItem.data = mItemBuf; + mItem.len = 0; + } + + nsresult DigestBuf(SECOidTag hashAlg, const uint8_t * buf, uint32_t len) + { + if (len > static_cast(std::numeric_limits::max())) { + return NS_ERROR_INVALID_ARG; + } + nsresult rv = SetLength(hashAlg); + NS_ENSURE_SUCCESS(rv, rv); + return MapSECStatus(PK11_HashBuf(hashAlg, mItem.data, buf, + static_cast(len))); + } + + nsresult End(SECOidTag hashAlg, UniquePK11Context& context) + { + nsresult rv = SetLength(hashAlg); + NS_ENSURE_SUCCESS(rv, rv); + uint32_t len; + rv = MapSECStatus(PK11_DigestFinal(context.get(), mItem.data, &len, + mItem.len)); + NS_ENSURE_SUCCESS(rv, rv); + context = nullptr; + NS_ENSURE_TRUE(len == mItem.len, NS_ERROR_UNEXPECTED); + return NS_OK; + } + + const SECItem & get() const { return mItem; } + +private: + nsresult SetLength(SECOidTag hashType) + { +#ifdef _MSC_VER +#pragma warning(push) + // C4061: enumerator 'symbol' in switch of enum 'symbol' is not + // explicitly handled. +#pragma warning(disable:4061) +#endif + switch (hashType) + { + case SEC_OID_SHA1: mItem.len = SHA1_LENGTH; break; + case SEC_OID_SHA256: mItem.len = SHA256_LENGTH; break; + case SEC_OID_SHA384: mItem.len = SHA384_LENGTH; break; + case SEC_OID_SHA512: mItem.len = SHA512_LENGTH; break; + default: + return NS_ERROR_INVALID_ARG; + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + return NS_OK; + } + + uint8_t mItemBuf[HASH_LENGTH_MAX]; + SECItem mItem; +}; + +// Deprecated: use the equivalent UniquePtr templates instead. +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SlotInfo, + PK11SlotInfo, + PK11_FreeSlot) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11SymKey, + PK11SymKey, + PK11_FreeSymKey) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11GenericObject, + PK11GenericObject, + PK11_DestroyGenericObject) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSEC_PKCS12DecoderContext, + SEC_PKCS12DecoderContext, + SEC_PKCS12DecoderFinish) +namespace internal { + +inline void +PORT_FreeArena_false(PLArenaPool* arena) +{ + // PL_FreeArenaPool can't be used because it doesn't actually free the + // memory, which doesn't work well with memory analysis tools. + return PORT_FreeArena(arena, false); +} + +} // namespace internal + +// Deprecated: use the equivalent UniquePtr templates instead. +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPLArenaPool, + PLArenaPool, + internal::PORT_FreeArena_false) + +// 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))) { +#ifndef MOZ_NO_MOZALLOC + mozalloc_handle_oom(len); + if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) +#endif + { + MOZ_CRASH(); + } + } +} + +class ScopedAutoSECItem final : public SECItem +{ +public: + explicit ScopedAutoSECItem(uint32_t initialAllocatedLen = 0) + { + data = nullptr; + len = 0; + if (initialAllocatedLen > 0) { + SECITEM_AllocItem(*this, initialAllocatedLen); + } + } + + void reset() + { + SECITEM_FreeItem(this, false); + } + + ~ScopedAutoSECItem() + { + reset(); + } +}; + +class MOZ_RAII AutoSECMODListReadLock final +{ +public: + AutoSECMODListReadLock() + : mLock(SECMOD_GetDefaultModuleListLock()) + { + MOZ_ASSERT(mLock, "should have SECMOD lock (has NSS been initialized?)"); + SECMOD_GetReadLock(mLock); + } + + ~AutoSECMODListReadLock() + { + SECMOD_ReleaseReadLock(mLock); + } + +private: + SECMODListLock* mLock; +}; + +namespace internal { + +inline void SECITEM_FreeItem_true(SECItem * s) +{ + return SECITEM_FreeItem(s, true); +} + +inline void SECOID_DestroyAlgorithmID_true(SECAlgorithmID * a) +{ + return SECOID_DestroyAlgorithmID(a, true); +} + +inline void SECKEYEncryptedPrivateKeyInfo_true(SECKEYEncryptedPrivateKeyInfo * epki) +{ + return SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); +} + +inline void VFY_DestroyContext_true(VFYContext * ctx) +{ + VFY_DestroyContext(ctx, true); +} + +} // namespace internal + +// Deprecated: use the equivalent UniquePtr templates instead. +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECItem, + SECItem, + internal::SECITEM_FreeItem_true) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPrivateKey, + SECKEYPrivateKey, + SECKEY_DestroyPrivateKey) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYEncryptedPrivateKeyInfo, + SECKEYEncryptedPrivateKeyInfo, + internal::SECKEYEncryptedPrivateKeyInfo_true) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPublicKey, + SECKEYPublicKey, + SECKEY_DestroyPublicKey) +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECAlgorithmID, + SECAlgorithmID, + internal::SECOID_DestroyAlgorithmID_true) + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificate, + CERTCertificate, + CERT_DestroyCertificate) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateList, + CERTCertificateList, + CERT_DestroyCertificateList) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificatePolicies, + CERTCertificatePolicies, + CERT_DestroyCertificatePoliciesExtension) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateRequest, + CERTCertificateRequest, + CERT_DestroyCertificateRequest) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertList, + CERTCertList, + CERT_DestroyCertList) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTName, + CERTName, + CERT_DestroyName) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTOidSequence, + CERTOidSequence, + CERT_DestroyOidSequence) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTSubjectPublicKeyInfo, + CERTSubjectPublicKeyInfo, + SECKEY_DestroySubjectPublicKeyInfo) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTUserNotice, + CERTUserNotice, + CERT_DestroyUserNotice) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTValidity, + CERTValidity, + CERT_DestroyValidity) + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSMessage, + NSSCMSMessage, + NSS_CMSMessage_Destroy) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSSignedData, + NSSCMSSignedData, + NSS_CMSSignedData_Destroy) + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotInfo, + PK11SlotInfo, + PK11_FreeSlot) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotList, + PK11SlotList, + PK11_FreeSlotList) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SymKey, + PK11SymKey, + PK11_FreeSymKey) + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePLArenaPool, + PLArenaPool, + internal::PORT_FreeArena_false) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePORTString, + char, + PORT_Free); +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePRFileDesc, + PRFileDesc, + PR_Close) + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECItem, + SECItem, + internal::SECITEM_FreeItem_true) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPrivateKey, + SECKEYPrivateKey, + SECKEY_DestroyPrivateKey) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPublicKey, + SECKEYPublicKey, + SECKEY_DestroyPublicKey) +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECMODModule, + SECMODModule, + SECMOD_DestroyModule) + +MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueVFYContext, + VFYContext, + internal::VFY_DestroyContext_true) +} // namespace mozilla + +#endif // ScopedNSSTypes_h -- cgit v1.2.3