diff options
| author | Linus Jahn <lnj@kaidan.im> | 2023-03-11 00:29:02 +0100 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2023-03-11 00:29:02 +0100 |
| commit | 463111576fb1476192acd2d8fe415b8482a8a696 (patch) | |
| tree | e87e3bb8f8724f019954692ac22b0d6386dfa5e7 /src/omemo/QXmppOmemoManager_p.cpp | |
| parent | 6ea3edfd83a0bf1558d43e48eac563730276c175 (diff) | |
| parent | 4897c9b6a36e961fb44d2bce04a698f979a423d5 (diff) | |
| download | qxmpp-463111576fb1476192acd2d8fe415b8482a8a696.tar.gz | |
Merge branch '1.5'
Diffstat (limited to 'src/omemo/QXmppOmemoManager_p.cpp')
| -rw-r--r-- | src/omemo/QXmppOmemoManager_p.cpp | 166 |
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)); |
