Skip to content

Commit 3ea7acb

Browse files
committed
Add expire date to label
Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent b17fddd commit 3ea7acb

File tree

8 files changed

+87
-109
lines changed

8 files changed

+87
-109
lines changed

cdoc/CDoc2Writer.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,15 @@ CDoc2Writer::writeHeader(const std::vector<libcdoc::Recipient> &recipients)
9797
}
9898

9999
static flatbuffers::Offset<cdoc20::header::RecipientRecord>
100-
createRSACapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::vector<uint8_t>& encrypted_kek, const std::vector<uint8_t>& xor_key)
100+
createRSACapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::vector<uint8_t>& encrypted_kek, uint64_t expiry_time, const std::vector<uint8_t>& xor_key)
101101
{
102102
auto capsule = cdoc20::recipients::CreateRSAPublicKeyCapsule(builder,
103103
builder.CreateVector(rcpt.rcpt_key),
104104
builder.CreateVector(encrypted_kek));
105105
return cdoc20::header::CreateRecipientRecord(builder,
106106
cdoc20::header::Capsule::recipients_RSAPublicKeyCapsule,
107107
capsule.Union(),
108-
builder.CreateString(rcpt.getLabel({})),
108+
builder.CreateString(rcpt.getLabel({{"x-expiry-time", expiry_time == 0 ? std::string() : std::to_string(expiry_time)}})),
109109
builder.CreateVector(xor_key),
110110
cdoc20::header::FMKEncryptionMethod::XOR);
111111
}
@@ -129,7 +129,7 @@ createRSAServerCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::R
129129
}
130130

131131
static flatbuffers::Offset<cdoc20::header::RecipientRecord>
132-
createECCCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::vector<uint8_t>& eph_public_key, const std::vector<uint8_t>& xor_key)
132+
createECCCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipient& rcpt, const std::vector<uint8_t>& eph_public_key, uint64_t expiry_time, const std::vector<uint8_t>& xor_key)
133133
{
134134
auto capsule = cdoc20::recipients::CreateECCPublicKeyCapsule(builder,
135135
cdoc20::recipients::EllipticCurve::secp384r1,
@@ -138,7 +138,7 @@ createECCCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipie
138138
return cdoc20::header::CreateRecipientRecord(builder,
139139
cdoc20::header::Capsule::recipients_ECCPublicKeyCapsule,
140140
capsule.Union(),
141-
builder.CreateString(rcpt.getLabel({})),
141+
builder.CreateString(rcpt.getLabel({{"x-expiry-time", expiry_time == 0 ? std::string() : std::to_string(expiry_time)}})),
142142
builder.CreateVector(xor_key),
143143
cdoc20::header::FMKEncryptionMethod::XOR);
144144
}
@@ -285,7 +285,7 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
285285
auto record = createRSAServerCapsule(builder, rcpt, cinfo.transaction_id, cinfo.expiry_time, xor_key);
286286
fb_rcpts.push_back(std::move(record));
287287
} else {
288-
auto record = createRSACapsule(builder, rcpt, key_material, xor_key);
288+
auto record = createRSACapsule(builder, rcpt, key_material, rcpt.expiry_ts, xor_key);
289289
fb_rcpts.push_back(std::move(record));
290290
}
291291
} else {
@@ -320,7 +320,7 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
320320
auto record = createECCServerCapsule(builder, rcpt, cinfo.transaction_id, cinfo.expiry_time, xor_key);
321321
fb_rcpts.push_back(std::move(record));
322322
} else {
323-
auto record = createECCCapsule(builder, rcpt, key_material, xor_key);
323+
auto record = createECCCapsule(builder, rcpt, key_material, rcpt.expiry_ts, xor_key);
324324
fb_rcpts.push_back(std::move(record));
325325
}
326326
}

cdoc/Certificate.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,21 @@ Certificate::getSerialNumber() const
7474
return getName(cert, NID_serialNumber);
7575
}
7676

77+
time_t
78+
Certificate::getNotAfter() const
79+
{
80+
if(!cert)
81+
return 0;
82+
tm tm{};
83+
if(ASN1_TIME_to_tm(X509_get0_notAfter(cert.get()), &tm) != 1)
84+
return 0;
85+
#ifdef _WIN32
86+
return _mkgmtime(&tm);
87+
#else
88+
return timegm(&tm);
89+
#endif
90+
}
91+
7792

7893

7994
std::vector<std::string>
@@ -85,8 +100,8 @@ Certificate::policies() const
85100
if(!cert)
86101
return list;
87102

88-
auto p = static_cast<CERTIFICATEPOLICIES *>(X509_get_ext_d2i(cert.get(), NID_certificate_policies, nullptr, nullptr));
89-
auto cp = std::unique_ptr<CERTIFICATEPOLICIES,decltype(&CERTIFICATEPOLICIES_free)>(p,CERTIFICATEPOLICIES_free);
103+
auto cp = make_unique_cast<CERTIFICATEPOLICIES_free>(X509_get_ext_d2i(
104+
cert.get(), NID_certificate_policies, nullptr, nullptr));
90105
if(!cp)
91106
return list;
92107

@@ -122,7 +137,7 @@ Certificate::getAlgorithm() const
122137
return (alg == EVP_PKEY_RSA) ? Algorithm::RSA : Algorithm::ECC;
123138
}
124139

125-
std::vector<uint8_t> Certificate::getDigest()
140+
std::vector<uint8_t> Certificate::getDigest() const
126141
{
127142
if(!cert)
128143
return {};

cdoc/Certificate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ class Certificate {
5050

5151
std::vector<uint8_t> getPublicKey() const;
5252
Algorithm getAlgorithm() const;
53+
time_t getNotAfter() const;
5354

54-
std::vector<uint8_t> getDigest();
55+
std::vector<uint8_t> getDigest() const;
5556
};
5657

5758
} // Namespace

cdoc/Io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
namespace libcdoc {
2828

29-
class DataSource;
29+
struct DataSource;
3030

3131
/**
3232
* @brief The DataConsumer class

cdoc/Recipient.cpp

Lines changed: 50 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ Recipient::makeCertificate(std::string label, std::vector<uint8_t> cert)
8080
Recipient rcpt(Type::PUBLIC_KEY);
8181
rcpt.label = std::move(label);
8282
rcpt.cert = std::move(cert);
83-
Certificate ssl(rcpt.cert);
84-
rcpt.rcpt_key = ssl.getPublicKey();
85-
rcpt.pk_type = (ssl.getAlgorithm() == libcdoc::Certificate::RSA) ? PKType::RSA : PKType::ECC;
83+
Certificate x509(rcpt.cert);
84+
rcpt.rcpt_key = x509.getPublicKey();
85+
rcpt.pk_type = (x509.getAlgorithm() == libcdoc::Certificate::RSA) ? PKType::RSA : PKType::ECC;
86+
rcpt.expiry_ts = x509.getNotAfter();
8687
return rcpt;
8788
}
8889

@@ -138,26 +139,10 @@ Recipient::isTheSameRecipient(const std::vector<uint8_t>& public_key) const
138139
return rcpt_key == public_key;
139140
}
140141

141-
static std::string
142-
buildLabel(std::vector<std::pair<std::string_view, std::string_view>> components)
143-
{
144-
std::ostringstream ofs;
145-
ofs << LABELPREFIX;
146-
bool first = true;
147-
for (auto& [key, value] : components) {
148-
if (!value.empty()) {
149-
if (!first) ofs << '&';
150-
ofs << libcdoc::urlEncode(key) << '=' << libcdoc::urlEncode(value);
151-
first = false;
152-
}
153-
}
154-
return ofs.str();
155-
}
156-
157142
static Recipient::EIDType
158143
getEIDType(const std::vector<std::string>& policies)
159144
{
160-
for (std::vector<std::string>::const_reference policy : policies)
145+
for (const auto& policy : policies)
161146
{
162147
if (policy.starts_with("1.3.6.1.4.1.51361.1.1.3") ||
163148
policy.starts_with("1.3.6.1.4.1.51361.1.2.3")) {
@@ -181,113 +166,101 @@ getEIDType(const std::vector<std::string>& policies)
181166
return Recipient::EIDType::Unknown;
182167
}
183168

184-
static std::string
185-
BuildLabelEID(const std::vector<uint8_t>& cert)
169+
static void
170+
buildLabel(std::ostream& ofs, std::string_view type, const std::initializer_list<std::pair<std::string_view, std::string_view>> &components)
186171
{
187-
Certificate x509(cert);
188-
Recipient::EIDType type = getEIDType(x509.policies());
189-
std::string cn = x509.getCommonName();
190-
std::string sn = x509.getSerialNumber();
191-
std::string gn = x509.getGivenName();
192-
if (!gn.empty()) {
193-
return buildLabel({
194-
{"v", std::to_string(CDoc2::KEYLABELVERSION)},
195-
{"type", eid_strs[type]},
196-
{"cn", cn},
197-
{"serial_number", sn}
198-
});
199-
} else {
200-
return buildLabel({
201-
{"v", std::to_string(CDoc2::KEYLABELVERSION)},
202-
{"type", eid_strs[type]},
203-
{"cn", cn},
204-
{"serial_number", sn},
205-
{"last_name", x509.getSurname()},
206-
{"first_name", gn}
207-
});
172+
ofs << LABELPREFIX;
173+
ofs << "v" << '=' << std::to_string(CDoc2::KEYLABELVERSION) << '&'
174+
<< "type" << '=' << type;
175+
for (auto& [key, value] : components) {
176+
if (value.empty())
177+
continue;
178+
ofs << '&';
179+
ofs << libcdoc::urlEncode(key) << '=' << libcdoc::urlEncode(value);
208180
}
209181
}
210182

211-
static std::string
212-
BuildLabelCertificate(std::string_view file, const std::vector<uint8_t>& cert)
183+
static void
184+
BuildLabelEID(std::ostream& ofs, Recipient::EIDType type, const Certificate& x509)
213185
{
214-
Certificate x509(cert);
215-
return buildLabel({
216-
{"v", std::to_string(CDoc2::KEYLABELVERSION)},
217-
{"type", "cert"},
186+
buildLabel(ofs, eid_strs[type], {
187+
{"cn", x509.getCommonName()},
188+
{"serial_number", x509.getSerialNumber()},
189+
{"last_name", x509.getSurname()},
190+
{"first_name", x509.getGivenName()},
191+
});
192+
}
193+
194+
static void
195+
BuildLabelCertificate(std::ostream &ofs, std::string_view file, const Certificate& x509)
196+
{
197+
buildLabel(ofs, "cert", {
218198
{"file", file},
219199
{"cn", x509.getCommonName()},
220200
{"cert_sha1", toHex(x509.getDigest())}
221201
});
222202
}
223203

224-
static std::string
225-
BuildLabelPublicKey(int version, const std::string file)
204+
static void
205+
BuildLabelPublicKey(std::ostream &ofs, const std::string file)
226206
{
227-
return buildLabel({
228-
{"v", std::to_string(version)},
229-
{"type", "pub_key"},
207+
buildLabel(ofs, "pub_key", {
230208
{"file", file}
231209
});
232210
}
233211

234-
static std::string
235-
BuildLabelSymmetricKey(int version, const std::string& label, const std::string file)
212+
static void
213+
BuildLabelSymmetricKey(std::ostream &ofs, const std::string& label, const std::string file)
236214
{
237-
return buildLabel({
238-
{"v", std::to_string(version)},
239-
{"type", "secret"},
215+
buildLabel(ofs, "secret", {
240216
{"label", label},
241217
{"file", file}
242218
});
243219
}
244220

245-
static std::string
246-
BuildLabelPassword(int version, const std::string& label)
221+
static void
222+
BuildLabelPassword(std::ostream &ofs, const std::string& label)
247223
{
248-
return buildLabel({
249-
{"v", std::to_string(version)},
250-
{"type", "pw"},
224+
buildLabel(ofs, "pw", {
251225
{"label", label}
252226
});
253227
}
254228

255229
std::string
256-
Recipient::getLabel(std::vector<std::pair<std::string_view, std::string_view>> extra) const
230+
Recipient::getLabel(const std::vector<std::pair<std::string_view, std::string_view>> &extra) const
257231
{
258232
LOG_DBG("Generating label");
259233
if (!label.empty()) return label;
260234
std::ostringstream ofs;
261235
switch(type) {
262-
case NONE:
236+
case NONE:
263237
LOG_DBG("The recipient is not initialized");
264238
break;
265239
case SYMMETRIC_KEY:
266240
if (kdf_iter > 0) {
267-
ofs << BuildLabelPassword(CDoc2::KEYLABELVERSION, key_name);
241+
BuildLabelPassword(ofs, key_name);
268242
} else {
269-
ofs << BuildLabelSymmetricKey(CDoc2::KEYLABELVERSION, key_name, file_name);
243+
BuildLabelSymmetricKey(ofs, key_name, file_name);
270244
}
271245
case PUBLIC_KEY:
272246
if (!cert.empty()) {
273247
Certificate x509(cert);
274-
EIDType eid_type = getEIDType(x509.policies());
275-
if (eid_type != EIDType::Unknown) {
276-
ofs << BuildLabelEID(cert);
248+
if (auto type = getEIDType(x509.policies()); type != EIDType::Unknown) {
249+
BuildLabelEID(ofs, type, x509);
277250
} else {
278-
ofs << BuildLabelCertificate(file_name, cert);
251+
BuildLabelCertificate(ofs, file_name, x509);
279252
}
280253
} else {
281-
ofs << BuildLabelPublicKey(CDoc2::KEYLABELVERSION, file_name);
254+
BuildLabelPublicKey(ofs, file_name);
282255
}
283256
case KEYSHARE:
284257
break;
285258
}
286259
for (auto& [key, value] : extra) {
287-
if (!value.empty()) {
288-
ofs << '&';
289-
ofs << libcdoc::urlEncode(key) << '=' << libcdoc::urlEncode(value);
290-
}
260+
if (value.empty())
261+
continue;
262+
ofs << '&';
263+
ofs << libcdoc::urlEncode(key) << '=' << libcdoc::urlEncode(value);
291264
}
292265
LOG_DBG("Generated label: {}", ofs.str());
293266
return ofs.str();

cdoc/Recipient.h

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,6 @@ struct CDOC_EXPORT Recipient {
8080
DigiID_EResident
8181
};
8282

83-
/**
84-
* @brief Extra parameters for automatic label generation
85-
*/
86-
enum Params : unsigned char {
87-
/**
88-
* @brief Name of symmetric key/password ('label')
89-
*/
90-
LABEL,
91-
/**
92-
* @brief Public key or certificate filename ('file')
93-
*/
94-
FILE
95-
};
96-
9783
Recipient() = default;
9884

9985
/**
@@ -257,7 +243,7 @@ struct CDOC_EXPORT Recipient {
257243
* @param extra additional parameter values to use
258244
* @return a label value
259245
*/
260-
std::string getLabel(std::vector<std::pair<std::string_view, std::string_view>> extra) const;
246+
std::string getLabel(const std::vector<std::pair<std::string_view, std::string_view>> &extra) const;
261247

262248
/**
263249
* @brief parse machine-readable CDoc2 label

cdoc/Utils.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,13 @@ buildURL(const std::string& host, int port)
118118
return std::string("https://") + host + ":" + std::to_string(port) + "/";
119119
}
120120

121-
std::string
122-
urlEncode(std::string_view src)
121+
std::ostream&
122+
operator<<(std::ostream& escaped, urlEncode src)
123123
{
124-
std::ostringstream escaped;
125124
escaped.fill('0');
126125
escaped << std::hex;
127126

128-
for (auto c : src) {
127+
for (auto c : src.src) {
129128
// Keep alphanumeric and other accepted characters intact
130129
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
131130
escaped << c;
@@ -136,7 +135,7 @@ urlEncode(std::string_view src)
136135
escaped << '%' << std::setw(2) << int((unsigned char) c);
137136
escaped << std::nouppercase;
138137
}
139-
return escaped.str();
138+
return escaped;
140139
}
141140

142141
std::string

cdoc/Utils.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ readAllBytes(std::string_view filename)
118118
int parseURL(const std::string& url, std::string& host, int& port, std::string& path, bool end_with_slash = false);
119119
std::string buildURL(const std::string& host, int port);
120120

121-
std::string urlEncode(std::string_view src);
121+
struct urlEncode {
122+
std::string_view src;
123+
friend std::ostream& operator<<(std::ostream& escaped, urlEncode src);
124+
};
125+
122126
std::string urlDecode(const std::string &src);
123127

124128
} // namespace libcdoc

0 commit comments

Comments
 (0)