diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8c0acc1b..048d30323 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,7 +50,7 @@ option(WITH_XC_NETWORKING "Include networking code (e.g. for downloading website
option(WITH_XC_BROWSER "Include browser integration with keepassxc-browser." OFF)
option(WITH_XC_YUBIKEY "Include YubiKey support." OFF)
option(WITH_XC_SSHAGENT "Include SSH agent support." OFF)
-option(WITH_XC_KEESHARE "Sharing integration with KeeShare (requires quazip5 for secure containers)" OFF)
+option(WITH_XC_KEESHARE "Sharing integration with KeeShare" OFF)
option(WITH_XC_UPDATECHECK "Include automatic update checks; disable for controlled distributions" ON)
if(UNIX AND NOT APPLE)
option(WITH_XC_FDOSECRETS "Implement freedesktop.org Secret Storage Spec server side API." OFF)
diff --git a/INSTALL.md b/INSTALL.md
index ca2c5ba5c..b25dd38b8 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -102,7 +102,6 @@ These steps place the compiled KeePassXC binary inside the `./build/src/` direct
-DWITH_XC_TOUCHID=[ON|OFF] (macOS Only) Enable/Disable Touch ID unlock (default:OFF)
-DWITH_XC_FDOSECRETS=[ON|OFF] (Linux Only) Enable/Disable Freedesktop.org Secrets Service support (default:OFF)
-DWITH_XC_KEESHARE=[ON|OFF] Enable/Disable KeeShare group synchronization extension (default: OFF)
- -DWITH_XC_KEESHARE_SECURE=[ON|OFF] Enable/Disable KeeShare signed containers, requires libquazip5 (default: OFF)
-DWITH_XC_ALL=[ON|OFF] Enable/Disable compiling all plugins above (default: OFF)
-DWITH_XC_UPDATECHECK=[ON|OFF] Enable/Disable automatic updating checking (requires WITH_XC_NETWORKING) (default: ON)
diff --git a/cmake/FindMinizip.cmake b/cmake/FindMinizip.cmake
new file mode 100644
index 000000000..a3817c960
--- /dev/null
+++ b/cmake/FindMinizip.cmake
@@ -0,0 +1,9 @@
+# MINIZIP_FOUND - Minizip library was found
+# MINIZIP_INCLUDE_DIR - Path to Minizip include dir
+# MINIZIP_LIBRARIES - List of Minizip libraries
+
+find_library(MINIZIP_LIBRARIES NAMES minizip libminizip)
+find_path(MINIZIP_INCLUDE_DIR zip.h PATH_SUFFIXES minizip)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Minizip DEFAULT_MSG MINIZIP_LIBRARIES MINIZIP_INCLUDE_DIR)
diff --git a/cmake/FindQuaZip.cmake b/cmake/FindQuaZip.cmake
deleted file mode 100644
index 2242baca4..000000000
--- a/cmake/FindQuaZip.cmake
+++ /dev/null
@@ -1,24 +0,0 @@
-# QUAZIP_FOUND - QuaZip library was found
-# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir
-# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR)
-# QUAZIP_LIBRARIES - List of QuaZip libraries
-# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers
-
-if(WIN32)
- find_library(QUAZIP_LIBRARIES libquazip5)
- find_path(QUAZIP_INCLUDE_DIR quazip.h PATH_SUFFIXES quazip5)
- find_path(QUAZIP_ZLIB_INCLUDE_DIR zlib.h)
-else()
- find_library(QUAZIP_LIBRARIES
- NAMES quazip5 quazip
- PATHS /usr/lib /usr/lib64 /usr/local/lib
- )
- find_path(QUAZIP_INCLUDE_DIR quazip.h
- PATHS /usr/include /usr/local/include
- PATH_SUFFIXES quazip5 quazip
- )
- find_path(QUAZIP_ZLIB_INCLUDE_DIR zlib.h PATHS /usr/include /usr/local/include)
-endif()
-include(FindPackageHandleStandardArgs)
-set(QUAZIP_INCLUDE_DIRS ${QUAZIP_INCLUDE_DIR} ${QUAZIP_ZLIB_INCLUDE_DIR})
-find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_LIBRARIES QUAZIP_INCLUDE_DIR QUAZIP_ZLIB_INCLUDE_DIR QUAZIP_INCLUDE_DIRS)
diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index dc58e114d..320296028 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -3083,10 +3083,6 @@ Would you like to correct it?
Inactive
-
-
- KeeShare unsigned container
-
KeeShare signed container
@@ -3173,6 +3169,10 @@ Supported extensions are: %1.
+
+
+
+
EditGroupWidgetMain
@@ -6742,18 +6742,6 @@ Kernel: %3 %4
Auto-Type
-
-
-
-
-
-
-
-
-
-
-
-
@@ -7641,6 +7629,10 @@ Please consider generating a new key file.
+
+
+
+
QtIOCompressor
@@ -8243,91 +8235,14 @@ Please consider generating a new key file.
Fingerprint:
-
-
- Signer
-
Generate
-
-
- Import
-
-
-
- Export
-
-
-
- Imported certificates
-
-
-
- Trust
-
-
-
- Ask
-
-
-
- Untrust
-
-
-
- Remove
-
-
-
- Path
-
-
-
- Status
-
Fingerprint
-
-
- Trusted
-
-
-
- Untrusted
-
-
-
- Unknown
-
-
-
- Filetype for KeeShare key
- key.share
-
-
-
- KeeShare key file
-
-
-
- All files
-
-
-
- Select path
-
-
-
- Exporting changed certificate
-
-
-
- The exported certificate is not the same as the one in use. Do you want to export the current certificate?
-
@@ -8352,132 +8267,18 @@ Please consider generating a new key file.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
ShareExport
-
- Overwriting signed share container is not supported - export prevented
-
-
-
- Could not write export container (%1)
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Overwriting unsigned share container is not supported - export prevented
-
-
-
- Could not write export container
-
ShareImport
-
- Not this time
-
-
-
- Never
-
-
-
- Always
-
-
-
- Just this time
-
-
-
- Signed share container are not supported - import prevented
-
-
-
- File is not readable
-
-
-
- Invalid sharing container
-
-
-
- Untrusted import prevented
-
-
-
- Successful signed import
-
-
-
- Unsigned share container are not supported - import prevented
-
-
-
- Successful unsigned import
-
-
-
- File does not exist
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index fc58dfda3..6ca739e85 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -53,7 +53,6 @@ parts:
- -DKEEPASSXC_BUILD_TYPE=Release
- -DWITH_TESTS=OFF
- -DWITH_XC_ALL=ON
- - -DWITH_XC_KEESHARE_SECURE=ON
build-packages:
- g++
- libgcrypt20-dev
@@ -71,7 +70,7 @@ parts:
- libsodium-dev
- libargon2-0-dev
- libqrencode-dev
- - libquazip5-dev
+ - libminizip-dev
- asciidoctor
stage-packages:
- dbus
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e9a07073f..1b08910d7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -226,7 +226,7 @@ add_feature_info(Auto-Type WITH_XC_AUTOTYPE "Automatic password typing")
add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)")
add_feature_info(KeePassXC-Browser WITH_XC_BROWSER "Browser integration with KeePassXC-Browser")
add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent")
-add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare (requires quazip5 for secure containers)")
+add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare")
add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response")
add_feature_info(UpdateCheck WITH_XC_UPDATECHECK "Automatic update checking")
if(UNIX AND NOT APPLE)
diff --git a/src/config-keepassx.h.cmake b/src/config-keepassx.h.cmake
index 6aceaa2a0..53c3f03cb 100644
--- a/src/config-keepassx.h.cmake
+++ b/src/config-keepassx.h.cmake
@@ -18,8 +18,6 @@
#cmakedefine WITH_XC_YUBIKEY
#cmakedefine WITH_XC_SSHAGENT
#cmakedefine WITH_XC_KEESHARE
-#cmakedefine WITH_XC_KEESHARE_INSECURE
-#cmakedefine WITH_XC_KEESHARE_SECURE
#cmakedefine WITH_XC_UPDATECHECK
#cmakedefine WITH_XC_TOUCHID
#cmakedefine WITH_XC_FDOSECRETS
diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp
index 61c8cb6e2..59ddf9e30 100644
--- a/src/core/Tools.cpp
+++ b/src/core/Tools.cpp
@@ -92,12 +92,8 @@ namespace Tools
#ifdef WITH_XC_SSHAGENT
extensions += "\n- " + QObject::tr("SSH Agent");
#endif
-#if defined(WITH_XC_KEESHARE_SECURE) && defined(WITH_XC_KEESHARE_INSECURE)
- extensions += "\n- " + QObject::tr("KeeShare (signed and unsigned sharing)");
-#elif defined(WITH_XC_KEESHARE_SECURE)
- extensions += "\n- " + QObject::tr("KeeShare (only signed sharing)");
-#elif defined(WITH_XC_KEESHARE_INSECURE)
- extensions += "\n- " + QObject::tr("KeeShare (only unsigned sharing)");
+#ifdef WITH_XC_KEESHARE
+ extensions += "\n- " + QObject::tr("KeeShare");
#endif
#ifdef WITH_XC_YUBIKEY
extensions += "\n- " + QObject::tr("YubiKey");
diff --git a/src/keeshare/CMakeLists.txt b/src/keeshare/CMakeLists.txt
index af4bc61a8..9fcc55dc2 100644
--- a/src/keeshare/CMakeLists.txt
+++ b/src/keeshare/CMakeLists.txt
@@ -1,8 +1,4 @@
if(WITH_XC_KEESHARE)
- set(WITH_XC_KEESHARE_INSECURE ON PARENT_SCOPE)
-
- include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
-
set(keeshare_SOURCES
SettingsPageKeeShare.cpp
SettingsWidgetKeeShare.cpp
@@ -15,23 +11,12 @@ if(WITH_XC_KEESHARE)
ShareImport.cpp
ShareExport.cpp
ShareObserver.cpp
- Signature.cpp
- )
+ )
+
+ find_package(Minizip REQUIRED)
add_library(keeshare STATIC ${keeshare_SOURCES})
- target_link_libraries(keeshare PUBLIC Qt5::Core Qt5::Widgets ${BOTAN2_LIBRARIES})
-
- # Try to find libquazip5, if found, enable secure sharing
- find_package(QuaZip)
- if(QUAZIP_FOUND)
- set(WITH_XC_KEESHARE_SECURE ON PARENT_SCOPE)
- target_include_directories(keeshare SYSTEM PRIVATE ${QUAZIP_INCLUDE_DIR})
- target_link_libraries(keeshare PRIVATE ${QUAZIP_LIBRARIES})
- else()
- set(WITH_XC_KEESHARE_SECURE OFF PARENT_SCOPE)
- message(STATUS "KeeShare: Secure container support is DISABLED; quazip library not found")
- endif()
-else(WITH_XC_KEESHARE)
- set(WITH_XC_KEESHARE_INSECURE OFF PARENT_SCOPE)
- set(WITH_XC_KEESHARE_SECURE OFF PARENT_SCOPE)
+ target_link_libraries(keeshare PUBLIC Qt5::Core Qt5::Widgets ${BOTAN2_LIBRARIES} ${ZLIB_LIBRARIES} PRIVATE ${MINIZIP_LIBRARIES})
+ target_include_directories(keeshare SYSTEM PRIVATE ${MINIZIP_INCLUDE_DIR})
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
endif(WITH_XC_KEESHARE)
diff --git a/src/keeshare/KeeShare.cpp b/src/keeshare/KeeShare.cpp
index 7f512c6d9..2dec75502 100644
--- a/src/keeshare/KeeShare.cpp
+++ b/src/keeshare/KeeShare.cpp
@@ -53,7 +53,13 @@ void KeeShare::init(QObject* parent)
KeeShareSettings::Own KeeShare::own()
{
- return KeeShareSettings::Own::deserialize(config()->get(Config::KeeShare_Own).toString());
+ // Read existing own certificate or generate a new one if none available
+ auto own = KeeShareSettings::Own::deserialize(config()->get(Config::KeeShare_Own).toString());
+ if (own.key.isNull()) {
+ own = KeeShareSettings::Own::generate();
+ setOwn(own);
+ }
+ return own;
}
KeeShareSettings::Active KeeShare::active()
@@ -61,16 +67,6 @@ KeeShareSettings::Active KeeShare::active()
return KeeShareSettings::Active::deserialize(config()->get(Config::KeeShare_Active).toString());
}
-KeeShareSettings::Foreign KeeShare::foreign()
-{
- return KeeShareSettings::Foreign::deserialize(config()->get(Config::KeeShare_Foreign).toString());
-}
-
-void KeeShare::setForeign(const KeeShareSettings::Foreign& foreign)
-{
- config()->set(Config::KeeShare_Foreign, KeeShareSettings::Foreign::serialize(foreign));
-}
-
void KeeShare::setActive(const KeeShareSettings::Active& active)
{
config()->set(Config::KeeShare_Active, KeeShareSettings::Active::serialize(active));
@@ -117,16 +113,6 @@ void KeeShare::setReferenceTo(Group* group, const KeeShareSettings::Reference& r
bool KeeShare::isEnabled(const Group* group)
{
const auto reference = KeeShare::referenceOf(group);
-#if !defined(WITH_XC_KEESHARE_SECURE)
- if (reference.path.endsWith(signedContainerFileType(), Qt::CaseInsensitive)) {
- return false;
- }
-#endif
-#if !defined(WITH_XC_KEESHARE_INSECURE)
- if (reference.path.endsWith(unsignedContainerFileType(), Qt::CaseInsensitive)) {
- return false;
- }
-#endif
const auto active = KeeShare::active();
return (reference.isImporting() && active.in) || (reference.isExporting() && active.out);
}
diff --git a/src/keeshare/KeeShare.h b/src/keeshare/KeeShare.h
index d9d580e01..606947da3 100644
--- a/src/keeshare/KeeShare.h
+++ b/src/keeshare/KeeShare.h
@@ -55,12 +55,11 @@ public:
static QString sharingLabel(const Group* group);
static KeeShareSettings::Own own();
- static KeeShareSettings::Active active();
- static KeeShareSettings::Foreign foreign();
- static void setForeign(const KeeShareSettings::Foreign& foreign);
- static void setActive(const KeeShareSettings::Active& active);
static void setOwn(const KeeShareSettings::Own& own);
+ static KeeShareSettings::Active active();
+ static void setActive(const KeeShareSettings::Active& active);
+
static KeeShareSettings::Reference referenceOf(const Group* group);
static void setReferenceTo(Group* group, const KeeShareSettings::Reference& reference);
static QString referenceTypeLabel(const KeeShareSettings::Reference& reference);
diff --git a/src/keeshare/KeeShareSettings.cpp b/src/keeshare/KeeShareSettings.cpp
index 601b05310..4f53fc25f 100644
--- a/src/keeshare/KeeShareSettings.cpp
+++ b/src/keeshare/KeeShareSettings.cpp
@@ -23,8 +23,8 @@
#include "core/Metadata.h"
#include "crypto/Random.h"
#include "gui/DatabaseIcons.h"
-#include "keeshare/Signature.h"
+#include
#include
#include
@@ -261,82 +261,6 @@ namespace KeeShareSettings
return own;
}
- bool ScopedCertificate::operator==(const ScopedCertificate& other) const
- {
- return trust == other.trust && path == other.path && certificate == other.certificate;
- }
-
- bool ScopedCertificate::operator!=(const ScopedCertificate& other) const
- {
- return !operator==(other);
- }
-
- void ScopedCertificate::serialize(QXmlStreamWriter& writer, const ScopedCertificate& scopedCertificate)
- {
- writer.writeAttribute("Path", scopedCertificate.path);
- QString trust = "Ask";
- if (scopedCertificate.trust == KeeShareSettings::Trust::Trusted) {
- trust = "Trusted";
- }
- if (scopedCertificate.trust == KeeShareSettings::Trust::Untrusted) {
- trust = "Untrusted";
- }
- writer.writeAttribute("Trust", trust);
- Certificate::serialize(writer, scopedCertificate.certificate);
- }
-
- ScopedCertificate ScopedCertificate::deserialize(QXmlStreamReader& reader)
- {
- ScopedCertificate scopedCertificate;
- scopedCertificate.path = reader.attributes().value("Path").toString();
- scopedCertificate.trust = KeeShareSettings::Trust::Ask;
- auto trust = reader.attributes().value("Trust").toString();
- if (trust.compare("Trusted", Qt::CaseInsensitive) == 0) {
- scopedCertificate.trust = KeeShareSettings::Trust::Trusted;
- }
- if (trust.compare("Untrusted", Qt::CaseInsensitive) == 0) {
- scopedCertificate.trust = KeeShareSettings::Trust::Untrusted;
- }
- scopedCertificate.certificate = Certificate::deserialize(reader);
- return scopedCertificate;
- }
-
- QString Foreign::serialize(const Foreign& foreign)
- {
- return xmlSerialize([&](QXmlStreamWriter& writer) {
- writer.writeStartElement("Foreign");
- for (const ScopedCertificate& scopedCertificate : foreign.certificates) {
- writer.writeStartElement("Certificate");
- ScopedCertificate::serialize(writer, scopedCertificate);
- writer.writeEndElement();
- }
- writer.writeEndElement();
- });
- }
-
- Foreign Foreign::deserialize(const QString& raw)
- {
- Foreign foreign;
- xmlDeserialize(raw, [&](QXmlStreamReader& reader) {
- while (!reader.error() && reader.readNextStartElement()) {
- if (reader.name() == "Foreign") {
- while (!reader.error() && reader.readNextStartElement()) {
- if (reader.name() == "Certificate") {
- foreign.certificates << ScopedCertificate::deserialize(reader);
- } else {
- qWarning("Unknown Certificates element %s", qPrintable(reader.name().toString()));
- reader.skipCurrentElement();
- }
- }
- } else {
- qWarning("Unknown KeeShareSettings element %s", qPrintable(reader.name().toString()));
- reader.skipCurrentElement();
- }
- }
- });
- return foreign;
- }
-
Reference::Reference()
: type(Inactive)
, uuid(QUuid::createUuid())
@@ -433,31 +357,38 @@ namespace KeeShareSettings
QString Sign::serialize(const Sign& sign)
{
+ if (sign.certificate.isNull()) {
+ return {};
+ }
+
+ // Extract RSA key data to serialize an ssh-rsa public key.
+ // ssh-rsa keys are currently not built into Botan
+ const auto rsaKey = static_cast(sign.certificate.key.data());
+
+ std::vector rsaE(rsaKey->get_e().bytes());
+ rsaKey->get_e().binary_encode(rsaE.data());
+
+ std::vector rsaN(rsaKey->get_n().bytes());
+ rsaKey->get_n().binary_encode(rsaN.data());
+
+ QByteArray rsaKeySerialized;
+ QDataStream stream(&rsaKeySerialized, QIODevice::WriteOnly);
+ stream.writeBytes("ssh-rsa", 7);
+ stream.writeBytes(reinterpret_cast(rsaE.data()), rsaE.size());
+ stream.writeBytes(reinterpret_cast(rsaN.data()), rsaN.size());
+
return xmlSerialize([&](QXmlStreamWriter& writer) {
writer.writeStartElement("Signature");
writer.writeCharacters(sign.signature);
writer.writeEndElement();
writer.writeStartElement("Certificate");
- Certificate::serialize(writer, sign.certificate);
+ writer.writeStartElement("Signer");
+ writer.writeCharacters(sign.certificate.signer);
+ writer.writeEndElement();
+ writer.writeStartElement("Key");
+ writer.writeCharacters(rsaKeySerialized.toBase64());
+ writer.writeEndElement();
writer.writeEndElement();
});
}
-
- Sign Sign::deserialize(const QString& raw)
- {
- Sign sign;
- xmlDeserialize(raw, [&](QXmlStreamReader& reader) {
- while (!reader.error() && reader.readNextStartElement()) {
- if (reader.name() == "Signature") {
- sign.signature = reader.readElementText();
- } else if (reader.name() == "Certificate") {
- sign.certificate = KeeShareSettings::Certificate::deserialize(reader);
- } else {
- qWarning("Unknown Sign element %s", qPrintable(reader.name().toString()));
- reader.skipCurrentElement();
- }
- }
- });
- return sign;
- }
} // namespace KeeShareSettings
diff --git a/src/keeshare/KeeShareSettings.h b/src/keeshare/KeeShareSettings.h
index ad6ca9c5b..b81dc15af 100644
--- a/src/keeshare/KeeShareSettings.h
+++ b/src/keeshare/KeeShareSettings.h
@@ -55,7 +55,6 @@ namespace KeeShareSettings
bool operator!=(const Key& other) const;
bool isNull() const;
- QString privateKey() const;
static void serialize(QXmlStreamWriter& writer, const Key& key);
static Key deserialize(QXmlStreamReader& reader);
@@ -99,42 +98,6 @@ namespace KeeShareSettings
static Own generate();
};
- enum class Trust
- {
- Ask,
- Untrusted,
- Trusted
- };
- struct ScopedCertificate
- {
- QString path;
- Certificate certificate;
- Trust trust;
-
- bool operator==(const ScopedCertificate& other) const;
- bool operator!=(const ScopedCertificate& other) const;
-
- bool isUnknown() const
- {
- return certificate.isNull();
- }
- bool isKnown() const
- {
- return !certificate.isNull();
- }
-
- static void serialize(QXmlStreamWriter& writer, const ScopedCertificate& certificate);
- static ScopedCertificate deserialize(QXmlStreamReader& reader);
- };
-
- struct Foreign
- {
- QList certificates;
-
- static QString serialize(const Foreign& foreign);
- static Foreign deserialize(const QString& raw);
- };
-
struct Sign
{
QString signature;
@@ -146,7 +109,6 @@ namespace KeeShareSettings
}
static QString serialize(const Sign& sign);
- static Sign deserialize(const QString& raw);
};
enum TypeFlag
diff --git a/src/keeshare/SettingsWidgetKeeShare.cpp b/src/keeshare/SettingsWidgetKeeShare.cpp
index 1dcb4ad00..7462aa5f3 100644
--- a/src/keeshare/SettingsWidgetKeeShare.cpp
+++ b/src/keeshare/SettingsWidgetKeeShare.cpp
@@ -33,21 +33,8 @@ SettingsWidgetKeeShare::SettingsWidgetKeeShare(QWidget* parent)
{
m_ui->setupUi(this);
-#if !defined(WITH_XC_KEESHARE_SECURE)
- // Setting does not help the user of Version without signed export
- m_ui->ownCertificateGroupBox->setVisible(false);
-#endif
-
connect(m_ui->ownCertificateSignerEdit, SIGNAL(textChanged(QString)), SLOT(setVerificationExporter(QString)));
-
connect(m_ui->generateOwnCerticateButton, SIGNAL(clicked(bool)), SLOT(generateCertificate()));
- connect(m_ui->importOwnCertificateButton, SIGNAL(clicked(bool)), SLOT(importCertificate()));
- connect(m_ui->exportOwnCertificateButton, SIGNAL(clicked(bool)), SLOT(exportCertificate()));
-
- connect(m_ui->trustImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(trustSelectedCertificates()));
- connect(m_ui->askImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(askSelectedCertificates()));
- connect(m_ui->untrustImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(untrustSelectedCertificates()));
- connect(m_ui->removeImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(removeSelectedCertificates()));
}
SettingsWidgetKeeShare::~SettingsWidgetKeeShare()
@@ -62,46 +49,6 @@ void SettingsWidgetKeeShare::loadSettings()
m_own = KeeShare::own();
updateOwnCertificate();
-
- m_foreign = KeeShare::foreign();
- updateForeignCertificates();
-}
-
-void SettingsWidgetKeeShare::updateForeignCertificates()
-{
- auto headers = QStringList() << tr("Path") << tr("Status");
-#if defined(WITH_XC_KEESHARE_SECURE)
- headers << tr("Signer") << tr("Fingerprint");
-#endif
-
- m_importedCertificateModel.reset(new QStandardItemModel());
- m_importedCertificateModel->setHorizontalHeaderLabels(headers);
-
- for (const auto& scopedCertificate : m_foreign.certificates) {
- QList items;
- items << new QStandardItem(scopedCertificate.path);
-
- switch (scopedCertificate.trust) {
- case KeeShareSettings::Trust::Ask:
- items << new QStandardItem(tr("Ask"));
- break;
- case KeeShareSettings::Trust::Trusted:
- items << new QStandardItem(tr("Trusted"));
- break;
- case KeeShareSettings::Trust::Untrusted:
- items << new QStandardItem(tr("Untrusted"));
- break;
- }
-
-#if defined(WITH_XC_KEESHARE_SECURE)
- items << new QStandardItem(scopedCertificate.isKnown() ? scopedCertificate.certificate.signer : tr("Unknown"));
- items << new QStandardItem(scopedCertificate.certificate.fingerprint());
-#endif
- m_importedCertificateModel->appendRow(items);
- }
-
- m_ui->importedCertificateTableView->setModel(m_importedCertificateModel.data());
- m_ui->importedCertificateTableView->resizeColumnsToContents();
}
void SettingsWidgetKeeShare::updateOwnCertificate()
@@ -119,7 +66,6 @@ void SettingsWidgetKeeShare::saveSettings()
// store changes to the settings in a temporary object and check on the final values
// of this object (similar scheme to Entry) - this way we could validate the settings before save
KeeShare::setOwn(m_own);
- KeeShare::setForeign(m_foreign);
KeeShare::setActive(active);
config()->set(Config::KeeShare_QuietSuccess, m_ui->quietSuccessCheckBox->isChecked());
@@ -137,99 +83,3 @@ void SettingsWidgetKeeShare::generateCertificate()
m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer);
m_ui->ownCertificateFingerprintEdit->setText(m_own.certificate.fingerprint());
}
-
-void SettingsWidgetKeeShare::importCertificate()
-{
- auto defaultDirPath = FileDialog::getLastDir("keeshare_key");
- const auto filetype = tr("key.share", "Filetype for KeeShare key");
- const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files"));
- QString filename = fileDialog()->getOpenFileName(this, tr("Select path"), defaultDirPath, filters);
- if (filename.isEmpty()) {
- return;
- }
- QFile file(filename);
- file.open(QIODevice::ReadOnly);
- QTextStream stream(&file);
- m_own = KeeShareSettings::Own::deserialize(stream.readAll());
- file.close();
- FileDialog::saveLastDir("keeshare_key", filename);
-
- updateOwnCertificate();
-}
-
-void SettingsWidgetKeeShare::exportCertificate()
-{
- if (KeeShare::own() != m_own) {
- auto ans = MessageBox::warning(
- this,
- tr("Exporting changed certificate"),
- tr("The exported certificate is not the same as the one in use. Do you want to export the "
- "current certificate?"),
- MessageBox::Yes | MessageBox::No,
- MessageBox::No);
- if (ans != MessageBox::Yes) {
- return;
- }
- }
- auto defaultDirPath = FileDialog::getLastDir("keeshare_key");
- const auto filetype = tr("key.share", "Filetype for KeeShare key");
- const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files"));
- QString filename = QString("%1.%2").arg(m_own.certificate.signer).arg(filetype);
- filename = fileDialog()->getSaveFileName(this, tr("Select path"), defaultDirPath, filters);
- if (filename.isEmpty()) {
- return;
- }
- QFile file(filename);
- file.open(QIODevice::Truncate | QIODevice::WriteOnly);
- QTextStream stream(&file);
- stream << KeeShareSettings::Own::serialize(m_own);
- stream.flush();
- file.close();
- FileDialog::saveLastDir("keeshare_key", filename);
-}
-
-void SettingsWidgetKeeShare::trustSelectedCertificates()
-{
- const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
- Q_ASSERT(selectionModel);
- for (const auto& index : selectionModel->selectedRows()) {
- m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Trusted;
- }
-
- updateForeignCertificates();
-}
-
-void SettingsWidgetKeeShare::askSelectedCertificates()
-{
- const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
- Q_ASSERT(selectionModel);
- for (const auto& index : selectionModel->selectedRows()) {
- m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Ask;
- }
-
- updateForeignCertificates();
-}
-
-void SettingsWidgetKeeShare::untrustSelectedCertificates()
-{
- const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
- Q_ASSERT(selectionModel);
- for (const auto& index : selectionModel->selectedRows()) {
- m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Untrusted;
- }
-
- updateForeignCertificates();
-}
-
-void SettingsWidgetKeeShare::removeSelectedCertificates()
-{
- auto certificates = m_foreign.certificates;
- const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
- Q_ASSERT(selectionModel);
- for (const auto& index : selectionModel->selectedRows()) {
- certificates.removeOne(m_foreign.certificates[index.row()]);
- }
- m_foreign.certificates = certificates;
-
- updateForeignCertificates();
-}
diff --git a/src/keeshare/SettingsWidgetKeeShare.h b/src/keeshare/SettingsWidgetKeeShare.h
index bb29e8937..fcc920bab 100644
--- a/src/keeshare/SettingsWidgetKeeShare.h
+++ b/src/keeshare/SettingsWidgetKeeShare.h
@@ -50,23 +50,13 @@ private slots:
void setVerificationExporter(const QString& signer);
void generateCertificate();
- void importCertificate();
- void exportCertificate();
-
- void trustSelectedCertificates();
- void askSelectedCertificates();
- void untrustSelectedCertificates();
- void removeSelectedCertificates();
private:
void updateOwnCertificate();
- void updateForeignCertificates();
QScopedPointer m_ui;
KeeShareSettings::Own m_own;
- KeeShareSettings::Foreign m_foreign;
- QScopedPointer m_importedCertificateModel;
};
#endif // KEEPASSXC_SETTINGSWIDGETKEESHARE_H
diff --git a/src/keeshare/SettingsWidgetKeeShare.ui b/src/keeshare/SettingsWidgetKeeShare.ui
index bd0b98a85..48a79d8d3 100644
--- a/src/keeshare/SettingsWidgetKeeShare.ui
+++ b/src/keeshare/SettingsWidgetKeeShare.ui
@@ -6,11 +6,11 @@
0
0
- 378
- 511
+ 425
+ 251
-
+
0
@@ -70,67 +70,55 @@
-
-
-
- 0
- 0
-
-
Own certificate
-
- 10
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Generate new certificate
-
-
- Generate
-
-
-
- -
-
-
- Import existing certificate
-
-
- Import
-
-
-
- -
-
-
- Export own certificate
-
-
- Export
-
-
-
-
+ -
+
+
+ Signer:
+
+
- -
+
-
+
+
+ Generate new certificate
+
+
+ Generate
+
+
+
+ -
+
+
+ Fingerprint:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Signer name field
+
+
+
+ -
Fingerprint
@@ -140,133 +128,6 @@
- -
-
-
- Signer name field
-
-
-
- -
-
-
- Signer:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Fingerprint:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- -
-
-
- Imported certificates
-
-
-
-
-
-
- Known shares
-
-
- QAbstractItemView::NoEditTriggers
-
-
- false
-
-
- false
-
-
- true
-
-
- QAbstractItemView::MultiSelection
-
-
- QAbstractItemView::SelectRows
-
-
- true
-
-
- true
-
-
- false
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Trust selected certificate
-
-
- Trust
-
-
-
- -
-
-
- Ask whether to trust the selected certificate every time
-
-
- Ask
-
-
-
- -
-
-
- Untrust selected certificate
-
-
- Untrust
-
-
-
- -
-
-
- Remove selected certificate
-
-
- Remove
-
-
-
-
-
@@ -289,16 +150,8 @@
enableImportCheckBox
quietSuccessCheckBox
enableExportCheckBox
- generateOwnCerticateButton
- importOwnCertificateButton
- exportOwnCertificateButton
ownCertificateSignerEdit
ownCertificateFingerprintEdit
- trustImportedCertificateButton
- askImportedCertificateButton
- untrustImportedCertificateButton
- removeImportedCertificateButton
- importedCertificateTableView
diff --git a/src/keeshare/ShareExport.cpp b/src/keeshare/ShareExport.cpp
index 31f7fece3..55c4ca711 100644
--- a/src/keeshare/ShareExport.cpp
+++ b/src/keeshare/ShareExport.cpp
@@ -14,23 +14,20 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
#include "ShareExport.h"
-#include "config-keepassx.h"
#include "core/Group.h"
#include "core/Metadata.h"
+#include "crypto/Random.h"
#include "format/KeePass2Writer.h"
#include "gui/Icons.h"
+#include "gui/MessageBox.h"
#include "keeshare/KeeShare.h"
-#include "keeshare/Signature.h"
#include "keys/PasswordKey.h"
#include
-#include
-
-#if defined(WITH_XC_KEESHARE_SECURE)
-#include
-#include
-#endif
+#include
+#include
namespace
{
@@ -64,8 +61,6 @@ namespace
auto* targetDb = new Database();
auto* targetMetadata = targetDb->metadata();
targetMetadata->setRecycleBinEnabled(false);
- auto key = QSharedPointer::create();
- key->addKey(QSharedPointer::create(reference.password));
// Copy the source root as the root of the export database, memory manage the old root node
auto* targetRoot = sourceRoot->clone(Entry::CloneNoFlags, Group::CloneNoFlags);
@@ -86,7 +81,10 @@ namespace
}
}
+ auto key = QSharedPointer::create();
+ key->addKey(QSharedPointer::create(reference.password));
targetDb->setKey(key);
+
auto* obsoleteRoot = targetDb->rootGroup();
targetDb->setRootGroup(targetRoot);
delete obsoleteRoot;
@@ -108,124 +106,106 @@ namespace
return targetDb;
}
- ShareObserver::Result
- intoSignedContainer(const QString& resolvedPath, const KeeShareSettings::Reference& reference, Database* targetDb)
+ bool writeZipFile(void* zf, const QString& fileName, const QByteArray& data)
{
-#if !defined(WITH_XC_KEESHARE_SECURE)
- Q_UNUSED(targetDb);
- Q_UNUSED(resolvedPath);
- return {reference.path,
- ShareObserver::Result::Warning,
- ShareExport::tr("Overwriting signed share container is not supported - export prevented")};
-#else
- QByteArray bytes;
- {
- QBuffer buffer(&bytes);
- buffer.open(QIODevice::WriteOnly);
- KeePass2Writer writer;
- writer.writeDatabase(&buffer, targetDb);
- if (writer.hasError()) {
- qWarning("Serializing export dabase failed: %s.", writer.errorString().toLatin1().data());
- return {reference.path, ShareObserver::Result::Error, writer.errorString()};
- }
- }
- const auto own = KeeShare::own();
- QuaZip zip(resolvedPath);
- zip.setFileNameCodec("UTF-8");
- const bool zipOpened = zip.open(QuaZip::mdCreate);
- if (!zipOpened) {
- ::qWarning("Opening export file failed: %d", zip.getZipError());
- return {reference.path,
- ShareObserver::Result::Error,
- ShareExport::tr("Could not write export container (%1)").arg(zip.getZipError())};
- }
- {
- QuaZipFile file(&zip);
- const auto signatureOpened = file.open(QIODevice::WriteOnly, QuaZipNewInfo(KeeShare::signatureFileName()));
- if (!signatureOpened) {
- ::qWarning("Embedding signature failed: Could not open file to write (%d)", zip.getZipError());
- return {reference.path,
- ShareObserver::Result::Error,
- ShareExport::tr("Could not embed signature: Could not open file to write (%1)")
- .arg(file.getZipError())};
- }
- QTextStream stream(&file);
- KeeShareSettings::Sign sign;
- // TODO: check for false return
- Signature::create(bytes, own.key.key, sign.signature);
- sign.certificate = own.certificate;
- stream << KeeShareSettings::Sign::serialize(sign);
- stream.flush();
- if (file.getZipError() != ZIP_OK) {
- ::qWarning("Embedding signature failed: Could not write file (%d)", zip.getZipError());
- return {
- reference.path,
- ShareObserver::Result::Error,
- ShareExport::tr("Could not embed signature: Could not write file (%1)").arg(file.getZipError())};
- }
- file.close();
- }
- {
- QuaZipFile file(&zip);
- const auto dbOpened = file.open(QIODevice::WriteOnly, QuaZipNewInfo(KeeShare::containerFileName()));
- if (!dbOpened) {
- ::qWarning("Embedding database failed: Could not open file to write (%d)", zip.getZipError());
- return {reference.path,
- ShareObserver::Result::Error,
- ShareExport::tr("Could not embed database: Could not open file to write (%1)")
- .arg(file.getZipError())};
- }
- file.write(bytes);
- if (file.getZipError() != ZIP_OK) {
- ::qWarning("Embedding database failed: Could not write file (%d)", zip.getZipError());
- return {reference.path,
- ShareObserver::Result::Error,
- ShareExport::tr("Could not embed database: Could not write file (%1)").arg(file.getZipError())};
- }
- file.close();
- }
- zip.close();
- return {reference.path};
-#endif
+ zipOpenNewFileInZip64(zf,
+ fileName.toLatin1().data(),
+ nullptr,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_BEST_COMPRESSION,
+ 1);
+ int pos = 0;
+ do {
+ auto len = qMin(data.size() - pos, 8192);
+ zipWriteInFileInZip(zf, data.data() + pos, len);
+ pos += len;
+ } while (pos < data.size());
+
+ zipCloseFileInZip(zf);
+ return true;
}
- ShareObserver::Result
- intoUnsignedContainer(const QString& resolvedPath, const KeeShareSettings::Reference& reference, Database* targetDb)
+ bool signData(const QByteArray& data, const KeeShareSettings::Key& key, QString& signature)
{
-#if !defined(WITH_XC_KEESHARE_INSECURE)
- Q_UNUSED(targetDb);
- Q_UNUSED(resolvedPath);
- return {reference.path,
- ShareObserver::Result::Warning,
- ShareExport::tr("Overwriting unsigned share container is not supported - export prevented")};
-#else
- QFile file(resolvedPath);
- const bool fileOpened = file.open(QIODevice::WriteOnly);
- if (!fileOpened) {
- ::qWarning("Opening export file failed");
- return {reference.path, ShareObserver::Result::Error, ShareExport::tr("Could not write export container")};
- }
- KeePass2Writer writer;
- writer.writeDatabase(&file, targetDb);
- if (writer.hasError()) {
- qWarning("Exporting dabase failed: %s.", writer.errorString().toLatin1().data());
- return {reference.path, ShareObserver::Result::Error, writer.errorString()};
- }
- file.close();
-#endif
- return {reference.path};
- }
+ if (key.key->algo_name() == "RSA") {
+ try {
+ Botan::PK_Signer signer(*key.key, "EMSA3(SHA-256)");
+ signer.update(reinterpret_cast(data.constData()), data.size());
+ auto s = signer.signature(*randomGen()->getRng());
+ auto hex = QByteArray(reinterpret_cast(s.data()), s.size()).toHex();
+ signature = QString("rsa|%1").arg(QString::fromLatin1(hex));
+ return true;
+ } catch (std::exception& e) {
+ qWarning("KeeShare: Failed to sign data: %s", e.what());
+ return false;
+ }
+ }
+ qWarning("Unsupported Public/Private key format");
+ return false;
+ }
} // namespace
ShareObserver::Result ShareExport::intoContainer(const QString& resolvedPath,
const KeeShareSettings::Reference& reference,
const Group* group)
{
- QScopedPointer targetDb(extractIntoDatabase(reference, group));
- const QFileInfo info(resolvedPath);
- if (KeeShare::isContainerType(info, KeeShare::signedContainerFileType())) {
- return intoSignedContainer(resolvedPath, reference, targetDb.data());
+ QFile file(resolvedPath);
+ const bool fileOpened = file.open(QIODevice::WriteOnly);
+ if (!fileOpened) {
+ qWarning("Opening export file failed");
+ return {resolvedPath, ShareObserver::Result::Error, file.errorString()};
}
- return intoUnsignedContainer(resolvedPath, reference, targetDb.data());
+
+ QScopedPointer targetDb(extractIntoDatabase(reference, group));
+ if (resolvedPath.endsWith(".kdbx.share")) {
+ // Write database to memory and sign it
+ QByteArray dbData, signatureData;
+ QBuffer buffer;
+
+ buffer.setBuffer(&dbData);
+ buffer.open(QIODevice::WriteOnly);
+
+ KeePass2Writer writer;
+ if (!writer.writeDatabase(&buffer, targetDb.data())) {
+ qWarning("Serializing export dabase failed: %s.", writer.errorString().toLatin1().data());
+ return {reference.path, ShareObserver::Result::Error, writer.errorString()};
+ }
+
+ buffer.close();
+
+ // Get Own Certificate for signing
+ const auto own = KeeShare::own();
+ Q_ASSERT(!own.isNull());
+
+ // Sign the database data
+ KeeShareSettings::Sign sign;
+ sign.certificate = own.certificate;
+ signData(dbData, own.key, sign.signature);
+
+ signatureData = KeeShareSettings::Sign::serialize(sign).toLatin1();
+
+ auto zf = zipOpen64(resolvedPath.toLatin1().data(), 0);
+ if (!zf) {
+ return {reference.path, ShareObserver::Result::Error, ShareExport::tr("Could not write export container.")};
+ }
+
+ writeZipFile(zf, KeeShare::signatureFileName().toLatin1().data(), signatureData);
+ writeZipFile(zf, KeeShare::containerFileName().toLatin1().data(), dbData);
+
+ zipClose(zf, nullptr);
+ } else {
+ QString error;
+ if (!targetDb->saveAs(resolvedPath, Database::Atomic, {}, &error)) {
+ qWarning("Exporting dabase failed: %s.", error.toLatin1().data());
+ return {resolvedPath, ShareObserver::Result::Error, error};
+ }
+ }
+
+ return {resolvedPath};
}
diff --git a/src/keeshare/ShareImport.cpp b/src/keeshare/ShareImport.cpp
index 309ff29af..71d02b74f 100644
--- a/src/keeshare/ShareImport.cpp
+++ b/src/keeshare/ShareImport.cpp
@@ -15,324 +15,87 @@
* along with this program. If not, see .
*/
#include "ShareImport.h"
-#include "config-keepassx.h"
#include "core/Merger.h"
#include "format/KeePass2Reader.h"
#include "keeshare/KeeShare.h"
-#include "keeshare/Signature.h"
#include "keys/PasswordKey.h"
#include
-#include
-#include
-#include
-
-#if defined(WITH_XC_KEESHARE_SECURE)
-#include
-#include
-#endif
+#include
namespace
{
- enum Trust
+ QByteArray readZipFile(void* uf)
{
- Invalid,
- Own,
- UntrustedForever,
- UntrustedOnce,
- TrustedOnce,
- TrustedForever,
- };
-
- QPair
- check(QByteArray& data,
- const KeeShareSettings::Reference& reference,
- const KeeShareSettings::Certificate& ownCertificate,
- const QList& knownCertificates,
- const KeeShareSettings::Sign& sign)
- {
- KeeShareSettings::Certificate certificate;
- if (!sign.signature.isEmpty()) {
- certificate = sign.certificate;
- if (!Signature::verify(data, sign.certificate.key, sign.signature)) {
- qCritical("Invalid signature for shared container %s.", qPrintable(reference.path));
- return {Invalid, KeeShareSettings::Certificate()};
+ QByteArray data;
+ int bytes, bytesRead = 0;
+ unzOpenCurrentFile(uf);
+ do {
+ data.resize(data.size() + 8192);
+ bytes = unzReadCurrentFile(uf, data.data() + bytesRead, 8192);
+ if (bytes > 0) {
+ bytesRead += bytes;
}
-
- // Automatically trust your own certificate
- if (ownCertificate == sign.certificate) {
- return {Own, ownCertificate};
- }
- }
-
- for (const auto& scopedCertificate : knownCertificates) {
- if (scopedCertificate.certificate == certificate && scopedCertificate.path == reference.path) {
- if (scopedCertificate.trust == KeeShareSettings::Trust::Trusted) {
- return {TrustedForever, certificate};
- } else if (scopedCertificate.trust == KeeShareSettings::Trust::Untrusted) {
- return {UntrustedForever, certificate};
- }
- // Default to ask
- break;
- }
- }
-
- // Ask the user if they want to trust the certificate
- QMessageBox warning;
- warning.setWindowTitle(ShareImport::tr("KeeShare Import"));
- if (sign.signature.isEmpty()) {
- warning.setIcon(QMessageBox::Warning);
- warning.setText(ShareImport::tr("The source of the shared container cannot be verified because it is not "
- "signed. Do you really want to import from %1?")
- .arg(reference.path));
- } else {
- warning.setIcon(QMessageBox::Question);
- warning.setText(ShareImport::tr("Do you want to trust %1 with certificate fingerprint:\n%2\n%3")
- .arg(reference.path)
- .arg(certificate.signer)
- .arg(certificate.fingerprint()));
- }
- auto untrustedOnce = warning.addButton(ShareImport::tr("Not this time"), QMessageBox::ButtonRole::NoRole);
- auto untrustedForever = warning.addButton(ShareImport::tr("Never"), QMessageBox::ButtonRole::NoRole);
- auto trustedForever = warning.addButton(ShareImport::tr("Always"), QMessageBox::ButtonRole::YesRole);
- auto trustedOnce = warning.addButton(ShareImport::tr("Just this time"), QMessageBox::ButtonRole::YesRole);
- warning.setDefaultButton(untrustedOnce);
- warning.exec();
- if (warning.clickedButton() == trustedForever) {
- return {TrustedForever, certificate};
- }
- if (warning.clickedButton() == trustedOnce) {
- return {TrustedOnce, certificate};
- }
- if (warning.clickedButton() == untrustedOnce) {
- return {UntrustedOnce, certificate};
- }
- if (warning.clickedButton() == untrustedForever) {
- return {UntrustedForever, certificate};
- }
- return {UntrustedOnce, certificate};
+ } while (bytes > 0);
+ unzCloseCurrentFile(uf);
+ data.truncate(bytesRead);
+ return data;
}
-
- ShareObserver::Result
- signedContainerInto(const QString& resolvedPath, const KeeShareSettings::Reference& reference, Group* targetGroup)
- {
-#if !defined(WITH_XC_KEESHARE_SECURE)
- Q_UNUSED(targetGroup);
- Q_UNUSED(resolvedPath);
- return {reference.path,
- ShareObserver::Result::Warning,
- ShareImport::tr("Signed share container are not supported - import prevented")};
-#else
- QuaZip zip(resolvedPath);
- if (!zip.open(QuaZip::mdUnzip)) {
- qCritical("Unable to open file %s.", qPrintable(reference.path));
- return {reference.path, ShareObserver::Result::Error, ShareImport::tr("File is not readable")};
- }
- const auto expected = QSet() << KeeShare::signatureFileName() << KeeShare::containerFileName();
- const auto files = zip.getFileInfoList();
- QSet actual;
- for (const auto& file : files) {
- actual << file.name;
- }
- if (expected != actual) {
- qCritical("Invalid sharing container %s.", qPrintable(reference.path));
- return {reference.path, ShareObserver::Result::Error, ShareImport::tr("Invalid sharing container")};
- }
-
- zip.setCurrentFile(KeeShare::signatureFileName());
- QuaZipFile signatureFile(&zip);
- signatureFile.open(QuaZipFile::ReadOnly);
- QTextStream stream(&signatureFile);
-
- const auto sign = KeeShareSettings::Sign::deserialize(stream.readAll());
- signatureFile.close();
-
- zip.setCurrentFile(KeeShare::containerFileName());
- QuaZipFile databaseFile(&zip);
- databaseFile.open(QuaZipFile::ReadOnly);
- auto payload = databaseFile.readAll();
- databaseFile.close();
- QBuffer buffer(&payload);
- buffer.open(QIODevice::ReadOnly);
-
- KeePass2Reader reader;
- auto key = QSharedPointer::create();
- key->addKey(QSharedPointer::create(reference.password));
- auto sourceDb = QSharedPointer::create();
- if (!reader.readDatabase(&buffer, key, sourceDb.data())) {
- qCritical("Error while parsing the database: %s", qPrintable(reader.errorString()));
- return {reference.path, ShareObserver::Result::Error, reader.errorString()};
- }
-
- auto foreign = KeeShare::foreign();
- auto own = KeeShare::own();
- auto trust = check(payload, reference, own.certificate, foreign.certificates, sign);
- switch (trust.first) {
- case Invalid:
- qWarning("Prevent untrusted import");
- return {reference.path, ShareObserver::Result::Error, ShareImport::tr("Untrusted import prevented")};
-
- case UntrustedForever:
- case TrustedForever: {
- bool found = false;
- const auto trusted =
- trust.first == TrustedForever ? KeeShareSettings::Trust::Trusted : KeeShareSettings::Trust::Untrusted;
- for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) {
- if (scopedCertificate.certificate == trust.second && scopedCertificate.path == reference.path) {
- scopedCertificate.certificate.signer = trust.second.signer;
- scopedCertificate.path = reference.path;
- scopedCertificate.trust = trusted;
- found = true;
- break;
- }
- }
- if (!found) {
- foreign.certificates << KeeShareSettings::ScopedCertificate{reference.path, trust.second, trusted};
- }
- // update foreign certificates with new settings
- KeeShare::setForeign(foreign);
-
- if (trust.first == TrustedForever) {
- qDebug("Synchronize %s %s with %s",
- qPrintable(reference.path),
- qPrintable(targetGroup->name()),
- qPrintable(sourceDb->rootGroup()->name()));
- Merger merger(sourceDb->rootGroup(), targetGroup);
- merger.setForcedMergeMode(Group::Synchronize);
- auto changelist = merger.merge();
- if (!changelist.isEmpty()) {
- return {
- reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful signed import")};
- }
- }
- // Silent ignore of untrusted import or unchanging import
- return {};
- }
- case TrustedOnce:
- case Own: {
- qDebug("Synchronize %s %s with %s",
- qPrintable(reference.path),
- qPrintable(targetGroup->name()),
- qPrintable(sourceDb->rootGroup()->name()));
- Merger merger(sourceDb->rootGroup(), targetGroup);
- merger.setForcedMergeMode(Group::Synchronize);
- auto changelist = merger.merge();
- if (!changelist.isEmpty()) {
- return {reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful signed import")};
- }
- return {};
- }
- default:
- qWarning("Prevented untrusted import of signed KeeShare database %s", qPrintable(reference.path));
- return {reference.path, ShareObserver::Result::Warning, ShareImport::tr("Untrusted import prevented")};
- }
-#endif
- }
-
- ShareObserver::Result
- unsignedContainerInto(const QString& resolvedPath, const KeeShareSettings::Reference& reference, Group* targetGroup)
- {
-#if !defined(WITH_XC_KEESHARE_INSECURE)
- Q_UNUSED(targetGroup);
- Q_UNUSED(resolvedPath);
- return {reference.path,
- ShareObserver::Result::Warning,
- ShareImport::tr("Unsigned share container are not supported - import prevented")};
-#else
- QFile file(resolvedPath);
- if (!file.open(QIODevice::ReadOnly)) {
- qCritical("Unable to open file %s.", qPrintable(reference.path));
- return {reference.path, ShareObserver::Result::Error, ShareImport::tr("File is not readable")};
- }
- auto payload = file.readAll();
- file.close();
- QBuffer buffer(&payload);
- buffer.open(QIODevice::ReadOnly);
-
- KeePass2Reader reader;
- auto key = QSharedPointer::create();
- key->addKey(QSharedPointer::create(reference.password));
- auto sourceDb = QSharedPointer::create();
- if (!reader.readDatabase(&buffer, key, sourceDb.data())) {
- qCritical("Error while parsing the database: %s", qPrintable(reader.errorString()));
- return {reference.path, ShareObserver::Result::Error, reader.errorString()};
- }
-
- auto foreign = KeeShare::foreign();
- const auto own = KeeShare::own();
- const auto sign = KeeShareSettings::Sign(); // invalid sign
- auto trust = check(payload, reference, own.certificate, foreign.certificates, sign);
- switch (trust.first) {
- case UntrustedForever:
- case TrustedForever: {
- bool found = false;
- const auto trusted =
- trust.first == TrustedForever ? KeeShareSettings::Trust::Trusted : KeeShareSettings::Trust::Untrusted;
- for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) {
- if (scopedCertificate.certificate == trust.second && scopedCertificate.path == reference.path) {
- scopedCertificate.certificate.signer = trust.second.signer;
- scopedCertificate.path = reference.path;
- scopedCertificate.trust = trusted;
- found = true;
- break;
- }
- }
- if (!found) {
- foreign.certificates << KeeShareSettings::ScopedCertificate{reference.path, trust.second, trusted};
- }
- // update foreign certificates with new settings
- KeeShare::setForeign(foreign);
-
- if (trust.first == TrustedForever) {
- qDebug("Synchronize %s %s with %s",
- qPrintable(reference.path),
- qPrintable(targetGroup->name()),
- qPrintable(sourceDb->rootGroup()->name()));
- Merger merger(sourceDb->rootGroup(), targetGroup);
- merger.setForcedMergeMode(Group::Synchronize);
- auto changelist = merger.merge();
- if (!changelist.isEmpty()) {
- return {
- reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful signed import")};
- }
- }
- return {};
- }
-
- case TrustedOnce: {
- qDebug("Synchronize %s %s with %s",
- qPrintable(reference.path),
- qPrintable(targetGroup->name()),
- qPrintable(sourceDb->rootGroup()->name()));
- Merger merger(sourceDb->rootGroup(), targetGroup);
- merger.setForcedMergeMode(Group::Synchronize);
- auto changelist = merger.merge();
- if (!changelist.isEmpty()) {
- return {reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful unsigned import")};
- }
- return {};
- }
- default:
- qWarning("Prevented untrusted import of unsigned KeeShare database %s", qPrintable(reference.path));
- return {reference.path, ShareObserver::Result::Warning, ShareImport::tr("Untrusted import prevented")};
- }
-#endif
- }
-
} // namespace
ShareObserver::Result ShareImport::containerInto(const QString& resolvedPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup)
{
- const QFileInfo info(resolvedPath);
- if (!info.exists()) {
- qCritical("File %s does not exist.", qPrintable(info.absoluteFilePath()));
- return {reference.path, ShareObserver::Result::Warning, tr("File does not exist")};
+ // TODO: Read signing certificate as well, but don't check validity
+ QByteArray dbData;
+
+ auto uf = unzOpen64(resolvedPath.toLatin1().constData());
+ if (uf) {
+ // Open zip share, extract database portion, ignore signature file
+ char zipFileName[256];
+ auto err = unzGoToFirstFile(uf);
+ while (err == UNZ_OK) {
+ unzGetCurrentFileInfo64(uf, nullptr, zipFileName, sizeof(zipFileName), nullptr, 0, nullptr, 0);
+ if (QString(zipFileName).compare(KeeShare::containerFileName()) == 0) {
+ dbData = readZipFile(uf);
+ }
+ err = unzGoToNextFile(uf);
+ }
+ unzClose(uf);
+ } else {
+ // Open KDBX file directly
+ QFile file(resolvedPath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical("Unable to open file %s.", qPrintable(reference.path));
+ return {reference.path, ShareObserver::Result::Error, file.errorString()};
+ }
+ dbData = file.readAll();
}
- if (KeeShare::isContainerType(info, KeeShare::signedContainerFileType())) {
- return signedContainerInto(resolvedPath, reference, targetGroup);
+ QBuffer buffer(&dbData);
+ buffer.open(QIODevice::ReadOnly);
+
+ KeePass2Reader reader;
+ auto key = QSharedPointer::create();
+ key->addKey(QSharedPointer::create(reference.password));
+ auto sourceDb = QSharedPointer::create();
+ if (!reader.readDatabase(&buffer, key, sourceDb.data())) {
+ qCritical("Error while parsing the database: %s", qPrintable(reader.errorString()));
+ return {reference.path, ShareObserver::Result::Error, reader.errorString()};
}
- return unsignedContainerInto(resolvedPath, reference, targetGroup);
+
+ qDebug("Synchronize %s %s with %s",
+ qPrintable(reference.path),
+ qPrintable(targetGroup->name()),
+ qPrintable(sourceDb->rootGroup()->name()));
+
+ Merger merger(sourceDb->rootGroup(), targetGroup);
+ merger.setForcedMergeMode(Group::Synchronize);
+ auto changelist = merger.merge();
+ if (!changelist.isEmpty()) {
+ return {reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful import")};
+ }
+
+ return {};
}
diff --git a/src/keeshare/ShareObserver.cpp b/src/keeshare/ShareObserver.cpp
index a30cced2d..ac1c44baa 100644
--- a/src/keeshare/ShareObserver.cpp
+++ b/src/keeshare/ShareObserver.cpp
@@ -278,13 +278,14 @@ QList ShareObserver::exportShares()
}
for (auto it = references.cbegin(); it != references.cend(); ++it) {
- const auto& reference = it.value().first();
+ auto reference = it.value().first();
const QString resolvedPath = resolvePath(reference.config.path, m_db);
auto watcher = m_fileWatchers.value(resolvedPath);
if (watcher) {
watcher->stop();
}
+ // TODO: save new path into group settings if not saving to signed container anymore
results << ShareExport::intoContainer(resolvedPath, reference.config, reference.group);
if (watcher) {
diff --git a/src/keeshare/Signature.cpp b/src/keeshare/Signature.cpp
deleted file mode 100644
index 029ca97ef..000000000
--- a/src/keeshare/Signature.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 KeePassXC Team
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 or (at your option)
- * version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "Signature.h"
-
-#include "crypto/Random.h"
-
-#include
-
-bool Signature::create(const QByteArray& data, QSharedPointer key, QString& signature)
-{
- // TODO HNH: currently we publish the signature in our own non-standard format - it would
- // be better to use a standard format (like ASN1 - but this would be more easy
- // when we integrate a proper library)
- // Even more, we could publish standard self signed certificates with the container
- // instead of the custom certificates
- if (key->algo_name() == "RSA") {
- try {
- Botan::PK_Signer signer(*key, "EMSA3(SHA-256)");
- signer.update(reinterpret_cast(data.constData()), data.size());
- auto s = signer.signature(*randomGen()->getRng());
-
- auto hex = QByteArray(reinterpret_cast(s.data()), s.size()).toHex();
- signature = QString("rsa|%1").arg(QString::fromLatin1(hex));
- return true;
- } catch (std::exception& e) {
- qWarning("KeeShare: Failed to sign data: %s", e.what());
- return false;
- }
- }
- qWarning("Unsupported Public/Private key format");
- return false;
-}
-
-bool Signature::verify(const QByteArray& data, QSharedPointer key, const QString& signature)
-{
- if (key && key->algo_name() == "RSA") {
- QRegExp extractor("rsa\\|([a-f0-9]+)", Qt::CaseInsensitive);
- if (!extractor.exactMatch(signature) || extractor.captureCount() != 1) {
- qWarning("Could not unpack signature parts");
- return false;
- }
- const QByteArray sig_s = QByteArray::fromHex(extractor.cap(1).toLatin1());
-
- try {
- Botan::PK_Verifier verifier(*key, "EMSA3(SHA-256)");
- verifier.update(reinterpret_cast(data.constData()), data.size());
- return verifier.check_signature(reinterpret_cast(sig_s.constData()), sig_s.size());
- } catch (std::exception& e) {
- qWarning("KeeShare: Failed to verify signature: %s", e.what());
- return false;
- }
- }
- qWarning("Unsupported Public/Private key format");
- return false;
-}
diff --git a/src/keeshare/Signature.h b/src/keeshare/Signature.h
deleted file mode 100644
index 9c4f83bba..000000000
--- a/src/keeshare/Signature.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 KeePassXC Team
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 or (at your option)
- * version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef KEEPASSXC_SIGNATURE_H
-#define KEEPASSXC_SIGNATURE_H
-
-#include
-#include
-#include
-
-namespace Signature
-{
- bool create(const QByteArray& data, QSharedPointer key, QString& signature);
- bool verify(const QByteArray& data, QSharedPointer key, const QString& signature);
-}; // namespace Signature
-
-#endif // KEEPASSXC_SIGNATURE_H
diff --git a/src/keeshare/group/EditGroupWidgetKeeShare.cpp b/src/keeshare/group/EditGroupWidgetKeeShare.cpp
index 6067ec412..82f8dd1c0 100644
--- a/src/keeshare/group/EditGroupWidgetKeeShare.cpp
+++ b/src/keeshare/group/EditGroupWidgetKeeShare.cpp
@@ -103,13 +103,8 @@ void EditGroupWidgetKeeShare::updateSharingState()
return;
}
- auto supportedExtensions = QStringList();
-#if defined(WITH_XC_KEESHARE_INSECURE)
- supportedExtensions << KeeShare::unsignedContainerFileType();
-#endif
-#if defined(WITH_XC_KEESHARE_SECURE)
- supportedExtensions << KeeShare::signedContainerFileType();
-#endif
+ QStringList supportedExtensions;
+ supportedExtensions << KeeShare::unsignedContainerFileType() << KeeShare::signedContainerFileType();
// Custom message for active KeeShare reference
const auto reference = KeeShare::referenceOf(m_temporaryGroup);
@@ -225,26 +220,15 @@ void EditGroupWidgetKeeShare::launchPathSelectionDialog()
return;
}
auto reference = KeeShare::referenceOf(m_temporaryGroup);
- QString defaultFiletype = "";
- auto supportedExtensions = QStringList();
- auto unsupportedExtensions = QStringList();
- auto knownFilters = QStringList() << QString("%1 (*)").arg("All files");
-#if defined(WITH_XC_KEESHARE_INSECURE)
- defaultFiletype = KeeShare::unsignedContainerFileType();
- supportedExtensions << KeeShare::unsignedContainerFileType();
- knownFilters.prepend(
- QString("%1 (*.%2)").arg(tr("KeeShare unsigned container"), KeeShare::unsignedContainerFileType()));
-#else
- unsupportedExtensions << KeeShare::unsignedContainerFileType();
-#endif
-#if defined(WITH_XC_KEESHARE_SECURE)
- defaultFiletype = KeeShare::signedContainerFileType();
- supportedExtensions << KeeShare::signedContainerFileType();
- knownFilters.prepend(
- QString("%1 (*.%2)").arg(tr("KeeShare signed container"), KeeShare::signedContainerFileType()));
-#else
- unsupportedExtensions << KeeShare::signedContainerFileType();
-#endif
+ QString defaultFiletype = KeeShare::unsignedContainerFileType();
+
+ QStringList supportedExtensions;
+ supportedExtensions << KeeShare::unsignedContainerFileType() << KeeShare::signedContainerFileType();
+
+ QStringList knownFilters;
+ knownFilters << QString("%1 (*.%2)").arg(tr("KeeShare container"), KeeShare::unsignedContainerFileType());
+ knownFilters << QString("%1 (*.%2)").arg(tr("KeeShare signed container"), KeeShare::signedContainerFileType());
+ knownFilters << QString("%1 (*)").arg("All files");
const auto filters = knownFilters.join(";;");
auto defaultDirPath = FileDialog::getLastDir("keeshare");
@@ -269,7 +253,7 @@ void EditGroupWidgetKeeShare::launchPathSelectionDialog()
return;
}
bool validFilename = false;
- for (const auto& extension : supportedExtensions + unsupportedExtensions) {
+ for (const auto& extension : supportedExtensions) {
if (filename.endsWith(extension, Qt::CaseInsensitive)) {
validFilename = true;
break;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 88e907ebc..325ff880e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -125,11 +125,6 @@ add_unit_test(NAME testcryptohash SOURCES TestCryptoHash.cpp
add_unit_test(NAME testsymmetriccipher SOURCES TestSymmetricCipher.cpp
LIBS ${TEST_LIBRARIES})
-if(WITH_XC_KEESHARE)
- add_unit_test(NAME testsignature SOURCES TestSignature.cpp
- LIBS ${TEST_LIBRARIES})
-endif()
-
add_unit_test(NAME testhashedblockstream SOURCES TestHashedBlockStream.cpp
LIBS testsupport ${TEST_LIBRARIES})
diff --git a/tests/TestSharing.cpp b/tests/TestSharing.cpp
index 865ce9a41..14a72b142 100644
--- a/tests/TestSharing.cpp
+++ b/tests/TestSharing.cpp
@@ -31,9 +31,6 @@ QTEST_GUILESS_MAIN(TestSharing)
Q_DECLARE_METATYPE(KeeShareSettings::Type)
Q_DECLARE_METATYPE(KeeShareSettings::Key)
Q_DECLARE_METATYPE(KeeShareSettings::Certificate)
-Q_DECLARE_METATYPE(KeeShareSettings::Trust)
-Q_DECLARE_METATYPE(KeeShareSettings::ScopedCertificate)
-Q_DECLARE_METATYPE(QList)
void TestSharing::initTestCase()
{
@@ -65,55 +62,12 @@ void TestSharing::testNullObjects()
const auto xmlActive = KeeShareSettings::Active::deserialize(empty);
QVERIFY(xmlActive.isNull());
- const auto foreign = KeeShareSettings::Foreign();
- QVERIFY(foreign.certificates.isEmpty());
- const auto xmlForeign = KeeShareSettings::Foreign::deserialize(empty);
- QVERIFY(xmlForeign.certificates.isEmpty());
-
const auto reference = KeeShareSettings::Reference();
QVERIFY(reference.isNull());
const auto xmlReference = KeeShareSettings::Reference::deserialize(empty);
QVERIFY(xmlReference.isNull());
}
-void TestSharing::testCertificateSerialization()
-{
- QFETCH(KeeShareSettings::Trust, trusted);
- auto key = stubkey();
- KeeShareSettings::ScopedCertificate original;
- original.path = "/path";
- original.certificate = KeeShareSettings::Certificate{key, "Some _\"\" weird string"};
- original.trust = trusted;
-
- QString buffer;
- QXmlStreamWriter writer(&buffer);
- writer.writeStartDocument();
- writer.writeStartElement("Certificate");
- KeeShareSettings::ScopedCertificate::serialize(writer, original);
- writer.writeEndElement();
- writer.writeEndDocument();
-
- QXmlStreamReader reader(buffer);
- reader.readNextStartElement();
- QVERIFY(reader.name() == "Certificate");
- KeeShareSettings::ScopedCertificate restored = KeeShareSettings::ScopedCertificate::deserialize(reader);
-
- QCOMPARE(restored.certificate.key->private_key_bits(), original.certificate.key->private_key_bits());
- QCOMPARE(restored.certificate.signer, original.certificate.signer);
- QCOMPARE(restored.trust, original.trust);
- QCOMPARE(restored.path, original.path);
-
- QCOMPARE(restored.certificate.key->public_key_bits(), key->public_key_bits());
-}
-
-void TestSharing::testCertificateSerialization_data()
-{
- QTest::addColumn("trusted");
- QTest::newRow("Ask") << KeeShareSettings::Trust::Ask;
- QTest::newRow("Trusted") << KeeShareSettings::Trust::Trusted;
- QTest::newRow("Untrusted") << KeeShareSettings::Trust::Untrusted;
-}
-
void TestSharing::testKeySerialization()
{
auto key = stubkey();
@@ -177,16 +131,13 @@ void TestSharing::testSettingsSerialization()
QFETCH(bool, exporting);
QFETCH(KeeShareSettings::Certificate, ownCertificate);
QFETCH(KeeShareSettings::Key, ownKey);
- QFETCH(QList, foreignCertificates);
KeeShareSettings::Own originalOwn;
- KeeShareSettings::Foreign originalForeign;
KeeShareSettings::Active originalActive;
originalActive.in = importing;
originalActive.out = exporting;
originalOwn.certificate = ownCertificate;
originalOwn.key = ownKey;
- originalForeign.certificates = foreignCertificates;
const QString serializedActive = KeeShareSettings::Active::serialize(originalActive);
KeeShareSettings::Active restoredActive = KeeShareSettings::Active::deserialize(serializedActive);
@@ -194,9 +145,6 @@ void TestSharing::testSettingsSerialization()
const QString serializedOwn = KeeShareSettings::Own::serialize(originalOwn);
KeeShareSettings::Own restoredOwn = KeeShareSettings::Own::deserialize(serializedOwn);
- const QString serializedForeign = KeeShareSettings::Foreign::serialize(originalForeign);
- KeeShareSettings::Foreign restoredForeign = KeeShareSettings::Foreign::deserialize(serializedForeign);
-
QCOMPARE(restoredActive.in, importing);
QCOMPARE(restoredActive.out, exporting);
if (ownCertificate.key) {
@@ -205,44 +153,29 @@ void TestSharing::testSettingsSerialization()
if (ownKey.key) {
QCOMPARE(restoredOwn.key, ownKey);
}
- QCOMPARE(restoredForeign.certificates.count(), foreignCertificates.count());
- for (int i = 0; i < foreignCertificates.count(); ++i) {
- QCOMPARE(restoredForeign.certificates[i].certificate, foreignCertificates[i].certificate);
- }
}
void TestSharing::testSettingsSerialization_data()
{
auto sshKey0 = stubkey(0);
- KeeShareSettings::ScopedCertificate certificate0;
- certificate0.path = "/path/0";
- certificate0.certificate = KeeShareSettings::Certificate{sshKey0, "Some _\"\" weird string"};
- certificate0.trust = KeeShareSettings::Trust::Trusted;
+
+ KeeShareSettings::Certificate certificate0;
+ certificate0.key = sshKey0;
+ certificate0.signer = "signer";
KeeShareSettings::Key key0;
key0.key = sshKey0;
- auto sshKey1 = stubkey(1);
- KeeShareSettings::ScopedCertificate certificate1;
- certificate1.path = "/path/1";
- certificate1.certificate = KeeShareSettings::Certificate{sshKey1, "Another "};
- certificate1.trust = KeeShareSettings::Trust::Untrusted;
-
QTest::addColumn("importing");
QTest::addColumn("exporting");
QTest::addColumn("ownCertificate");
QTest::addColumn("ownKey");
- QTest::addColumn>("foreignCertificates");
- QTest::newRow("1") << false << false << KeeShareSettings::Certificate() << KeeShareSettings::Key()
- << QList();
- QTest::newRow("2") << true << false << KeeShareSettings::Certificate() << KeeShareSettings::Key()
- << QList();
- QTest::newRow("3") << true << true << KeeShareSettings::Certificate() << KeeShareSettings::Key()
- << QList({certificate0, certificate1});
- QTest::newRow("4") << false << true << certificate0.certificate << key0
- << QList();
- QTest::newRow("5") << false << false << certificate0.certificate << key0
- << QList({certificate1});
+
+ QTest::newRow("1") << false << false << KeeShareSettings::Certificate() << KeeShareSettings::Key();
+ QTest::newRow("2") << true << false << KeeShareSettings::Certificate() << KeeShareSettings::Key();
+ QTest::newRow("3") << true << true << KeeShareSettings::Certificate() << KeeShareSettings::Key();
+ QTest::newRow("4") << false << true << certificate0 << key0;
+ QTest::newRow("5") << false << false << certificate0 << key0;
}
const QSharedPointer TestSharing::stubkey(int index)
diff --git a/tests/TestSharing.h b/tests/TestSharing.h
index bba627f64..cfb521e02 100644
--- a/tests/TestSharing.h
+++ b/tests/TestSharing.h
@@ -31,8 +31,6 @@ class TestSharing : public QObject
private slots:
void initTestCase();
void testNullObjects();
- void testCertificateSerialization();
- void testCertificateSerialization_data();
void testKeySerialization();
void testReferenceSerialization();
void testReferenceSerialization_data();
diff --git a/tests/TestSignature.cpp b/tests/TestSignature.cpp
deleted file mode 100644
index 1c454504e..000000000
--- a/tests/TestSignature.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2010 Felix Geyer
- * Copyright (C) 2017 KeePassXC Team
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 or (at your option)
- * version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "TestSignature.h"
-
-#include
-
-#include "crypto/Crypto.h"
-#include "crypto/Random.h"
-#include "keeshare/Signature.h"
-
-#include
-#include
-
-QTEST_GUILESS_MAIN(TestSignature)
-static const char* rsa_2_private = "-----BEGIN RSA PRIVATE KEY-----\n"
- "MIIEowIBAAKCAQEAwGdladnqFfcDy02Gubx4sdBT8NYEg2YKXfcKLSwca5gV4X7I\n"
- "z/+QR51LAfPCkj+QjWpj3DD1/6P7s6jOJ4BNd6CSDukv18DOsIsFn2D+zLmVoir2\n"
- "lki3sTsmiEz65KvHE8EnQ8IzZCqZDC40tZOcz2bnkZrmcsEibKoxYsmQJk95NwdR\n"
- "teFymp1qH3zq85xdNWw2u6c5CKzLgI5BjInttO98iSxL0KuY/JmzMx0gTbRiqc0x\n"
- "22EODtdVsBoNL/pt8v6Q+WLpRg4/Yq7YurAngxk4h38NWvufj2vJvbcRqX4cupcu\n"
- "92T9SWwSwZmd4Xy3bt+AUlq4XRMa1MlKfPvXmwIDAQABAoIBAGbWnRD/xaup1OBU\n"
- "dr9N6qD3/fXLHqxw3PeudEUCv8oOhxt43bK3IZH1k8LeXFA5I3VCuU9W6BWUu5Mi\n"
- "ldXtMPrQ22CW6NiEGLWqCP5QJMCeLUl5d0WKZoyXVhgiNTQGUKjRY8BGy5stXZJy\n"
- "HAA1fuooUXu09Jm/ezvjl/P6Uk722nZns4g6cc8aUSQDSVoeuCvwDaix5o4Z4RGY\n"
- "4biIKGj5qYxoe+rbgYH/2zlEcAiSJIuqjYY+Xk4IdB89DYZBYnO/xPkRaDeiY2xl\n"
- "QM7Inr7PQC8PWJc9zYYvlGnnmIRCkO15mWau70N1Y1rUAsyW61g2GyFhdsIIODH/\n"
- "878Kc9ECgYEA+2JaUqRWr6dqE+uVPpGkbGiAaRQ79olTcRmxXCnM+Y3c88z9G7kC\n"
- "2S5UKPRDl7EzwmMJqqb8BZbdSWoAxO4++F6ylSz7TqowPw+13Wxwm3wApvr2Q1Mo\n"
- "rkq4ltgyHMR+iXvKqOYa2GqZNmRwh7JGLIJ7Y0Z77nwBkkgDc/3ey8MCgYEAw+/N\n"
- "fxv2t+r6VKxEtjdy3sfn8LLjiWqghPngJzcYH9NdB8fmMN1WHqX075hbKjI9TyJw\n"
- "77p8onjZI0opLexHHUmepEa6Ijo1zynJJ7XPXnyruiTXXqz49io6lFOLcXi/i+DZ\n"
- "B2vQcMGWA4qwJxz7KA6EZ/HimjuysV1guvlKf0kCgYA6+JGTvXWQc0eRMLysFuJp\n"
- "hAJLpDGE3iYy7AINSskI6dyhXL8rl7UxWYroqJSKq0knGrCT1eRdM0zqAfH4QKOJ\n"
- "BD4EfK7ff1EeGgNh1CR+dRJ6GXlXxdRPPrwattDaqsW8Xsvl30UA69DRT7KOQqXv\n"
- "nxRu74P3KCP+OuKEfVOcnQKBgQC+/2r1Zj/5huBhW9BbQ/ABBSOuueMeGEfDeIUu\n"
- "FQG6PGKqbA2TQp9pnuMGECGGH5UuJ+epeMN36Y/ZW7iKoJGuFg7EGoHlTZMYj6Yb\n"
- "xJoRhDwuZy1eiATkicOyxUHf6hHme9dz6YA1+i+O4knWxuR5ZrVhUiRPrrQBO4JI\n"
- "oSwiqQKBgHblgOVfOJrG3HDg6bo+qmxQsGFRCD0mehsg9YpokuZVX0UJtGx/RJHU\n"
- "vIBL00An6YcNfPTSlNJeG83APtk/tdgsXvQd3pmIkeY78x6xWKSieZXv4lyDv7lX\n"
- "r28lCTj2Ez2gEzEohZgf4V1uzBvTdJefarpQ00ep34UZ9FsNfUwD\n"
- "-----END RSA PRIVATE KEY-----\n";
-static const char* rsa_2_public = "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIIBCgKCAQEAwGdladnqFfcDy02Gubx4sdBT8NYEg2YKXfcKLSwca5gV4X7Iz/+Q\n"
- "R51LAfPCkj+QjWpj3DD1/6P7s6jOJ4BNd6CSDukv18DOsIsFn2D+zLmVoir2lki3\n"
- "sTsmiEz65KvHE8EnQ8IzZCqZDC40tZOcz2bnkZrmcsEibKoxYsmQJk95NwdRteFy\n"
- "mp1qH3zq85xdNWw2u6c5CKzLgI5BjInttO98iSxL0KuY/JmzMx0gTbRiqc0x22EO\n"
- "DtdVsBoNL/pt8v6Q+WLpRg4/Yq7YurAngxk4h38NWvufj2vJvbcRqX4cupcu92T9\n"
- "SWwSwZmd4Xy3bt+AUlq4XRMa1MlKfPvXmwIDAQAB\n"
- "-----END RSA PUBLIC KEY-----\n";
-static const char* rsa_2_sign = "4fda1b39f93f174cdc79ac2bd6118155359830c90e2c39b60a1a548852f2c87a"
- "cd61b2a378259a38befad35dbf208a2c1332ab74faf2cee2ff2e8be49c4c5f41"
- "dc10e5a5fafb53d3c54e2b7640d7bfee6bb0f24c5a1fb934150a144c2b465fe4"
- "8a1579e666a097fb1609ae9abc5760f6e6d6e73acb610fb11dd1c409ca284a72"
- "0be64dd56a28ab257e8721f5bade58816382581ac08d932098dd200d836fe897"
- "f78a5f02095ac3b21cca2a47b2afd282ce075c6450cba8c85b08b58c5bacb75d"
- "e1a73bdec4321193d4a3ce653d8e3aa8a4f2beac6a44497328f8855f7e28e15d"
- "f63b21f8bc7204bf6e202c9cb08be050379be5ad88d8e695a38440a50e75dfdf";
-static const char* rsa_1_private = "-----BEGIN RSA PRIVATE KEY-----\n"
- "MIIEpAIBAAKCAQEAsCHtJicDPWnvHSIKbnTZaJkIB9vgE0pmLdK580JUqBuonVbB\n"
- "y1QTy0ZQ7/TtqvLPgwPK88TR46OLO/QGCzo2+XxgJ85uy0xfuyUYRmSuw0drsErN\n"
- "mH8vU91lSBxsGDp9LtBbgHKoR23vMWZ34IxFRc55XphrIH48ijsMaL6bXBwF/3tD\n"
- "9T3lm2MpP1huyVNnIY9+GRRWCy4f9LMj/UGu/n4RtwwfpOZBBRwYkq5QkzA9lPm/\n"
- "VzF3MP1rKTMkvAw+Nfb383mkmc6MRnsa6uh6iDa9aVB7naegM13UJQX/PY1Ks6pO\n"
- "XDpy/MQ7iCh+HmYNq5dRmARyaNl9xIXJNhz1cQIDAQABAoIBAQCnEUc1LUQxeM5K\n"
- "wANNCqE+SgoIClPdeHC7fmrLh1ttqe6ib6ybBUFRS31yXs0hnfefunVEDKlaV8K2\n"
- "N52UAMAsngFHQNRvGh6kEWeZPd9Xc+N98TZbNCjcT+DGKc+Om8wqH5DrodZlCq4c\n"
- "GaoT4HnE4TjWtZTH2XXrWF9I66PKFWf070R44nvyVcvaZi4pC2YmURRPuGF6K1iK\n"
- "dH8zM6HHG1UGu2W6hLNn+K01IulG0Lb8eWNaNYMmtQWaxyp7I2IWkkecUs3nCuiR\n"
- "byFOoomCjdh8r9yZFvwxjGUhgtkALN9GCU0Mwve+s11IB2gevruN+q9/Qejbyfdm\n"
- "IlgLAeTRAoGBANRcVzW9CYeobCf+U9hKJFEOur8XO+J2mTMaELA0EjWpTJFAeIT7\n"
- "KeRpCRG4/vOSklxxRF6vP1EACA4Z+5BlN+FTipHHs+bSEgqkPZiiANDH7Zot5Iqv\n"
- "1q0fRyldNRZNZK7DWp08BPNVWGA/EnEuKJiURxnxBaxNXbUyMCdjxvMvAoGBANRT\n"
- "utbrqS/bAa/DcHKn3V6DRqBl3TDOfvCNjiKC84a67F2uXgzLIdMktr4d1NyCZVJd\n"
- "7/zVgWORLIdg1eAi6rYGoOvNV39wwga7CF+m9sBY0wAaKYCELe6L26r4aQHVCX6n\n"
- "rnIgUv+4o4itmU2iP0r3wlmDC9pDRQP82vfvQPlfAoGASwhleANW/quvq2HdViq8\n"
- "Mje2HBalfhrRfpDTHK8JUBSFjTzuWG42GxJRtgVbb8x2ElujAKGDCaetMO5VSGu7\n"
- "Fs5hw6iAFCpdXY0yhl+XUi2R8kwM2EPQ4lKO3jqkq0ClNmqn9a5jQWcCVt9yMLNS\n"
- "fLbHeI8EpiCf34ngIcrLXNkCgYEAzlcEZuKkC46xB+dNew8pMTUwSKZVm53BfPKD\n"
- "44QRN6imFbBjU9mAaJnwQbfp6dWKs834cGPolyM4++MeVfB42iZ88ksesgmZdUMD\n"
- "szkl6O0pOJs0I+HQZVdjRbadDZvD22MHQ3+oST1dJ3FVXz3Cdo9qPuT8esMO6f4r\n"
- "qfDH2s8CgYAXC/lWWHQ//PGP0pH4oiEXisx1K0X1u0xMGgrChxBRGRiKZUwNMIvJ\n"
- "TqUu7IKizK19cLHF/NBvxHYHFw+m7puNjn6T1RtRCUjRZT7Dx1VHfVosL9ih5DA8\n"
- "tpbZA5KGKcvHtB5DDgT0MHwzBZnb4Q//Rhovzn+HXZPsJTTgHHy3NQ==\n"
- "-----END RSA PRIVATE KEY-----\n";
-static const char* rsa_1_public = "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIIBCgKCAQEAsCHtJicDPWnvHSIKbnTZaJkIB9vgE0pmLdK580JUqBuonVbBy1QT\n"
- "y0ZQ7/TtqvLPgwPK88TR46OLO/QGCzo2+XxgJ85uy0xfuyUYRmSuw0drsErNmH8v\n"
- "U91lSBxsGDp9LtBbgHKoR23vMWZ34IxFRc55XphrIH48ijsMaL6bXBwF/3tD9T3l\n"
- "m2MpP1huyVNnIY9+GRRWCy4f9LMj/UGu/n4RtwwfpOZBBRwYkq5QkzA9lPm/VzF3\n"
- "MP1rKTMkvAw+Nfb383mkmc6MRnsa6uh6iDa9aVB7naegM13UJQX/PY1Ks6pOXDpy\n"
- "/MQ7iCh+HmYNq5dRmARyaNl9xIXJNhz1cQIDAQAB\n"
- "-----END RSA PUBLIC KEY-----\n";
-
-static QByteArray data("Some trivial test with a longer .... ................................. longer text");
-
-QSharedPointer loadPrivateKey(const QString& pem)
-{
- try {
- std::string label;
- auto der = Botan::PEM_Code::decode(pem.toStdString(), label);
- auto key = new Botan::RSA_PrivateKey(
- Botan::AlgorithmIdentifier("RSA", Botan::AlgorithmIdentifier::USE_NULL_PARAM), der);
- return QSharedPointer(key);
- } catch (std::exception& e) {
- qWarning("Failed to load key: %s", e.what());
- return {};
- }
-}
-
-QSharedPointer loadPublicKey(const QString& pem)
-{
- try {
- std::string label;
- auto der = Botan::PEM_Code::decode(pem.toStdString(), label);
- auto key =
- new Botan::RSA_PublicKey(Botan::AlgorithmIdentifier("RSA", Botan::AlgorithmIdentifier::USE_NULL_PARAM),
- std::vector(der.begin(), der.end()));
- return QSharedPointer(key);
- } catch (std::exception& e) {
- qWarning("Failed to load key: %s", e.what());
- return {};
- }
-}
-
-void TestSignature::initTestCase()
-{
- QVERIFY(Crypto::init());
-}
-
-void TestSignature::testSigningOpenSSH_RSA_PrivateOnly()
-{
- auto rsaKey = loadPrivateKey(rsa_2_private);
- QVERIFY(rsaKey);
-
- QString sign;
- Signature::create(data, rsaKey, sign);
- QCOMPARE(sign, QString("rsa|%1").arg(QString::fromLatin1(rsa_2_sign)));
-
- const bool verified = Signature::verify(data, rsaKey, sign);
- QCOMPARE(verified, true);
-}
-
-void TestSignature::testSigningOpenSSH_RSA()
-{
- auto privateKey = loadPrivateKey(rsa_2_private);
- QVERIFY(privateKey);
-
- QString sign;
- Signature::create(data, privateKey, sign);
- QVERIFY(!sign.isEmpty());
-
- auto publicKey = loadPublicKey(rsa_2_public);
- QVERIFY(publicKey);
-
- const bool verified = Signature::verify(data, publicKey, sign);
- QCOMPARE(verified, true);
-}
-
-void TestSignature::testSigningGenerated_RSA_PrivateOnly()
-{
- QSharedPointer key(new Botan::RSA_PrivateKey(*randomGen()->getRng(), 2048));
-
- QString sign;
- Signature::create(data, key, sign);
- QVERIFY(!sign.isEmpty());
-
- const bool verified = Signature::verify(data, key, sign);
- QCOMPARE(verified, true);
-}
-
-void TestSignature::testSigningTest_RSA_PrivateOnly()
-{
- auto rsaKey = loadPrivateKey(rsa_2_private);
- QVERIFY(rsaKey);
-
- QString sign;
- Signature::create(data, rsaKey, sign);
- QVERIFY(!sign.isEmpty());
-
- const bool verified = Signature::verify(data, rsaKey, sign);
- QCOMPARE(verified, true);
-}
-
-void TestSignature::testSigningTest_RSA()
-{
- auto privateKey = loadPrivateKey(rsa_1_private);
- QVERIFY(privateKey);
-
- QString sign;
- Signature::create(data, privateKey, sign);
- QVERIFY(!sign.isEmpty());
-
- auto publicKey = loadPublicKey(rsa_1_public);
- QVERIFY(publicKey);
-
- const bool verified = Signature::verify(data, publicKey, sign);
- QCOMPARE(verified, true);
-}
diff --git a/tests/TestSignature.h b/tests/TestSignature.h
deleted file mode 100644
index 38e576462..000000000
--- a/tests/TestSignature.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 Felix Geyer
- * Copyright (C) 2017 KeePassXC Team
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 or (at your option)
- * version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef KEEPASSXC_TESTSIGNATURE_H
-#define KEEPASSXC_TESTSIGNATURE_H
-
-#include
-
-class TestSignature : public QObject
-{
- Q_OBJECT
-
-private slots:
- void initTestCase();
-
- void testSigningOpenSSH_RSA_PrivateOnly();
- void testSigningOpenSSH_RSA();
-
- void testSigningGenerated_RSA_PrivateOnly();
-
- void testSigningTest_RSA_PrivateOnly();
- void testSigningTest_RSA();
-};
-
-#endif // KEEPASSX_TESTSIGNATURE_H