diff options
| author | Linus Jahn <lnj@kaidan.im> | 2022-05-31 12:22:48 +0200 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2022-08-13 15:55:03 +0200 |
| commit | f0e0e1cd227c08ffd97aa42813a479b8c3ca6d23 (patch) | |
| tree | 12ca6aefdef9195ee8937406db86e73cf1a5f820 /src/omemo/QXmppOmemoManager_p.h | |
| parent | 87df8a8dda385558d39639ce09e2717974264ab6 (diff) | |
| download | qxmpp-f0e0e1cd227c08ffd97aa42813a479b8c3ca6d23.tar.gz | |
Split up OMEMO into extra module
Diffstat (limited to 'src/omemo/QXmppOmemoManager_p.h')
| -rw-r--r-- | src/omemo/QXmppOmemoManager_p.h | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/src/omemo/QXmppOmemoManager_p.h b/src/omemo/QXmppOmemoManager_p.h new file mode 100644 index 00000000..7f697ed2 --- /dev/null +++ b/src/omemo/QXmppOmemoManager_p.h @@ -0,0 +1,342 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// SPDX-FileCopyrightText: 2022 Linus Jahn <lnj@kaidan.im> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPOMEMOMANAGER_P_H +#define QXMPPOMEMOMANAGER_P_H + +#include "QXmppE2eeMetadata.h" +#include "QXmppOmemoDeviceBundle_p.h" +#include "QXmppOmemoManager.h" +#include "QXmppOmemoStorage.h" + +#include "OmemoLibWrappers.h" +#include <QDomElement> +#include <QTimer> +#include <QtCrypto> + +class QXmppTrustManager; +class QXmppOmemoManager; +class QXmppPubSubManager; +class QXmppPubSubNodeConfig; +class QXmppPubSubPublishOptions; +class QXmppOmemoIq; +class QXmppOmemoEnvelope; +class QXmppOmemoElement; +class QXmppOmemoDeviceListItem; +class QXmppOmemoDeviceBundleItem; + +using namespace QXmpp; +using namespace std::chrono_literals; + +namespace QXmpp::Omemo::Private { + +// default possible trust levels a key must have to be used for encryption +// The class documentation must be adapted if the trust levels are modified. +constexpr auto ACCEPTED_TRUST_LEVELS = TrustLevel::AutomaticallyTrusted | TrustLevel::ManuallyTrusted | TrustLevel::Authenticated; + +// count of unresponded stanzas sent to a device until QXmpp stops encrypting for it +constexpr int UNRESPONDED_STANZAS_UNTIL_ENCRYPTION_IS_STOPPED = 106; + +// count of unresponded stanzas received from a device until a heartbeat message is sent to it +constexpr int UNRESPONDED_STANZAS_UNTIL_HEARTBEAT_MESSAGE_IS_SENT = 53; + +// size of empty OMEMO message's decryption data +constexpr int EMPTY_MESSAGE_DECRYPTION_DATA_SIZE = 32; + +// workaround for PubSub nodes that are not configurable to store 'max' as the value for +// 'pubsub#max_items' +constexpr uint64_t PUBSUB_NODE_MAX_ITEMS_1 = 1000; +constexpr uint64_t PUBSUB_NODE_MAX_ITEMS_2 = 100; +constexpr uint64_t PUBSUB_NODE_MAX_ITEMS_3 = 10; + +constexpr uint32_t PRE_KEY_ID_MIN = 1; +constexpr uint32_t SIGNED_PRE_KEY_ID_MIN = 1; +constexpr uint32_t PRE_KEY_ID_MAX = std::numeric_limits<int32_t>::max(); +constexpr uint32_t SIGNED_PRE_KEY_ID_MAX = std::numeric_limits<int32_t>::max(); +constexpr uint32_t PRE_KEY_INITIAL_CREATION_COUNT = 100; + +// maximum count of devices stored per JID +constexpr int DEVICES_PER_JID_MAX = 200; + +// maximum count of devices for whom a stanza is encrypted +constexpr int DEVICES_PER_STANZA_MAX = 1000; + +// interval to remove old signed pre keys and create new ones +constexpr auto SIGNED_PRE_KEY_RENEWAL_INTERVAL = 24h * 7 * 4; + +// interval to check for old signed pre keys +constexpr auto SIGNED_PRE_KEY_RENEWAL_CHECK_INTERVAL = 24h; + +// interval to remove devices locally after removal from their servers +constexpr auto DEVICE_REMOVAL_INTERVAL = 24h * 7 * 12; + +// interval to check for devices removed from their servers +constexpr auto DEVICE_REMOVAL_CHECK_INTERVAL = 24h; + +constexpr auto PAYLOAD_CIPHER_TYPE = "aes256"; +constexpr QCA::Cipher::Mode PAYLOAD_CIPHER_MODE = QCA::Cipher::CBC; +constexpr QCA::Cipher::Padding PAYLOAD_CIPHER_PADDING = QCA::Cipher::PKCS7; + +constexpr auto HKDF_INFO = "OMEMO Payload"; +constexpr int HKDF_KEY_SIZE = 32; +constexpr int HKDF_SALT_SIZE = 32; +constexpr int HKDF_OUTPUT_SIZE = 60; + +extern const QString PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE; +constexpr uint32_t PAYLOAD_MESSAGE_AUTHENTICATION_CODE_SIZE = 16; + +constexpr int PAYLOAD_KEY_SIZE = 32; +constexpr uint32_t PAYLOAD_INITIALIZATION_VECTOR_SIZE = 16; +constexpr uint32_t PAYLOAD_AUTHENTICATION_KEY_SIZE = 16; + +// boundaries for the count of characters in SCE's <rpad/> element +constexpr uint32_t SCE_RPAD_SIZE_MIN = 0; +constexpr uint32_t SCE_RPAD_SIZE_MAX = 200; + +struct PayloadEncryptionResult +{ + QCA::SecureArray decryptionData; + QByteArray encryptedPayload; +}; + +struct DecryptionResult +{ + QDomElement sceContent; + QXmppE2eeMetadata e2eeMetadata; +}; + +struct IqDecryptionResult +{ + QDomElement iq; + QXmppE2eeMetadata e2eeMetadata; +}; + +QByteArray createKeyId(const QByteArray &key); + +} // namespace QXmpp::Omemo::Private + +using namespace QXmpp::Omemo::Private; + +class QXmppOmemoManagerPrivate +{ +public: + using Result = std::variant<QXmpp::Success, QXmppStanza::Error>; + + QXmppOmemoManager *q; + + bool isStarted = false; + bool isNewDeviceAutoSessionBuildingEnabled = false; + + QXmppOmemoStorage *omemoStorage; + QXmppTrustManager *trustManager = nullptr; + QXmppPubSubManager *pubSubManager = nullptr; + + QCA::Initializer cryptoLibInitializer; + QTimer signedPreKeyPairsRenewalTimer; + QTimer deviceRemovalTimer; + + TrustLevels acceptedSessionBuildingTrustLevels = ACCEPTED_TRUST_LEVELS; + + QXmppOmemoStorage::OwnDevice ownDevice; + QHash<uint32_t, QByteArray> preKeyPairs; + QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> signedPreKeyPairs; + QXmppOmemoDeviceBundle deviceBundle; + + int maximumDevicesPerJid = DEVICES_PER_JID_MAX; + int maximumDevicesPerStanza = DEVICES_PER_STANZA_MAX; + + // recipient JID mapped to device ID mapped to device + QHash<QString, QHash<uint32_t, QXmppOmemoStorage::Device>> devices; + + QList<QString> jidsOfManuallySubscribedDevices; + + OmemoContextPtr globalContext; + StoreContextPtr storeContext; + QRecursiveMutex mutex; + signal_crypto_provider cryptoProvider; + + signal_protocol_identity_key_store identityKeyStore; + signal_protocol_pre_key_store preKeyStore; + signal_protocol_signed_pre_key_store signedPreKeyStore; + signal_protocol_session_store sessionStore; + + QXmppOmemoManagerPrivate(QXmppOmemoManager *parent, QXmppOmemoStorage *omemoStorage); + + void init(); + bool initGlobalContext(); + bool initLocking(); + bool initCryptoProvider(); + void initStores(); + + signal_protocol_identity_key_store createIdentityKeyStore() const; + signal_protocol_signed_pre_key_store createSignedPreKeyStore() const; + signal_protocol_pre_key_store createPreKeyStore() const; + signal_protocol_session_store createSessionStore() const; + + QFuture<bool> setUpDeviceId(); + bool setUpIdentityKeyPair(ratchet_identity_key_pair **identityKeyPair); + void schedulePeriodicTasks(); + void renewSignedPreKeyPairs(); + bool updateSignedPreKeyPair(ratchet_identity_key_pair *identityKeyPair); + bool renewPreKeyPairs(uint32_t keyPairBeingRenewed); + bool updatePreKeyPairs(uint32_t count = 1); + void removeDevicesRemovedFromServer(); + bool generateIdentityKeyPair(ratchet_identity_key_pair **identityKeyPair) const; + + QFuture<QXmppE2eeExtension::MessageEncryptResult> encryptMessageForRecipients(QXmppMessage &&message, + QVector<QString> recipientJids, + TrustLevels acceptedTrustLevels); + template<typename T> + QFuture<std::optional<QXmppOmemoElement>> encryptStanza(const T &stanza, const QVector<QString> &recipientJids, TrustLevels acceptedTrustLevels); + std::optional<PayloadEncryptionResult> encryptPayload(const QByteArray &payload) const; + template<typename T> + QByteArray createSceEnvelope(const T &stanza); + QByteArray createOmemoEnvelopeData(const signal_protocol_address &address, const QCA::SecureArray &payloadDecryptionData) const; + + QFuture<std::optional<QXmppMessage>> decryptMessage(QXmppMessage stanza); + QFuture<std::optional<IqDecryptionResult>> decryptIq(const QDomElement &iqElement); + template<typename T> + QFuture<std::optional<DecryptionResult>> decryptStanza(T stanza, + const QString &senderJid, + uint32_t senderDeviceId, + const QXmppOmemoEnvelope &omemoEnvelope, + const QByteArray &omemoPayload, + bool isMessageStanza = true); + QFuture<QByteArray> extractSceEnvelope(const QString &senderJid, + uint32_t senderDeviceId, + const QXmppOmemoEnvelope &omemoEnvelope, + const QByteArray &omemoPayload, + bool isMessageStanza); + QFuture<QCA::SecureArray> extractPayloadDecryptionData(const QString &senderJid, + uint32_t senderDeviceId, + const QXmppOmemoEnvelope &omemoEnvelope, + bool isMessageStanza = true); + QByteArray decryptPayload(const QCA::SecureArray &payloadDecryptionData, const QByteArray &payload) const; + + QFuture<bool> publishOmemoData(); + + template<typename Function> + void publishDeviceBundle(bool isDeviceBundlesNodeExistent, + bool arePublishOptionsSupported, + bool isAutomaticCreationSupported, + bool isCreationAndConfigurationSupported, + bool isCreationSupported, + bool isConfigurationSupported, + bool isConfigNodeMaxSupported, + Function continuation); + template<typename Function> + void publishDeviceBundleWithoutOptions(bool isDeviceBundlesNodeExistent, + bool isCreationAndConfigurationSupported, + bool isCreationSupported, + bool isConfigurationSupported, + bool isConfigNodeMaxSupported, + Function continuation); + template<typename Function> + void configureNodeAndPublishDeviceBundle(bool isConfigNodeMaxSupported, Function continuation); + template<typename Function> + void createAndConfigureDeviceBundlesNode(bool isConfigNodeMaxSupported, Function continuation); + template<typename Function> + void createDeviceBundlesNode(Function continuation); + template<typename Function> + void configureDeviceBundlesNode(bool isConfigNodeMaxSupported, Function continuation); + template<typename Function> + void publishDeviceBundleItem(Function continuation); + template<typename Function> + void publishDeviceBundleItemWithOptions(Function continuation); + QXmppOmemoDeviceBundleItem deviceBundleItem() const; + QFuture<std::optional<QXmppOmemoDeviceBundle>> requestDeviceBundle(const QString &deviceOwnerJid, uint32_t deviceId) const; + template<typename Function> + void deleteDeviceBundle(Function continuation); + + template<typename Function> + void publishDeviceElement(bool isDeviceListNodeExistent, + bool arePublishOptionsSupported, + bool isAutomaticCreationSupported, + bool isCreationAndConfigurationSupported, + bool isCreationSupported, + bool isConfigurationSupported, + Function continuation); + template<typename Function> + void publishDeviceElementWithoutOptions(bool isDeviceListNodeExistent, + bool isCreationAndConfigurationSupported, + bool isCreationSupported, + bool isConfigurationSupported, + Function continuation); + template<typename Function> + void configureNodeAndPublishDeviceElement(Function continuation); + template<typename Function> + void createAndConfigureDeviceListNode(Function continuation); + template<typename Function> + void createDeviceListNode(Function continuation); + template<typename Function> + void configureDeviceListNode(Function continuation); + template<typename Function> + void publishDeviceListItem(bool addOwnDevice, Function continuation); + template<typename Function> + void publishDeviceListItemWithOptions(Function continuation); + QXmppOmemoDeviceListItem deviceListItem(bool addOwnDevice = true); + template<typename Function> + void updateOwnDevicesLocally(bool isDeviceListNodeExistent, Function continuation); + void updateDevices(const QString &deviceOwnerJid, const QXmppOmemoDeviceListItem &deviceListItem); + void handleIrregularDeviceListChanges(const QString &deviceOwnerJid); + template<typename Function> + void deleteDeviceElement(Function continuation); + + template<typename Function> + void createNode(const QString &node, Function continuation); + template<typename Function> + void createNode(const QString &node, const QXmppPubSubNodeConfig &config, Function continuation); + template<typename Function> + void configureNode(const QString &node, const QXmppPubSubNodeConfig &config, Function continuation); + template<typename Function> + void retractItem(const QString &node, uint32_t itemId, Function continuation); + template<typename Function> + void deleteNode(const QString &node, Function continuation); + + template<typename T, typename Function> + void publishItem(const QString &node, const T &item, Function continuation); + template<typename T, typename Function> + void publishItem(const QString &node, const T &item, const QXmppPubSubPublishOptions &publishOptions, Function continuation); + + template<typename T, typename Function> + void runPubSubQueryWithContinuation(QFuture<T> future, const QString &errorMessage, Function continuation); + + QFuture<bool> changeDeviceLabel(const QString &deviceLabel); + + QFuture<QXmppPubSubManager::ItemResult<QXmppOmemoDeviceListItem>> requestDeviceList(const QString &jid); + void subscribeToNewDeviceLists(const QString &jid, uint32_t deviceId); + QFuture<Result> subscribeToDeviceList(const QString &jid); + QFuture<QXmppOmemoManager::DevicesResult> unsubscribeFromDeviceLists(const QList<QString> &jids); + QFuture<Result> unsubscribeFromDeviceList(const QString &jid); + + QFuture<bool> resetOwnDevice(); + QFuture<bool> resetAll(); + + QFuture<bool> buildSessionForNewDevice(const QString &jid, uint32_t deviceId, QXmppOmemoStorage::Device &device); + QFuture<bool> buildSessionWithDeviceBundle(const QString &jid, uint32_t deviceId, QXmppOmemoStorage::Device &device); + bool buildSession(signal_protocol_address address, const QXmppOmemoDeviceBundle &deviceBundle); + bool createSessionBundle(session_pre_key_bundle **sessionBundle, + const QByteArray &serializedPublicIdentityKey, + const QByteArray &serializedSignedPublicPreKey, + uint32_t signedPublicPreKeyId, + const QByteArray &serializedSignedPublicPreKeySignature, + const QByteArray &serializedPublicPreKey, + uint32_t publicPreKeyId); + bool deserializePublicIdentityKey(ec_public_key **publicIdentityKey, const QByteArray &serializedPublicIdentityKey) const; + bool deserializeSignedPublicPreKey(ec_public_key **signedPublicPreKey, const QByteArray &serializedSignedPublicPreKey) const; + bool deserializePublicPreKey(ec_public_key **publicPreKey, const QByteArray &serializedPublicPreKey) const; + + QFuture<QXmpp::SendResult> sendEmptyMessage(const QString &recipientJid, uint32_t recipientDeviceId, bool isKeyExchange = false) const; + QFuture<void> storeOwnKey() const; + QFuture<TrustLevel> storeKeyDependingOnSecurityPolicy(const QString &keyOwnerJid, const QByteArray &key); + QFuture<TrustLevel> storeKey(const QString &keyOwnerJid, const QByteArray &key, TrustLevel trustLevel = TrustLevel::AutomaticallyDistrusted) const; + QString ownBareJid() const; + QString ownFullJid() const; + QHash<uint32_t, QXmppOmemoStorage::Device> otherOwnDevices(); + + void warning(const QString &msg) const; +}; + +#endif // QXMPPOMEMOMANAGER_P_H |
