diff --git a/cdoc/CDoc.cpp b/cdoc/CDoc.cpp index 679ddfc1..2fac95f4 100644 --- a/cdoc/CDoc.cpp +++ b/cdoc/CDoc.cpp @@ -56,6 +56,7 @@ static constexpr Result results[] = { {HASH_MISMATCH, "Hash mismatch"}, {CONFIGURATION_ERROR, "Configuration error"}, {NOT_FOUND, "Object not found"}, + {INTERNAL_ERROR, "Internal error"}, {UNSPECIFIED_ERROR, "Unspecified error"}, }; diff --git a/cdoc/CDoc.h b/cdoc/CDoc.h index 235d39a3..234127e7 100644 --- a/cdoc/CDoc.h +++ b/cdoc/CDoc.h @@ -119,6 +119,10 @@ enum { * @brief Object not found */ NOT_FOUND = -116, + /** + * @brief Internal error in libcdoc logic + */ + INTERNAL_ERROR = -117, /** * @brief Unspecified error */ diff --git a/cdoc/CDocCipher.cpp b/cdoc/CDocCipher.cpp index 9f445895..ed9096d3 100644 --- a/cdoc/CDocCipher.cpp +++ b/cdoc/CDocCipher.cpp @@ -41,54 +41,84 @@ using namespace std; using namespace libcdoc; +struct CipherInfo { + enum Mode { + ENCRYPT, + DECRYPT + }; + /* Current mode (encrypt/decrypt) */ + Mode mode; + /* Encryption recipients */ + const std::vector& enc_rcpts; + /* Decryption recipient */ + const RcptInfo& dec_rcpt; + + CipherInfo(Mode m, const std::vector& enc, const RcptInfo& dec) : mode(m), enc_rcpts(enc), dec_rcpt(dec) {} + const libcdoc::RcptInfo* getRcpt(unsigned int lock_idx) const { + if (mode == ENCRYPT) { + if (lock_idx >= enc_rcpts.size()) return nullptr; + if (enc_rcpts[lock_idx].lock_idx != lock_idx) return nullptr; + return &enc_rcpts[lock_idx]; + } else { + if (dec_rcpt.lock_idx != lock_idx) return nullptr; + return &dec_rcpt; + } + } +}; + struct ToolPKCS11 : public libcdoc::PKCS11Backend { - const std::vector& rcpts; + /* Shared cipher info */ + const CipherInfo& c_info; - ToolPKCS11(const std::string& library, const std::vector& vec) : libcdoc::PKCS11Backend(library), rcpts(vec) {} + ToolPKCS11(const std::string& library, const CipherInfo& info) : PKCS11Backend(library), c_info(info) {} libcdoc::result_t connectToKey(int idx, bool priv) override final { - if (idx >= rcpts.size()) idx = 0; - const libcdoc::RcptInfo& rcpt = rcpts[idx]; + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; if (!priv) { - return useSecretKey(rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); + return useSecretKey(long(rcpt->p11.slot), rcpt->secret, rcpt->p11.key_id, rcpt->p11.key_label); } else { - return usePrivateKey(rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); + return usePrivateKey(long(rcpt->p11.slot), rcpt->secret, rcpt->p11.key_id, rcpt->p11.key_label); } } }; #ifdef _WIN32 struct ToolWin : public libcdoc::WinBackend { - const std::vector& rcpts; + /* Shared cipher info */ + const CipherInfo& c_info; - ToolWin(const std::string& provider, const std::vector& vec) : libcdoc::WinBackend(provider), rcpts(vec) {} + ToolWin(const std::string& provider, const CipherInfo& info) : libcdoc::WinBackend(provider), c_info(info) {} result_t connectToKey(int idx, bool priv) { - if (idx >= rcpts.size()) idx = 0; - const libcdoc::RcptInfo& rcpt = rcpts[idx]; - return useKey(rcpt.p11.key_label, std::string(rcpt.secret.cbegin(), rcpt.secret.cend())); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + return useKey(rcpt->p11.key_label, std::string(rcpt->secret.cbegin(), rcpt->secret.cend())); } }; #endif struct ToolCrypto : public libcdoc::CryptoBackend { - const std::vector& rcpts; + /* Shared cipher info */ + const CipherInfo& c_info; + + /* Link to PKCS11 backend if needed */ std::unique_ptr p11; #ifdef _WIN32 + /* Link to NCRYPT backend if needed */ std::unique_ptr ncrypt; #endif - ToolCrypto(const std::vector& recipients) : rcpts(recipients) { - } + ToolCrypto(const CipherInfo& info) : c_info(info) {} bool connectLibrary(const std::string& library) { - p11 = std::make_unique(library, rcpts); + p11 = std::make_unique(library, c_info); return true; } bool connectNCrypt() { #ifdef _WIN32 - ncrypt = std::make_unique("", rcpts); + ncrypt = std::make_unique("", c_info); return true; #else return false; @@ -96,13 +126,16 @@ 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 (idx >= rcpts.size()) idx = 0; - const libcdoc::RcptInfo& rcpt = rcpts[idx]; - if (rcpt.secret.empty()) return libcdoc::CRYPTO_ERROR; - const uint8_t *p = rcpt.secret.data(); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + if (rcpt->isPKCS11()) { + if (!p11) return libcdoc::CRYPTO_ERROR; + return p11->decryptRSA(dst, data, oaep, idx); + } + if (rcpt->secret.empty()) return libcdoc::CRYPTO_ERROR; + const uint8_t *p = rcpt->secret.data(); - auto key = make_unique_ptr(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, rcpt.secret.size())); + auto key = make_unique_ptr(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, rcpt->secret.size())); if (!key) return libcdoc::CRYPTO_ERROR; auto ctx = make_unique_ptr(EVP_PKEY_CTX_new(key.get(), nullptr)); @@ -129,12 +162,13 @@ struct ToolCrypto : public libcdoc::CryptoBackend { } libcdoc::result_t deriveECDH1(std::vector& dst, const std::vector &public_key, unsigned int idx) override final { - if (idx >= rcpts.size()) idx = 0; - const libcdoc::RcptInfo& rcpt = rcpts[idx]; - if (rcpt.secret.empty()) return libcdoc::CRYPTO_ERROR; - const uint8_t *p = rcpt.secret.data(); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + /* This only happens in decryption mode */ + if (rcpt->secret.empty()) return libcdoc::CRYPTO_ERROR; + const uint8_t *p = rcpt->secret.data(); - auto key = make_unique_ptr(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &p, rcpt.secret.size())); + auto key = make_unique_ptr(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &p, rcpt->secret.size())); if (!key) return libcdoc::CRYPTO_ERROR; auto ctx = make_unique_ptr(EVP_PKEY_CTX_new(key.get(), nullptr)); @@ -166,29 +200,49 @@ struct ToolCrypto : public libcdoc::CryptoBackend { libcdoc::result_t deriveConcatKDF(std::vector& dst, const std::vector &publicKey, const std::string &digest, const std::vector &algorithmID, const std::vector &partyUInfo, const std::vector &partyVInfo, unsigned int idx) override final { - if (p11) return p11->deriveConcatKDF(dst, publicKey, digest, algorithmID, partyUInfo, partyVInfo, idx); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + if (rcpt->isPKCS11()) { + if (!p11) return libcdoc::CRYPTO_ERROR; + return p11->deriveConcatKDF(dst, publicKey, digest, algorithmID, partyUInfo, partyVInfo, idx); + } return libcdoc::CryptoBackend::deriveConcatKDF(dst, publicKey, digest, algorithmID, partyUInfo, partyVInfo, idx); } libcdoc::result_t deriveHMACExtract(std::vector& dst, const std::vector &publicKey, const std::vector &salt, unsigned int idx) override final { - if (p11) return p11->deriveHMACExtract(dst, publicKey, salt, idx); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + if (rcpt->isPKCS11()) { + if (!p11) return libcdoc::CRYPTO_ERROR; + return p11->deriveHMACExtract(dst, publicKey, salt, idx); + } return libcdoc::CryptoBackend::deriveHMACExtract(dst, publicKey, salt, idx); } libcdoc::result_t extractHKDF(std::vector& kek, const std::vector& salt, const std::vector& pw_salt, int32_t kdf_iter, unsigned int idx) override { - if (p11) return p11->extractHKDF(kek, salt, pw_salt, kdf_iter, idx); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + if (rcpt->isPKCS11()) { + if (!p11) return libcdoc::CRYPTO_ERROR; + return p11->extractHKDF(kek, salt, pw_salt, kdf_iter, idx); + } return libcdoc::CryptoBackend::extractHKDF(kek, salt, pw_salt, kdf_iter, idx); } libcdoc::result_t getSecret(std::vector& secret, unsigned int idx) override final { - if (idx >= rcpts.size()) idx = 0; - const libcdoc::RcptInfo& rcpt = rcpts[idx]; - secret = rcpt.secret; + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + secret = rcpt->secret; return secret.empty() ? INVALID_PARAMS : libcdoc::OK; } libcdoc::result_t sign(std::vector& dst, HashAlgorithm algorithm, const std::vector &digest, int idx) { - if (p11) return p11->sign(dst, algorithm, digest, idx); + const libcdoc::RcptInfo *rcpt = c_info.getRcpt(idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + if (rcpt->isPKCS11()) { + if (!p11) return libcdoc::CRYPTO_ERROR; + return p11->sign(dst, algorithm, digest, idx); + } return libcdoc::NOT_IMPLEMENTED; } }; @@ -204,9 +258,9 @@ struct ToolNetwork : public libcdoc::NetworkBackend { } libcdoc::result_t getClientTLSCertificate(std::vector& dst) override final { - if (rcpt_idx >= crypto->rcpts.size()) rcpt_idx = 0; - const libcdoc::RcptInfo& rcpt = crypto->rcpts[rcpt_idx]; - return crypto->p11->getCertificate(dst, rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); + const RcptInfo *rcpt = crypto->c_info.getRcpt(rcpt_idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; + return crypto->p11->getCertificate(dst, long(rcpt->p11.slot), rcpt->secret, rcpt->p11.key_id, rcpt->p11.key_label); } libcdoc::result_t getPeerTLSCertificates(std::vector> &dst) override final { @@ -215,7 +269,8 @@ struct ToolNetwork : public libcdoc::NetworkBackend { } libcdoc::result_t signTLS(std::vector& dst, libcdoc::CryptoBackend::HashAlgorithm algorithm, const std::vector &digest) override final { - if (rcpt_idx >= crypto->rcpts.size()) rcpt_idx = 0; + const RcptInfo *rcpt = crypto->c_info.getRcpt(rcpt_idx); + if (!rcpt) return libcdoc::INTERNAL_ERROR; return crypto->p11->sign(dst, algorithm, digest, rcpt_idx); } @@ -256,10 +311,11 @@ 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, const std::vector& recipients) +fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& rcpts, std::vector& recipients) { - int idx = 0; - for (const auto& rcpt : recipients) { + for (auto idx = 0; idx < recipients.size(); idx++) { + auto& rcpt = recipients[idx]; + rcpt.lock_idx = int(idx); // Generate the labels if needed string label; if (!conf.gen_label) label = rcpt.label; @@ -290,7 +346,7 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector val; ToolPKCS11* p11 = dynamic_cast(crypto.p11.get()); - int result = p11->getPublicKey(val, rcpt.p11.slot, rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); + int result = p11->getPublicKey(val, long(rcpt.p11.slot), rcpt.secret, rcpt.p11.key_id, rcpt.p11.key_label); if (result != libcdoc::OK) { LOG_ERROR("No such public key: {}", rcpt.p11.key_label); continue; @@ -320,7 +376,9 @@ fill_recipients_from_rcpt_info(ToolConf& conf, ToolCrypto& crypto, std::vector& recipients) { - ToolCrypto crypto(recipients); + CipherInfo cipher(CipherInfo::ENCRYPT, recipients, {}); + + ToolCrypto crypto(cipher); ToolNetwork network(&crypto); network.certs = std::move(conf.accept_certs); @@ -360,10 +418,11 @@ int CDocCipher::Encrypt(ToolConf& conf, std::vector& recipien return result; } -int CDocCipher::Decrypt(ToolConf& conf, const RcptInfo& recipient) +int CDocCipher::Decrypt(ToolConf& conf, RcptInfo& recipient) { - std::vector r = {recipient}; - ToolCrypto crypto(r); + CipherInfo cipher(CipherInfo::DECRYPT, {}, recipient); + + ToolCrypto crypto(cipher); ToolNetwork network(&crypto); network.certs = std::move(conf.accept_certs); @@ -390,14 +449,14 @@ int CDocCipher::Decrypt(ToolConf& conf, const RcptInfo& recipient) } } else if (recipient.lock_idx >= 0) { if (recipient.lock_idx >= locks.size()) { - LOG_ERROR("Label index is out of range"); + LOG_ERROR("Lock index is out of range"); return 1; } lock_idx = recipient.lock_idx; } else if (crypto.p11) { vector cert_bytes; ToolPKCS11* p11 = dynamic_cast(crypto.p11.get()); - int64_t result = p11->getCertificate(cert_bytes, (int) recipient.p11.slot, recipient.secret, recipient.p11.key_id, recipient.p11.key_label); + int64_t result = p11->getCertificate(cert_bytes, long(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.p11.key_label); return 1; @@ -415,6 +474,7 @@ int CDocCipher::Decrypt(ToolConf& conf, const RcptInfo& recipient) return 1; } LOG_INFO("Found matching lock: {}", recipient.label); + recipient.lock_idx = lock_idx; network.rcpt_idx = lock_idx; return Decrypt(rdr, lock_idx, conf.out); @@ -503,13 +563,14 @@ int CDocCipher::Decrypt(const unique_ptr& rdr, unsigned int lock_idx } int -CDocCipher::ReEncrypt(ToolConf& conf, const RcptInfo& dec_info, std::vector& enc_info) +CDocCipher::ReEncrypt(ToolConf& conf, RcptInfo& dec_info, std::vector& enc_info) { - // Decryption part - std::vector rcpt_list = {dec_info}; - ToolCrypto crypto(rcpt_list); + /* First we decrypt FMK, then write recipients */ + CipherInfo cipher(CipherInfo::DECRYPT, enc_info, dec_info); + + ToolCrypto crypto(cipher); ToolNetwork network(&crypto); - network.certs = std::move(conf.accept_certs); + network.certs = conf.accept_certs; if (!conf.library.empty()) { crypto.connectLibrary(conf.library); @@ -538,42 +599,42 @@ CDocCipher::ReEncrypt(ToolConf& conf, const RcptInfo& dec_info, std::vector cert_bytes; + ToolPKCS11* p11 = dynamic_cast(crypto.p11.get()); + int64_t result = p11->getCertificate(cert_bytes, long(dec_info.p11.slot), dec_info.secret, dec_info.p11.key_id, dec_info.p11.key_label); + if (result != libcdoc::OK) { + LOG_ERROR("Certificate reading from SC card failed. Key label: {}", dec_info.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 {}", dec_info.p11.key_label); + return 1; + } + lock_idx = (int) result; } if (lock_idx < 0) { LOG_ERROR("Lock not found: {}", dec_info.label); return 1; } - + dec_info.lock_idx = lock_idx; network.rcpt_idx = lock_idx; - // Encryption part - ToolCrypto enc_crypto(enc_info); - ToolNetwork enc_network(&enc_crypto); - enc_network.certs = std::move(conf.accept_certs); - - if (!conf.library.empty()) { - enc_crypto.connectLibrary(conf.library); - } - for (const auto& rcpt : enc_info) { - if (rcpt.type == RcptInfo::NCRYPT) { - enc_crypto.connectNCrypt(); - break; - } - } - vector rcpts; - fill_recipients_from_rcpt_info(conf, enc_crypto, rcpts, enc_info); + fill_recipients_from_rcpt_info(conf, crypto, rcpts, enc_info); if (rcpts.empty()) { LOG_ERROR("No key for encryption was found"); return 1; } - unique_ptr wrtr(CDocWriter::createWriter(conf.cdocVersion, conf.out, &conf, &enc_crypto, &enc_network)); + unique_ptr wrtr(CDocWriter::createWriter(conf.cdocVersion, conf.out, &conf, &crypto, &network)); // Begin vector fmk; - LOG_DBG("Fetching FMK, idx=", lock_idx); + LOG_DBG("Fetching FMK, idx={}", lock_idx); int64_t result = rdr->getFMK(fmk, lock_idx); LOG_DBG("Got FMK"); if (result != libcdoc::OK) { @@ -593,6 +654,10 @@ CDocCipher::ReEncrypt(ToolConf& conf, const RcptInfo& dec_info, std::vectorgetLastErrorStr()); return 1; } + + /* Now switch to encryption */ + cipher.mode = CipherInfo::ENCRYPT; + result = wrtr->beginEncryption(); if (result != libcdoc::OK) { LOG_ERROR("Error starting encryption: {} {}", result, wrtr->getLastErrorStr()); @@ -650,7 +715,7 @@ CDocCipher::ReEncrypt(ToolConf& conf, const RcptInfo& dec_info, std::vector rdr(CDocReader::createReader(file, nullptr, nullptr, nullptr)); if (!rdr) { diff --git a/cdoc/CDocCipher.h b/cdoc/CDocCipher.h index 92bcc079..1cb49457 100644 --- a/cdoc/CDocCipher.h +++ b/cdoc/CDocCipher.h @@ -38,17 +38,17 @@ class CDOC_EXPORT CDocCipher CDocCipher(const CDocCipher&) = delete; CDocCipher(CDocCipher&&) = delete; - int Encrypt(ToolConf& conf, std::vector& recipients); + static int Encrypt(ToolConf& conf, std::vector& recipients); - int Decrypt(ToolConf& conf, const RcptInfo& recipient); + static int Decrypt(ToolConf& conf, RcptInfo& recipient); - int ReEncrypt(ToolConf& conf, const RcptInfo& lock_info, std::vector& recipients); + static int ReEncrypt(ToolConf& conf, RcptInfo& lock_info, std::vector& recipients); - void Locks(const char* file) const; + static void Locks(const char* file); private: - int writer_push(CDocWriter& writer, const std::vector& keys, const std::vector& files); - int Decrypt(const std::unique_ptr& rdr, unsigned int lock_idx, const std::string& base_path); + static int writer_push(CDocWriter& writer, const std::vector& keys, const std::vector& files); + static int Decrypt(const std::unique_ptr& rdr, unsigned int lock_idx, const std::string& base_path); }; } diff --git a/cdoc/PKCS11Backend.cpp b/cdoc/PKCS11Backend.cpp index d69e7428..385d5bb2 100644 --- a/cdoc/PKCS11Backend.cpp +++ b/cdoc/PKCS11Backend.cpp @@ -113,7 +113,7 @@ libcdoc::PKCS11Backend::Private::login(int slot, const std::vector& pin LOG_DBG("PKCS11:C_Login CANCELED"); break; default: - LOG_DBG("PKCS11:C_Login {}", result); + LOG_DBG("PKCS11:C_Login {}", result); f->C_CloseSession(session); session = CK_INVALID_HANDLE; return PKCS11_ERROR; @@ -296,7 +296,10 @@ libcdoc::PKCS11Backend::useSecretKey(int slot, const std::vector& pin, } std::vector handles = d->findObjects(d->session, CKO_SECRET_KEY, id, label, nullptr); LOG_DBG("PKCS11: useSecretKey id={}; label={}; found {} keys", toHex(id), label, handles.size()); - if (handles.empty() || (handles.size() != 1)) return CRYPTO_ERROR; + if (handles.empty() || (handles.size() != 1)) { + d->logout(); + return CRYPTO_ERROR; + } d->key = handles[0]; LOG_DBG("PKCS11: useSecretKey Using key {}", d->key); return OK; @@ -312,7 +315,10 @@ libcdoc::PKCS11Backend::usePrivateKey(int slot, const std::vector& pin, } std::vector handles = d->findObjects(d->session, CKO_PRIVATE_KEY, id, label, nullptr); LOG_DBG("PKCS11: usePrivateKey id={}; label={}; found {} keys", toHex(id), label, handles.size()); - if (handles.size() != 1) return CRYPTO_ERROR; + if (handles.size() != 1) { + d->logout(); + return CRYPTO_ERROR; + } d->key = handles[0]; LOG_DBG("PKCS11: usePrivateKey Using key {}", d->key); return OK; @@ -328,13 +334,18 @@ libcdoc::PKCS11Backend::getCertificate(std::vector& val, int slot, cons } std::vector handles = d->findObjects(d->session, CKO_CERTIFICATE, id, label, nullptr); LOG_DBG("PKCS11: getCertificate id={}; label={}; found {} certificates", toHex(id), label, handles.size()); - if (handles.empty() || (handles.size() != 1)) return CRYPTO_ERROR; + if (handles.empty() || (handles.size() != 1)) { + d->logout(); + return CRYPTO_ERROR; + } CK_OBJECT_HANDLE handle = handles[0]; val = d->attribute(d->session, handle, CKA_VALUE); if (val.empty()) { LOG_DBG("PKCS11: getCertificate CKA_VALUE error"); + d->logout(); return CRYPTO_ERROR; } + d->logout(); return OK; } @@ -348,11 +359,15 @@ libcdoc::PKCS11Backend::getPublicKey(std::vector& val, int slot, const } std::vector handles = d->findObjects(d->session, CKO_PUBLIC_KEY, id, label, nullptr); LOG_DBG("PKCS11: usePublicKey id={}; label={}; found {} objects", toHex(id), label, handles.size()); - if (handles.empty() || (handles.size() != 1)) return CRYPTO_ERROR; + if (handles.empty() || (handles.size() != 1)) { + d->logout(); + return CRYPTO_ERROR; + } CK_OBJECT_HANDLE handle = handles[0]; std::vector v = d->attribute(d->session, handle, CKA_KEY_TYPE); if (v.empty()) { LOG_DBG("PKCS11: getValue CKA_KEY_TYPE error"); + d->logout(); return CRYPTO_ERROR; } if (*((CK_KEY_TYPE *) v.data()) != CKK_EC) @@ -360,17 +375,20 @@ libcdoc::PKCS11Backend::getPublicKey(std::vector& val, int slot, const v = d->attribute(d->session, handle, CKA_EC_PARAMS); if (v.empty()) { LOG_DBG("PKCS11: getValue CKA_EC_PARAMS error"); + d->logout(); return CRYPTO_ERROR; } std::vector w = d->attribute(d->session, handle, CKA_EC_POINT); if (w.empty()) { LOG_DBG("PKCS11: getValue CKA_EC_POINT error"); + d->logout(); return CRYPTO_ERROR; } const uint8_t *p = v.data(); EC_GROUP *group = d2i_ECPKParameters(nullptr, &p, v.size()); if (!group) { LOG_DBG("PKCS11: getValue d2i_ECPKParameters error"); + d->logout(); return CRYPTO_ERROR; } EC_POINT *pub_key_point = EC_POINT_new(group); @@ -381,10 +399,11 @@ libcdoc::PKCS11Backend::getPublicKey(std::vector& val, int slot, const EC_KEY_set_public_key(key, pub_key_point); EVP_PKEY *evp_pkey = EVP_PKEY_new(); EVP_PKEY_assign_EC_KEY(evp_pkey, key); - val = Crypto::toPublicKeyDer(evp_pkey); + val = Crypto::toPublicKeyDerLong(evp_pkey); EVP_PKEY_free(evp_pkey); EC_POINT_free(pub_key_point); EC_GROUP_free(group); + d->logout(); return OK; } @@ -544,15 +563,19 @@ libcdoc::PKCS11Backend::sign(std::vector& dst, HashAlgorithm algorithm, data.insert(data.end(), digest.begin(), digest.end()); if(d->f->C_SignInit(d->session, &mech, d->key) != CKR_OK) { + d->logout(); return PKCS11_ERROR; } CK_ULONG size = 0; if(d->f->C_Sign(d->session, CK_BYTE_PTR(data.data()), CK_ULONG(data.size()), nullptr, &size) != CKR_OK) { + d->logout(); return PKCS11_ERROR; } dst.resize(int(size)); if(d->f->C_Sign(d->session, CK_BYTE_PTR(data.data()), CK_ULONG(data.size()), CK_BYTE_PTR(dst.data()), &size) != CKR_OK) { + d->logout(); return PKCS11_ERROR; } + d->logout(); return OK; } diff --git a/cdoc/PKCS11Backend.h b/cdoc/PKCS11Backend.h index b0084ad8..4df96df6 100644 --- a/cdoc/PKCS11Backend.h +++ b/cdoc/PKCS11Backend.h @@ -78,7 +78,9 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend { * * Opens slot, logs in with pin and finds the correct secret key. * Both key id and label have to match unless either one is empty. - * If the key is found, it is loaded internally for subsequent cryptographic operations. + * If the key is found, it is loaded internally for subsequent cryptographic operations and PKCS11 session remains OPEN. + * If the key is not found, the session closed. + * * @param slot a PKCS11 slot to use * @param pin a user pin * @param id the key id or empty vector @@ -91,7 +93,9 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend { * * Opens slot, logs in with pin and finds the correct private key. * Both key id and label have to match unless either one is empty. - * If the key is found, it is loaded internally for subsequent cryptographic operations. + * If the key is found, it is loaded internally for subsequent cryptographic operations and PKCS11 session remains OPEN. + * If the key is not found, the session closed. + * * @param slot a PKCS11 slot to use * @param pin a user pin * @param id the key id @@ -105,6 +109,7 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend { * * Get a certificate value given slot, label and id. * Both key id and label have to match unless either one is empty. + * * @param val a destination container for value * @param slot the slot to use * @param pin the pin code or empty if public @@ -118,6 +123,7 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend { * * Get a public key value given slot, label and id. * Both key id and label have to match unless either one is empty. + * * @param val a destination container for value * @param slot the slot to use * @param pin the pin code or empty if public @@ -133,6 +139,8 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend { * A method to load the correct private/secret key for given capsule or receiver. The subclass implementation should * call either useSecretKey or usePrivateKey with proper pin, PKCS11 label and/or id to actually load the key for subsequent * cryptographic operation. + * On success, the PKCS11 session remains OPEN. + * * @param idx lock or recipient index (0-based) in CDoc container * @param priv whether to connect to private or secret key * @return error code or OK @@ -143,7 +151,7 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend { * * A subclass should overwrite this to inform the backend about the correct padding. * @param idx a lock idx - * @return true if PSS padding is sued + * @return true if PSS padding is used */ virtual result_t usePSS(int idx) {return true;} diff --git a/cdoc/RcptInfo.h b/cdoc/RcptInfo.h index e4142553..60fb0149 100644 --- a/cdoc/RcptInfo.h +++ b/cdoc/RcptInfo.h @@ -27,7 +27,7 @@ struct RcptInfo { // PKCS11/NCrypt data // NB! PIN is stored in secret struct PKCS11Info { - long slot = 0; + int64_t slot = -1; std::vector key_id; std::string key_label; }; @@ -35,7 +35,6 @@ struct RcptInfo { enum Type { // For decryption (use the lock type) LOCK, - // For encryption // Certificate from file CERT, @@ -71,6 +70,9 @@ struct RcptInfo { std::string id; // Lock index int lock_idx = -1; + + bool isPKCS11() const { return p11.slot >= 0; } + bool needPassword() const { return (type == PASSWORD || type == P11_SYMMETRIC || type == P11_PKI) && !secret.empty() && secret[0] == '?'; } }; } diff --git a/cdoc/cdoc-tool.cpp b/cdoc/cdoc-tool.cpp index 21b9e33d..daddb3a3 100644 --- a/cdoc/cdoc-tool.cpp +++ b/cdoc/cdoc-tool.cpp @@ -68,14 +68,14 @@ print_usage(ostream& ofs) ofs << " [label]:p11sk:SLOT:[PIN]:[PKCS11 ID]:[PKCS11 LABEL] - use AES key from PKCS11 module" << endl; ofs << " [label]:p11pk:SLOT:[PIN]:[PKCS11 ID]:[PKCS11 LABEL] - use public key from PKCS11 module" << endl; ofs << " [label]:share:ID - keyshares with given ID (personal code)" << endl; - ofs << " -v1 - creates CDOC1 version container. Supported only for encryption with certificate." << endl; + ofs << " --v1 - creates CDOC1 version container. Supported only for encryption with certificate." << endl; ofs << " --genlabel - Generate machine-readable label." << endl; ofs << endl; ofs << "cdoc-tool decrypt ARGUMENTS FILE [OUTPU_DIR]" << endl; ofs << " Decrypt CDoc container using lock specified by label or number" << endl; ofs << " Supported arguments" << endl; ofs << " --label LABEL - lock label" << endl; - ofs << " --lock-idx INDEX - lock number (1-based)" << endl; + ofs << " --lock-idx INDEX - lock number (1-based)" << endl; ofs << " --pkey PRIVATE_KEY_HEX - hex encoded private key (DER format)" << endl; ofs << " --pfkey PRIVATE_KEY_HEX - private key from file (DER format)" << endl; ofs << " --slot SLOT - PKCS11 slot number" << endl; @@ -123,31 +123,74 @@ load_certs(ToolConf& conf, const std::string& filename) } } +static void +inputSecret(std::vector& secret, std::string_view text) +{ + cout << text; +#ifdef _WIN32 + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode = 0; + GetConsoleMode(hStdin, &mode); + SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT); +#else + termios o {}; + tcgetattr(STDIN_FILENO, &o); + termios n = o; + n.c_lflag &= ~ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, &n); +#endif + string result; + getline(std::cin, result); +#ifdef _WIN32 + SetConsoleMode(hStdin, mode); +#else + tcsetattr(STDIN_FILENO, TCSANOW, &o); + cout << endl; +#endif + secret.assign(result.begin(), result.end()); +} + // Return the number of arguments consumed or error code static int parse_common(ToolConf& conf, int arg_idx, int argc, char *argv[]) { string_view arg(argv[arg_idx]); - if ((arg == "--library") && ((arg_idx + 1) < argc)) { + if (arg == "--library") { + if ((arg_idx + 1) >= argc) return RESULT_USAGE; conf.library = argv[arg_idx + 1]; return 2; - } else if ((arg == "--server") && ((arg_idx + 2) < argc)) { + } else if (arg == "--server") { + if ((arg_idx + 2) >= argc) return RESULT_USAGE; ToolConf::ServerData sdata; sdata.ID = argv[arg_idx + 1]; sdata.url = argv[arg_idx + 2]; conf.servers.push_back(sdata); return 3; - } else if ((arg == "--accept") && ((arg_idx + 1) < argc)) { + } else if (arg == "--accept") { + if ((arg_idx + 1) >= argc) return RESULT_USAGE; load_certs(conf, argv[arg_idx + 1]); return 2; - } else if ((arg == "--conf") && ((arg_idx + 1) < argc)) { + } else if (arg == "--conf") { + if ((arg_idx + 1) >= argc) return RESULT_USAGE; conf.parse(argv[arg_idx + 1]); return 2; - } else if ((arg == "--log-level") && ((arg_idx + 1) < argc)) { + } else if (arg == "--log-level") { + if ((arg_idx + 1) >= argc) return RESULT_USAGE; if (!str2level.contains(argv[arg_idx + 1])) return 0; libcdoc::setLogLevel(str2level[argv[arg_idx + 1]]); return 2; + } else if (arg == "--out") { + if ((arg_idx + 1) >= argc) return RESULT_USAGE; + conf.out = argv[arg_idx + 1]; + arg_idx += 1; + return 2; + } else if ((arg == "-v1") || (arg == "--v1")) { + conf.cdocVersion = 1; + return 1; + } else if (arg == "--genlabel") { + conf.gen_label = true; + return 1; } return 0; } @@ -185,7 +228,7 @@ parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, rcpt.secret = readAllBytes(parts[2]); if (rcpt.secret.empty()) { // Occurs when the file does not exist. readAllBytes already output the error message. - return 1; + return RESULT_ERROR; } filesystem::path key_file(parts[2]); @@ -215,16 +258,18 @@ parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, size_t last_char_idx; if (parts[2].starts_with("0x")) { - rcpt.p11.slot = std::stoul(parts[2].substr(2), &last_char_idx, 16); + rcpt.p11.slot = std::stoll(parts[2].substr(2), &last_char_idx, 16); last_char_idx += 2; } else { - rcpt.p11.slot = std::stoul(parts[2], &last_char_idx); + rcpt.p11.slot = std::stoll(parts[2], &last_char_idx); } if (last_char_idx < parts[2].size()) { LOG_ERROR("Slot is not a number"); return RESULT_USAGE; + } else if ((rcpt.p11.slot < 0) || (rcpt.p11.slot > UINT32_MAX)) { + LOG_ERROR("Slot is out of range"); + return RESULT_USAGE; } - if (parts.size() > 3) { rcpt.secret.assign(parts[3].cbegin(), parts[3].cend()); if (parts.size() > 4) { @@ -283,109 +328,10 @@ parse_rcpt(ToolConf& conf, std::vector& rcpts, int& arg_idx, return 2; } -// -// cdoc-tool encrypt --rcpt RECIPIENT [--rcpt...] --out OUTPUTFILE FILE [FILE...] -// Where RECIPIENT has a format: -// label:cert:CERTIFICATE_HEX -// label:key:SECRET_KEY_HEX -// label:pw:PASSWORD -// label:p11sk:SLOT:[PIN]:[ID]:[LABEL] -// label:p11pk:SLOT:[PIN]:[ID]:[LABEL] -// - -static int ParseAndEncrypt(int argc, char *argv[]) -{ - LOG_INFO("Encrypting"); - - ToolConf conf; - std::vector rcpts; - - // - // Parse all arguments into ToolConf structure - // - int arg_idx = 0; - while (arg_idx < argc) { - int result = parse_common(conf, arg_idx, argc, argv); - if (result < 0) return result; - arg_idx += result; - if (result > 0) continue; - result = parse_rcpt(conf, rcpts, arg_idx, argc, argv); - if (result < 0) return result; - arg_idx += result; - if (result > 0) continue; - - string_view arg(argv[arg_idx]); - if (arg == "--out" && ((arg_idx + 1) < argc)) { - conf.out = argv[arg_idx + 1]; - arg_idx += 1; - } else if (arg == "-v1") { - conf.cdocVersion = 1; - } else if (arg == "--genlabel") { - conf.gen_label = true; - } else if (arg[0] == '-') { - LOG_ERROR("Unknown argument: {}", arg); - return 2; - } else { - conf.input_files.push_back(argv[arg_idx]); - } - arg_idx += 1; - } - - // Validate input parameters - if (rcpts.empty()) { - LOG_ERROR("No recipients"); - return RESULT_USAGE; - } - 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(), [](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"); - } else { - LOG_ERROR("Label not provided"); - } - return 2; - } - } - - if (conf.input_files.empty()) { - LOG_ERROR("No files specified"); - return 2; - } - if (conf.out.empty()) { - LOG_ERROR("No output specified"); - return 2; - } - - if (conf.libraryRequired && conf.library.empty()) { - LOG_ERROR("Cryptographic library is required"); - return 2; - } - - // CDOC1 is supported only for encryption with certificate. - if (conf.cdocVersion == 1) { - 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; - } - } - - CDocCipher cipher; - if (int ret = cipher.Encrypt(conf, rcpts); ret != 0) { - cerr << "Encryption failed"; - return ret; - } else { - cout << "Container " << conf.out << " encrypted successfully" << endl; - } - return 0; -} - struct LockData { string lock_label; int lock_idx = -1; - long slot = -1; + int64_t slot = -1; vector key_id; string key_label; vector secret; @@ -420,9 +366,14 @@ parse_key_data(LockData& ldata, const int& arg_idx, int argc, char *argv[]) if (arg == "--label_idx" || arg == "--lock-idx") { size_t last_char_idx; string str(argv[arg_idx + 1]); - ldata.lock_idx = std::stol(str, &last_char_idx); + try { + ldata.lock_idx = std::stol(str, &last_char_idx); + } catch (...) { + LOG_ERROR("Invalid lock index"); + return RESULT_USAGE; + } if (last_char_idx < str.size()) { - LOG_ERROR("Label index is not a number"); + LOG_ERROR("Lock index is not a number"); return RESULT_USAGE; } if (ldata.lock_idx < 1) { @@ -435,7 +386,6 @@ parse_key_data(LockData& ldata, const int& arg_idx, int argc, char *argv[]) return 2; } else if (arg == "--password" || arg == "--pin") { if ((arg_idx + 1) >= argc) return RESULT_USAGE; - string_view s(argv[arg_idx + 1]); ldata.secret.assign(s.cbegin(), s.cend()); return 2; @@ -453,18 +403,20 @@ parse_key_data(LockData& ldata, const int& arg_idx, int argc, char *argv[]) return 2; } else if (arg == "--slot") { if ((arg_idx + 1) >= argc) return RESULT_USAGE; - string str(argv[arg_idx + 1]); size_t last_char_idx; if (str.starts_with("0x")) { - ldata.slot = std::stol(str.substr(2), &last_char_idx, 16); + ldata.slot = std::stoll(str.substr(2), &last_char_idx, 16); last_char_idx += 2; } else { - ldata.slot = std::stol(str, &last_char_idx); + ldata.slot = std::stoll(str, &last_char_idx); } if (last_char_idx < str.size()) { LOG_ERROR("Slot is not a number"); - return 2; + return RESULT_USAGE; + } else if ((ldata.slot < 0) || (ldata.slot > UINT32_MAX)) { + LOG_ERROR("Slot must be a positive integer"); + return RESULT_USAGE; } return 2; } else if (arg == "--key-id") { @@ -480,31 +432,109 @@ parse_key_data(LockData& ldata, const int& arg_idx, int argc, char *argv[]) return 0; } -static std::string -inputSecret(std::string_view text) +// +// cdoc-tool encrypt --rcpt RECIPIENT [--rcpt...] --out OUTPUTFILE FILE [FILE...] +// Where RECIPIENT has a format: +// label:cert:CERTIFICATE_HEX +// label:key:SECRET_KEY_HEX +// label:pw:PASSWORD +// label:p11sk:SLOT:[PIN]:[ID]:[LABEL] +// label:p11pk:SLOT:[PIN]:[ID]:[LABEL] +// + +static int +validateEncryptionInfo(const ToolConf &conf, std::vector &rcpts) { - cout << text; -#ifdef _WIN32 - HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); - DWORD mode = 0; - GetConsoleMode(hStdin, &mode); - SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT); -#else - termios o {}; - tcgetattr(STDIN_FILENO, &o); - termios n = o; - n.c_lflag &= ~ECHO; - tcsetattr(STDIN_FILENO, TCSANOW, &n); -#endif - string result; - getline(std::cin, result); -#ifdef _WIN32 - SetConsoleMode(hStdin, mode); -#else - tcsetattr(STDIN_FILENO, TCSANOW, &o); - cout << endl; -#endif - return result; + if (rcpts.empty()) { + LOG_ERROR("No recipients given"); + return RESULT_USAGE; + } + 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(), [](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"); + } else { + LOG_ERROR("Label not provided"); + } + return RESULT_USAGE; + } + } + if (conf.out.empty()) { + LOG_ERROR("No output specified"); + return RESULT_USAGE; + } + if (conf.libraryRequired && conf.library.empty()) { + LOG_ERROR("Cryptographic library is required"); + return RESULT_USAGE; + } + // CDOC1 is supported only for encryption with certificate. + if (conf.cdocVersion == 1) { + 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 RESULT_ERROR; + } + } + return RESULT_OK; +} + +static int ParseAndEncrypt(int argc, char *argv[]) +{ + LOG_INFO("Encrypting"); + + ToolConf conf; + std::vector rcpts; + + // + // Parse all arguments into ToolConf structure + // + int arg_idx = 0; + while (arg_idx < argc) { + int result = parse_common(conf, arg_idx, argc, argv); + if (result < 0) return result; + arg_idx += result; + if (result > 0) continue; + result = parse_rcpt(conf, rcpts, arg_idx, argc, argv); + if (result < 0) return result; + arg_idx += result; + if (result > 0) continue; + + if (*argv[arg_idx] == '-') { + LOG_ERROR("Unknown argument: {}", argv[arg_idx]); + return RESULT_USAGE; + } else { + conf.input_files.push_back(argv[arg_idx]); + } + arg_idx += 1; + } + + if (conf.input_files.empty()) { + LOG_ERROR("No files specified"); + return RESULT_USAGE; + } + + if (int result = validateEncryptionInfo(conf, rcpts); result != RESULT_OK) { + return result; + } + + // Ask encryption secrets if needed + for (auto idx = 0; idx < rcpts.size(); idx++) { + libcdoc::RcptInfo& rcpt = rcpts[idx]; + if (rcpt.needPassword()) { + inputSecret(rcpt.secret, rcpt.isPKCS11() ? FORMAT("Enter PIN for recipient {}: ", idx + 1) : FORMAT("Enter password for recipient {}: ", idx + 1)); + } + } + + CDocCipher cipher; + if (int ret = cipher.Encrypt(conf, rcpts); ret != 0) { + cerr << "Encryption failed"; + return ret; + } else { + cout << "Container " << conf.out << " encrypted successfully" << endl; + } + return 0; } // @@ -541,6 +571,7 @@ static int ParseAndDecrypt(int argc, char *argv[]) } arg_idx += 1; } else { + LOG_ERROR("Unknown argument: {}", argv[arg_idx]); return RESULT_USAGE; } } @@ -559,10 +590,9 @@ static int ParseAndDecrypt(int argc, char *argv[]) conf.out = "."; } - // Ask secret if not provided - if (ldata.secret[0] == '?') { - std::string secret = inputSecret("Enter password: "); - ldata.secret.assign(secret.cbegin(), secret.cend()); + // Ask decryption secret if needed + if (!ldata.secret.empty() && ldata.secret[0] == '?') { + inputSecret(ldata.secret, (ldata.slot >= 0) ? "Enter decryption PIN: " : "Enter decryption password: "); } CDocCipher cipher; @@ -597,69 +627,35 @@ static int ParseAndReEncrypt(int argc, char *argv[]) arg_idx += result; if (result > 0) continue; - string_view arg(argv[arg_idx]); - if (arg == "--out" && ((arg_idx + 1) < argc)) { - conf.out = argv[arg_idx + 1]; - arg_idx += 1; - } else if (arg == "-v1") { - conf.cdocVersion = 1; - } else if (arg == "--genlabel") { - conf.gen_label = true; - } else if (argv[arg_idx][0] != '-') { + if (*argv[arg_idx] != '-') { conf.input_files.push_back(argv[arg_idx]); } else { - LOG_ERROR("Unknown argument: {}", arg); + LOG_ERROR("Unknown argument: {}", argv[arg_idx]); return RESULT_USAGE; } arg_idx += 1; } - // Validating the input parameters - int result = ldata.validate(conf); - if (result != RESULT_OK) return result; - - if (rcpts.empty()) { - LOG_ERROR("No recipients"); - return RESULT_USAGE; - } - - 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(), [](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"); - } else { - LOG_ERROR("Label not provided"); - } - return RESULT_USAGE; - } + if (int result = validateEncryptionInfo(conf, rcpts); result != RESULT_OK) { + return result; } - if (conf.out.empty()) { - LOG_ERROR("No output specified"); - return RESULT_USAGE; + if (int result = ldata.validate(conf); result != RESULT_OK) { + return result; } - if (conf.libraryRequired && conf.library.empty()) { - LOG_ERROR("Cryptographic library is required"); - return RESULT_USAGE; + // Ask decryption secret if needed + if (!ldata.secret.empty() && ldata.secret[0] == '?') { + inputSecret(ldata.secret, (ldata.slot >= 0) ? "Enter decryption PIN: " : "Enter decryption password: "); } - - // CDOC1 is supported only for encryption with certificate. - if (conf.cdocVersion == 1) { - 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; + // Ask encryption secrets if needed + for (auto idx = 0; idx < rcpts.size(); idx++) { + libcdoc::RcptInfo& rcpt = rcpts[idx]; + if (rcpt.needPassword()) { + inputSecret(rcpt.secret, rcpt.isPKCS11() ? FORMAT("Enter PIN for recipient {}: ", idx + 1) : FORMAT("Enter password for recipient {}: ", idx + 1)); } } - if ((ldata.lock_idx < 0) && (ldata.lock_label.empty())) { - LOG_ERROR("Lock index or label must be provided"); - return RESULT_USAGE; - } - CDocCipher cipher; 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}; if (int ret = cipher.ReEncrypt(conf, rcpt, rcpts); ret != 0) { @@ -732,7 +728,6 @@ int main(int argc, char *argv[]) } if (retVal == RESULT_USAGE) { - // We print usage information only in case the parse-function returned 2. Value 1 indicates other error. print_usage(cout); } diff --git a/doc/tool.md b/doc/tool.md index 5801e3b9..aa79de75 100644 --- a/doc/tool.md +++ b/doc/tool.md @@ -21,7 +21,7 @@ To re-encrypt a file for a different recipient(s) or with a different encryption ### Options -- `-v1` - generates CDOC ver. 1 format container instead of CDOC ver. 2 container. The option can be used only when encrypting with public-key certificate +- `--v1` - generates CDOC ver. 1 format container instead of CDOC ver. 2 container. The option can be used only when encrypting with public-key certificate (see [Recipients](#Recipients)). In all other cases, CDOC ver. 2 format container is created. Tool gives an error if the option is used with any other encryption method. - `--genlabel` - causes machine-readable label generation for the lock instead of using label provided with `--rcpt` option. The machine-readable label follows the @@ -61,6 +61,7 @@ If the `label` is omitted then the `--genlabel` option must be specified at comm option are provided then depending on encryption method, the `label` may be ignored, but may be also used a part of machine-readable label, like in encrypting with symmetric key and password case. Refer [Appendix D](https://open-eid.github.io/CDOC2/1.1/02_protocol_and_cryptography_spec/appendix_d_keylabel/) section of *CDOC2 container format* specification for examples of machine-readable key-labels. +If '?' is used in place of PIN or PASSWORD the tool asks for the value interactively. ### Examples @@ -116,9 +117,9 @@ Following options are supported: - `--label LABEL` - CDOC container's lock label. Either the label or label's index must be provided. - `--label_idx INDEX` - CDOC container's lock 1-based label index. Either the label or label's index must be provided. - `--slot SLOT` - PKCS11 slot number. Usually 0. -- `--password PASSWORD` - lock's password if the file was encrypted with password. -- `--secret SECRET` - secret phrase (AES key) if the file was encrypted with symmetric key. -- `--pin PIN` - PKCS11 (smart-card's) pin code. +- `--password PASSWORD` - lock's password if the file was encrypted with password. Use '?' to ask for the password interactively. +- `--secret SECRET` - secret phrase (AES key) if the file was encrypted with symmetric key. Use '?' to ask for the secret interactively. +- `--pin PIN` - PKCS11 (smart-card's) pin code. Use '?' to ask for the pin interactively. - `--key-id` - PKCS11 key ID. - `--key-label` - PKCS11 key label. - `--library PKCS11_LIBRARY` - path to the PKCS11 library. Same as in encryption case. @@ -153,6 +154,27 @@ then it is overwritten. --- +## Re-encryption + +Re-encrypting a file decrypts it and then encrypts again for new recipients on-the-fly. This avoids writing the decrypted data to the disk. + +The syntax for re-encrypting an encrypted file is the following: + +```bash +cdoc-tool re-encrypt OPTIONS INPUT_FILE --out OUTPUTFILE +``` + +### Options + +Both decryption and encryption options are supported with the following constraints: + +- Output directory, if specified, is ignored. +- Only single URL can be specified for server. Thus, if re-encrypting by using capsule server base lock to another capsule server recipient, the configuration json should be used. +- Only single PKCS11 library can be specified. Thus it is not possible to re-encrypt from one harware token to another, unless they use the same PKCS11 library. +- All original locks (recipients) will be removed from container and replaced with new ones. + +--- + ## Viewing Locks To view the locks in a container, use the following syntax: