Skip to content

Commit 8309182

Browse files
authored
Merge branch 'open-eid:master' into master
2 parents 5b32d9f + 7f658d2 commit 8309182

File tree

15 files changed

+274
-285
lines changed

15 files changed

+274
-285
lines changed

cdoc/CDoc1Writer.cpp

Lines changed: 103 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ using namespace libcdoc;
3232

3333
#define RET_ERROR(F) if (auto rv = F; rv < 0) return rv
3434

35+
constexpr XMLWriter::NS DENC{ "denc", "http://www.w3.org/2001/04/xmlenc#" };
36+
constexpr XMLWriter::NS DS{ "ds", "http://www.w3.org/2000/09/xmldsig#" };
37+
constexpr XMLWriter::NS XENC11{ "xenc11", "http://www.w3.org/2009/xmlenc11#" };
38+
constexpr XMLWriter::NS DSIG11{ "dsig11", "http://www.w3.org/2009/xmldsig11#" };
39+
3540
struct FileEntry {
3641
std::string name;
3742
size_t size;
@@ -45,8 +50,6 @@ struct FileEntry {
4550

4651
struct CDoc1Writer::Private final: public XMLWriter
4752
{
48-
static const XMLWriter::NS DENC, DS, XENC11, DSIG11;
49-
5053
Private(DataConsumer &dst, std::string &last_error)
5154
: XMLWriter(dst)
5255
, lastError(last_error)
@@ -57,57 +60,60 @@ struct CDoc1Writer::Private final: public XMLWriter
5760
std::string &lastError;
5861
std::vector<FileEntry> files;
5962

60-
int64_t writeEncryptionProperties(bool use_ddoc);
61-
int64_t writeKeyInfo(bool use_ddoc, const std::vector<Recipient> &rcpts, const Crypto::Key& transportKey);
63+
int64_t writeDocument(bool use_ddoc, const std::vector<Recipient> &rcpts, const std::function<int64_t(DataConsumer&)> &f);
6264
int64_t writeRecipient(const std::vector<uint8_t> &recipient, const Crypto::Key& transportKey);
6365
};
6466

65-
const XMLWriter::NS CDoc1Writer::Private::DENC{ "denc", "http://www.w3.org/2001/04/xmlenc#" };
66-
const XMLWriter::NS CDoc1Writer::Private::DS{ "ds", "http://www.w3.org/2000/09/xmldsig#" };
67-
const XMLWriter::NS CDoc1Writer::Private::XENC11{ "xenc11", "http://www.w3.org/2009/xmlenc11#" };
68-
const XMLWriter::NS CDoc1Writer::Private::DSIG11{ "dsig11", "http://www.w3.org/2009/xmldsig11#" };
69-
7067
CDoc1Writer::CDoc1Writer(DataConsumer *dst, bool take_ownership)
7168
: CDocWriter(1, dst, take_ownership)
7269
{}
7370

7471
CDoc1Writer::~CDoc1Writer() noexcept = default;
7572

76-
int64_t CDoc1Writer::Private::writeEncryptionProperties(bool use_ddoc)
73+
int64_t CDoc1Writer::Private::writeDocument(bool use_ddoc, const std::vector<Recipient> &rcpts, const std::function<int64_t(DataConsumer&)> &f)
7774
{
78-
RET_ERROR(writeElement(DENC, "EncryptionProperties", [&]() -> int64_t {
79-
RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "LibraryVersion"}}, "cdoc|0.0.1"));
80-
RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "DocumentFormat"}}, documentFormat));
81-
RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "Filename"}}, use_ddoc ? "tmp.ddoc" : files.at(0).name));
82-
for(const FileEntry &file: files)
83-
{
84-
RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "orig_file"}},
85-
file.name + "|" + std::to_string(file.size) + "|" + "application/octet-stream" + "|D0"));
75+
return writeElement(DENC, "EncryptedData",
76+
{{"MimeType", use_ddoc ? "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : "application/octet-stream"}}, [&] -> int64_t {
77+
RET_ERROR(writeElement(DENC, "EncryptionMethod", {{"Algorithm", method}}));
78+
libcdoc::Crypto::Key transportKey = libcdoc::Crypto::generateKey(method);
79+
if (transportKey.key.empty()) {
80+
lastError = "Failed to generate transport key";
81+
LOG_ERROR("{}", lastError);
82+
return CRYPTO_ERROR;
8683
}
87-
return OK;
88-
}));
89-
return writeEndElement(Private::DENC); // EncryptedData
90-
}
91-
92-
int64_t CDoc1Writer::Private::writeKeyInfo(bool use_ddoc, const std::vector<Recipient> &rcpts, const Crypto::Key& transportKey)
93-
{
94-
RET_ERROR(writeStartElement(Private::DENC, "EncryptedData",
95-
{{"MimeType", use_ddoc ? "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : "application/octet-stream"}}));
96-
RET_ERROR(writeElement(Private::DENC, "EncryptionMethod", {{"Algorithm", method}}));
97-
return writeElement(Private::DS, "KeyInfo", {}, [&]() -> int64_t {
98-
for (const Recipient& key : rcpts) {
99-
if (!key.isCertificate()) {
100-
lastError = "Invalid recipient type";
101-
LOG_ERROR("{}", lastError);
102-
return UNSPECIFIED_ERROR;
84+
RET_ERROR(writeElement(DS, "KeyInfo", {}, [&] -> int64_t {
85+
for (const Recipient& key : rcpts) {
86+
if (!key.isCertificate()) {
87+
lastError = "Invalid recipient type";
88+
LOG_ERROR("{}", lastError);
89+
return UNSPECIFIED_ERROR;
90+
}
91+
if(auto rv = writeRecipient(key.cert, transportKey); rv < 0) {
92+
lastError = "Failed to write Recipient info";
93+
LOG_ERROR("{}", lastError);
94+
return rv;
95+
}
10396
}
104-
if(auto rv = writeRecipient(key.cert, transportKey); rv < 0) {
105-
lastError = "Failed to write Recipient info";
106-
LOG_ERROR("{}", lastError);
107-
return rv;
97+
return OK;
98+
}));
99+
RET_ERROR(writeElement(DENC, "CipherData", [&] {
100+
return writeBase64Element(DENC, "CipherValue", [&](DataConsumer &dst) -> int64_t {
101+
EncryptionConsumer enc(dst, method, transportKey);
102+
RET_ERROR(f(enc));
103+
return enc.close();
104+
});
105+
}));
106+
return writeElement(DENC, "EncryptionProperties", [&] -> int64_t {
107+
RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "LibraryVersion"}}, "cdoc|0.0.1"));
108+
RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "DocumentFormat"}}, documentFormat));
109+
RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "Filename"}}, use_ddoc ? "tmp.ddoc" : files.at(0).name));
110+
for(const FileEntry &file: files)
111+
{
112+
RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "orig_file"}},
113+
file.name + "|" + std::to_string(file.size) + "|" + "application/octet-stream" + "|D0"));
108114
}
109-
}
110-
return OK;
115+
return OK;
116+
});
111117
});
112118
}
113119

@@ -134,18 +140,18 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector<uint8_t> &recipie
134140
OPENSSL_free(data);
135141
return cn;
136142
}();
137-
return writeElement(Private::DENC, "EncryptedKey", {{"Recipient", cn}}, [&]() -> int64_t {
143+
return writeElement(DENC, "EncryptedKey", {{"Recipient", cn}}, [&] -> int64_t {
138144
std::vector<uint8_t> encryptedData;
139145
auto *peerPKey = X509_get0_pubkey(peerCert.get());
140146
switch(EVP_PKEY_base_id(peerPKey))
141147
{
142148
case EVP_PKEY_RSA:
143149
{
144150
encryptedData = Crypto::encrypt(peerPKey, RSA_PKCS1_PADDING, transportKey.key);
145-
RET_ERROR(writeElement(Private::DENC, "EncryptionMethod", {{"Algorithm", Crypto::RSA_MTH}}));
146-
RET_ERROR(writeElement(Private::DS, "KeyInfo", [&] {
147-
return writeElement(Private::DS, "X509Data", [&] {
148-
return writeBase64Element(Private::DS, "X509Certificate", recipient);
151+
RET_ERROR(writeElement(DENC, "EncryptionMethod", {{"Algorithm", Crypto::RSA_MTH}}));
152+
RET_ERROR(writeElement(DS, "KeyInfo", [&] {
153+
return writeElement(DS, "X509Data", [&] {
154+
return writeBase64Element(DS, "X509Certificate", recipient);
149155
});
150156
}));
151157
break;
@@ -183,28 +189,28 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector<uint8_t> &recipie
183189
LOG_TRACE_KEY("iv {}", transportKey.iv);
184190
LOG_TRACE_KEY("transport {}", transportKey.key);
185191

186-
RET_ERROR(writeElement(Private::DENC, "EncryptionMethod", {{"Algorithm", encryptionMethod}}));
187-
RET_ERROR(writeElement(Private::DS, "KeyInfo", [&] {
188-
return writeElement(Private::DENC, "AgreementMethod", {{"Algorithm", Crypto::AGREEMENT_MTH}}, [&] {
189-
RET_ERROR(writeElement(Private::XENC11, "KeyDerivationMethod", {{"Algorithm", Crypto::CONCATKDF_MTH}}, [&] {
190-
return writeElement(Private::XENC11, "ConcatKDFParams", {
192+
RET_ERROR(writeElement(DENC, "EncryptionMethod", {{"Algorithm", encryptionMethod}}));
193+
RET_ERROR(writeElement(DS, "KeyInfo", [&] {
194+
return writeElement(DENC, "AgreementMethod", {{"Algorithm", Crypto::AGREEMENT_MTH}}, [&] {
195+
RET_ERROR(writeElement(XENC11, "KeyDerivationMethod", {{"Algorithm", Crypto::CONCATKDF_MTH}}, [&] {
196+
return writeElement(XENC11, "ConcatKDFParams", {
191197
{"AlgorithmID", "00" + toHex(AlgorithmID)},
192198
{"PartyUInfo", "00" + toHex(SsDer)},
193199
{"PartyVInfo", "00" + toHex(recipient)}}, [&] {
194-
return writeElement(Private::DS, "DigestMethod", {{"Algorithm", concatDigest}});
200+
return writeElement(DS, "DigestMethod", {{"Algorithm", concatDigest}});
195201
});
196202
}));
197-
RET_ERROR(writeElement(Private::DENC, "OriginatorKeyInfo", [&] {
198-
return writeElement(Private::DS, "KeyValue", [&] {
199-
return writeElement(Private::DSIG11, "ECKeyValue", [&] {
200-
RET_ERROR(writeElement(Private::DSIG11, "NamedCurve", {{"URI", "urn:oid:" + oid}}));
201-
return writeBase64Element(Private::DSIG11, "PublicKey", SsDer);
203+
RET_ERROR(writeElement(DENC, "OriginatorKeyInfo", [&] {
204+
return writeElement(DS, "KeyValue", [&] {
205+
return writeElement(DSIG11, "ECKeyValue", [&] {
206+
RET_ERROR(writeElement(DSIG11, "NamedCurve", {{"URI", "urn:oid:" + oid}}));
207+
return writeBase64Element(DSIG11, "PublicKey", SsDer);
202208
});
203209
});
204210
}));
205-
return writeElement(Private::DENC, "RecipientKeyInfo", [&] {
206-
return writeElement(Private::DS, "X509Data", [&] {
207-
return writeBase64Element(Private::DS, "X509Certificate", recipient);
211+
return writeElement(DENC, "RecipientKeyInfo", [&] {
212+
return writeElement(DS, "X509Data", [&] {
213+
return writeBase64Element(DS, "X509Certificate", recipient);
208214
});
209215
});
210216
});
@@ -217,8 +223,8 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector<uint8_t> &recipie
217223

218224
if (encryptedData.empty())
219225
return UNSPECIFIED_ERROR;
220-
return writeElement(Private::DENC, "CipherData", [&] {
221-
return writeBase64Element(Private::DENC, "CipherValue", encryptedData);
226+
return writeElement(DENC, "CipherData", [&] {
227+
return writeBase64Element(DENC, "CipherValue", encryptedData);
222228
});
223229
});
224230
}
@@ -231,38 +237,31 @@ CDoc1Writer::encrypt(libcdoc::MultiDataSource& src, const std::vector<libcdoc::R
231237
{
232238
if(keys.empty())
233239
return WORKFLOW_ERROR;
234-
RET_ERROR(beginEncryption());
235240
rcpts = keys;
236-
Crypto::Key transportKey = Crypto::generateKey(d->method);
241+
RET_ERROR(beginEncryption());
237242
int n_components = src.getNumComponents();
238243
bool use_ddoc = (n_components > 1) || (n_components == libcdoc::NOT_IMPLEMENTED);
239-
240-
RET_ERROR(d->writeKeyInfo(use_ddoc, keys, transportKey));
241-
RET_ERROR(d->writeElement(Private::DENC, "CipherData", [&] {
242-
return d->writeBase64Element(Private::DENC, "CipherValue", [&](DataConsumer &dst) -> int64_t {
243-
EncryptionConsumer enc(dst, d->method, transportKey);
244-
std::string name;
245-
int64_t size;
246-
if(use_ddoc) {
247-
DDOCWriter ddoc(enc);
248-
result_t result;
249-
for (result = src.next(name, size); result == OK; result = src.next(name, size)) {
250-
RET_ERROR(ddoc.addFile(name, "application/octet-stream", size, src));
251-
d->files.push_back({name, size_t(size)});
252-
}
253-
if(result != END_OF_STREAM)
254-
return result;
255-
} else {
256-
RET_ERROR(src.next(name, size));
257-
if(auto rv = src.readAll(enc); rv >= 0)
258-
d->files.push_back({std::move(name), size_t(rv)});
259-
else
260-
return rv;
244+
RET_ERROR(d->writeDocument(use_ddoc, keys, [&](DataConsumer &dst) -> int64_t {
245+
std::string name;
246+
int64_t size;
247+
if(use_ddoc) {
248+
DDOCWriter ddoc(dst);
249+
result_t result;
250+
for (result = src.next(name, size); result == OK; result = src.next(name, size)) {
251+
RET_ERROR(ddoc.addFile(name, "application/octet-stream", size, src));
252+
d->files.push_back({name, size_t(size)});
261253
}
262-
return enc.close();
263-
});
254+
if(result != END_OF_STREAM)
255+
return result;
256+
} else {
257+
RET_ERROR(src.next(name, size));
258+
if(auto rv = src.readAll(dst); rv >= 0)
259+
d->files.push_back({std::move(name), size_t(rv)});
260+
else
261+
return rv;
262+
}
263+
return OK;
264264
}));
265-
RET_ERROR(d->writeEncryptionProperties(use_ddoc));
266265
d.reset();
267266
if (owned) return dst->close();
268267
return OK;
@@ -271,8 +270,16 @@ CDoc1Writer::encrypt(libcdoc::MultiDataSource& src, const std::vector<libcdoc::R
271270
libcdoc::result_t
272271
CDoc1Writer::beginEncryption()
273272
{
274-
if(d)
273+
if(rcpts.empty()) {
274+
setLastError("No recipients added");
275+
LOG_ERROR("{}", last_error);
276+
return WORKFLOW_ERROR;
277+
}
278+
if(d) {
279+
setLastError("Encryption already started");
280+
LOG_ERROR("{}", last_error);
275281
return WORKFLOW_ERROR;
282+
}
276283
d = std::make_unique<Private>(*dst, last_error);
277284
return libcdoc::OK;
278285
}
@@ -308,26 +315,16 @@ CDoc1Writer::writeData(const uint8_t *src, size_t size)
308315
libcdoc::result_t
309316
CDoc1Writer::finishEncryption()
310317
{
311-
if(!d || rcpts.empty() || d->files.empty())
318+
if(!d || d->files.empty())
312319
return WORKFLOW_ERROR;
313320
bool use_ddoc = d->files.size() > 1;
314-
libcdoc::Crypto::Key transportKey = libcdoc::Crypto::generateKey(d->method);
315-
316-
RET_ERROR(d->writeKeyInfo(use_ddoc, rcpts, transportKey));
317-
RET_ERROR(d->writeElement(Private::DENC, "CipherData", [&] {
318-
return d->writeBase64Element(Private::DENC, "CipherValue", [&](DataConsumer &dst) -> int64_t {
319-
EncryptionConsumer enc(dst, d->method, transportKey);
320-
if(use_ddoc)
321-
{
322-
for(DDOCWriter ddoc(enc); const FileEntry& file : d->files)
323-
RET_ERROR(ddoc.addFile(file.name, "application/octet-stream", file.data));
324-
}
325-
else
326-
RET_ERROR(VectorSource(d->files.back().data).readAll(enc));
327-
return enc.close();
328-
});
321+
RET_ERROR(d->writeDocument(use_ddoc, rcpts, [&, this](DataConsumer &dst) -> int64_t {
322+
if(!use_ddoc)
323+
return VectorSource(d->files.back().data).readAll(dst);
324+
for(DDOCWriter ddoc(dst); const FileEntry& file : d->files)
325+
RET_ERROR(ddoc.addFile(file.name, "application/octet-stream", file.data));
326+
return OK;
329327
}));
330-
RET_ERROR(d->writeEncryptionProperties(use_ddoc));
331328
d.reset();
332329
if (owned) return dst->close();
333330
return libcdoc::OK;

cdoc/Crypto.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ EncryptionConsumer::EncryptionConsumer(DataConsumer &dst, const EVP_CIPHER *ciph
449449
}
450450

451451
result_t
452-
EncryptionConsumer::write(const uint8_t *src, size_t size)
452+
EncryptionConsumer::write(const uint8_t *src, size_t size) noexcept try
453453
{
454454
if(!src || size == 0)
455455
return OK;
@@ -460,10 +460,12 @@ EncryptionConsumer::write(const uint8_t *src, size_t size)
460460
if(SSL_FAILED(EVP_CipherUpdate(ctx.get(), buf.data(), &len, src, int(size)), "EVP_CipherUpdate"))
461461
return CRYPTO_ERROR;
462462
return dst.write(buf.data(), size_t(len));
463+
} catch(...) {
464+
return OUTPUT_STREAM_ERROR;
463465
}
464466

465467
result_t
466-
EncryptionConsumer::writeAAD(const std::vector<uint8_t> &data)
468+
EncryptionConsumer::writeAAD(const std::vector<uint8_t> &data) noexcept
467469
{
468470
int len = 0;
469471
if(SSL_FAILED(EVP_CipherUpdate(ctx.get(), nullptr, &len, data.data(), int(data.size())), "EVP_CipherUpdate"))
@@ -472,7 +474,7 @@ EncryptionConsumer::writeAAD(const std::vector<uint8_t> &data)
472474
}
473475

474476
result_t
475-
EncryptionConsumer::close()
477+
EncryptionConsumer::close() noexcept try
476478
{
477479
buf.resize(std::max<size_t>(buf.size(), size_t(EVP_CIPHER_CTX_block_size(ctx.get()))));
478480
int len = int(buf.size());
@@ -498,6 +500,8 @@ EncryptionConsumer::close()
498500
return IO_ERROR;
499501
}
500502
return OK;
503+
} catch(...) {
504+
return OUTPUT_STREAM_ERROR;
501505
}
502506

503507
DecryptionSource::DecryptionSource(DataSource &src, const std::string &method, const std::vector<unsigned char> &key, size_t ivLen)
@@ -531,7 +535,7 @@ result_t DecryptionSource::updateAAD(const std::vector<uint8_t> &data)
531535
return OK;
532536
}
533537

534-
result_t DecryptionSource::read(unsigned char *dst, size_t size)
538+
result_t DecryptionSource::read(unsigned char *dst, size_t size) noexcept
535539
{
536540
if (error != OK)
537541
return error;

cdoc/Crypto.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ struct EncryptionConsumer final : public DataConsumer {
114114
EncryptionConsumer(DataConsumer &dst, const std::string &method, const Crypto::Key &key);
115115
EncryptionConsumer(DataConsumer &dst, const EVP_CIPHER *cipher, const Crypto::Key &key);
116116
CDOC_DISABLE_MOVE_COPY(EncryptionConsumer)
117-
result_t write(const uint8_t *src, size_t size) final;
118-
result_t writeAAD(const std::vector<uint8_t> &data);
119-
result_t close() final;
120-
bool isError() final { return error != OK || dst.isError(); }
117+
result_t write(const uint8_t *src, size_t size) noexcept final;
118+
result_t writeAAD(const std::vector<uint8_t> &data) noexcept;
119+
result_t close() noexcept final;
120+
bool isError() noexcept final { return error != OK || dst.isError(); }
121121

122122
private:
123123
unique_free_t<EVP_CIPHER_CTX> ctx;
@@ -131,11 +131,11 @@ struct DecryptionSource final : public DataSource {
131131
DecryptionSource(DataSource &src, const EVP_CIPHER *cipher, const std::vector<unsigned char> &key, size_t ivLen = 0);
132132
CDOC_DISABLE_MOVE_COPY(DecryptionSource)
133133

134-
result_t read(unsigned char* dst, size_t size) final;
134+
result_t read(unsigned char* dst, size_t size) noexcept final;
135135
result_t updateAAD(const std::vector<uint8_t>& data);
136136
result_t close();
137-
bool isError() final { return error != OK || src.isError(); }
138-
bool isEof() final { return src.isEof(); }
137+
bool isError() noexcept final { return error != OK || src.isError(); }
138+
bool isEof() noexcept final { return src.isEof(); }
139139

140140
private:
141141
unique_free_t<EVP_CIPHER_CTX> ctx;

0 commit comments

Comments
 (0)