Skip to content

Commit 6f37471

Browse files
committed
Add always required keys and parse empty field
Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 7aa1eac commit 6f37471

File tree

3 files changed

+83
-55
lines changed

3 files changed

+83
-55
lines changed

cdoc/Lock.cpp

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#include "json/base.h"
2525

26+
#include <ranges>
27+
2628
namespace libcdoc {
2729

2830
std::string
@@ -59,50 +61,51 @@ Lock::parseLabel(const std::string& label)
5961
{
6062
std::map<std::string, std::string> parsed_label;
6163
// Check if provided label starts with the machine generated label prefix.
62-
if (!label.starts_with(CDoc2::LABELPREFIX))
63-
{
64+
if (!label.starts_with(CDoc2::LABELPREFIX)) {
6465
return parsed_label;
6566
}
6667

67-
std::string label_wo_prefix(label.substr(CDoc2::LABELPREFIX.size()));
68+
auto label_wo_prefix = std::string_view(label).substr(CDoc2::LABELPREFIX.size());
6869

6970
// Label to be processed
70-
std::string label_to_prcss;
71+
std::string decodedBase64; // Strong ref
72+
std::string_view label_to_prcss;
7173

7274
// We ignore mediatype part
7375

7476
// Check, if the label is Base64 encoded
75-
auto base64IndPos = label_wo_prefix.find(CDoc2::LABELBASE64IND);
76-
if (base64IndPos == std::string::npos)
77-
{
78-
if (label_wo_prefix.starts_with(",")) {
79-
label_to_prcss = label_wo_prefix.substr(1);
80-
} else {
81-
label_to_prcss = std::move(label_wo_prefix);
82-
}
83-
}
84-
else
77+
if (auto base64IndPos = label_wo_prefix.find(CDoc2::LABELBASE64IND);
78+
base64IndPos != std::string::npos)
8579
{
8680
std::string base64_label(label_wo_prefix.substr(base64IndPos + CDoc2::LABELBASE64IND.size()));
87-
label_to_prcss = jwt::base::decode<jwt::alphabet::base64>(base64_label);
81+
decodedBase64 = jwt::base::decode<jwt::alphabet::base64>(base64_label);
82+
label_to_prcss = decodedBase64;
83+
} else if (label_wo_prefix.starts_with(",")) {
84+
label_to_prcss = label_wo_prefix.substr(1);
85+
} else {
86+
label_to_prcss = label_wo_prefix;
8887
}
8988

90-
auto label_parts(split(label_to_prcss, '&'));
91-
for (auto& part : label_parts)
89+
for (const auto &part : std::ranges::split_view(label_to_prcss, '&'))
9290
{
93-
auto label_data_parts(split(part, '='));
94-
if (label_data_parts.size() != 2)
95-
{
96-
// Invalid label data. We just ignore them.
91+
auto label_data_parts = std::ranges::split_view(part, '=');
92+
if (label_data_parts.empty()) {
9793
LOG_ERROR("The label '{}' is invalid", label);
94+
continue;
9895
}
99-
else
100-
{
101-
std::string key = urlDecode(label_data_parts[0]);
102-
std::string value = urlDecode(label_data_parts[1]);
103-
std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c){ return std::tolower(c); });
104-
parsed_label[key] = value;
96+
auto it = label_data_parts.begin();
97+
auto key_range = *it;
98+
std::string key = urlDecode(std::string_view(key_range.begin(), key_range.end()));
99+
++it;
100+
if (it == label_data_parts.end() || std::next(it) != label_data_parts.end()) {
101+
// Must have exactly two parts
102+
LOG_ERROR("The label '{}' is invalid", label);
103+
continue;
105104
}
105+
auto value_range = *it;
106+
std::string value = urlDecode(std::string_view(value_range.begin(), value_range.end()));
107+
std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c){ return std::tolower(c); });
108+
parsed_label[std::move(key)] = std::move(value);
106109
}
107110

108111
return parsed_label;

cdoc/Recipient.cpp

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,17 @@ Recipient::isTheSameRecipient(const std::vector<uint8_t>& public_key) const
121121
}
122122

123123
static void
124-
buildLabel(std::ostream& ofs, std::string_view type, std::initializer_list<std::pair<std::string_view, std::string_view>> components)
124+
buildLabel(std::ostream& ofs, std::string_view type,
125+
std::initializer_list<std::pair<std::string_view, std::string_view>> components,
126+
std::initializer_list<std::pair<std::string_view, std::string_view>> optional)
125127
{
126128
ofs << CDoc2::LABELPREFIX;
127129
ofs << "v" << '=' << std::to_string(CDoc2::KEYLABELVERSION) << '&'
128130
<< "type" << '=' << type;
129131
for (const auto& [key, value] : components) {
132+
ofs << '&' << urlEncode(key) << '=' << urlEncode(value);
133+
}
134+
for (const auto& [key, value] : optional) {
130135
if (!value.empty())
131136
ofs << '&' << urlEncode(key) << '=' << urlEncode(value);
132137
}
@@ -138,6 +143,7 @@ BuildLabelEID(std::ostream& ofs, Certificate::EIDType type, const Certificate& x
138143
buildLabel(ofs, CDoc2::eid_strs[type], {
139144
{"cn", x509.getCommonName()},
140145
{"serial_number", x509.getSerialNumber()},
146+
}, {
141147
{"last_name", x509.getSurname()},
142148
{"first_name", x509.getGivenName()},
143149
});
@@ -146,7 +152,7 @@ BuildLabelEID(std::ostream& ofs, Certificate::EIDType type, const Certificate& x
146152
static void
147153
BuildLabelCertificate(std::ostream &ofs, const std::string& file, const Certificate& x509)
148154
{
149-
buildLabel(ofs, "cert", {
155+
buildLabel(ofs, "cert", {}, {
150156
{"file", file},
151157
{"cn", x509.getCommonName()},
152158
{"cert_sha1", toHex(x509.getDigest())}
@@ -156,7 +162,7 @@ BuildLabelCertificate(std::ostream &ofs, const std::string& file, const Certific
156162
static void
157163
BuildLabelPublicKey(std::ostream &ofs, const std::string& file)
158164
{
159-
buildLabel(ofs, "pub_key", {
165+
buildLabel(ofs, "pub_key", {}, {
160166
{"file", file}
161167
});
162168
}
@@ -166,6 +172,7 @@ BuildLabelSymmetricKey(std::ostream &ofs, const std::string& label, const std::s
166172
{
167173
buildLabel(ofs, "secret", {
168174
{"label", label},
175+
}, {
169176
{"file", file}
170177
});
171178
}
@@ -175,7 +182,7 @@ BuildLabelPassword(std::ostream &ofs, const std::string& label)
175182
{
176183
buildLabel(ofs, "pw", {
177184
{"label", label}
178-
});
185+
}, {});
179186
}
180187

181188
std::string
@@ -185,30 +192,27 @@ Recipient::getLabel(const std::vector<std::pair<std::string_view, std::string_vi
185192
if (!label.empty()) return label;
186193
std::ostringstream ofs;
187194
switch(type) {
188-
case NONE:
189-
LOG_DBG("The recipient is not initialized");
190-
break;
191-
case SYMMETRIC_KEY:
192-
if (kdf_iter > 0) {
193-
BuildLabelPassword(ofs, key_name);
194-
} else {
195-
BuildLabelSymmetricKey(ofs, key_name, file_name);
196-
}
197-
break;
198-
case PUBLIC_KEY:
199-
if (!cert.empty()) {
200-
Certificate x509(cert);
201-
if (auto eid = x509.getEIDType(); eid != Certificate::Unknown) {
202-
BuildLabelEID(ofs, eid, x509);
203-
} else {
204-
BuildLabelCertificate(ofs, file_name, x509);
205-
}
206-
} else {
207-
BuildLabelPublicKey(ofs, file_name);
208-
}
209-
break;
210-
case KEYSHARE:
211-
break;
195+
case NONE:
196+
LOG_DBG("The recipient is not initialized");
197+
break;
198+
case SYMMETRIC_KEY:
199+
if (kdf_iter > 0) {
200+
BuildLabelPassword(ofs, key_name);
201+
} else {
202+
BuildLabelSymmetricKey(ofs, key_name, file_name);
203+
}
204+
break;
205+
case PUBLIC_KEY:
206+
if (Certificate x509(cert); !x509) {
207+
BuildLabelPublicKey(ofs, file_name);
208+
} else if (auto eid = x509.getEIDType(); eid != Certificate::Unknown) {
209+
BuildLabelEID(ofs, eid, x509);
210+
} else {
211+
BuildLabelCertificate(ofs, file_name, x509);
212+
}
213+
break;
214+
case KEYSHARE:
215+
break;
212216
}
213217
for (const auto& [key, value] : extra) {
214218
if (!value.empty())

test/libcdoc_boost.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,27 @@ BOOST_AUTO_TEST_CASE(Base64LabelParsingWithMediaType)
790790
}
791791
}
792792
}
793+
794+
BOOST_AUTO_TEST_CASE(Base64LabelParsingEmptyLabel)
795+
{
796+
const string label("data:v=1&type=pw&label=");
797+
798+
auto result = libcdoc::Lock::parseLabel(label);
799+
for (const auto& [key, value] : {
800+
pair<string, string> {"v", "1"},
801+
pair<string, string> {"type", "ID-card"},
802+
pair<string, string> {"label", ""},
803+
})
804+
{
805+
auto result_pair = result.find(key);
806+
BOOST_TEST((result_pair != result.cend()), "Field " << key << " presented");
807+
if (result_pair != result.end())
808+
{
809+
BOOST_CHECK_EQUAL(result_pair->second, value);
810+
}
811+
}
812+
}
813+
793814
BOOST_AUTO_TEST_SUITE_END()
794815

795816
BOOST_AUTO_TEST_SUITE(StreamingDecryption)

0 commit comments

Comments
 (0)