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()) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Server sent invalid f."); } QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId); concatenatedData += AbstractSshPacket::encodeString(m_serverId); 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); SymmetricKey k = m_dhKey->derive_key(reply.f); m_k = AbstractSshPacket::encodeMpInt(BigInt(k.begin(), k.length())); concatenatedData += m_k; m_hash.reset(get_hash(botanSha1Name())); const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData), concatenatedData.size()); m_h = convertByteArray(hashResult); 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(get_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(get_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, reply.signatureBlob.size())) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Invalid signature in SSH_MSG_KEXDH_REPLY packet."); } m_sendFacility.sendNewKeysPacket(); }
void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply, const QByteArray &clientId) { const SshKeyExchangeReply &reply = dhReply.extractKeyExchangeReply(m_serverHostKeyAlgo); 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."); } QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId); concatenatedData += AbstractSshPacket::encodeString(m_serverId); concatenatedData += AbstractSshPacket::encodeString(m_clientKexInitPayload); concatenatedData += AbstractSshPacket::encodeString(m_serverKexInitPayload); concatenatedData += reply.k_s; 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(botanHMacAlgoName(hashAlgoForKexAlgo()))); const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData), concatenatedData.size()); m_h = convertByteArray(hashResult); #ifdef CREATOR_SSH_DEBUG printData("Client Id", AbstractSshPacket::encodeString(clientId)); printData("Server Id", AbstractSshPacket::encodeString(m_serverId)); printData("Client Payload", AbstractSshPacket::encodeString(m_clientKexInitPayload)); printData("Server payload", AbstractSshPacket::encodeString(m_serverKexInitPayload)); printData("K_S", reply.k_s); printData("y", AbstractSshPacket::encodeMpInt(m_dhKey->get_y())); printData("f", AbstractSshPacket::encodeMpInt(reply.f)); printData("K", m_k); printData("Concatenated data", concatenatedData); printData("H", m_h); #endif // CREATOR_SSH_DEBUG QScopedPointer<Public_Key> sigKey; 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); } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) { 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 nor ECDSA!"); } const byte * const botanH = convertByteArray(m_h); 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())) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Invalid signature in key exchange reply packet."); } checkHostKey(reply.k_s); m_sendFacility.sendNewKeysPacket(); m_dhKey.reset(nullptr); m_ecdhKey.reset(nullptr); }
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()) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Server sent invalid f."); } QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId); concatenatedData += AbstractSshPacket::encodeString(m_serverId); 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); const BigInt k = power_mod(reply.f, m_dhKey->get_x(), m_dhKey->get_domain().get_p()); m_k = AbstractSshPacket::encodeMpInt(k); concatenatedData += m_k; m_hash.reset(get_hash(botanSha1Name())); const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData), concatenatedData.size()); m_h = convertByteArray(hashResult); #ifdef CREATOR_SSH_DEBUG printData("Client Id", AbstractSshPacket::encodeString(clientId)); printData("Server Id", AbstractSshPacket::encodeString(m_serverId)); printData("Client Payload", AbstractSshPacket::encodeString(m_clientKexInitPayload)); printData("Server payload", AbstractSshPacket::encodeString(m_serverKexInitPayload)); printData("K_S", reply.k_s); printData("y", AbstractSshPacket::encodeMpInt(m_dhKey->get_y())); printData("f", AbstractSshPacket::encodeMpInt(reply.f)); printData("K", m_k); printData("Concatenated data", concatenatedData); printData("H", m_h); #endif // CREATOR_SSH_DEBUG QSharedPointer<Public_Key> publicKey; QByteArray algorithm; if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) { const DL_Group group(reply.parameters.at(0), reply.parameters.at(1), reply.parameters.at(2)); publicKey = createDsaPublicKey(group, reply.parameters.at(3)); algorithm = SshCapabilities::PubKeyDss; } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) { publicKey = createRsaPublicKey(reply.parameters.at(1), reply.parameters.at(0)); algorithm = 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 (!PK_Verifier(*publicKey, botanEmsaAlgoName(algorithm)).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."); } m_sendFacility.sendNewKeysPacket(); }