diff options
Diffstat (limited to 'dom/wifi/WifiCertService.cpp')
-rw-r--r-- | dom/wifi/WifiCertService.cpp | 536 |
1 files changed, 0 insertions, 536 deletions
diff --git a/dom/wifi/WifiCertService.cpp b/dom/wifi/WifiCertService.cpp deleted file mode 100644 index 85e0d2f5b0..0000000000 --- a/dom/wifi/WifiCertService.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/EndianUtils.h" -#include "mozilla/ModuleUtils.h" -#include "mozilla/RefPtr.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/ToJSValue.h" -#include "cert.h" -#include "certdb.h" -#include "CryptoTask.h" -#include "nsIDOMBlob.h" -#include "nsIWifiService.h" -#include "nsNetUtil.h" -#include "nsIInputStream.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 final: public CryptoTask -{ -public: - ImportCertTask(int32_t aId, Blob* 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() 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; - } - - // Try import as DER format first. - rv = ImportDERBlob(buf, size); - if (NS_SUCCEEDED(rv)) { - return rv; - } - - // Try import as PKCS#12 format. - return ImportPKCS12Blob(buf, size, mPassword); - } - - virtual void CallCallback(nsresult rv) - { - if (NS_FAILED(rv)) { - mResult.mStatus = -1; - } - gWifiCertService->DispatchResult(mResult); - } - - nsresult ImportDERBlob(char* buf, uint32_t size) - { - // Create certificate object. - ScopedCERTCertificate cert(CERT_DecodeCertFromPackage(buf, size)); - if (!cert) { - return MapSECStatus(SECFailure); - } - - // Import certificate. - return ImportCert(cert); - } - - static SECItem* - HandleNicknameCollision(SECItem* aOldNickname, PRBool* aCancel, void* aWincx) - { - const char* dummyName = "Imported User Cert"; - const size_t dummyNameLen = strlen(dummyName); - SECItem* newNick = ::SECITEM_AllocItem(nullptr, nullptr, dummyNameLen + 1); - if (!newNick) { - return nullptr; - } - - newNick->type = siAsciiString; - // Dummy name, will be renamed later. - memcpy(newNick->data, dummyName, dummyNameLen + 1); - newNick->len = dummyNameLen; - - return newNick; - } - - static SECStatus - HandleNicknameUpdate(const CERTCertificate *aCert, - const SECItem *default_nickname, - SECItem **new_nickname, - void *arg) - { - WifiCertServiceResultOptions *result = (WifiCertServiceResultOptions *)arg; - - nsCString userNickname; - CopyUTF16toUTF8(result->mNickname, userNickname); - - nsCString fullNickname; - if (aCert->isRoot && (aCert->nsCertType & NS_CERT_TYPE_SSL_CA)) { - // Accept self-signed SSL CA as server certificate. - fullNickname.AssignLiteral("WIFI_SERVERCERT_"); - fullNickname += userNickname; - result->mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER; - } else if (aCert->nsCertType & NS_CERT_TYPE_SSL_CLIENT) { - // User Certificate - fullNickname.AssignLiteral("WIFI_USERCERT_"); - fullNickname += userNickname; - result->mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_USER; - } - char* nickname; - uint32_t length = fullNickname.GetMutableData(&nickname); - - SECItem* newNick = ::SECITEM_AllocItem(nullptr, nullptr, length + 1); - if (!newNick) { - return SECFailure; - } - - newNick->type = siAsciiString; - memcpy(newNick->data, nickname, length + 1); - newNick->len = length; - - *new_nickname = newNick; - return SECSuccess; - } - - nsresult ImportPKCS12Blob(char* buf, uint32_t size, const nsAString& aPassword) - { - nsString password(aPassword); - - // password is null-terminated wide-char string. - // passwordItem is required to be big-endian form of password, stored in char - // array, including the null-termination. - uint32_t length = password.Length() + 1; - ScopedSECItem passwordItem( - ::SECITEM_AllocItem(nullptr, nullptr, length * sizeof(nsString::char_type))); - - if (!passwordItem) { - return NS_ERROR_FAILURE; - } - - mozilla::NativeEndian::copyAndSwapToBigEndian(passwordItem->data, - password.BeginReading(), - length); - // Create a decoder. - ScopedSEC_PKCS12DecoderContext p12dcx(SEC_PKCS12DecoderStart( - passwordItem, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr)); - - if (!p12dcx) { - return NS_ERROR_FAILURE; - } - - // Assign data to decorder. - SECStatus srv = SEC_PKCS12DecoderUpdate(p12dcx, - reinterpret_cast<unsigned char*>(buf), - size); - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - - // Verify certificates. - srv = SEC_PKCS12DecoderVerify(p12dcx); - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - - // Set certificate nickname and usage flag. - srv = SEC_PKCS12DecoderRenameCertNicknames(p12dcx, HandleNicknameUpdate, - &mResult); - - // Validate certificates. - srv = SEC_PKCS12DecoderValidateBags(p12dcx, HandleNicknameCollision); - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - - // Initialize slot. - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); - if (!slot) { - return NS_ERROR_FAILURE; - } - if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) { - srv = PK11_InitPin(slot, "", ""); - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - } - - // Import cert and key. - srv = SEC_PKCS12DecoderImportBags(p12dcx); - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - - // User certificate must be imported from PKCS#12. - return (mResult.mUsageFlag & nsIWifiCertService::WIFI_CERT_USAGE_FLAG_USER) - ? NS_OK : NS_ERROR_FAILURE; - } - - nsresult ReadBlob(/*out*/ nsCString& aBuf) - { - NS_ENSURE_ARG_POINTER(mBlob); - - static const uint64_t MAX_FILE_SIZE = 16384; - - ErrorResult rv; - uint64_t size = mBlob->GetSize(rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - if (size > MAX_FILE_SIZE) { - return NS_ERROR_FILE_TOO_BIG; - } - - nsCOMPtr<nsIInputStream> inputStream; - mBlob->GetInternalStream(getter_AddRefs(inputStream), rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - rv = NS_ReadInputStreamToString(inputStream, aBuf, (uint32_t)size); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - return NS_OK; - } - - nsresult ImportCert(CERTCertificate* aCert) - { - nsCString userNickname, fullNickname; - - CopyUTF16toUTF8(mResult.mNickname, 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; - mResult.mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER; - } else if (aCert->nsCertType & NS_CERT_TYPE_SSL_CLIENT) { - // User Certificate - fullNickname.AssignLiteral("WIFI_USERCERT_"); - fullNickname += userNickname; - mResult.mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_USER; - } 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, nullptr); - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - - return NS_OK; - } - - RefPtr<Blob> mBlob; - nsString mPassword; - WifiCertServiceResultOptions mResult; -}; - -class DeleteCertTask final: public CryptoTask -{ -public: - DeleteCertTask(int32_t aId, const nsAString& aCertNickname) - { - MOZ_ASSERT(NS_IsMainThread()); - - mResult.mId = aId; - mResult.mStatus = 0; - mResult.mUsageFlag = 0; - mResult.mNickname = aCertNickname; - } - -private: - virtual void ReleaseNSSResources() {} - - virtual nsresult CalculateResult() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - nsCString userNickname; - CopyUTF16toUTF8(mResult.mNickname, userNickname); - - // Delete server certificate. - nsCString serverCertName("WIFI_SERVERCERT_", 16); - serverCertName += userNickname; - nsresult rv = deleteCert(serverCertName); - if (NS_FAILED(rv)) { - return rv; - } - - // Delete user certificate and private key. - nsCString userCertName("WIFI_USERCERT_", 14); - userCertName += userNickname; - rv = deleteCert(userCertName); - if (NS_FAILED(rv)) { - return rv; - } - - return NS_OK; - } - - nsresult deleteCert(const nsCString &aCertNickname) - { - ScopedCERTCertificate cert( - CERT_FindCertByNickname(CERT_GetDefaultCertDB(), aCertNickname.get()) - ); - // Because we delete certificates in blind, so it's acceptable to delete - // a non-exist certificate. - if (!cert) { - return NS_OK; - } - - ScopedPK11SlotInfo slot( - PK11_KeyForCertExists(cert, nullptr, nullptr) - ); - - SECStatus srv; - if (slot) { - // Delete private key along with certificate. - srv = PK11_DeleteTokenCertAndKey(cert, nullptr); - } else { - srv = SEC_DeletePermCertificate(cert); - } - - if (srv != SECSuccess) { - return MapSECStatus(srv); - } - - return NS_OK; - } - - virtual void CallCallback(nsresult rv) - { - if (NS_FAILED(rv)) { - mResult.mStatus = -1; - } - gWifiCertService->DispatchResult(mResult); - } - - WifiCertServiceResultOptions mResult; -}; - -NS_IMPL_ISUPPORTS(WifiCertService, nsIWifiCertService) - -NS_IMETHODIMP -WifiCertService::Start(nsIWifiEventListener* aListener) -{ - MOZ_ASSERT(aListener); - - mListener = aListener; - - return NS_OK; -} - -NS_IMETHODIMP -WifiCertService::Shutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - - mListener = nullptr; - - return NS_OK; -} - -void -WifiCertService::DispatchResult(const WifiCertServiceResultOptions& aOptions) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mozilla::AutoSafeJSContext cx; - JS::RootedValue val(cx); - nsCString dummyInterface; - - if (!ToJSValue(cx, aOptions, &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); - - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return; - } - shutdown(ShutdownCalledFrom::Object); -} - -already_AddRefed<WifiCertService> -WifiCertService::FactoryCreate() -{ - if (!XRE_IsParentProcess()) { - return nullptr; - } - - MOZ_ASSERT(NS_IsMainThread()); - - if (!gWifiCertService) { - gWifiCertService = new WifiCertService(); - ClearOnShutdown(&gWifiCertService); - } - - RefPtr<WifiCertService> service = gWifiCertService.get(); - return service.forget(); -} - -NS_IMETHODIMP -WifiCertService::ImportCert(int32_t aId, nsIDOMBlob* aCertBlob, - const nsAString& aCertPassword, - const nsAString& aCertNickname) -{ - RefPtr<Blob> blob = static_cast<Blob*>(aCertBlob); - RefPtr<CryptoTask> task = new ImportCertTask(aId, blob, aCertPassword, - aCertNickname); - return task->Dispatch("WifiImportCert"); -} - -NS_IMETHODIMP -WifiCertService::DeleteCert(int32_t aId, const nsAString& aCertNickname) -{ - RefPtr<CryptoTask> task = new DeleteCertTask(aId, aCertNickname); - return task->Dispatch("WifiDeleteCert"); -} - -NS_IMETHODIMP -WifiCertService::HasPrivateKey(const nsAString& aCertNickname, bool *aHasKey) -{ - *aHasKey = false; - - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return NS_ERROR_NOT_AVAILABLE; - } - - nsCString certNickname; - CopyUTF16toUTF8(aCertNickname, certNickname); - - ScopedCERTCertificate cert( - CERT_FindCertByNickname(CERT_GetDefaultCertDB(), certNickname.get()) - ); - if (!cert) { - return NS_OK; - } - - ScopedPK11SlotInfo slot( - PK11_KeyForCertExists(cert, nullptr, nullptr) - ); - if (slot) { - *aHasKey = true; - } - - return NS_OK; -} - -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; |