aboutsummaryrefslogtreecommitdiff
path: root/src/omemo/QXmppOmemoManager_p.cpp
diff options
context:
space:
mode:
authorLinus Jahn <lnj@kaidan.im>2023-03-11 00:29:02 +0100
committerLinus Jahn <lnj@kaidan.im>2023-03-11 00:29:02 +0100
commit463111576fb1476192acd2d8fe415b8482a8a696 (patch)
treee87e3bb8f8724f019954692ac22b0d6386dfa5e7 /src/omemo/QXmppOmemoManager_p.cpp
parent6ea3edfd83a0bf1558d43e48eac563730276c175 (diff)
parent4897c9b6a36e961fb44d2bce04a698f979a423d5 (diff)
downloadqxmpp-463111576fb1476192acd2d8fe415b8482a8a696.tar.gz
Merge branch '1.5'
Diffstat (limited to 'src/omemo/QXmppOmemoManager_p.cpp')
-rw-r--r--src/omemo/QXmppOmemoManager_p.cpp166
1 files changed, 57 insertions, 109 deletions
diff --git a/src/omemo/QXmppOmemoManager_p.cpp b/src/omemo/QXmppOmemoManager_p.cpp
index 2e08da04..1c86d80b 100644
--- a/src/omemo/QXmppOmemoManager_p.cpp
+++ b/src/omemo/QXmppOmemoManager_p.cpp
@@ -7,13 +7,12 @@
#include "QXmppOmemoManager_p.h"
-#include "QXmppConstants_p.h"
#include "QXmppOmemoDeviceElement_p.h"
#include "QXmppOmemoElement_p.h"
#include "QXmppOmemoEnvelope_p.h"
#include "QXmppOmemoIq_p.h"
#include "QXmppOmemoItems_p.h"
-#include "QXmppPubSubItem.h"
+#include "QXmppPubSubBaseItem.h"
#include "QXmppSceEnvelope_p.h"
#include "QXmppTrustManager.h"
#include "QXmppUtils.h"
@@ -25,6 +24,9 @@
#include <QRandomGenerator>
#include <QStringBuilder>
+#undef max
+#undef interface
+
using namespace QXmpp;
using namespace QXmpp::Private;
using namespace QXmpp::Omemo::Private;
@@ -33,27 +35,19 @@ using Error = QXmppStanza::Error;
using Manager = QXmppOmemoManager;
using ManagerPrivate = QXmppOmemoManagerPrivate;
+const char *ns_client = "jabber:client";
+const char *ns_pubsub_auto_create = "http://jabber.org/protocol/pubsub#auto-create";
+const char *ns_pubsub_config_node = "http://jabber.org/protocol/pubsub#config-node";
+const char *ns_pubsub_config_node_max = "http://jabber.org/protocol/pubsub#config-node-max";
+const char *ns_pubsub_create_and_configure = "http://jabber.org/protocol/pubsub#create-and-configure";
+const char *ns_pubsub_create_nodes = "http://jabber.org/protocol/pubsub#create-nodes";
+const char *ns_pubsub_publish = "http://jabber.org/protocol/pubsub#publish";
+const char *ns_pubsub_publish_options = "http://jabber.org/protocol/pubsub#publish-options";
+
namespace QXmpp::Omemo::Private {
const QString PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE = QStringLiteral("hmac(sha256)");
-//
-// Creates a key ID.
-//
-// The first byte representing a version string used by the OMEMO library but
-// not needed for trust management is removed.
-// It corresponds to the fingerprint shown to users which also does not contain
-// the first byte.
-//
-// \param key key for whom its ID is created
-//
-// \return the key ID
-//
-QByteArray createKeyId(const QByteArray &key)
-{
- return QByteArray(key).remove(0, 1);
-}
-
} // namespace QXmpp::Omemo::Private
//
@@ -710,13 +704,7 @@ bool ManagerPrivate::setUpIdentityKeyPair(ratchet_identity_key_pair **identityKe
const auto privateIdentityKey = privateIdentityKeyBuffer.toByteArray();
ownDevice.privateIdentityKey = privateIdentityKey;
- BufferPtr publicIdentityKeyBuffer;
-
- if (ec_public_key_serialize(publicIdentityKeyBuffer.ptrRef(), ratchet_identity_key_pair_get_public(*identityKeyPair)) < 0) {
- warning("Public identity key could not be serialized");
- return false;
- }
-
+ BufferPtr publicIdentityKeyBuffer(ec_public_key_get_ed(ratchet_identity_key_pair_get_public(*identityKeyPair)));
const auto publicIdentityKey = publicIdentityKeyBuffer.toByteArray();
deviceBundle.setPublicIdentityKey(publicIdentityKey);
ownDevice.publicIdentityKey = publicIdentityKey;
@@ -832,18 +820,12 @@ bool ManagerPrivate::updateSignedPreKeyPair(ratchet_identity_key_pair *identityK
signedPreKeyPairs.insert(latestSignedPreKeyId, signedPreKeyPairForStorage);
omemoStorage->addSignedPreKeyPair(latestSignedPreKeyId, signedPreKeyPairForStorage);
- BufferPtr signedPublicPreKeyBuffer;
-
- if (ec_public_key_serialize(signedPublicPreKeyBuffer.ptrRef(), ec_key_pair_get_public(session_signed_pre_key_get_key_pair(signedPreKeyPair.get()))) < 0) {
- warning("Signed public pre key could not be serialized");
- return false;
- }
-
+ BufferPtr signedPublicPreKeyBuffer(ec_public_key_get_mont(ec_key_pair_get_public(session_signed_pre_key_get_key_pair(signedPreKeyPair.get()))));
const auto signedPublicPreKeyByteArray = signedPublicPreKeyBuffer.toByteArray();
deviceBundle.setSignedPublicPreKeyId(latestSignedPreKeyId);
deviceBundle.setSignedPublicPreKey(signedPublicPreKeyByteArray);
- deviceBundle.setSignedPublicPreKeySignature(QByteArray(reinterpret_cast<const char *>(session_signed_pre_key_get_signature(signedPreKeyPair.get())), session_signed_pre_key_get_signature_len(signedPreKeyPair.get())));
+ deviceBundle.setSignedPublicPreKeySignature(QByteArray(reinterpret_cast<const char *>(session_signed_pre_key_get_signature_omemo(signedPreKeyPair.get())), session_signed_pre_key_get_signature_omemo_len(signedPreKeyPair.get())));
ownDevice.latestSignedPreKeyId = latestSignedPreKeyId;
@@ -921,7 +903,6 @@ bool ManagerPrivate::updatePreKeyPairs(uint32_t count)
node != nullptr;
node = signal_protocol_key_helper_key_list_next(node)) {
BufferSecurePtr preKeyPairBuffer;
- BufferPtr publicPreKeyBuffer;
auto preKeyPair = signal_protocol_key_helper_key_list_element(node);
@@ -934,11 +915,7 @@ bool ManagerPrivate::updatePreKeyPairs(uint32_t count)
serializedPreKeyPairs.insert(preKeyId, preKeyPairBuffer.toByteArray());
- if (ec_public_key_serialize(publicPreKeyBuffer.ptrRef(), ec_key_pair_get_public(session_pre_key_get_key_pair(preKeyPair))) < 0) {
- warning("Public pre key could not be serialized");
- return false;
- }
-
+ BufferPtr publicPreKeyBuffer(ec_public_key_get_mont(ec_key_pair_get_public(session_pre_key_get_key_pair(preKeyPair))));
const auto serializedPublicPreKey = publicPreKeyBuffer.toByteArray();
deviceBundle.addPublicPreKey(preKeyId, serializedPublicPreKey);
}
@@ -1017,7 +994,7 @@ bool ManagerPrivate::generateIdentityKeyPair(ratchet_identity_key_pair **identit
RefCountedPtr<ec_public_key> publicIdentityKey;
- if (curve_decode_point(publicIdentityKey.ptrRef(), signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) {
+ if (curve_decode_point_ed(publicIdentityKey.ptrRef(), signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) {
warning("Public identity key could not be deserialized");
return false;
}
@@ -1234,15 +1211,14 @@ QXmppTask<std::optional<QXmppOmemoElement>> ManagerPrivate::encryptStanza(const
if (optionalDeviceBundle && devices.value(jid).contains(deviceId)) {
auto &deviceBeingModified = devices[jid][deviceId];
const auto &deviceBundle = *optionalDeviceBundle;
- const auto key = deviceBundle.publicIdentityKey();
- deviceBeingModified.keyId = createKeyId(key);
+ deviceBeingModified.keyId = deviceBundle.publicIdentityKey();
auto future = q->trustLevel(jid, deviceBeingModified.keyId);
future.then(q, [=](TrustLevel trustLevel) mutable {
// Store the retrieved key's trust level if it is not stored
// yet.
if (trustLevel == TrustLevel::Undecided) {
- auto future = storeKeyDependingOnSecurityPolicy(jid, key);
+ auto future = storeKeyDependingOnSecurityPolicy(jid, deviceBeingModified.keyId);
future.then(q, [=](TrustLevel trustLevel) mutable {
omemoStorage->addDevice(jid, deviceId, deviceBeingModified);
Q_EMIT q->deviceChanged(jid, deviceId);
@@ -1473,8 +1449,6 @@ QXmppTask<std::optional<QXmppMessage>> ManagerPrivate::decryptMessage(QXmppMessa
future.then(q, [=](std::optional<QCA::SecureArray> payloadDecryptionData) mutable {
if (!payloadDecryptionData) {
warning("Empty OMEMO message could not be successfully processed");
- } else if (payloadDecryptionData->isEmpty()) {
- warning("Empty OMEMO message could not be successfully processed");
} else {
q->debug("Successfully processed empty OMEMO message");
}
@@ -1576,48 +1550,38 @@ QXmppTask<std::optional<DecryptionResult>> ManagerPrivate::decryptStanza(T stanz
QXmppSceEnvelopeReader sceEnvelopeReader(document.documentElement());
if (sceEnvelopeReader.from() != senderJid) {
- warning("Sender '" % senderJid % "' of stanza does not match SCE 'from' affix element '" % sceEnvelopeReader.from() % "'");
- interface.finish(std::nullopt);
- } else {
- const auto recipientJid = QXmppUtils::jidToBareJid(stanza.to());
- auto isSceAffixElementValid = true;
+ q->info("Sender '" % senderJid % "' of stanza does not match SCE 'from' affix element '" % sceEnvelopeReader.from() % "'");
+ }
- if (isMessageStanza) {
- if (const auto &message = dynamic_cast<const QXmppMessage &>(stanza); message.type() == QXmppMessage::GroupChat && (sceEnvelopeReader.to() != recipientJid)) {
- warning("Recipient of group chat message does not match SCE affix element '<to/>'");
- isSceAffixElementValid = false;
- }
- } else {
- if (sceEnvelopeReader.to() != recipientJid) {
- warning("Recipient of IQ does not match SCE affix element '<to/>'");
- isSceAffixElementValid = false;
- }
+ if (const auto recipientJid = QXmppUtils::jidToBareJid(stanza.to()); isMessageStanza) {
+ if (const auto &message = dynamic_cast<const QXmppMessage &>(stanza); message.type() == QXmppMessage::GroupChat && (sceEnvelopeReader.to() != recipientJid)) {
+ warning("Recipient of group chat message does not match SCE affix element '<to/>'");
+ interface.finish(std::nullopt);
+ return;
}
+ } else if (sceEnvelopeReader.to() != recipientJid) {
+ q->info("Recipient of IQ does not match SCE affix element '<to/>'");
+ }
- if (!isSceAffixElementValid) {
- interface.finish(std::nullopt);
- } else {
- auto &device = devices[senderJid][senderDeviceId];
- device.unrespondedSentStanzasCount = 0;
+ auto &device = devices[senderJid][senderDeviceId];
+ device.unrespondedSentStanzasCount = 0;
- // Send a heartbeat message to the sender if too many stanzas were
- // received responding to none.
- if (device.unrespondedReceivedStanzasCount == UNRESPONDED_STANZAS_UNTIL_HEARTBEAT_MESSAGE_IS_SENT) {
- sendEmptyMessage(senderJid, senderDeviceId);
- device.unrespondedReceivedStanzasCount = 0;
- } else {
- ++device.unrespondedReceivedStanzasCount;
- }
+ // Send a heartbeat message to the sender if too many stanzas were
+ // received responding to none.
+ if (device.unrespondedReceivedStanzasCount == UNRESPONDED_STANZAS_UNTIL_HEARTBEAT_MESSAGE_IS_SENT) {
+ sendEmptyMessage(senderJid, senderDeviceId);
+ device.unrespondedReceivedStanzasCount = 0;
+ } else {
+ ++device.unrespondedReceivedStanzasCount;
+ }
- QXmppE2eeMetadata e2eeMetadata;
- e2eeMetadata.setSceTimestamp(sceEnvelopeReader.timestamp());
- e2eeMetadata.setEncryption(QXmpp::Omemo2);
- const auto &senderDevice = devices.value(senderJid).value(senderDeviceId);
- e2eeMetadata.setSenderKey(senderDevice.keyId);
+ QXmppE2eeMetadata e2eeMetadata;
+ e2eeMetadata.setSceTimestamp(sceEnvelopeReader.timestamp());
+ e2eeMetadata.setEncryption(QXmpp::Omemo2);
+ const auto &senderDevice = devices.value(senderJid).value(senderDeviceId);
+ e2eeMetadata.setSenderKey(senderDevice.keyId);
- interface.finish(DecryptionResult { sceEnvelopeReader.contentElement(), e2eeMetadata });
- }
- }
+ interface.finish(DecryptionResult { sceEnvelopeReader.contentElement(), e2eeMetadata });
}
});
@@ -1648,9 +1612,6 @@ QXmppTask<QByteArray> ManagerPrivate::extractSceEnvelope(const QString &senderJi
if (!payloadDecryptionData) {
warning("Data for decrypting OMEMO payload could not be extracted");
interface.finish(QByteArray());
- } else if (payloadDecryptionData->isEmpty()) {
- warning("Data for decrypting OMEMO payload could not be extracted");
- interface.finish(QByteArray());
} else {
interface.finish(decryptPayload(*payloadDecryptionData, omemoPayload));
}
@@ -1669,8 +1630,7 @@ QXmppTask<QByteArray> ManagerPrivate::extractSceEnvelope(const QString &senderJi
// \param omemoEnvelope OMEMO envelope containing the payload decryption data
// \param isMessageStanza whether the received stanza is a message stanza
//
-// \return the serialized payload decryption data if it could be extracted, otherwise a
-// default-constructed secure array
+// \return the serialized payload decryption data if it could be extracted, otherwise std::nullopt
//
QXmppTask<std::optional<QCA::SecureArray>> ManagerPrivate::extractPayloadDecryptionData(const QString &senderJid, uint32_t senderDeviceId, const QXmppOmemoEnvelope &omemoEnvelope, bool isMessageStanza)
{
@@ -1728,11 +1688,10 @@ QXmppTask<std::optional<QCA::SecureArray>> ManagerPrivate::extractPayloadDecrypt
const auto key = publicIdentityKeyBuffer.toByteArray();
auto &device = devices[senderJid][senderDeviceId];
auto &storedKeyId = device.keyId;
- const auto createdKeyId = createKeyId(key);
// Store the key if its ID has changed.
- if (storedKeyId != createdKeyId) {
- storedKeyId = createdKeyId;
+ if (storedKeyId != key) {
+ storedKeyId = key;
omemoStorage->addDevice(senderJid, senderDeviceId, device);
Q_EMIT q->deviceChanged(senderJid, senderDeviceId);
}
@@ -1781,12 +1740,7 @@ QXmppTask<std::optional<QCA::SecureArray>> ManagerPrivate::extractPayloadDecrypt
auto future = q->trustLevel(senderJid, storedKeyId);
future.then(q, [=](TrustLevel trustLevel) mutable {
if (trustLevel == TrustLevel::Undecided) {
- auto future = storeKeyDependingOnSecurityPolicy(senderJid, key);
- future.then(q, [=](auto) mutable {
- interface.finish(std::nullopt);
- });
- } else {
- interface.finish(std::nullopt);
+ storeKeyDependingOnSecurityPolicy(senderJid, key);
}
});
}
@@ -3338,8 +3292,7 @@ QXmppTask<bool> ManagerPrivate::buildSessionWithDeviceBundle(const QString &jid,
future.then(q, [=, &device](std::optional<QXmppOmemoDeviceBundle> optionalDeviceBundle) mutable {
if (optionalDeviceBundle) {
const auto &deviceBundle = *optionalDeviceBundle;
- const auto key = deviceBundle.publicIdentityKey();
- device.keyId = createKeyId(key);
+ device.keyId = deviceBundle.publicIdentityKey();
auto future = q->trustLevel(jid, device.keyId);
future.then(q, [=](TrustLevel trustLevel) mutable {
@@ -3372,7 +3325,7 @@ QXmppTask<bool> ManagerPrivate::buildSessionWithDeviceBundle(const QString &jid,
if (trustLevel == TrustLevel::Undecided) {
// Store the key's trust level if it is not stored yet.
- auto future = storeKeyDependingOnSecurityPolicy(jid, key);
+ auto future = storeKeyDependingOnSecurityPolicy(jid, device.keyId);
future.then(q, [=](TrustLevel trustLevel) mutable {
buildSessionDependingOnTrustLevel(trustLevel);
});
@@ -3517,7 +3470,7 @@ bool ManagerPrivate::deserializePublicIdentityKey(ec_public_key **publicIdentity
return false;
}
- if (curve_decode_point(publicIdentityKey, signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) {
+ if (curve_decode_point_ed(publicIdentityKey, signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) {
warning("Public identity key could not be deserialized");
return false;
}
@@ -3542,7 +3495,7 @@ bool ManagerPrivate::deserializeSignedPublicPreKey(ec_public_key **signedPublicP
return false;
}
- if (curve_decode_point(signedPublicPreKey, signal_buffer_data(signedPublicPreKeyBuffer.get()), signal_buffer_len(signedPublicPreKeyBuffer.get()), globalContext.get()) < 0) {
+ if (curve_decode_point_mont(signedPublicPreKey, signal_buffer_data(signedPublicPreKeyBuffer.get()), signal_buffer_len(signedPublicPreKeyBuffer.get()), globalContext.get()) < 0) {
warning("Signed public pre key could not be deserialized");
return false;
}
@@ -3567,7 +3520,7 @@ bool ManagerPrivate::deserializePublicPreKey(ec_public_key **publicPreKey, const
return false;
}
- if (curve_decode_point(publicPreKey, signal_buffer_data(publicPreKeyBuffer.get()), signal_buffer_len(publicPreKeyBuffer.get()), globalContext.get()) < 0) {
+ if (curve_decode_point_mont(publicPreKey, signal_buffer_data(publicPreKeyBuffer.get()), signal_buffer_len(publicPreKeyBuffer.get()), globalContext.get()) < 0) {
warning("Public pre key could not be deserialized");
return false;
}
@@ -3633,16 +3586,11 @@ QXmppTask<QXmpp::SendResult> ManagerPrivate::sendEmptyMessage(const QString &rec
//
// Sets the key of this client instance's device.
//
-// The first byte representing a version string used by the OMEMO library but
-// not needed for trust management is removed before storing it.
-// It corresponds to the fingerprint shown to users which also does not contain
-// the first byte.
-//
QXmppTask<void> ManagerPrivate::storeOwnKey() const
{
QXmppPromise<void> interface;
- auto future = trustManager->setOwnKey(ns_omemo_2, createKeyId(ownDevice.publicIdentityKey));
+ auto future = trustManager->setOwnKey(ns_omemo_2, ownDevice.publicIdentityKey);
future.then(q, [=]() mutable {
interface.finish();
});
@@ -3715,7 +3663,7 @@ QXmppTask<TrustLevel> ManagerPrivate::storeKey(const QString &keyOwnerJid, const
{
QXmppPromise<TrustLevel> interface;
- auto future = trustManager->addKeys(ns_omemo_2, keyOwnerJid, { createKeyId(key) }, trustLevel);
+ auto future = trustManager->addKeys(ns_omemo_2, keyOwnerJid, { key }, trustLevel);
future.then(q, [=]() mutable {
Q_EMIT q->trustLevelsChanged({ { keyOwnerJid, key } });
interface.finish(std::move(trustLevel));