Line data Source code
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/. */
6 :
7 : // This header provides smart pointers and various helpers for code that needs
8 : // to interact with NSS.
9 :
10 : #ifndef ScopedNSSTypes_h
11 : #define ScopedNSSTypes_h
12 :
13 : #include <limits>
14 : #include <memory>
15 :
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 "pk11pub.h"
26 : #include "pkcs12.h"
27 : #include "prerror.h"
28 : #include "prio.h"
29 : #include "sechash.h"
30 : #include "secmod.h"
31 : #include "secpkcs7.h"
32 : #include "secport.h"
33 :
34 : #ifndef MOZ_NO_MOZALLOC
35 : #include "mozilla/mozalloc_oom.h"
36 : #endif
37 :
38 : namespace mozilla {
39 :
40 : // NSPR APIs use PRStatus/PR_GetError and NSS APIs use SECStatus/PR_GetError to
41 : // report success/failure. This function makes it more convenient and *safer*
42 : // to translate NSPR/NSS results to nsresult. It is safer because it
43 : // refuses to translate any bad PRStatus/SECStatus into an NS_OK, even when the
44 : // NSPR/NSS function forgot to call PR_SetError. The actual enforcement of
45 : // this happens in mozilla::psm::GetXPCOMFromNSSError.
46 : // IMPORTANT: This must be called immediately after the function returning the
47 : // SECStatus result. The recommended usage is:
48 : // nsresult rv = MapSECStatus(f(x, y, z));
49 : inline nsresult
50 1 : MapSECStatus(SECStatus rv)
51 : {
52 1 : if (rv == SECSuccess) {
53 1 : return NS_OK;
54 : }
55 :
56 0 : return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
57 : }
58 :
59 : namespace internal {
60 :
61 : inline void
62 0 : PK11_DestroyContext_true(PK11Context * ctx) {
63 0 : PK11_DestroyContext(ctx, true);
64 0 : }
65 :
66 : } // namespace internal
67 :
68 : // Emulates MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE, but for UniquePtrs.
69 : #define MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(name, Type, Deleter) \
70 : struct name##DeletePolicy \
71 : { \
72 : void operator()(Type* aValue) { Deleter(aValue); } \
73 : }; \
74 : typedef std::unique_ptr<Type, name##DeletePolicy> name;
75 :
76 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11Context,
77 : PK11Context,
78 : internal::PK11_DestroyContext_true)
79 :
80 : /** A more convenient way of dealing with digests calculated into
81 : * stack-allocated buffers. NSS must be initialized on the main thread before
82 : * use, and the caller must ensure NSS isn't shut down, typically by
83 : * subclassing nsNSSShutDownObject, while Digest is in use.
84 : *
85 : * Typical usage, for digesting a buffer in memory:
86 : *
87 : * nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &rv);
88 : * Digest digest;
89 : * nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mybuffer, myBufferLen);
90 : * NS_ENSURE_SUCCESS(rv, rv);
91 : * rv = MapSECStatus(SomeNSSFunction(..., digest.get(), ...));
92 : *
93 : * Less typical usage, for digesting while doing streaming I/O and similar:
94 : *
95 : * Digest digest;
96 : * UniquePK11Context digestContext(PK11_CreateDigestContext(SEC_OID_SHA256));
97 : * NS_ENSURE_TRUE(digestContext, NS_ERROR_OUT_OF_MEMORY);
98 : * rv = MapSECStatus(PK11_DigestBegin(digestContext.get()));
99 : * NS_ENSURE_SUCCESS(rv, rv);
100 : * for (...) {
101 : * rv = MapSECStatus(PK11_DigestOp(digestContext.get(), ...));
102 : * NS_ENSURE_SUCCESS(rv, rv);
103 : * }
104 : * rv = digest.End(SEC_OID_SHA256, digestContext);
105 : * NS_ENSURE_SUCCESS(rv, rv)
106 : */
107 : class Digest
108 : {
109 : public:
110 0 : Digest()
111 0 : {
112 0 : mItem.type = siBuffer;
113 0 : mItem.data = mItemBuf;
114 0 : mItem.len = 0;
115 0 : }
116 :
117 0 : nsresult DigestBuf(SECOidTag hashAlg, const uint8_t * buf, uint32_t len)
118 : {
119 0 : if (len > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
120 0 : return NS_ERROR_INVALID_ARG;
121 : }
122 0 : nsresult rv = SetLength(hashAlg);
123 0 : NS_ENSURE_SUCCESS(rv, rv);
124 0 : return MapSECStatus(PK11_HashBuf(hashAlg, mItem.data, buf,
125 0 : static_cast<int32_t>(len)));
126 : }
127 :
128 0 : nsresult End(SECOidTag hashAlg, UniquePK11Context& context)
129 : {
130 0 : nsresult rv = SetLength(hashAlg);
131 0 : NS_ENSURE_SUCCESS(rv, rv);
132 : uint32_t len;
133 0 : rv = MapSECStatus(PK11_DigestFinal(context.get(), mItem.data, &len,
134 0 : mItem.len));
135 0 : NS_ENSURE_SUCCESS(rv, rv);
136 0 : context = nullptr;
137 0 : NS_ENSURE_TRUE(len == mItem.len, NS_ERROR_UNEXPECTED);
138 0 : return NS_OK;
139 : }
140 :
141 0 : const SECItem & get() const { return mItem; }
142 :
143 : private:
144 0 : nsresult SetLength(SECOidTag hashType)
145 : {
146 : #ifdef _MSC_VER
147 : #pragma warning(push)
148 : // C4061: enumerator 'symbol' in switch of enum 'symbol' is not
149 : // explicitly handled.
150 : #pragma warning(disable:4061)
151 : #endif
152 0 : switch (hashType)
153 : {
154 0 : case SEC_OID_SHA1: mItem.len = SHA1_LENGTH; break;
155 0 : case SEC_OID_SHA256: mItem.len = SHA256_LENGTH; break;
156 0 : case SEC_OID_SHA384: mItem.len = SHA384_LENGTH; break;
157 0 : case SEC_OID_SHA512: mItem.len = SHA512_LENGTH; break;
158 : default:
159 0 : return NS_ERROR_INVALID_ARG;
160 : }
161 : #ifdef _MSC_VER
162 : #pragma warning(pop)
163 : #endif
164 :
165 0 : return NS_OK;
166 : }
167 :
168 : uint8_t mItemBuf[HASH_LENGTH_MAX];
169 : SECItem mItem;
170 : };
171 :
172 : namespace internal {
173 :
174 : inline void
175 0 : PORT_FreeArena_false(PLArenaPool* arena)
176 : {
177 : // PL_FreeArenaPool can't be used because it doesn't actually free the
178 : // memory, which doesn't work well with memory analysis tools.
179 0 : return PORT_FreeArena(arena, false);
180 : }
181 :
182 : } // namespace internal
183 :
184 : // Wrapper around NSS's SECItem_AllocItem that handles OOM the same way as
185 : // other allocators.
186 : inline void
187 0 : SECITEM_AllocItem(SECItem & item, uint32_t len)
188 : {
189 0 : if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) {
190 : #ifndef MOZ_NO_MOZALLOC
191 0 : mozalloc_handle_oom(len);
192 0 : if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len)))
193 : #endif
194 : {
195 0 : MOZ_CRASH();
196 : }
197 : }
198 0 : }
199 :
200 : class ScopedAutoSECItem final : public SECItem
201 : {
202 : public:
203 86 : explicit ScopedAutoSECItem(uint32_t initialAllocatedLen = 0)
204 86 : {
205 86 : data = nullptr;
206 86 : len = 0;
207 86 : if (initialAllocatedLen > 0) {
208 0 : SECITEM_AllocItem(*this, initialAllocatedLen);
209 : }
210 86 : }
211 :
212 86 : void reset()
213 : {
214 86 : SECITEM_FreeItem(this, false);
215 86 : }
216 :
217 86 : ~ScopedAutoSECItem()
218 86 : {
219 86 : reset();
220 86 : }
221 : };
222 :
223 : class MOZ_RAII AutoSECMODListReadLock final
224 : {
225 : public:
226 2 : AutoSECMODListReadLock()
227 2 : : mLock(SECMOD_GetDefaultModuleListLock())
228 : {
229 2 : MOZ_ASSERT(mLock, "should have SECMOD lock (has NSS been initialized?)");
230 2 : SECMOD_GetReadLock(mLock);
231 2 : }
232 :
233 2 : ~AutoSECMODListReadLock()
234 2 : {
235 2 : SECMOD_ReleaseReadLock(mLock);
236 2 : }
237 :
238 : private:
239 : SECMODListLock* mLock;
240 : };
241 :
242 : namespace internal {
243 :
244 0 : inline void SECITEM_FreeItem_true(SECItem * s)
245 : {
246 0 : return SECITEM_FreeItem(s, true);
247 : }
248 :
249 0 : inline void SECOID_DestroyAlgorithmID_true(SECAlgorithmID * a)
250 : {
251 0 : return SECOID_DestroyAlgorithmID(a, true);
252 : }
253 :
254 : inline void SECKEYEncryptedPrivateKeyInfo_true(SECKEYEncryptedPrivateKeyInfo * epki)
255 : {
256 : return SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
257 : }
258 :
259 0 : inline void VFY_DestroyContext_true(VFYContext * ctx)
260 : {
261 0 : VFY_DestroyContext(ctx, true);
262 0 : }
263 :
264 : } // namespace internal
265 :
266 83 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificate,
267 : CERTCertificate,
268 : CERT_DestroyCertificate)
269 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateList,
270 : CERTCertificateList,
271 : CERT_DestroyCertificateList)
272 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificatePolicies,
273 : CERTCertificatePolicies,
274 : CERT_DestroyCertificatePoliciesExtension)
275 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificateRequest,
276 : CERTCertificateRequest,
277 : CERT_DestroyCertificateRequest)
278 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertList,
279 : CERTCertList,
280 : CERT_DestroyCertList)
281 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTName,
282 : CERTName,
283 : CERT_DestroyName)
284 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTOidSequence,
285 : CERTOidSequence,
286 : CERT_DestroyOidSequence)
287 11 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTSubjectPublicKeyInfo,
288 : CERTSubjectPublicKeyInfo,
289 : SECKEY_DestroySubjectPublicKeyInfo)
290 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTUserNotice,
291 : CERTUserNotice,
292 : CERT_DestroyUserNotice)
293 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTValidity,
294 : CERTValidity,
295 : CERT_DestroyValidity)
296 :
297 12 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueHASHContext,
298 : HASHContext,
299 : HASH_Destroy)
300 :
301 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSMessage,
302 : NSSCMSMessage,
303 : NSS_CMSMessage_Destroy)
304 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSSignedData,
305 : NSSCMSSignedData,
306 : NSS_CMSSignedData_Destroy)
307 :
308 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11GenericObject,
309 : PK11GenericObject,
310 : PK11_DestroyGenericObject)
311 12 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotInfo,
312 : PK11SlotInfo,
313 : PK11_FreeSlot)
314 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotList,
315 : PK11SlotList,
316 : PK11_FreeSlotList)
317 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SymKey,
318 : PK11SymKey,
319 : PK11_FreeSymKey)
320 :
321 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePLArenaPool,
322 : PLArenaPool,
323 : internal::PORT_FreeArena_false)
324 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePORTString,
325 : char,
326 : PORT_Free)
327 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePRFileDesc,
328 : PRFileDesc,
329 : PR_Close)
330 1 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePRLibraryName,
331 : char,
332 : PR_FreeLibraryName)
333 :
334 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECAlgorithmID,
335 : SECAlgorithmID,
336 : internal::SECOID_DestroyAlgorithmID_true)
337 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECItem,
338 : SECItem,
339 : internal::SECITEM_FreeItem_true)
340 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPrivateKey,
341 : SECKEYPrivateKey,
342 : SECKEY_DestroyPrivateKey)
343 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECKEYPublicKey,
344 : SECKEYPublicKey,
345 : SECKEY_DestroyPublicKey)
346 1 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSECMODModule,
347 : SECMODModule,
348 : SECMOD_DestroyModule)
349 :
350 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueSGNDigestInfo,
351 : SGNDigestInfo,
352 : SGN_DestroyDigestInfo)
353 :
354 0 : MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueVFYContext,
355 : VFYContext,
356 : internal::VFY_DestroyContext_true)
357 : } // namespace mozilla
358 :
359 : #endif // ScopedNSSTypes_h
|