forked from qt-creator/qt-creator
SSH: Work around issue with dynamic_cast.
It has been observed that on MacOs, a dynamic_cast from
Botan::Public_Key to Botan::RSA_PublicKey reproducibly fails even though
it should definitely succeed. This happens with both gcc and clang on
different Macs, but on no other platform. The problem could not be
reproduced with an example project.
The workaround is to move the allocation of the respective object from
the client side to the Botan library itself. In addition, the following
actions were taken to guard against similar problems in the future:
- Also move to Botan the allocations of all other objects that are
potentially dynamically cast.
- Use shared pointers for these objects, so the deallocation also
happens inside Botan.
Change-Id: Ie595a56a239a41e2629b6ff631de59910b8244dd
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
This commit is contained in:
41
src/libs/3rdparty/botan/botan.cpp
vendored
41
src/libs/3rdparty/botan/botan.cpp
vendored
@@ -47182,3 +47182,44 @@ u32bit version_minor() { return BOTAN_VERSION_MINOR; }
|
|||||||
u32bit version_patch() { return BOTAN_VERSION_PATCH; }
|
u32bit version_patch() { return BOTAN_VERSION_PATCH; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Botan {
|
||||||
|
PublicKeyPtr createRsaPublicKey(const BigInt &e, const BigInt &n)
|
||||||
|
{
|
||||||
|
return PublicKeyPtr(new RSA_PublicKey(e, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicKeyPtr createDsaPublicKey(const DL_Group &group, const BigInt &y)
|
||||||
|
{
|
||||||
|
return PublicKeyPtr(new DSA_PublicKey(group, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateKeyPtr createRsaPrivateKey(RandomNumberGenerator &rng, const BigInt &p, const BigInt &q,
|
||||||
|
const BigInt &e, const BigInt &d, const BigInt &n)
|
||||||
|
{
|
||||||
|
return PrivateKeyPtr(new RSA_PrivateKey(rng, p, q, e, d, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateKeyPtr createRsaPrivateKey(RandomNumberGenerator &rng, size_t bits, size_t exp)
|
||||||
|
{
|
||||||
|
return PrivateKeyPtr(new RSA_PrivateKey(rng, bits, exp));
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateKeyPtr createDsaPrivateKey(RandomNumberGenerator &rng, const DL_Group &group,
|
||||||
|
const BigInt &private_key)
|
||||||
|
{
|
||||||
|
return PrivateKeyPtr(new DSA_PrivateKey(rng, group, private_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateKeyPtr loadPkcs8PrivateKey(DataSource& source, RandomNumberGenerator& rng,
|
||||||
|
const User_Interface& ui)
|
||||||
|
{
|
||||||
|
return PrivateKeyPtr(PKCS8::load_key(source, rng, ui));
|
||||||
|
}
|
||||||
|
|
||||||
|
DhPrivateKeyPtr createDhPrivateKey(RandomNumberGenerator &rng, const DL_Group &grp, const BigInt &x)
|
||||||
|
{
|
||||||
|
return DhPrivateKeyPtr(new DH_PrivateKey(rng, grp, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
20
src/libs/3rdparty/botan/botan.h
vendored
20
src/libs/3rdparty/botan/botan.h
vendored
@@ -9,6 +9,7 @@
|
|||||||
#define BOTAN_AMALGAMATION_H__
|
#define BOTAN_AMALGAMATION_H__
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -16181,7 +16182,26 @@ class BOTAN_DLL ANSI_X919_MAC : public MessageAuthenticationCode
|
|||||||
SecureVector<byte> state;
|
SecureVector<byte> state;
|
||||||
size_t position;
|
size_t position;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Botan {
|
||||||
|
typedef QSharedPointer<Public_Key> PublicKeyPtr;
|
||||||
|
BOTAN_DLL PublicKeyPtr createRsaPublicKey(const BigInt &e, const BigInt &n);
|
||||||
|
BOTAN_DLL PublicKeyPtr createDsaPublicKey(const DL_Group& group, const BigInt& y);
|
||||||
|
|
||||||
|
typedef QSharedPointer<Private_Key> PrivateKeyPtr;
|
||||||
|
BOTAN_DLL PrivateKeyPtr createRsaPrivateKey(RandomNumberGenerator& rng, const BigInt& p,
|
||||||
|
const BigInt& q, const BigInt& e, const BigInt& d = 0, const BigInt& n = 0);
|
||||||
|
BOTAN_DLL PrivateKeyPtr createRsaPrivateKey(RandomNumberGenerator& rng, size_t bits,
|
||||||
|
size_t exp = 65537);
|
||||||
|
BOTAN_DLL PrivateKeyPtr createDsaPrivateKey(RandomNumberGenerator& rng, const DL_Group& group,
|
||||||
|
const BigInt& private_key = 0);
|
||||||
|
BOTAN_DLL PrivateKeyPtr loadPkcs8PrivateKey(DataSource& source, RandomNumberGenerator& rng,
|
||||||
|
const User_Interface& ui);
|
||||||
|
|
||||||
|
typedef QSharedPointer<DH_PrivateKey> DhPrivateKeyPtr;
|
||||||
|
BOTAN_DLL DhPrivateKeyPtr createDhPrivateKey(RandomNumberGenerator& rng, const DL_Group& grp,
|
||||||
|
const BigInt& x = 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -218,16 +218,14 @@ bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &p
|
|||||||
try {
|
try {
|
||||||
Pipe pipe;
|
Pipe pipe;
|
||||||
pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
|
pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
|
||||||
Private_Key * const key = PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever());
|
const PrivateKeyPtr authKey = loadPkcs8PrivateKey(pipe, m_rng, SshKeyPasswordRetriever());
|
||||||
if (DSA_PrivateKey * const dsaKey = dynamic_cast<DSA_PrivateKey *>(key)) {
|
if (DSA_PrivateKey * const dsaKey = dynamic_cast<DSA_PrivateKey *>(authKey.data())) {
|
||||||
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
|
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
|
||||||
m_authKey.reset(dsaKey);
|
|
||||||
pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
|
pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
|
||||||
<< dsaKey->group_g() << dsaKey->get_y();
|
<< dsaKey->group_g() << dsaKey->get_y();
|
||||||
allKeyParams << pubKeyParams << dsaKey->get_x();
|
allKeyParams << pubKeyParams << dsaKey->get_x();
|
||||||
} else if (RSA_PrivateKey * const rsaKey = dynamic_cast<RSA_PrivateKey *>(key)) {
|
} else if (RSA_PrivateKey * const rsaKey = dynamic_cast<RSA_PrivateKey *>(authKey.data())) {
|
||||||
m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
|
m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
|
||||||
m_authKey.reset(rsaKey);
|
|
||||||
pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
|
pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
|
||||||
allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
|
allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
|
||||||
<< rsaKey->get_d();
|
<< rsaKey->get_d();
|
||||||
@@ -235,6 +233,7 @@ bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &p
|
|||||||
qWarning("%s: Unexpected code flow, expected success or exception.", Q_FUNC_INFO);
|
qWarning("%s: Unexpected code flow, expected success or exception.", Q_FUNC_INFO);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
m_authKey = authKey;
|
||||||
} catch (const Botan::Exception &ex) {
|
} catch (const Botan::Exception &ex) {
|
||||||
error = QLatin1String(ex.what());
|
error = QLatin1String(ex.what());
|
||||||
return false;
|
return false;
|
||||||
@@ -291,15 +290,13 @@ bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray
|
|||||||
if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) {
|
if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) {
|
||||||
BigInt p, q, g, y, x;
|
BigInt p, q, g, y, x;
|
||||||
sequence.decode (p).decode (q).decode (g).decode (y).decode (x);
|
sequence.decode (p).decode (q).decode (g).decode (y).decode (x);
|
||||||
DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x);
|
m_authKey = createDsaPrivateKey(m_rng, DL_Group(p, q, g), x);
|
||||||
m_authKey.reset(dsaKey);
|
|
||||||
pubKeyParams << p << q << g << y;
|
pubKeyParams << p << q << g << y;
|
||||||
allKeyParams << pubKeyParams << x;
|
allKeyParams << pubKeyParams << x;
|
||||||
} else {
|
} else {
|
||||||
BigInt p, q, e, d, n;
|
BigInt p, q, e, d, n;
|
||||||
sequence.decode(n).decode(e).decode(d).decode(p).decode(q);
|
sequence.decode(n).decode(e).decode(d).decode(p).decode(q);
|
||||||
RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(m_rng, p, q, e, d, n);
|
m_authKey = createRsaPrivateKey(m_rng, p, q, e, d, n);
|
||||||
m_authKey.reset(rsaKey);
|
|
||||||
pubKeyParams << e << n;
|
pubKeyParams << e << n;
|
||||||
allKeyParams << pubKeyParams << p << q << d;
|
allKeyParams << pubKeyParams << p << q << d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ private:
|
|||||||
QByteArray m_authKeyAlgoName;
|
QByteArray m_authKeyAlgoName;
|
||||||
QByteArray m_authPubKeyBlob;
|
QByteArray m_authPubKeyBlob;
|
||||||
QByteArray m_cachedPrivKeyContents;
|
QByteArray m_cachedPrivKeyContents;
|
||||||
QScopedPointer<Botan::Private_Key> m_authKey;
|
QSharedPointer<Botan::Private_Key> m_authKey;
|
||||||
mutable Botan::AutoSeeded_RNG m_rng;
|
mutable Botan::AutoSeeded_RNG m_rng;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -136,8 +136,7 @@ bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit)
|
|||||||
kexInitParams.compressionAlgorithmsServerToClient.names);
|
kexInitParams.compressionAlgorithmsServerToClient.names);
|
||||||
|
|
||||||
AutoSeeded_RNG rng;
|
AutoSeeded_RNG rng;
|
||||||
m_dhKey.reset(new DH_PrivateKey(rng,
|
m_dhKey = createDhPrivateKey(rng, DL_Group(botanKeyExchangeAlgoName(keyAlgo)));
|
||||||
DL_Group(botanKeyExchangeAlgoName(keyAlgo))));
|
|
||||||
|
|
||||||
m_serverKexInitPayload = serverKexInit.payLoad();
|
m_serverKexInitPayload = serverKexInit.payLoad();
|
||||||
m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y());
|
m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y());
|
||||||
@@ -184,28 +183,24 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
|
|||||||
printData("H", m_h);
|
printData("H", m_h);
|
||||||
#endif // CREATOR_SSH_DEBUG
|
#endif // CREATOR_SSH_DEBUG
|
||||||
|
|
||||||
QScopedPointer<Public_Key> sigKey;
|
QSharedPointer<Public_Key> publicKey;
|
||||||
QScopedPointer<PK_Verifier> verifier;
|
QByteArray algorithm;
|
||||||
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
|
publicKey = createDsaPublicKey(group, reply.parameters.at(3));
|
||||||
= new DSA_PublicKey(group, reply.parameters.at(3));
|
algorithm = SshCapabilities::PubKeyDss;
|
||||||
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
|
publicKey = createRsaPublicKey(reply.parameters.at(1), reply.parameters.at(0));
|
||||||
= new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0));
|
algorithm = SshCapabilities::PubKeyRsa;
|
||||||
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,
|
if (!PK_Verifier(*publicKey, botanEmsaAlgoName(algorithm)).verify_message(botanH, m_h.size(),
|
||||||
reply.signatureBlob.size())) {
|
botanSig, 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.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
namespace Botan {
|
namespace Botan {
|
||||||
class DH_PrivateKey;
|
class DH_PrivateKey;
|
||||||
@@ -71,7 +72,7 @@ private:
|
|||||||
QByteArray m_serverId;
|
QByteArray m_serverId;
|
||||||
QByteArray m_clientKexInitPayload;
|
QByteArray m_clientKexInitPayload;
|
||||||
QByteArray m_serverKexInitPayload;
|
QByteArray m_serverKexInitPayload;
|
||||||
QScopedPointer<Botan::DH_PrivateKey> m_dhKey;
|
QSharedPointer<Botan::DH_PrivateKey> m_dhKey;
|
||||||
QByteArray m_k;
|
QByteArray m_k;
|
||||||
QByteArray m_h;
|
QByteArray m_h;
|
||||||
QByteArray m_serverHostKeyAlgo;
|
QByteArray m_serverHostKeyAlgo;
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int ke
|
|||||||
AutoSeeded_RNG rng;
|
AutoSeeded_RNG rng;
|
||||||
KeyPtr key;
|
KeyPtr key;
|
||||||
if (m_type == Rsa)
|
if (m_type == Rsa)
|
||||||
key = KeyPtr(new RSA_PrivateKey(rng, keySize));
|
key = createRsaPrivateKey(rng, keySize);
|
||||||
else
|
else
|
||||||
key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, keySize)));
|
key = createDsaPrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, keySize));
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case Pkcs8:
|
case Pkcs8:
|
||||||
generatePkcs8KeyStrings(key, rng);
|
generatePkcs8KeyStrings(key, rng);
|
||||||
|
|||||||
Reference in New Issue
Block a user