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