From 1b76e52715e6cb4cd8d2625abd5dc43de20c63c1 Mon Sep 17 00:00:00 2001 From: Lauris Kaplinski Date: Fri, 9 Jan 2026 11:12:33 +0200 Subject: [PATCH 01/10] Added CDocV1 tests Signed-off-by: Lauris Kaplinski --- test/data/ec-secp384r1-cert.der | Bin 0 -> 660 bytes test/data/rsa_2048_cert.der | Bin 0 -> 995 bytes test/data/test_data2.txt | 1 + test/data/test_data3.txt | 3 +++ 4 files changed, 4 insertions(+) create mode 100644 test/data/ec-secp384r1-cert.der create mode 100644 test/data/rsa_2048_cert.der create mode 100644 test/data/test_data2.txt create mode 100644 test/data/test_data3.txt diff --git a/test/data/ec-secp384r1-cert.der b/test/data/ec-secp384r1-cert.der new file mode 100644 index 0000000000000000000000000000000000000000..b806ac8b425807091071c74302895ef99334d37b GIT binary patch literal 660 zcmXqLVwzyk#3Z(WnTe5!NhHNg^7Y(3_s^<4{^X!_Xa18+J7OKIN6v(S=fY`TwM*d3^YI-W*$Ya!&6=TgWPqz938!Ny@Nc1L%baQbc`(w3=9n{ zOwA1~3-0xQBU29ib5}m^-u*XE@SG4sSHKTaAk4`4pM}+c8Au^VJ#z+wK`N6W z!`dk}Tjk%Zx4Cz6|Hn%=fAiERvgR$hlM^>}spWzL5u4NX<~9fw+)P;gzbiTI^R_Pw zm<*JROsnrTM_ihBlCQqu^evNTUnef{Zf_EATivW*{jGU_$~>z@^OlQL&)6-{D!^{H F001_W)M@|# literal 0 HcmV?d00001 diff --git a/test/data/rsa_2048_cert.der b/test/data/rsa_2048_cert.der new file mode 100644 index 0000000000000000000000000000000000000000..4c0463f8b79859db14d0a8420596f0d57ddd1b88 GIT binary patch literal 995 zcmXqLV!m(C#B_WCGZP~dlZemt_xo0hONw~02paJ3`X!l^ar}eR9F8XcO5TBM{iy4AkW|sFGoKeV+#WV zLjwy_b3+S50RujeS{5F5s9HlY0}+sj77s6qE<-5;36MCeuwa0nzpJY*k|_pq;=D#? zKr<~3%uURVjibbQjX_*dm(4$i8Z<2 zibt|s?T_7>Q*8KLIgKaV&H2@qzsqLLmiVIC;{5*g(%Vu0<&y1o_c0k2RqU{O|E%-t zgc*;G1$RDJQ7U@!X{LYX&pDeizR1;opBKoq$hCeWd(MgGtFKxFTTR4*-a6#@E_6Gz z?eLEe-`EzYE>ky*w439-)O`DsuNevjed2rOOKy2l{dtj||DODwG=6dEu(ExfiNTEe->5)W*~(e?7*}N40c9_3?-xXJZ5X1pSLt^RVKDimug^5J<+mgk0*23 zcb~KO=FaVD=-IU9-Cu*#E*ZBiR(5Bq{}biZk@K-GlM4NNbyAwl1U0c+ZpoVaZ^oo{ z3n@)_ShudwdEc+O@{Z{h2mV|S+3jjvFEh`}|LFcgrft8ru6X_+PckUCw6rc-b7zcs zZBm-bmipNS-|H`XUcKC46Q{A4-Sz0^Uu!2$vpC7I=l+sq-Twa*%2PHSI=!;|X~#j` z7YVPf=0@MS(aE-0D&W59q5F4_%n$v~@UGZsl9;DxqVx;HedpfC+ Date: Fri, 9 Jan 2026 16:35:28 +0200 Subject: [PATCH 02/10] Added CDoc1 tests and cleaned up testing Signed-off-by: Lauris Kaplinski --- cdoc/CDocCipher.cpp | 10 +- cdoc/CDocCipher.h | 7 +- cdoc/RcptInfo.h | 5 +- cdoc/cdoc-tool.cpp | 20 +- test/CMakeLists.txt | 5 +- test/libcdoc_boost.cpp | 412 ++++++++++++++++++----------------------- 6 files changed, 202 insertions(+), 257 deletions(-) diff --git a/cdoc/CDocCipher.cpp b/cdoc/CDocCipher.cpp index 7d0fe9c7..df775e3b 100644 --- a/cdoc/CDocCipher.cpp +++ b/cdoc/CDocCipher.cpp @@ -227,9 +227,9 @@ struct ToolNetwork : public libcdoc::NetworkBackend { }; -int CDocCipher::writer_push(CDocWriter& writer, const vector& keys, const vector& files) +int CDocCipher::writer_push(CDocWriter& writer, const vector& rcpts, const vector& files) { - for (const libcdoc::Recipient& rcpt : keys) { + for (const libcdoc::Recipient& rcpt : rcpts) { int64_t result = writer.addRecipient(rcpt); if (result != libcdoc::OK) return result; } @@ -262,7 +262,7 @@ int CDocCipher::writer_push(CDocWriter& writer, const vector& keys, c #define PUSH true static bool -fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& rcpts, RecipientInfoIdMap& crypto_rcpts, const RecipientInfoVector& recipients) +fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& rcpts, RecipientInfoIdMap& crypto_rcpts, const std::vector& recipients) { int idx = 0; for (const auto& rcpt : recipients) { @@ -329,7 +329,7 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& recipients) { RecipientInfoIdMap crypto_rcpts; ToolCrypto crypto(crypto_rcpts); @@ -550,7 +550,7 @@ int CDocCipher::Decrypt(const unique_ptr& rdr, unsigned int lock_idx } int -CDocCipher::ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lock_label, const RcptInfo& lock_info, RecipientInfoVector& recipients) +CDocCipher::ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lock_label, const RcptInfo& lock_info, std::vector& recipients) { // Decryption part RecipientInfoIdMap dec_info; diff --git a/cdoc/CDocCipher.h b/cdoc/CDocCipher.h index 84614bb4..bd3d8333 100644 --- a/cdoc/CDocCipher.h +++ b/cdoc/CDocCipher.h @@ -30,8 +30,7 @@ namespace libcdoc { -typedef typename std::map RecipientInfoIdMap; -typedef typename std::vector RecipientInfoVector; +typedef typename std::map RecipientInfoIdMap; class CDocCipher { @@ -40,12 +39,12 @@ class CDocCipher CDocCipher(const CDocCipher&) = delete; CDocCipher(CDocCipher&&) = delete; - int Encrypt(ToolConf& conf, RecipientInfoVector& recipients); + int Encrypt(ToolConf& conf, std::vector& recipients); int Decrypt(ToolConf& conf, int idx_base_1, const RcptInfo& recipient); int Decrypt(ToolConf& conf, const std::string& label, const RcptInfo& recipient); - int ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lock_label, const RcptInfo& lock_info, RecipientInfoVector& recipients); + int ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lock_label, const RcptInfo& lock_info, std::vector& recipients); void Locks(const char* file) const; diff --git a/cdoc/RcptInfo.h b/cdoc/RcptInfo.h index 86168c6a..c9ecd53f 100644 --- a/cdoc/RcptInfo.h +++ b/cdoc/RcptInfo.h @@ -47,6 +47,9 @@ struct RcptInfo { }; Type type; + // Locks label + std::string label; + // Certificate for encryption std::vector cert; // Pin or password std::vector secret; @@ -56,8 +59,6 @@ struct RcptInfo { std::string key_file_name; // ID code for shares server std::string id; - // Locks label - std::string label; }; } diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index 12adf66d..ad76cd88 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -44,7 +44,7 @@ static void print_usage(ostream& ofs) ofs << "cdoc-tool encrypt --rcpt RECIPIENT [--rcpt...] [-v1] [--genlabel] --out OUTPUTFILE FILE [FILE...]" << endl; ofs << " Encrypt files for one or more recipients" << endl; ofs << " RECIPIENT has to be one of the following:" << endl; - ofs << " [label]:cert:CERTIFICATE_HEX - public key from certificate" << endl; + ofs << " [label]:cert:CERTIFICATE_FILE - public key from certificate" << endl; ofs << " [label]:pkey:SECRET_KEY_HEX - public key" << endl; ofs << " [label]:pfkey:PUB_KEY_FILE - path to DER file with EC (secp384r1 curve) public key" << endl; ofs << " [label]:skey:SECRET_KEY_HEX - AES key" << endl; @@ -140,7 +140,7 @@ parse_common(ToolConf& conf, int arg_idx, int argc, char *argv[]) } static int -parse_rcpt(ToolConf& conf, RecipientInfoVector& rcpts, int& arg_idx, int argc, char *argv[]) +parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, int argc, char *argv[]) { string_view arg(argv[arg_idx]); if ((arg != "--rcpt") || ((arg_idx + 1) >= argc)) return 0; @@ -285,7 +285,7 @@ static int ParseAndEncrypt(int argc, char *argv[]) LOG_INFO("Encrypting"); ToolConf conf; - RecipientInfoVector rcpts; + std::vector rcpts; // // Parse all arguments into ToolConf structure @@ -325,7 +325,7 @@ static int ParseAndEncrypt(int argc, char *argv[]) } if (!conf.gen_label) { // If labels must not be generated then is there any Recipient without provided label? - auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](RecipientInfoVector::const_reference rcpt) -> bool {return rcpt.label.empty();}) }; + auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.label.empty();}) }; if (rcpt_wo_label != rcpts.cend()) { if (rcpts.size() > 1) { LOG_ERROR("Not all Recipients have label"); @@ -352,7 +352,7 @@ static int ParseAndEncrypt(int argc, char *argv[]) // CDOC1 is supported only for encryption with certificate. if (conf.cdocVersion == 1) { - auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](RecipientInfoVector::const_reference rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; + auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; if (rcpt_type_non_cert != rcpts.cend()) { LOG_ERROR("CDOC version 1 container can be used for encryption with certificate only."); return 1; @@ -539,7 +539,7 @@ static int ParseAndDecrypt(int argc, char *argv[]) } CDocCipher cipher; - RcptInfo rcpt {RcptInfo::ANY, {}, ldata.secret, ldata.slot, ldata.key_id, ldata.key_label}; + RcptInfo rcpt {RcptInfo::ANY, {}, {}, ldata.secret, ldata.slot, ldata.key_id, ldata.key_label}; if (ldata.lock_idx != -1) { return cipher.Decrypt(conf, ldata.lock_idx, rcpt); } else { @@ -550,7 +550,7 @@ static int ParseAndDecrypt(int argc, char *argv[]) static int ParseAndReEncrypt(int argc, char *argv[]) { ToolConf conf; - RecipientInfoVector rcpts; + std::vector rcpts; LockData ldata; int arg_idx = 0; @@ -596,7 +596,7 @@ static int ParseAndReEncrypt(int argc, char *argv[]) if (!conf.gen_label) { // If labels must not be generated then is there any Recipient without provided label? - auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](RecipientInfoVector::const_reference rcpt) -> bool {return rcpt.label.empty();}) }; + auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.label.empty();}) }; if (rcpt_wo_label != rcpts.cend()) { if (rcpts.size() > 1) { LOG_ERROR("Not all Recipients have label"); @@ -619,7 +619,7 @@ static int ParseAndReEncrypt(int argc, char *argv[]) // CDOC1 is supported only for encryption with certificate. if (conf.cdocVersion == 1) { - auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](RecipientInfoVector::const_reference rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; + auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; if (rcpt_type_non_cert != rcpts.cend()) { LOG_ERROR("CDOC version 1 container can be used for encryption with certificate only."); return 1; @@ -627,7 +627,7 @@ static int ParseAndReEncrypt(int argc, char *argv[]) } CDocCipher cipher; - RcptInfo rcpt {RcptInfo::ANY, {}, ldata.secret, ldata.slot, ldata.key_id, ldata.key_label}; + RcptInfo rcpt {RcptInfo::ANY, {}, {}, ldata.secret, ldata.slot, ldata.key_id, ldata.key_label}; if (ldata.lock_idx != -1) { return cipher.ReEncrypt(conf, ldata.lock_idx, ldata.lock_label, rcpt, rcpts); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4b60ec69..1e9f06c1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,9 +3,6 @@ add_executable(unittests ../cdoc/CDocCipher.cpp ../cdoc/Crypto.cpp) -target_compile_definitions(unittests PRIVATE - DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data") - target_link_libraries(unittests OpenSSL::SSL cdoc @@ -13,7 +10,7 @@ target_link_libraries(unittests add_test(NAME runtest COMMAND ${CMAKE_CURRENT_BINARY_DIR}/unittests --build_info=YES --logger=HRF,all,stdout - WORKING_DIRECTORY $ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test ) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index d9ff9eab..3f61fc1d 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -32,7 +32,7 @@ #include "pipe.h" #ifndef DATA_DIR -#define DATA_DIR "." +#define DATA_DIR "data" #endif namespace btools = boost::test_tools; @@ -45,6 +45,8 @@ using namespace std; * @brief Unencrypted file name. */ constexpr string_view SourceFile("test_data.txt"); +constexpr string_view SourceFile2("test_data2.txt"); +constexpr string_view SourceFile3("test_data3.txt"); /** * @brief Encrypted file name. @@ -52,8 +54,10 @@ constexpr string_view SourceFile("test_data.txt"); constexpr string_view TargetFile("test_data.txt.cdoc"); constexpr string_view ECPrivKeyFile("ec-secp384r1-priv.der"); constexpr string_view ECPubKeyFile("ec-secp384r1-pub.der"); +constexpr string_view ECCertFile("ec-secp384r1-cert.der"); constexpr string_view RSAPrivKeyFile("rsa_2048_priv.der"); constexpr string_view RSAPubKeyFile("rsa_2048_pub.der"); +constexpr string_view RSACertFile("rsa_2048_cert.der"); const string Label("Proov"); @@ -110,34 +114,46 @@ class FixtureBase target /= fileName; } - /** - * @brief Checks if the file exists in the test data path. - * - * The method prepends the fileName with the test data path and checks its existence. If the file does not - * exist then appropriate message is appended to returned predicate_result object and the value of the object - * is set to false. - * @param fileName the name of the file thats existence has to be checked. - * @return predicate_result object with the check result. - */ - boost::test_tools::predicate_result DoesFileExist(const string& fileName) const + std::string formTargetFile(const std::string_view name) const { - fs::path file(testDataPath); - file /= fileName; - if (fs::exists(file)) - { - return true; - } - else - { - btools::predicate_result res(false); - res.message() << "File " << file << " does not exist"; - return res; + fs::path path(fs::path(tmpDataPath) / name); + if (fs::exists(path)) { + error_code e; + fs::remove(path, e); + if(e) BOOST_TEST_MESSAGE("Failed to remove file"); } + return path.string(); + } + + std::string checkDataFile(const std::string_view name) const + { + fs::path path(fs::path(testDataPath) / name); + BOOST_TEST_REQUIRE(fs::exists(path), "file " << name << " does not exist"); + return path.string(); + } + + std::string checkTargetFile(const std::string_view name) const + { + fs::path path(fs::path(tmpDataPath) / name); + BOOST_TEST_REQUIRE(fs::exists(path), "file " << name << " does not exist"); + return path.string(); + } + + std::vector fetchDataFile(const std::string_view name) const + { + fs::path path(fs::path(testDataPath) / name); + BOOST_TEST_REQUIRE(fs::exists(path), "file " << name << " does not exist"); + return libcdoc::readAllBytes(path.string()); } fs::path testDataPath = DATA_DIR; + fs::path tmpDataPath = fs::path(DATA_DIR) / "tmp"; fs::path sourceFilePath; - fs::path targetFilePath; + fs::path sourceFilePath2; + fs::path sourceFilePath3; + + std::vector sources = {"test_data.txt", "test_data2.txt", "test_data3.txt"}; + size_t max_filesize = 100000000; }; @@ -153,18 +169,8 @@ class EncryptFixture : public FixtureBase // Setup source, unencrypted file path FormFilePath(SourceFile, sourceFilePath); - - // Setup target, encrypted file path - FormFilePath(TargetFile, targetFilePath); - - // Remove target file if it exists - if (fs::exists(targetFilePath)) - { - error_code e; - fs::remove(targetFilePath, e); - if(e) - BOOST_TEST_MESSAGE("Failed to remove file"); - } + FormFilePath(SourceFile2, sourceFilePath2); + FormFilePath(SourceFile3, sourceFilePath3); } ~EncryptFixture() { BOOST_TEST_MESSAGE("Encrypt fixture deardown"); } @@ -218,9 +224,6 @@ class DecryptFixture : public FixtureBase // Setup source, encrypted file path FormFilePath(TargetFile, sourceFilePath); - - // Setup target, unencrypted file path - FormFilePath(SourceFile, targetFilePath); } ~DecryptFixture() @@ -229,6 +232,70 @@ class DecryptFixture : public FixtureBase } }; +static void +encrypt(unsigned int version, const std::vector& files, const std::string& container, std::vector& rcpts) { + libcdoc::ToolConf conf; + for (auto file : files) { + conf.input_files.push_back(file); + } + conf.out = container; + conf.cdocVersion = version; + + libcdoc::CDocCipher cipher; + BOOST_CHECK_EQUAL(cipher.Encrypt(conf, rcpts), 0); + + BOOST_TEST(fs::exists(fs::path(container)), "File " << container << " does not exist"); +} + +static void +encryptV1(const std::vector& files, const std::string& container, const std::vector& cert) { + std::vector rcpts { + {libcdoc::RcptInfo::CERT, {}, cert} + }; + encrypt(1, files, container, rcpts); +} + +static void +encryptV2(const std::vector& files, const std::string& container, const std::vector& cert) { + std::vector rcpts { + {libcdoc::RcptInfo::CERT, {}, cert} + }; + encrypt(2, files, container, rcpts); +} + +static void +decrypt(const std::vector& files, const std::string& container, const std::string& dir, libcdoc::RcptInfo& rcpt) +{ + libcdoc::ToolConf conf; + conf.input_files.push_back(container); + conf.out = dir; + + libcdoc::CDocCipher cipher; + if (rcpt.label.empty()) { + BOOST_CHECK_EQUAL(cipher.Decrypt(conf, 1, rcpt), 0); + } else { + BOOST_CHECK_EQUAL(cipher.Decrypt(conf, rcpt.label, rcpt), 0); + } + + fs::path path(dir); + for (auto file : files) { + BOOST_TEST(fs::exists(path / fs::path(file).filename()), "File " << file << " does not exist"); + } + + path = fs::path(container); + if (fs::exists(path)) { + error_code e; + fs::remove(path, e); + if(e) + BOOST_TEST_MESSAGE("Failed to remove file"); } +} + +static void +decrypt(const std::vector& files, const std::string& container, const std::string& dir, const std::vector& key) +{ + libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, {}, key}; + decrypt(files, container, dir, rcpt); +} static int unicode_to_utf8 (unsigned int uval, uint8_t *d, uint64_t size) { @@ -344,258 +411,141 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordAndLabel, FixtureBase, * u BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE(PasswordUsageWithLabel) +// CDoc2 password and label +BOOST_AUTO_TEST_SUITE(PasswordUsageWithLabel) BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordAndLabel, EncryptFixture, * utf::description("Encrypting a file with password and given label")) { - // Check if the source, unecrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = targetFilePath.string(); - - libcdoc::RcptInfo rcpt; - rcpt.type = libcdoc::RcptInfo::PASSWORD; - rcpt.secret.assign(Password.cbegin(), Password.cend()); - rcpt.label = Label; - - libcdoc::RecipientInfoVector rcpts {rcpt}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Encrypt(conf, rcpts), 0); - - // Validate the encrypted file - BOOST_TEST(ValidateEncryptedFile(targetFilePath)); + std::vector rcpts { + {libcdoc::RcptInfo::PASSWORD, Label, {}, std::vector(Password.cbegin(), Password.cend())} + }; + encrypt(2, {checkDataFile(sources[0])}, formTargetFile("PasswordUsageWithoutLabel.cdoc"), rcpts); } - BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithPasswordAndLabel, DecryptFixture, * utf::depends_on("PasswordUsageWithLabel/EncryptWithPasswordAndLabel") * utf::description("Decrypting a file with password and given label")) { - // Check if the source, encrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - - auto tmp = testDataPath / "tmp"; - fs::remove_all(tmp); - fs::create_directory(tmp); - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = tmp.string(); - - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, vector(Password.cbegin(), Password.cend())}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, Label, rcpt), 0); - - // Check if the encrypted file exists - BOOST_TEST(fs::exists(targetFilePath), "File " << targetFilePath << " exists"); + libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, Label, {}, std::vector(Password.cbegin(), Password.cend())}; + decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath, rcpt); } - BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE(PasswordUsageWithoutLabel) +// CDoc2 password and label +BOOST_AUTO_TEST_SUITE(PasswordUsageWithoutLabel) BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordWithoutLabel, EncryptFixture, * utf::description("Encrypting a file with password and without label")) { - // Check if the source, unecrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - - libcdoc::ToolConf conf; - conf.gen_label = true; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = targetFilePath.string(); - - libcdoc::RcptInfo rcpt; - rcpt.type = libcdoc::RcptInfo::PASSWORD; - rcpt.secret.assign(Password.cbegin(), Password.cend()); - - libcdoc::RecipientInfoVector rcpts {rcpt}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Encrypt(conf, rcpts), 0); - - // Validate the encrypted file - BOOST_TEST(ValidateEncryptedFile(targetFilePath)); + std::vector rcpts { + {libcdoc::RcptInfo::PASSWORD, {}, {}, std::vector(Password.cbegin(), Password.cend())} + }; + encrypt(2, {checkDataFile(sources[0])}, formTargetFile("PasswordUsageWithoutLabel.cdoc"), rcpts); } - BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithPasswordLabelIndex, DecryptFixture, * utf::depends_on("PasswordUsageWithoutLabel/EncryptWithPasswordWithoutLabel") * utf::description("Decrypting a file with password and label index")) { - // Check if the source, encrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = testDataPath.string(); - - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, vector(Password.cbegin(), Password.cend())}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, 1, rcpt), 0); - - // Check if the encrypted file exists - BOOST_TEST(fs::exists(targetFilePath), "File " << targetFilePath << " exists"); + decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath, std::vector(Password.cbegin(), Password.cend())); } - BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE(AESKeyUsage) +// CDoc2 AES key +BOOST_AUTO_TEST_SUITE(AESKeyUsage) BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithAESKey, EncryptFixture, * utf::description("Encrypting a file with symmetric AES key")) { - // Check if the source, unecrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = targetFilePath.string(); - - libcdoc::RcptInfo rcpt; - rcpt.type = libcdoc::RcptInfo::SKEY; - rcpt.secret = std::move(libcdoc::fromHex(AESKey)); - rcpt.label = Label; - - libcdoc::RecipientInfoVector rcpts {rcpt}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Encrypt(conf, rcpts), 0); - - // Validate the encrypted file - BOOST_TEST(ValidateEncryptedFile(targetFilePath)); + std::vector rcpts { + {libcdoc::RcptInfo::SKEY, {}, {}, libcdoc::fromHex(AESKey)} + }; + encrypt(2, {checkDataFile(sources[0])}, formTargetFile("AESKeyUsage.cdoc"), rcpts); } - BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithAESKey, DecryptFixture, * utf::depends_on("AESKeyUsage/EncryptWithAESKey") * utf::description("Decrypting a file with with symmetric AES key")) { - // Check if the source, encrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = testDataPath.string(); - - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, libcdoc::fromHex(AESKey)}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, Label, rcpt), 0); - - // Check if the encrypted file exists - BOOST_TEST(fs::exists(targetFilePath), "File " << targetFilePath << " exists"); + decrypt({checkDataFile(sources[0])}, checkTargetFile("AESKeyUsage.cdoc"), tmpDataPath, libcdoc::fromHex(AESKey)); } - BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE(ECKeyUsage) +// CDoc2 EC public/private key +BOOST_AUTO_TEST_SUITE(ECKeyUsage) BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKey, EncryptFixture, * utf::description("Encrypting a file with EC key")) { - // Check if the source and public key file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - fs::path keyPath; - FormFilePath(ECPubKeyFile, keyPath); - BOOST_TEST_REQUIRE(fs::exists(keyPath), "File " << keyPath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = targetFilePath.string(); - - libcdoc::RcptInfo rcpt; - rcpt.type = libcdoc::RcptInfo::PKEY; - rcpt.secret = libcdoc::readAllBytes(keyPath.string()); - rcpt.label = Label; - - libcdoc::RecipientInfoVector rcpts {rcpt}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Encrypt(conf, rcpts), 0); - - // Validate the encrypted file - BOOST_TEST(ValidateEncryptedFile(targetFilePath)); + std::vector rcpts { + {libcdoc::RcptInfo::PKEY, {}, {}, fetchDataFile(ECPubKeyFile)} + }; + encrypt(2, {checkDataFile(sources[0])}, formTargetFile("ECKeyUsage.cdoc"), rcpts); } - BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKey, DecryptFixture, * utf::depends_on("ECKeyUsage/EncryptWithECKey") * utf::description("Decrypting a file with with EC private key")) { - // Check if the source, encrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - fs::path keyPath; - FormFilePath(ECPrivKeyFile, keyPath); - BOOST_TEST_REQUIRE(fs::exists(keyPath), "File " << keyPath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = testDataPath.string(); - - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, libcdoc::readAllBytes(keyPath.string())}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, Label, rcpt), 0); - - // Check if the encrypted file exists - BOOST_TEST(fs::exists(targetFilePath), "File " << targetFilePath << " exists"); + decrypt({checkDataFile(sources[0])}, checkTargetFile("ECKeyUsage.cdoc"), tmpDataPath, fetchDataFile(ECPrivKeyFile)); } - BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE(RSAKeyUsage) +// CDoc2 RSA public/private key +BOOST_AUTO_TEST_SUITE(RSAKeyUsage) BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithRSAKey, EncryptFixture, * utf::description("Encrypting a file with RSA key")) { - // Check if the source and public key file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - fs::path keyPath; - FormFilePath(RSAPubKeyFile, keyPath); - BOOST_TEST_REQUIRE(fs::exists(keyPath), "File " << keyPath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = targetFilePath.string(); - - libcdoc::RcptInfo rcpt; - rcpt.type = libcdoc::RcptInfo::PKEY; - rcpt.secret = libcdoc::readAllBytes(keyPath.string()); - rcpt.label = Label; - - libcdoc::RecipientInfoVector rcpts {rcpt}; - - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Encrypt(conf, rcpts), 0); - - // Validate the encrypted file - BOOST_TEST(ValidateEncryptedFile(targetFilePath)); + std::vector rcpts { + {libcdoc::RcptInfo::PKEY, {}, {}, fetchDataFile(RSAPubKeyFile)} + }; + encrypt(2, {checkDataFile(sources[0])}, formTargetFile("RSAKeyUsage.cdoc"), rcpts); } - BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithRSAKey, DecryptFixture, * utf::depends_on("RSAKeyUsage/EncryptWithRSAKey") * utf::description("Decrypting a file with with RSA private key")) { - // Check if the source, encrypted file exists - BOOST_TEST_REQUIRE(fs::exists(sourceFilePath), "File " << sourceFilePath << " must exists"); - fs::path keyPath; - FormFilePath(RSAPrivKeyFile, keyPath); - BOOST_TEST_REQUIRE(fs::exists(keyPath), "File " << keyPath << " must exists"); - - libcdoc::ToolConf conf; - conf.input_files.push_back(sourceFilePath.string()); - conf.out = testDataPath.string(); + decrypt({checkDataFile(sources[0])}, checkTargetFile("RSAKeyUsage.cdoc"), tmpDataPath, fetchDataFile(RSAPrivKeyFile)); +} +BOOST_AUTO_TEST_SUITE_END() - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, libcdoc::readAllBytes(keyPath.string())}; +// CDoc1 tests - libcdoc::CDocCipher cipher; - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, Label, rcpt), 0); +BOOST_AUTO_TEST_SUITE(CDoc1ECKeySingle) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKeyV1, EncryptFixture, * utf::description("Encrypting a file with EC key in CDoc1 format")) +{ + encryptV1({checkDataFile(sources[0])}, formTargetFile("ECKeyUsageV1.cdoc"), fetchDataFile(ECCertFile)); +} +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKeyV1, DecryptFixture, + * utf::depends_on("CDoc1ECKeySingle/EncryptWithECKeyV1") + * utf::description("Decrypting a file in CDoc1 format with with EC private key")) +{ + decrypt({checkDataFile(sources[0])}, checkTargetFile("ECKeyUsageV1.cdoc"), tmpDataPath, fetchDataFile(ECPrivKeyFile)); +} +BOOST_AUTO_TEST_SUITE_END() - // Check if the encrypted file exists - BOOST_TEST(fs::exists(targetFilePath), "File " << targetFilePath << " exists"); +BOOST_AUTO_TEST_SUITE(CDoc1ECKeyMulti) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKeyV1Multi, EncryptFixture, * utf::description("Encrypting multiple files with EC key in CDoc1 format")) +{ + encryptV1({checkDataFile(sources[0]), checkDataFile(sources[1]), checkDataFile(sources[2])}, formTargetFile("ECKeyUsageV1Multi.cdoc"), fetchDataFile(ECCertFile)); +} +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKeyV1Multi, DecryptFixture, + * utf::depends_on("CDoc1ECKeyMulti/EncryptWithECKeyV1Multi") + * utf::description("Decrypting multiple files in CDoc1 format with with EC private key")) +{ + decrypt({checkDataFile(sources[0]), checkDataFile(sources[1]), checkDataFile(sources[2])}, checkTargetFile("ECKeyUsageV1Multi.cdoc"), tmpDataPath, fetchDataFile(ECPrivKeyFile)); } +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(CDoc1RSAKeySingle) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithRSAKeyV1, EncryptFixture, * utf::description("Encrypting a file with RSA key in CDoc1 format")) +{ + encryptV1({checkDataFile(sources[0])}, formTargetFile("RSAKeyUsageV1.cdoc"), fetchDataFile(RSACertFile)); +} +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithRSAKeyV1, DecryptFixture, + * utf::depends_on("CDoc1RSAKeySingle/EncryptWithRSAKeyV1") + * utf::description("Decrypting a file in CDoc1 format with with RSA private key")) +{ + decrypt({checkDataFile(sources[0])}, checkTargetFile("RSAKeyUsageV1.cdoc"), tmpDataPath, fetchDataFile(RSAPrivKeyFile)); +} BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE(MachineLabelParsing) +// Label parsing +BOOST_AUTO_TEST_SUITE(MachineLabelParsing) BOOST_AUTO_TEST_CASE(PlainLabelParsing) { const string label("data:v=1&type=ID-card&serial_number=PNOEE-38001085718&cn=J%C3%95EORG%2CJAAK-KRISTJAN%2C38001085718"); @@ -643,11 +593,9 @@ BOOST_AUTO_TEST_CASE(Base64LabelParsingWithMediaType) } } } - BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(StreamingDecryption) - using BufTypes = std::tuple, std::array, std::array, std::array>; BOOST_AUTO_TEST_CASE_TEMPLATE(constructor, Buf, BufTypes) { From 26297566d95f4949ea7e0d1eb834b06fa82796d7 Mon Sep 17 00:00:00 2001 From: Lauris Kaplinski Date: Tue, 13 Jan 2026 17:06:16 +0200 Subject: [PATCH 03/10] More CDocCipher cleanups --- cdoc/CDocCipher.cpp | 134 ++++++++++++++++------------------------- cdoc/CDocCipher.h | 7 +-- cdoc/RcptInfo.h | 22 +++++-- cdoc/cdoc-tool.cpp | 42 ++++++------- test/libcdoc_boost.cpp | 10 +-- 5 files changed, 94 insertions(+), 121 deletions(-) diff --git a/cdoc/CDocCipher.cpp b/cdoc/CDocCipher.cpp index df775e3b..e93d5db1 100644 --- a/cdoc/CDocCipher.cpp +++ b/cdoc/CDocCipher.cpp @@ -43,46 +43,43 @@ using namespace libcdoc; static string GenerateRandomSequence(); struct ToolPKCS11 : public libcdoc::PKCS11Backend { - const RecipientInfoIdMap& rcpts; + const std::map& rcpts; - ToolPKCS11(const std::string& library, const RecipientInfoIdMap& vec) : libcdoc::PKCS11Backend(library), rcpts(vec) {} + ToolPKCS11(const std::string& library, const std::map& vec) : libcdoc::PKCS11Backend(library), rcpts(vec) {} libcdoc::result_t connectToKey(int idx, bool priv) override final { if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - const RcptInfo& rcpt = rcpts.at(idx); - int result = libcdoc::CRYPTO_ERROR; + libcdoc::RcptInfo rcpt = rcpts.at(idx); if (!priv) { - result = useSecretKey(rcpt.slot, rcpt.secret, rcpt.key_id, rcpt.key_label); + return useSecretKey(rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); } else { - result = usePrivateKey(rcpt.slot, rcpt.secret, rcpt.key_id, rcpt.key_label); + return usePrivateKey(rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); } - if (result != libcdoc::OK) return result; - return libcdoc::OK; } }; #ifdef _WIN32 struct ToolWin : public libcdoc::WinBackend { - const RecipientInfoIdMap& rcpts; + const std::map& rcpts; - ToolWin(const std::string& provider, const RecipientInfoIdMap& vec) : libcdoc::WinBackend(provider), rcpts(vec) {} + ToolWin(const std::string& provider, const std::map& vec) : libcdoc::WinBackend(provider), rcpts(vec) {} result_t connectToKey(int idx, bool priv) { - const RcptInfo& rcpt = rcpts.at(idx); - return useKey(rcpt.key_label, std::string(rcpt.secret.cbegin(), rcpt.secret.cend())); + if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; + libcdoc::RcptInfo rcpt = rcpts.at(idx); + return useKey(rcpt.p11.key_label, std::string(rcpt.secret.cbegin(), rcpt.secret.cend())); } - }; #endif struct ToolCrypto : public libcdoc::CryptoBackend { - const RecipientInfoIdMap& rcpts; + const std::map& rcpts; std::unique_ptr p11; #ifdef _WIN32 std::unique_ptr ncrypt; #endif - ToolCrypto(const RecipientInfoIdMap& recipients) : rcpts(recipients) { + ToolCrypto(const std::map& recipients) : rcpts(recipients) { } bool connectLibrary(const std::string& library) { @@ -102,7 +99,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t decryptRSA(std::vector& dst, const std::vector &data, bool oaep, unsigned int idx) override final { if (p11) return p11->decryptRSA(dst, data, oaep, idx); if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - const RcptInfo& rcpt = rcpts.at(idx); + libcdoc::RcptInfo rcpt = rcpts.at(idx); if (rcpt.secret.empty()) return libcdoc::CRYPTO_ERROR; const uint8_t *p = rcpt.secret.data(); @@ -134,7 +131,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t deriveECDH1(std::vector& dst, const std::vector &public_key, unsigned int idx) override final { if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - const RcptInfo& rcpt = rcpts.at(idx); + libcdoc::RcptInfo rcpt = rcpts.at(idx); if (rcpt.secret.empty()) return libcdoc::CRYPTO_ERROR; const uint8_t *p = rcpt.secret.data(); @@ -151,7 +148,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { (EVP_PKEY_paramgen(ctx.get(), ¶ms) < 0)) return libcdoc::CRYPTO_ERROR; - p = public_key.data(); + p = public_key.data(); auto pubkey = make_unique_ptr(d2i_PublicKey(EVP_PKEY_EC, ¶ms, &p, long(public_key.size()))); if (!pubkey) return libcdoc::CRYPTO_ERROR; @@ -187,7 +184,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t getSecret(std::vector& secret, unsigned int idx) override final { if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - const RcptInfo& rcpt = rcpts.at(idx); + libcdoc::RcptInfo rcpt = rcpts.at(idx); secret = rcpt.secret; return secret.empty() ? INVALID_PARAMS : libcdoc::OK; } @@ -212,7 +209,7 @@ struct ToolNetwork : public libcdoc::NetworkBackend { if (!crypto->rcpts.contains(rcpt_idx)) return libcdoc::CRYPTO_ERROR; const RcptInfo& rcpt = crypto->rcpts.at(rcpt_idx); bool rsa = false; - return crypto->p11->getCertificate(dst, rsa, rcpt.slot, rcpt.secret, rcpt.key_id, rcpt.key_label); + return crypto->p11->getCertificate(dst, rsa, rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); } libcdoc::result_t getPeerTLSCertificates(std::vector> &dst) override final { @@ -262,7 +259,7 @@ int CDocCipher::writer_push(CDocWriter& writer, const vector& rcpts, #define PUSH true static bool -fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& rcpts, RecipientInfoIdMap& crypto_rcpts, const std::vector& recipients) +fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& rcpts, std::map& crypto_rcpts, const std::vector& recipients) { int idx = 0; for (const auto& rcpt : recipients) { @@ -305,9 +302,9 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector val; bool rsa; ToolPKCS11* p11 = dynamic_cast(crypto.p11.get()); - int result = p11->getPublicKey(val, rsa, rcpt.slot, rcpt.secret, rcpt.key_id, rcpt.key_label); + int result = p11->getPublicKey(val, rsa, rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); if (result != libcdoc::OK) { - LOG_ERROR("No such public key: {}", rcpt.key_label); + LOG_ERROR("No such public key: {}", rcpt.p11.key_label); continue; } LOG_DBG("Public key ({}): {}", rsa ? "rsa" : "ecc", toHex(val)); @@ -331,7 +328,7 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& recipients) { - RecipientInfoIdMap crypto_rcpts; + std::map crypto_rcpts; ToolCrypto crypto(crypto_rcpts); ToolNetwork network(&crypto); network.certs = std::move(conf.accept_certs); @@ -372,48 +369,9 @@ int CDocCipher::Encrypt(ToolConf& conf, std::vector& recipien return result; } -int CDocCipher::Decrypt(ToolConf& conf, int idx_base_1, const RcptInfo& recipient) -{ - RecipientInfoIdMap rcpts; - ToolCrypto crypto(rcpts); - ToolNetwork network(&crypto); - network.certs = std::move(conf.accept_certs); - - unique_ptr rdr(CDocReader::createReader(conf.input_files[0], &conf, &crypto, &network)); - if (rdr) { - LOG_DBG("Reader created"); - } else { - LOG_ERROR("Cannot create reader (invalid file?)"); - return 1; - } - - // Acquire the locks and get the labels according to the index - const vector &locks = rdr->getLocks(); - int lock_idx = idx_base_1 - 1; - if (lock_idx < 0) { - LOG_ERROR("Indexing of labels starts from 1"); - return 1; - } - if (lock_idx >= locks.size()) { - LOG_ERROR("Label index is out of range"); - return 1; - } - rcpts[lock_idx] = recipient; - - const Lock& lock = locks[lock_idx]; - LOG_INFO("Found matching label: {}", lock.label); - network.rcpt_idx = lock_idx; - //rcpts[idx_base_1] = recipient; - - if (!conf.library.empty()) - crypto.connectLibrary(conf.library); - - return Decrypt(rdr, lock_idx, conf.out); -} - -int CDocCipher::Decrypt(ToolConf& conf, const std::string& label, const RcptInfo& recipient) +int CDocCipher::Decrypt(ToolConf& conf, const RcptInfo& recipient) { - RecipientInfoIdMap rcpts; + std::map rcpts; ToolCrypto crypto(rcpts); ToolNetwork network(&crypto); network.certs = std::move(conf.accept_certs); @@ -428,39 +386,45 @@ int CDocCipher::Decrypt(ToolConf& conf, const std::string& label, const RcptInfo } LOG_DBG("Reader created"); - // Acquire the locks and get the labels according to the index + // Find lock by label/index/certificate int lock_idx = -1; const vector& locks = rdr->getLocks(); - if (!label.empty()) { + if (!recipient.label.empty()) { LOG_DBG("Looking for lock by label"); for (unsigned int i = 0; i < locks.size(); i++) { - if (locks[i].label == label) { + if (locks[i].label == recipient.label) { lock_idx = i; break; } } + } else if (recipient.lock_idx >= 0) { + if (recipient.lock_idx >= locks.size()) { + LOG_ERROR("Label index is out of range"); + return 1; + } + lock_idx = recipient.lock_idx; } else if (crypto.p11) { bool isRsa; vector cert_bytes; ToolPKCS11* p11 = dynamic_cast(crypto.p11.get()); - int64_t result = p11->getCertificate(cert_bytes, isRsa, (int) recipient.slot, recipient.secret, recipient.key_id, recipient.key_label); + int64_t result = p11->getCertificate(cert_bytes, isRsa, (int) recipient.p11.slot, recipient.secret, recipient.p11.key_id, recipient.p11.key_label); if (result != libcdoc::OK) { - LOG_ERROR("Certificate reading from SC card failed. Key label: {}", recipient.key_label); + LOG_ERROR("Certificate reading from SC card failed. Key label: {}", recipient.p11.key_label); return 1; } LOG_DBG("Got certificate from P11 module"); result = rdr->getLockForCert(cert_bytes); if (result < 0) { - LOG_ERROR("No lock for certificate {}", recipient.key_label); + LOG_ERROR("No lock for certificate {}", recipient.p11.key_label); return 1; } lock_idx = (int) result; } if (lock_idx < 0) { - LOG_ERROR("Lock not found: {}", label); + LOG_ERROR("Lock not found: {}", recipient.label); return 1; } - LOG_INFO("Found matching label: {}", label); + LOG_INFO("Found matching lock: {}", recipient.label); rcpts[lock_idx] = recipient; network.rcpt_idx = lock_idx; @@ -550,10 +514,10 @@ int CDocCipher::Decrypt(const unique_ptr& rdr, unsigned int lock_idx } int -CDocCipher::ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lock_label, const RcptInfo& lock_info, std::vector& recipients) +CDocCipher::ReEncrypt(ToolConf& conf, const RcptInfo& lock_info, std::vector& recipients) { // Decryption part - RecipientInfoIdMap dec_info; + std::map dec_info; ToolCrypto crypto(dec_info); ToolNetwork network(&crypto); network.certs = std::move(conf.accept_certs); @@ -571,26 +535,32 @@ CDocCipher::ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lo const vector& locks = rdr->getLocks(); - int lock_idx = lock_idx_base_1 - 1; - if (lock_idx < 0) { + int lock_idx = -1; + if (!lock_info.label.empty()) { for (unsigned int i = 0; i < locks.size(); i++) { - if (locks[i].label == lock_label) { + if (locks[i].label == lock_info.label) { lock_idx = i; break; } } - if (lock_idx < 0) { - LOG_ERROR("Lock not found: {}", lock_label); + } else if (lock_info.lock_idx >= 0) { + if (lock_info.lock_idx >= locks.size()) { + LOG_ERROR("Label index is out of range"); return 1; } - LOG_INFO("Found matching label: {}", lock_label); + lock_idx = lock_info.lock_idx; } + if (lock_idx < 0) { + LOG_ERROR("Lock not found: {}", lock_info.label); + return 1; + } + dec_info[lock_idx] = lock_info; network.rcpt_idx = lock_idx; // Encryption part - RecipientInfoIdMap crypto_rcpts; + std::map crypto_rcpts; ToolCrypto enc_crypto(crypto_rcpts); ToolNetwork enc_network(&enc_crypto); enc_network.certs = std::move(conf.accept_certs); diff --git a/cdoc/CDocCipher.h b/cdoc/CDocCipher.h index bd3d8333..5563a8fc 100644 --- a/cdoc/CDocCipher.h +++ b/cdoc/CDocCipher.h @@ -30,7 +30,7 @@ namespace libcdoc { -typedef typename std::map RecipientInfoIdMap; +//typedef typename std::map RecipientInfoIdMap; class CDocCipher { @@ -41,10 +41,9 @@ class CDocCipher int Encrypt(ToolConf& conf, std::vector& recipients); - int Decrypt(ToolConf& conf, int idx_base_1, const RcptInfo& recipient); - int Decrypt(ToolConf& conf, const std::string& label, const RcptInfo& recipient); + int Decrypt(ToolConf& conf, const RcptInfo& recipient); - int ReEncrypt(ToolConf& conf, int lock_idx_base_1, const std::string& lock_label, const RcptInfo& lock_info, std::vector& recipients); + int ReEncrypt(ToolConf& conf, const RcptInfo& lock_info, std::vector& recipients); void Locks(const char* file) const; diff --git a/cdoc/RcptInfo.h b/cdoc/RcptInfo.h index c9ecd53f..e4142553 100644 --- a/cdoc/RcptInfo.h +++ b/cdoc/RcptInfo.h @@ -24,10 +24,19 @@ namespace libcdoc { struct RcptInfo { + // PKCS11/NCrypt data + // NB! PIN is stored in secret + struct PKCS11Info { + long slot = 0; + std::vector key_id; + std::string key_label; + }; + enum Type { - // Detect type from container - ANY, + // For decryption (use the lock type) + LOCK, + // For encryption // Certificate from file CERT, // Password from command line @@ -53,12 +62,15 @@ struct RcptInfo { std::vector cert; // Pin or password std::vector secret; - long slot = 0; - std::vector key_id; - std::string key_label; + // PKCS11-specific info + PKCS11Info p11; + + // Keyfile name for automatic labels std::string key_file_name; // ID code for shares server std::string id; + // Lock index + int lock_idx = -1; }; } diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index ad76cd88..45848c15 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -202,10 +202,10 @@ parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, size_t last_char_idx; if (parts[2].starts_with("0x")) { - rcpt.slot = std::stoul(parts[2].substr(2), &last_char_idx, 16); + rcpt.p11.slot = std::stoul(parts[2].substr(2), &last_char_idx, 16); last_char_idx += 2; } else { - rcpt.slot = std::stoul(parts[2], &last_char_idx); + rcpt.p11.slot = std::stoul(parts[2], &last_char_idx); } if (last_char_idx < parts[2].size()) { LOG_ERROR("Slot is not a number"); @@ -215,31 +215,31 @@ parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, if (parts.size() > 3) { rcpt.secret.assign(parts[3].cbegin(), parts[3].cend()); if (parts.size() > 4) { - if (!parts[4].empty()) rcpt.key_id = fromHex(parts[4]); + if (!parts[4].empty()) rcpt.p11.key_id = fromHex(parts[4]); if (parts.size() > 5) - rcpt.key_label = parts[5]; + rcpt.p11.key_label = parts[5]; } } #ifndef NDEBUG // For debugging LOG_DBG("Method: {}", method); - LOG_DBG("Slot: {}", rcpt.slot); + LOG_DBG("Slot: {}", rcpt.p11.slot); if (!rcpt.secret.empty()) { string str(rcpt.secret.cbegin(), rcpt.secret.cend()); LOG_TRACE("Pin: {}", str); } - if (!rcpt.key_id.empty()) - LOG_DBG("Key ID: {}", toHex(rcpt.key_id)); - if (!rcpt.key_label.empty()) - LOG_DBG("Key label: {}", rcpt.key_label); + if (!rcpt.p11.key_id.empty()) + LOG_DBG("Key ID: {}", toHex(rcpt.p11.key_id)); + if (!rcpt.p11.key_label.empty()) + LOG_DBG("Key label: {}", rcpt.p11.key_label); #endif } else if (method == "ncrypt") { // label:ncrypt:key_label[:pin] rcpt.type = RcptInfo::NCRYPT; if (parts.size() > 2) { - rcpt.key_label = parts[2]; + rcpt.p11.key_label = parts[2]; if (parts.size() > 3) { rcpt.secret.assign(parts[3].cbegin(), parts[3].cend()); } @@ -248,13 +248,13 @@ parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, #ifndef NDEBUG // For debugging cout << "Method: " << method << endl; - cout << "Slot: " << rcpt.slot << endl; + cout << "Slot: " << rcpt.p11.slot << endl; if (!rcpt.secret.empty()) cout << "Pin: " << string(rcpt.secret.cbegin(), rcpt.secret.cend()) << endl; - if (!rcpt.key_id.empty()) - cout << "Key ID: " << toHex(rcpt.key_id) << endl; - if (!rcpt.key_label.empty()) - cout << "Key label: " << rcpt.key_label << endl; + if (!rcpt.p11.key_id.empty()) + cout << "Key ID: " << toHex(rcpt.p11.key_id) << endl; + if (!rcpt.p11.key_label.empty()) + cout << "Key label: " << rcpt.p11.key_label << endl; #endif } else if (method == "share") { // label:share:RECIPIENT_ID @@ -539,12 +539,8 @@ static int ParseAndDecrypt(int argc, char *argv[]) } CDocCipher cipher; - RcptInfo rcpt {RcptInfo::ANY, {}, {}, ldata.secret, ldata.slot, ldata.key_id, ldata.key_label}; - if (ldata.lock_idx != -1) { - return cipher.Decrypt(conf, ldata.lock_idx, rcpt); - } else { - return cipher.Decrypt(conf, ldata.lock_label, rcpt); - } + RcptInfo rcpt {.type=RcptInfo::LOCK, .label=ldata.lock_label, .lock_idx=ldata.lock_idx - 1, .secret=ldata.secret, .p11={ldata.slot, ldata.key_id, ldata.key_label}}; + return cipher.Decrypt(conf, rcpt); } static int ParseAndReEncrypt(int argc, char *argv[]) @@ -627,9 +623,9 @@ static int ParseAndReEncrypt(int argc, char *argv[]) } CDocCipher cipher; - RcptInfo rcpt {RcptInfo::ANY, {}, {}, ldata.secret, ldata.slot, ldata.key_id, ldata.key_label}; + RcptInfo rcpt {.type=RcptInfo::LOCK, .label=ldata.lock_label, .lock_idx=ldata.lock_idx, .secret=ldata.secret, .p11={ldata.slot, ldata.key_id, ldata.key_label}}; if (ldata.lock_idx != -1) { - return cipher.ReEncrypt(conf, ldata.lock_idx, ldata.lock_label, rcpt, rcpts); + return cipher.ReEncrypt(conf, rcpt, rcpts); } return true; } diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 3f61fc1d..75015535 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -271,11 +271,7 @@ decrypt(const std::vector& files, const std::string& container, con conf.out = dir; libcdoc::CDocCipher cipher; - if (rcpt.label.empty()) { - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, 1, rcpt), 0); - } else { - BOOST_CHECK_EQUAL(cipher.Decrypt(conf, rcpt.label, rcpt), 0); - } + BOOST_CHECK_EQUAL(cipher.Decrypt(conf, rcpt), 0); fs::path path(dir); for (auto file : files) { @@ -293,7 +289,7 @@ decrypt(const std::vector& files, const std::string& container, con static void decrypt(const std::vector& files, const std::string& container, const std::string& dir, const std::vector& key) { - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, {}, {}, key}; + libcdoc::RcptInfo rcpt {.type=libcdoc::RcptInfo::LOCK, .lock_idx=0, .secret=key}; decrypt(files, container, dir, rcpt); } static int @@ -425,7 +421,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithPasswordAndLabel, DecryptFixture, * utf::depends_on("PasswordUsageWithLabel/EncryptWithPasswordAndLabel") * utf::description("Decrypting a file with password and given label")) { - libcdoc::RcptInfo rcpt {libcdoc::RcptInfo::ANY, Label, {}, std::vector(Password.cbegin(), Password.cend())}; + libcdoc::RcptInfo rcpt {.type=libcdoc::RcptInfo::LOCK, .label=Label, .secret=std::vector(Password.cbegin(), Password.cend())}; decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath, rcpt); } BOOST_AUTO_TEST_SUITE_END() From 4febb5c6f1b919a366442fd6fec6f164683c42ac Mon Sep 17 00:00:00 2001 From: Lauris Kaplinski Date: Tue, 13 Jan 2026 17:19:52 +0200 Subject: [PATCH 04/10] Fix windows build --- test/libcdoc_boost.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 75015535..035b4e35 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -440,7 +440,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithPasswordLabelIndex, DecryptFixture * utf::depends_on("PasswordUsageWithoutLabel/EncryptWithPasswordWithoutLabel") * utf::description("Decrypting a file with password and label index")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath, std::vector(Password.cbegin(), Password.cend())); + decrypt({checkDataFile(sources[0])}, checkTargetFile("PasswordUsageWithoutLabel.cdoc"), tmpDataPath.string(), std::vector(Password.cbegin(), Password.cend())); } BOOST_AUTO_TEST_SUITE_END() @@ -458,7 +458,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithAESKey, DecryptFixture, * utf::depends_on("AESKeyUsage/EncryptWithAESKey") * utf::description("Decrypting a file with with symmetric AES key")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("AESKeyUsage.cdoc"), tmpDataPath, libcdoc::fromHex(AESKey)); + decrypt({checkDataFile(sources[0])}, checkTargetFile("AESKeyUsage.cdoc"), tmpDataPath.string(), libcdoc::fromHex(AESKey)); } BOOST_AUTO_TEST_SUITE_END() @@ -476,7 +476,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKey, DecryptFixture, * utf::depends_on("ECKeyUsage/EncryptWithECKey") * utf::description("Decrypting a file with with EC private key")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("ECKeyUsage.cdoc"), tmpDataPath, fetchDataFile(ECPrivKeyFile)); + decrypt({checkDataFile(sources[0])}, checkTargetFile("ECKeyUsage.cdoc"), tmpDataPath.string(), fetchDataFile(ECPrivKeyFile)); } BOOST_AUTO_TEST_SUITE_END() @@ -494,7 +494,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithRSAKey, DecryptFixture, * utf::depends_on("RSAKeyUsage/EncryptWithRSAKey") * utf::description("Decrypting a file with with RSA private key")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("RSAKeyUsage.cdoc"), tmpDataPath, fetchDataFile(RSAPrivKeyFile)); + decrypt({checkDataFile(sources[0])}, checkTargetFile("RSAKeyUsage.cdoc"), tmpDataPath.string(), fetchDataFile(RSAPrivKeyFile)); } BOOST_AUTO_TEST_SUITE_END() @@ -509,7 +509,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKeyV1, DecryptFixture, * utf::depends_on("CDoc1ECKeySingle/EncryptWithECKeyV1") * utf::description("Decrypting a file in CDoc1 format with with EC private key")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("ECKeyUsageV1.cdoc"), tmpDataPath, fetchDataFile(ECPrivKeyFile)); + decrypt({checkDataFile(sources[0])}, checkTargetFile("ECKeyUsageV1.cdoc"), tmpDataPath.string(), fetchDataFile(ECPrivKeyFile)); } BOOST_AUTO_TEST_SUITE_END() @@ -522,7 +522,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKeyV1Multi, DecryptFixture, * utf::depends_on("CDoc1ECKeyMulti/EncryptWithECKeyV1Multi") * utf::description("Decrypting multiple files in CDoc1 format with with EC private key")) { - decrypt({checkDataFile(sources[0]), checkDataFile(sources[1]), checkDataFile(sources[2])}, checkTargetFile("ECKeyUsageV1Multi.cdoc"), tmpDataPath, fetchDataFile(ECPrivKeyFile)); + decrypt({checkDataFile(sources[0]), checkDataFile(sources[1]), checkDataFile(sources[2])}, checkTargetFile("ECKeyUsageV1Multi.cdoc"), tmpDataPath.string(), fetchDataFile(ECPrivKeyFile)); } BOOST_AUTO_TEST_SUITE_END() @@ -535,7 +535,7 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithRSAKeyV1, DecryptFixture, * utf::depends_on("CDoc1RSAKeySingle/EncryptWithRSAKeyV1") * utf::description("Decrypting a file in CDoc1 format with with RSA private key")) { - decrypt({checkDataFile(sources[0])}, checkTargetFile("RSAKeyUsageV1.cdoc"), tmpDataPath, fetchDataFile(RSAPrivKeyFile)); + decrypt({checkDataFile(sources[0])}, checkTargetFile("RSAKeyUsageV1.cdoc"), tmpDataPath.string(), fetchDataFile(RSAPrivKeyFile)); } BOOST_AUTO_TEST_SUITE_END() From dd2cf6838837297335ca2f081c0f6cdbb8d42d82 Mon Sep 17 00:00:00 2001 From: Lauris Kaplinski Date: Tue, 13 Jan 2026 17:28:32 +0200 Subject: [PATCH 05/10] Fix initializer order for gcc --- cdoc/cdoc-tool.cpp | 4 ++-- test/libcdoc_boost.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index 45848c15..7c81c1a8 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -539,7 +539,7 @@ static int ParseAndDecrypt(int argc, char *argv[]) } CDocCipher cipher; - RcptInfo rcpt {.type=RcptInfo::LOCK, .label=ldata.lock_label, .lock_idx=ldata.lock_idx - 1, .secret=ldata.secret, .p11={ldata.slot, ldata.key_id, ldata.key_label}}; + RcptInfo rcpt {.type=RcptInfo::LOCK, .label=ldata.lock_label, .secret=ldata.secret, .p11={ldata.slot, ldata.key_id, ldata.key_label}, .lock_idx=ldata.lock_idx - 1}; return cipher.Decrypt(conf, rcpt); } @@ -623,7 +623,7 @@ static int ParseAndReEncrypt(int argc, char *argv[]) } CDocCipher cipher; - RcptInfo rcpt {.type=RcptInfo::LOCK, .label=ldata.lock_label, .lock_idx=ldata.lock_idx, .secret=ldata.secret, .p11={ldata.slot, ldata.key_id, ldata.key_label}}; + RcptInfo rcpt {.type=RcptInfo::LOCK, .label=ldata.lock_label, .secret=ldata.secret, .p11={ldata.slot, ldata.key_id, ldata.key_label}, .lock_idx=ldata.lock_idx}; if (ldata.lock_idx != -1) { return cipher.ReEncrypt(conf, rcpt, rcpts); } diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 035b4e35..982ea26f 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -289,7 +289,7 @@ decrypt(const std::vector& files, const std::string& container, con static void decrypt(const std::vector& files, const std::string& container, const std::string& dir, const std::vector& key) { - libcdoc::RcptInfo rcpt {.type=libcdoc::RcptInfo::LOCK, .lock_idx=0, .secret=key}; + libcdoc::RcptInfo rcpt {.type=libcdoc::RcptInfo::LOCK, .secret=key, .lock_idx=0}; decrypt(files, container, dir, rcpt); } static int From 5e4e80f65571cf2e47f1b51acf72dc110a3f0730 Mon Sep 17 00:00:00 2001 From: Lauris Kaplinski Date: Tue, 13 Jan 2026 17:38:37 +0200 Subject: [PATCH 06/10] Use again absolute paths for tests --- test/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1e9f06c1..78f89cac 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,6 +3,10 @@ add_executable(unittests ../cdoc/CDocCipher.cpp ../cdoc/Crypto.cpp) +target_compile_definitions(unittests PRIVATE + DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" +) + target_link_libraries(unittests OpenSSL::SSL cdoc @@ -10,7 +14,7 @@ target_link_libraries(unittests add_test(NAME runtest COMMAND ${CMAKE_CURRENT_BINARY_DIR}/unittests --build_info=YES --logger=HRF,all,stdout - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test + WORKING_DIRECTORY $ ) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) From bb66be55ced8e6a9bf84f75ec3d844de18c27ddb Mon Sep 17 00:00:00 2001 From: Lauris Kaplinski Date: Tue, 13 Jan 2026 18:02:19 +0200 Subject: [PATCH 07/10] Create test tmp path if not exist --- test/CMakeLists.txt | 6 +----- test/libcdoc_boost.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 78f89cac..1e9f06c1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,10 +3,6 @@ add_executable(unittests ../cdoc/CDocCipher.cpp ../cdoc/Crypto.cpp) -target_compile_definitions(unittests PRIVATE - DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" -) - target_link_libraries(unittests OpenSSL::SSL cdoc @@ -14,7 +10,7 @@ target_link_libraries(unittests add_test(NAME runtest COMMAND ${CMAKE_CURRENT_BINARY_DIR}/unittests --build_info=YES --logger=HRF,all,stdout - WORKING_DIRECTORY $ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test ) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 982ea26f..93e95350 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -101,6 +101,14 @@ class FixtureBase max_filesize = std::stoull(utf::framework::master_test_suite().argv[i]); } } + if (!fs::exists(testDataPath)) { + std::cerr << "Path " << testDataPath << " does not exist!" << std::endl; + ::exit(1); + } + tmpDataPath = fs::path(DATA_DIR) / "tmp"; + if (!fs::exists(tmpDataPath)) { + fs::create_directories(tmpDataPath); + } } /** @@ -147,7 +155,7 @@ class FixtureBase } fs::path testDataPath = DATA_DIR; - fs::path tmpDataPath = fs::path(DATA_DIR) / "tmp"; + fs::path tmpDataPath; fs::path sourceFilePath; fs::path sourceFilePath2; fs::path sourceFilePath3; From 0cab1cb98077067a32a55577a1be683fe5e4a1d3 Mon Sep 17 00:00:00 2001 From: lauris71 Date: Wed, 14 Jan 2026 13:17:19 +0200 Subject: [PATCH 08/10] Apply suggestions from code review Co-authored-by: Raul Metsma --- cdoc/CDocCipher.cpp | 8 ++++---- cdoc/CDocCipher.h | 1 - cdoc/cdoc-tool.cpp | 4 ++-- test/libcdoc_boost.cpp | 21 ++++++++++++++------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/cdoc/CDocCipher.cpp b/cdoc/CDocCipher.cpp index e93d5db1..b1f3230d 100644 --- a/cdoc/CDocCipher.cpp +++ b/cdoc/CDocCipher.cpp @@ -66,7 +66,7 @@ struct ToolWin : public libcdoc::WinBackend { result_t connectToKey(int idx, bool priv) { if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - libcdoc::RcptInfo rcpt = rcpts.at(idx); + const libcdoc::RcptInfo &rcpt = rcpts.at(idx); return useKey(rcpt.p11.key_label, std::string(rcpt.secret.cbegin(), rcpt.secret.cend())); } }; @@ -99,7 +99,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t decryptRSA(std::vector& dst, const std::vector &data, bool oaep, unsigned int idx) override final { if (p11) return p11->decryptRSA(dst, data, oaep, idx); if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - libcdoc::RcptInfo rcpt = rcpts.at(idx); + const libcdoc::RcptInfo &rcpt = rcpts.at(idx); if (rcpt.secret.empty()) return libcdoc::CRYPTO_ERROR; const uint8_t *p = rcpt.secret.data(); @@ -131,7 +131,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t deriveECDH1(std::vector& dst, const std::vector &public_key, unsigned int idx) override final { if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - libcdoc::RcptInfo rcpt = rcpts.at(idx); + const libcdoc::RcptInfo &rcpt = rcpts.at(idx); if (rcpt.secret.empty()) return libcdoc::CRYPTO_ERROR; const uint8_t *p = rcpt.secret.data(); @@ -184,7 +184,7 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t getSecret(std::vector& secret, unsigned int idx) override final { if (!rcpts.contains(idx)) return libcdoc::CRYPTO_ERROR; - libcdoc::RcptInfo rcpt = rcpts.at(idx); + const libcdoc::RcptInfo &rcpt = rcpts.at(idx); secret = rcpt.secret; return secret.empty() ? INVALID_PARAMS : libcdoc::OK; } diff --git a/cdoc/CDocCipher.h b/cdoc/CDocCipher.h index 5563a8fc..42b76cfb 100644 --- a/cdoc/CDocCipher.h +++ b/cdoc/CDocCipher.h @@ -30,7 +30,6 @@ namespace libcdoc { -//typedef typename std::map RecipientInfoIdMap; class CDocCipher { diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index 7c81c1a8..080533de 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -592,7 +592,7 @@ static int ParseAndReEncrypt(int argc, char *argv[]) if (!conf.gen_label) { // If labels must not be generated then is there any Recipient without provided label? - auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.label.empty();}) }; + auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](const libcdoc::RcptInfo &rcpt) -> bool {return rcpt.label.empty();}) }; if (rcpt_wo_label != rcpts.cend()) { if (rcpts.size() > 1) { LOG_ERROR("Not all Recipients have label"); @@ -615,7 +615,7 @@ static int ParseAndReEncrypt(int argc, char *argv[]) // CDOC1 is supported only for encryption with certificate. if (conf.cdocVersion == 1) { - auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; + auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](const libcdoc::RcptInfo &rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; if (rcpt_type_non_cert != rcpts.cend()) { LOG_ERROR("CDOC version 1 container can be used for encryption with certificate only."); return 1; diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 93e95350..78e3ce4a 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -418,7 +418,8 @@ BOOST_AUTO_TEST_SUITE_END() // CDoc2 password and label BOOST_AUTO_TEST_SUITE(PasswordUsageWithLabel) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordAndLabel, EncryptFixture, * utf::description("Encrypting a file with password and given label")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordAndLabel, EncryptFixture, + * utf::description("Encrypting a file with password and given label")) { std::vector rcpts { {libcdoc::RcptInfo::PASSWORD, Label, {}, std::vector(Password.cbegin(), Password.cend())} @@ -437,7 +438,8 @@ BOOST_AUTO_TEST_SUITE_END() // CDoc2 password and label BOOST_AUTO_TEST_SUITE(PasswordUsageWithoutLabel) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordWithoutLabel, EncryptFixture, * utf::description("Encrypting a file with password and without label")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithPasswordWithoutLabel, EncryptFixture, + * utf::description("Encrypting a file with password and without label")) { std::vector rcpts { {libcdoc::RcptInfo::PASSWORD, {}, {}, std::vector(Password.cbegin(), Password.cend())} @@ -455,7 +457,8 @@ BOOST_AUTO_TEST_SUITE_END() // CDoc2 AES key BOOST_AUTO_TEST_SUITE(AESKeyUsage) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithAESKey, EncryptFixture, * utf::description("Encrypting a file with symmetric AES key")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithAESKey, EncryptFixture, + * utf::description("Encrypting a file with symmetric AES key")) { std::vector rcpts { {libcdoc::RcptInfo::SKEY, {}, {}, libcdoc::fromHex(AESKey)} @@ -473,7 +476,8 @@ BOOST_AUTO_TEST_SUITE_END() // CDoc2 EC public/private key BOOST_AUTO_TEST_SUITE(ECKeyUsage) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKey, EncryptFixture, * utf::description("Encrypting a file with EC key")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKey, EncryptFixture, + * utf::description("Encrypting a file with EC key")) { std::vector rcpts { {libcdoc::RcptInfo::PKEY, {}, {}, fetchDataFile(ECPubKeyFile)} @@ -491,7 +495,8 @@ BOOST_AUTO_TEST_SUITE_END() // CDoc2 RSA public/private key BOOST_AUTO_TEST_SUITE(RSAKeyUsage) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithRSAKey, EncryptFixture, * utf::description("Encrypting a file with RSA key")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithRSAKey, EncryptFixture, + * utf::description("Encrypting a file with RSA key")) { std::vector rcpts { {libcdoc::RcptInfo::PKEY, {}, {}, fetchDataFile(RSAPubKeyFile)} @@ -509,7 +514,8 @@ BOOST_AUTO_TEST_SUITE_END() // CDoc1 tests BOOST_AUTO_TEST_SUITE(CDoc1ECKeySingle) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKeyV1, EncryptFixture, * utf::description("Encrypting a file with EC key in CDoc1 format")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKeyV1, EncryptFixture, + * utf::description("Encrypting a file with EC key in CDoc1 format")) { encryptV1({checkDataFile(sources[0])}, formTargetFile("ECKeyUsageV1.cdoc"), fetchDataFile(ECCertFile)); } @@ -522,7 +528,8 @@ BOOST_FIXTURE_TEST_CASE_WITH_DECOR(DecryptWithECKeyV1, DecryptFixture, BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(CDoc1ECKeyMulti) -BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKeyV1Multi, EncryptFixture, * utf::description("Encrypting multiple files with EC key in CDoc1 format")) +BOOST_FIXTURE_TEST_CASE_WITH_DECOR(EncryptWithECKeyV1Multi, EncryptFixture, + * utf::description("Encrypting multiple files with EC key in CDoc1 format")) { encryptV1({checkDataFile(sources[0]), checkDataFile(sources[1]), checkDataFile(sources[2])}, formTargetFile("ECKeyUsageV1Multi.cdoc"), fetchDataFile(ECCertFile)); } From 0da1fd80dd02745b866f1ee4bfd6a6159db9eb5b Mon Sep 17 00:00:00 2001 From: lauris71 Date: Wed, 14 Jan 2026 14:06:16 +0200 Subject: [PATCH 09/10] Update cdoc/cdoc-tool.cpp Co-authored-by: Raul Metsma --- cdoc/cdoc-tool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index 080533de..ff049a85 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -325,7 +325,7 @@ static int ParseAndEncrypt(int argc, char *argv[]) } if (!conf.gen_label) { // If labels must not be generated then is there any Recipient without provided label? - auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.label.empty();}) }; + auto rcpt_wo_label{ find_if(rcpts.cbegin(), rcpts.cend(), [](const libcdoc::RcptInfo &rcpt) -> bool {return rcpt.label.empty();}) }; if (rcpt_wo_label != rcpts.cend()) { if (rcpts.size() > 1) { LOG_ERROR("Not all Recipients have label"); From 75d1101d6bc7638226dd1f28bc7f975717eebf13 Mon Sep 17 00:00:00 2001 From: lauris71 Date: Wed, 14 Jan 2026 14:06:27 +0200 Subject: [PATCH 10/10] Update cdoc/cdoc-tool.cpp Co-authored-by: Raul Metsma --- cdoc/cdoc-tool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index ff049a85..c00495fb 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -352,7 +352,7 @@ static int ParseAndEncrypt(int argc, char *argv[]) // CDOC1 is supported only for encryption with certificate. if (conf.cdocVersion == 1) { - auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](std::vector::const_reference rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; + auto rcpt_type_non_cert{ find_if(rcpts.cbegin(), rcpts.cend(), [](const libcdoc::RcptInfo &rcpt) -> bool {return rcpt.type != RcptInfo::CERT;}) }; if (rcpt_type_non_cert != rcpts.cend()) { LOG_ERROR("CDOC version 1 container can be used for encryption with certificate only."); return 1;