blob: 9d388a3f9ce67fed008ea6b399db20e59e3882a7 [file] [log] [blame]
Max Bires44c78812020-04-10 09:38:23 -07001/*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "cppbor_parse.h"
18
Max Bires44c78812020-04-10 09:38:23 -070019#include <stack>
20
Bram Bonnéf04333a2020-10-20 16:40:52 +020021#ifndef __TRUSTY__
Shawn Willden6ad57322020-11-20 00:31:53 -070022#include <android-base/logging.h>
23#define LOG_TAG "CppBor"
Bram Bonnéf04333a2020-10-20 16:40:52 +020024#else
Shawn Willden6ad57322020-11-20 00:31:53 -070025#define CHECK(x) (void)(x)
Bram Bonnéf04333a2020-10-20 16:40:52 +020026#endif
Max Bires44c78812020-04-10 09:38:23 -070027
28namespace cppbor {
29
30namespace {
31
32std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
33 const std::string& type) {
Bram Bonnéf04333a2020-10-20 16:40:52 +020034 char buf[1024];
Shawn Willden0f9cd2d2020-11-20 00:35:10 -070035 snprintf(buf, sizeof(buf), "Need %zu byte(s) for %s, have %zu.", bytesNeeded, type.c_str(),
Shawn Willden6ad57322020-11-20 00:31:53 -070036 bytesAvail);
Bram Bonnéf04333a2020-10-20 16:40:52 +020037 return std::string(buf);
Max Bires44c78812020-04-10 09:38:23 -070038}
39
40template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
41std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
42 ParseClient* parseClient) {
43 if (pos + sizeof(T) > end) {
44 parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
45 return {false, 0, pos};
46 }
47
48 const uint8_t* intEnd = pos + sizeof(T);
49 T result = 0;
50 do {
51 result = static_cast<T>((result << 8) | *pos++);
52 } while (pos < intEnd);
53 return {true, result, pos};
54}
55
56std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
Andrei Homescu4d171a72021-02-12 22:47:05 -080057 bool emitViews, ParseClient* parseClient);
Max Bires44c78812020-04-10 09:38:23 -070058
59std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
60 const uint8_t* hdrEnd,
61 ParseClient* parseClient) {
62 std::unique_ptr<Item> item = std::make_unique<Uint>(value);
63 return {hdrEnd,
64 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
65}
66
67std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
68 const uint8_t* hdrEnd,
69 ParseClient* parseClient) {
70 if (value > std::numeric_limits<int64_t>::max()) {
71 parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
72 return {hdrBegin, nullptr /* end parsing */};
73 }
Andrei Homescua7ca25a2021-04-02 23:14:02 -070074 std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<int64_t>(value));
Max Bires44c78812020-04-10 09:38:23 -070075 return {hdrEnd,
76 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
77}
78
79std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
80 const uint8_t* hdrEnd,
81 ParseClient* parseClient) {
82 std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
83 return {hdrEnd,
84 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
85}
86
87std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
88 ParseClient* parseClient) {
89 std::unique_ptr<Item> item = std::make_unique<Null>();
90 return {hdrEnd,
91 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
92}
93
94template <typename T>
95std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
96 const uint8_t* valueBegin, const uint8_t* end,
97 const std::string& errLabel,
98 ParseClient* parseClient) {
Shawn Willden49072642021-06-25 10:44:06 -060099 ssize_t signed_length = static_cast<ssize_t>(length);
100 if (end - valueBegin < signed_length || signed_length < 0) {
Max Bires44c78812020-04-10 09:38:23 -0700101 parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
102 return {hdrBegin, nullptr /* end parsing */};
103 }
104
105 std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
106 return {valueBegin + length,
107 parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
108}
109
110class IncompleteItem {
111 public:
112 virtual ~IncompleteItem() {}
113 virtual void add(std::unique_ptr<Item> item) = 0;
114};
115
116class IncompleteArray : public Array, public IncompleteItem {
117 public:
Shawn Willden03990c22020-11-24 19:05:09 -0700118 explicit IncompleteArray(size_t size) : mSize(size) {}
Max Bires44c78812020-04-10 09:38:23 -0700119
120 // We return the "complete" size, rather than the actual size.
121 size_t size() const override { return mSize; }
122
123 void add(std::unique_ptr<Item> item) override {
124 mEntries.reserve(mSize);
125 mEntries.push_back(std::move(item));
126 }
127
128 private:
129 size_t mSize;
130};
131
132class IncompleteMap : public Map, public IncompleteItem {
133 public:
Shawn Willden03990c22020-11-24 19:05:09 -0700134 explicit IncompleteMap(size_t size) : mSize(size) {}
Max Bires44c78812020-04-10 09:38:23 -0700135
136 // We return the "complete" size, rather than the actual size.
137 size_t size() const override { return mSize; }
138
139 void add(std::unique_ptr<Item> item) override {
Shawn Willden03990c22020-11-24 19:05:09 -0700140 if (mKeyHeldForAdding) {
141 mEntries.reserve(mSize);
142 mEntries.push_back({std::move(mKeyHeldForAdding), std::move(item)});
143 } else {
144 mKeyHeldForAdding = std::move(item);
145 }
Max Bires44c78812020-04-10 09:38:23 -0700146 }
147
148 private:
Shawn Willden03990c22020-11-24 19:05:09 -0700149 std::unique_ptr<Item> mKeyHeldForAdding;
Max Bires44c78812020-04-10 09:38:23 -0700150 size_t mSize;
151};
152
Shawn Willden315d8592020-11-25 15:46:34 -0700153class IncompleteSemanticTag : public SemanticTag, public IncompleteItem {
Max Bires44c78812020-04-10 09:38:23 -0700154 public:
Shawn Willden315d8592020-11-25 15:46:34 -0700155 explicit IncompleteSemanticTag(uint64_t value) : SemanticTag(value) {}
Max Bires44c78812020-04-10 09:38:23 -0700156
157 // We return the "complete" size, rather than the actual size.
158 size_t size() const override { return 1; }
159
Shawn Willden315d8592020-11-25 15:46:34 -0700160 void add(std::unique_ptr<Item> item) override { mTaggedItem = std::move(item); }
Max Bires44c78812020-04-10 09:38:23 -0700161};
162
163std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
164 const uint8_t* pos, const uint8_t* end,
165 const std::string& typeName,
Andrei Homescu4d171a72021-02-12 22:47:05 -0800166 bool emitViews,
Max Bires44c78812020-04-10 09:38:23 -0700167 ParseClient* parseClient) {
168 while (entryCount > 0) {
169 --entryCount;
170 if (pos == end) {
171 parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
172 return {hdrBegin, nullptr /* end parsing */};
173 }
Andrei Homescu4d171a72021-02-12 22:47:05 -0800174 std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient);
Max Bires44c78812020-04-10 09:38:23 -0700175 if (!parseClient) return {hdrBegin, nullptr};
176 }
177 return {pos, parseClient};
178}
179
180std::tuple<const uint8_t*, ParseClient*> handleCompound(
181 std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
182 const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName,
Andrei Homescu4d171a72021-02-12 22:47:05 -0800183 bool emitViews, ParseClient* parseClient) {
Max Bires44c78812020-04-10 09:38:23 -0700184 parseClient =
185 parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
186 if (!parseClient) return {hdrBegin, nullptr};
187
188 const uint8_t* pos;
189 std::tie(pos, parseClient) =
Andrei Homescu4d171a72021-02-12 22:47:05 -0800190 handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, emitViews, parseClient);
Max Bires44c78812020-04-10 09:38:23 -0700191 if (!parseClient) return {hdrBegin, nullptr};
192
193 return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
194}
195
196std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
Andrei Homescu4d171a72021-02-12 22:47:05 -0800197 bool emitViews, ParseClient* parseClient) {
Hasini Gunasinghe8f490882022-01-11 02:58:57 +0000198 if (begin == end) {
199 parseClient->error(
200 begin,
201 "Input buffer is empty. Begin and end cannot point to the same location.");
202 return {begin, nullptr};
203 }
204
Max Bires44c78812020-04-10 09:38:23 -0700205 const uint8_t* pos = begin;
206
207 MajorType type = static_cast<MajorType>(*pos & 0xE0);
208 uint8_t tagInt = *pos & 0x1F;
209 ++pos;
210
211 bool success = true;
212 uint64_t addlData;
Andrew Scull42a7aa82021-03-30 12:48:04 +0000213 if (tagInt < ONE_BYTE_LENGTH) {
Max Bires44c78812020-04-10 09:38:23 -0700214 addlData = tagInt;
Andrew Scull42a7aa82021-03-30 12:48:04 +0000215 } else if (tagInt > EIGHT_BYTE_LENGTH) {
216 parseClient->error(
217 begin,
218 "Reserved additional information value or unsupported indefinite length item.");
219 return {begin, nullptr};
Max Bires44c78812020-04-10 09:38:23 -0700220 } else {
221 switch (tagInt) {
222 case ONE_BYTE_LENGTH:
223 std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
224 break;
225
226 case TWO_BYTE_LENGTH:
227 std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
228 break;
229
230 case FOUR_BYTE_LENGTH:
231 std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
232 break;
233
234 case EIGHT_BYTE_LENGTH:
235 std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
236 break;
237
238 default:
239 CHECK(false); // It's impossible to get here
240 break;
241 }
242 }
243
244 if (!success) return {begin, nullptr};
245
246 switch (type) {
247 case UINT:
248 return handleUint(addlData, begin, pos, parseClient);
249
250 case NINT:
251 return handleNint(addlData, begin, pos, parseClient);
252
253 case BSTR:
Andrei Homescu4d171a72021-02-12 22:47:05 -0800254 if (emitViews) {
255 return handleString<ViewBstr>(addlData, begin, pos, end, "byte string", parseClient);
256 } else {
257 return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
258 }
Max Bires44c78812020-04-10 09:38:23 -0700259
260 case TSTR:
Andrei Homescu4d171a72021-02-12 22:47:05 -0800261 if (emitViews) {
262 return handleString<ViewTstr>(addlData, begin, pos, end, "text string", parseClient);
263 } else {
264 return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
265 }
Max Bires44c78812020-04-10 09:38:23 -0700266
267 case ARRAY:
268 return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
Andrei Homescu4d171a72021-02-12 22:47:05 -0800269 end, "array", emitViews, parseClient);
Max Bires44c78812020-04-10 09:38:23 -0700270
271 case MAP:
272 return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
Andrei Homescu4d171a72021-02-12 22:47:05 -0800273 pos, end, "map", emitViews, parseClient);
Max Bires44c78812020-04-10 09:38:23 -0700274
275 case SEMANTIC:
Shawn Willden315d8592020-11-25 15:46:34 -0700276 return handleCompound(std::make_unique<IncompleteSemanticTag>(addlData), 1, begin, pos,
Andrei Homescu4d171a72021-02-12 22:47:05 -0800277 end, "semantic", emitViews, parseClient);
Max Bires44c78812020-04-10 09:38:23 -0700278
279 case SIMPLE:
280 switch (addlData) {
281 case TRUE:
282 case FALSE:
283 return handleBool(addlData, begin, pos, parseClient);
284 case NULL_V:
285 return handleNull(begin, pos, parseClient);
Andrew Scullbdc577b2021-03-30 12:53:04 +0000286 default:
287 parseClient->error(begin, "Unsupported floating-point or simple value.");
288 return {begin, nullptr};
Max Bires44c78812020-04-10 09:38:23 -0700289 }
290 }
291 CHECK(false); // Impossible to get here.
292 return {};
293}
294
295class FullParseClient : public ParseClient {
296 public:
297 virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
298 const uint8_t* end) override {
299 if (mParentStack.empty() && !item->isCompound()) {
300 // This is the first and only item.
301 mTheItem = std::move(item);
302 mPosition = end;
303 return nullptr; // We're done.
304 }
305
306 if (item->isCompound()) {
307 // Starting a new compound data item, i.e. a new parent. Save it on the parent stack.
308 // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
309 // existence until the corresponding itemEnd() call.
Shawn Willdenc5a4a3f2020-12-01 08:14:39 -0700310 mParentStack.push(item.get());
Max Bires44c78812020-04-10 09:38:23 -0700311 return this;
312 } else {
313 appendToLastParent(std::move(item));
314 return this;
315 }
316 }
317
318 virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
319 const uint8_t* end) override {
320 CHECK(item->isCompound() && item.get() == mParentStack.top());
321 mParentStack.pop();
322
323 if (mParentStack.empty()) {
324 mTheItem = std::move(item);
325 mPosition = end;
326 return nullptr; // We're done
327 } else {
328 appendToLastParent(std::move(item));
329 return this;
330 }
331 }
332
333 virtual void error(const uint8_t* position, const std::string& errorMessage) override {
334 mPosition = position;
335 mErrorMessage = errorMessage;
336 }
337
338 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
339 std::string /* errMsg */>
340 parseResult() {
341 std::unique_ptr<Item> p = std::move(mTheItem);
342 return {std::move(p), mPosition, std::move(mErrorMessage)};
343 }
344
345 private:
346 void appendToLastParent(std::unique_ptr<Item> item) {
347 auto parent = mParentStack.top();
Shawn Willden6ad57322020-11-20 00:31:53 -0700348#if __has_feature(cxx_rtti)
349 assert(dynamic_cast<IncompleteItem*>(parent));
350#endif
Shawn Willden315d8592020-11-25 15:46:34 -0700351
352 IncompleteItem* parentItem{};
Max Bires44c78812020-04-10 09:38:23 -0700353 if (parent->type() == ARRAY) {
Shawn Willden315d8592020-11-25 15:46:34 -0700354 parentItem = static_cast<IncompleteArray*>(parent);
Max Bires44c78812020-04-10 09:38:23 -0700355 } else if (parent->type() == MAP) {
Shawn Willden315d8592020-11-25 15:46:34 -0700356 parentItem = static_cast<IncompleteMap*>(parent);
357 } else if (parent->asSemanticTag()) {
358 parentItem = static_cast<IncompleteSemanticTag*>(parent);
Max Bires44c78812020-04-10 09:38:23 -0700359 } else {
360 CHECK(false); // Impossible to get here.
361 }
Shawn Willden315d8592020-11-25 15:46:34 -0700362 parentItem->add(std::move(item));
Max Bires44c78812020-04-10 09:38:23 -0700363 }
364
365 std::unique_ptr<Item> mTheItem;
Shawn Willdenc5a4a3f2020-12-01 08:14:39 -0700366 std::stack<Item*> mParentStack;
Max Bires44c78812020-04-10 09:38:23 -0700367 const uint8_t* mPosition = nullptr;
368 std::string mErrorMessage;
369};
370
371} // anonymous namespace
372
373void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
Andrei Homescu4d171a72021-02-12 22:47:05 -0800374 parseRecursively(begin, end, false, parseClient);
Max Bires44c78812020-04-10 09:38:23 -0700375}
376
377std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
378 std::string /* errMsg */>
379parse(const uint8_t* begin, const uint8_t* end) {
380 FullParseClient parseClient;
381 parse(begin, end, &parseClient);
382 return parseClient.parseResult();
383}
384
Andrei Homescu4d171a72021-02-12 22:47:05 -0800385void parseWithViews(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
386 parseRecursively(begin, end, true, parseClient);
387}
388
389std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
390 std::string /* errMsg */>
391parseWithViews(const uint8_t* begin, const uint8_t* end) {
392 FullParseClient parseClient;
393 parseWithViews(begin, end, &parseClient);
394 return parseClient.parseResult();
395}
396
Max Bires44c78812020-04-10 09:38:23 -0700397} // namespace cppbor