Crypto.cpp (3341B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "Crypto.h" 8 9 #include "js/ScalarType.h" 10 #include "js/experimental/TypedData.h" // JS_GetArrayBufferViewType 11 #include "mozilla/dom/CryptoBinding.h" 12 #include "mozilla/dom/SubtleCrypto.h" 13 #include "nsCOMPtr.h" 14 #include "nsIRandomGenerator.h" 15 #include "nsReadableUtils.h" 16 #include "nsServiceManagerUtils.h" 17 18 namespace mozilla::dom { 19 20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Crypto) 21 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 22 NS_INTERFACE_MAP_ENTRY(nsISupports) 23 NS_INTERFACE_MAP_END 24 25 NS_IMPL_CYCLE_COLLECTING_ADDREF(Crypto) 26 NS_IMPL_CYCLE_COLLECTING_RELEASE(Crypto) 27 28 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Crypto, mParent, mSubtle) 29 30 Crypto::Crypto(nsIGlobalObject* aParent) : mParent(aParent) {} 31 32 Crypto::~Crypto() = default; 33 34 /* virtual */ 35 JSObject* Crypto::WrapObject(JSContext* aCx, 36 JS::Handle<JSObject*> aGivenProto) { 37 return Crypto_Binding::Wrap(aCx, this, aGivenProto); 38 } 39 40 void Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray, 41 JS::MutableHandle<JSObject*> aRetval, 42 ErrorResult& aRv) { 43 // Throw if the wrong type of ArrayBufferView is passed in 44 // (Part of the Web Crypto API spec) 45 switch (aArray.Type()) { 46 case js::Scalar::Int8: 47 case js::Scalar::Uint8: 48 case js::Scalar::Uint8Clamped: 49 case js::Scalar::Int16: 50 case js::Scalar::Uint16: 51 case js::Scalar::Int32: 52 case js::Scalar::Uint32: 53 case js::Scalar::BigInt64: 54 case js::Scalar::BigUint64: 55 break; 56 default: 57 aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR); 58 return; 59 } 60 61 nsCOMPtr<nsIRandomGenerator> randomGenerator = 62 do_GetService("@mozilla.org/security/random-generator;1"); 63 if (!randomGenerator) { 64 aRv.Throw(NS_ERROR_DOM_OPERATION_ERR); 65 return; 66 } 67 68 aArray.ProcessFixedData([&](const Span<uint8_t>& aData) { 69 if (aData.Length() == 0) { 70 NS_WARNING("ArrayBufferView length is 0, cannot continue"); 71 aRetval.set(aArray.Obj()); 72 return; 73 } 74 75 if (aData.Length() > 65536) { 76 aRv.ThrowQuotaExceededError( 77 "getRandomValues can only generate maximum 65536 bytes"); 78 return; 79 } 80 81 nsresult rv = randomGenerator->GenerateRandomBytesInto(aData.Elements(), 82 aData.Length()); 83 if (NS_FAILED(rv)) { 84 aRv.Throw(NS_ERROR_DOM_OPERATION_ERR); 85 return; 86 } 87 88 aRetval.set(aArray.Obj()); 89 }); 90 } 91 92 void Crypto::RandomUUID(nsACString& aRetVal) { 93 // NSID_LENGTH == 39 == 36 UUID chars + 2 curly braces + 1 NUL byte 94 static_assert(NSID_LENGTH == 39); 95 96 nsIDToCString uuidString(nsID::GenerateUUID()); 97 MOZ_ASSERT(strlen(uuidString.get()) == NSID_LENGTH - 1); 98 99 // Omit the curly braces and NUL. 100 aRetVal = Substring(uuidString.get() + 1, NSID_LENGTH - 3); 101 MOZ_ASSERT(aRetVal.Length() == NSID_LENGTH - 3); 102 } 103 104 SubtleCrypto* Crypto::Subtle() { 105 if (!mSubtle) { 106 mSubtle = new SubtleCrypto(GetParentObject()); 107 } 108 return mSubtle; 109 } 110 111 } // namespace mozilla::dom