CryptoBuffer.cpp (4485B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CryptoBuffer.h" 8 9 #include "mozilla/Base64.h" 10 #include "mozilla/dom/BufferSourceBinding.h" 11 #include "mozilla/dom/UnionTypes.h" 12 #include "secitem.h" 13 14 namespace mozilla::dom { 15 16 uint8_t* CryptoBuffer::Assign(const CryptoBuffer& aData) { 17 // Same as in nsTArray_Impl::operator=, but return the value 18 // returned from ReplaceElementsAt to enable OOM detection 19 return ReplaceElementsAt(0, Length(), aData.Elements(), aData.Length(), 20 fallible); 21 } 22 23 uint8_t* CryptoBuffer::Assign(const uint8_t* aData, uint32_t aLength) { 24 return ReplaceElementsAt(0, Length(), aData, aLength, fallible); 25 } 26 27 uint8_t* CryptoBuffer::Assign(const nsACString& aString) { 28 return Assign(reinterpret_cast<uint8_t const*>(aString.BeginReading()), 29 aString.Length()); 30 } 31 32 uint8_t* CryptoBuffer::Assign(const SECItem* aItem) { 33 MOZ_ASSERT(aItem); 34 return Assign(aItem->data, aItem->len); 35 } 36 37 uint8_t* CryptoBuffer::Assign(const nsTArray<uint8_t>& aData) { 38 return ReplaceElementsAt(0, Length(), aData.Elements(), aData.Length(), 39 fallible); 40 } 41 42 uint8_t* CryptoBuffer::Assign(const ArrayBuffer& aData) { 43 Clear(); 44 return aData.AppendDataTo(*this) ? Elements() : nullptr; 45 } 46 47 uint8_t* CryptoBuffer::Assign(const ArrayBufferView& aData) { 48 Clear(); 49 return aData.AppendDataTo(*this) ? Elements() : nullptr; 50 } 51 52 uint8_t* CryptoBuffer::Assign(const BufferSource& aData) { 53 Clear(); 54 55 return AppendTypedArrayDataTo(aData, *this) ? Elements() : nullptr; 56 } 57 58 uint8_t* CryptoBuffer::Assign(const OwningBufferSource& aData) { 59 Clear(); 60 61 return AppendTypedArrayDataTo(aData, *this) ? Elements() : nullptr; 62 } 63 64 uint8_t* CryptoBuffer::Assign(const Uint8Array& aArray) { 65 Clear(); 66 return aArray.AppendDataTo(*this) ? Elements() : nullptr; 67 } 68 69 uint8_t* CryptoBuffer::AppendSECItem(const SECItem* aItem) { 70 MOZ_ASSERT(aItem); 71 return AppendElements(aItem->data, aItem->len, fallible); 72 } 73 74 uint8_t* CryptoBuffer::AppendSECItem(const SECItem& aItem) { 75 return AppendElements(aItem.data, aItem.len, fallible); 76 } 77 78 // Helpers to encode/decode JWK's special flavor of Base64 79 // * No whitespace 80 // * No padding 81 // * URL-safe character set 82 nsresult CryptoBuffer::FromJwkBase64(const nsString& aBase64) { 83 NS_ConvertUTF16toUTF8 temp(aBase64); 84 temp.StripWhitespace(); 85 86 // JWK prohibits padding per RFC 7515, section 2. 87 nsresult rv = 88 Base64URLDecode(temp, Base64URLDecodePaddingPolicy::Reject, *this); 89 NS_ENSURE_SUCCESS(rv, rv); 90 91 return NS_OK; 92 } 93 94 nsresult CryptoBuffer::ToJwkBase64(nsString& aBase64) const { 95 // Shortcut for the empty octet string 96 if (Length() == 0) { 97 aBase64.Truncate(); 98 return NS_OK; 99 } 100 101 nsAutoCString base64; 102 nsresult rv = Base64URLEncode(Length(), Elements(), 103 Base64URLEncodePaddingPolicy::Omit, base64); 104 NS_ENSURE_SUCCESS(rv, rv); 105 106 CopyASCIItoUTF16(base64, aBase64); 107 return NS_OK; 108 } 109 110 bool CryptoBuffer::ToSECItem(PLArenaPool* aArena, SECItem* aItem) const { 111 aItem->type = siBuffer; 112 aItem->data = nullptr; 113 114 if (!::SECITEM_AllocItem(aArena, aItem, Length())) { 115 return false; 116 } 117 // If this CryptoBuffer is of 0 length, aItem->data will be null. Passing 118 // null to memcpy is not valid, even if the length is 0, so return early. 119 if (!aItem->data) { 120 MOZ_ASSERT(Length() == 0); 121 return true; 122 } 123 memcpy(aItem->data, Elements(), Length()); 124 return true; 125 } 126 127 JSObject* CryptoBuffer::ToUint8Array(JSContext* aCx, 128 ErrorResult& aError) const { 129 return Uint8Array::Create(aCx, *this, aError); 130 } 131 132 JSObject* CryptoBuffer::ToArrayBuffer(JSContext* aCx, 133 ErrorResult& aError) const { 134 return ArrayBuffer::Create(aCx, *this, aError); 135 } 136 137 // "BigInt" comes from the WebCrypto spec 138 // ("unsigned long" isn't very "big", of course) 139 // Likewise, the spec calls for big-endian ints 140 bool CryptoBuffer::GetBigIntValue(unsigned long& aRetVal) { 141 if (Length() > sizeof(aRetVal)) { 142 return false; 143 } 144 145 aRetVal = 0; 146 for (size_t i = 0; i < Length(); ++i) { 147 aRetVal = (aRetVal << 8) + ElementAt(i); 148 } 149 return true; 150 } 151 152 } // namespace mozilla::dom