michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "Crypto.h" michael@0: #include "jsfriendapi.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIRandomGenerator.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "MainThreadUtils.h" michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: #include "mozilla/dom/ContentChild.h" michael@0: #include "mozilla/dom/CryptoBinding.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: using mozilla::dom::ContentChild; michael@0: michael@0: using namespace js::ArrayBufferView; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Crypto) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(Crypto) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(Crypto) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Crypto, mWindow) michael@0: michael@0: Crypto::Crypto() michael@0: { michael@0: MOZ_COUNT_CTOR(Crypto); michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: Crypto::~Crypto() michael@0: { michael@0: MOZ_COUNT_DTOR(Crypto); michael@0: } michael@0: michael@0: void michael@0: Crypto::Init(nsIDOMWindow* aWindow) michael@0: { michael@0: mWindow = do_QueryInterface(aWindow); michael@0: MOZ_ASSERT(mWindow); michael@0: } michael@0: michael@0: /* virtual */ JSObject* michael@0: Crypto::WrapObject(JSContext* aCx) michael@0: { michael@0: return CryptoBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: void michael@0: Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray, michael@0: JS::MutableHandle aRetval, michael@0: ErrorResult& aRv) michael@0: { michael@0: NS_ABORT_IF_FALSE(NS_IsMainThread(), "Called on the wrong thread"); michael@0: michael@0: JS::Rooted view(aCx, aArray.Obj()); michael@0: michael@0: // Throw if the wrong type of ArrayBufferView is passed in michael@0: // (Part of the Web Crypto API spec) michael@0: switch (JS_GetArrayBufferViewType(view)) { michael@0: case TYPE_INT8: michael@0: case TYPE_UINT8: michael@0: case TYPE_UINT8_CLAMPED: michael@0: case TYPE_INT16: michael@0: case TYPE_UINT16: michael@0: case TYPE_INT32: michael@0: case TYPE_UINT32: michael@0: break; michael@0: default: michael@0: aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR); michael@0: return; michael@0: } michael@0: michael@0: aArray.ComputeLengthAndData(); michael@0: uint32_t dataLen = aArray.Length(); michael@0: if (dataLen == 0) { michael@0: NS_WARNING("ArrayBufferView length is 0, cannot continue"); michael@0: aRetval.set(view); michael@0: return; michael@0: } else if (dataLen > 65536) { michael@0: aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR); michael@0: return; michael@0: } michael@0: michael@0: uint8_t* data = aArray.Data(); michael@0: michael@0: if (XRE_GetProcessType() != GeckoProcessType_Default) { michael@0: InfallibleTArray randomValues; michael@0: // Tell the parent process to generate random values via PContent michael@0: ContentChild* cc = ContentChild::GetSingleton(); michael@0: if (!cc->SendGetRandomValues(dataLen, &randomValues) || michael@0: randomValues.Length() == 0) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return; michael@0: } michael@0: NS_ASSERTION(dataLen == randomValues.Length(), michael@0: "Invalid length returned from parent process!"); michael@0: memcpy(data, randomValues.Elements(), dataLen); michael@0: } else { michael@0: uint8_t *buf = GetRandomValues(dataLen); michael@0: michael@0: if (!buf) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return; michael@0: } michael@0: michael@0: memcpy(data, buf, dataLen); michael@0: NS_Free(buf); michael@0: } michael@0: michael@0: aRetval.set(view); michael@0: } michael@0: michael@0: #ifndef MOZ_DISABLE_CRYPTOLEGACY michael@0: // Stub out the legacy nsIDOMCrypto methods. The actual michael@0: // implementations are in security/manager/ssl/src/nsCrypto.{cpp,h} michael@0: michael@0: NS_IMETHODIMP michael@0: Crypto::GetEnableSmartCardEvents(bool *aEnableSmartCardEvents) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Crypto::SetEnableSmartCardEvents(bool aEnableSmartCardEvents) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: bool michael@0: Crypto::EnableSmartCardEvents() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: Crypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv) michael@0: { michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: } michael@0: michael@0: void michael@0: Crypto::GetVersion(nsString& aVersion) michael@0: { michael@0: } michael@0: michael@0: mozilla::dom::CRMFObject* michael@0: Crypto::GenerateCRMFRequest(JSContext* aContext, michael@0: const nsCString& aReqDN, michael@0: const nsCString& aRegToken, michael@0: const nsCString& aAuthenticator, michael@0: const nsCString& aEaCert, michael@0: const nsCString& aJsCallback, michael@0: const Sequence& aArgs, michael@0: ErrorResult& aRv) michael@0: { michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: Crypto::ImportUserCertificates(const nsAString& aNickname, michael@0: const nsAString& aCmmfResponse, michael@0: bool aDoForcedBackup, michael@0: nsAString& aReturn, michael@0: ErrorResult& aRv) michael@0: { michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: } michael@0: michael@0: void michael@0: Crypto::SignText(JSContext* aContext, michael@0: const nsAString& aStringToSign, michael@0: const nsAString& aCaOption, michael@0: const Sequence& aArgs, michael@0: nsAString& aReturn) michael@0: michael@0: { michael@0: aReturn.AssignLiteral("error:internalError"); michael@0: } michael@0: michael@0: void michael@0: Crypto::Logout(ErrorResult& aRv) michael@0: { michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: /* static */ uint8_t* michael@0: Crypto::GetRandomValues(uint32_t aLength) michael@0: { michael@0: nsCOMPtr randomGenerator; michael@0: nsresult rv; michael@0: randomGenerator = do_GetService("@mozilla.org/security/random-generator;1"); michael@0: NS_ENSURE_TRUE(randomGenerator, nullptr); michael@0: michael@0: uint8_t* buf; michael@0: rv = randomGenerator->GenerateRandomBytes(aLength, &buf); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: return buf; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla