From 6491c55011d8c677b776a7ba66c21031f689c2d2 Mon Sep 17 00:00:00 2001 From: Melvin Keskin Date: Sat, 15 Jan 2022 13:55:18 +0100 Subject: Split up ATM parts of trust storage and refactor (#388) QXmppTrustStorage is now the base class for all trust storages used by end-to-end encryption managers. QXmppAtmTrustStorage is used by QXmppAtmManager. QXmppTrustMemoryStorage is now the base class for all trust storages that use the memory for storing data. QXmppAtmTrustMemoryStorage can be used by QXmppAtmManager. Methods needed by the upcoming OMEMO implementation are added. Some existing methods are refactored. --- src/client/QXmppAtmManager.cpp | 23 +--- src/client/QXmppAtmManager.h | 11 +- src/client/QXmppAtmTrustMemoryStorage.cpp | 145 ++++++++++++++++++++ src/client/QXmppAtmTrustMemoryStorage.h | 33 +++++ src/client/QXmppAtmTrustStorage.cpp | 80 +++++++++++ src/client/QXmppAtmTrustStorage.h | 24 ++++ src/client/QXmppTrustMemoryStorage.cpp | 221 ++++++++++++------------------ src/client/QXmppTrustMemoryStorage.h | 21 +-- src/client/QXmppTrustStorage.cpp | 142 ++++++++++--------- src/client/QXmppTrustStorage.h | 33 ++--- 10 files changed, 476 insertions(+), 257 deletions(-) create mode 100644 src/client/QXmppAtmTrustMemoryStorage.cpp create mode 100644 src/client/QXmppAtmTrustMemoryStorage.h create mode 100644 src/client/QXmppAtmTrustStorage.cpp create mode 100644 src/client/QXmppAtmTrustStorage.h (limited to 'src/client') diff --git a/src/client/QXmppAtmManager.cpp b/src/client/QXmppAtmManager.cpp index 4155e993..c4fe2cad 100644 --- a/src/client/QXmppAtmManager.cpp +++ b/src/client/QXmppAtmManager.cpp @@ -8,13 +8,11 @@ #include "QXmppClient.h" #include "QXmppConstants_p.h" #include "QXmppFutureUtils_p.h" +#include "QXmppMessage.h" #include "QXmppTrustMessageElement.h" +#include "QXmppTrustMessageKeyOwner.h" #include "QXmppUtils.h" -#include -#include -#include - using namespace QXmpp::Private; /// @@ -27,21 +25,10 @@ using namespace QXmpp::Private; /// storage interface must be added. /// That implementation has to be adapted to your storage such as a database. /// In case you only need memory and no peristent storage, you can use the -/// existing implementation: +/// existing implementation and add the storage with it: /// ///\code -/// QXmppTrustStorage *trustStorage = new QXmppTrustMemoryStorage; -/// \endcode -/// -/// You can set a security policy used by ATM via the trust manager. -/// Is is recommended to apply TOAKAFA for good security and usability when -/// using \xep{0384, OMEMO Encryption}: -/// \code -/// trustStorage->setSecurityPolicy("urn:xmpp:omemo:2", QXmppTrustStorage::Toakafa); -/// \endcode -/// -/// Afterwards, this manager must be added with the storage: -/// \code +/// QXmppAtmTrustStorage *trustStorage = new QXmppAtmTrustMemoryStorage; /// QXmppAtmManager *manager = new QXmppAtmManager(trustStorage); /// client->addExtension(manager); /// \endcode @@ -73,7 +60,7 @@ using namespace QXmpp::Private; /// /// \param trustStorage trust storage implementation /// -QXmppAtmManager::QXmppAtmManager(QXmppTrustStorage *trustStorage) +QXmppAtmManager::QXmppAtmManager(QXmppAtmTrustStorage *trustStorage) { m_trustStorage = trustStorage; } diff --git a/src/client/QXmppAtmManager.h b/src/client/QXmppAtmManager.h index 5c2dc1e7..042d1342 100644 --- a/src/client/QXmppAtmManager.h +++ b/src/client/QXmppAtmManager.h @@ -5,18 +5,19 @@ #ifndef QXMPPATMMANAGER_H #define QXMPPATMMANAGER_H +#include "QXmppAtmTrustStorage.h" #include "QXmppClientExtension.h" -#include "QXmppMessage.h" #include "QXmppSendResult.h" -#include "QXmppTrustMessageKeyOwner.h" -#include "QXmppTrustStorage.h" + +class QXmppMessage; +class QXmppTrustMessageKeyOwner; class QXMPP_EXPORT QXmppAtmManager : public QXmppClientExtension { Q_OBJECT public: - QXmppAtmManager(QXmppTrustStorage *trustStorage); + QXmppAtmManager(QXmppAtmTrustStorage *trustStorage); QFuture makeTrustDecisions(const QString &encryption, const QString &keyOwnerJid, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting = {}); /// \cond @@ -41,7 +42,7 @@ private: QFuture sendTrustMessage(const QString &encryption, const QList &keyOwners, const QString &recipientJid); - QXmppTrustStorage *m_trustStorage; + QXmppAtmTrustStorage *m_trustStorage; friend class tst_QXmppAtmManager; }; diff --git a/src/client/QXmppAtmTrustMemoryStorage.cpp b/src/client/QXmppAtmTrustMemoryStorage.cpp new file mode 100644 index 00000000..404c5564 --- /dev/null +++ b/src/client/QXmppAtmTrustMemoryStorage.cpp @@ -0,0 +1,145 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppAtmTrustMemoryStorage.h" + +#include "QXmppFutureUtils_p.h" +#include "QXmppTrustMessageKeyOwner.h" + +using namespace QXmpp::Private; + +/// +/// \class QXmppAtmTrustMemoryStorage +/// +/// \brief The QXmppAtmTrustMemoryStorage class stores trust data for +/// \xep{0450, Automatic Trust Management (ATM)} in the memory. +/// +/// \warning THIS API IS NOT FINALIZED YET! +/// +/// \since QXmpp 1.5 +/// + +struct UnprocessedKey +{ + QByteArray id; + QString ownerJid; + QByteArray senderKeyId; + bool trust; +}; + +class QXmppAtmTrustMemoryStoragePrivate +{ +public: + // encryption protocols mapped to trust message data received from endpoints + // with unauthenticated keys + QMultiHash keys; +}; + +/// +/// Constructs an ATM trust memory storage. +/// +QXmppAtmTrustMemoryStorage::QXmppAtmTrustMemoryStorage() + : d(new QXmppAtmTrustMemoryStoragePrivate) +{ +} + +QXmppAtmTrustMemoryStorage::~QXmppAtmTrustMemoryStorage() = default; + +/// \cond +QFuture QXmppAtmTrustMemoryStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) +{ + const auto addKeys = [&](const QXmppTrustMessageKeyOwner &keyOwner, bool trust, const QList &keyIds) { + for (const auto &keyId : keyIds) { + auto isKeyFound = false; + + for (auto itr = d->keys.find(encryption); itr != d->keys.end() && itr.key() == encryption; ++itr) { + auto &key = itr.value(); + if (key.id == keyId && key.ownerJid == keyOwner.jid() && key.senderKeyId == senderKeyId) { + // Update the stored trust if it differs from the new one. + if (key.trust != trust) { + key.trust = trust; + } + + isKeyFound = true; + break; + } + } + + // Create a new entry and store it if there is no such entry yet. + if (!isKeyFound) { + UnprocessedKey key; + key.id = keyId; + key.ownerJid = keyOwner.jid(); + key.senderKeyId = senderKeyId; + key.trust = trust; + d->keys.insert(encryption, key); + } + } + }; + + for (const auto &keyOwner : keyOwners) { + addKeys(keyOwner, true, keyOwner.trustedKeys()); + addKeys(keyOwner, false, keyOwner.distrustedKeys()); + } + + return makeReadyFuture(); +} + +QFuture QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) +{ + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + const auto &key = itr.value(); + if ((key.trust && keyIdsForAuthentication.contains(key.id)) || + (!key.trust && keyIdsForDistrusting.contains(key.id))) { + itr = d->keys.erase(itr); + } else { + ++itr; + } + } + + return makeReadyFuture(); +} + +QFuture QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) +{ + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + if (senderKeyIds.contains(itr.value().senderKeyId)) { + itr = d->keys.erase(itr); + } else { + ++itr; + } + } + + return makeReadyFuture(); +} + +QFuture QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption) +{ + d->keys.remove(encryption); + return makeReadyFuture(); +} + +QFuture>> QXmppAtmTrustMemoryStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) +{ + QHash> keys; + + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { + if (senderKeyIds.contains(key.senderKeyId) || senderKeyIds.isEmpty()) { + keys[key.trust].insert(key.ownerJid, key.id); + } + } + + return makeReadyFuture(std::move(keys)); +} + +QFuture QXmppAtmTrustMemoryStorage::resetAll(const QString &encryption) +{ + QXmppTrustMemoryStorage::resetAll(encryption); + d->keys.remove(encryption); + return makeReadyFuture(); +} +/// \endcond diff --git a/src/client/QXmppAtmTrustMemoryStorage.h b/src/client/QXmppAtmTrustMemoryStorage.h new file mode 100644 index 00000000..432c2058 --- /dev/null +++ b/src/client/QXmppAtmTrustMemoryStorage.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPATMTRUSTMEMORYSTORAGE_H +#define QXMPPATMTRUSTMEMORYSTORAGE_H + +#include "QXmppAtmTrustStorage.h" +#include "QXmppTrustMemoryStorage.h" + +class QXmppAtmTrustMemoryStoragePrivate; + +class QXMPP_EXPORT QXmppAtmTrustMemoryStorage : virtual public QXmppAtmTrustStorage, public QXmppTrustMemoryStorage +{ +public: + QXmppAtmTrustMemoryStorage(); + ~QXmppAtmTrustMemoryStorage(); + + /// \cond + QFuture addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) override; + QFuture removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) override; + QFuture removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) override; + QFuture removeKeysForPostponedTrustDecisions(const QString &encryption) override; + QFuture>> keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds = {}) override; + + QFuture resetAll(const QString &encryption) override; + /// \endcond + +private: + std::unique_ptr d; +}; + +#endif // QXMPPATMTRUSTMEMORYSTORAGE_H diff --git a/src/client/QXmppAtmTrustStorage.cpp b/src/client/QXmppAtmTrustStorage.cpp new file mode 100644 index 00000000..70ce2822 --- /dev/null +++ b/src/client/QXmppAtmTrustStorage.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +/// +/// \class QXmppAtmTrustStorage +/// +/// \brief The QXmppAtmTrustStorage class stores trust data for +/// \xep{0450, Automatic Trust Management (ATM)}. +/// +/// \warning THIS API IS NOT FINALIZED YET! +/// +/// \since QXmpp 1.5 +/// + +/// +/// \fn QXmppAtmTrustStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) +/// +/// Adds keys that cannot be authenticated or distrusted directly because the +/// key of the trust message's sender is not yet authenticated. +/// +/// Those keys are being authenticated or distrusted once the sender's key is +/// authenticated. +/// Each element of keyOwners (i.e., keyOwner) can contain keys for postponed +/// authentication as trustedKeys or for postponed distrusting as +/// distrustedKeys. +/// +/// If keys of keyOwner.trustedKeys() are already stored for postponed +/// distrusting, they are changed to be used for postponed authentication. +/// If keys of keyOwner.distrustedKeys() are already stored for postponed +/// authentication, they are changed to be used for postponed distrusting. +/// If the same keys are in keyOwner.trustedKeys() and +/// keyOwner.distrustedKeys(), they are used for postponed distrusting. +/// +/// \param encryption encryption protocol namespace +/// \param senderKeyId key ID of the trust message's sender +/// \param keyOwners key owners containing key IDs for postponed trust decisions +/// + +/// +/// \fn QXmppAtmTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) +/// +/// Removes keys for postponed authentication or distrusting. +/// +/// \param encryption encryption protocol namespace +/// \param keyIdsForAuthentication IDs of the keys for postponed authentication +/// \param keyIdsForDistrusting IDs of the keys for postponed distrusting +/// + +/// +/// \fn QXmppAtmTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) +/// +/// Removes keys for postponed authentication or distrusting by the trust +/// message sender's key ID. +/// +/// \param encryption encryption protocol namespace +/// \param senderKeyIds key IDs of the trust messages' senders +/// + +/// +/// \fn QXmppAtmTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption) +/// +/// Removes all keys for postponed authentication or distrusting for encryption. +/// +/// \param encryption encryption protocol namespace +/// + +/// +/// \fn QXmppAtmTrustStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds = {}) +/// +/// Returns the JIDs of key owners mapped to the IDs of their keys stored for +/// postponed authentication (true) or postponed distrusting (false). +/// +/// If senderKeyIds is empty, all keys for encryption are returned. +/// +/// \param encryption encryption protocol namespace +/// \param senderKeyIds key IDs of the trust messages' senders +/// +/// \return the key owner JIDs mapped to their keys +/// diff --git a/src/client/QXmppAtmTrustStorage.h b/src/client/QXmppAtmTrustStorage.h new file mode 100644 index 00000000..e801c7df --- /dev/null +++ b/src/client/QXmppAtmTrustStorage.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPATMTRUSTSTORAGE_H +#define QXMPPATMTRUSTSTORAGE_H + +#include "QXmppTrustStorage.h" + +class QXmppTrustMessageKeyOwner; + +class QXMPP_EXPORT QXmppAtmTrustStorage : virtual public QXmppTrustStorage +{ +public: + virtual ~QXmppAtmTrustStorage() = default; + + virtual QFuture addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) = 0; + virtual QFuture removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) = 0; + virtual QFuture removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) = 0; + virtual QFuture removeKeysForPostponedTrustDecisions(const QString &encryption) = 0; + virtual QFuture>> keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds = {}) = 0; +}; + +#endif // QXMPPATMTRUSTSTORAGE_H diff --git a/src/client/QXmppTrustMemoryStorage.cpp b/src/client/QXmppTrustMemoryStorage.cpp index f5e99b33..5a1b6e61 100644 --- a/src/client/QXmppTrustMemoryStorage.cpp +++ b/src/client/QXmppTrustMemoryStorage.cpp @@ -5,7 +5,6 @@ #include "QXmppTrustMemoryStorage.h" #include "QXmppFutureUtils_p.h" -#include "QXmppTrustMessageKeyOwner.h" using namespace QXmpp::Private; @@ -20,21 +19,13 @@ using namespace QXmpp::Private; /// \since QXmpp 1.5 /// -struct ProcessedKey +struct Key { QByteArray id; QString ownerJid; QXmppTrustStorage::TrustLevel trustLevel; }; -struct UnprocessedKey -{ - QByteArray id; - QString ownerJid; - QByteArray senderKeyId; - bool trust; -}; - class QXmppTrustMemoryStoragePrivate { public: @@ -45,11 +36,7 @@ public: QMap ownKeys; // encryption protocols mapped to keys with specified trust levels - QMultiHash processedKeys; - - // encryption protocols mapped to trust message data received from endpoints - // with unauthenticated keys - QMultiHash unprocessedKeys; + QMultiHash keys; }; /// @@ -63,16 +50,15 @@ QXmppTrustMemoryStorage::QXmppTrustMemoryStorage() QXmppTrustMemoryStorage::~QXmppTrustMemoryStorage() = default; /// \cond -QFuture QXmppTrustMemoryStorage::setSecurityPolicies(const QString &encryption, const QXmppTrustStorage::SecurityPolicy securityPolicy) +QFuture QXmppTrustMemoryStorage::setSecurityPolicy(const QString &encryption, const QXmppTrustStorage::SecurityPolicy securityPolicy) { - if (encryption.isEmpty()) { - d->securityPolicies.clear(); - } else if (securityPolicy == QXmppTrustStorage::NoSecurityPolicy) { - d->securityPolicies.remove(encryption); - } else { - d->securityPolicies.insert(encryption, securityPolicy); - } + d->securityPolicies.insert(encryption, securityPolicy); + return makeReadyFuture(); +} +QFuture QXmppTrustMemoryStorage::resetSecurityPolicy(const QString &encryption) +{ + d->securityPolicies.remove(encryption); return makeReadyFuture(); } @@ -81,13 +67,13 @@ QFuture QXmppTrustMemoryStorage::securityPoli return makeReadyFuture(std::move(d->securityPolicies.value(encryption))); } -QFuture QXmppTrustMemoryStorage::addOwnKey(const QString &encryption, const QByteArray &keyId) +QFuture QXmppTrustMemoryStorage::setOwnKey(const QString &encryption, const QByteArray &keyId) { d->ownKeys.insert(encryption, keyId); return makeReadyFuture(); } -QFuture QXmppTrustMemoryStorage::removeOwnKey(const QString &encryption) +QFuture QXmppTrustMemoryStorage::resetOwnKey(const QString &encryption) { d->ownKeys.remove(encryption); return makeReadyFuture(); @@ -102,11 +88,11 @@ QFuture QXmppTrustMemoryStorage::ownKey(const QString &encryption) QFuture QXmppTrustMemoryStorage::addKeys(const QString &encryption, const QString &keyOwnerJid, const QList &keyIds, const QXmppTrustStorage::TrustLevel trustLevel) { for (const auto &keyId : keyIds) { - ProcessedKey key; + Key key; key.id = keyId; key.ownerJid = keyOwnerJid; key.trustLevel = trustLevel; - d->processedKeys.insert(encryption, key); + d->keys.insert(encryption, key); } return makeReadyFuture(); @@ -114,30 +100,44 @@ QFuture QXmppTrustMemoryStorage::addKeys(const QString &encryption, const QFuture QXmppTrustMemoryStorage::removeKeys(const QString &encryption, const QList &keyIds) { - if (encryption.isEmpty()) { - d->processedKeys.clear(); - } else if (keyIds.isEmpty()) { - d->processedKeys.remove(encryption); - } else { - for (auto itr = d->processedKeys.find(encryption); - itr != d->processedKeys.end() && itr.key() == encryption;) { - if (keyIds.contains(itr.value().id)) { - itr = d->processedKeys.erase(itr); - } else { - itr++; - } + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + if (keyIds.contains(itr.value().id)) { + itr = d->keys.erase(itr); + } else { + ++itr; } } return makeReadyFuture(); } +QFuture QXmppTrustMemoryStorage::removeKeys(const QString &encryption, const QString &keyOwnerJid) +{ + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + if (itr.value().ownerJid == keyOwnerJid) { + itr = d->keys.erase(itr); + } else { + ++itr; + } + } + + return makeReadyFuture(); +} + +QFuture QXmppTrustMemoryStorage::removeKeys(const QString &encryption) +{ + d->keys.remove(encryption); + return makeReadyFuture(); +} + QFuture>> QXmppTrustMemoryStorage::keys(const QString &encryption, const TrustLevels trustLevels) { QHash> keys; - const auto processedKeys = d->processedKeys.values(encryption); - for (const auto &key : processedKeys) { + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { const auto trustLevel = key.trustLevel; if (trustLevels.testFlag(trustLevel) || !trustLevels) { keys[trustLevel].insert(key.ownerJid, key.id); @@ -147,6 +147,34 @@ QFuture>> Q return makeReadyFuture(std::move(keys)); } +QFuture>> QXmppTrustMemoryStorage::keys(const QString &encryption, const QList &keyOwnerJids, TrustLevels trustLevels) +{ + QHash> keys; + + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { + const auto keyOwnerJid = key.ownerJid; + const auto trustLevel = key.trustLevel; + if (keyOwnerJids.contains(keyOwnerJid) && (trustLevels.testFlag(trustLevel) || !trustLevels)) { + keys[keyOwnerJid].insert(key.id, trustLevel); + } + } + + return makeReadyFuture(std::move(keys)); +} + +QFuture QXmppTrustMemoryStorage::hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) +{ + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { + if (key.ownerJid == keyOwnerJid && trustLevels.testFlag(key.trustLevel)) { + return makeReadyFuture(std::move(true)); + } + } + + return makeReadyFuture(std::move(false)); +} + QFuture QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, const QMultiHash &keyIds, const TrustLevel trustLevel) { for (auto itr = keyIds.constBegin(); itr != keyIds.constEnd(); ++itr) { @@ -155,13 +183,13 @@ QFuture QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, auto isKeyFound = false; - for (auto itrProcessedKeys = d->processedKeys.find(encryption); - itrProcessedKeys != d->processedKeys.end() && itrProcessedKeys.key() == encryption; - ++itrProcessedKeys) { - auto &key = itrProcessedKeys.value(); + for (auto itrKeys = d->keys.find(encryption); + itrKeys != d->keys.end() && itrKeys.key() == encryption; + ++itrKeys) { + auto &key = itrKeys.value(); if (key.id == keyId && key.ownerJid == keyOwnerJid) { + // Update the stored trust level if it differs from the new one. if (key.trustLevel != trustLevel) { - // Update the stored trust level if it differs from the new one. key.trustLevel = trustLevel; } @@ -170,13 +198,13 @@ QFuture QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, } } + // Create a new entry and store it if there is no such entry yet. if (!isKeyFound) { - // Create a new entry and store it if there is no such entry yet. - ProcessedKey key; + Key key; key.id = keyId; key.ownerJid = keyOwnerJid; key.trustLevel = trustLevel; - d->processedKeys.insert(encryption, key); + d->keys.insert(encryption, key); } } @@ -185,7 +213,7 @@ QFuture QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, QFuture QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, const QList &keyOwnerJids, const QXmppTrustStorage::TrustLevel oldTrustLevel, const QXmppTrustStorage::TrustLevel newTrustLevel) { - for (auto itr = d->processedKeys.find(encryption); itr != d->processedKeys.end() && itr.key() == encryption; ++itr) { + for (auto itr = d->keys.find(encryption); itr != d->keys.end() && itr.key() == encryption; ++itr) { auto &key = itr.value(); if (keyOwnerJids.contains(key.ownerJid) && key.trustLevel == oldTrustLevel) { key.trustLevel = newTrustLevel; @@ -197,101 +225,22 @@ QFuture QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, QFuture QXmppTrustMemoryStorage::trustLevel(const QString &encryption, const QByteArray &keyId) { - const auto processedKeys = d->processedKeys.values(encryption); - for (const auto &key : processedKeys) { + const auto keys = d->keys.values(encryption); + for (const auto &key : keys) { if (key.id == keyId) { return makeReadyFuture(std::move(QXmppTrustStorage::TrustLevel(key.trustLevel))); } } - return makeReadyFuture(std::move(TrustLevel::AutomaticallyDistrusted)); -} - -QFuture QXmppTrustMemoryStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) -{ - const auto addKeys = [&](const QXmppTrustMessageKeyOwner &keyOwner, bool trust, const QList &keyIds) { - for (const auto &keyId : keyIds) { - auto isKeyFound = false; - - for (auto itr = d->unprocessedKeys.find(encryption); itr != d->unprocessedKeys.end() && itr.key() == encryption; ++itr) { - auto &key = itr.value(); - if (key.id == keyId && key.ownerJid == keyOwner.jid() && key.senderKeyId == senderKeyId) { - if (key.trust != trust) { - // Update the stored trust if it differs from the new one. - key.trust = trust; - } - - isKeyFound = true; - break; - } - } - - if (!isKeyFound) { - // Create a new entry and store it if there is no such entry yet. - UnprocessedKey key; - key.id = keyId; - key.ownerJid = keyOwner.jid(); - key.senderKeyId = senderKeyId; - key.trust = trust; - d->unprocessedKeys.insert(encryption, key); - } - } - }; - - for (const auto &keyOwner : keyOwners) { - addKeys(keyOwner, true, keyOwner.trustedKeys()); - addKeys(keyOwner, false, keyOwner.distrustedKeys()); - } - - return makeReadyFuture(); -} - -QFuture QXmppTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) -{ - for (auto itr = d->unprocessedKeys.find(encryption); - itr != d->unprocessedKeys.end() && itr.key() == encryption;) { - const auto &key = itr.value(); - if ((key.trust && keyIdsForAuthentication.contains(key.id)) || - (!key.trust && keyIdsForDistrusting.contains(key.id))) { - itr = d->unprocessedKeys.erase(itr); - } else { - ++itr; - } - } - return makeReadyFuture(); + return makeReadyFuture(std::move(QXmppTrustStorage::Undecided)); } -QFuture QXmppTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) +QFuture QXmppTrustMemoryStorage::resetAll(const QString &encryption) { - if (encryption.isEmpty()) { - d->unprocessedKeys.clear(); - } else if (senderKeyIds.isEmpty()) { - d->unprocessedKeys.remove(encryption); - } else { - for (auto itr = d->unprocessedKeys.find(encryption); - itr != d->unprocessedKeys.end() && itr.key() == encryption;) { - if (senderKeyIds.contains(itr.value().senderKeyId)) { - itr = d->unprocessedKeys.erase(itr); - } else { - ++itr; - } - } - } + d->securityPolicies.remove(encryption); + d->ownKeys.remove(encryption); + d->keys.remove(encryption); return makeReadyFuture(); } - -QFuture>> QXmppTrustMemoryStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds) -{ - QHash> keys; - - const auto unprocessedKeys = d->unprocessedKeys.values(encryption); - for (const auto &key : unprocessedKeys) { - if (senderKeyIds.contains(key.senderKeyId) || senderKeyIds.isEmpty()) { - keys[key.trust].insert(key.ownerJid, key.id); - } - } - - return makeReadyFuture(std::move(keys)); -} /// \endcond diff --git a/src/client/QXmppTrustMemoryStorage.h b/src/client/QXmppTrustMemoryStorage.h index 63b8a14e..08696039 100644 --- a/src/client/QXmppTrustMemoryStorage.h +++ b/src/client/QXmppTrustMemoryStorage.h @@ -5,39 +5,40 @@ #ifndef QXMPPTRUSTMEMORYSTORAGE_H #define QXMPPTRUSTMEMORYSTORAGE_H -#include "QXmppGlobal.h" #include "QXmppTrustStorage.h" #include class QXmppTrustMemoryStoragePrivate; -class QXMPP_EXPORT QXmppTrustMemoryStorage : public QXmppTrustStorage +class QXMPP_EXPORT QXmppTrustMemoryStorage : virtual public QXmppTrustStorage { public: QXmppTrustMemoryStorage(); ~QXmppTrustMemoryStorage(); /// \cond - QFuture setSecurityPolicies(const QString &encryption = {}, SecurityPolicy securityPolicy = QXmppTrustStorage::NoSecurityPolicy) override; + QFuture setSecurityPolicy(const QString &encryption, SecurityPolicy securityPolicy) override; + QFuture resetSecurityPolicy(const QString &encryption) override; QFuture securityPolicy(const QString &encryption) override; - QFuture addOwnKey(const QString &encryption, const QByteArray &keyId) override; - QFuture removeOwnKey(const QString &encryption) override; + QFuture setOwnKey(const QString &encryption, const QByteArray &keyId) override; + QFuture resetOwnKey(const QString &encryption) override; QFuture ownKey(const QString &encryption) override; QFuture addKeys(const QString &encryption, const QString &keyOwnerJid, const QList &keyIds, TrustLevel trustLevel = TrustLevel::AutomaticallyDistrusted) override; - QFuture removeKeys(const QString &encryption = {}, const QList &keyIds = {}) override; + QFuture removeKeys(const QString &encryption, const QList &keyIds) override; + QFuture removeKeys(const QString &encryption, const QString &keyOwnerJid) override; + QFuture removeKeys(const QString &encryption) override; QFuture>> keys(const QString &encryption, TrustLevels trustLevels = {}) override; + QFuture>> keys(const QString &encryption, const QList &keyOwnerJids, TrustLevels trustLevels = {}) override; + QFuture hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) override; QFuture setTrustLevel(const QString &encryption, const QMultiHash &keyIds, const TrustLevel trustLevel) override; QFuture setTrustLevel(const QString &encryption, const QList &keyOwnerJids, const TrustLevel oldTrustLevel, const TrustLevel newTrustLevel) override; QFuture trustLevel(const QString &encryption, const QByteArray &keyId) override; - QFuture addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) override; - QFuture removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) override; - QFuture removeKeysForPostponedTrustDecisions(const QString &encryption = {}, const QList &senderKeyIds = {}) override; - QFuture>> keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds = {}) override; + QFuture resetAll(const QString &encryption) override; /// \endcond private: diff --git a/src/client/QXmppTrustStorage.cpp b/src/client/QXmppTrustStorage.cpp index dc26d1ed..149eccfe 100644 --- a/src/client/QXmppTrustStorage.cpp +++ b/src/client/QXmppTrustStorage.cpp @@ -8,25 +8,30 @@ /// \brief The QXmppTrustStorage class stores trust data for end-to-end /// encryption. /// +/// The term "key" is used for a public long-term key. +/// /// \warning THIS API IS NOT FINALIZED YET! /// /// \since QXmpp 1.5 /// /// -/// \fn QXmppTrustStorage::setSecurityPolicies(const QString &encryption = {}, SecurityPolicy securityPolicy = SecurityPolicy::NoSecurityPolicy) -/// -/// Sets the security policy for an encryption protocol or resets the set -/// security policies. +/// \fn QXmppTrustStorage::setSecurityPolicy(const QString &encryption, SecurityPolicy securityPolicy) /// -/// If securityPolicy is not passed, the set security policy for encryption is -/// reset. -/// If also encryption is not passed, all set security policies are reset. +/// Sets the security policy for an encryption protocol. /// /// \param encryption encryption protocol namespace /// \param securityPolicy security policy being applied /// +/// +/// \fn QXmppTrustStorage::resetSecurityPolicy(const QString &encryption) +/// +/// Resets the security policy for an encryption protocol. +/// +/// \param encryption encryption protocol namespace +/// + /// /// \fn QXmppTrustStorage::securityPolicy(const QString &encryption) /// @@ -38,18 +43,20 @@ /// /// -/// \fn QXmppTrustStorage::addOwnKey(const QString &encryption, const QByteArray &keyId) +/// \fn QXmppTrustStorage::setOwnKey(const QString &encryption, const QByteArray &keyId) /// -/// Adds an own key (i.e., the key used by this client instance). +/// Sets the own key (i.e., the key used by this client instance) for an +/// encryption protocol. /// /// \param encryption encryption protocol namespace /// \param keyId ID of the key /// /// -/// \fn QXmppTrustStorage::removeOwnKey(const QString &encryption) +/// \fn QXmppTrustStorage::resetOwnKey(const QString &encryption) /// -/// Removes an own key (i.e., the key used by this client instance). +/// Resets the own key (i.e., the key used by this client instance) for an +/// encryption protocol. /// /// \param encryption encryption protocol namespace /// @@ -57,7 +64,8 @@ /// /// \fn QXmppTrustStorage::ownKey(const QString &encryption) /// -/// Returns an own key (i.e., the key used by this client instance). +/// Returns the own key (i.e., the key used by this client instance) for an +/// encryption protocol. /// /// \param encryption encryption protocol namespace /// @@ -80,120 +88,110 @@ /// /// Removes keys. /// -/// If keyIds is not passed, all keys for encryption are removed. -/// If encryption is also not passed, all keys are removed. -/// /// \param encryption encryption protocol namespace /// \param keyIds IDs of the keys /// /// -/// \fn QXmppTrustStorage::keys(const QString &encryption, TrustLevels trustLevels = {}) -/// -/// Returns the JIDs of the key owners mapped to the IDs of their keys with a -/// specific trust level. +/// \fn QXmppTrustStorage::removeKeys(const QString &encryption, const QString &keyOwnerJid) /// -/// If no trust levels are passed, all keys are returned. +/// Removes all keys of a key owner. /// /// \param encryption encryption protocol namespace -/// \param trustLevels trust levels of the keys +/// \param keyOwnerJid key owner's bare JID +/// + /// -/// \return the key owner JIDs mapped to their keys with a specific trust level +/// \fn QXmppTrustStorage::removeKeys(const QString &encryption) +/// +/// Removes all keys for encryption. +/// +/// \param encryption encryption protocol namespace /// /// -/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QMultiHash &keyIds, TrustLevel trustLevel) +/// \fn QXmppTrustStorage::keys(const QString &encryption, TrustLevels trustLevels = {}) /// -/// Sets the trust level of keys. +/// Returns the JIDs of all key owners mapped to the IDs of their keys with +/// specific trust levels. /// -/// If a key is not stored, it is added to the storage. +/// If no trust levels are passed, all keys for encryption are returned. /// /// \param encryption encryption protocol namespace -/// \param keyIds key owners' bare JIDs mapped to the IDs of their keys -/// \param trustLevel trust level being set +/// \param trustLevels trust levels of the keys +/// +/// \return the key owner JIDs mapped to their keys with specific trust levels /// /// -/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QList &keyOwnerJids, TrustLevel oldTrustLevel, TrustLevel newTrustLevel) +/// \fn QXmppTrustStorage::keys(const QString &encryption, const QList &keyOwnerJids, TrustLevels trustLevels = {}) /// -/// Sets the trust level of keys specified by their key owner and trust level. +/// Returns the IDs of keys mapped to their trust levels for specific key +/// owners. +/// +/// If no trust levels are passed, all keys for encryption and keyOwnerJids are +/// returned. /// /// \param encryption encryption protocol namespace /// \param keyOwnerJids key owners' bare JIDs -/// \param oldTrustLevel trust level being changed -/// \param newTrustLevel trust level being set +/// \param trustLevels trust levels of the keys /// - +/// \return the key IDs mapped to their trust levels for specific key owners /// -/// \fn QXmppTrustStorage::trustLevel(const QString &encryption, const QByteArray &keyId) + /// -/// Returns the trust level of a key. +/// \fn QXmppTrustStorage::hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) /// -/// If the key is not stored, it is seen as automatically distrusted. +/// Returns whether at least one key of a key owner with a specific trust level +/// is stored. /// /// \param encryption encryption protocol namespace -/// \param keyId ID of the key +/// \param keyOwnerJid key owner's bare JID +/// \param trustLevels possible trust levels of the key /// -/// \return the key's trust level +/// \return whether a key of the key owner with a passed trust level is stored /// /// -/// \fn QXmppTrustStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) -/// -/// Adds keys that cannot be authenticated or distrusted directly because the -/// key of the trust message's sender is not yet authenticated. +/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QMultiHash &keyIds, TrustLevel trustLevel) /// -/// Those keys are being authenticated or distrusted once the sender's key is -/// authenticated. -/// Each element of keyOwners (i.e., keyOwner) can contain keys for postponed -/// authentication as trustedKeys or for postponed distrusting as -/// distrustedKeys. +/// Sets the trust level of keys. /// -/// If keys of keyOwner.trustedKeys() are already stored for postponed -/// distrusting, they are changed to be used for postponed authentication. -/// If keys of keyOwner.distrustedKeys() are already stored for postponed -/// authentication, they are changed to be used for postponed distrusting. -/// If the same keys are in keyOwner.trustedKeys() and -/// keyOwner.distrustedKeys(), they are used for postponed distrusting. +/// If a key is not stored, it is added to the storage. /// /// \param encryption encryption protocol namespace -/// \param senderKeyId key ID of the trust message's sender -/// \param keyOwners key owners containing key IDs for postponed trust decisions +/// \param keyIds key owners' bare JIDs mapped to the IDs of their keys +/// \param trustLevel trust level being set /// /// -/// \fn QXmppTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) +/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QList &keyOwnerJids, TrustLevel oldTrustLevel, TrustLevel newTrustLevel) /// -/// Removes keys for postponed authentication or distrusting. +/// Sets the trust level of keys specified by their key owner and trust level. /// /// \param encryption encryption protocol namespace -/// \param keyIdsForAuthentication IDs of the keys for postponed authentication -/// \param keyIdsForDistrusting IDs of the keys for postponed distrusting +/// \param keyOwnerJids key owners' bare JIDs +/// \param oldTrustLevel trust level being changed +/// \param newTrustLevel trust level being set /// /// -/// \fn QXmppTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption = {}, const QList &senderKeyIds = {}) +/// \fn QXmppTrustStorage::trustLevel(const QString &encryption, const QByteArray &keyId) /// -/// Removes keys for postponed authentication or distrusting by the trust -/// message's sender's key ID. +/// Returns the trust level of a key. /// -/// If senderKeyIds is empty, all keys for encryption are removed. -/// If encryption is empty too, all keys are removed. +/// If the key is not stored, the trust in that key is undecided. /// /// \param encryption encryption protocol namespace -/// \param senderKeyIds key IDs of the trust messages' senders +/// \param keyId ID of the key /// - +/// \return the key's trust level /// -/// \fn QXmppTrustStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds = {}) + /// -/// Returns the JIDs of key owners mapped to the IDs of their keys stored for -/// postponed authentication (true) or postponed distrusting (false). +/// \fn QXmppTrustStorage::resetAll(const QString &encryption) /// -/// If senderKeyIds is empty, all keys for encryption are returned. +/// Resets all data for encryption. /// /// \param encryption encryption protocol namespace -/// \param senderKeyIds key IDs of the trust messages' senders -/// -/// \return the key owner JIDs mapped to their keys /// diff --git a/src/client/QXmppTrustStorage.h b/src/client/QXmppTrustStorage.h index 2c7b593e..dffbcfae 100644 --- a/src/client/QXmppTrustStorage.h +++ b/src/client/QXmppTrustStorage.h @@ -9,8 +9,6 @@ #include -class QXmppTrustMessageKeyOwner; - class QXMPP_EXPORT QXmppTrustStorage { public: @@ -20,7 +18,7 @@ public: /// enum SecurityPolicy { NoSecurityPolicy, ///< New keys must be trusted manually. - Toakafa, ///< New keys are trusted automatically until the first authentication but automatically distrusted afterwards. + Toakafa, ///< New keys are trusted automatically until the first authentication but automatically distrusted afterwards. \see \xep{0450, Automatic Trust Management (ATM)} }; /// @@ -28,35 +26,38 @@ public: /// protocols /// enum TrustLevel { - AutomaticallyDistrusted = 1, ///< The key is automatically distrusted (e.g., by ATM's security policy). - ManuallyDistrusted = 2, ///< The key is manually distrusted (e.g., by clicking a button or ATM). - AutomaticallyTrusted = 4, ///< The key is automatically trusted (e.g., by the client for all keys of a bare JID until one of it is authenticated). - ManuallyTrusted = 8, ///< The key is manually trusted (e.g., by clicking a button). - Authenticated = 16, ///< The key is authenticated (e.g., by QR code scanning or ATM). + Undecided = 1, ///< The key's trust is not decided. + AutomaticallyDistrusted = 2, ///< The key is automatically distrusted (e.g., by the security policy TOAKAFA). \see SecurityPolicy + ManuallyDistrusted = 4, ///< The key is manually distrusted (e.g., by clicking a button or \xep{0450, Automatic Trust Management (ATM)}). + AutomaticallyTrusted = 8, ///< The key is automatically trusted (e.g., by the client for all keys of a bare JID until one of it is authenticated). + ManuallyTrusted = 16, ///< The key is manually trusted (e.g., by clicking a button). + Authenticated = 32, ///< The key is authenticated (e.g., by QR code scanning or \xep{0450, Automatic Trust Management (ATM)}). }; Q_DECLARE_FLAGS(TrustLevels, TrustLevel) virtual ~QXmppTrustStorage() = default; - virtual QFuture setSecurityPolicies(const QString &encryption = {}, SecurityPolicy securityPolicy = SecurityPolicy::NoSecurityPolicy) = 0; + virtual QFuture setSecurityPolicy(const QString &encryption, SecurityPolicy securityPolicy) = 0; + virtual QFuture resetSecurityPolicy(const QString &encryption) = 0; virtual QFuture securityPolicy(const QString &encryption) = 0; - virtual QFuture addOwnKey(const QString &encryption, const QByteArray &keyId) = 0; - virtual QFuture removeOwnKey(const QString &encryption) = 0; + virtual QFuture setOwnKey(const QString &encryption, const QByteArray &keyId) = 0; + virtual QFuture resetOwnKey(const QString &encryption) = 0; virtual QFuture ownKey(const QString &encryption) = 0; virtual QFuture addKeys(const QString &encryption, const QString &keyOwnerJid, const QList &keyIds, TrustLevel trustLevel = TrustLevel::AutomaticallyDistrusted) = 0; - virtual QFuture removeKeys(const QString &encryption = {}, const QList &keyIds = {}) = 0; + virtual QFuture removeKeys(const QString &encryption, const QList &keyIds) = 0; + virtual QFuture removeKeys(const QString &encryption, const QString &keyOwnerJid) = 0; + virtual QFuture removeKeys(const QString &encryption) = 0; virtual QFuture>> keys(const QString &encryption, TrustLevels trustLevels = {}) = 0; + virtual QFuture>> keys(const QString &encryption, const QList &keyOwnerJids, TrustLevels trustLevels = {}) = 0; + virtual QFuture hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) = 0; virtual QFuture setTrustLevel(const QString &encryption, const QMultiHash &keyIds, TrustLevel trustLevel) = 0; virtual QFuture setTrustLevel(const QString &encryption, const QList &keyOwnerJids, TrustLevel oldTrustLevel, TrustLevel newTrustLevel) = 0; virtual QFuture trustLevel(const QString &encryption, const QByteArray &keyId) = 0; - virtual QFuture addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList &keyOwners) = 0; - virtual QFuture removeKeysForPostponedTrustDecisions(const QString &encryption, const QList &keyIdsForAuthentication, const QList &keyIdsForDistrusting) = 0; - virtual QFuture removeKeysForPostponedTrustDecisions(const QString &encryption = {}, const QList &senderKeyIds = {}) = 0; - virtual QFuture>> keysForPostponedTrustDecisions(const QString &encryption, const QList &senderKeyIds = {}) = 0; + virtual QFuture resetAll(const QString &encryption) = 0; }; Q_DECLARE_METATYPE(QXmppTrustStorage::SecurityPolicy) -- cgit v1.2.3