Bug 1605894 reduce the proliferation of DefaultLoopbackTone to only AudioStreamFlowin...
[gecko.git] / security / manager / ssl / ScopedNSSTypes.h
blob6ae25db8681d3013291eb65401a99bf00aee96e3
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // This header provides smart pointers and various helpers for code that needs
8 // to interact with NSS.
10 #ifndef ScopedNSSTypes_h
11 #define ScopedNSSTypes_h
13 #include <limits>
14 #include <memory>
16 #include "cert.h"
17 #include "cms.h"
18 #include "cryptohi.h"
19 #include "keyhi.h"
20 #include "mozilla/Likely.h"
21 #include "mozilla/UniquePtr.h"
22 #include "nsDebug.h"
23 #include "nsError.h"
24 #include "NSSErrorsService.h"
25 #include "pk11hpke.h"
26 #include "pk11pub.h"
27 #include "pkcs12.h"
28 #include "prerror.h"
29 #include "prio.h"
30 #include "prmem.h"
31 #include "sechash.h"
32 #include "secmod.h"
33 #include "secpkcs7.h"
34 #include "secport.h"
36 #ifndef MOZ_NO_MOZALLOC
37 # include "mozilla/mozalloc_oom.h"
38 #endif
40 // Normally this would be included from nsNSSComponent.h, but that file includes
41 // this file.
42 bool EnsureNSSInitializedChromeOrContent();
44 namespace mozilla {
46 // NSPR APIs use PRStatus/PR_GetError and NSS APIs use SECStatus/PR_GetError to
47 // report success/failure. This function makes it more convenient and *safer*
48 // to translate NSPR/NSS results to nsresult. It is safer because it
49 // refuses to translate any bad PRStatus/SECStatus into an NS_OK, even when the
50 // NSPR/NSS function forgot to call PR_SetError. The actual enforcement of
51 // this happens in mozilla::psm::GetXPCOMFromNSSError.
52 // IMPORTANT: This must be called immediately after the function returning the
53 // SECStatus result. The recommended usage is:
54 // nsresult rv = MapSECStatus(f(x, y, z));
55 inline nsresult MapSECStatus(SECStatus rv) {
56 if (rv == SECSuccess) {
57 return NS_OK;
60 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
63 namespace internal {
65 inline void PK11_DestroyContext_true(PK11Context* ctx) {
66 PK11_DestroyContext(ctx, true);
69 inline void SECKEYEncryptedPrivateKeyInfo_true(
70 SECKEYEncryptedPrivateKeyInfo* epki) {
71 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, true);
74 // If this was created via PK11_ListFixedKeysInSlot, we may have a list of keys,
75 // in which case we have to free them all (and if not, this will still free the
76 // one key).
77 inline void FreeOneOrMoreSymKeys(PK11SymKey* keys) {
78 PK11SymKey* next;
79 while (keys) {
80 next = PK11_GetNextSymKey(keys);
81 PK11_FreeSymKey(keys);
82 keys = next;
86 } // namespace internal
88 // Emulates MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE, but for UniquePtrs.
89 #define MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(name, Type, Deleter) \
90 struct name##DeletePolicy { \
91 void operator()(Type* aValue) { Deleter(aValue); } \
92 }; \
93 typedef std::unique_ptr<Type, name##DeletePolicy> name;
95 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11Context, PK11Context,
96 internal::PK11_DestroyContext_true)
97 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotInfo, PK11SlotInfo,
98 PK11_FreeSlot)
99 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SymKey, PK11SymKey,
100 internal::FreeOneOrMoreSymKeys)
102 // Common base class for Digest and HMAC. Should not be used directly.
103 // Subclasses must implement a `Begin` function that initializes
104 // `mDigestContext` and calls `SetLength`.
105 class DigestBase {
106 protected:
107 explicit DigestBase() : mLen(0), mDigestContext(nullptr) {}
109 public:
110 nsresult Update(Span<const uint8_t> in) {
111 return Update(in.Elements(), in.Length());
114 nsresult Update(const unsigned char* buf, const uint32_t len) {
115 if (!mDigestContext) {
116 return NS_ERROR_NOT_INITIALIZED;
118 return MapSECStatus(PK11_DigestOp(mDigestContext.get(), buf, len));
121 nsresult End(/*out*/ nsTArray<uint8_t>& out) {
122 if (!mDigestContext) {
123 return NS_ERROR_NOT_INITIALIZED;
125 out.SetLength(mLen);
126 uint32_t len;
127 nsresult rv = MapSECStatus(
128 PK11_DigestFinal(mDigestContext.get(), out.Elements(), &len, mLen));
129 NS_ENSURE_SUCCESS(rv, rv);
130 mDigestContext = nullptr;
131 NS_ENSURE_TRUE(len == mLen, NS_ERROR_UNEXPECTED);
133 return NS_OK;
136 protected:
137 nsresult SetLength(SECOidTag hashType) {
138 switch (hashType) {
139 case SEC_OID_MD5:
140 mLen = MD5_LENGTH;
141 break;
142 case SEC_OID_SHA1:
143 mLen = SHA1_LENGTH;
144 break;
145 case SEC_OID_SHA256:
146 mLen = SHA256_LENGTH;
147 break;
148 case SEC_OID_SHA384:
149 mLen = SHA384_LENGTH;
150 break;
151 case SEC_OID_SHA512:
152 mLen = SHA512_LENGTH;
153 break;
154 default:
155 return NS_ERROR_INVALID_ARG;
157 return NS_OK;
160 private:
161 uint8_t mLen;
163 protected:
164 UniquePK11Context mDigestContext;
167 /** A more convenient way of dealing with digests calculated into
168 * stack-allocated buffers. NSS must be initialized on the main thread before
169 * use, and the caller must ensure NSS isn't shut down, typically by
170 * being within the lifetime of XPCOM.
172 * Typical usage, for digesting a buffer in memory:
174 * nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &rv);
175 * nsTArray<uint8_t> digestArray;
176 * nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, mybuffer, myBufferLen,
177 * digestArray);
178 * NS_ENSURE_SUCCESS(rv, rv);
180 * Less typical usage, for digesting while doing streaming I/O and similar:
182 * Digest digest;
183 * nsresult rv = digest.Begin(SEC_OID_SHA256);
184 * NS_ENSURE_SUCCESS(rv, rv);
185 * for (...) {
186 * rv = digest.Update(buf, len);
187 * NS_ENSURE_SUCCESS(rv, rv);
189 * nsTArray<uint8_t> digestArray;
190 * rv = digest.End(digestArray);
191 * NS_ENSURE_SUCCESS(rv, rv)
193 class Digest : public DigestBase {
194 public:
195 explicit Digest() = default;
197 static nsresult DigestBuf(SECOidTag hashAlg, Span<const uint8_t> buf,
198 /*out*/ nsTArray<uint8_t>& out) {
199 return Digest::DigestBuf(hashAlg, buf.Elements(), buf.Length(), out);
202 static nsresult DigestBuf(SECOidTag hashAlg, const uint8_t* buf, uint32_t len,
203 /*out*/ nsTArray<uint8_t>& out) {
204 Digest digest;
206 nsresult rv = digest.Begin(hashAlg);
207 if (NS_FAILED(rv)) {
208 return rv;
211 rv = digest.Update(buf, len);
212 if (NS_FAILED(rv)) {
213 return rv;
216 rv = digest.End(out);
217 if (NS_FAILED(rv)) {
218 return rv;
221 return rv;
224 nsresult Begin(SECOidTag hashAlg) {
225 if (!EnsureNSSInitializedChromeOrContent()) {
226 return NS_ERROR_FAILURE;
229 switch (hashAlg) {
230 case SEC_OID_SHA1:
231 case SEC_OID_SHA256:
232 case SEC_OID_SHA384:
233 case SEC_OID_SHA512:
234 break;
236 default:
237 return NS_ERROR_INVALID_ARG;
240 mDigestContext = UniquePK11Context(PK11_CreateDigestContext(hashAlg));
241 if (!mDigestContext) {
242 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
245 nsresult rv = SetLength(hashAlg);
246 NS_ENSURE_SUCCESS(rv, rv);
247 return MapSECStatus(PK11_DigestBegin(mDigestContext.get()));
251 // A helper class to calculate HMACs over some data given a key.
252 // Only SHA256 and, sadly, MD5 are supported at the moment.
253 // Typical usage:
254 // (ensure NSS is initialized)
255 // (obtain raw bytes for a key, some data to calculate the HMAC for)
256 // HMAC hmac;
257 // nsresult rv = hmac.Begin(SEC_OID_SHA256, Span(key));
258 // NS_ENSURE_SUCCESS(rv, rv);
259 // rv = hmac.Update(buf, len);
260 // NS_ENSURE_SUCCESS(rv, rv);
261 // nsTArray<uint8_t> calculatedHmac;
262 // rv = hmac.End(calculatedHmac);
263 // NS_ENSURE_SUCCESS(rv, rv);
264 class HMAC : public DigestBase {
265 public:
266 explicit HMAC() = default;
268 nsresult Begin(SECOidTag hashAlg, Span<const uint8_t> key) {
269 if (!EnsureNSSInitializedChromeOrContent()) {
270 return NS_ERROR_FAILURE;
272 CK_MECHANISM_TYPE mechType;
273 switch (hashAlg) {
274 case SEC_OID_SHA256:
275 mechType = CKM_SHA256_HMAC;
276 break;
277 case SEC_OID_MD5:
278 mechType = CKM_MD5_HMAC;
279 break;
280 default:
281 return NS_ERROR_INVALID_ARG;
283 if (key.Length() > std::numeric_limits<unsigned int>::max()) {
284 return NS_ERROR_INVALID_ARG;
286 // SECItem's data field is a non-const unsigned char*. The good news is the
287 // data won't be mutated, but the bad news is the constness needs to be
288 // casted away.
289 SECItem keyItem = {siBuffer, const_cast<unsigned char*>(key.Elements()),
290 static_cast<unsigned int>(key.Length())};
291 UniquePK11SlotInfo slot(PK11_GetInternalSlot());
292 if (!slot) {
293 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
295 UniquePK11SymKey symKey(
296 PK11_ImportSymKey(slot.get(), CKM_GENERIC_SECRET_KEY_GEN,
297 PK11_OriginUnwrap, CKA_SIGN, &keyItem, nullptr));
298 if (!symKey) {
299 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
301 SECItem emptyData = {siBuffer, nullptr, 0};
302 mDigestContext = UniquePK11Context(PK11_CreateContextBySymKey(
303 mechType, CKA_SIGN, symKey.get(), &emptyData));
304 if (!mDigestContext) {
305 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
308 nsresult rv = SetLength(hashAlg);
309 NS_ENSURE_SUCCESS(rv, rv);
310 return MapSECStatus(PK11_DigestBegin(mDigestContext.get()));
314 namespace internal {
316 inline void PORT_FreeArena_false(PLArenaPool* arena) {
317 // PL_FreeArenaPool can't be used because it doesn't actually free the
318 // memory, which doesn't work well with memory analysis tools.
319 return PORT_FreeArena(arena, false);
322 } // namespace internal
324 // Wrapper around NSS's SECItem_AllocItem that handles OOM the same way as
325 // other allocators.
326 inline void SECITEM_AllocItem(SECItem& item, uint32_t len) {
327 if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) {
328 #ifndef MOZ_NO_MOZALLOC
329 mozalloc_handle_oom(len);
330 if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len)))
331 #endif
333 MOZ_CRASH();
338 class ScopedAutoSECItem final : public SECItem {
339 public:
340 explicit ScopedAutoSECItem(uint32_t initialAllocatedLen = 0) {
341 data = nullptr;
342 len = 0;
343 if (initialAllocatedLen > 0) {
344 SECITEM_AllocItem(*this, initialAllocatedLen);
348 void reset() { SECITEM_FreeItem(this, false); }
350 ~ScopedAutoSECItem() { reset(); }
353 class MOZ_RAII AutoSECMODListReadLock final {
354 public:
355 AutoSECMODListReadLock() : mLock(SECMOD_GetDefaultModuleListLock()) {
356 MOZ_ASSERT(mLock, "should have SECMOD lock (has NSS been initialized?)");
357 SECMOD_GetReadLock(mLock);
360 ~AutoSECMODListReadLock() { SECMOD_ReleaseReadLock(mLock); }
362 private:
363 SECMODListLock* mLock;
366 namespace internal {
368 inline void SECITEM_FreeItem_true(SECItem* s) {
369 return SECITEM_FreeItem(s, true);
372 inline void SECOID_DestroyAlgorithmID_true(SECAlgorithmID* a) {
373 return SECOID_DestroyAlgorithmID(a, true);
376 inline void VFY_DestroyContext_true(VFYContext* ctx) {
377 VFY_DestroyContext(ctx, true);
380 inline void PK11_HPKE_DestroyContext_true(HpkeContext* cx) {
381 PK11_HPKE_DestroyContext(cx, true);
384 } // namespace internal
386 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificate, CERTCertificate,
387 CERT_DestroyCertificate)
388 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateList,
389 CERTCertificateList,
390 CERT_DestroyCertificateList)
391 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificatePolicies,
392 CERTCertificatePolicies,
393 CERT_DestroyCertificatePoliciesExtension)
394 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateRequest,
395 CERTCertificateRequest,
396 CERT_DestroyCertificateRequest)
397 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertList, CERTCertList,
398 CERT_DestroyCertList)
399 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTName, CERTName,
400 CERT_DestroyName)
401 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTOidSequence, CERTOidSequence,
402 CERT_DestroyOidSequence)
403 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTSubjectPublicKeyInfo,
404 CERTSubjectPublicKeyInfo,
405 SECKEY_DestroySubjectPublicKeyInfo)
406 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTUserNotice, CERTUserNotice,
407 CERT_DestroyUserNotice)
408 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTValidity, CERTValidity,
409 CERT_DestroyValidity)
411 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueHASHContext, HASHContext,
412 HASH_Destroy)
414 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSMessage, NSSCMSMessage,
415 NSS_CMSMessage_Destroy)
416 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSSignedData, NSSCMSSignedData,
417 NSS_CMSSignedData_Destroy)
419 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11GenericObject,
420 PK11GenericObject,
421 PK11_DestroyGenericObject)
422 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotList, PK11SlotList,
423 PK11_FreeSlotList)
425 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePLArenaPool, PLArenaPool,
426 internal::PORT_FreeArena_false)
427 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePORTString, char, PORT_Free)
428 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePRFileDesc, PRFileDesc, PR_Close)
429 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePRString, char, PR_Free)
431 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECAlgorithmID, SECAlgorithmID,
432 internal::SECOID_DestroyAlgorithmID_true)
433 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECItem, SECItem,
434 internal::SECITEM_FreeItem_true)
435 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPrivateKey, SECKEYPrivateKey,
436 SECKEY_DestroyPrivateKey)
437 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPrivateKeyList,
438 SECKEYPrivateKeyList,
439 SECKEY_DestroyPrivateKeyList)
440 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPublicKey, SECKEYPublicKey,
441 SECKEY_DestroyPublicKey)
442 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECMODModule, SECMODModule,
443 SECMOD_DestroyModule)
445 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSGNDigestInfo, SGNDigestInfo,
446 SGN_DestroyDigestInfo)
448 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueVFYContext, VFYContext,
449 internal::VFY_DestroyContext_true)
451 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSEC_PKCS12DecoderContext,
452 SEC_PKCS12DecoderContext,
453 SEC_PKCS12DecoderFinish)
454 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSEC_PKCS12ExportContext,
455 SEC_PKCS12ExportContext,
456 SEC_PKCS12DestroyExportContext)
457 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(
458 UniqueSECKEYEncryptedPrivateKeyInfo, SECKEYEncryptedPrivateKeyInfo,
459 internal::SECKEYEncryptedPrivateKeyInfo_true)
460 MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueHpkeContext, HpkeContext,
461 internal::PK11_HPKE_DestroyContext_true)
462 } // namespace mozilla
464 #endif // ScopedNSSTypes_h