Skip to content

Commit ae5ffd0

Browse files
committed
Use CBOR-write wrappers
1 parent f934066 commit ae5ffd0

File tree

5 files changed

+137
-269
lines changed

5 files changed

+137
-269
lines changed

src/crypto/cbor.cpp

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ namespace
9999
throw CBORDecodeError(
100100
Error::DECODE_FAILED, "Failed to decode signed value");
101101
}
102-
return std::make_unique<ValueImpl>(value);
102+
return std::make_shared<ValueImpl>(value);
103103
}
104104

105105
Value consume_byte_string(cbor_nondet_t cbor)
@@ -112,7 +112,7 @@ namespace
112112
Error::DECODE_FAILED, "Failed to decode byte string");
113113
}
114114
Bytes value{data, static_cast<size_t>(length)};
115-
return std::make_unique<ValueImpl>(value);
115+
return std::make_shared<ValueImpl>(value);
116116
}
117117

118118
Value consume_text_string(cbor_nondet_t cbor)
@@ -126,7 +126,7 @@ namespace
126126
}
127127
String value{
128128
reinterpret_cast<const char*>(data), static_cast<size_t>(length)};
129-
return std::make_unique<ValueImpl>(value);
129+
return std::make_shared<ValueImpl>(value);
130130
}
131131

132132
Value consume_array(cbor_nondet_t cbor)
@@ -149,7 +149,7 @@ namespace
149149
}
150150
array.items.push_back(consume(item));
151151
}
152-
return std::make_unique<ValueImpl>(std::move(array));
152+
return std::make_shared<ValueImpl>(std::move(array));
153153
}
154154

155155
Value consume_map(cbor_nondet_t cbor)
@@ -173,7 +173,7 @@ namespace
173173
}
174174
map.items.emplace_back(consume(key_raw), consume(value_raw));
175175
}
176-
return std::make_unique<ValueImpl>(std::move(map));
176+
return std::make_shared<ValueImpl>(std::move(map));
177177
}
178178

179179
Value consume_tagged(cbor_nondet_t cbor)
@@ -189,7 +189,7 @@ namespace
189189
Tagged tagged;
190190
tagged.tag = tag;
191191
tagged.item = consume(payload);
192-
return std::make_unique<ValueImpl>(std::move(tagged));
192+
return std::make_shared<ValueImpl>(std::move(tagged));
193193
}
194194

195195
Value consume_simple(cbor_nondet_t cbor)
@@ -203,7 +203,7 @@ namespace
203203
throw CBORDecodeError(
204204
Error::DECODE_FAILED, "Failed to decode simple value");
205205
}
206-
return std::make_unique<ValueImpl>(value);
206+
return std::make_shared<ValueImpl>(value);
207207
}
208208

209209
Value consume(cbor_nondet_t cbor)
@@ -502,17 +502,38 @@ namespace ccf::cbor
502502

503503
Value make_signed(int64_t value)
504504
{
505-
return std::make_unique<ValueImpl>(value);
505+
return std::make_shared<ValueImpl>(value);
506+
}
507+
508+
Value make_simple(SimpleValue value)
509+
{
510+
return std::make_shared<ValueImpl>(value);
506511
}
507512

508513
Value make_string(std::string_view data)
509514
{
510-
return std::make_unique<ValueImpl>(data);
515+
return std::make_shared<ValueImpl>(data);
511516
}
512517

513518
Value make_bytes(std::span<const uint8_t> data)
514519
{
515-
return std::make_unique<ValueImpl>(data);
520+
return std::make_shared<ValueImpl>(data);
521+
}
522+
523+
Value make_tagged(uint64_t tag, Value&& value)
524+
{
525+
return std::make_shared<ValueImpl>(
526+
Tagged{.tag = tag, .item = std::move(value)});
527+
}
528+
529+
Value make_array(std::vector<Value>&& data)
530+
{
531+
return std::make_shared<ValueImpl>(Array{.items = std::move(data)});
532+
}
533+
534+
Value make_map(std::vector<MapItem>&& data)
535+
{
536+
return std::make_shared<ValueImpl>(Map{.items = std::move(data)});
516537
}
517538

518539
Value parse(std::span<const uint8_t> raw)
@@ -587,6 +608,11 @@ namespace ccf::cbor
587608
}
588609
}
589610

611+
SimpleValue boolean_to_simple(bool value)
612+
{
613+
return value ? SimpleValue::True : SimpleValue::False;
614+
}
615+
590616
const Value& ValueImpl::array_at(size_t index) const
591617
{
592618
if (!std::holds_alternative<Array>(value))

src/crypto/cbor.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
namespace ccf::cbor
1818
{
1919
struct ValueImpl;
20-
using Value = std::unique_ptr<ValueImpl>;
20+
using Value = std::shared_ptr<ValueImpl>;
2121

2222
using Signed = int64_t;
2323
using Bytes = std::span<const uint8_t>;
@@ -40,9 +40,10 @@ namespace ccf::cbor
4040
std::vector<Value> items;
4141
};
4242

43+
using MapItem = std::pair<Value, Value>;
4344
struct Map
4445
{
45-
std::vector<std::pair<Value, Value>> items;
46+
std::vector<MapItem> items;
4647
};
4748

4849
struct Tagged
@@ -99,14 +100,19 @@ namespace ccf::cbor
99100
};
100101

101102
Value make_signed(int64_t value);
103+
Value make_simple(SimpleValue value);
102104
Value make_string(std::string_view data);
103105
Value make_bytes(std::span<const uint8_t> data);
106+
Value make_tagged(uint64_t tag, Value&& value);
107+
Value make_array(std::vector<Value>&& data);
108+
Value make_map(std::vector<MapItem>&& data);
104109

105110
Value parse(std::span<const uint8_t> raw);
106111
std::vector<uint8_t> serialize(const Value& value);
107112

108113
std::string to_string(const Value& value);
109114
bool simple_to_boolean(const Simple& value);
115+
SimpleValue boolean_to_simple(bool value);
110116

111117
decltype(auto) rethrow_with_msg(auto&& f, std::string_view msg = {})
112118
{

src/crypto/cose.cpp

Lines changed: 36 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "ccf/crypto/cose.h"
55

6+
#include "crypto/cbor.h"
7+
68
#include <qcbor/qcbor_decode.h>
79
#include <qcbor/qcbor_encode.h>
810
#include <qcbor/qcbor_spiffy_decode.h>
@@ -14,158 +16,70 @@ namespace ccf::cose::edit
1416
std::vector<uint8_t> set_unprotected_header(
1517
const std::span<const uint8_t>& cose_input, const desc::Type& descriptor)
1618
{
17-
UsefulBufC buf{cose_input.data(), cose_input.size()};
18-
19-
QCBORError err = QCBOR_SUCCESS;
20-
QCBORDecodeContext ctx;
21-
QCBORDecode_Init(&ctx, buf, QCBOR_DECODE_MODE_NORMAL);
22-
23-
size_t pos_start = 0;
24-
size_t pos_end = 0;
25-
26-
QCBORDecode_EnterArray(&ctx, nullptr);
27-
err = QCBORDecode_GetError(&ctx);
28-
if (err != QCBOR_SUCCESS)
29-
{
30-
throw std::logic_error("Failed to parse COSE_Sign1 outer array");
31-
}
32-
33-
auto tag = QCBORDecode_GetNthTagOfLast(&ctx, 0);
34-
if (tag != CBOR_TAG_COSE_SIGN1)
35-
{
36-
throw std::logic_error("Failed to parse COSE_Sign1 tag");
37-
}
38-
39-
QCBORItem item;
40-
err = QCBORDecode_GetNext(&ctx, &item);
41-
if (err != QCBOR_SUCCESS || item.uDataType != QCBOR_TYPE_BYTE_STRING)
42-
{
43-
throw std::logic_error(
44-
"Failed to parse COSE_Sign1 protected header as bstr");
45-
}
46-
UsefulBufC phdr = {item.val.string.ptr, item.val.string.len};
47-
48-
// Skip unprotected header
49-
QCBORDecode_VGetNextConsume(&ctx, &item);
50-
51-
err = QCBORDecode_PartialFinish(&ctx, &pos_start);
52-
if (err != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED)
53-
{
54-
throw std::logic_error("Failed to find start of payload");
55-
}
56-
QCBORDecode_VGetNextConsume(&ctx, &item);
57-
err = QCBORDecode_PartialFinish(&ctx, &pos_end);
58-
if (err != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED)
59-
{
60-
throw std::logic_error("Failed to find end of payload");
61-
}
62-
UsefulBufC payload = {cose_input.data() + pos_start, pos_end - pos_start};
63-
64-
// QCBORDecode_PartialFinish() before and after should allow constructing a
65-
// span of the encoded payload, which can perhaps then be passed to
66-
// QCBOREncode_AddEncoded and would allow blindly copying the payload
67-
// without parsing it.
68-
69-
err = QCBORDecode_GetNext(&ctx, &item);
70-
if (err != QCBOR_SUCCESS && item.uDataType != QCBOR_TYPE_BYTE_STRING)
71-
{
72-
throw std::logic_error("Failed to parse COSE_Sign1 signature");
73-
}
74-
UsefulBufC signature = {item.val.string.ptr, item.val.string.len};
19+
using namespace ccf::cbor;
7520

76-
QCBORDecode_ExitArray(&ctx);
77-
err = QCBORDecode_Finish(&ctx);
78-
if (err != QCBOR_SUCCESS)
79-
{
80-
throw std::logic_error("Failed to parse COSE_Sign1");
81-
}
21+
auto cose_cbor = rethrow_with_msg(
22+
[&]() { return parse(cose_input); }, "Failed to parse COSE_Sign1");
8223

83-
size_t additional_map_size = 0;
24+
const auto& cose_envelope = rethrow_with_msg(
25+
[&]() -> auto& { return cose_cbor->tag_at(18); },
26+
"Failed to parse COSE_Sign1 tag");
8427

85-
if (std::holds_alternative<desc::Empty>(descriptor))
86-
{
87-
// Nothing to do
88-
}
89-
else if (std::holds_alternative<desc::Value>(descriptor))
90-
{
91-
const auto& [pos, key, value] = std::get<desc::Value>(descriptor);
28+
const auto& phdr = rethrow_with_msg(
29+
[&]() -> auto& { return cose_envelope->array_at(0); },
30+
"Failed to parse COSE_Sign1 protected header");
9231

93-
// Maximum expected size of the additional map, sub-map is the
94-
// worst-case scenario
95-
additional_map_size = QCBOR_HEAD_BUFFER_SIZE + // map
96-
QCBOR_HEAD_BUFFER_SIZE + // key
97-
sizeof(key) + // key
98-
QCBOR_HEAD_BUFFER_SIZE + // submap
99-
QCBOR_HEAD_BUFFER_SIZE + // subkey
100-
sizeof(pos::AtKey::key) + // subkey
101-
QCBOR_HEAD_BUFFER_SIZE + // value
102-
value.size(); // value
103-
}
104-
else
105-
{
106-
throw std::logic_error("Invalid COSE_Sign1 edit descriptor");
107-
}
32+
const auto& payload = rethrow_with_msg(
33+
[&]() -> auto& { return cose_envelope->array_at(2); },
34+
"Failed to parse COSE_Sign1 payload");
10835

109-
// We add one extra QCBOR_HEAD_BUFFER_SIZE, because we parse and re-encode
110-
// the protected header bstr, which involves variable integer encoding, just
111-
// in case the library does not pick the most compact encoding.
112-
std::vector<uint8_t> output(
113-
cose_input.size() + additional_map_size + QCBOR_HEAD_BUFFER_SIZE);
114-
UsefulBuf output_buf{output.data(), output.size()};
36+
const auto& signature = rethrow_with_msg(
37+
[&]() -> auto& { return cose_envelope->array_at(3); },
38+
"Failed to parse COSE_Sign1 signature");
11539

116-
QCBOREncodeContext ectx;
117-
QCBOREncode_Init(&ectx, output_buf);
118-
QCBOREncode_AddTag(&ectx, CBOR_TAG_COSE_SIGN1);
119-
QCBOREncode_OpenArray(&ectx);
120-
QCBOREncode_AddBytes(&ectx, phdr);
121-
QCBOREncode_OpenMap(&ectx);
40+
std::vector<Value> edited;
41+
edited.push_back(phdr);
12242

12343
if (std::holds_alternative<desc::Empty>(descriptor))
12444
{
125-
// Nothing to do
45+
edited.push_back(make_map({}));
12646
}
12747
else if (std::holds_alternative<desc::Value>(descriptor))
12848
{
12949
const auto& [pos, key, value] = std::get<desc::Value>(descriptor);
50+
std::vector<MapItem> uhdr;
13051

13152
if (std::holds_alternative<pos::InArray>(pos))
13253
{
133-
QCBOREncode_OpenArrayInMapN(&ectx, key);
134-
QCBOREncode_AddBytes(&ectx, {value.data(), value.size()});
135-
QCBOREncode_CloseArray(&ectx);
54+
std::vector<Value> items{make_bytes(value)};
55+
uhdr.emplace_back(make_signed(key), make_array(std::move(items)));
13656
}
13757
else if (std::holds_alternative<pos::AtKey>(pos))
13858
{
139-
QCBOREncode_OpenMapInMapN(&ectx, key);
14059
auto subkey = std::get<pos::AtKey>(pos).key;
141-
QCBOREncode_OpenArrayInMapN(&ectx, subkey);
142-
QCBOREncode_AddBytes(&ectx, {value.data(), value.size()});
143-
QCBOREncode_CloseArray(&ectx);
144-
QCBOREncode_CloseMap(&ectx);
60+
61+
std::vector<Value> items{make_bytes(value)};
62+
std::vector<MapItem> submap{
63+
{make_signed(subkey), make_array(std::move(items))}};
64+
65+
uhdr.emplace_back(make_signed(key), make_map(std::move(submap)));
14566
}
14667
else
14768
{
14869
throw std::logic_error("Invalid COSE_Sign1 edit operation");
14970
}
71+
72+
edited.push_back(make_map(std::move(uhdr)));
15073
}
15174
else
15275
{
15376
throw std::logic_error("Invalid COSE_Sign1 edit descriptor");
15477
}
15578

156-
QCBOREncode_CloseMap(&ectx);
157-
QCBOREncode_AddEncoded(&ectx, payload);
158-
QCBOREncode_AddBytes(&ectx, signature);
159-
QCBOREncode_CloseArray(&ectx);
79+
edited.push_back(payload);
80+
edited.push_back(signature);
16081

161-
UsefulBufC cose_output;
162-
err = QCBOREncode_Finish(&ectx, &cose_output);
163-
if (err != QCBOR_SUCCESS)
164-
{
165-
throw std::logic_error("Failed to encode COSE_Sign1");
166-
}
167-
output.resize(cose_output.len);
168-
output.shrink_to_fit();
169-
return output;
170-
};
82+
auto edited_envelope = make_tagged(18, make_array(std::move(edited)));
83+
return serialize(edited_envelope);
84+
}
17185
}

0 commit comments

Comments
 (0)