From edaca3e9ce514aeddde04d9f022dddfc179bf744 Mon Sep 17 00:00:00 2001 From: Iru Cai Date: Wed, 9 May 2018 16:33:50 +0800 Subject: fqterm packet: use C buffer Tested using SSH2 --- src/protocol/fqterm_ssh_socket.cpp | 9 +- src/protocol/internal/fqterm_ssh1_packet.cpp | 65 +++++---- src/protocol/internal/fqterm_ssh2_kex.cpp | 40 +++--- src/protocol/internal/fqterm_ssh2_packet.cpp | 189 +++++++++++++-------------- src/protocol/internal/fqterm_ssh2_packet.h | 1 + src/protocol/internal/fqterm_ssh_channel.cpp | 15 ++- src/protocol/internal/fqterm_ssh_kex.cpp | 2 +- src/protocol/internal/fqterm_ssh_packet.cpp | 148 ++++++++++++++------- src/protocol/internal/fqterm_ssh_packet.h | 16 ++- src/protocol/internal/ssh_mac.h | 2 + 10 files changed, 271 insertions(+), 216 deletions(-) diff --git a/src/protocol/fqterm_ssh_socket.cpp b/src/protocol/fqterm_ssh_socket.cpp index c48fc51..ea0f774 100644 --- a/src/protocol/fqterm_ssh_socket.cpp +++ b/src/protocol/fqterm_ssh_socket.cpp @@ -270,10 +270,11 @@ void FQTermSSHSocket::connectToHost(const QString &host_name, quint16 port) { private_socket_->connectToHost(host_name, port); } -void FQTermSSHSocket::writeData() { - socketWriteBlock((const char*)packet_sender_->output_buffer_->data(), - packet_sender_->output_buffer_->len()); - private_socket_->flush(); +void FQTermSSHSocket::writeData() +{ + socketWriteBlock((const char*)buffer_data(&packet_sender_->data_to_send), + buffer_len(&packet_sender_->data_to_send)); + private_socket_->flush(); } void FQTermSSHSocket::handlePacket(int type) { diff --git a/src/protocol/internal/fqterm_ssh1_packet.cpp b/src/protocol/internal/fqterm_ssh1_packet.cpp index aab8f92..78a8bda 100644 --- a/src/protocol/internal/fqterm_ssh1_packet.cpp +++ b/src/protocol/internal/fqterm_ssh1_packet.cpp @@ -47,34 +47,31 @@ namespace FQTerm { cipher = new_3des_ssh1(1); } -void FQTermSSH1PacketSender::makePacket() { - int len, padding, i; - u_int32_t rand_val = 0; - - delete output_buffer_; - - len = buffer_->len() + 4; //CRC32 - padding = 8-(len % 8); - - output_buffer_ = new FQTermSSHBuffer(len + padding + 4); //pktlen and crc32 - output_buffer_->putInt(len); - - for (i = 0; i < padding; i++) { - if (i % 4 == 0) { - rand_val = rand(); // FIXME: rand() doesn't range from 0 to 2^32. - } - - output_buffer_->putByte(rand_val &0xff); - rand_val >>= 8; - } - - output_buffer_->putRawData((const char*)buffer_->data(), buffer_->len()); - output_buffer_->putInt(ssh_crc32(output_buffer_->data() + 4, output_buffer_->len() - 4)); - - if (is_encrypt_) { - cipher->crypt(cipher, output_buffer_->data() + 4, output_buffer_->data() + 4, output_buffer_->len() - 4); - } - +void FQTermSSH1PacketSender::makePacket() +{ + int len, padding_len; + uint32_t padding[2]; + uint8_t *data = buffer_data(&orig_data); + size_t data_len = buffer_len(&orig_data); + + len = data_len + 4; //CRC32 + padding_len = 8 - (len % 8); + padding[0] = rand(); + padding[1] = rand(); + + buffer_clear(&data_to_send); + buffer_append_be32(&data_to_send, len); + buffer_append(&data_to_send, (const uint8_t*)padding, padding_len); + buffer_append(&data_to_send, data, data_len); + buffer_append_be32(&data_to_send, ssh_crc32( + buffer_data(&data_to_send) + 4, + buffer_len(&data_to_send) - 4)); + + if (is_encrypt_) { + cipher->crypt(cipher, buffer_data(&data_to_send) + 4, + buffer_data(&data_to_send) + 4, + buffer_len(&data_to_send) - 4); + } } //============================================================================== @@ -110,7 +107,7 @@ void FQTermSSH1PacketReceiver::parseData(FQTermSSHBuffer *input) { u_int padding_len = total_len - real_data_len_; real_data_len_ -= 5; - buffer_->clear(); + buffer_clear(&recvbuf); // Get the data of the packet. if (input->len() - 4 < (long)total_len) { @@ -131,12 +128,12 @@ void FQTermSSH1PacketReceiver::parseData(FQTermSSHBuffer *input) { memcpy(targetData, sourceData, total_len); } - buffer_->putRawData((char*)targetData, total_len); + buffer_append(&recvbuf, targetData, total_len); // Check the crc32. - buf = buffer_->data() + total_len - 4; + buf = buffer_data(&recvbuf) + total_len - 4; mycrc = ntohu32(buf); - gotcrc = ssh_crc32(buffer_->data(), total_len - 4); + gotcrc = ssh_crc32(buffer_data(&recvbuf), total_len - 4); if (mycrc != gotcrc) { emit packetError(tr("parseData: bad CRC32")); @@ -144,9 +141,9 @@ void FQTermSSH1PacketReceiver::parseData(FQTermSSHBuffer *input) { } // Drop the padding. - buffer_->consume(padding_len); + buffer_consume(&recvbuf, padding_len); - packet_type_ = buffer_->getByte(); + packet_type_ = buffer_get_u8(&recvbuf); emit packetAvaliable(packet_type_); diff --git a/src/protocol/internal/fqterm_ssh2_kex.cpp b/src/protocol/internal/fqterm_ssh2_kex.cpp index 8566e92..ab62ede 100644 --- a/src/protocol/internal/fqterm_ssh2_kex.cpp +++ b/src/protocol/internal/fqterm_ssh2_kex.cpp @@ -128,7 +128,7 @@ bool FQTermSSH2Kex::negotiateAlgorithms() { delete[] I_S_; I_S_ = new char[I_S_len_]; I_S_[0] = SSH2_MSG_KEXINIT; - memcpy(I_S_ + 1, packet_receiver_->buffer_->data(), I_S_len_ - 1); + memcpy(I_S_ + 1, buffer_data(&packet_receiver_->recvbuf), I_S_len_ - 1); // 1. Parse server kex init packet packet_receiver_->getRawData((char*)cookie_, 16); @@ -218,7 +218,7 @@ bool FQTermSSH2Kex::negotiateAlgorithms() { // 2. compose a kex init packet. packet_sender_->startPacket(SSH2_MSG_KEXINIT); - packet_sender_->putRawData((const char*)cookie_, 16); // FIXME: generate new cookie_; + packet_sender_->putRawData((const uint8_t*)cookie_, 16); // FIXME: generate new cookie_; packet_sender_->putString(all_dh_list); packet_sender_->putString("ssh-rsa"); packet_sender_->putString(all_ciphers_list); @@ -234,10 +234,10 @@ bool FQTermSSH2Kex::negotiateAlgorithms() { packet_sender_->putInt(0); // 3. backup the payload of this client packet. - I_C_len_ = packet_sender_->buffer_->len(); + I_C_len_ = buffer_len(&packet_sender_->orig_data); delete[] I_C_; I_C_ = new char[I_C_len_]; - memcpy(I_C_, packet_sender_->buffer_->data(), I_C_len_); + memcpy(I_C_, buffer_data(&packet_sender_->orig_data), I_C_len_); // 4. send packet to server packet_sender_->write(); @@ -259,10 +259,11 @@ bool FQTermSSH2Kex::negotiateAlgorithms() { * string signature of H */ -void FQTermSSH2Kex::exchangeKey() { - packet_sender_->startPacket(SSH2_MSG_KEXDH_INIT); - packet_sender_->putRawData((const char*)sess.dh->mpint_e, sess.dh->e_len); - packet_sender_->write(); +void FQTermSSH2Kex::exchangeKey() +{ + packet_sender_->startPacket(SSH2_MSG_KEXDH_INIT); + packet_sender_->putRawData(sess.dh->mpint_e, sess.dh->e_len); + packet_sender_->write(); } static RSA *CreateRSAContext(unsigned char *host_key, int len); @@ -289,19 +290,20 @@ bool FQTermSSH2Kex::verifyKey() { int s_len = -1; unsigned char *s = (unsigned char *)packet_receiver_->getString(&s_len); - FQTermSSHBuffer *buffer = packet_sender_->output_buffer_; + buffer vbuf; + buffer_init(&vbuf); + buffer_append_string(&vbuf, V_C_, strlen(V_C_)); + buffer_append_string(&vbuf, V_S_, strlen(V_S_)); + buffer_append_string(&vbuf, I_C_, I_C_len_); + buffer_append_string(&vbuf, I_S_, I_S_len_); + buffer_append_string(&vbuf, K_S_, K_S_len_); + buffer_append(&vbuf, sess.dh->mpint_e, sess.dh->e_len); + buffer_append_string(&vbuf, (const char*)mpint_f, mpint_f_len); + buffer_append(&vbuf, sess.dh->secret, sess.dh->secret_len); - buffer->clear(); - buffer->putString(V_C_); - buffer->putString(V_S_); - buffer->putString(I_C_, I_C_len_); - buffer->putString(I_S_, I_S_len_); - buffer->putString(K_S_, K_S_len_); - buffer->putRawData((const char*)sess.dh->mpint_e, sess.dh->e_len); - buffer->putString((const char*)mpint_f, mpint_f_len); - buffer->putRawData((const char*)sess.dh->secret, sess.dh->secret_len); + ssh_dh_hash(sess.dh, buffer_data(&vbuf), sess.H, buffer_len(&vbuf)); - ssh_dh_hash(sess.dh, buffer->data(), sess.H, buffer->len()); + buffer_deinit(&vbuf); // Start verify // ssh-rsa specifies SHA-1 hashing diff --git a/src/protocol/internal/fqterm_ssh2_packet.cpp b/src/protocol/internal/fqterm_ssh2_packet.cpp index 6b95972..4399757 100644 --- a/src/protocol/internal/fqterm_ssh2_packet.cpp +++ b/src/protocol/internal/fqterm_ssh2_packet.cpp @@ -23,7 +23,7 @@ #include "fqterm_ssh2_packet.h" #include "fqterm_serialization.h" -#include "crc32.h" +#include "buffer.h" namespace FQTerm { //============================================================================== @@ -37,103 +37,89 @@ namespace FQTerm { // byte[m] mac (Message Authentication Code - MAC); m = mac_length //============================================================================== -void FQTermSSH2PacketSender::makePacket() { - FQ_TRACE("ssh2packet", 9) << "----------------------------Send " - << (is_encrypt_ ? "Encrypted": "plain") - << " Packet---->>>>>>>"; +void FQTermSSH2PacketSender::makePacket() +{ + FQ_TRACE("ssh2packet", 9) << "----------------------------Send " + << (is_encrypt_ ? "Encrypted": "plain") + << " Packet---->>>>>>>"; - // 0. compress - if (is_compressed_) { - FQ_VERIFY(false); - } + // 0. compress + if (is_compressed_) + FQ_VERIFY(false); - // 1. compute the padding length for padding. - int non_padding_len = 4 + 1 + buffer_->len(); + // 1. compute the padding length for padding. + int non_padding_len = 4 + 1 + buffer_len(&orig_data); - int padding_block_len = 8; - if (is_encrypt_ && cipher->blkSize > padding_block_len) { - padding_block_len = cipher->blkSize; - } + int padding_block_len = 8; + if (is_encrypt_ && cipher->blkSize > padding_block_len) + padding_block_len = cipher->blkSize; - int padding_len = padding_block_len - (non_padding_len % padding_block_len); - if (padding_len < 4) { - padding_len += padding_block_len; - } + int padding_len = padding_block_len - (non_padding_len % padding_block_len); + if (padding_len < 4) + padding_len += padding_block_len; - // 2. renew the output buffer. - int total_len = non_padding_len + padding_len; - if (is_mac_) - total_len += mac->dgstSize; + // 2. renew the output buffer. + int total_len = non_padding_len + padding_len; + if (is_mac_) + total_len += mac->dgstSize; - delete output_buffer_; - output_buffer_ = new FQTermSSHBuffer(total_len); + buffer_clear(&data_to_send); - // 3. Fill the output buffer. - int packet_len = 1 + buffer_->len() + padding_len; + // 3. Fill the output buffer. + int packet_len = 1 + buffer_len(&orig_data) + padding_len; - output_buffer_->putInt(packet_len); - output_buffer_->putByte(padding_len); - output_buffer_->putRawData((const char*)buffer_->data(), buffer_->len()); + buffer_append_be32(&data_to_send, packet_len); + buffer_append_byte(&data_to_send, padding_len); + buffer_append(&data_to_send, buffer_data(&orig_data), buffer_len(&orig_data)); - u_int32_t rand_val = 0; - for (int i = 0; i < padding_len; i++) { - if (i % 4 == 0) { - rand_val = rand(); // FIXME: rand() doesn't range from 0 to 2^32. - } - output_buffer_->putByte(rand_val & 0xff); - rand_val >>= 8; - } + uint32_t padding[8]; /* padding at most 256 bits */ + for (int i = 0; i < 8; i++) + padding[i] = rand(); + buffer_append(&data_to_send, (const uint8_t*)padding, padding_len); - // 4. Add MAC on the entire unencrypted packet, - // including two length fields, 'payload' and 'random padding'. - if (is_mac_) { - const unsigned char *packet = output_buffer_->data(); - int len = output_buffer_->len(); - - FQTermSSHBuffer buffer(4 + len); - buffer.putInt(sequence_no_); - buffer.putRawData((const char *)packet, len); - - std::vector digest(mac->dgstSize); - mac->getmac(mac, buffer.data(), buffer.len(), &digest[0]); - - FQ_TRACE("ssh2packet", 9) << "Making packets..."; - FQ_TRACE("ssh2packet", 9) << "Append MAC with sequence_no_" << sequence_no_; - FQ_TRACE("ssh2packet", 9) << "Compute MAC with " - << buffer.len() << " bytes data:\n" - << dumpHexString << std::string((char *)buffer.data(), buffer.len()); - FQ_TRACE("ssh2packet", 9) << "MAC data " - << digest.size() << " bytes:\n" - << dumpHexString << std::string((const char *)&digest[0], digest.size()); - - output_buffer_->putRawData((const char *)&digest[0], digest.size()); - } + // 4. Add MAC on the entire unencrypted packet, + // including two length fields, 'payload' and 'random padding'. + if (is_mac_) { + const unsigned char *packet = buffer_data(&data_to_send); + int len = buffer_len(&data_to_send); - if (is_compressed_) { - FQ_VERIFY(false); - } + uint8_t digest[MAX_DGSTLEN]; + + buffer mbuffer; + buffer_init(&mbuffer); + buffer_append_be32(&mbuffer, sequence_no_); + buffer_append(&mbuffer, packet, len); + mac->getmac(mac, buffer_data(&mbuffer), buffer_len(&mbuffer), digest); + buffer_deinit(&mbuffer); + + buffer_append(&data_to_send, digest, mac->dgstSize); + } + + if (is_compressed_) { + FQ_VERIFY(false); + } - if (is_encrypt_) { - // as RFC 4253: - // When encryption is in effect, the packet length, padding - // length, payload, and padding fields of each packet MUST be encrypted - // with the given algorithm. + if (is_encrypt_) { + // as RFC 4253: + // When encryption is in effect, the packet length, padding + // length, payload, and padding fields of each packet MUST be encrypted + // with the given algorithm. - u_char *data = output_buffer_->data(); - int len = output_buffer_->len() - mac->dgstSize; + uint8_t *data = buffer_data(&data_to_send); + int len = buffer_len(&data_to_send) - mac->dgstSize; - FQ_TRACE("ssh2packet", 9) << "An packet (without MAC) to be encrypted:" - << len << " bytes:\n" - << dumpHexString << std::string((const char *)data, len); + FQ_TRACE("ssh2packet", 9) << "An packet (without MAC) to be encrypted:" + << len << " bytes:\n" + << dumpHexString << std::string((const char *)data, len); - FQ_VERIFY(cipher->crypt(cipher, data, data, len)==1); + FQ_VERIFY(cipher->crypt(cipher, data, data, len)==1); - FQ_TRACE("ssh2packet", 9) << "An encrypted packet (without MAC) made:" - << len << " bytes:\n" - << dumpHexString << std::string((const char *)data, len); - } + FQ_TRACE("ssh2packet", 9) << "An encrypted packet (without MAC) made:" + << len << " bytes:\n" + << dumpHexString << std::string((const char *)data, len); + } - ++sequence_no_; + ++sequence_no_; } //============================================================================== @@ -192,23 +178,26 @@ void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) { FQ_VERIFY(cipher->crypt(cipher, tmp, tmp, left_len)==1); } - // 3. check MAC + // 3. check MAC if (is_mac_) { - int digest_len = mac->dgstSize; - std::vector digest(digest_len); - - FQTermSSHBuffer buffer(4 + expected_input_len - digest_len); - buffer.putInt(sequence_no_); - buffer.putRawData((const char *)input->data(), expected_input_len - digest_len); - mac->getmac(mac, buffer.data(), buffer.len(), &digest[0]); - - u_char *received_digest = input->data() + expected_input_len - digest_len; - - if (memcmp(&digest[0], received_digest, digest_len) != 0) { - emit packetError("incorrect MAC."); - return ; - } - } + int digest_len = mac->dgstSize; + uint8_t digest[MAX_DGSTLEN]; + + buffer mbuf; + buffer_init(&mbuf); + buffer_append_be32(&mbuf, sequence_no_); + buffer_append(&mbuf, (const uint8_t*)input->data(), + expected_input_len - digest_len); + mac->getmac(mac, buffer_data(&mbuf), buffer_len(&mbuf), digest); + buffer_deinit(&mbuf); + + u_char *received_digest = input->data() + expected_input_len - digest_len; + + if (memcmp(digest, received_digest, digest_len) != 0) { + emit packetError("incorrect MAC."); + return ; + } + } // 4. get every field of the ssh packet. packet_len = input->getInt(); @@ -223,14 +212,14 @@ void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) { real_data_len_ = packet_len - 1 - padding_len; - buffer_->clear(); - buffer_->putRawData((char*)&data[0] + 1, real_data_len_); + buffer_clear(&recvbuf); + buffer_append(&recvbuf, &data[0] + 1, real_data_len_); FQ_TRACE("ssh2packet", 9) << "Receive " << real_data_len_ << " bytes payload:\n" << dumpHexString << std::string((char *)&data[0] + 1, real_data_len_); // 5. notify others a ssh packet is parsed successfully. - packet_type_ = buffer_->getByte(); + packet_type_ = buffer_get_u8(&recvbuf); real_data_len_ -= 1; emit packetAvaliable(packet_type_); diff --git a/src/protocol/internal/fqterm_ssh2_packet.h b/src/protocol/internal/fqterm_ssh2_packet.h index f2e6b0f..7c7bf63 100644 --- a/src/protocol/internal/fqterm_ssh2_packet.h +++ b/src/protocol/internal/fqterm_ssh2_packet.h @@ -22,6 +22,7 @@ #define FQTERM_SSH2_PACKET_H #include "fqterm_ssh_packet.h" +#include "buffer.h" namespace FQTerm { diff --git a/src/protocol/internal/fqterm_ssh_channel.cpp b/src/protocol/internal/fqterm_ssh_channel.cpp index 1e338c9..e997121 100644 --- a/src/protocol/internal/fqterm_ssh_channel.cpp +++ b/src/protocol/internal/fqterm_ssh_channel.cpp @@ -67,7 +67,7 @@ void FQTermSSH1Channel::changeTermSize(int col, int row) { void FQTermSSH1Channel::sendData(const char *data, int len) { packet_sender_->startPacket(SSH1_CMSG_STDIN_DATA); packet_sender_->putInt(len); - packet_sender_->putRawData(data, len); + packet_sender_->putRawData((const uint8_t *)data, len); packet_sender_->write(); } @@ -98,7 +98,7 @@ void FQTermSSH1Channel::handlePacket(int type) { case SSH1_SMSG_STDOUT_DATA: case SSH1_SMSG_STDERR_DATA: { - const char *data = (const char *)packet_receiver_->buffer_->data() + 4; + const char *data = (const char*)buffer_data(&packet_receiver_->recvbuf) + 4; int len = packet_receiver_->packetDataLen() - 4; emit channelReadyRead(data, len); } @@ -336,7 +336,7 @@ void FQTermSSH2Channel::processChannelPacket() { // string data packet_receiver_->consume(4); int len = packet_receiver_->getInt(); - const char *data = (const char *)packet_receiver_->buffer_->data(); + const char *data = (const char*)buffer_data(&packet_receiver_->recvbuf); local_window_size_ -= len; checkLocalWindowSize(); emit channelReadyRead(data, len); @@ -349,7 +349,7 @@ void FQTermSSH2Channel::processChannelPacket() { // string data packet_receiver_->consume(4); int len = packet_receiver_->getInt(); - const char *data = (const char *)packet_receiver_->buffer_->data(); + const char *data = (const char*)buffer_data(&packet_receiver_->recvbuf); local_window_size_ -= len; checkLocalWindowSize(); emit channelReadyRead(data, len); @@ -377,9 +377,10 @@ void FQTermSSH2Channel::processChannelPacket() { } } -void FQTermSSH2Channel::handlePacket(int type) { +void FQTermSSH2Channel::handlePacket(int type) +{ // first check the channel id. - u_int32_t channel_id = ntohu32(packet_receiver_->buffer_->data()); + u_int32_t channel_id = ntohu32(buffer_data(&packet_receiver_->recvbuf)); if (channel_id != channel_id_) { return; } @@ -400,7 +401,7 @@ void FQTermSSH2Channel::handlePacket(int type) { FQ_TRACE("ssh2channel", 8) << "SSH2_MSG_CHANNEL_REQUEST isn't supported, just send back a packet with SSH2_MSG_CHANNEL_SUCCESS if reply is needed."; packet_receiver_->consume(4); - u_int32_t len = ntohu32(packet_receiver_->buffer_->data()); + u_int32_t len = ntohu32(buffer_data(&packet_receiver_->recvbuf)); packet_receiver_->consume(4 + len); bool replyNeeded = packet_receiver_->getByte(); diff --git a/src/protocol/internal/fqterm_ssh_kex.cpp b/src/protocol/internal/fqterm_ssh_kex.cpp index e2975d1..910eb26 100644 --- a/src/protocol/internal/fqterm_ssh_kex.cpp +++ b/src/protocol/internal/fqterm_ssh_kex.cpp @@ -178,7 +178,7 @@ void FQTermSSH1Kex::makeSessionKey() { packet_sender_->startPacket(SSH1_CMSG_SESSION_KEY); packet_sender_->putByte(SSH_CIPHER_3DES); - packet_sender_->putRawData((const char*)cookie_, 8); + packet_sender_->putRawData((const uint8_t*)cookie_, 8); packet_sender_->putBN(key); BN_free(key); diff --git a/src/protocol/internal/fqterm_ssh_packet.cpp b/src/protocol/internal/fqterm_ssh_packet.cpp index 6e40de8..5db2385 100644 --- a/src/protocol/internal/fqterm_ssh_packet.cpp +++ b/src/protocol/internal/fqterm_ssh_packet.cpp @@ -25,6 +25,7 @@ #include "fqterm_serialization.h" #include "crc32.h" +#include namespace FQTerm { @@ -32,9 +33,10 @@ namespace FQTerm { //FQTermSSHPacketSender //============================================================================== -FQTermSSHPacketSender::FQTermSSHPacketSender() { - buffer_ = new FQTermSSHBuffer(1024); - output_buffer_ = new FQTermSSHBuffer(1024); +FQTermSSHPacketSender::FQTermSSHPacketSender() +{ + buffer_init(&orig_data); + buffer_init(&data_to_send); is_encrypt_ = false; cipher_type_ = SSH_CIPHER_NONE; @@ -48,43 +50,56 @@ FQTermSSHPacketSender::FQTermSSHPacketSender() { sequence_no_ = 0; } -FQTermSSHPacketSender::~FQTermSSHPacketSender() { - delete buffer_; - delete output_buffer_; +FQTermSSHPacketSender::~FQTermSSHPacketSender() +{ if (cipher) cipher->cleanup(cipher); if (mac) mac->cleanup(mac); + buffer_deinit(&data_to_send); + buffer_deinit(&orig_data); } -void FQTermSSHPacketSender::putRawData(const char *data, int len) { - buffer_->putRawData(data, len); -} - -void FQTermSSHPacketSender::putByte(int data) { - buffer_->putByte(data); -} - -void FQTermSSHPacketSender::putInt(u_int data) { - buffer_->putInt(data); -} - -void FQTermSSHPacketSender::putString(const char *string, int len) { - buffer_->putString(string, len); -} +void FQTermSSHPacketSender::putString(const char *s, int len) +{ + if (len < 0) + len = strlen(s); -void FQTermSSHPacketSender::putBN(BIGNUM *bn) { - buffer_->putSSH1BN(bn); + putInt(len); + putRawData((const uint8_t *)s, len); } -void FQTermSSHPacketSender::startPacket(int pkt_type) { - buffer_->clear(); - buffer_->putByte(pkt_type); +void FQTermSSHPacketSender::putBN(BIGNUM *bignum) +{ + int bits = BN_num_bits(bignum); + int bin_size = (bits + 7) / 8; + uint8_t buf[bin_size]; + int oi; + uint8_t msg[2]; + + // Get the value of in binary + oi = BN_bn2bin(bignum, buf); + if (oi != bin_size) { + FQ_TRACE("sshbuffer", 0) << "BN_bn2bin() failed: oi = " << oi + << " != bin_size." << bin_size; + } + + // Store the number of bits in the buffer in two bytes, msb first + buffer_append_be16(&orig_data, bits); + // Store the binary data. + putRawData(buf, oi); +} + +void FQTermSSHPacketSender::startPacket(uint8_t pkt_type) +{ + buffer_clear(&orig_data); + putByte(pkt_type); } -void FQTermSSHPacketSender::write() { - makePacket(); - emit dataToWrite(); +void FQTermSSHPacketSender::write() +{ + makePacket(); + emit dataToWrite(); } void FQTermSSHPacketSender::startEncryption(const u_char *key, const u_char *IV) { @@ -114,8 +129,9 @@ void FQTermSSHPacketSender::resetMac() { //FQTermSSHPacketReceiver //============================================================================== -FQTermSSHPacketReceiver::FQTermSSHPacketReceiver() { - buffer_ = new FQTermSSHBuffer(1024); +FQTermSSHPacketReceiver::FQTermSSHPacketReceiver() +{ + buffer_init(&recvbuf); is_decrypt_ = false; cipher_type_ = SSH_CIPHER_NONE; @@ -131,35 +147,79 @@ FQTermSSHPacketReceiver::FQTermSSHPacketReceiver() { FQTermSSHPacketReceiver::~FQTermSSHPacketReceiver() { - delete buffer_; + buffer_deinit(&recvbuf); if (cipher) cipher->cleanup(cipher); if (mac) mac->cleanup(mac); } -void FQTermSSHPacketReceiver::getRawData(char *data, int length) { - buffer_->getRawData(data, length); +void FQTermSSHPacketReceiver::getRawData(char *data, int length) +{ + if (buffer_len(&recvbuf) >= length) + buffer_get(&recvbuf, (uint8_t*)data, length); + else + emit packetError("Read too many bytes!"); } -u_char FQTermSSHPacketReceiver::getByte() { - return buffer_->getByte(); +u_char FQTermSSHPacketReceiver::getByte() +{ + if (buffer_len(&recvbuf) >= 1) + return buffer_get_u8(&recvbuf); + else + emit packetError("Read too many bytes!"); } -u_int FQTermSSHPacketReceiver::getInt() { - return buffer_->getInt(); +u_int FQTermSSHPacketReceiver::getInt() +{ + if (buffer_len(&recvbuf) >= 4) + return buffer_get_u32(&recvbuf); + else + emit packetError("Read too many bytes!"); } -void *FQTermSSHPacketReceiver::getString(int *length) { - return buffer_->getString(length); +void *FQTermSSHPacketReceiver::getString(int *length) +{ + uint32_t l = getInt(); + char *data = new char[l+1]; + getRawData(data, l); + data[l] = 0; + if (length != NULL) + *length = l; + return data; } -void FQTermSSHPacketReceiver::getBN(BIGNUM *bignum) { - buffer_->getSSH1BN(bignum); +void FQTermSSHPacketReceiver::getBN(BIGNUM *bignum) +{ + int bits, bytes; + u_char buf[2]; + u_char *bin; + + // Get the number for bits. + if (buffer_len(&recvbuf) >= 2) { + bits = buffer_get_u16(&recvbuf); + } else { + emit packetError("Read too many bytes!"); + return; + } + // Compute the number of binary bytes that follow. + bytes = (bits + 7) / 8; + if (bytes > 8 *1024) { + emit packetError("Can't handle BN of size!"); + return ; + } + if (buffer_len(&recvbuf) < bytes) { + emit packetError("The input buffer is too small!"); + return ; + } + bin = buffer_data(&recvbuf); + BN_bin2bn(bin, bytes, bignum); + buffer_consume(&recvbuf, bytes); } -void FQTermSSHPacketReceiver::consume(int len) { - buffer_->consume(len); +void FQTermSSHPacketReceiver::consume(int len) +{ + buffer_consume(&recvbuf, len); } void FQTermSSHPacketReceiver::startEncryption(const u_char *key, const u_char *IV) { diff --git a/src/protocol/internal/fqterm_ssh_packet.h b/src/protocol/internal/fqterm_ssh_packet.h index 83dcac7..32f9a29 100644 --- a/src/protocol/internal/fqterm_ssh_packet.h +++ b/src/protocol/internal/fqterm_ssh_packet.h @@ -30,25 +30,27 @@ #include "ssh_mac.h" #include "fqterm_serialization.h" #include "ssh_cipher.h" +#include "buffer.h" namespace FQTerm { class FQTermSSHPacketSender: public QObject { Q_OBJECT; public: - FQTermSSHBuffer *output_buffer_; - FQTermSSHBuffer *buffer_; + buffer orig_data; /* always unencrypted */ + buffer data_to_send; ssh_cipher_t *cipher; ssh_mac_t *mac; FQTermSSHPacketSender(); virtual ~FQTermSSHPacketSender(); - void startPacket(int pkt_type); - void putByte(int data); - void putInt(u_int data); + void startPacket(uint8_t pkt_type); + inline void putByte(uint8_t b) { buffer_append_byte(&orig_data, b); } + inline void putInt(uint32_t x) { buffer_append_be32(&orig_data, x); } void putString(const char *string, int len = -1); - void putRawData(const char *data, int length); + inline void putRawData(const uint8_t *data, size_t len) + { buffer_append(&orig_data, data, len); } void putBN(BIGNUM *bignum); void write(); @@ -84,7 +86,7 @@ class FQTermSSHPacketSender: public QObject { class FQTermSSHPacketReceiver: public QObject { Q_OBJECT; public: - FQTermSSHBuffer *buffer_; + buffer recvbuf; ssh_cipher_t *cipher; ssh_mac_t *mac; diff --git a/src/protocol/internal/ssh_mac.h b/src/protocol/internal/ssh_mac.h index 507a9cd..8e44095 100644 --- a/src/protocol/internal/ssh_mac.h +++ b/src/protocol/internal/ssh_mac.h @@ -24,6 +24,8 @@ #include #include +#define MAX_DGSTLEN 128 + #ifdef __cplusplus extern "C" { #endif -- cgit v1.2.3