1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // XXX: This must be done prior to including cert.h (directly or indirectly).
7 // CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm.
8 #define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
10 #include "WifiCertService.h"
12 #include "mozilla/ClearOnShutdown.h"
13 #include "mozilla/ModuleUtils.h"
14 #include "mozilla/RefPtr.h"
15 #include "mozilla/dom/ToJSValue.h"
18 #include "CryptoTask.h"
19 #include "nsIDOMFile.h"
20 #include "nsIWifiService.h"
21 #include "nsNetUtil.h"
22 #include "nsServiceManagerUtils.h"
23 #include "nsXULAppAPI.h"
24 #include "ScopedNSSTypes.h"
26 #define NS_WIFICERTSERVICE_CID \
27 { 0x83585afd, 0x0e11, 0x43aa, {0x83, 0x46, 0xf3, 0x4d, 0x97, 0x5e, 0x46, 0x77} }
29 using namespace mozilla
;
30 using namespace mozilla::dom
;
34 // The singleton Wifi Cert service, to be used on the main thread.
35 StaticRefPtr
<WifiCertService
> gWifiCertService
;
37 class ImportCertTask MOZ_FINAL
: public CryptoTask
40 ImportCertTask(int32_t aId
, nsIDOMBlob
* aCertBlob
,
41 const nsAString
& aCertPassword
,
42 const nsAString
& aCertNickname
)
44 , mPassword(aCertPassword
)
46 MOZ_ASSERT(NS_IsMainThread());
50 mResult
.mUsageFlag
= 0;
51 mResult
.mNickname
= aCertNickname
;
55 virtual void ReleaseNSSResources() {}
57 virtual nsresult
CalculateResult() MOZ_OVERRIDE
59 MOZ_ASSERT(!NS_IsMainThread());
61 // read data from blob.
63 nsresult rv
= ReadBlob(blobBuf
);
69 uint32_t size
= blobBuf
.GetMutableData(&buf
);
71 return NS_ERROR_OUT_OF_MEMORY
;
74 // Only support DER format now.
75 return ImportDERBlob(buf
, size
, mResult
.mNickname
,
79 virtual void CallCallback(nsresult rv
)
84 gWifiCertService
->DispatchResult(mResult
);
87 nsresult
ImportDERBlob(char* buf
, uint32_t size
,
88 const nsAString
& aNickname
,
89 /*out*/ uint16_t* aUsageFlag
)
91 NS_ENSURE_ARG_POINTER(aUsageFlag
);
93 // Create certificate object.
94 ScopedCERTCertificate
cert(CERT_DecodeCertFromPackage(buf
, size
));
96 return MapSECStatus(SECFailure
);
99 // Import certificate with nickname.
100 return ImportCert(cert
, aNickname
, aUsageFlag
);
103 nsresult
ReadBlob(/*out*/ nsCString
& aBuf
)
105 NS_ENSURE_ARG_POINTER(mBlob
);
107 static const uint64_t MAX_FILE_SIZE
= 16384;
109 nsresult rv
= mBlob
->GetSize(&size
);
113 if (size
> MAX_FILE_SIZE
) {
114 return NS_ERROR_FILE_TOO_BIG
;
117 nsCOMPtr
<nsIInputStream
> inputStream
;
118 rv
= mBlob
->GetInternalStream(getter_AddRefs(inputStream
));
123 rv
= NS_ReadInputStreamToString(inputStream
, aBuf
, (uint32_t)size
);
131 nsresult
ImportCert(CERTCertificate
* aCert
, const nsAString
& aNickname
,
132 /*out*/ uint16_t* aUsageFlag
)
134 NS_ENSURE_ARG_POINTER(aUsageFlag
);
136 nsCString userNickname
, fullNickname
;
138 CopyUTF16toUTF8(aNickname
, userNickname
);
139 // Determine certificate nickname by adding prefix according to its type.
140 if (aCert
->isRoot
&& (aCert
->nsCertType
& NS_CERT_TYPE_SSL_CA
)) {
141 // Accept self-signed SSL CA as server certificate.
142 fullNickname
.AssignLiteral("WIFI_SERVERCERT_");
143 fullNickname
+= userNickname
;
144 *aUsageFlag
|= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER
;
146 return NS_ERROR_ABORT
;
151 length
= fullNickname
.GetMutableData(&nickname
);
153 return NS_ERROR_UNEXPECTED
;
156 // Import certificate, duplicated nickname will cause error.
157 SECStatus srv
= CERT_AddTempCertToPerm(aCert
, nickname
, NULL
);
158 if (srv
!= SECSuccess
) {
159 return MapSECStatus(srv
);
165 nsCOMPtr
<nsIDOMBlob
> mBlob
;
167 WifiCertServiceResultOptions mResult
;
170 class DeleteCertTask MOZ_FINAL
: public CryptoTask
173 DeleteCertTask(int32_t aId
, const nsAString
& aCertNickname
)
175 MOZ_ASSERT(NS_IsMainThread());
179 mResult
.mUsageFlag
= 0;
180 mResult
.mNickname
= aCertNickname
;
184 virtual void ReleaseNSSResources() {}
186 virtual nsresult
CalculateResult() MOZ_OVERRIDE
188 MOZ_ASSERT(!NS_IsMainThread());
190 nsCString userNickname
;
191 CopyUTF16toUTF8(mResult
.mNickname
, userNickname
);
193 // Delete server certificate.
194 nsCString
serverCertName("WIFI_SERVERCERT_", 16);
195 serverCertName
+= userNickname
;
197 ScopedCERTCertificate
cert(
198 CERT_FindCertByNickname(CERT_GetDefaultCertDB(), serverCertName
.get())
201 return MapSECStatus(SECFailure
);
204 SECStatus srv
= SEC_DeletePermCertificate(cert
);
205 if (srv
!= SECSuccess
) {
206 return MapSECStatus(srv
);
212 virtual void CallCallback(nsresult rv
)
215 mResult
.mStatus
= -1;
217 gWifiCertService
->DispatchResult(mResult
);
220 WifiCertServiceResultOptions mResult
;
223 NS_IMPL_ISUPPORTS(WifiCertService
, nsIWifiCertService
)
226 WifiCertService::Start(nsIWifiEventListener
* aListener
)
228 MOZ_ASSERT(aListener
);
230 nsresult rv
= NS_NewThread(getter_AddRefs(mRequestThread
));
232 NS_WARNING("Certn't create wifi control thread");
234 return NS_ERROR_FAILURE
;
237 mListener
= aListener
;
243 WifiCertService::Shutdown()
245 MOZ_ASSERT(NS_IsMainThread());
246 if (mRequestThread
) {
247 mRequestThread
->Shutdown();
248 mRequestThread
= nullptr;
257 WifiCertService::DispatchResult(const WifiCertServiceResultOptions
& aOptions
)
259 MOZ_ASSERT(NS_IsMainThread());
261 mozilla::AutoSafeJSContext cx
;
262 JS::RootedValue
val(cx
);
263 nsCString dummyInterface
;
265 if (!ToJSValue(cx
, aOptions
, &val
)) {
269 // Certll the listener with a JS value.
270 mListener
->OnCommand(val
, dummyInterface
);
273 WifiCertService::WifiCertService()
275 MOZ_ASSERT(NS_IsMainThread());
276 MOZ_ASSERT(!gWifiCertService
);
279 WifiCertService::~WifiCertService()
281 MOZ_ASSERT(!gWifiCertService
);
284 already_AddRefed
<WifiCertService
>
285 WifiCertService::FactoryCreate()
287 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
291 MOZ_ASSERT(NS_IsMainThread());
293 if (!gWifiCertService
) {
294 gWifiCertService
= new WifiCertService();
295 ClearOnShutdown(&gWifiCertService
);
298 nsRefPtr
<WifiCertService
> service
= gWifiCertService
.get();
299 return service
.forget();
303 WifiCertService::ImportCert(int32_t aId
, nsIDOMBlob
* aCertBlob
,
304 const nsAString
& aCertPassword
,
305 const nsAString
& aCertNickname
)
307 RefPtr
<CryptoTask
> task
= new ImportCertTask(aId
, aCertBlob
, aCertPassword
,
309 return task
->Dispatch("WifiImportCert");
313 WifiCertService::DeleteCert(int32_t aId
, const nsAString
& aCertNickname
)
315 RefPtr
<CryptoTask
> task
= new DeleteCertTask(aId
, aCertNickname
);
316 return task
->Dispatch("WifiDeleteCert");
319 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiCertService
,
320 WifiCertService::FactoryCreate
)
322 NS_DEFINE_NAMED_CID(NS_WIFICERTSERVICE_CID
);
324 static const mozilla::Module::CIDEntry kWifiCertServiceCIDs
[] = {
325 { &kNS_WIFICERTSERVICE_CID
, false, nullptr, WifiCertServiceConstructor
},
329 static const mozilla::Module::ContractIDEntry kWifiCertServiceContracts
[] = {
330 { "@mozilla.org/wifi/certservice;1", &kNS_WIFICERTSERVICE_CID
},
334 static const mozilla::Module kWifiCertServiceModule
= {
335 mozilla::Module::kVersion
,
336 kWifiCertServiceCIDs
,
337 kWifiCertServiceContracts
,
341 } // namespace mozilla
343 NSMODULE_DEFN(WifiCertServiceModule
) = &kWifiCertServiceModule
;