aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/crypto/qolmaccount.cpp10
-rw-r--r--lib/crypto/qolmaccount.h3
-rw-r--r--lib/crypto/qolmsession.cpp21
-rw-r--r--lib/crypto/qolmsession.h9
-rw-r--r--lib/encryptionmanager.cpp95
5 files changed, 90 insertions, 48 deletions
diff --git a/lib/crypto/qolmaccount.cpp b/lib/crypto/qolmaccount.cpp
index fc0fc1cf..76b0a263 100644
--- a/lib/crypto/qolmaccount.cpp
+++ b/lib/crypto/qolmaccount.cpp
@@ -197,6 +197,16 @@ QByteArray QOlmAccount::signOneTimeKey(const QString &key) const
return sign(j.toJson());
}
+std::optional<QOlmError> QOlmAccount::removeOneTimeKeys(const std::unique_ptr<QOlmSession> &session) const
+{
+ const auto error = olm_remove_one_time_keys(m_account, session->raw());
+
+ if (error == olm_error()) {
+ return lastError(m_account);
+ }
+ return std::nullopt;
+}
+
OlmAccount *Quotient::QOlmAccount::data()
{
return m_account;
diff --git a/lib/crypto/qolmaccount.h b/lib/crypto/qolmaccount.h
index b33e3768..4398214a 100644
--- a/lib/crypto/qolmaccount.h
+++ b/lib/crypto/qolmaccount.h
@@ -68,6 +68,9 @@ public:
SignedOneTimeKey signedOneTimeKey(const QByteArray &key, const QString &signature) const;
+ //! Remove the one time key used to create the supplied session.
+ [[nodiscard]] std::optional<QOlmError> removeOneTimeKeys(const std::unique_ptr<QOlmSession> &session) const;
+
//! Creates an inbound session for sending/receiving messages from a received 'prekey' message.
//!
//! \param message An Olm pre-key message that was encrypted for this account.
diff --git a/lib/crypto/qolmsession.cpp b/lib/crypto/qolmsession.cpp
index cfe21650..b901a440 100644
--- a/lib/crypto/qolmsession.cpp
+++ b/lib/crypto/qolmsession.cpp
@@ -213,7 +213,7 @@ bool QOlmSession::hasReceivedMessage() const
return olm_session_has_received_message(m_session);
}
-std::variant<bool, QOlmError> QOlmSession::matchesInboundSession(QOlmMessage &preKeyMessage)
+std::variant<bool, QOlmError> QOlmSession::matchesInboundSession(const QOlmMessage &preKeyMessage) const
{
Q_ASSERT(preKeyMessage.type() == QOlmMessage::Type::PreKey);
QByteArray oneTimeKeyBuf(preKeyMessage.data());
@@ -231,6 +231,25 @@ std::variant<bool, QOlmError> QOlmSession::matchesInboundSession(QOlmMessage &pr
return QOlmError::Unknown;
}
}
+std::variant<bool, QOlmError> QOlmSession::matchesInboundSessionFrom(const QString &theirIdentityKey, const QOlmMessage &preKeyMessage) const
+{
+ const auto theirIdentityKeyBuf = theirIdentityKey.toUtf8();
+ auto oneTimeKeyMessageBuf = preKeyMessage.toCiphertext();
+ const auto error = olm_matches_inbound_session_from(m_session, theirIdentityKeyBuf.data(), theirIdentityKeyBuf.length(),
+ oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length());
+
+ if (error == olm_error()) {
+ return lastError(m_session);
+ }
+ switch (error) {
+ case 0:
+ return false;
+ case 1:
+ return true;
+ default:
+ return QOlmError::Unknown;
+ }
+}
QOlmSession::QOlmSession(OlmSession *session)
: m_session(session)
diff --git a/lib/crypto/qolmsession.h b/lib/crypto/qolmsession.h
index 6e13801e..0fc59e9e 100644
--- a/lib/crypto/qolmsession.h
+++ b/lib/crypto/qolmsession.h
@@ -50,7 +50,10 @@ public:
bool hasReceivedMessage() const;
//! Checks if the 'prekey' message is for this in-bound session.
- std::variant<bool, QOlmError> matchesInboundSession(QOlmMessage &preKeyMessage);
+ std::variant<bool, QOlmError> matchesInboundSession(const QOlmMessage &preKeyMessage) const;
+
+ //! Checks if the 'prekey' message is for this in-bound session.
+ std::variant<bool, QOlmError> matchesInboundSessionFrom(const QString &theirIdentityKey, const QOlmMessage &preKeyMessage) const;
friend bool operator<(const QOlmSession& lhs, const QOlmSession& rhs)
{
@@ -61,6 +64,10 @@ public:
return *lhs < *rhs;
}
+ OlmSession *raw() const
+ {
+ return m_session;
+ }
QOlmSession(OlmSession* session);
private:
//! Helper function for creating new sessions and handling errors.
diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp
index 8081f788..449eb2a3 100644
--- a/lib/encryptionmanager.cpp
+++ b/lib/encryptionmanager.cpp
@@ -88,7 +88,7 @@ public:
QHash<QString, int> targetOneTimeKeyCounts;
// A map from senderKey to InboundSession
- QMap<QString, QOlmSession*> sessions; // TODO: cache
+ QMap<QString, std::unique_ptr<QOlmSession>> sessions; // TODO: cache
void updateDeviceKeys(
const QHash<QString,
QHash<QString, QueryKeysJob::DeviceInformation>>& deviceKeys)
@@ -100,44 +100,45 @@ public:
}
}
}
- QString sessionDecrypt(QOlmMessage* message, const QString& senderKey)
+ QString sessionDecrypt(const QOlmMessage& message, const QString& senderKey)
{
- QString decrypted;
- QList<QOlmSession*> senderSessions = sessions.values(senderKey);
// Try to decrypt message body using one of the known sessions for that
// device
bool sessionsPassed = false;
// new e2ee TODO:
- /*
- for (auto senderSession : senderSessions) {
- if (senderSession == senderSessions.last()) {
+ for (auto &senderSession : sessions) {
+ if (senderSession == sessions.last()) {
sessionsPassed = true;
}
- try {
- decrypted = senderSession->decrypt(message);
+
+ const auto decryptedResult = senderSession->decrypt(message);
+ if (std::holds_alternative<QString>(decryptedResult)) {
qCDebug(E2EE)
<< "Success decrypting Olm event using existing session"
- << senderSession->id();
- break;
- } catch (QOlmError* e) {
- if (message->type() == QOlmMessage::PreKey) {
- if (senderSession->matches(&message, senderKey)) {
- // We had a matching session for a pre-key message, but
- // it didn't work. This means something is wrong, so we
- // fail now.
- qCDebug(E2EE)
- << "Error decrypting pre-key message with existing "
- "Olm session"
- << senderSession->id() << "reason:" << e->what();
- return QString();
+ << senderSession->sessionId();
+ return std::get<QString>(decryptedResult);
+ } else {
+ const auto error = std::get<QOlmError>(decryptedResult);
+ if (message.type() == QOlmMessage::PreKey) {
+ const auto matches = senderSession->matchesInboundSessionFrom(senderKey, message);
+ if (auto hasMatch = std::get_if<bool>(&matches)) {
+ if (hasMatch) {
+ // We had a matching session for a pre-key message, but
+ // it didn't work. This means something is wrong, so we
+ // fail now.
+ qCDebug(E2EE)
+ << "Error decrypting pre-key message with existing "
+ "Olm session"
+ << senderSession->sessionId() << "reason:" << error;
+ return QString();
+ }
}
}
// Simply keep trying otherwise
}
}
- */
- if (sessionsPassed || senderSessions.empty()) {
- if (message->type() != QOlmMessage::PreKey) {
+ if (sessionsPassed || sessions.empty()) {
+ if (message.type() != QOlmMessage::PreKey) {
// Not a pre-key message, we should have had a matching session
if (!sessions.empty()) {
qCDebug(E2EE) << "Error decrypting with existing sessions";
@@ -148,36 +149,39 @@ public:
}
// We have a pre-key message without any matching session, in this
// case we should try to create one.
- QOlmSession* newSession;
qCDebug(E2EE) << "try to establish new InboundSession with" << senderKey;
- QOlmMessage preKeyMessage = QOlmMessage(message->toCiphertext(),QOlmMessage::PreKey);
+ QOlmMessage preKeyMessage = QOlmMessage(message.toCiphertext(), QOlmMessage::PreKey);
// new e2ee TODO:
- /*
- try {
- newSession = new InboundSession(olmAccount.data(),
- &preKeyMessage,
- senderKey.toLatin1(), q);
- } catch (OlmError* e) {
+ const auto sessionResult = olmAccount->createInboundSessionFrom(senderKey.toUtf8(), preKeyMessage);
+
+ if (const auto error = std::get_if<QOlmError>(&sessionResult)) {
qCDebug(E2EE) << "Error decrypting pre-key message when trying "
"to establish a new session:"
- << e->what();
+ << error;
return QString();
}
- qCDebug(E2EE) << "Created new Olm session" << newSession->id();
- try {
- decrypted = newSession->decrypt(message);
- } catch (OlmError* e) {
+
+ const auto newSession = std::get<std::unique_ptr<QOlmSession>>(sessionResult);
+
+ qCDebug(E2EE) << "Created new Olm session" << newSession->sessionId();
+
+ const auto decryptedResult = newSession->decrypt(message);
+ if (const auto error = std::get_if<QOlmError>(&decryptedResult)) {
qCDebug(E2EE)
<< "Error decrypting pre-key message with new session"
- << e->what();
+ << error;
return QString();
}
- olmAccount->removeOneTimeKeys(newSession);
- */
- sessions.insert(senderKey, newSession);
+ if (auto error = olmAccount->removeOneTimeKeys(newSession)) {
+ qCDebug(E2EE)
+ << "Error removing one time keys"
+ << error.value();
+ }
+ sessions.insert(senderKey, std::move(newSession));
+ return std::get<QString>(decryptedResult);
}
- return decrypted;
+ return QString();
}
};
@@ -330,11 +334,10 @@ QString EncryptionManager::sessionDecryptMessage(
QByteArray body = personalCipherObject.value(BodyKeyL).toString().toLatin1();
if (type == 0) {
QOlmMessage preKeyMessage = QOlmMessage(body, QOlmMessage::PreKey);
- decrypted = d->sessionDecrypt(reinterpret_cast<QOlmMessage*>(&preKeyMessage),
- senderKey);
+ decrypted = d->sessionDecrypt(preKeyMessage, senderKey);
} else if (type == 1) {
QOlmMessage message = QOlmMessage(body, QOlmMessage::PreKey);
- decrypted = d->sessionDecrypt(&message, senderKey);
+ decrypted = d->sessionDecrypt(message, senderKey);
}
return decrypted;
}