diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 27f5a21..31d46dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -74,6 +74,7 @@ jobs: env: VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/vcpkg_cache,readwrite VCPKG_DEFAULT_TRIPLET: ${{ matrix.triplet }} + VCPKG_INSTALLED_DIR: ${{ github.workspace }}/build/${{ matrix.target }}/vcpkg_installed - name: Build run: | cmake --preset ${{ matrix.target }} "-GUnix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=libcdoc.${{ matrix.target }} @@ -120,6 +121,7 @@ jobs: env: VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/vcpkg_cache,readwrite VCPKG_DEFAULT_TRIPLET: ${{ matrix.triplet }} + VCPKG_INSTALLED_DIR: ${{ github.workspace }}/build/${{ matrix.target }}/vcpkg_installed - name: Build run: | cmake --preset ${{ matrix.target }} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=${{ env.DEST }} @@ -175,7 +177,7 @@ jobs: "-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake" ` "-DSWIG_EXECUTABLE=$swig" ` -DVCPKG_TARGET_TRIPLET=${{ env.VCPKG_DEFAULT_TRIPLET }} ` - -DVCPKG_MANIFEST_FEATURES=tests ` + ${{ matrix.platform == 'x64' && '-DVCPKG_MANIFEST_FEATURES=tests' || '' }} ` -DCMAKE_INSTALL_LIBDIR=bin cmake --build build --config RelWithDebInfo ctest -V -C RelWithDebInfo --test-dir build diff --git a/cdoc/CDoc1Reader.cpp b/cdoc/CDoc1Reader.cpp index 6f27222..3d9be2c 100644 --- a/cdoc/CDoc1Reader.cpp +++ b/cdoc/CDoc1Reader.cpp @@ -171,53 +171,54 @@ CDoc1Reader::decrypt(const std::vector& fmk, libcdoc::MultiDataConsumer result = finishDecryption(); return result; #else - std::string mime; - std::vector data; - if (auto result = CDoc1Reader::decryptData(fmk, mime, data); result != OK) { - return result; - } - libcdoc::VectorSource vsrc(data); - if(mime == MIME_DDOC || mime == MIME_DDOC_OLD) { - LOG_DBG("Contains DDoc content {}", mime); - auto result = DDOCReader::parse(&vsrc, dst); - if (result != libcdoc::OK) { - setLastError("Failed to parse DDOC file"); - LOG_ERROR("{}", last_error); + return CDoc1Reader::decryptData(fmk, [&](DataSource &src, const std::string &mime) -> result_t { + if(mime == MIME_DDOC || mime == MIME_DDOC_OLD) { + LOG_DBG("Contains DDoc content {}", mime); + auto rv = DDOCReader(&src).parse(dst); + if (rv != libcdoc::OK) { + setLastError("Failed to parse DDOC file"); + LOG_ERROR("{}", last_error); + } + return rv; } - return result; - } - dst->open(d->properties["Filename"], data.size()); - dst->writeAll(vsrc); - dst->close(); - return libcdoc::OK; + if(auto rv = dst->open(d->properties["Filename"], -1/*data.size()*/); rv != OK) + return rv; + if(auto rv = dst->writeAll(src); rv < OK) + return rv; + return dst->close(); + }); #endif } libcdoc::result_t CDoc1Reader::beginDecryption(const std::vector& fmk) { - std::string mime; - std::vector data; - if (auto result = CDoc1Reader::decryptData(fmk, mime, data); result != OK) { - return result; - } - if(mime == MIME_DDOC || mime == MIME_DDOC_OLD) { - LOG_DBG("Contains DDoc content {}", mime); - d->files = DDOCReader::files(data); - } else { + setLastError({}); + return CDoc1Reader::decryptData(fmk, [&](DataSource &src, const std::string &mime) -> result_t { + if(mime == MIME_DDOC || mime == MIME_DDOC_OLD) { + LOG_DBG("Contains DDoc content {}", mime); + auto rv = DDOCReader(&src).files(d->files); + if (rv != libcdoc::OK) { + setLastError("Failed to parse DDOC file"); + LOG_ERROR("{}", last_error); + d->files.clear(); + } + return rv; + } + std::vector data; + VectorConsumer vsrc(data); + if(auto rv = vsrc.writeAll(src); rv < OK) { + setLastError("Cannot parse container"); + LOG_ERROR("{}", last_error); + return rv; + } d->files.push_back({ d->properties["Filename"], "application/octet-stream", std::move(data) }); - } - if (d->files.empty()) { - setLastError("Cannot parse container"); - LOG_ERROR("{}", last_error); - return libcdoc::IO_ERROR; - } - setLastError({}); - return libcdoc::OK; + return OK; + }); } libcdoc::result_t @@ -361,10 +362,10 @@ CDoc1Reader::isCDoc1File(libcdoc::DataSource *src) /* * Returns decrypted data * @param key Transport key to used for decrypt data - * @param mime decrypted mime type - * @param data decrypted data + * @param f callback with DataSource and mime data */ -result_t CDoc1Reader::decryptData(const std::vector& fmk, std::string& mime, std::vector& data) +result_t CDoc1Reader::decryptData(const std::vector& fmk, + const std::function& f) { if (fmk.empty()) { setLastError("FMK is missing"); @@ -413,16 +414,14 @@ result_t CDoc1Reader::decryptData(const std::vector& fmk, std::string& setLastError("Failed to decrypt data, verify if FMK is correct"); return CRYPTO_ERROR; } - libcdoc::VectorConsumer out(data); setLastError({}); + if (d->mime == MIME_ZLIB) { libcdoc::ZSource zsrc(&dec); - out.writeAll(zsrc); - mime = d->properties["OriginalMimeType"]; - } - else { - mime = d->mime; - out.writeAll(dec); + if(auto rv = f(zsrc, d->properties["OriginalMimeType"]); rv < OK) + return rv; } + else if(auto rv = f(dec, d->mime); rv < OK) + return rv; return dec.close(); } diff --git a/cdoc/CDoc1Reader.h b/cdoc/CDoc1Reader.h index 6f7b2f9..5d6b35d 100644 --- a/cdoc/CDoc1Reader.h +++ b/cdoc/CDoc1Reader.h @@ -20,6 +20,8 @@ #include "CDocReader.h" +#include + class Token; class CDoc1Reader : public libcdoc::CDocReader @@ -43,7 +45,8 @@ class CDoc1Reader : public libcdoc::CDocReader private: CDoc1Reader(const CDoc1Reader &) = delete; CDoc1Reader &operator=(const CDoc1Reader &) = delete; - libcdoc::result_t decryptData(const std::vector& fmk, std::string& mime, std::vector& data); + libcdoc::result_t decryptData(const std::vector& fmk, + const std::function& f); class Private; Private *d; }; diff --git a/cdoc/Crypto.cpp b/cdoc/Crypto.cpp index 9040d6e..25a6e57 100644 --- a/cdoc/Crypto.cpp +++ b/cdoc/Crypto.cpp @@ -455,7 +455,7 @@ EncryptionConsumer::write(const uint8_t *src, size_t size) return OK; if(error != OK) return error; - buf.resize(std::max(buf.size(), size + EVP_CIPHER_CTX_block_size(ctx.get()) - 1)); + buf.resize(std::max(buf.size(), size + EVP_CIPHER_CTX_block_size(ctx.get()) - 1)); int len = int(buf.size()); if(SSL_FAILED(EVP_CipherUpdate(ctx.get(), buf.data(), &len, src, int(size)), "EVP_CipherUpdate")) return CRYPTO_ERROR; @@ -474,7 +474,7 @@ EncryptionConsumer::writeAAD(const std::vector &data) result_t EncryptionConsumer::close() { - buf.resize(std::max(buf.size(), size_t(EVP_CIPHER_CTX_block_size(ctx.get())))); + buf.resize(std::max(buf.size(), size_t(EVP_CIPHER_CTX_block_size(ctx.get())))); int len = int(buf.size()); if(SSL_FAILED(EVP_CipherFinal(ctx.get(), buf.data(), &len), "EVP_CipherFinal")) return CRYPTO_ERROR; diff --git a/cdoc/DDocReader.cpp b/cdoc/DDocReader.cpp index eb6f9de..8756d52 100644 --- a/cdoc/DDocReader.cpp +++ b/cdoc/DDocReader.cpp @@ -19,52 +19,50 @@ #include "DDocReader.h" #include "CDoc.h" #include "Io.h" -#include "XmlReader.h" using namespace libcdoc; -int -DDOCReader::parse(libcdoc::DataSource *src, libcdoc::MultiDataConsumer *dst) +int64_t +DDOCReader::parse(MultiDataConsumer *dst) { - XMLReader reader(src); - while(reader.read()) { - if(reader.isEndElement()) continue; - // EncryptedData - if(!reader.isElement("DataFile")) continue; - std::string name = reader.attribute("Filename"); - std::vector content = reader.readBase64(); - int result = dst->open(name, content.size()); - if (result != libcdoc::OK) return result; - int64_t n_written = dst->write(content.data(), content.size()); - if (n_written < 0) return (int) n_written; - result = dst->close(); - if (result != libcdoc::OK) return result; + while(read()) { + if(isEndElement()) + continue; + // EncryptedData + if(!isElement("DataFile")) + continue; + std::string name = attribute("Filename"); + std::vector content = readBase64(); + if (auto rv = dst->open(name, content.size()); rv != libcdoc::OK) + return rv; + if (auto rv = dst->write(content.data(), content.size()); rv < 0) + return rv; + if (auto rv = dst->close(); rv != libcdoc::OK) + return rv; } return (dst->isError()) ? libcdoc::IO_ERROR : libcdoc::OK; } struct DDocFileListConsumer : public libcdoc::MultiDataConsumer { - std::vector files; + std::vector &files; - explicit DDocFileListConsumer() = default; - int64_t write(const uint8_t *src, size_t size) override final { - DDOCReader::File& file = files.back(); - file.data.insert(file.data.end(), src, src + size); - return size; - } - libcdoc::result_t close() override final { return libcdoc::OK; } - bool isError() override final { return false; } - libcdoc::result_t open(const std::string& name, int64_t size) override final { - files.push_back({name, "application/octet-stream", {}}); - return libcdoc::OK; - } + DDocFileListConsumer(std::vector &_files): files(_files) {} + int64_t write(const uint8_t *src, size_t size) final { + DDOCReader::File& file = files.back(); + file.data.insert(file.data.end(), src, src + size); + return size; + } + libcdoc::result_t close() final { return libcdoc::OK; } + bool isError() final { return false; } + libcdoc::result_t open(const std::string& name, int64_t /*size*/) final { + files.push_back({name, "application/octet-stream", {}}); + return libcdoc::OK; + } }; -std::vector -DDOCReader::files(const std::vector &data) +int64_t +DDOCReader::files(std::vector &files) { - libcdoc::VectorSource src(data); - DDocFileListConsumer list; - parse(&src, &list); - return std::move(list.files); + DDocFileListConsumer list{files}; + return parse(&list); } diff --git a/cdoc/DDocReader.h b/cdoc/DDocReader.h index 9bed7ce..8be469c 100644 --- a/cdoc/DDocReader.h +++ b/cdoc/DDocReader.h @@ -18,26 +18,23 @@ #pragma once -#include -#include -#include +#include "XmlReader.h" namespace libcdoc { -struct DataSource; struct MultiDataConsumer; -class DDOCReader +struct DDOCReader: public XMLReader { -public: + using XMLReader::XMLReader; struct File { std::string name, mime; std::vector data; }; - static int parse(libcdoc::DataSource *src, libcdoc::MultiDataConsumer *dst); + int64_t parse(MultiDataConsumer *dst); - static std::vector files(const std::vector &data); + int64_t files(std::vector &files); }; -} // namespace libcdoc \ No newline at end of file +} // namespace libcdoc diff --git a/cdoc/PKCS11Backend.cpp b/cdoc/PKCS11Backend.cpp index 4bccd92..4d20176 100644 --- a/cdoc/PKCS11Backend.cpp +++ b/cdoc/PKCS11Backend.cpp @@ -427,12 +427,17 @@ libcdoc::PKCS11Backend::deriveECDH1(std::vector& dst, const std::vector CK_ECDH1_DERIVE_PARAMS ecdh_parms = { CKD_NULL, 0, nullptr, CK_ULONG(public_key.size()), CK_BYTE_PTR(public_key.data()) }; CK_MECHANISM mech = { CKM_ECDH1_DERIVE, &ecdh_parms, sizeof(CK_ECDH1_DERIVE_PARAMS) }; CK_BBOOL _false = CK_FALSE; + CK_BBOOL _true = CK_TRUE; CK_OBJECT_CLASS newkey_class = CKO_SECRET_KEY; CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET; - std::vector newkey_template{ - {CKA_TOKEN, &_false, sizeof(_false)}, - {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, - {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)} + CK_ULONG value_len = (public_key.size() - 1) / 2; + std::array newkey_template{ + CK_ATTRIBUTE{CKA_TOKEN, &_false, sizeof(_false)}, + CK_ATTRIBUTE{CKA_CLASS, &newkey_class, sizeof(newkey_class)}, + CK_ATTRIBUTE{CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)}, + CK_ATTRIBUTE{CKA_SENSITIVE, &_false, sizeof(_false)}, + CK_ATTRIBUTE{CKA_EXTRACTABLE, &_true, sizeof(_true)}, + CK_ATTRIBUTE{CKA_VALUE_LEN, &value_len, sizeof(value_len)}, }; CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE; unsigned long p11result = d->f->C_DeriveKey(d->session, &mech, d->key, newkey_template.data(), CK_ULONG(newkey_template.size()), &newkey); diff --git a/cdoc/XmlReader.cpp b/cdoc/XmlReader.cpp index 3866b79..089b156 100644 --- a/cdoc/XmlReader.cpp +++ b/cdoc/XmlReader.cpp @@ -62,24 +62,7 @@ XMLReader::XMLReader(libcdoc::DataSource *src, bool delete_on_close) d->reader = xmlReaderForIO(Private::xmlInputReadCallback, nullptr, d, nullptr, nullptr, XML_PARSE_HUGE); } -XMLReader::XMLReader(std::istream *ifs, bool delete_on_close) - : XMLReader(new libcdoc::IStreamSource(ifs, delete_on_close), true) -{ -} - -XMLReader::XMLReader(const std::string &file) - : d(new Private) -{ - d->reader = xmlReaderForFile(file.c_str(), nullptr, XML_PARSE_HUGE); -} - -XMLReader::XMLReader(const std::vector &data) - : d(new Private) -{ - d->reader = xmlReaderForMemory((const char*)data.data(), int(data.size()), nullptr, nullptr, XML_PARSE_HUGE); -} - -XMLReader::~XMLReader() +XMLReader::~XMLReader() noexcept { xmlFreeTextReader(d->reader); if(d->_src && d->_delete_src) delete d->_src; diff --git a/cdoc/XmlReader.h b/cdoc/XmlReader.h index 1742326..e2bb5c3 100644 --- a/cdoc/XmlReader.h +++ b/cdoc/XmlReader.h @@ -31,10 +31,7 @@ class XMLReader { public: XMLReader(libcdoc::DataSource *src, bool delete_on_close = false); - XMLReader(std::istream *ifs, bool delete_on_close = false); - XMLReader(const std::string &file); - XMLReader(const std::vector &data); - ~XMLReader(); + virtual ~XMLReader() noexcept; std::string attribute(const char *attr) const; bool isElement(const char *element) const; @@ -48,4 +45,4 @@ class XMLReader Private *d; }; -} // namespace libcdoc \ No newline at end of file +} // namespace libcdoc diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index c5deef6..ab88712 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -63,9 +63,9 @@ static void print_usage(ostream& ofs) ofs << " --key-id - PKCS11 key ID" << endl; ofs << " --key-label - PKCS11 key label" << endl; ofs << endl; - ofs << "cdoc-tool re-encrypt FILE" << endl; + ofs << "cdoc-tool locks FILE" << endl; ofs << endl; - ofs << "cdoc-tool locks DECRYPT_ARGUMENTS ENCRYPT_ARGUMENTS FILE --out OUTPUTFILE" << endl; + ofs << "cdoc-tool re-encrypt DECRYPT_ARGUMENTS ENCRYPT_ARGUMENTS FILE --out OUTPUTFILE" << endl; ofs << " Re-encrypts container for different recipient(s)" << endl; ofs << endl; ofs << "Common arguments:" << endl; diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index dc8a5e2..78ced8d 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -544,7 +544,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(constructor, Buf, BufTypes) BOOST_CHECK_EQUAL_COLLECTIONS(encrypted_data.begin(), encrypted_data.end(), key.iv.begin(), key.iv.end()); //BOOST_CHECK_EQUAL(encrypt.writeAAD(aad), libcdoc::OK); libcdoc::VectorSource plain_src(plaintext); - for(ssize_t read_len = 0; (read_len = plain_src.read(buffer.data(), buffer.size())) > 0; ) { + for(libcdoc::result_t read_len = 0; (read_len = plain_src.read(buffer.data(), buffer.size())) > 0; ) { BOOST_CHECK_EQUAL(encrypt.write(buffer.data(), read_len), read_len); } BOOST_CHECK_EQUAL(encrypt.close(), libcdoc::OK); @@ -554,7 +554,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(constructor, Buf, BufTypes) libcdoc::DecryptionSource decrypt(encrypted_src, method, key.key); //BOOST_CHECK_EQUAL(decrypt.readAAD(aad), libcdoc::OK); std::vector decrypted_text; - for(ssize_t read_len = 0; (read_len = decrypt.read(buffer.data(), buffer.size())) > 0; ) { + for(libcdoc::result_t read_len = 0; (read_len = decrypt.read(buffer.data(), buffer.size())) > 0; ) { decrypted_text.insert(decrypted_text.end(), buffer.data(), buffer.data() + read_len); } BOOST_CHECK_EQUAL(decrypt.isError(), false);