@@ -81,7 +81,7 @@ namespace
8181 std::list<std::vector<cbor_raw>> arrays;
8282 std::list<std::vector<cbor_map_entry>> maps;
8383 };
84- Value consume (cbor_nondet_t cbor);
84+ Value consume (cbor_nondet_t cbor, size_t depth, size_t max_depth );
8585
8686 void print_indent (std::ostringstream& os, size_t indent)
8787 {
@@ -129,7 +129,7 @@ namespace
129129 return std::make_shared<ValueImpl>(value);
130130 }
131131
132- Value consume_array (cbor_nondet_t cbor)
132+ Value consume_array (cbor_nondet_t cbor, size_t depth, size_t max_depth )
133133 {
134134 cbor_nondet_array_iterator_t iter;
135135 if (!cbor_nondet_array_iterator_start (cbor, &iter))
@@ -147,12 +147,12 @@ namespace
147147 throw CBORDecodeError (
148148 Error::DECODE_FAILED, " Failed to get next array item" );
149149 }
150- array.items .push_back (consume (item));
150+ array.items .push_back (consume (item, depth + 1 , max_depth ));
151151 }
152152 return std::make_shared<ValueImpl>(std::move (array));
153153 }
154154
155- Value consume_map (cbor_nondet_t cbor)
155+ Value consume_map (cbor_nondet_t cbor, size_t depth, size_t max_depth )
156156 {
157157 cbor_map_iterator iter;
158158 if (!cbor_nondet_map_iterator_start (cbor, &iter))
@@ -171,12 +171,14 @@ namespace
171171 throw CBORDecodeError (
172172 Error::DECODE_FAILED, " Failed to get next map entry" );
173173 }
174- map.items .emplace_back (consume (key_raw), consume (value_raw));
174+ map.items .emplace_back (
175+ consume (key_raw, depth + 1 , max_depth),
176+ consume (value_raw, depth + 1 , max_depth));
175177 }
176178 return std::make_shared<ValueImpl>(std::move (map));
177179 }
178180
179- Value consume_tagged (cbor_nondet_t cbor)
181+ Value consume_tagged (cbor_nondet_t cbor, size_t depth, size_t max_depth )
180182 {
181183 uint64_t tag = 0 ;
182184 cbor_nondet_t payload;
@@ -188,7 +190,7 @@ namespace
188190
189191 Tagged tagged;
190192 tagged.tag = tag;
191- tagged.item = consume (payload);
193+ tagged.item = consume (payload, depth + 1 , max_depth );
192194 return std::make_shared<ValueImpl>(std::move (tagged));
193195 }
194196
@@ -206,8 +208,15 @@ namespace
206208 return std::make_shared<ValueImpl>(value);
207209 }
208210
209- Value consume (cbor_nondet_t cbor)
211+ Value consume (cbor_nondet_t cbor, size_t depth, size_t max_depth )
210212 {
213+ if (depth > max_depth)
214+ {
215+ throw CBORDecodeError (
216+ Error::DECODE_FAILED,
217+ fmt::format (" Maximum CBOR nesting depth ({}) exceeded" , max_depth));
218+ }
219+
211220 const auto mt = cbor_nondet_major_type (cbor);
212221 switch (mt)
213222 {
@@ -219,11 +228,11 @@ namespace
219228 case CBOR_MAJOR_TYPE_TEXT_STRING:
220229 return consume_text_string (cbor);
221230 case CBOR_MAJOR_TYPE_ARRAY:
222- return consume_array (cbor);
231+ return consume_array (cbor, depth, max_depth );
223232 case CBOR_MAJOR_TYPE_MAP:
224- return consume_map (cbor);
233+ return consume_map (cbor, depth, max_depth );
225234 case CBOR_MAJOR_TYPE_TAGGED:
226- return consume_tagged (cbor);
235+ return consume_tagged (cbor, depth, max_depth );
227236 case CBOR_MAJOR_TYPE_SIMPLE_VALUE:
228237 return consume_simple (cbor);
229238 default :
@@ -249,7 +258,8 @@ namespace
249258 }
250259 }
251260
252- cbor_raw to_raw_cbor (const Value& value, CborRawArena& arena);
261+ cbor_raw to_raw_cbor (
262+ const Value& value, CborRawArena& arena, size_t depth, size_t max_depth);
253263
254264 cbor_raw to_raw_signed (const Signed& v)
255265 {
@@ -295,10 +305,11 @@ namespace
295305 return result;
296306 }
297307
298- cbor_raw to_raw_tagged (const Tagged& v, CborRawArena& arena)
308+ cbor_raw to_raw_tagged (
309+ const Tagged& v, CborRawArena& arena, size_t depth, size_t max_depth)
299310 {
300311 cbor_raw result;
301- arena.push (to_raw_cbor (v.item , arena));
312+ arena.push (to_raw_cbor (v.item , arena, depth + 1 , max_depth ));
302313 if (!cbor_nondet_mk_tagged (v.tag , arena.single (), &result))
303314 {
304315 throw CBOREncodeError (
@@ -308,14 +319,15 @@ namespace
308319 return result;
309320 }
310321
311- cbor_raw to_raw_array (const Array& v, CborRawArena& arena)
322+ cbor_raw to_raw_array (
323+ const Array& v, CborRawArena& arena, size_t depth, size_t max_depth)
312324 {
313325 cbor_raw result;
314326 std::vector<cbor_raw> items;
315327 items.reserve (v.items .size ());
316328 for (const auto & item : v.items )
317329 {
318- items.push_back (to_raw_cbor (item, arena));
330+ items.push_back (to_raw_cbor (item, arena, depth + 1 , max_depth ));
319331 }
320332
321333 size_t arr_size = items.size ();
@@ -337,16 +349,17 @@ namespace
337349 return result;
338350 }
339351
340- cbor_raw to_raw_map (const Map& v, CborRawArena& arena)
352+ cbor_raw to_raw_map (
353+ const Map& v, CborRawArena& arena, size_t depth, size_t max_depth)
341354 {
342355 cbor_raw result;
343356
344357 std::vector<cbor_map_entry> entries;
345358 entries.reserve (v.items .size ());
346359 for (const auto & [key, value] : v.items )
347360 {
348- auto cbor_key = to_raw_cbor (key, arena);
349- auto cbor_value = to_raw_cbor (value, arena);
361+ auto cbor_key = to_raw_cbor (key, arena, depth + 1 , max_depth );
362+ auto cbor_value = to_raw_cbor (value, arena, depth + 1 , max_depth );
350363 entries.push_back (cbor_nondet_mk_map_entry (cbor_key, cbor_value));
351364 }
352365
@@ -369,8 +382,16 @@ namespace
369382 return result;
370383 }
371384
372- cbor_raw to_raw_cbor (const Value& value, CborRawArena& arena)
385+ cbor_raw to_raw_cbor (
386+ const Value& value, CborRawArena& arena, size_t depth, size_t max_depth)
373387 {
388+ if (depth > max_depth)
389+ {
390+ throw CBOREncodeError (
391+ Error::ENCODE_FAILED,
392+ fmt::format (" Maximum CBOR nesting depth ({}) exceeded" , max_depth));
393+ }
394+
374395 return std::visit (
375396 [&](const auto & v) {
376397 using T = std::decay_t <decltype (v)>;
@@ -392,15 +413,15 @@ namespace
392413 }
393414 if constexpr (std::is_same_v<T, Tagged>)
394415 {
395- return to_raw_tagged (v, arena);
416+ return to_raw_tagged (v, arena, depth, max_depth );
396417 }
397418 if constexpr (std::is_same_v<T, Array>)
398419 {
399- return to_raw_array (v, arena);
420+ return to_raw_array (v, arena, depth, max_depth );
400421 }
401422 if constexpr (std::is_same_v<T, Map>)
402423 {
403- return to_raw_map (v, arena);
424+ return to_raw_map (v, arena, depth, max_depth );
404425 }
405426 },
406427 value->value );
@@ -536,7 +557,7 @@ namespace ccf::cbor
536557 return std::make_shared<ValueImpl>(Map{.items = std::move (data)});
537558 }
538559
539- Value parse (std::span<const uint8_t > raw)
560+ Value parse (std::span<const uint8_t > raw, size_t max_depth )
540561 {
541562 cbor_nondet_t cbor;
542563 const bool check_map_key_bound = false ;
@@ -561,13 +582,13 @@ namespace ccf::cbor
561582 fmt::format (" Trailing {} byte(s) after CBOR item" , cbor_parse_size));
562583 }
563584
564- return consume (cbor);
585+ return consume (cbor, 0 , max_depth );
565586 }
566587
567- std::vector<uint8_t > serialize (const Value& value)
588+ std::vector<uint8_t > serialize (const Value& value, size_t max_depth )
568589 {
569590 CborRawArena arena{};
570- auto raw = to_raw_cbor (value, arena);
591+ auto raw = to_raw_cbor (value, arena, 0 , max_depth );
571592 const auto expected_size =
572593 cbor_nondet_size (raw, std::numeric_limits<size_t >::max ());
573594
0 commit comments