From 66ccbcbb37f0f33a4be1abf69c668e90fd4a6eb3 Mon Sep 17 00:00:00 2001
From: Christian Kandeler <christian.kandeler@theqtcompany.com>
Date: Fri, 22 May 2015 17:12:38 +0200
Subject: [PATCH] SSH: Minor refactorings in key exchange code.

Change-Id: I107a61831ca7824c30dcc83b3a13f5765dd2da52
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
---
 src/libs/ssh/sshcapabilities.cpp | 17 ++++++++++++++---
 src/libs/ssh/sshcapabilities_p.h |  2 ++
 src/libs/ssh/sshkeyexchange.cpp  | 13 +++++++------
 3 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/src/libs/ssh/sshcapabilities.cpp b/src/libs/ssh/sshcapabilities.cpp
index 1d70d73a60..6bad151fcd 100644
--- a/src/libs/ssh/sshcapabilities.cpp
+++ b/src/libs/ssh/sshcapabilities.cpp
@@ -89,14 +89,18 @@ const QList<QByteArray> SshCapabilities::CompressionAlgorithms
 
 const QByteArray SshCapabilities::SshConnectionService("ssh-connection");
 
-QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilities,
-    const QList<QByteArray> &serverCapabilities)
+QList<QByteArray> SshCapabilities::commonCapabilities(const QList<QByteArray> &myCapabilities,
+                                               const QList<QByteArray> &serverCapabilities)
 {
+    QList<QByteArray> capabilities;
     foreach (const QByteArray &myCapability, myCapabilities) {
         if (serverCapabilities.contains(myCapability))
-            return myCapability;
+            capabilities << myCapability;
     }
 
+    if (!capabilities.isEmpty())
+        return capabilities;
+
     throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
         "Server and client capabilities do not match.",
         QCoreApplication::translate("SshConnection",
@@ -104,6 +108,13 @@ QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilitie
             "Client list was: %1.\nServer list was %2.")
             .arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data()))
             .arg(QString::fromLocal8Bit(listAsByteArray(serverCapabilities).data())));
+
+}
+
+QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilities,
+    const QList<QByteArray> &serverCapabilities)
+{
+    return commonCapabilities(myCapabilities, serverCapabilities).first();
 }
 
 } // namespace Internal
diff --git a/src/libs/ssh/sshcapabilities_p.h b/src/libs/ssh/sshcapabilities_p.h
index d0295fccd0..1a82ae1ef2 100644
--- a/src/libs/ssh/sshcapabilities_p.h
+++ b/src/libs/ssh/sshcapabilities_p.h
@@ -65,6 +65,8 @@ public:
 
     static const QByteArray SshConnectionService;
 
+    static QList<QByteArray> commonCapabilities(const QList<QByteArray> &myCapabilities,
+                                                const QList<QByteArray> &serverCapabilities);
     static QByteArray findBestMatch(const QList<QByteArray> &myCapabilities,
         const QList<QByteArray> &serverCapabilities);
 };
diff --git a/src/libs/ssh/sshkeyexchange.cpp b/src/libs/ssh/sshkeyexchange.cpp
index 12c2607648..1f90417c1f 100644
--- a/src/libs/ssh/sshkeyexchange.cpp
+++ b/src/libs/ssh/sshkeyexchange.cpp
@@ -162,8 +162,11 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
     concatenatedData += reply.k_s;
     concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
     concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
-    const BigInt k = power_mod(reply.f, m_dhKey->get_x(), m_dhKey->get_domain().get_p());
-    m_k = AbstractSshPacket::encodeMpInt(k);
+    DH_KA_Operation dhOp(*m_dhKey);
+    SecureVector<byte> encodedF = BigInt::encode(reply.f);
+    SecureVector<byte> encodedK = dhOp.agree(encodedF, encodedF.size());
+    const BigInt k = BigInt::decode(encodedK);
+    m_k = AbstractSshPacket::encodeMpInt(k); // Roundtrip, as Botan encodes BigInts somewhat differently.
     concatenatedData += m_k;
 
     m_hash.reset(get_hash(botanSha1Name()));
@@ -186,26 +189,24 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
 #endif // CREATOR_SSH_DEBUG
 
     QScopedPointer<Public_Key> sigKey;
-    QScopedPointer<PK_Verifier> verifier;
     if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) {
         const DL_Group group(reply.parameters.at(0), reply.parameters.at(1),
             reply.parameters.at(2));
         DSA_PublicKey * const dsaKey
             = new DSA_PublicKey(group, reply.parameters.at(3));
         sigKey.reset(dsaKey);
-        verifier.reset(new PK_Verifier(*dsaKey, botanEmsaAlgoName(SshCapabilities::PubKeyDss)));
     } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) {
         RSA_PublicKey * const rsaKey
             = new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0));
         sigKey.reset(rsaKey);
-        verifier.reset(new PK_Verifier(*rsaKey, botanEmsaAlgoName(SshCapabilities::PubKeyRsa)));
     } else {
         Q_ASSERT(!"Impossible: Neither DSS nor RSA!");
     }
     const byte * const botanH = convertByteArray(m_h);
     const Botan::byte * const botanSig
         = convertByteArray(reply.signatureBlob);
-    if (!verifier->verify_message(botanH, m_h.size(), botanSig,
+    PK_Verifier verifier(*sigKey, botanEmsaAlgoName(m_serverHostKeyAlgo));
+    if (!verifier.verify_message(botanH, m_h.size(), botanSig,
         reply.signatureBlob.size())) {
         throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
             "Invalid signature in SSH_MSG_KEXDH_REPLY packet.");
-- 
GitLab