Bug 917102 - 0002. Add Wifi certificate service. r=mrbkap, r=keeler
authorChuck Lee <chulee@mozilla.com>
Mon, 28 Apr 2014 15:49:57 +0800
changeset 200872 7c032a129e9309b6bbfb603d8c4b11dc91374d13
parent 200871 a72a8e0a9b73091fde16355f38eb2ce4e6b59c1d
child 200873 c9cb944fae53cc18abd3376d83ca7fbb2171c0b2
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap, keeler
bugs917102
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 917102 - 0002. Add Wifi certificate service. r=mrbkap, r=keeler
dom/wifi/WifiCertService.cpp
dom/wifi/WifiCertService.h
dom/wifi/moz.build
toolkit/library/nsStaticXULComponents.cpp
new file mode 100644
--- /dev/null
+++ b/dom/wifi/WifiCertService.cpp
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "WifiCertService.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/RefPtr.h"
+#include "cert.h"
+#include "certdb.h"
+#include "CryptoTask.h"
+#include "nsCxPusher.h"
+#include "nsIDOMFile.h"
+#include "nsIWifiService.h"
+#include "nsNetUtil.h"
+#include "nsServiceManagerUtils.h"
+#include "nsXULAppAPI.h"
+#include "ScopedNSSTypes.h"
+
+#define NS_WIFICERTSERVICE_CID \
+  { 0x83585afd, 0x0e11, 0x43aa, {0x83, 0x46, 0xf3, 0x4d, 0x97, 0x5e, 0x46, 0x77} }
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+namespace mozilla {
+
+// The singleton Wifi Cert service, to be used on the main thread.
+StaticRefPtr<WifiCertService> gWifiCertService;
+
+class ImportCertTask MOZ_FINAL: public CryptoTask
+{
+public:
+  ImportCertTask(int32_t aId, nsIDOMBlob* aCertBlob,
+                 const nsAString& aCertPassword,
+                 const nsAString& aCertNickname)
+    : mBlob(aCertBlob)
+    , mPassword(aCertPassword)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mResult.mId = aId;
+    mResult.mStatus = 0;
+    mResult.mUsageFlag = 0;
+    mResult.mNickname = aCertNickname;
+  }
+
+private:
+  virtual void ReleaseNSSResources() {}
+
+  virtual nsresult CalculateResult() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    // read data from blob.
+    nsCString blobBuf;
+    nsresult rv = ReadBlob(blobBuf);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    char* buf;
+    uint32_t size = blobBuf.GetMutableData(&buf);
+    if (size == 0) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    // Only support DER format now.
+    return ImportDERBlob(buf, size, mResult.mNickname,
+                         &mResult.mUsageFlag);
+  }
+
+  virtual void CallCallback(nsresult rv)
+  {
+    if (NS_FAILED(rv)) {
+      mResult.mStatus = -1;
+    }
+    gWifiCertService->DispatchResult(mResult);
+  }
+
+  nsresult ImportDERBlob(char* buf, uint32_t size,
+                         const nsAString& aNickname,
+                         /*out*/ uint16_t* aUsageFlag)
+  {
+    NS_ENSURE_ARG_POINTER(aUsageFlag);
+
+    // Create certificate object.
+    ScopedCERTCertificate cert(CERT_DecodeCertFromPackage(buf, size));
+    if (!cert) {
+      return MapSECStatus(SECFailure);
+    }
+
+    // Import certificate with nickname.
+    return ImportCert(cert, aNickname, aUsageFlag);
+  }
+
+  nsresult ReadBlob(/*out*/ nsCString& aBuf)
+  {
+    NS_ENSURE_ARG_POINTER(mBlob);
+
+    static const uint64_t MAX_FILE_SIZE = 16384;
+    uint64_t size;
+    nsresult rv = mBlob->GetSize(&size);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    if (size > MAX_FILE_SIZE) {
+      return NS_ERROR_FILE_TOO_BIG;
+    }
+
+    nsCOMPtr<nsIInputStream> inputStream;
+    rv = mBlob->GetInternalStream(getter_AddRefs(inputStream));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    rv = NS_ReadInputStreamToString(inputStream, aBuf, (uint32_t)size);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    return NS_OK;
+  }
+
+  nsresult ImportCert(CERTCertificate* aCert, const nsAString& aNickname,
+                      /*out*/ uint16_t* aUsageFlag)
+  {
+    NS_ENSURE_ARG_POINTER(aUsageFlag);
+
+    nsCString userNickname, fullNickname;
+
+    CopyUTF16toUTF8(aNickname, userNickname);
+    // Determine certificate nickname by adding prefix according to its type.
+    if (aCert->isRoot && (aCert->nsCertType & NS_CERT_TYPE_SSL_CA)) {
+      // Accept self-signed SSL CA as server certificate.
+      fullNickname.AssignLiteral("WIFI_SERVERCERT_");
+      fullNickname += userNickname;
+      *aUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER;
+    } else {
+      return NS_ERROR_ABORT;
+    }
+
+    char* nickname;
+    uint32_t length;
+    length = fullNickname.GetMutableData(&nickname);
+    if (length == 0) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    // Import certificate, duplicated nickname will cause error.
+    SECStatus srv = CERT_AddTempCertToPerm(aCert, nickname, NULL);
+    if (srv != SECSuccess) {
+      return MapSECStatus(srv);
+    }
+
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsString mPassword;
+  WifiCertServiceResultOptions mResult;
+};
+
+NS_IMPL_ISUPPORTS(WifiCertService, nsIWifiCertService)
+
+NS_IMETHODIMP
+WifiCertService::Start(nsIWifiEventListener* aListener)
+{
+  MOZ_ASSERT(aListener);
+
+  nsresult rv = NS_NewThread(getter_AddRefs(mRequestThread));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Certn't create wifi control thread");
+    Shutdown();
+    return NS_ERROR_FAILURE;
+  }
+
+  mListener = aListener;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WifiCertService::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mRequestThread) {
+    mRequestThread->Shutdown();
+    mRequestThread = nullptr;
+  }
+  return NS_OK;
+}
+
+void
+WifiCertService::DispatchResult(const WifiCertServiceResultOptions& aOptions)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mozilla::AutoSafeJSContext cx;
+  JS::RootedValue val(cx);
+  nsCString dummyInterface;
+
+  if (!aOptions.ToObject(cx, &val)) {
+    return;
+  }
+
+  // Certll the listener with a JS value.
+  mListener->OnCommand(val, dummyInterface);
+}
+
+WifiCertService::WifiCertService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!gWifiCertService);
+}
+
+WifiCertService::~WifiCertService()
+{
+  MOZ_ASSERT(!gWifiCertService);
+}
+
+already_AddRefed<WifiCertService>
+WifiCertService::FactoryCreate()
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gWifiCertService) {
+    gWifiCertService = new WifiCertService();
+    ClearOnShutdown(&gWifiCertService);
+  }
+
+  nsRefPtr<WifiCertService> service = gWifiCertService.get();
+  return service.forget();
+}
+
+NS_IMETHODIMP
+WifiCertService::ImportCert(int32_t aId, nsIDOMBlob* aCertBlob,
+                            const nsAString& aCertPassword,
+                            const nsAString& aCertNickname)
+{
+  RefPtr<CryptoTask> task = new ImportCertTask(aId, aCertBlob, aCertPassword,
+                                               aCertNickname);
+  return task->Dispatch("WifiImportCert");
+}
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiCertService,
+                                         WifiCertService::FactoryCreate)
+
+NS_DEFINE_NAMED_CID(NS_WIFICERTSERVICE_CID);
+
+static const mozilla::Module::CIDEntry kWifiCertServiceCIDs[] = {
+  { &kNS_WIFICERTSERVICE_CID, false, nullptr, WifiCertServiceConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kWifiCertServiceContracts[] = {
+  { "@mozilla.org/wifi/certservice;1", &kNS_WIFICERTSERVICE_CID },
+  { nullptr }
+};
+
+static const mozilla::Module kWifiCertServiceModule = {
+  mozilla::Module::kVersion,
+  kWifiCertServiceCIDs,
+  kWifiCertServiceContracts,
+  nullptr
+};
+
+} // namespace mozilla
+
+NSMODULE_DEFN(WifiCertServiceModule) = &kWifiCertServiceModule;
new file mode 100644
--- /dev/null
+++ b/dom/wifi/WifiCertService.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef WifiCertService_h
+#define WifiCertService_h
+
+#include "nsIWifiCertService.h"
+#include "nsCOMPtr.h"
+#include "nsThread.h"
+#include "mozilla/dom/WifiOptionsBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+class WifiCertService MOZ_FINAL : public nsIWifiCertService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWIFICERTSERVICE
+
+  static already_AddRefed<WifiCertService>
+  FactoryCreate();
+  void DispatchResult(const mozilla::dom::WifiCertServiceResultOptions& aOptions);
+
+private:
+  WifiCertService();
+  ~WifiCertService();
+  nsCOMPtr<nsIThread> mRequestThread;
+  nsCOMPtr<nsIWifiEventListener> mListener;
+};
+
+} // namespce dom
+} // namespace mozilla
+
+#endif // WifiCertService_h
--- a/dom/wifi/moz.build
+++ b/dom/wifi/moz.build
@@ -29,13 +29,14 @@ EXTRA_JS_MODULES += [
     'WifiCommand.jsm',
     'WifiNetUtil.jsm',
     'WifiP2pManager.jsm',
     'WifiP2pWorkerObserver.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     SOURCES = [
+        'WifiCertService.cpp',
         'WifiProxyService.cpp',
         'WifiUtils.cpp',
     ]
 
 FINAL_LIBRARY = 'xul'
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -248,27 +248,29 @@
     /* end of list */
 
 #define MODULE(_name) \
   NSMODULE_DECL(_name);
 
 XUL_MODULES
 
 #ifdef MOZ_WIDGET_GONK
+MODULE(WifiCertServiceModule)
 MODULE(WifiProxyServiceModule)
 MODULE(NetworkWorkerModule)
 #endif
 
 #undef MODULE
 
 #define MODULE(_name) \
     &NSMODULE_NAME(_name),
 
 extern const mozilla::Module *const *const kPStaticModules[] = {
   XUL_MODULES
 #ifdef MOZ_WIDGET_GONK
+MODULE(WifiCertServiceModule)
 MODULE(WifiProxyServiceModule)
 MODULE(NetworkWorkerModule)
 #endif
   nullptr
 };
 
 #undef MODULE