forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -89,14 +89,18 @@ const QList<QByteArray> SshCapabilities::CompressionAlgorithms
|
|||||||
|
|
||||||
const QByteArray SshCapabilities::SshConnectionService("ssh-connection");
|
const QByteArray SshCapabilities::SshConnectionService("ssh-connection");
|
||||||
|
|
||||||
QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilities,
|
QList<QByteArray> SshCapabilities::commonCapabilities(const QList<QByteArray> &myCapabilities,
|
||||||
const QList<QByteArray> &serverCapabilities)
|
const QList<QByteArray> &serverCapabilities)
|
||||||
{
|
{
|
||||||
|
QList<QByteArray> capabilities;
|
||||||
foreach (const QByteArray &myCapability, myCapabilities) {
|
foreach (const QByteArray &myCapability, myCapabilities) {
|
||||||
if (serverCapabilities.contains(myCapability))
|
if (serverCapabilities.contains(myCapability))
|
||||||
return myCapability;
|
capabilities << myCapability;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!capabilities.isEmpty())
|
||||||
|
return capabilities;
|
||||||
|
|
||||||
throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
|
throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
|
||||||
"Server and client capabilities do not match.",
|
"Server and client capabilities do not match.",
|
||||||
QCoreApplication::translate("SshConnection",
|
QCoreApplication::translate("SshConnection",
|
||||||
@@ -104,6 +108,13 @@ QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilitie
|
|||||||
"Client list was: %1.\nServer list was %2.")
|
"Client list was: %1.\nServer list was %2.")
|
||||||
.arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data()))
|
.arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data()))
|
||||||
.arg(QString::fromLocal8Bit(listAsByteArray(serverCapabilities).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
|
} // namespace Internal
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ public:
|
|||||||
|
|
||||||
static const QByteArray SshConnectionService;
|
static const QByteArray SshConnectionService;
|
||||||
|
|
||||||
|
static QList<QByteArray> commonCapabilities(const QList<QByteArray> &myCapabilities,
|
||||||
|
const QList<QByteArray> &serverCapabilities);
|
||||||
static QByteArray findBestMatch(const QList<QByteArray> &myCapabilities,
|
static QByteArray findBestMatch(const QList<QByteArray> &myCapabilities,
|
||||||
const QList<QByteArray> &serverCapabilities);
|
const QList<QByteArray> &serverCapabilities);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -162,8 +162,11 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
|
|||||||
concatenatedData += reply.k_s;
|
concatenatedData += reply.k_s;
|
||||||
concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
|
concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
|
||||||
concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
|
concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
|
||||||
const BigInt k = power_mod(reply.f, m_dhKey->get_x(), m_dhKey->get_domain().get_p());
|
DH_KA_Operation dhOp(*m_dhKey);
|
||||||
m_k = AbstractSshPacket::encodeMpInt(k);
|
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;
|
concatenatedData += m_k;
|
||||||
|
|
||||||
m_hash.reset(get_hash(botanSha1Name()));
|
m_hash.reset(get_hash(botanSha1Name()));
|
||||||
@@ -186,26 +189,24 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
|
|||||||
#endif // CREATOR_SSH_DEBUG
|
#endif // CREATOR_SSH_DEBUG
|
||||||
|
|
||||||
QScopedPointer<Public_Key> sigKey;
|
QScopedPointer<Public_Key> sigKey;
|
||||||
QScopedPointer<PK_Verifier> verifier;
|
|
||||||
if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) {
|
if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) {
|
||||||
const DL_Group group(reply.parameters.at(0), reply.parameters.at(1),
|
const DL_Group group(reply.parameters.at(0), reply.parameters.at(1),
|
||||||
reply.parameters.at(2));
|
reply.parameters.at(2));
|
||||||
DSA_PublicKey * const dsaKey
|
DSA_PublicKey * const dsaKey
|
||||||
= new DSA_PublicKey(group, reply.parameters.at(3));
|
= new DSA_PublicKey(group, reply.parameters.at(3));
|
||||||
sigKey.reset(dsaKey);
|
sigKey.reset(dsaKey);
|
||||||
verifier.reset(new PK_Verifier(*dsaKey, botanEmsaAlgoName(SshCapabilities::PubKeyDss)));
|
|
||||||
} else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) {
|
} else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) {
|
||||||
RSA_PublicKey * const rsaKey
|
RSA_PublicKey * const rsaKey
|
||||||
= new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0));
|
= new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0));
|
||||||
sigKey.reset(rsaKey);
|
sigKey.reset(rsaKey);
|
||||||
verifier.reset(new PK_Verifier(*rsaKey, botanEmsaAlgoName(SshCapabilities::PubKeyRsa)));
|
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(!"Impossible: Neither DSS nor RSA!");
|
Q_ASSERT(!"Impossible: Neither DSS nor RSA!");
|
||||||
}
|
}
|
||||||
const byte * const botanH = convertByteArray(m_h);
|
const byte * const botanH = convertByteArray(m_h);
|
||||||
const Botan::byte * const botanSig
|
const Botan::byte * const botanSig
|
||||||
= convertByteArray(reply.signatureBlob);
|
= 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())) {
|
reply.signatureBlob.size())) {
|
||||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
|
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
|
||||||
"Invalid signature in SSH_MSG_KEXDH_REPLY packet.");
|
"Invalid signature in SSH_MSG_KEXDH_REPLY packet.");
|
||||||
|
|||||||
Reference in New Issue
Block a user