Commit 3b8ea3fc authored by Christian Kandeler's avatar Christian Kandeler
Browse files

SSH: Support ECDH key exchange.



As per RFC 5656.

Task-number: QTCREATORBUG-14025
Change-Id: I623c9f0808967f140cdfb40e11234c2e523484e6
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@theqtcompany.com>
Reviewed-by: default avatarChristian Kandeler <christian.kandeler@theqtcompany.com>
parent 244cdb78
......@@ -56,10 +56,18 @@ inline QByteArray convertByteArray(const Botan::SecureVector<Botan::byte> &v)
inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName)
{
Q_ASSERT(rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1
|| rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1);
return rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1
? "modp/ietf/1024" : "modp/ietf/2048";
if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1)
return "modp/ietf/1024";
if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1)
return "modp/ietf/2048";
if (rfcAlgoName == SshCapabilities::EcdhNistp256)
return "secp256r1";
if (rfcAlgoName == SshCapabilities::EcdhNistp384)
return "secp384r1";
if (rfcAlgoName == SshCapabilities::EcdhNistp521)
return "secp521r1";
throw SshClientException(SshInternalError, SSH_TR("Unexpected key exchange algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
......@@ -84,21 +92,28 @@ inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName)
{
Q_ASSERT(rfcAlgoName == SshCapabilities::PubKeyDss
|| rfcAlgoName == SshCapabilities::PubKeyRsa);
return rfcAlgoName == SshCapabilities::PubKeyDss
? "EMSA1(SHA-1)" : "EMSA3(SHA-1)";
if (rfcAlgoName == SshCapabilities::PubKeyDss)
return "EMSA1(SHA-1)";
if (rfcAlgoName == SshCapabilities::PubKeyRsa)
return "EMSA3(SHA-1)";
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa)
return "EMSA1_BSI(SHA-256)";
throw SshClientException(SshInternalError, SSH_TR("Unexpected host key algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline const char *botanSha1Name() { return "SHA-1"; }
inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName)
{
Q_ASSERT(rfcAlgoName == SshCapabilities::HMacSha1
|| rfcAlgoName == SshCapabilities::HMacSha256);
if (rfcAlgoName == SshCapabilities::HMacSha1)
return botanSha1Name();
return "SHA-256";
return "SHA-1";
if (rfcAlgoName == SshCapabilities::HMacSha256)
return "SHA-256";
if (rfcAlgoName == SshCapabilities::HMacSha384)
return "SHA-384";
if (rfcAlgoName == SshCapabilities::HMacSha512)
return "SHA-512";
throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName)
......
......@@ -52,15 +52,24 @@ namespace {
const QByteArray SshCapabilities::DiffieHellmanGroup1Sha1("diffie-hellman-group1-sha1");
const QByteArray SshCapabilities::DiffieHellmanGroup14Sha1("diffie-hellman-group14-sha1");
const QList<QByteArray> SshCapabilities::KeyExchangeMethods
= QList<QByteArray>() << SshCapabilities::DiffieHellmanGroup1Sha1
<< SshCapabilities::DiffieHellmanGroup14Sha1;
const QByteArray SshCapabilities::EcdhKexNamePrefix("ecdh-sha2-nistp");
const QByteArray SshCapabilities::EcdhNistp256 = EcdhKexNamePrefix + "256";
const QByteArray SshCapabilities::EcdhNistp384 = EcdhKexNamePrefix + "384";
const QByteArray SshCapabilities::EcdhNistp521 = EcdhKexNamePrefix + "521";
const QList<QByteArray> SshCapabilities::KeyExchangeMethods = QList<QByteArray>()
<< SshCapabilities::EcdhNistp256
<< SshCapabilities::EcdhNistp384
<< SshCapabilities::EcdhNistp521
<< SshCapabilities::DiffieHellmanGroup1Sha1
<< SshCapabilities::DiffieHellmanGroup14Sha1;
const QByteArray SshCapabilities::PubKeyDss("ssh-dss");
const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa");
const QList<QByteArray> SshCapabilities::PublicKeyAlgorithms
= QList<QByteArray>() << SshCapabilities::PubKeyRsa
<< SshCapabilities::PubKeyDss;
const QByteArray SshCapabilities::PubKeyEcdsa("ecdsa-sha2-nistp256");
const QList<QByteArray> SshCapabilities::PublicKeyAlgorithms = QList<QByteArray>()
<< SshCapabilities::PubKeyEcdsa
<< SshCapabilities::PubKeyRsa
<< SshCapabilities::PubKeyDss;
const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc");
const QByteArray SshCapabilities::CryptAlgo3DesCtr("3des-ctr");
......@@ -79,9 +88,13 @@ const QList<QByteArray> SshCapabilities::EncryptionAlgorithms
const QByteArray SshCapabilities::HMacSha1("hmac-sha1");
const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96");
const QByteArray SshCapabilities::HMacSha256("hmac-sha2-256");
const QByteArray SshCapabilities::HMacSha384("hmac-sha2-384");
const QByteArray SshCapabilities::HMacSha512("hmac-sha2-512");
const QList<QByteArray> SshCapabilities::MacAlgorithms
= QList<QByteArray>() /* << SshCapabilities::HMacSha196 */
<< SshCapabilities::HMacSha256 // Recommended as per RFC 6668
<< SshCapabilities::HMacSha256
<< SshCapabilities::HMacSha384
<< SshCapabilities::HMacSha512
<< SshCapabilities::HMacSha1;
const QList<QByteArray> SshCapabilities::CompressionAlgorithms
......
......@@ -42,10 +42,15 @@ class SshCapabilities
public:
static const QByteArray DiffieHellmanGroup1Sha1;
static const QByteArray DiffieHellmanGroup14Sha1;
static const QByteArray EcdhKexNamePrefix;
static const QByteArray EcdhNistp256;
static const QByteArray EcdhNistp384;
static const QByteArray EcdhNistp521; // sic
static const QList<QByteArray> KeyExchangeMethods;
static const QByteArray PubKeyDss;
static const QByteArray PubKeyRsa;
static const QByteArray PubKeyEcdsa;
static const QList<QByteArray> PublicKeyAlgorithms;
static const QByteArray CryptAlgo3DesCbc;
......@@ -59,6 +64,8 @@ public:
static const QByteArray HMacSha1;
static const QByteArray HMacSha196;
static const QByteArray HMacSha256;
static const QByteArray HMacSha384;
static const QByteArray HMacSha512;
static const QList<QByteArray> MacAlgorithms;
static const QList<QByteArray> CompressionAlgorithms;
......
......@@ -30,6 +30,7 @@
#include "sshincomingpacket_p.h"
#include "sshbotanconversions_p.h"
#include "sshcapabilities_p.h"
namespace QSsh {
......@@ -175,35 +176,51 @@ SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray
try {
SshKeyExchangeReply replyData;
quint32 offset = TypeOffset + 1;
const quint32 k_sLength
= SshPacketParser::asUint32(m_data, &offset);
if (offset + k_sLength > currentDataSize())
throw SshPacketParseException();
replyData.k_s = m_data.mid(offset - 4, k_sLength + 4);
if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo)
quint32 topLevelOffset = TypeOffset + 1;
replyData.k_s = SshPacketParser::asString(m_data, &topLevelOffset);
quint32 k_sOffset = 0;
if (SshPacketParser::asString(replyData.k_s, &k_sOffset) != pubKeyAlgo)
throw SshPacketParseException();
// DSS: p and q, RSA: e and n
replyData.parameters << SshPacketParser::asBigInt(m_data, &offset);
replyData.parameters << SshPacketParser::asBigInt(m_data, &offset);
// g and y
if (pubKeyAlgo == SshCapabilities::PubKeyDss) {
replyData.parameters << SshPacketParser::asBigInt(m_data, &offset);
replyData.parameters << SshPacketParser::asBigInt(m_data, &offset);
if (pubKeyAlgo == SshCapabilities::PubKeyDss || pubKeyAlgo == SshCapabilities::PubKeyRsa) {
// DSS: p and q, RSA: e and n
replyData.parameters << SshPacketParser::asBigInt(replyData.k_s, &k_sOffset);
replyData.parameters << SshPacketParser::asBigInt(replyData.k_s, &k_sOffset);
// g and y
if (pubKeyAlgo == SshCapabilities::PubKeyDss) {
replyData.parameters << SshPacketParser::asBigInt(replyData.k_s, &k_sOffset);
replyData.parameters << SshPacketParser::asBigInt(replyData.k_s, &k_sOffset);
}
replyData.f = SshPacketParser::asBigInt(m_data, &topLevelOffset);
} else {
Q_ASSERT(pubKeyAlgo == SshCapabilities::PubKeyEcdsa);
if (SshPacketParser::asString(replyData.k_s, &k_sOffset) != pubKeyAlgo.mid(11)) // Without "ecdsa-sha2-" prefix.
throw SshPacketParseException();
replyData.q = SshPacketParser::asString(replyData.k_s, &k_sOffset);
replyData.q_s = SshPacketParser::asString(m_data, &topLevelOffset);
}
replyData.f = SshPacketParser::asBigInt(m_data, &offset);
offset += 4;
if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo)
const QByteArray fullSignature = SshPacketParser::asString(m_data, &topLevelOffset);
quint32 sigOffset = 0;
if (SshPacketParser::asString(fullSignature, &sigOffset) != pubKeyAlgo)
throw SshPacketParseException();
replyData.signatureBlob = SshPacketParser::asString(m_data, &offset);
replyData.signatureBlob = SshPacketParser::asString(fullSignature, &sigOffset);
if (pubKeyAlgo == SshCapabilities::PubKeyEcdsa) {
// Botan's PK_Verifier wants the signature in this format.
quint32 blobOffset = 0;
const Botan::BigInt r = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
const Botan::BigInt s = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
replyData.signatureBlob = convertByteArray(Botan::BigInt::encode(r));
replyData.signatureBlob += convertByteArray(Botan::BigInt::encode(s));
}
replyData.k_s.prepend(m_data.mid(TypeOffset + 1, 4));
return replyData;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Key exchange failed: "
"Server sent invalid SSH_MSG_KEXDH_REPLY packet.");
"Server sent invalid key exchange reply packet.");
}
}
......
......@@ -63,7 +63,9 @@ struct SshKeyExchangeReply
{
QByteArray k_s;
QList<Botan::BigInt> parameters; // DSS: p, q, g, y. RSA: e, n.
Botan::BigInt f;
Botan::BigInt f; // For DH only.
QByteArray q_s; // For ECDH only.
QByteArray q; // For ECDH only.
QByteArray signatureBlob;
};
......
......@@ -113,44 +113,64 @@ bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit)
qDebug("First packet follows: %d", kexInitParams.firstKexPacketFollows);
#endif
const QByteArray &keyAlgo
= SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods,
kexInitParams.keyAlgorithms.names);
m_serverHostKeyAlgo
= SshCapabilities::findBestMatch(SshCapabilities::PublicKeyAlgorithms,
kexInitParams.serverHostKeyAlgorithms.names);
m_kexAlgoName = SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods,
kexInitParams.keyAlgorithms.names);
const QList<QByteArray> &commonHostKeyAlgos
= SshCapabilities::commonCapabilities(SshCapabilities::PublicKeyAlgorithms,
kexInitParams.serverHostKeyAlgorithms.names);
const bool ecdh = m_kexAlgoName.startsWith(SshCapabilities::EcdhKexNamePrefix);
foreach (const QByteArray &possibleHostKeyAlgo, commonHostKeyAlgos) {
if (ecdh && possibleHostKeyAlgo == SshCapabilities::PubKeyEcdsa) {
m_serverHostKeyAlgo = possibleHostKeyAlgo;
break;
}
if (!ecdh && (possibleHostKeyAlgo == SshCapabilities::PubKeyDss
|| possibleHostKeyAlgo == SshCapabilities::PubKeyRsa)) {
m_serverHostKeyAlgo = possibleHostKeyAlgo;
break;
}
}
if (m_serverHostKeyAlgo.isEmpty()) {
throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Invalid combination of key exchange and host key algorithms.",
QCoreApplication::translate("SshConnection",
"No matching host key algorithm available for key exchange algorithm '%1'.")
.arg(QString::fromLatin1(m_kexAlgoName)));
}
determineHashingAlgorithm(kexInitParams, true);
determineHashingAlgorithm(kexInitParams, false);
m_encryptionAlgo
= SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms,
kexInitParams.encryptionAlgorithmsClientToServer.names);
m_decryptionAlgo
= SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms,
kexInitParams.encryptionAlgorithmsServerToClient.names);
m_c2sHMacAlgo
= SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms,
kexInitParams.macAlgorithmsClientToServer.names);
m_s2cHMacAlgo
= SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms,
kexInitParams.macAlgorithmsServerToClient.names);
SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms,
kexInitParams.compressionAlgorithmsClientToServer.names);
SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms,
kexInitParams.compressionAlgorithmsServerToClient.names);
AutoSeeded_RNG rng;
m_dhKey.reset(new DH_PrivateKey(rng,
DL_Group(botanKeyExchangeAlgoName(keyAlgo))));
if (ecdh) {
m_ecdhKey.reset(new ECDH_PrivateKey(rng, EC_Group(botanKeyExchangeAlgoName(m_kexAlgoName))));
m_sendFacility.sendKeyEcdhInitPacket(convertByteArray(m_ecdhKey->public_value()));
} else {
m_dhKey.reset(new DH_PrivateKey(rng, DL_Group(botanKeyExchangeAlgoName(m_kexAlgoName))));
m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y());
}
m_serverKexInitPayload = serverKexInit.payLoad();
m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y());
return kexInitParams.firstKexPacketFollows;
}
void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
const QByteArray &clientId)
{
const SshKeyExchangeReply &reply
= dhReply.extractKeyExchangeReply(m_serverHostKeyAlgo);
if (reply.f <= 0 || reply.f >= m_dhKey->group_p()) {
if (m_dhKey && (reply.f <= 0 || reply.f >= m_dhKey->group_p())) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Server sent invalid f.");
}
......@@ -160,19 +180,28 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
concatenatedData += AbstractSshPacket::encodeString(m_clientKexInitPayload);
concatenatedData += AbstractSshPacket::encodeString(m_serverKexInitPayload);
concatenatedData += reply.k_s;
concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
DH_KA_Operation dhOp(*m_dhKey);
SecureVector<byte> encodedF = BigInt::encode(reply.f);
SecureVector<byte> encodedK = dhOp.agree(encodedF, encodedF.size());
SecureVector<byte> encodedK;
if (m_dhKey) {
concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
DH_KA_Operation dhOp(*m_dhKey);
SecureVector<byte> encodedF = BigInt::encode(reply.f);
encodedK = dhOp.agree(encodedF, encodedF.size());
} else {
Q_ASSERT(m_ecdhKey);
concatenatedData // Q_C.
+= AbstractSshPacket::encodeString(convertByteArray(m_ecdhKey->public_value()));
concatenatedData += AbstractSshPacket::encodeString(reply.q_s);
ECDH_KA_Operation ecdhOp(*m_ecdhKey);
encodedK = ecdhOp.agree(convertByteArray(reply.q_s), reply.q_s.count());
}
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()));
const SecureVector<byte> &hashResult
= m_hash->process(convertByteArray(concatenatedData),
concatenatedData.size());
m_hash.reset(get_hash(botanHMacAlgoName(hashAlgoForKexAlgo())));
const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData),
concatenatedData.size());
m_h = convertByteArray(hashResult);
#ifdef CREATOR_SSH_DEBUG
......@@ -199,22 +228,69 @@ void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
RSA_PublicKey * const rsaKey
= new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0));
sigKey.reset(rsaKey);
} else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyEcdsa) {
const PointGFp point = OS2ECP(convertByteArray(reply.q), reply.q.count(),
m_ecdhKey->domain().get_curve());
ECDSA_PublicKey * const ecdsaKey = new ECDSA_PublicKey(m_ecdhKey->domain(), point);
sigKey.reset(ecdsaKey);
} else {
Q_ASSERT(!"Impossible: Neither DSS nor RSA!");
Q_ASSERT(!"Impossible: Neither DSS nor RSA nor ECDSA!");
}
const byte * const botanH = convertByteArray(m_h);
const Botan::byte * const botanSig
= convertByteArray(reply.signatureBlob);
const Botan::byte * const botanSig = convertByteArray(reply.signatureBlob);
PK_Verifier verifier(*sigKey, botanEmsaAlgoName(m_serverHostKeyAlgo));
if (!verifier.verify_message(botanH, m_h.size(), botanSig,
reply.signatureBlob.size())) {
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.");
"Invalid signature in key exchange reply packet.");
}
checkHostKey(reply.k_s);
m_sendFacility.sendNewKeysPacket();
m_dhKey.reset(nullptr);
m_ecdhKey.reset(nullptr);
}
QByteArray SshKeyExchange::hashAlgoForKexAlgo() const
{
if (m_kexAlgoName == SshCapabilities::EcdhNistp256)
return SshCapabilities::HMacSha256;
if (m_kexAlgoName == SshCapabilities::EcdhNistp384)
return SshCapabilities::HMacSha384;
if (m_kexAlgoName == SshCapabilities::EcdhNistp521)
return SshCapabilities::HMacSha512;
return SshCapabilities::HMacSha1;
}
void SshKeyExchange::determineHashingAlgorithm(const SshKeyExchangeInit &kexInit,
bool serverToClient)
{
QByteArray * const algo = serverToClient ? &m_s2cHMacAlgo : &m_c2sHMacAlgo;
const QList<QByteArray> &serverCapabilities = serverToClient
? kexInit.macAlgorithmsServerToClient.names
: kexInit.macAlgorithmsClientToServer.names;
const QList<QByteArray> commonAlgos = SshCapabilities::commonCapabilities(
SshCapabilities::MacAlgorithms, serverCapabilities);
const QByteArray hashAlgo = hashAlgoForKexAlgo();
foreach (const QByteArray &potentialAlgo, commonAlgos) {
if (potentialAlgo == hashAlgo
|| !m_kexAlgoName.startsWith(SshCapabilities::EcdhKexNamePrefix)) {
*algo = potentialAlgo;
break;
}
}
if (algo->isEmpty()) {
throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Invalid combination of key exchange and hashing algorithms.",
QCoreApplication::translate("SshConnection",
"Server requested invalid combination of key exchange and hashing algorithms. "
"Key exchange algorithm list was: %1.\nHashing algorithm list was %2.")
.arg(QString::fromLocal8Bit(kexInit.keyAlgorithms.names.join(", ")))
.arg(QString::fromLocal8Bit(serverCapabilities.join(", "))));
}
}
void SshKeyExchange::checkHostKey(const QByteArray &hostKey)
......
......@@ -38,12 +38,14 @@
namespace Botan {
class DH_PrivateKey;
class ECDH_PrivateKey;
class HashFunction;
}
namespace QSsh {
namespace Internal {
class SshKeyExchangeInit;
class SshSendFacility;
class SshIncomingPacket;
......@@ -70,6 +72,8 @@ public:
QByteArray hMacAlgoServerToClient() const { return m_s2cHMacAlgo; }
private:
QByteArray hashAlgoForKexAlgo() const;
void determineHashingAlgorithm(const SshKeyExchangeInit &kexInit, bool serverToClient);
void checkHostKey(const QByteArray &hostKey);
Q_NORETURN void throwHostKeyException();
......@@ -77,6 +81,8 @@ private:
QByteArray m_clientKexInitPayload;
QByteArray m_serverKexInitPayload;
QScopedPointer<Botan::DH_PrivateKey> m_dhKey;
QScopedPointer<Botan::ECDH_PrivateKey> m_ecdhKey;
QByteArray m_kexAlgoName;
QByteArray m_k;
QByteArray m_h;
QByteArray m_serverHostKeyAlgo;
......
......@@ -89,6 +89,11 @@ void SshOutgoingPacket::generateKeyDhInitPacket(const Botan::BigInt &e)
init(SSH_MSG_KEXDH_INIT).appendMpInt(e).finalize();
}
void SshOutgoingPacket::generateKeyEcdhInitPacket(const QByteArray &clientQ)
{
init(SSH_MSG_KEX_ECDH_INIT).appendString(clientQ).finalize();
}
void SshOutgoingPacket::generateNewKeysPacket()
{
init(SSH_MSG_NEWKEYS).finalize();
......
......@@ -50,6 +50,7 @@ public:
QByteArray generateKeyExchangeInitPacket(); // Returns payload.
void generateKeyDhInitPacket(const Botan::BigInt &e);
void generateKeyEcdhInitPacket(const QByteArray &clientQ);
void generateNewKeysPacket();
void generateDisconnectPacket(SshErrorCode reason,
const QByteArray &reasonString);
......
......@@ -53,7 +53,9 @@ enum SshPacketType {
SSH_MSG_KEXINIT = 20,
SSH_MSG_NEWKEYS = 21,
SSH_MSG_KEXDH_INIT = 30,
SSH_MSG_KEX_ECDH_INIT = 30,
SSH_MSG_KEXDH_REPLY = 31,
SSH_MSG_KEX_ECDH_REPLY = 31,
SSH_MSG_USERAUTH_REQUEST = 50,
SSH_MSG_USERAUTH_FAILURE = 51,
......
......@@ -85,6 +85,12 @@ void SshSendFacility::sendKeyDhInitPacket(const Botan::BigInt &e)
sendPacket();
}
void SshSendFacility::sendKeyEcdhInitPacket(const QByteArray &clientQ)
{
m_outgoingPacket.generateKeyEcdhInitPacket(clientQ);
sendPacket();
}
void SshSendFacility::sendNewKeysPacket()
{
m_outgoingPacket.generateNewKeysPacket();
......
......@@ -57,6 +57,7 @@ public:
QByteArray sendKeyExchangeInitPacket();
void sendKeyDhInitPacket(const Botan::BigInt &e);
void sendKeyEcdhInitPacket(const QByteArray &clientQ);
void sendNewKeysPacket();
void sendDisconnectPacket(SshErrorCode reason,
const QByteArray &reasonString);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment