Line data Source code
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 : #include "secitem.h"
9 : #include "mozilla/Base64.h"
10 : #include "mozilla/dom/UnionTypes.h"
11 :
12 : namespace mozilla {
13 : namespace dom {
14 :
15 : uint8_t*
16 0 : CryptoBuffer::Assign(const CryptoBuffer& aData)
17 : {
18 : // Same as in nsTArray_Impl::operator=, but return the value
19 : // returned from ReplaceElementsAt to enable OOM detection
20 0 : return ReplaceElementsAt(0, Length(), aData.Elements(), aData.Length(),
21 0 : fallible);
22 : }
23 :
24 : uint8_t*
25 0 : CryptoBuffer::Assign(const uint8_t* aData, uint32_t aLength)
26 : {
27 0 : return ReplaceElementsAt(0, Length(), aData, aLength, fallible);
28 : }
29 :
30 : uint8_t*
31 0 : CryptoBuffer::Assign(const nsACString& aString)
32 : {
33 0 : return Assign(reinterpret_cast<uint8_t const*>(aString.BeginReading()),
34 0 : aString.Length());
35 : }
36 :
37 : uint8_t*
38 0 : CryptoBuffer::Assign(const SECItem* aItem)
39 : {
40 0 : MOZ_ASSERT(aItem);
41 0 : return Assign(aItem->data, aItem->len);
42 : }
43 :
44 : uint8_t*
45 0 : CryptoBuffer::Assign(const InfallibleTArray<uint8_t>& aData)
46 : {
47 0 : return ReplaceElementsAt(0, Length(), aData.Elements(), aData.Length(),
48 0 : fallible);
49 : }
50 :
51 : uint8_t*
52 0 : CryptoBuffer::Assign(const ArrayBuffer& aData)
53 : {
54 0 : aData.ComputeLengthAndData();
55 0 : return Assign(aData.Data(), aData.Length());
56 : }
57 :
58 : uint8_t*
59 0 : CryptoBuffer::Assign(const ArrayBufferView& aData)
60 : {
61 0 : aData.ComputeLengthAndData();
62 0 : return Assign(aData.Data(), aData.Length());
63 : }
64 :
65 : uint8_t*
66 0 : CryptoBuffer::Assign(const ArrayBufferViewOrArrayBuffer& aData)
67 : {
68 0 : if (aData.IsArrayBufferView()) {
69 0 : return Assign(aData.GetAsArrayBufferView());
70 0 : } else if (aData.IsArrayBuffer()) {
71 0 : return Assign(aData.GetAsArrayBuffer());
72 : }
73 :
74 : // If your union is uninitialized, something's wrong
75 0 : MOZ_ASSERT(false);
76 : Clear();
77 : return nullptr;
78 : }
79 :
80 : uint8_t*
81 0 : CryptoBuffer::Assign(const OwningArrayBufferViewOrArrayBuffer& aData)
82 : {
83 0 : if (aData.IsArrayBufferView()) {
84 0 : return Assign(aData.GetAsArrayBufferView());
85 0 : } else if (aData.IsArrayBuffer()) {
86 0 : return Assign(aData.GetAsArrayBuffer());
87 : }
88 :
89 : // If your union is uninitialized, something's wrong
90 0 : MOZ_ASSERT(false);
91 : Clear();
92 : return nullptr;
93 : }
94 :
95 : uint8_t*
96 0 : CryptoBuffer::AppendSECItem(const SECItem* aItem)
97 : {
98 0 : MOZ_ASSERT(aItem);
99 0 : return AppendElements(aItem->data, aItem->len, fallible);
100 : }
101 :
102 : uint8_t*
103 0 : CryptoBuffer::AppendSECItem(const SECItem& aItem)
104 : {
105 0 : return AppendElements(aItem.data, aItem.len, fallible);
106 : }
107 :
108 : // Helpers to encode/decode JWK's special flavor of Base64
109 : // * No whitespace
110 : // * No padding
111 : // * URL-safe character set
112 : nsresult
113 0 : CryptoBuffer::FromJwkBase64(const nsString& aBase64)
114 : {
115 0 : NS_ConvertUTF16toUTF8 temp(aBase64);
116 0 : temp.StripWhitespace();
117 :
118 : // JWK prohibits padding per RFC 7515, section 2.
119 0 : nsresult rv = Base64URLDecode(temp, Base64URLDecodePaddingPolicy::Reject,
120 0 : *this);
121 0 : NS_ENSURE_SUCCESS(rv, rv);
122 :
123 0 : return NS_OK;
124 : }
125 :
126 : nsresult
127 0 : CryptoBuffer::ToJwkBase64(nsString& aBase64) const
128 : {
129 : // Shortcut for the empty octet string
130 0 : if (Length() == 0) {
131 0 : aBase64.Truncate();
132 0 : return NS_OK;
133 : }
134 :
135 0 : nsAutoCString base64;
136 0 : nsresult rv = Base64URLEncode(Length(), Elements(),
137 0 : Base64URLEncodePaddingPolicy::Omit, base64);
138 0 : NS_ENSURE_SUCCESS(rv, rv);
139 :
140 0 : CopyASCIItoUTF16(base64, aBase64);
141 0 : return NS_OK;
142 : }
143 :
144 : bool
145 0 : CryptoBuffer::ToSECItem(PLArenaPool *aArena, SECItem* aItem) const
146 : {
147 0 : aItem->type = siBuffer;
148 0 : aItem->data = nullptr;
149 :
150 0 : if (!::SECITEM_AllocItem(aArena, aItem, Length())) {
151 0 : return false;
152 : }
153 :
154 0 : memcpy(aItem->data, Elements(), Length());
155 0 : return true;
156 : }
157 :
158 : JSObject*
159 0 : CryptoBuffer::ToUint8Array(JSContext* aCx) const
160 : {
161 0 : return Uint8Array::Create(aCx, Length(), Elements());
162 : }
163 :
164 : bool
165 0 : CryptoBuffer::ToNewUnsignedBuffer(uint8_t** aBuf, uint32_t* aBufLen) const
166 : {
167 0 : MOZ_ASSERT(aBuf);
168 0 : MOZ_ASSERT(aBufLen);
169 :
170 0 : uint32_t dataLen = Length();
171 0 : uint8_t* tmp = reinterpret_cast<uint8_t*>(moz_xmalloc(dataLen));
172 0 : if (NS_WARN_IF(!tmp)) {
173 0 : return false;
174 : }
175 :
176 0 : memcpy(tmp, Elements(), dataLen);
177 0 : *aBuf = tmp;
178 0 : *aBufLen = dataLen;
179 0 : return true;
180 : }
181 :
182 : // "BigInt" comes from the WebCrypto spec
183 : // ("unsigned long" isn't very "big", of course)
184 : // Likewise, the spec calls for big-endian ints
185 : bool
186 0 : CryptoBuffer::GetBigIntValue(unsigned long& aRetVal)
187 : {
188 0 : if (Length() > sizeof(aRetVal)) {
189 0 : return false;
190 : }
191 :
192 0 : aRetVal = 0;
193 0 : for (size_t i=0; i < Length(); ++i) {
194 0 : aRetVal = (aRetVal << 8) + ElementAt(i);
195 : }
196 0 : return true;
197 : }
198 :
199 : } // namespace dom
200 : } // namespace mozilla
|