3232
3333using namespace libcdoc ;
3434
35+ #define RET_ERROR (F ) if (auto rv = F; rv != OK) return rv
36+
3537struct FileEntry {
3638 std::string name;
3739 size_t size;
@@ -53,7 +55,9 @@ class CDoc1Writer::Private
5355 static const XMLWriter::NS DENC, DS, XENC11, DSIG11;
5456 std::string method, documentFormat = " ENCDOC-XML|1.1" , lastError;
5557
56- bool writeRecipient (XMLWriter *xmlw, const std::vector<uint8_t > &recipient, const libcdoc::Crypto::Key& transportKey);
58+ uint64_t writeEncryptionProperties (bool use_ddoc);
59+ uint64_t writeKeyInfo (bool use_ddoc, const libcdoc::Crypto::Key& transportKey);
60+ uint64_t writeRecipient (const std::vector<uint8_t > &recipient, const libcdoc::Crypto::Key& transportKey);
5761};
5862
5963const XMLWriter::NS CDoc1Writer::Private::DENC{ " denc" , " http://www.w3.org/2001/04/xmlenc#" };
@@ -72,11 +76,48 @@ CDoc1Writer::~CDoc1Writer()
7276 delete d;
7377}
7478
75- bool CDoc1Writer::Private::writeRecipient (XMLWriter *xmlw, const std::vector<uint8_t > &recipient, const libcdoc::Crypto::Key& transportKey)
79+ uint64_t CDoc1Writer::Private::writeEncryptionProperties (bool use_ddoc)
80+ {
81+ RET_ERROR (_xml->writeElement (DENC, " EncryptionProperties" , [&]() -> uint64_t {
82+ RET_ERROR (_xml->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " LibraryVersion" }}, " cdoc|0.0.1" ));
83+ RET_ERROR (_xml->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " DocumentFormat" }}, documentFormat));
84+ RET_ERROR (_xml->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " Filename" }}, use_ddoc ? " tmp.ddoc" : files.at (0 ).name ));
85+ for (const FileEntry &file: files)
86+ {
87+ RET_ERROR (_xml->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " orig_file" }},
88+ file.name + " |" + std::to_string (file.size ) + " |" + " application/octet-stream" + " |D0" ));
89+ }
90+ return OK;
91+ }));
92+ return _xml->writeEndElement (Private::DENC); // EncryptedData
93+ }
94+
95+ uint64_t CDoc1Writer::Private::writeKeyInfo (bool use_ddoc, const libcdoc::Crypto::Key& transportKey)
96+ {
97+ RET_ERROR (_xml->writeStartElement (Private::DENC, " EncryptedData" , {{" MimeType" , use_ddoc ? " http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : " application/octet-stream" }}));
98+ RET_ERROR (_xml->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , method}}));
99+ return _xml->writeElement (Private::DS, " KeyInfo" , {}, [&]() -> uint64_t {
100+ for (const libcdoc::Recipient& key : rcpts) {
101+ if (!key.isCertificate ()) {
102+ lastError = " Invalid recipient type" ;
103+ LOG_ERROR (" {}" , lastError);
104+ return libcdoc::UNSPECIFIED_ERROR;
105+ }
106+ if (auto rv = writeRecipient (key.cert , transportKey); rv != OK) {
107+ lastError = " Failed to write Recipient info" ;
108+ LOG_ERROR (" {}" , lastError);
109+ return rv;
110+ }
111+ }
112+ return OK;
113+ });
114+ }
115+
116+ uint64_t CDoc1Writer::Private::writeRecipient (const std::vector<uint8_t > &recipient, const libcdoc::Crypto::Key& transportKey)
76117{
77118 auto peerCert = libcdoc::Crypto::toX509 (recipient);
78119 if (!peerCert)
79- return false ;
120+ return UNSPECIFIED_ERROR ;
80121 std::string cn = [&]{
81122 std::string cn;
82123 X509_NAME *name = X509_get_subject_name (peerCert.get ());
@@ -95,7 +136,7 @@ bool CDoc1Writer::Private::writeRecipient(XMLWriter *xmlw, const std::vector<uin
95136 OPENSSL_free (data);
96137 return cn;
97138 }();
98- xmlw ->writeElement (Private::DENC, " EncryptedKey" , {{" Recipient" , cn}}, [&]{
139+ return _xml ->writeElement (Private::DENC, " EncryptedKey" , {{" Recipient" , cn}}, [&]() -> uint64_t {
99140 std::vector<uint8_t > encryptedData;
100141 auto *peerPKey = X509_get0_pubkey (peerCert.get ());
101142 switch (EVP_PKEY_base_id (peerPKey))
@@ -106,12 +147,12 @@ bool CDoc1Writer::Private::writeRecipient(XMLWriter *xmlw, const std::vector<uin
106147 encryptedData.resize (size_t (RSA_size (rsa.get ())));
107148 RSA_public_encrypt (int (transportKey.key .size ()), transportKey.key .data (),
108149 encryptedData.data (), rsa.get (), RSA_PKCS1_PADDING);
109- xmlw ->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , libcdoc::Crypto::RSA_MTH}});
110- xmlw ->writeElement (Private::DS, " KeyInfo" , [&]{
111- xmlw ->writeElement (Private::DS, " X509Data" , [&]{
112- xmlw ->writeBase64Element (Private::DS, " X509Certificate" , recipient);
150+ RET_ERROR (_xml ->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , libcdoc::Crypto::RSA_MTH}}) );
151+ RET_ERROR (_xml ->writeElement (Private::DS, " KeyInfo" , [&]{
152+ return _xml ->writeElement (Private::DS, " X509Data" , [&]{
153+ return _xml ->writeBase64Element (Private::DS, " X509Certificate" , recipient);
113154 });
114- } );
155+ }) );
115156 break ;
116157 }
117158 case EVP_PKEY_EC:
@@ -147,41 +188,44 @@ bool CDoc1Writer::Private::writeRecipient(XMLWriter *xmlw, const std::vector<uin
147188 LOG_TRACE_KEY (" iv {}" , transportKey.iv );
148189 LOG_TRACE_KEY (" transport {}" , transportKey.key );
149190
150- xmlw ->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , encryptionMethod}});
151- xmlw ->writeElement (Private::DS, " KeyInfo" , [&]{
152- xmlw ->writeElement (Private::DENC, " AgreementMethod" , {{" Algorithm" , libcdoc::Crypto::AGREEMENT_MTH}}, [&]{
153- xmlw ->writeElement (Private::XENC11, " KeyDerivationMethod" , {{" Algorithm" , libcdoc::Crypto::CONCATKDF_MTH}}, [&]{
154- xmlw ->writeElement (Private::XENC11, " ConcatKDFParams" , {
191+ RET_ERROR (_xml ->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , encryptionMethod}}) );
192+ RET_ERROR (_xml ->writeElement (Private::DS, " KeyInfo" , [&]{
193+ return _xml ->writeElement (Private::DENC, " AgreementMethod" , {{" Algorithm" , libcdoc::Crypto::AGREEMENT_MTH}}, [&]{
194+ RET_ERROR (_xml ->writeElement (Private::XENC11, " KeyDerivationMethod" , {{" Algorithm" , libcdoc::Crypto::CONCATKDF_MTH}}, [&]{
195+ return _xml ->writeElement (Private::XENC11, " ConcatKDFParams" , {
155196 {" AlgorithmID" , " 00" + libcdoc::toHex (AlgorithmID)},
156197 {" PartyUInfo" , " 00" + libcdoc::toHex (SsDer)},
157198 {" PartyVInfo" , " 00" + libcdoc::toHex (recipient)}}, [&]{
158- xmlw ->writeElement (Private::DS, " DigestMethod" , {{" Algorithm" , concatDigest}});
199+ return _xml ->writeElement (Private::DS, " DigestMethod" , {{" Algorithm" , concatDigest}});
159200 });
160- } );
161- xmlw ->writeElement (Private::DENC, " OriginatorKeyInfo" , [&]{
162- xmlw ->writeElement (Private::DS, " KeyValue" , [&]{
163- xmlw ->writeElement (Private::DSIG11, " ECKeyValue" , [&]{
164- xmlw ->writeElement (Private::DSIG11, " NamedCurve" , {{" URI" , " urn:oid:" + oid}});
165- xmlw ->writeBase64Element (Private::DSIG11, " PublicKey" , SsDer);
201+ }) );
202+ RET_ERROR (_xml ->writeElement (Private::DENC, " OriginatorKeyInfo" , [&]{
203+ return _xml ->writeElement (Private::DS, " KeyValue" , [&]{
204+ return _xml ->writeElement (Private::DSIG11, " ECKeyValue" , [&]{
205+ RET_ERROR (_xml ->writeElement (Private::DSIG11, " NamedCurve" , {{" URI" , " urn:oid:" + oid}}) );
206+ return _xml ->writeBase64Element (Private::DSIG11, " PublicKey" , SsDer);
166207 });
167208 });
168- } );
169- xmlw ->writeElement (Private::DENC, " RecipientKeyInfo" , [&]{
170- xmlw ->writeElement (Private::DS, " X509Data" , [&]{
171- xmlw ->writeBase64Element (Private::DS, " X509Certificate" , recipient);
209+ }) );
210+ return _xml ->writeElement (Private::DENC, " RecipientKeyInfo" , [&]{
211+ return _xml ->writeElement (Private::DS, " X509Data" , [&]{
212+ return _xml ->writeBase64Element (Private::DS, " X509Certificate" , recipient);
172213 });
173214 });
174215 });
175- } );
216+ }) );
176217 break ;
177218 }
178- default : break ;
179- }
180- xmlw->writeElement (Private::DENC, " CipherData" , [&]{
181- xmlw->writeBase64Element (Private::DENC, " CipherValue" , encryptedData);
219+ default :
220+ return UNSPECIFIED_ERROR;
221+ }
222+
223+ if (encryptedData.empty ())
224+ return UNSPECIFIED_ERROR;
225+ return _xml->writeElement (Private::DENC, " CipherData" , [&]{
226+ return _xml->writeBase64Element (Private::DENC, " CipherValue" , encryptedData);
182227 });
183228 });
184- return true ;
185229}
186230
187231/* *
@@ -194,72 +238,44 @@ CDoc1Writer::encrypt(libcdoc::MultiDataSource& src, const std::vector<libcdoc::R
194238
195239 int n_components = src.getNumComponents ();
196240 bool use_ddoc = (n_components > 1 ) || (n_components == libcdoc::NOT_IMPLEMENTED);
241+ d->rcpts = keys;
197242
198243 d->_xml = std::make_unique<XMLWriter>(dst);
199- d->_xml ->writeStartElement (Private::DENC, " EncryptedData" , {{" MimeType" , use_ddoc ? " http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : " application/octet-stream" }});
200- d->_xml ->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , d->method }});
201- d->_xml ->writeStartElement (Private::DS, " KeyInfo" , {});
202- for (const libcdoc::Recipient& key : keys) {
203- if (!key.isCertificate ()) {
204- d->lastError = " Invalid recipient type" ;
205- LOG_ERROR (" {}" , d->lastError );
206- return libcdoc::UNSPECIFIED_ERROR;
207- }
208- if (!d->writeRecipient (d->_xml .get (), key.cert , transportKey)) {
209- d->lastError = " Failed to write Recipient info" ;
210- LOG_ERROR (" {}" , d->lastError );
211- return libcdoc::IO_ERROR;
212- }
213- }
214- d->_xml ->writeEndElement (Private::DS); // KeyInfo
244+ RET_ERROR (d->writeKeyInfo (use_ddoc, transportKey));
215245
216- std::vector<FileEntry> files;
217- int64_t result = libcdoc::OK;
218- d->_xml ->writeElement (Private::DENC, " CipherData" , [&]() -> void {
246+ RET_ERROR (d->_xml ->writeElement (Private::DENC, " CipherData" , [&]() -> uint64_t {
219247 std::vector<uint8_t > data;
220248 if (use_ddoc) {
221249 data.reserve (16384 );
222250 DDOCWriter ddoc (data);
223251 std::string name;
224252 int64_t size;
225- result = src.next (name, size);
226- while (result == libcdoc::OK) {
253+ for (auto result = src.next (name, size); result == libcdoc::OK; result = src.next (name, size)) {
227254 std::vector<uint8_t > contents;
228255 libcdoc::VectorConsumer vcons (contents);
229- result = src.readAll (vcons);
230- if (result < 0 ) return ;
231- files.push_back ({name, (size_t ) result});
232- ddoc.addFile (name, " application/octet-stream" , contents);
233- result = src. next (name, size) ;
256+ if ( src.readAll (vcons) < 0 )
257+ return IO_ERROR ;
258+ d-> files .push_back ({name, (size_t ) result});
259+ if ( auto rv = ddoc.addFile (name, " application/octet-stream" , contents); rv != OK)
260+ return rv ;
234261 }
235262 } else {
236263 std::string name;
237264 int64_t size;
238- result = src.next (name, size);
239- if (result < 0 ) return ;
265+ if ( src.next (name, size) < 0 )
266+ return IO_ERROR ;
240267 libcdoc::VectorConsumer vcons (data);
241- result = src.readAll (vcons);
242- if (result < 0 ) return ;
243- files.push_back ({std::move (name), (size_t ) result});
268+ auto result = src.readAll (vcons);
269+ if (result < 0 )
270+ return IO_ERROR;
271+ d->files .push_back ({std::move (name), (size_t ) result});
244272 }
245- d->_xml ->writeBase64Element (Private::DENC, " CipherValue" , libcdoc::Crypto::encrypt (d->method , transportKey, data));
246- });
247- if (result < 0 ) return result;
248- d->_xml ->writeElement (Private::DENC, " EncryptionProperties" , [&]{
249- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " LibraryVersion" }}, " cdoc|0.0.1" );
250- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " DocumentFormat" }}, d->documentFormat );
251- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " Filename" }}, files.size () == 1 ? files.at (0 ).name : " tmp.ddoc" );
252- for (const FileEntry &file: files)
253- {
254- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " orig_file" }},
255- file.name + " |" + std::to_string (file.size ) + " |" + " application/octet-stream" + " |D0" );
256- }
257- });
258- d->_xml ->writeEndElement (Private::DENC); // EncryptedData
273+ return d->_xml ->writeBase64Element (Private::DENC, " CipherValue" , libcdoc::Crypto::encrypt (d->method , transportKey, data));
274+ }));
275+ RET_ERROR (d->writeEncryptionProperties (use_ddoc));
259276 d->_xml .reset ();
260- result = libcdoc::OK;
261- if (owned) result = dst->close ();
262- return result;
277+ if (owned) return dst->close ();
278+ return OK;
263279}
264280
265281libcdoc::result_t
@@ -301,48 +317,20 @@ CDoc1Writer::finishEncryption()
301317
302318 libcdoc::Crypto::Key transportKey = libcdoc::Crypto::generateKey (d->method );
303319
304- d->_xml ->writeStartElement (Private::DENC, " EncryptedData" , {{" MimeType" , use_ddoc ? " http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : " application/octet-stream" }});
305- d->_xml ->writeElement (Private::DENC, " EncryptionMethod" , {{" Algorithm" , d->method }});
306- d->_xml ->writeStartElement (Private::DS, " KeyInfo" , {});
307- for (const libcdoc::Recipient& key : d->rcpts ) {
308- if (!key.isCertificate ()) {
309- d->lastError = " Invalid recipient type" ;
310- LOG_ERROR (" {}" , d->lastError );
311- return libcdoc::UNSPECIFIED_ERROR;
312- }
313- if (!d->writeRecipient (d->_xml .get (), key.cert , transportKey)) {
314- d->lastError = " Failed to write Recipient info" ;
315- LOG_ERROR (" {}" , d->lastError );
316- return libcdoc::IO_ERROR;
317- }
318- }
319- d->_xml ->writeEndElement (Private::DS); // KeyInfo
320-
321- d->_xml ->writeElement (Private::DENC, " CipherData" , [&]{
322- if (use_ddoc) {
323- std::vector<uint8_t > data;
324- data.reserve (4096 );
325- for (DDOCWriter ddoc (data); const FileEntry& file : d->files ) {
326- std::vector<uint8_t > contents;
327- ddoc.addFile (file.name , " application/octet-stream" , file.data );
328- }
329- d->_xml ->writeBase64Element (Private::DENC, " CipherValue" , libcdoc::Crypto::encrypt (d->method , transportKey, data));
330- } else {
331- d->_xml ->writeBase64Element (Private::DENC, " CipherValue" , libcdoc::Crypto::encrypt (d->method , transportKey, d->files .back ().data ));
332- }
333- });
334- d->_xml ->writeElement (Private::DENC, " EncryptionProperties" , [&]{
335- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " LibraryVersion" }}, " cdoc|0.0.1" );
336- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " DocumentFormat" }}, d->documentFormat );
337- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " Filename" }}, use_ddoc ? " tmp.ddoc" : d->files .at (0 ).name );
338- for (const FileEntry &file: d->files )
339- {
340- d->_xml ->writeTextElement (Private::DENC, " EncryptionProperty" , {{" Name" , " orig_file" }},
341- file.name + " |" + std::to_string (file.size ) + " |" + " application/octet-stream" + " |D0" );
342- }
343- });
344- d->_xml ->writeEndElement (Private::DENC); // EncryptedData
320+ RET_ERROR (d->writeKeyInfo (use_ddoc, transportKey));
321+ RET_ERROR (d->_xml ->writeElement (Private::DENC, " CipherData" , [&]{
322+ if (!use_ddoc)
323+ return d->_xml ->writeBase64Element (Private::DENC, " CipherValue" , libcdoc::Crypto::encrypt (d->method , transportKey, d->files .back ().data ));
324+ std::vector<uint8_t > data;
325+ data.reserve (4096 );
326+ for (DDOCWriter ddoc (data); const FileEntry& file : d->files ) {
327+ std::vector<uint8_t > contents;
328+ ddoc.addFile (file.name , " application/octet-stream" , file.data );
329+ }
330+ return d->_xml ->writeBase64Element (Private::DENC, " CipherValue" , libcdoc::Crypto::encrypt (d->method , transportKey, data));
331+ }));
332+ RET_ERROR (d->writeEncryptionProperties (use_ddoc));
345333 d->_xml .reset ();
346- if (owned) dst->close ();
334+ if (owned) return dst->close ();
347335 return libcdoc::OK;
348336}
0 commit comments