1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
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
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "nsNSSModule.h"
8 
9 #ifndef MOZ_NEW_CERT_STORAGE
10 #  include "CertBlocklist.h"
11 #endif
12 #include "ContentSignatureVerifier.h"
13 #include "NSSErrorsService.h"
14 #include "OSKeyStore.h"
15 #include "OSReauthenticator.h"
16 #include "PKCS11ModuleDB.h"
17 #include "SecretDecoderRing.h"
18 #include "TransportSecurityInfo.h"
19 #include "mozilla/MacroArgs.h"
20 #include "mozilla/ModuleUtils.h"
21 #include "mozilla/SyncRunnable.h"
22 #include "nsCURILoader.h"
23 #include "nsCertOverrideService.h"
24 #include "nsCryptoHash.h"
25 #include "nsKeyModule.h"
26 #include "nsNSSCertificate.h"
27 #include "nsNSSCertificateDB.h"
28 #include "nsNSSComponent.h"
29 #include "nsNSSVersion.h"
30 #include "nsNetCID.h"
31 #include "nsPK11TokenDB.h"
32 #include "nsPKCS11Slot.h"
33 #include "nsRandomGenerator.h"
34 #include "nsSecureBrowserUI.h"
35 #include "nsSiteSecurityService.h"
36 #include "nsXULAppAPI.h"
37 
38 #ifdef MOZ_XUL
39 #  include "nsCertTree.h"
40 #endif
41 
42 namespace mozilla {
43 namespace psm {
44 
45 // Many of the implementations in this module call NSS functions and as a result
46 // require that PSM has successfully initialized NSS before being used.
47 // Additionally, some of the implementations have various restrictions on which
48 // process and threads they can be used on (e.g. some can only be used in the
49 // parent process and some must be initialized only on the main thread).
50 // The following initialization framework allows these requirements to be
51 // succinctly expressed and implemented.
52 
53 template <class InstanceClass, nsresult (InstanceClass::*InitMethod)()>
Instantiate(REFNSIID aIID,void ** aResult)54 MOZ_ALWAYS_INLINE static nsresult Instantiate(REFNSIID aIID, void** aResult) {
55   InstanceClass* inst = new InstanceClass();
56   NS_ADDREF(inst);
57   nsresult rv = InitMethod != nullptr ? (inst->*InitMethod)() : NS_OK;
58   if (NS_SUCCEEDED(rv)) {
59     rv = inst->QueryInterface(aIID, aResult);
60   }
61   NS_RELEASE(inst);
62   return rv;
63 }
64 
65 enum class ThreadRestriction {
66   // must be initialized on the main thread (but can be used on any thread)
67   MainThreadOnly,
68   // can be initialized and used on any thread
69   AnyThread,
70 };
71 
72 enum class ProcessRestriction {
73   ParentProcessOnly,
74   AnyProcess,
75 };
76 
77 template <class InstanceClass,
78           nsresult (InstanceClass::*InitMethod)() = nullptr,
79           ProcessRestriction processRestriction =
80               ProcessRestriction::ParentProcessOnly,
81           ThreadRestriction threadRestriction = ThreadRestriction::AnyThread>
Constructor(nsISupports * aOuter,REFNSIID aIID,void ** aResult)82 static nsresult Constructor(nsISupports* aOuter, REFNSIID aIID,
83                             void** aResult) {
84   *aResult = nullptr;
85   if (aOuter != nullptr) {
86     return NS_ERROR_NO_AGGREGATION;
87   }
88 
89   if (processRestriction == ProcessRestriction::ParentProcessOnly &&
90       !XRE_IsParentProcess()) {
91     return NS_ERROR_NOT_AVAILABLE;
92   }
93 
94   if (!EnsureNSSInitializedChromeOrContent()) {
95     return NS_ERROR_FAILURE;
96   }
97 
98   if (threadRestriction == ThreadRestriction::MainThreadOnly &&
99       !NS_IsMainThread()) {
100     nsCOMPtr<nsIThread> mainThread;
101     nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
102     if (NS_FAILED(rv)) {
103       return rv;
104     }
105 
106     // Forward to the main thread synchronously.
107     mozilla::SyncRunnable::DispatchToThread(
108         mainThread,
109         new SyncRunnable(NS_NewRunnableFunction("psm::Constructor", [&]() {
110           rv = Instantiate<InstanceClass, InitMethod>(aIID, aResult);
111         })));
112 
113     return rv;
114   }
115 
116   return Instantiate<InstanceClass, InitMethod>(aIID, aResult);
117 }
118 
119 #define IMPL(type, ...)                                                  \
120   template <>                                                            \
121   nsresult NSSConstructor<type>(nsISupports * aOuter, const nsIID& aIID, \
122                                 void** aResult) {                        \
123     return Constructor<type, __VA_ARGS__>(aOuter, aIID, aResult);        \
124   }
125 
126 // Components that require main thread initialization could cause a deadlock
127 // in necko code (bug 1418752). To prevent it we initialize all such components
128 // on main thread in advance in net_EnsurePSMInit(). Update that function when
129 // new component with ThreadRestriction::MainThreadOnly is added.
130 IMPL(SecretDecoderRing, nullptr)
131 IMPL(nsPK11TokenDB, nullptr)
132 IMPL(PKCS11ModuleDB, nullptr)
133 IMPL(nsNSSCertificate, nullptr, ProcessRestriction::AnyProcess)
134 IMPL(nsNSSCertificateDB, nullptr)
135 #ifdef MOZ_XUL
136 IMPL(nsCertTree, nullptr)
137 #endif
138 IMPL(nsCryptoHash, nullptr, ProcessRestriction::AnyProcess)
139 IMPL(nsCryptoHMAC, nullptr, ProcessRestriction::AnyProcess)
140 IMPL(nsKeyObject, nullptr, ProcessRestriction::AnyProcess)
141 IMPL(nsKeyObjectFactory, nullptr, ProcessRestriction::AnyProcess)
142 IMPL(ContentSignatureVerifier, nullptr)
143 IMPL(nsCertOverrideService, &nsCertOverrideService::Init,
144      ProcessRestriction::ParentProcessOnly, ThreadRestriction::MainThreadOnly)
145 IMPL(nsRandomGenerator, nullptr, ProcessRestriction::AnyProcess)
146 IMPL(TransportSecurityInfo, nullptr, ProcessRestriction::AnyProcess)
147 IMPL(nsSiteSecurityService, &nsSiteSecurityService::Init,
148      ProcessRestriction::AnyProcess, ThreadRestriction::MainThreadOnly)
149 #ifndef MOZ_NEW_CERT_STORAGE
150 IMPL(CertBlocklist, &CertBlocklist::Init, ProcessRestriction::ParentProcessOnly,
151      ThreadRestriction::MainThreadOnly)
152 #endif
153 IMPL(OSKeyStore, nullptr, ProcessRestriction::ParentProcessOnly,
154      ThreadRestriction::MainThreadOnly)
155 IMPL(OSReauthenticator, nullptr, ProcessRestriction::ParentProcessOnly,
156      ThreadRestriction::MainThreadOnly)
157 #undef IMPL
158 
159 }  // namespace psm
160 }  // namespace mozilla
161