diff options
Diffstat (limited to 'src/protocol/internal')
32 files changed, 4055 insertions, 0 deletions
diff --git a/src/protocol/internal/crc32.cpp b/src/protocol/internal/crc32.cpp new file mode 100644 index 0000000..2039ac8 --- /dev/null +++ b/src/protocol/internal/crc32.cpp @@ -0,0 +1,84 @@ +/* $OpenBSD: crc32.c,v 1.9 2003/02/12 21:39:50 markus Exp $ */ + +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "crc32.h" + +namespace FQTerm { +static const u_int32_t crc32tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, + 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, + 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, + 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, + 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, + 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, + 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, + 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, + 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, + 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, + 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, + 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, + 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, + 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, + 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, + 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, + 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, + 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, + 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, + 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, + 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, + 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, + 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, + 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, + 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, + 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, + 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +u_int32_t ssh_crc32(const u_char *buf, u_int32_t size) { + u_int32_t i, crc; + + crc = 0; + for (i = 0; i < size; i++) { + crc = crc32tab[(crc ^ buf[i]) &0xff] ^ (crc >> 8); + } return crc; +} + +} // namespace FQTerm diff --git a/src/protocol/internal/crc32.h b/src/protocol/internal/crc32.h new file mode 100644 index 0000000..ca95b89 --- /dev/null +++ b/src/protocol/internal/crc32.h @@ -0,0 +1,37 @@ +/* $OpenBSD: crc32.h,v 1.14 2003/02/12 21:39:50 markus Exp $ */ + +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SSH_CRC32_H +#define SSH_CRC32_H +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +u_int32_t ssh_crc32(const u_char *, u_int32_t); + +} // namespace FQTerm + +#endif diff --git a/src/protocol/internal/fqterm_serialization.h b/src/protocol/internal/fqterm_serialization.h new file mode 100644 index 0000000..7a858c0 --- /dev/null +++ b/src/protocol/internal/fqterm_serialization.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SERIALIZATION_H +#define FQTERM_SERIALIZATION_H + +#if defined(WIN32) +typedef unsigned __int16 u_int16_t; +#else +#include <arpa/inet.h> +#endif + +namespace FQTerm { + +inline u_int16_t ntohu16(const unsigned char *buf) { + return (buf[0] << 8) | buf[1]; +} + +inline u_int32_t ntohu32(const unsigned char *buf) { + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +inline void htonu32(unsigned char *buf, u_int32_t number) { + buf[0] = (number >> 24) & 0xFF; + buf[1] = (number >> 16) & 0xFF; + buf[2] = (number >> 8) & 0xFF; + buf[3] = number & 0xFF; +} + +inline void htonu16(unsigned char *buf, u_int16_t number) { + buf[0] = (number >> 8 & 0xFF); + buf[1] = (number & 0xFF); +} + +} // namespace FQTerm + +#endif // FQTERM_SERIALIZATION_H diff --git a/src/protocol/internal/fqterm_ssh1_packet.cpp b/src/protocol/internal/fqterm_ssh1_packet.cpp new file mode 100644 index 0000000..ded7fe4 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh1_packet.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh1_packet.h" +#include "fqterm_ssh_des.h" + +#include "fqterm_serialization.h" +#include "crc32.h" + +namespace FQTerm { +//============================================================================== +//FQTermSSH1PacketSender +//============================================================================== +//============================================================================== +// +// SSH1 Packet Structure: +// -------------------------------------------------------------------------- +// | length | padding | type | data | crc32 | +// -------------------------------------------------------------------------- +// | uint32 | 1-7bytes | uchar | | 4bytes| +// -------------------------------------------------------------------------- +// encrypt = padding + type + data + crc32 +// length = type + data + crc32 +// +//============================================================================== + +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_->encrypt(output_buffer_->data() + 4, output_buffer_->data() + 4, output_buffer_->len() - 4); + } + +} + +//============================================================================== +//FQTermSSH1PacketReceiver +//============================================================================== +void FQTermSSH1PacketReceiver::parseData(FQTermSSHBuffer *input) { + u_int mycrc, gotcrc; + u_char *buf = NULL; + u_char *targetData = NULL; + u_char *sourceData = NULL; + + // Get the length of the packet. + while (input->len() > 0) { + if (input->len() < 4) { + FQ_TRACE("ssh1packet", 3) << "The packet is too small."; + return ; + } + buf = input->data(); + real_data_len_ = ntohu32(buf); + + if (real_data_len_ > SSH_BUFFER_MAX) { + emit packetError(tr("parseData: The packet is too big")); + return ; + } + + u_int total_len = (real_data_len_ + 8) &~7; + u_int padding_len = total_len - real_data_len_; + + real_data_len_ -= 5; + buffer_->clear(); + + // Get the data of the packet. + if (input->len() - 4 < (long)total_len) { + FQ_TRACE("ssh1packet", 3) << "The packet is too small"; + return ; + } + + real_data_len_ = input->getInt() - 5; + targetData = new u_char[total_len]; + sourceData = new u_char[total_len]; + memset(targetData, 0, total_len); + memset(sourceData, 0, total_len); + + input->getRawData((char*)sourceData, total_len); + if (is_decrypt_) { + cipher_->decrypt(sourceData, targetData, total_len); + } else { + memcpy(targetData, sourceData, total_len); + } + + buffer_->putRawData((char*)targetData, total_len); + + // Check the crc32. + buf = buffer_->data() + total_len - 4; + mycrc = ntohu32(buf); + gotcrc = ssh_crc32(buffer_->data(), total_len - 4); + + if (mycrc != gotcrc) { + emit packetError(tr("parseData: bad CRC32")); + break; + } + + // Drop the padding. + buffer_->consume(padding_len); + + packet_type_ = buffer_->getByte(); + + emit packetAvaliable(packet_type_); + + delete [] sourceData; + delete [] targetData; + } +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh1_packet.h b/src/protocol/internal/fqterm_ssh1_packet.h new file mode 100644 index 0000000..a535635 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh1_packet.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH1_PACKET_H +#define FQTERM_SSH1_PACKET_H + +#include "fqterm_ssh_packet.h" + +namespace FQTerm { + +class FQTermSSH1PacketSender: public FQTermSSHPacketSender { +protected: + virtual void makePacket(); +}; + +class FQTermSSH1PacketReceiver: public FQTermSSHPacketReceiver { +public: + virtual void parseData(FQTermSSHBuffer *input); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH1_PACKET diff --git a/src/protocol/internal/fqterm_ssh2_kex.cpp b/src/protocol/internal/fqterm_ssh2_kex.cpp new file mode 100644 index 0000000..acae08d --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_kex.cpp @@ -0,0 +1,394 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include <vector> +#include <string> +#include <openssl/bn.h> +#include <openssl/sha.h> +#include <openssl/des.h> +#include <openssl/objects.h> +#include <openssl/evp.h> + +#include "fqterm_ssh2_kex.h" +#include "fqterm_ssh_md5.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +static const int g = 2; +static const int q = 128; +static const unsigned char p[q]={ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +FQTermSSH2Kex::FQTermSSH2Kex(const char *V_C, const char *V_S) + : FQTermSSHKex(V_C, V_S) { + is_first_kex_ = true; + kex_state_ = FQTermSSH2Kex::BEFORE_KEXINIT; + + I_C_len_ = 0; + I_C_ = NULL; + I_S_len_ = 0; + I_S_ = NULL; + + bn_x_ = BN_new(); + bn_e_ = BN_new(); + bn_g_ = BN_new(); + bn_p_ = BN_new(); + ctx_ = BN_CTX_new(); + + bn_K_ = BN_new(); + bn_f_ = BN_new(); + + BN_set_word(bn_g_, g); + BN_bin2bn(p, q, bn_p_); + + session_id_ = NULL; +} + +FQTermSSH2Kex::~FQTermSSH2Kex() { + delete[] I_C_; + delete[] I_S_; + + BN_clear_free(bn_x_); + BN_clear_free(bn_e_); + BN_clear_free(bn_g_); + BN_clear_free(bn_p_); + BN_CTX_free(ctx_); + + BN_clear_free(bn_K_); + BN_clear_free(bn_f_); + + delete[] session_id_; +} + +void FQTermSSH2Kex::initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *packetSender) { + packet_receiver_ = packetReceiver; + packet_sender_ = packetSender; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + kex_state_ = FQTermSSH2Kex::BEFORE_KEXINIT; + emit reKex(); +} + +void FQTermSSH2Kex::handlePacket(int type) { + switch (kex_state_) { + case FQTermSSH2Kex::BEFORE_KEXINIT: + negotiateAlgorithms(); + exchangeKey(); + kex_state_ = FQTermSSH2Kex::WAIT_REPLY; + break; + case FQTermSSH2Kex::WAIT_REPLY: + if (verifyKey()) { + sendNewKeys(); + kex_state_ = FQTermSSH2Kex::SESSIONKEY_SENT; + } else { + emit kexError(tr("Key exchange failed!")); + } + break; + case FQTermSSH2Kex::SESSIONKEY_SENT: + if (changeKeyAlg()) { + kex_state_ = FQTermSSH2Kex::KEYEX_OK; + emit kexOK(); + } + break; + case FQTermSSH2Kex::KEYEX_OK: + // TODO: how about Key Re-Exchange (see RFC 4253, 9. Key Re-Exchange) + break; + } +} + +void FQTermSSH2Kex::negotiateAlgorithms() { + FQ_FUNC_TRACE("ssh2kex", 10); + + if (packet_receiver_->packetType() != SSH2_MSG_KEXINIT) { + emit kexError(tr("startKex: First packet is not SSH_MSG_KEXINIT")); + return ; + } + + // 0. Backup the payload of this server packet. + I_S_len_ = packet_receiver_->packetDataLen() + 1; // add 1 bytes for packet type. + 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); + + // 1. Parse server kex init packet + packet_receiver_->getRawData((char*)cookie_, 16); + + std::vector<char> name_lists; + for (int i = 0; i < 10; ++i) { + int name_lists_len = packet_receiver_->getInt(); + if (name_lists_len > 0) { + name_lists.resize(name_lists_len); + packet_receiver_->getRawData(&name_lists[0], name_lists_len); + FQ_TRACE("ssh2kex", 5) << "Algorithms: " << QString::fromAscii(&name_lists[0], name_lists_len); + } else { + FQ_TRACE("ssh2kex", 5) << "None Algorithms"; + } + } + + bool first_kex_packet_follows = packet_receiver_->getByte(); + FQ_TRACE("ssh2kex", 5) << "first_kex_packet_follows: " << first_kex_packet_follows; + + packet_receiver_->consume(4); + + // 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_->putString("diffie-hellman-group1-sha1"); + packet_sender_->putString("ssh-rsa"); + packet_sender_->putString("3des-cbc"); + packet_sender_->putString("3des-cbc"); + packet_sender_->putString("hmac-sha1"); + packet_sender_->putString("hmac-sha1"); + packet_sender_->putString("none"); + packet_sender_->putString("none"); + packet_sender_->putString(""); + packet_sender_->putString(""); + + packet_sender_->putByte(false); + packet_sender_->putInt(0); + + // 3. backup the payload of this client packet. + I_C_len_ = packet_sender_->buffer_->len(); + delete[] I_C_; + I_C_ = new char[I_C_len_]; + memcpy(I_C_, packet_sender_->buffer_->data(), I_C_len_); + + // 4. send packet to server + packet_sender_->write(); +} + +void FQTermSSH2Kex::exchangeKey() { + BN_rand(bn_x_, q, 0, -1); + BN_mod_exp(bn_e_, bn_g_, bn_x_, bn_p_, ctx_); + + packet_sender_->startPacket(SSH2_MSG_KEXDH_INIT); + packet_sender_->putBN2(bn_e_); + packet_sender_->write(); +} + +static RSA *CreateRSAContext(unsigned char *host_key, int len); + +bool FQTermSSH2Kex::verifyKey() { + if (packet_receiver_->packetType() != SSH2_MSG_KEXDH_REPLY) { + emit kexError(tr("Expect a SSH_MSG_KEXDH_REPLY packet")); + return false; + } + + // Extract data + + int K_S_len = -1; + unsigned char *K_S = (unsigned char *)packet_receiver_->getString(&K_S_len); + + packet_receiver_->getBN2(bn_f_); + + int s_len = -1; + unsigned char *s = (unsigned char *)packet_receiver_->getString(&s_len); + + BN_mod_exp(bn_K_, bn_f_, bn_x_, bn_p_, ctx_); + + FQTermSSHBuffer *buffer = packet_sender_->output_buffer_; + + 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((char *)K_S, K_S_len); + buffer->putSSH2BN(bn_e_); + buffer->putSSH2BN(bn_f_); + buffer->putSSH2BN(bn_K_); + + SHA1(buffer->data(), buffer->len(), H_); + + // Start verify + unsigned char s_H[SHA_DIGEST_LENGTH]; + SHA1(H_, SHA_DIGEST_LENGTH, s_H); + + // Ignore the first 15 bytes of the signature of H sent from server: + // algorithm_name_length[4], algorithm_name[7]("ssh-rsa") and signature_length[4]. + RSA *rsactx = CreateRSAContext(K_S, K_S_len); + int sig_len = s_len - 15; + unsigned char *sig = s + 15; + int res = RSA_verify(NID_sha1, s_H, SHA_DIGEST_LENGTH, + sig, sig_len, rsactx); + + RSA_free(rsactx); + + delete K_S; + delete s; + + return res == 1; +} + +static RSA *CreateRSAContext(unsigned char *host_key, int len) { + FQTermSSHBuffer buffer(len); + + buffer.putRawData((char *)host_key, len); + + int algo_len = -1; + unsigned char *algo = (unsigned char *)buffer.getString(&algo_len); + + FQ_VERIFY(std::string("ssh-rsa") == std::string((char *)algo)); + + int e_len = -1; + unsigned char *e = (unsigned char *)buffer.getString(&e_len); + + int n_len = -1; + unsigned char *n = (unsigned char *)buffer.getString(&n_len); + + + RSA *rsa = RSA_new(); + rsa->e = BN_new(); + BN_bin2bn(e, e_len, rsa->e); + + rsa->n = BN_new(); + BN_bin2bn(n, n_len, rsa->n); + + delete[] algo; + delete[] e; + delete[] n; + + return rsa; +} + +void FQTermSSH2Kex::sendNewKeys(){ + packet_sender_->startPacket(SSH2_MSG_NEWKEYS); + packet_sender_->write(); +} + +bool FQTermSSH2Kex::changeKeyAlg() { + if (packet_receiver_->packetType() != SSH2_MSG_NEWKEYS) { + emit kexError(tr("Expect a SSH_MSG_NEWKEYS packet")); + return false; + } + + if (session_id_ == NULL) { + session_id_ = new unsigned char[SHA_DIGEST_LENGTH]; + memcpy(session_id_, H_, SHA_DIGEST_LENGTH); + } + + packet_sender_->setEncryptionType(SSH_CIPHER_3DES); + packet_receiver_->setEncryptionType(SSH_CIPHER_3DES); + + packet_sender_->setMacType(FQTERM_SSH_HMAC_SHA1); + packet_receiver_->setMacType(FQTERM_SSH_HMAC_SHA1); + + // From RFC 4253 section 7.2: + // Initial IV client to server: HASH(K || H || "A" || session_id) + // (Here K is encoded as mpint and "A" as byte and session_id as raw + // data. "A" means the single character A, ASCII 65). + // + // Initial IV server to client: HASH(K || H || "B" || session_id) + // + // Encryption key client to server: HASH(K || H || "C" || session_id) + // + // Encryption key server to client: HASH(K || H || "D" || session_id) + // + // Integrity key client to server: HASH(K || H || "E" || session_id) + // + // Integrity key server to client: HASH(K || H || "F" || session_id) + + int IV_c2s_len = packet_sender_->getIVSize(); + unsigned char *IV_c2s = computeKey(IV_c2s_len, 'A'); + + int IV_s2c_len = packet_receiver_->getIVSize(); + unsigned char *IV_s2c = computeKey(IV_s2c_len, 'B'); + + int key_c2s_len = packet_sender_->getKeySize(); + unsigned char *key_c2s = computeKey(key_c2s_len, 'C'); + + int key_s2c_len = packet_receiver_->getKeySize(); + unsigned char *key_s2c = computeKey(key_s2c_len, 'D'); + + int mac_key_c2s_len = packet_sender_->getMacKeySize(); + unsigned char *mac_key_c2s = computeKey(mac_key_c2s_len, 'E'); + + int mac_key_s2c_len = packet_receiver_->getMacKeySize(); + unsigned char *mac_key_s2c = computeKey(mac_key_s2c_len, 'F'); + + + packet_sender_->startEncryption(key_c2s, IV_c2s); + packet_sender_->startMac(mac_key_c2s); + + packet_receiver_->startEncryption(key_s2c, IV_s2c); + packet_receiver_->startMac(mac_key_s2c); + + + delete[] IV_c2s; + delete[] IV_s2c; + delete[] key_c2s; + delete[] key_s2c; + delete[] mac_key_c2s; + delete[] mac_key_s2c; + + return true; +} + +unsigned char *FQTermSSH2Kex::computeKey(int expected_len, char flag) { + unsigned char *key = new unsigned char[expected_len + SHA_DIGEST_LENGTH]; + + int len = 0; + SHA_CTX hash; + + FQTermSSHBuffer K(BN_num_bytes(bn_K_) + 5); + K.putSSH2BN(bn_K_); + + while (len < expected_len) { + SHA1_Init(&hash); + SHA1_Update(&hash, K.data(), K.len()); + SHA1_Update(&hash, H_, SHA_DIGEST_LENGTH); + + if (len == 0) { + SHA1_Update(&hash, &flag, 1); + SHA1_Update(&hash, session_id_, SHA_DIGEST_LENGTH); + } else { + SHA1_Update(&hash, key, len); + } + + SHA1_Final(key + len, &hash); + len += SHA_DIGEST_LENGTH; + } + + return key; +} + +} // namespace FQTerm + +#include "fqterm_ssh2_kex.moc" diff --git a/src/protocol/internal/fqterm_ssh2_kex.h b/src/protocol/internal/fqterm_ssh2_kex.h new file mode 100644 index 0000000..671e094 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_kex.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH2_KEX_H +#define FQTERM_SSH2_KEX_H + +#include <openssl/sha.h> + +#include "fqterm_ssh_kex.h" + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSH2Kex: public FQTermSSHKex { + Q_OBJECT; +private: + enum FQTermSSH2KexState { + BEFORE_KEXINIT, WAIT_REPLY, SESSIONKEY_SENT, KEYEX_OK + } kex_state_; + + /* + string V_C, the client's identification string (CR and LF + excluded) + string V_S, the server's identification string (CR and LF + excluded) + string I_C, the payload of the client's SSH_MSG_KEXINIT + string I_S, the payload of the server's SSH_MSG_KEXINIT + string K_S, the host key + mpint e, exchange value sent by the client + mpint f, exchange value sent by the server + mpint K, the shared secret + */ + + int I_C_len_; + char *I_C_; + int I_S_len_; + char *I_S_; + + BIGNUM *bn_x_; + BIGNUM *bn_e_; + BIGNUM *bn_g_; + BIGNUM *bn_p_; + BN_CTX *ctx_; + + BIGNUM *bn_K_; + BIGNUM *bn_f_; + + unsigned char H_[SHA_DIGEST_LENGTH]; + + unsigned char *session_id_; + + + + + bool is_first_kex_; + + FQTermSSHRSA *host_key_; + FQTermSSHRSA *server_key_; + + u_char cookie_[16]; + int server_flag_, ciphers_, auth_; +// u_char session_id_[16]; + u_char session_key_[32]; + + void negotiateAlgorithms(); + void exchangeKey(); + bool verifyKey(); + void sendNewKeys(); + bool changeKeyAlg(); + + unsigned char *computeKey(int len, char flag); + +public: + FQTermSSH2Kex(const char *V_C, const char *V_S); + ~FQTermSSH2Kex(); + + virtual void initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *outputSender); + +public slots: + void handlePacket(int type); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH2_KEX_H diff --git a/src/protocol/internal/fqterm_ssh2_packet.cpp b/src/protocol/internal/fqterm_ssh2_packet.cpp new file mode 100644 index 0000000..d3094d3 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_packet.cpp @@ -0,0 +1,267 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh2_packet.h" +#include "fqterm_ssh_des.h" + +#include "fqterm_serialization.h" +#include "crc32.h" + +namespace FQTerm { +//============================================================================== +//FQTermSSH2PacketSender +//============================================================================== +// SSH2 Packet Structure: +// uint32 packet_length +// byte padding_length +// byte[n1] payload; n1 = packet_length - padding_length - 1 +// byte[n2] random padding; n2 = padding_length +// byte[m] mac (Message Authentication Code - MAC); m = mac_length +//============================================================================== + +void FQTermSSH2PacketSender::makePacket() { + FQ_TRACE("ssh2packet", 9) << "----------------------------Send " + << (is_encrypt_ ? "Encrypted": "plain") + << " Packet---->>>>>>>"; + + // 0. compress + if (is_compressed_) { + FQ_VERIFY(false); + } + + // 1. compute the padding length for padding. + int non_padding_len = 4 + 1 + buffer_->len(); + + int padding_block_len = 8; + if (is_encrypt_ && cipher_->blockSize() > padding_block_len) { + padding_block_len = cipher_->blockSize(); + } + + 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_->digestSize(); + } + + delete output_buffer_; + output_buffer_ = new FQTermSSHBuffer(total_len); + + // 3. Fill the output buffer. + int packet_len = 1 + buffer_->len() + padding_len; + + output_buffer_->putInt(packet_len); + output_buffer_->putByte(padding_len); + output_buffer_->putRawData((const char*)buffer_->data(), buffer_->len()); + + 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; + } + + // 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<u_char> digest(mac_->digestSize()); + mac_->getDigest(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()); + } + + 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. + + u_char *data = output_buffer_->data(); + int len = output_buffer_->len() - mac_->digestSize(); + + FQ_TRACE("ssh2packet", 9) << "An packet (without MAC) to be encrypted:" + << len << " bytes:\n" + << dumpHexString << std::string((const char *)data, len); + + cipher_->encrypt(data, data, len); + + FQ_TRACE("ssh2packet", 9) << "An encrypted packet (without MAC) made:" + << len << " bytes:\n" + << dumpHexString << std::string((const char *)data, len); + } + + ++sequence_no_; +} + +void FQTermSSH2PacketSender::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH2TripleDESCBC; + break; + } +} + + +//============================================================================== +//FQTermSSH2PacketReceiver +//============================================================================== +void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) { + FQ_TRACE("ssh2packet", 9) << "----------------------------Receive " + << (is_decrypt_ ? "Encrypted": "plain") + << " Packet----<<<<<<<"; + while (input->len() > 0) { + // 1. Check the ssh packet + if (input->len() < 16 + || (is_decrypt_ && input->len() < cipher_->blockSize()) + || input->len() < last_expected_input_length_ + ) { + FQ_TRACE("ssh2packet", 3) + << "Got an incomplete packet. Wait for more data."; + return ; + } + + if (last_expected_input_length_ == 0) { + if (is_decrypt_) { + // decrypte the first block to get the packet_length field. + cipher_->decrypt(input->data(), input->data(), cipher_->blockSize()); + } + } else { + // last_expected_input_length_ != 0 + // indicates an incomplete ssh2 packet received last time, + // the first block of data is already decrypted at that time, + // so it must not be decrypted again. + } + + int packet_len = ntohu32(input->data()); + + if (packet_len > SSH_BUFFER_MAX) { + emit packetError(tr("parseData: packet too big")); + return ; + } + + int expected_input_len = 4 + packet_len + (is_mac_ ? mac_->digestSize() : 0); + + if (input->len() < (long)expected_input_len) { + FQ_TRACE("ssh2packet", 3) + << "The packet is too small. Wait for more data."; + last_expected_input_length_ = expected_input_len; + return ; + } else { + last_expected_input_length_ = 0; + } + + // 2. decrypte data. + if (is_decrypt_) { + // decrypte blocks left. + unsigned char *tmp = input->data() + cipher_->blockSize(); + int left_len = expected_input_len - cipher_->blockSize() - mac_->digestSize(); + cipher_->decrypt(tmp, tmp, left_len); + } + + // 3. check MAC + if (is_mac_) { + int digest_len = mac_->digestSize(); + std::vector<u_char> digest(digest_len); + mac_->getDigest(input->data(), expected_input_len - digest_len, &digest[0]); + + u_char *received_digest = input->data() + expected_input_len - digest_len; + + if (memcmp(&digest[0], received_digest, digest_len) == 0) { + FQ_TRACE("ssh2packet", 0) << "incorrect MAC."; + return ; + } + } + + // 4. get every field of the ssh packet. + packet_len = input->getInt(); + + std::vector<u_char> data(packet_len); + + input->getRawData((char*)&data[0], packet_len); + if (is_mac_) { + input->consume(mac_->digestSize()); + } + + int padding_len = data[0]; + + real_data_len_ = packet_len - 1 - padding_len; + + buffer_->clear(); + buffer_->putRawData((char*)&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(); + real_data_len_ -= 1; + emit packetAvaliable(packet_type_); + + ++sequence_no_; + } +} + +void FQTermSSH2PacketReceiver::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH2TripleDESCBC; + break; + } +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh2_packet.h b/src/protocol/internal/fqterm_ssh2_packet.h new file mode 100644 index 0000000..c460984 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh2_packet.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH2_PACKET_H +#define FQTERM_SSH2_PACKET_H + +#include "fqterm_ssh_packet.h" + +namespace FQTerm { + +class FQTermSSH2PacketSender: public FQTermSSHPacketSender { + protected: + virtual void makePacket(); + + public: + virtual void setEncryptionType(int cipherType); +}; + +class FQTermSSH2PacketReceiver: public FQTermSSHPacketReceiver { + private: + // greater than 0 if last time an incomplete ssh2 packet received. + int last_expected_input_length_; + public: + FQTermSSH2PacketReceiver() + : last_expected_input_length_(0) { + } + + virtual void parseData(FQTermSSHBuffer *input); + virtual void setEncryptionType(int cipherType); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH2_PACKET diff --git a/src/protocol/internal/fqterm_ssh_auth.cpp b/src/protocol/internal/fqterm_ssh_auth.cpp new file mode 100644 index 0000000..d063d14 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_auth.cpp @@ -0,0 +1,223 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include <QString> + +#include "fqterm_ssh_auth.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh_const.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +//============================================================================== +//FQTermSSH1PasswdAuth +//============================================================================== + +FQTermSSH1PasswdAuth::FQTermSSH1PasswdAuth(const char *sshuser, + const char *sshpasswd) + : FQTermSSHPasswdAuth(sshuser, sshpasswd) { + is_tried_ = false; + ssh_pw_auth_state_ = FQTermSSH1PasswdAuth::BEFORE_AUTH; +} + +void FQTermSSH1PasswdAuth::initAuth(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output) { + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + packet_sender_->startPacket(SSH1_CMSG_USER); + user_name_.clear(); + passwd_.clear(); + + if (!default_user_.isEmpty() && !default_passwd_.isEmpty()) { + user_name_ = default_user_; + passwd_ = default_passwd_; + } + + while (user_name_.isEmpty()) { + bool isOK = false; + emit requestUserPwd(&user_name_, &passwd_, &isOK); + // SSHLoginDialog login(&d_user, &d_passwd); + if (!isOK) { + emit authError(tr("UserCancel")); + return ; + } + } + + packet_sender_->putString(user_name_.toLatin1()); + packet_sender_->write(); + ssh_pw_auth_state_ = USER_SENT; + is_tried_ = false; +} + +void FQTermSSH1PasswdAuth::handlePacket(int type) { + switch (ssh_pw_auth_state_) { + case BEFORE_AUTH: + FQ_TRACE("sshauth", 0) << "Auth: We should not be here."; + break; + case USER_SENT: + if (type == SSH1_SMSG_SUCCESS) { + ssh_pw_auth_state_ = AUTH_OK; + emit authOK(); + break; + } + if (type != SSH1_SMSG_FAILURE) { + emit authError(tr("Strange response from server")); + break; + } + if (is_tried_) { + bool isOK = false; + emit requestUserPwd(&user_name_, &passwd_, &isOK); + // SSHLoginDialog login(&d_user, &d_passwd); + if (!isOK) { + emit authError(tr("User canceled")); + break; + } + is_tried_ = false; + } + packet_sender_->startPacket(SSH1_CMSG_AUTH_PASSWORD); + packet_sender_->putString(passwd_.toLatin1()); + packet_sender_->write(); + is_tried_ = true; + break; + case AUTH_OK: + break; + default: + return ; + } +} + +//============================================================================== +//FQTermSSH2PasswdAuth +//============================================================================== + +FQTermSSH2PasswdAuth::FQTermSSH2PasswdAuth(const char *sshuser, + const char *sshpasswd) + : FQTermSSHPasswdAuth(sshuser, sshpasswd) { + is_tried_ = false; + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::SERVICE_ACCEPTED; +} + +void FQTermSSH2PasswdAuth::initAuth(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output) { + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + + packet_sender_->startPacket(SSH2_MSG_SERVICE_REQUEST); + packet_sender_->putString("ssh-userauth"); + packet_sender_->write(); + + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::SERVICE_ACCEPTED; +} + +void FQTermSSH2PasswdAuth::handlePacket(int type) { + switch (ssh_pw_auth_state_) { + case FQTermSSH2PasswdAuth::SERVICE_ACCEPTED: + sendUserPasswd(); + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::USER_PASSWD_SENT; + break; + case FQTermSSH2PasswdAuth::USER_PASSWD_SENT: + if (check()) { + FQ_TRACE("ssh2passwdauth", 3) << "Auth OK."; + + emit authOK(); + ssh_pw_auth_state_ = FQTermSSH2PasswdAuth::AUTH_OK; + } + break; + case FQTermSSH2PasswdAuth::AUTH_OK: + break; + default: + return ; + } +} + +bool FQTermSSH2PasswdAuth::check() { + switch(packet_receiver_->packetType()) { + case SSH2_MSG_USERAUTH_SUCCESS: + return true; + break; + case SSH2_MSG_USERAUTH_BANNER: + // TODO: just ignore banner messages. + break; + case SSH2_MSG_USERAUTH_FAILURE: + emit authError(tr("Authentication failed!")); + break; + default: + emit authError(tr("Unexpected packet")); + } + + return false; +} + +void FQTermSSH2PasswdAuth::sendUserPasswd() { + if (packet_receiver_->packetType() != SSH2_MSG_SERVICE_ACCEPT) { + emit authError(tr("Expect a SSH2_MSG_SERVICE_ACCEPT packet")); + return; + } + + u_char *service_name = (u_char *)packet_receiver_->getString(); + + if (std::string((char *)service_name) != std::string("ssh-userauth")) { + emit authError(tr("Error when sending username and password.")); + return; + } + + delete[] service_name; + + // byte SSH_MSG_USERAUTH_REQUEST + // string user name in ISO-10646 UTF-8 encoding [RFC3629] + // string service name in US-ASCII + // string method name in US-ASCII + // .... method specific fields + user_name_.clear(); + passwd_.clear(); + + if (!default_user_.isEmpty() && !default_passwd_.isEmpty()) { + user_name_ = default_user_; + passwd_ = default_passwd_; + } + + while (user_name_.isEmpty()) { + bool isOK = false; + emit requestUserPwd(&user_name_, &passwd_, &isOK); + if (!isOK) { + emit authError(tr("UserCancel")); + return ; + } + } + + packet_sender_->startPacket(SSH2_MSG_USERAUTH_REQUEST); + packet_sender_->putString(user_name_.toLatin1()); + packet_sender_->putString("ssh-connection"); + packet_sender_->putString("password"); + packet_sender_->putByte(false); + packet_sender_->putString(passwd_.toLatin1()); + packet_sender_->write(); +} + +} // namespace FQTerm + +#include <fqterm_ssh_auth.moc> diff --git a/src/protocol/internal/fqterm_ssh_auth.h b/src/protocol/internal/fqterm_ssh_auth.h new file mode 100644 index 0000000..6152a71 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_auth.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_AUTH_H +#define FQTERM_SSH_AUTH_H + +#include <QObject> + +class QString; + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSHAuth: public QObject { + + Q_OBJECT; +protected: + QString user_name_; + FQTermSSHPacketReceiver *packet_receiver_; + FQTermSSHPacketSender *packet_sender_; + +public: + FQTermSSHAuth(const char *sshuser = NULL) + : user_name_(sshuser) { + } + + ~FQTermSSHAuth() {} + + virtual void initAuth(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output) = 0; +public slots: + virtual void handlePacket(int type) = 0; + +signals: + void requestUserPwd(QString *user, QString *pwd, bool *isOK); + void authOK(); + void authError(QString); +}; + +class FQTermSSHPasswdAuth: public FQTermSSHAuth { + Q_OBJECT; +protected: + QString passwd_; + bool is_tried_; + + QString default_user_; + QString default_passwd_; + +public: + FQTermSSHPasswdAuth(const char *sshuser, const char *sshpasswd) + : FQTermSSHAuth(sshuser), + passwd_(sshpasswd), + default_user_(sshuser), + default_passwd_(sshpasswd) { + } +}; + +class FQTermSSH1PasswdAuth: public FQTermSSHPasswdAuth { + Q_OBJECT; +private: + enum FQTermSSH1PasswdAuthState { + BEFORE_AUTH, USER_SENT, PASS_SENT, AUTH_OK + } ssh_pw_auth_state_; + +public: + FQTermSSH1PasswdAuth(const char *sshuser, const char *sshpasswd); + +public slots: + void handlePacket(int type); + void initAuth(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output); +}; + +class FQTermSSH2PasswdAuth: public FQTermSSHPasswdAuth { + Q_OBJECT; +private: + enum FQTermSSH2PasswdAuthState { + SERVICE_ACCEPTED, USER_PASSWD_SENT, PASS_SENT, AUTH_OK + } ssh_pw_auth_state_; + + void sendUserPasswd(); + bool check(); + +public: + FQTermSSH2PasswdAuth(const char *sshuser, const char *sshpasswd); + +public slots: + void handlePacket(int type); + void initAuth(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_AUTH_H diff --git a/src/protocol/internal/fqterm_ssh_buffer.cpp b/src/protocol/internal/fqterm_ssh_buffer.cpp new file mode 100644 index 0000000..d95497a --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_buffer.cpp @@ -0,0 +1,302 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <vector> + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_serialization.h" + +namespace FQTerm { +//============================================================================== +// FQTermSSHBuffer +//============================================================================== + +FQTermSSHBuffer::FQTermSSHBuffer(int size) { + alloc_size_ = size; + buffer_size_ = 0; + offset_ = 0; + buffer_ = new u_char[alloc_size_]; +} + +FQTermSSHBuffer::~FQTermSSHBuffer() { + delete [] buffer_; + offset_ = 0; + buffer_size_ = 0; + alloc_size_ = 0; +} + +void FQTermSSHBuffer::ensure(int len) { + if (len <= (alloc_size_ - (offset_ + buffer_size_))) { + return ; + } else { + alloc_size_ = buffer_size_ + len; + rebuffer(); + } +} + +void FQTermSSHBuffer::rebuffer() { + u_char *newBuffer; + newBuffer = new u_char[alloc_size_]; + memset(newBuffer, 0, alloc_size_); + memcpy(newBuffer, buffer_ + offset_, buffer_size_); + delete [] buffer_; + buffer_ = newBuffer; + offset_ = 0; +} + +void FQTermSSHBuffer::clear() { + memset(buffer_, 0, alloc_size_); + offset_ = 0; + buffer_size_ = 0; +} + +void FQTermSSHBuffer::consume(int len) { + if (len > buffer_size_) { + len = buffer_size_; + } + + offset_ += len; + buffer_size_ -= len; +} + +void FQTermSSHBuffer::putRawData(const char *data, int len) { + if (len < 0) { + FQ_TRACE("sshbuffer", 0) << "Write data error."; + } + + ensure(len); + memcpy((buffer_ + offset_ + buffer_size_), data, len); + buffer_size_ += len; +} + +void FQTermSSHBuffer::getRawData(char *data, int len) { + if (len <= buffer_size_ && len >= 0) { + memcpy(data, buffer_ + offset_, len); + consume(len); + } else { + FQ_TRACE("sshbuffer", 0) << "Read too many data: " << len << " bytes."; + } +} + +//============================================================================== +// Store an BIGNUM in the buffer with a 2-byte msb first bit count, followed by +// (bits+7)/8 bytes of binary data, msb first. +//============================================================================== + +void FQTermSSHBuffer::putSSH1BN(BIGNUM *bignum) { + int bits = BN_num_bits(bignum); + int bin_size = (bits + 7) / 8; + u_char *buf = new u_char[bin_size]; + int oi; + u_char 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 + htonu16(msg, bits); + putRawData((char*)msg, 2); + // Store the binary data. + putRawData((char*)buf, oi); + + memset(buf, 0, bin_size); + delete [] buf; +} + + + +void FQTermSSHBuffer::putSSH2BN(BIGNUM *bignum) { + // FIXME: support negative number and add error handling. + + FQ_VERIFY(!bignum->neg); // currently we don't support negative big number. + + if (BN_is_zero(bignum)) { + this->putInt(0); + } else { + u_int bytes = BN_num_bytes(bignum) + 1; + + FQ_VERIFY(bytes >= 2); // currently we don't support big numbers so small + + std::vector<u_char> buf(bytes); + buf[0] = 0; + + int bin_len = BN_bn2bin(bignum, &buf[0] + 1); + + FQ_VERIFY(bin_len == (int)bytes - 1); + + u_int no_high_bit = (buf[1] & 0x80) ? 0 : 1; + + this->putInt(bytes - no_high_bit); + this->putRawData((const char *)&buf[0] + no_high_bit, bytes - no_high_bit); + } +} + +//============================================================================== +// Retrieves a BIGNUM from the buffer. +//============================================================================== + +void FQTermSSHBuffer::getSSH1BN(BIGNUM *bignum) { + int bits, bytes; + u_char buf[2]; + u_char *bin; + + // Get the number for bits. + getRawData((char*)buf, 2); + bits = ntohu16(buf); + // Compute the number of binary bytes that follow. + bytes = (bits + 7) / 8; + if (bytes > 8 *1024) { + FQ_TRACE("sshbuffer", 0) << "Can't handle BN of size " << bytes; + return ; + } + if (len() < bytes) { + FQ_TRACE("sshbuffer", 0) << "The input buffer is too small."; + return ; + } + bin = data(); + BN_bin2bn(bin, bytes, bignum); + consume(bytes); +} + +void FQTermSSHBuffer::getSSH2BN(BIGNUM *bignum) { + // FIXME: support negative numbers and error handling + int len; + unsigned char *hex_data = (unsigned char *)getString(&len); + + FQ_VERIFY(!(len > 0 && (hex_data[0] & 0x80))); // don't support negative numbers. + + FQ_VERIFY(len < 10240); // don't support so large numbers. + + BIGNUM *res = BN_bin2bn(hex_data, len, bignum); + + FQ_VERIFY(res != NULL); + + delete hex_data; +} + +u_short FQTermSSHBuffer::getWord() { + u_char buf[2]; + u_short data; + + getRawData((char*)buf, 2); + data = ntohu16(buf); + return data; +} + +void FQTermSSHBuffer::putWord(u_short data) { + u_char buf[2]; + + htonu16(buf, data); + putRawData((char*)buf, 2); +} + +u_int FQTermSSHBuffer::getInt() { + u_char buf[4]; + u_int data; + getRawData((char*)buf, 4); + data = ntohu32(buf); + return data; +} + +void FQTermSSHBuffer::putInt(u_int data) { + u_char buf[4]; + + htonu32(buf, data); + putRawData((char*)buf, 4); +} + +//============================================================================== +// Return a character from the buffer (0-255). +//============================================================================== + +u_char FQTermSSHBuffer::getByte() { + u_char ch; + + getRawData((char*) &ch, 1); + return ch; +} + +//============================================================================== +// Stores a character in the buffer. +//============================================================================== + +void FQTermSSHBuffer::putByte(int data) { + u_char ch = data; + + putRawData((char*) &ch, 1); +} + +//============================================================================== +// Stores an arbitrary binary string in the buffer. +//============================================================================== + +void FQTermSSHBuffer::putString(const char *str, int len) { + if (str == NULL) { + FQ_TRACE("sshbuffer", 0) << "Can't put a null pointer string."; + return ; + } + + if (len < 0) { + len = strlen(str); + } + + putInt(len); + putRawData(str, len); +} + +//============================================================================== +// Return an arbitrary binary string from the buffer. The string cannot be +// longer than 256k. The returned value points to memory allocated with new; +// It is the responsibility of the calling function to free the data. +//============================================================================== + +void *FQTermSSHBuffer::getString(int *length) { + u_char *data; + u_int len; + + // Get the length. + len = getInt(); + if ((long)len > buffer_size_) { + FQ_TRACE("sshbuffer", 0) + << "String length " << len + << " is greater than buffer size " << buffer_size_; + return 0; + } + // Allocate space for the string. Add one byte for a null character. + data = new u_char[len + 1]; + // Get the string. + getRawData((char*)data, len); + // Append a null character to make processing easier. + data[len] = 0; + if (length != NULL) { + *length = len; + } + // return the length of the string. + return data; +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_buffer.h b/src/protocol/internal/fqterm_ssh_buffer.h new file mode 100644 index 0000000..e06872f --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_buffer.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_BUFFER_H +#define FQTERM_SSH_BUFFER_H + +#include <openssl/bn.h> +#include <string.h> + +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +#define SSH_BUFFER_MAX 10000000 + +class FQTermSSHBuffer { + private: + u_char *buffer_; + int offset_; + int buffer_size_; + int alloc_size_; + + void ensure(int len); + void rebuffer(); + + public: + FQTermSSHBuffer(int size); + ~FQTermSSHBuffer(); + + u_char *data() const { + return buffer_ + offset_; + } + + int len() const { + return buffer_size_; + } + + void consume(int len); + + void clear(); + + void putRawData(const char *data, int len); + void getRawData(char *data, int len); + + void putSSH1BN(BIGNUM *bignum); + void getSSH1BN(BIGNUM *bignum); + + void putSSH2BN(BIGNUM *bignum); + void getSSH2BN(BIGNUM *bignum); + + void putInt(u_int data); + u_int getInt(); + + void putWord(u_short data); + u_short getWord(); + + void putByte(int data); + u_char getByte(); + + void putString(const char *str, int len = -1); + void *getString(int *length = NULL); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_BUFFER diff --git a/src/protocol/internal/fqterm_ssh_channel.cpp b/src/protocol/internal/fqterm_ssh_channel.cpp new file mode 100644 index 0000000..38a755a --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_channel.cpp @@ -0,0 +1,439 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_channel.h" +#include "fqterm_ssh_const.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_trace.h" +#include <QString> +namespace FQTerm { + +//============================================================================== +//FQTermSSH1Channel +//============================================================================== + +FQTermSSH1Channel::FQTermSSH1Channel() + : FQTermSSHChannel() { + service_state_ = FQTermSSH1Channel::BEGIN_SERVICE; +} + +void FQTermSSH1Channel::initChannel(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output, + int col, int row, const QString& termtype) { + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), this, SLOT(handlePacket(int)))); + packet_sender_->startPacket(SSH1_CMSG_REQUEST_PTY); + // pty request is of no use in BBS, but we do this + packet_sender_->putString(termtype.toLatin1()); + packet_sender_->putInt(row); // FIXME: hardcoded term size. + packet_sender_->putInt(col); + packet_sender_->putInt(0); + packet_sender_->putInt(0); + packet_sender_->putByte(0); + packet_sender_->write(); + service_state_ = FQTermSSH1Channel::REQPTY_SENT; + + is_closed_ = false; +} + +void FQTermSSH1Channel::changeTermSize(int col, int row) { + packet_sender_->startPacket(SSH1_CMSG_WINDOW_SIZE); + packet_sender_->putInt(row); + packet_sender_->putInt(col); + packet_sender_->putInt(0); + packet_sender_->putInt(0); + packet_sender_->write(); +} + +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_->write(); +} + +void FQTermSSH1Channel::closeConnection(const char *reason) { + packet_sender_->startPacket(SSH1_MSG_DISCONNECT); + packet_sender_->putString(reason); + packet_sender_->write(); + is_closed_ = true; +} + +void FQTermSSH1Channel::handlePacket(int type) { + switch (service_state_) { + case BEGIN_SERVICE: + FQ_TRACE("sshchannel", 0) << "Channel: We should not be here"; + break; + case REQPTY_SENT: + if (type != SSH1_SMSG_SUCCESS) { + emit channelError(tr("Server refused pty allocation!")); + } + packet_sender_->startPacket(SSH1_CMSG_EXEC_SHELL); + packet_sender_->write(); + emit channelOK(); + service_state_ = FQTermSSH1Channel::SERVICE_OK; + //emit msg to tell window we could process input. + break; + case SERVICE_OK: + switch (type) { + case SSH1_SMSG_STDOUT_DATA: + case SSH1_SMSG_STDERR_DATA: + { + const char *data = (const char *)packet_receiver_->buffer_->data() + 4; + int len = packet_receiver_->packetDataLen() - 4; + emit channelReadyRead(data, len); + } + break; + case SSH1_SMSG_X11_OPEN: + case SSH1_SMSG_AGENT_OPEN: + case SSH1_MSG_PORT_OPEN: + { + int i = packet_receiver_->getInt(); + packet_sender_->startPacket(SSH1_MSG_CHANNEL_OPEN_FAILURE); + packet_sender_->putInt(i); + packet_sender_->write(); + } + break; + case SSH1_SMSG_EXIT_STATUS: + packet_sender_->startPacket(SSH1_CMSG_EXIT_CONFIRMATION); + packet_sender_->write(); + closeConnection("end"); + is_closed_ = true; + break; + case SSH1_SMSG_SUCCESS: + case SSH1_SMSG_FAILURE: + break; + default: + FQ_TRACE("sshchannel", 0) << "Unimplemented message: " + << service_state_; + } + } +} + + +//============================================================================== +//FQTermSSH2Channel +//============================================================================== +u_int32_t FQTermSSH2Channel::generateChannelID() { + static u_int32_t id = 0; + return id++; +} + +FQTermSSH2Channel::FQTermSSH2Channel() + : FQTermSSHChannel(), + col_(80), + row_(24), + termtype_("vt100") { + channel_id_ = generateChannelID(); + server_channel_id_ = 0xCCCCCCCC; + local_window_size_ = 0; + channel_state_ = FQTermSSH2Channel::BEGIN_CHANNEL; +} + +void FQTermSSH2Channel::initChannel(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output, + int col, int row, const QString& termtype) { + FQ_FUNC_TRACE("ssh2channel", 5); + col_ = col; + row_ = row; + termtype_ = termtype; + packet_receiver_ = packet; + packet_sender_ = output; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), this, SLOT(handlePacket(int)))); + + // byte SSH_MSG_CHANNEL_OPEN + // string channel type in US-ASCII only + // uint32 sender channel + // uint32 initial window size + // uint32 maximum packet size + // .... channel type specific data follows + + packet_sender_->startPacket(SSH2_MSG_CHANNEL_OPEN); + packet_sender_->putString("session"); + packet_sender_->putInt(channel_id_); + packet_sender_->putInt(MAX_LOCAL_WINDOW_SIZE); // TODO: what's the best window size? + packet_sender_->putInt(MAX_LOCAL_PACKET_SIZE); // TODO: what's the best maximum packet size? + packet_sender_->write(); + + server_window_size_ = 0; + server_max_packet_size_ = 0; + local_window_size_ = MAX_LOCAL_WINDOW_SIZE; + + is_closed_ = false; +} + +void FQTermSSH2Channel::changeTermSize(int col, int row) { + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "window-change" + // boolean FALSE + // uint32 terminal width, columns + // uint32 terminal height, rows + // uint32 terminal width, pixels + // uint32 terminal height, pixels + + packet_sender_->startPacket(SSH2_MSG_CHANNEL_REQUEST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString("window-change"); + packet_sender_->putByte(false); + packet_sender_->putInt(col); + packet_sender_->putInt(row); + packet_sender_->putInt(640); // FIXME: hard-coded screen pixels. + packet_sender_->putInt(480); + packet_sender_->write(); +} + +void FQTermSSH2Channel::sendData(const char *data, int len) { + if (len > (int)server_window_size_ || len > (int)server_max_packet_size_) { + FQ_TRACE("ssh2channel", 3) << "Data length is greater than server's capacity: " + << "data length: " << len << ", " + << "server window: " << server_window_size_ << ", " + << "server packet max size: " << server_max_packet_size_; + return; + } + + // byte SSH_MSG_CHANNEL_DATA + // uint32 recipient channel + // string data + packet_sender_->startPacket(SSH2_MSG_CHANNEL_DATA); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString(data, len); + packet_sender_->write(); + + server_window_size_ -= len;; + + FQ_TRACE("ssh2channel", 5) << len + << " bytes data sent, server window size left: " + << server_window_size_;; +} + +void FQTermSSH2Channel::closeConnection(const char *reason) { + packet_sender_->startPacket(SSH1_MSG_DISCONNECT); + packet_sender_->putString(reason); + packet_sender_->write(); + is_closed_ = true; +} + +void FQTermSSH2Channel::requestPty() { + if (packet_receiver_->packetType() == SSH2_MSG_CHANNEL_OPEN_FAILURE) { + // TODO: Here the error reason in the packet is ignored. + emit channelError(tr("Server refuces to open a channel.")); + return; + } + + if (packet_receiver_->packetType() != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { + emit channelError(tr("Server error when opening a channel.")); + return; + } + + FQ_TRACE("ssh2channel", 5) << "Channel open. Try to request a pty."; + + // byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION + // uint32 recipient channel + // uint32 sender channel + // uint32 initial window size + // uint32 maximum packet size + // .... channel type specific data follows + packet_receiver_->consume(4); + server_channel_id_ = packet_receiver_->getInt(); + server_window_size_ = packet_receiver_->getInt(); + server_max_packet_size_ = packet_receiver_->getInt(); + + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "pty-req" + // boolean want_reply + // string TERM environment variable value (e.g., vt100) + // uint32 terminal width, characters (e.g., 80) + // uint32 terminal height, rows (e.g., 24) + // uint32 terminal width, pixels (e.g., 640) + // uint32 terminal height, pixels (e.g., 480) + // string encoded terminal modes + packet_sender_->startPacket(SSH2_MSG_CHANNEL_REQUEST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString("pty-req"); + packet_sender_->putByte(true); + packet_sender_->putString(termtype_.toLatin1()); // TODO: hardcoded term type. + packet_sender_->putInt(col_); // FIXME: hardcoded screen parameters. + packet_sender_->putInt(row_); + packet_sender_->putInt(640); + packet_sender_->putInt(480); + packet_sender_->putString(""); // TODO: no modes sent. + packet_sender_->write(); +} + + +void FQTermSSH2Channel::requestShell() { + if (packet_receiver_->packetType() != SSH2_MSG_CHANNEL_SUCCESS) { + emit channelError(tr("Server refused pty allocation!")); + } + FQ_TRACE("ssh2channel", 5) << "Pty allocated. Now try to request a shell."; + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "shell" + // boolean want reply + packet_sender_->startPacket(SSH2_MSG_CHANNEL_REQUEST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putString("shell"); + packet_sender_->putByte(true); + packet_sender_->write(); +} + +void FQTermSSH2Channel::checkLocalWindowSize() { + if (local_window_size_ < MAX_LOCAL_WINDOW_SIZE/2) { + // byte SSH_MSG_CHANNEL_WINDOW_ADJUST + // uint32 recipient channel + // uint32 bytes to add + int inc = MAX_LOCAL_WINDOW_SIZE/2; + local_window_size_ += inc; + + packet_sender_->startPacket(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + packet_sender_->putInt(server_channel_id_); + packet_sender_->putInt(inc); + packet_sender_->write(); + } +} + +void FQTermSSH2Channel::processChannelPacket() { + switch (packet_receiver_->packetType()) { + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + { + // byte SSH_MSG_CHANNEL_WINDOW_ADJUST + // uint32 recipient channel + // uint32 bytes to add + packet_receiver_->consume(4); // channel id is already checked. + int inc = packet_receiver_->getInt(); + server_window_size_ += inc; + FQ_TRACE("ssh2channel", 5) << "Server window size increased from " + << server_window_size_ - inc + << " to " << server_window_size_; + } + break; + case SSH2_MSG_CHANNEL_DATA: + { + // byte SSH_MSG_CHANNEL_DATA + // uint32 recipient channel + // string data + packet_receiver_->consume(4); + int len = packet_receiver_->getInt(); + const char *data = (const char *)packet_receiver_->buffer_->data(); + local_window_size_ -= len; + checkLocalWindowSize(); + emit channelReadyRead(data, len); + } + break; + case SSH2_MSG_CHANNEL_EXTENDED_DATA: + { + // byte SSH_MSG_CHANNEL_DATA + // uint32 recipient channel + // string data + packet_receiver_->consume(4); + int len = packet_receiver_->getInt(); + const char *data = (const char *)packet_receiver_->buffer_->data(); + local_window_size_ -= len; + checkLocalWindowSize(); + emit channelReadyRead(data, len); + } + break; + case SSH2_MSG_CHANNEL_EOF: + case SSH2_MSG_CHANNEL_CLOSE: + // byte SSH_MSG_CHANNEL_EOF + // uint32 recipient channel + // FIXME: this error would cause the connection closed, while only the channel need be closed in ssh2. + emit channelError(tr("Channel closed by the server.")); + break; + case SSH2_MSG_CHANNEL_REQUEST: + // byte SSH_MSG_CHANNEL_REQUEST + // uint32 recipient channel + // string "xon-xoff" + // boolean FALSE + // boolean client can do + + // TODO: just ignore this message currently. + break; + } +} + +void FQTermSSH2Channel::handlePacket(int type) { + // first check the channel id. + u_int32_t channel_id = ntohu32(packet_receiver_->buffer_->data()); + if (channel_id != channel_id_) { + return; + } + + switch (channel_state_) { + case FQTermSSH2Channel::BEGIN_CHANNEL: + requestPty(); + channel_state_ = FQTermSSH2Channel::REQUEST_PTY_SENT; + break; + case FQTermSSH2Channel::REQUEST_PTY_SENT: + requestShell(); + channel_state_ = FQTermSSH2Channel::REQUEST_SHELL_SENT; + break; + case FQTermSSH2Channel::REQUEST_SHELL_SENT: + switch (type) { + case SSH2_MSG_CHANNEL_REQUEST: + { + 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()); + packet_receiver_->consume(4 + len); + bool replyNeeded = packet_receiver_->getByte(); + + if (replyNeeded) { + packet_sender_->startPacket(SSH2_MSG_CHANNEL_SUCCESS); + packet_sender_->putInt(server_channel_id_); + packet_sender_->write(); + } + } + break; + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: + { + packet_receiver_->consume(4); + u_int32_t inc = packet_receiver_->getInt(); + server_window_size_ += inc; + } + break; + case SSH2_MSG_CHANNEL_SUCCESS: + emit channelOK(); + channel_state_ = FQTermSSH2Channel::CHANNEL_OK; + //emit a msg to tell window we could process input. + break; + case SSH2_MSG_CHANNEL_FAILURE: + emit channelError(tr("Can't open a shell.")); + break; + default: + emit channelError(tr("Unsupported packet.")); + break; + } + break; + case FQTermSSH2Channel::CHANNEL_OK: + processChannelPacket(); + break; + } +} + +} // namespace FQTerm + +#include "fqterm_ssh_channel.moc" diff --git a/src/protocol/internal/fqterm_ssh_channel.h b/src/protocol/internal/fqterm_ssh_channel.h new file mode 100644 index 0000000..9922528 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_channel.h @@ -0,0 +1,130 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_CHANNEL_H +#define FQTERM_SSH_CHANNEL_H + +#include "fqterm_ssh_types.h" + +#include <QObject> + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSHChannel: public QObject { + Q_OBJECT; +protected: + bool is_closed_; + + FQTermSSHPacketReceiver *packet_receiver_; + FQTermSSHPacketSender *packet_sender_; + +public: + FQTermSSHChannel(){} + virtual ~FQTermSSHChannel(){} + virtual void initChannel(FQTermSSHPacketReceiver *packet, + FQTermSSHPacketSender *output, + int col, int row, const QString& termtype) = 0; + virtual void closeConnection(const char *reason) = 0; + + // TODO: it seems this function isn't used. + virtual void changeTermSize(int col, int row) = 0; + + virtual void sendData(const char *data, int len) = 0; + +public slots: + virtual void handlePacket(int type) = 0; +signals: + void channelOK(); + void channelReadyRead(const char *data, int len); + void channelError(QString); +}; + +class FQTermSSH1Channel: public FQTermSSHChannel { + Q_OBJECT; +private: + enum FQTermSSH1ChannelState { + BEGIN_SERVICE, REQPTY_SENT, + //REQCMD_SENT, + SERVICE_OK + } service_state_; + +public: + FQTermSSH1Channel(); + virtual void initChannel(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output, + int col, int row, const QString& termtype); + virtual void closeConnection(const char *reason); + virtual void changeTermSize(int col, int row); + virtual void sendData(const char *data, int len); + +public slots: + virtual void handlePacket(int type); +signals: + void channelReadyRead(const char *data, int len); +}; + + +class FQTermSSH2Channel: public FQTermSSHChannel { + Q_OBJECT; +private: + static u_int32_t generateChannelID(); + +private: + int col_; + int row_; + QString termtype_; + enum FQTermSSH2ChannelState { + BEGIN_CHANNEL, REQUEST_PTY_SENT, REQUEST_SHELL_SENT, CHANNEL_OK + } channel_state_; + + u_int32_t channel_id_; + + enum {MAX_LOCAL_WINDOW_SIZE = 0x100000, MAX_LOCAL_PACKET_SIZE = 0x4000}; + + u_int32_t local_window_size_; + + u_int32_t server_channel_id_; + u_int32_t server_window_size_; // connection packet window size; + u_int32_t server_max_packet_size_; // max size of each packet sent to server. + + void requestPty(); + void requestShell(); + void processChannelPacket(); + void checkLocalWindowSize(); + +public: + FQTermSSH2Channel(); + virtual void initChannel(FQTermSSHPacketReceiver *packet, FQTermSSHPacketSender *output, + int col, int row, const QString& termtype); + virtual void closeConnection(const char *reason); + virtual void changeTermSize(int col, int row); + virtual void sendData(const char *data, int len); + +public slots: + virtual void handlePacket(int type); +signals: + void channelReadyRead(const char *data, int len); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_CHANNEL_H diff --git a/src/protocol/internal/fqterm_ssh_cipher.h b/src/protocol/internal/fqterm_ssh_cipher.h new file mode 100644 index 0000000..13bc9f3 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_cipher.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_CIPHER_H +#define FQTERM_SSH_CIPHER_H + +#include <stdlib.h> + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_const.h" + +namespace FQTerm { + +class FQTermSSHCipher { +protected: + const char *d_name; + +public: + FQTermSSHCipher() { + d_name = NULL; + } + + virtual ~FQTermSSHCipher(){} + + const char *name() const { + return d_name; + } + + virtual int blockSize() const = 0; + virtual int getKeySize() const = 0; + virtual int getIVSize() const = 0; + + virtual void setIV(const u_char *data) = 0; + virtual void setKey(const u_char *data) = 0; + virtual void encrypt(const u_char *source, u_char *dest, int len) = 0; + virtual void decrypt(const u_char *source, u_char *dest, int len) = 0; +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_CIPHER_H diff --git a/src/protocol/internal/fqterm_ssh_const.h b/src/protocol/internal/fqterm_ssh_const.h new file mode 100644 index 0000000..412760e --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_const.h @@ -0,0 +1,146 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERMCONST_H +#define FQTERMCONST_H + +namespace FQTerm { + +#define SSH_CIPHER_SSH2 -3 +#define SSH_CIPHER_ILLEGAL -2 +#define SSH_CIPHER_NOT_SET -1 +#define SSH_CIPHER_NONE 0 +#define SSH_CIPHER_IDEA 1 +#define SSH_CIPHER_DES 2 +#define SSH_CIPHER_3DES 3 +#define SSH_CIPHER_BROKEN_TSS 4 +#define SSH_CIPHER_BROKEN_RC4 5 +#define SSH_CIPHER_BLOWFISH 6 +#define SSH_CIPHER_RESERVED 7 +#define SSH_CIPHER_MAX 31 + +#define SSH1_MSG_DISCONNECT 1 +#define SSH1_SMSG_PUBLIC_KEY 2 +#define SSH1_CMSG_SESSION_KEY 3 +#define SSH1_CMSG_USER 4 +#define SSH1_CMSG_AUTH_RSA 6 +#define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 +#define SSH1_CMSG_AUTH_RSA_RESPONSE 8 +#define SSH1_CMSG_AUTH_PASSWORD 9 +#define SSH1_CMSG_REQUEST_PTY 10 +#define SSH1_CMSG_WINDOW_SIZE 11 +#define SSH1_CMSG_EXEC_SHELL 12 +#define SSH1_CMSG_EXEC_CMD 13 +#define SSH1_SMSG_SUCCESS 14 +#define SSH1_SMSG_FAILURE 15 +#define SSH1_CMSG_STDIN_DATA 16 +#define SSH1_SMSG_STDOUT_DATA 17 +#define SSH1_SMSG_STDERR_DATA 18 +#define SSH1_CMSG_EOF 19 +#define SSH1_SMSG_EXIT_STATUS 20 +#define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 +#define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 +#define SSH1_MSG_CHANNEL_DATA 23 +#define SSH1_MSG_CHANNEL_CLOSE 24 +#define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 +#define SSH1_SMSG_X11_OPEN 27 +#define SSH1_CMSG_PORT_FORWARD_REQUEST 28 +#define SSH1_MSG_PORT_OPEN 29 +#define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 +#define SSH1_SMSG_AGENT_OPEN 31 +#define SSH1_MSG_IGNORE 32 +#define SSH1_CMSG_EXIT_CONFIRMATION 33 +#define SSH1_CMSG_X11_REQUEST_FORWARDING 34 +#define SSH1_CMSG_AUTH_RHOSTS_RSA 35 +#define SSH1_MSG_DEBUG 36 +#define SSH1_CMSG_REQUEST_COMPRESSION 37 +#define SSH1_CMSG_AUTH_TIS 39 +#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 +#define SSH1_CMSG_AUTH_TIS_RESPONSE 41 +#define SSH1_CMSG_AUTH_CCARD 70 +#define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 +#define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 +#define SSH1_AUTH_TIS 5 +#define SSH1_PROTOFLAG_SCREEN_NUMBER 1 +#define SSH1_PROTOFLAGS_SUPPORTED 0 + + +#define SSH2_MSG_DISCONNECT 1 +#define SSH2_MSG_IGNORE 2 +#define SSH2_MSG_UNIMPLEMENTED 3 +#define SSH2_MSG_DEBUG 4 +#define SSH2_MSG_SERVICE_REQUEST 5 +#define SSH2_MSG_SERVICE_ACCEPT 6 +#define SSH2_MSG_KEXINIT 20 +#define SSH2_MSG_NEWKEYS 21 +#define SSH2_MSG_KEXDH_INIT 30 +#define SSH2_MSG_KEXDH_REPLY 31 +#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30 +#define SSH2_MSG_KEX_DH_GEX_GROUP 31 +#define SSH2_MSG_KEX_DH_GEX_INIT 32 +#define SSH2_MSG_KEX_DH_GEX_REPLY 33 +#define SSH2_MSG_KEX_DH_GEX_REQUEST 34 +#define SSH2_MSG_USERAUTH_REQUEST 50 +#define SSH2_MSG_USERAUTH_FAILURE 51 +#define SSH2_MSG_USERAUTH_SUCCESS 52 +#define SSH2_MSG_USERAUTH_BANNER 53 +#define SSH2_MSG_USERAUTH_PK_OK 60 +#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 +#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 +#define SSH2_MSG_GLOBAL_REQUEST 80 +#define SSH2_MSG_REQUEST_SUCCESS 81 +#define SSH2_MSG_REQUEST_FAILURE 82 +#define SSH2_MSG_CHANNEL_OPEN 90 +#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 +#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 +#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 +#define SSH2_MSG_CHANNEL_DATA 94 +#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 +#define SSH2_MSG_CHANNEL_EOF 96 +#define SSH2_MSG_CHANNEL_CLOSE 97 +#define SSH2_MSG_CHANNEL_REQUEST 98 +#define SSH2_MSG_CHANNEL_SUCCESS 99 +#define SSH2_MSG_CHANNEL_FAILURE 100 +#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 +#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 +#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 +#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 +#define SSH2_DISCONNECT_RESERVED 4 +#define SSH2_DISCONNECT_MAC_ERROR 5 +#define SSH2_DISCONNECT_COMPRESSION_ERROR 6 +#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 +#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 +#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 +#define SSH2_DISCONNECT_CONNECTION_LOST 10 +#define SSH2_DISCONNECT_BY_APPLICATION 11 +#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 +#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 +#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 +#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 +#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 +#define SSH2_OPEN_CONNECT_FAILED 2 +#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 +#define SSH2_OPEN_RESOURCE_SHORTAGE 4 +#define SSH2_EXTENDED_DATA_STDERR 1 + +} // namespace FQTerm + +#endif // FQTERMCONST_H diff --git a/src/protocol/internal/fqterm_ssh_des.cpp b/src/protocol/internal/fqterm_ssh_des.cpp new file mode 100644 index 0000000..603b6fe --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_des.cpp @@ -0,0 +1,180 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include <memory.h> +#include <openssl/des.h> +#include <openssl/objects.h> +#include <openssl/evp.h> + +#include "fqterm_ssh_const.h" +#include "fqterm_ssh_des.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +//============================================================================== +//FQTermSSH1DES3 +//============================================================================== + +FQTermSSH1DES3::FQTermSSH1DES3() { + d_name = "des3-cbc"; + + memset(d_IV1, 0, sizeof(d_IV1)); + memset(d_IV2, 0, sizeof(d_IV2)); + memset(d_IV3, 0, sizeof(d_IV3)); +} + +int FQTermSSH1DES3::blockSize() const { + return 8; +} + +void FQTermSSH1DES3::decrypt(const u_char *source, u_char *dest, int len) { + DES_ncbc_encrypt(source, dest, len, &d_key3, &d_IV3, DES_DECRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key2, &d_IV2, DES_ENCRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key1, &d_IV1, DES_DECRYPT); +} + +void FQTermSSH1DES3::encrypt(const u_char *source, u_char *dest, int len) { + DES_ncbc_encrypt(source, dest, len, &d_key1, &d_IV1, DES_ENCRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key2, &d_IV2, DES_DECRYPT); + DES_ncbc_encrypt(dest, dest, len, &d_key3, &d_IV3, DES_ENCRYPT); +} + +int FQTermSSH1DES3::getKeySize() const { + return 3*DES_KEY_SZ; +} + +int FQTermSSH1DES3::getIVSize() const { + return 0; +} + +void FQTermSSH1DES3::setIV(const u_char *data) { + memset(d_IV1, 0, sizeof(d_IV1)); + memset(d_IV2, 0, sizeof(d_IV2)); + memset(d_IV3, 0, sizeof(d_IV3)); +} + +void FQTermSSH1DES3::setKey(const u_char *data) { + DES_cblock key; + memset(key, 0, sizeof(key)); + memcpy(key, data, sizeof(key)); + DES_set_key(&key, &d_key1); + data += 8; + memset(key, 0, sizeof(key)); + memcpy(key, data, sizeof(key)); + DES_set_key(&key, &d_key2); + data += 8; + memset(key, 0, sizeof(key)); + memcpy(key, data, sizeof(key)); + DES_set_key(&key, &d_key3); +} + + +//================================================== +// TripleDES-CBC +//================================================== + +FQTermSSH2TripleDESCBC::FQTermSSH2TripleDESCBC() { + d_name = "des3-cbc"; + ctx_ = NULL; +} + +FQTermSSH2TripleDESCBC::~FQTermSSH2TripleDESCBC() { + if (ctx_ != NULL) { + EVP_CIPHER_CTX_cleanup(ctx_); + delete ctx_; + } +} + + +int FQTermSSH2TripleDESCBC::blockSize() const { + return 8; +} + +int FQTermSSH2TripleDESCBC::getKeySize() const { + return 24; +} + +int FQTermSSH2TripleDESCBC::getIVSize() const { + return 8; +} + +void FQTermSSH2TripleDESCBC::setIV(const u_char *data) { + memcpy(IV_, data, getIVSize()); +} + +void FQTermSSH2TripleDESCBC::setKey(const u_char *data) { + memcpy(key_, data, getKeySize()); +} + +void FQTermSSH2TripleDESCBC::encrypt(const u_char *source, u_char *dest, int len) { + FQ_TRACE("3DES_CBC", 9) << "Start encrypting"; + FQ_TRACE("3DES_CBC", 9) << "data len:" << len; + FQ_TRACE("3DES_CBC", 9) << "Source: \n" << dumpHexString << std::string((char *)source, len); + + int ret = 0; + if (ctx_ == NULL) { + // Lazy initialization. + ctx_ = new EVP_CIPHER_CTX; + EVP_CIPHER_CTX_init(ctx_); + ret = EVP_CipherInit(ctx_, EVP_des_ede3_cbc(), key_, IV_, 1); + FQ_VERIFY(ret == 1); + } + + ret = EVP_Cipher(ctx_, dest, source, len); + + FQ_VERIFY(ret == 1); + + FQ_TRACE("3DES_CBC", 9) << "Dest: \n" << dumpHexString << std::string((char *)dest, len); + + FQ_TRACE("3DES_CBC", 9) << "IV:\n" << dumpHexString << std::string((char *)IV_, getIVSize()); + FQ_TRACE("3DES_CBC", 9) << "key:\n" << dumpHexString << std::string((char *)key_, getKeySize()); + +} + +void FQTermSSH2TripleDESCBC::decrypt(const u_char *source, u_char *dest, int len) { + FQ_TRACE("3DES_CBC", 9) << "Start dencrypting"; + FQ_TRACE("3DES_CBC", 9) << "data len:" << len; + FQ_TRACE("3DES_CBC", 9) << "Source: \n" << dumpHexString << std::string((char *)source, len); + + int ret = 0; + if (ctx_ == NULL) { + // Lazy initialization. + ctx_ = new EVP_CIPHER_CTX; + EVP_CIPHER_CTX_init(ctx_); + ret = EVP_CipherInit(ctx_, EVP_des_ede3_cbc(), key_, IV_, 0); + FQ_VERIFY(ret == 1); + } + + ret = EVP_Cipher(ctx_, dest, source, len); + + FQ_VERIFY(ret == 1); + + FQ_TRACE("3DES_CBC", 9) << "Dest: \n" << dumpHexString << std::string((char *)dest, len); + + FQ_TRACE("3DES_CBC", 9) << "IV:\n" << dumpHexString << std::string((char *)IV_, getIVSize()); + FQ_TRACE("3DES_CBC", 9) << "key:\n" << dumpHexString << std::string((char *)key_, getKeySize()); +} + + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_des.h b/src/protocol/internal/fqterm_ssh_des.h new file mode 100644 index 0000000..ba153f2 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_des.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_DES_H +#define FQTERM_SSH_DES_H + +#include <openssl/ssl.h> +#include <openssl/des.h> + +#include "fqterm_ssh_cipher.h" +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +class FQTermSSH1DES3: public FQTermSSHCipher { + private: + DES_cblock d_IV1; + DES_cblock d_IV2; + DES_cblock d_IV3; + DES_key_schedule d_key1; + DES_key_schedule d_key2; + DES_key_schedule d_key3; + public: + FQTermSSH1DES3(); + + virtual int blockSize() const; + virtual int getKeySize() const; + virtual int getIVSize() const; + virtual void setIV(const u_char *data); + virtual void setKey(const u_char *data); + virtual void encrypt(const u_char *source, u_char *dest, int len); + virtual void decrypt(const u_char *source, u_char *dest, int len); +}; + +class FQTermSSH2TripleDESCBC: public FQTermSSHCipher { + private: + unsigned char IV_[8]; + unsigned char key_[24]; + + EVP_CIPHER_CTX *ctx_; + + public: + FQTermSSH2TripleDESCBC(); + ~FQTermSSH2TripleDESCBC(); + + virtual int blockSize() const; + virtual int getKeySize() const; + virtual int getIVSize() const; + virtual void setIV(const u_char *data); + virtual void setKey(const u_char *data); + virtual void encrypt(const u_char *source, u_char *dest, int len); + virtual void decrypt(const u_char *source, u_char *dest, int len); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_DES_H diff --git a/src/protocol/internal/fqterm_ssh_hash.h b/src/protocol/internal/fqterm_ssh_hash.h new file mode 100644 index 0000000..b4679f4 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_hash.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_HASH_H +#define FQTERM_SSH_HASH_H + +#include "fqterm_ssh_types.h" + +namespace FQTerm { + +class FQTermSSHHash { +protected: + int d_digestLength; + int digestLength()const { + return d_digestLength; + } + +public: + FQTermSSHHash() { + d_digestLength = 0; + } + virtual ~FQTermSSHHash() {} + + virtual void update(u_char *data, int len) = 0; + virtual void final(u_char *data) = 0; +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_HASH_H diff --git a/src/protocol/internal/fqterm_ssh_kex.cpp b/src/protocol/internal/fqterm_ssh_kex.cpp new file mode 100644 index 0000000..d27bf14 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_kex.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_kex.h" +#include "fqterm_ssh_md5.h" +#include "fqterm_trace.h" + +namespace FQTerm { + +FQTermSSHKex::FQTermSSHKex(const char *V_C, const char *V_S) { + V_C_ = new char[strlen(V_C) + 1]; + V_S_ = new char[strlen(V_S) + 1]; + + strcpy(V_C_, V_C); + strcpy(V_S_, V_S); +} + +FQTermSSHKex::~FQTermSSHKex() { + delete[] V_C_; + delete[] V_S_; +} + + +//============================================================================== +//FQTermSSH1Kex +//============================================================================== + +FQTermSSH1Kex::FQTermSSH1Kex(const char *V_C, const char *V_S) + : FQTermSSHKex(V_C, V_S) { + is_first_kex_ = true; + kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY; +} + +FQTermSSH1Kex::~FQTermSSH1Kex(){} + +void FQTermSSH1Kex::initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *packetSender) { + packet_receiver_ = packetReceiver; + packet_sender_ = packetSender; + packet_receiver_->disconnect(this); + FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)), + this, SLOT(handlePacket(int)))); + kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY; + emit reKex(); +} + +void FQTermSSH1Kex::handlePacket(int type) { + switch (kex_state_) { + case FQTermSSH1Kex::BEFORE_PUBLICKEY: + makeSessionKey(); + kex_state_ = FQTermSSH1Kex::SESSIONKEY_SENT; + break; + case FQTermSSH1Kex::SESSIONKEY_SENT: + if (type != SSH1_SMSG_SUCCESS) { + emit kexError(tr("Kex exchange failed!")); + break; + } + emit kexOK(); + kex_state_ = FQTermSSH1Kex::KEYEX_OK; + break; + case FQTermSSH1Kex::KEYEX_OK: + break; + } +} + +void FQTermSSH1Kex::makeSessionKey() { + int i; + BIGNUM *key; + u_int32_t rand_val; + int bits; + int rbits; + + if (packet_receiver_->packetType() != SSH1_SMSG_PUBLIC_KEY) { + emit kexError(tr("startKex: First packet is not public key")); + return ; + } + packet_receiver_->getRawData((char*)cookie_, 8); + + // Get the public key. + server_key_ = new FQTermSSHRSA; + bits = packet_receiver_->getInt(); + packet_receiver_->getBN(server_key_->d_rsa->e); + packet_receiver_->getBN(server_key_->d_rsa->n); + + rbits = BN_num_bits(server_key_->d_rsa->n); + if (bits != rbits) { + FQ_TRACE("sshkex", 0) << "Warning: Server lies about " + << "size of server public key: " + << "actual size: " << rbits + << " vs. anounced: " << bits; + FQ_TRACE("sshkex", 0) << "Warning: This may be due to " + << "an old implementation of ssh."; + } + + // Get the host key. + host_key_ = new FQTermSSHRSA; + bits = packet_receiver_->getInt(); + packet_receiver_->getBN(host_key_->d_rsa->e); + packet_receiver_->getBN(host_key_->d_rsa->n); + + rbits = BN_num_bits(host_key_->d_rsa->n); + if (bits != rbits) { + FQ_TRACE("sshkex", 0) << "Warning: Server lies about " + << "size of server public key: " + << "actual size: " << rbits + << " vs. anounced: " << bits; + FQ_TRACE("sshkex", 0) << "Warning: This may be due to " + << "an old implementation of ssh."; + } + + // Get protocol flags. + server_flag_ = packet_receiver_->getInt(); + ciphers_ = packet_receiver_->getInt(); + auth_ = packet_receiver_->getInt(); + + if ((ciphers_ &(1 << SSH_CIPHER_3DES)) == 0) { + FQ_VERIFY(false); // server do not support my cipher + } + + makeSessionId(); + + // Generate an encryption key for the session. The key is a 256 bit + // random number, interpreted as a 32-byte key, with the least + // significant 8 bits being the first byte of the key. + + for (i = 0; i < 32; i++) { + if (i % 4 == 0) { + rand_val = rand(); + } + + session_key_[i] = (rand_val &0xff); + rand_val >>= 8; + } + + key = BN_new(); + + BN_set_word(key, 0); + for (i = 0; i < 32; i++) { + BN_lshift(key, key, 8); + if (i < 16) { + BN_add_word(key, session_key_[i] ^ session_id_[i]); + } else { + BN_add_word(key, session_key_[i]); + } + } + + if (BN_cmp(server_key_->d_rsa->n, host_key_->d_rsa->n) < 0) { + server_key_->publicEncrypt(key, key); + host_key_->publicEncrypt(key, key); + } else { + host_key_->publicEncrypt(key, key); + server_key_->publicEncrypt(key, key); + } + + delete host_key_; + delete server_key_; + + packet_sender_->startPacket(SSH1_CMSG_SESSION_KEY); + packet_sender_->putByte(SSH_CIPHER_3DES); + packet_sender_->putRawData((const char*)cookie_, 8); + packet_sender_->putBN(key); + + BN_free(key); + + packet_sender_->putInt(1); + packet_sender_->write(); + + emit startEncryption(session_key_); +} + +void FQTermSSH1Kex::makeSessionId() { + u_char *p; + FQTermSSHMD5 *md5; + int servlen, hostlen; + + md5 = new FQTermSSHMD5; + servlen = BN_num_bytes(server_key_->d_rsa->n); + hostlen = BN_num_bytes(host_key_->d_rsa->n); + + p = new u_char[servlen + hostlen]; + + BN_bn2bin(host_key_->d_rsa->n, p); + BN_bn2bin(server_key_->d_rsa->n, p + hostlen); + md5->update(p, servlen + hostlen); + md5->update(cookie_, 8); + md5->final(session_id_); + delete md5; + delete [] p; +} + +} // namespace FQTerm + +#include "fqterm_ssh_kex.moc" diff --git a/src/protocol/internal/fqterm_ssh_kex.h b/src/protocol/internal/fqterm_ssh_kex.h new file mode 100644 index 0000000..b2f9c56 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_kex.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_KEX_H +#define FQTERM_SSH_KEX_H + +#include <openssl/bn.h> +#include <QObject> + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_rsa.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh_const.h" + +namespace FQTerm { + +class FQTermSSHPacketReceiver; +class FQTermSSHPacketSender; + +class FQTermSSHKex: public QObject { + Q_OBJECT; +protected: + FQTermSSHPacketReceiver *packet_receiver_; + FQTermSSHPacketSender *packet_sender_; + + char *V_C_; + char *V_S_; +public: + // Init with + // string V_C, the client's identification string (CR and LF + // excluded) + // string V_S, the server's identification string (CR and LF + // excluded) + FQTermSSHKex(const char *V_C, const char *V_S); + virtual ~FQTermSSHKex(); + + virtual void initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *outputSender) = 0; + +public slots: + virtual void handlePacket(int type) = 0; + +signals: + void kexOK(); + void reKex(); + void kexError(QString); + + void startEncryption(const u_char *sessionkey); + +}; + +class FQTermSSH1Kex: public FQTermSSHKex { + Q_OBJECT; +private: + enum FQTermSSH1KexState { + BEFORE_PUBLICKEY, SESSIONKEY_SENT, KEYEX_OK + } kex_state_; + + bool is_first_kex_; + + FQTermSSHRSA *host_key_; + FQTermSSHRSA *server_key_; + + u_char cookie_[8]; + int server_flag_, ciphers_, auth_; + u_char session_id_[16]; + u_char session_key_[32]; + + void makeSessionId(); + void makeSessionKey(); + +public: + FQTermSSH1Kex(const char *V_C, const char *V_S); + ~FQTermSSH1Kex(); + virtual void initKex(FQTermSSHPacketReceiver *packetReceiver, + FQTermSSHPacketSender *outputSender); + + virtual void handlePacket(int type); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_KEX_H diff --git a/src/protocol/internal/fqterm_ssh_mac.cpp b/src/protocol/internal/fqterm_ssh_mac.cpp new file mode 100644 index 0000000..e2d345f --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_mac.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include <openssl/evp.h> +#include <openssl/hmac.h> + +#include "fqterm_trace.h" +#include "fqterm_ssh_mac.h" +#include "fqterm_ssh_packet.h" + +namespace FQTerm { + +void FQTermSSHSHA1::setKey(const unsigned char *key) { + memcpy(key_, key, keySize()); +} + +int FQTermSSHSHA1::keySize() const { + return SHA_DIGEST_LENGTH; +} + +int FQTermSSHSHA1::digestSize() const { + return SHA_DIGEST_LENGTH; +} + +void FQTermSSHSHA1::getDigest(const unsigned char *data, int len, unsigned char *digest) const { + unsigned int tmp; + HMAC(EVP_sha1(), key_, SHA_DIGEST_LENGTH, data, len, digest, &tmp); + + FQ_TRACE("SHA1", 9) << "Key: \n" << dumpHexString << std::string((char *)key_, SHA_DIGEST_LENGTH); + FQ_TRACE("SHA1", 9) << "data len:" << len; + FQ_TRACE("SHA1", 9) << "data:\n" << dumpHexString << std::string((char *)data, len); + FQ_TRACE("SHA1", 9) << "digest len:" << tmp; + FQ_TRACE("SHA1", 9) << "digest:\n" << dumpHexString << std::string((char *)digest, tmp); +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_mac.h b/src/protocol/internal/fqterm_ssh_mac.h new file mode 100644 index 0000000..545909c --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_mac.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_MAC_H +#define FQTERM_SSH_MAC_H + +#include <openssl/sha.h> + +namespace FQTerm { + +class FQTermSSHMac { +public: + FQTermSSHMac() {} + virtual ~FQTermSSHMac() {} + virtual void setKey(const unsigned char *key) = 0; + virtual int keySize() const = 0; + virtual int digestSize() const = 0; + virtual void getDigest(const unsigned char *data, int len, unsigned char *digest) const = 0; +}; + +const int FQTERM_SSH_MAC_NONE = 0; +const int FQTERM_SSH_HMAC_SHA1 = 1; + +class FQTermSSHSHA1: public FQTermSSHMac { + unsigned char key_[SHA_DIGEST_LENGTH]; + +public: + virtual void setKey(const unsigned char *key); + virtual int keySize() const; + virtual int digestSize() const; + virtual void getDigest(const unsigned char *data, int len, unsigned char *digest) const; +}; + + +} // namespace FQTerm + +#endif // FQTERM_SSH_MAC_H diff --git a/src/protocol/internal/fqterm_ssh_md5.cpp b/src/protocol/internal/fqterm_ssh_md5.cpp new file mode 100644 index 0000000..10713e9 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_md5.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_ssh_md5.h" + +namespace FQTerm { + +//============================================================================== +//FQTermSSHMD5 +//============================================================================== +void FQTermSSHMD5::final(u_char *digest) { + MD5_Final(digest, &d_md5); +} + +void FQTermSSHMD5::update(u_char *data, int len) { + MD5_Update(&d_md5, data, len); +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_md5.h b/src/protocol/internal/fqterm_ssh_md5.h new file mode 100644 index 0000000..abb8127 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_md5.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_MD5_H +#define FQTERM_SSH_MD5_H + +#include <stdio.h> + +#include <openssl/md5.h> + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_hash.h" + +namespace FQTerm { + +class FQTermSSHMD5: public FQTermSSHHash { +protected: + MD5_CTX d_md5; +public: + FQTermSSHMD5() + : FQTermSSHHash() { + d_digestLength = 16; + MD5_Init(&d_md5); + } + virtual ~FQTermSSHMD5() {} + + void update(u_char *data, int len); + void final(u_char *digest); +}; + +} // namespace FQTerm + +#endif //FQTERM_SSH_MD5_H diff --git a/src/protocol/internal/fqterm_ssh_packet.cpp b/src/protocol/internal/fqterm_ssh_packet.cpp new file mode 100644 index 0000000..9c4ff6c --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_packet.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm_trace.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh_packet.h" +#include "fqterm_ssh_des.h" + +#include "fqterm_serialization.h" +#include "crc32.h" + +namespace FQTerm { + +//============================================================================== +//FQTermSSHPacketSender +//============================================================================== + +FQTermSSHPacketSender::FQTermSSHPacketSender() { + buffer_ = new FQTermSSHBuffer(1024); + output_buffer_ = new FQTermSSHBuffer(1024); + + is_encrypt_ = false; + cipher_type_ = SSH_CIPHER_NONE; + cipher_ = NULL; + setEncryptionType(SSH_CIPHER_3DES); + + is_mac_ = false; + mac_type_ = FQTERM_SSH_MAC_NONE; + mac_ = NULL; + + is_compressed_ = false; + + sequence_no_ = 0; +} + +FQTermSSHPacketSender::~FQTermSSHPacketSender() { + delete buffer_; + delete output_buffer_; + if (is_encrypt_) { + delete cipher_; + } +} + +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::putBN(BIGNUM *bn) { + buffer_->putSSH1BN(bn); +} + +void FQTermSSHPacketSender::putBN2(BIGNUM *bn) { + buffer_->putSSH2BN(bn); +} + +void FQTermSSHPacketSender::startPacket(int pkt_type) { + buffer_->clear(); + buffer_->putByte(pkt_type); +} + +void FQTermSSHPacketSender::write() { + makePacket(); + emit dataToWrite(); +} + +void FQTermSSHPacketSender::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH1DES3; + break; + } +} + +void FQTermSSHPacketSender::startEncryption(const u_char *key, const u_char *IV) { + is_encrypt_ = true; + cipher_->setIV(IV); + cipher_->setKey(key); +} + +void FQTermSSHPacketSender::resetEncryption() { + is_encrypt_ = false; +} + +void FQTermSSHPacketSender::setMacType(int macType) { + mac_type_ = macType; + + delete mac_; + mac_ = NULL; + + switch (mac_type_) { + case FQTERM_SSH_HMAC_SHA1: + mac_ = new FQTermSSHSHA1; + break; + } +} + +void FQTermSSHPacketSender::startMac(const u_char *key) { + is_mac_ = true; + mac_->setKey(key); +} + +void FQTermSSHPacketSender::resetMac() { + is_mac_ = false; +} + +//============================================================================== +//FQTermSSHPacketReceiver +//============================================================================== + +FQTermSSHPacketReceiver::FQTermSSHPacketReceiver() { + buffer_ = new FQTermSSHBuffer(1024); + + is_decrypt_ = false; + cipher_type_ = SSH_CIPHER_NONE; + cipher_ = NULL; + setEncryptionType(SSH_CIPHER_3DES); + + is_mac_ = false; + mac_type_ = FQTERM_SSH_MAC_NONE; + mac_ = NULL; + + is_compressed_ = false; + + sequence_no_ = 0; +} + +FQTermSSHPacketReceiver::~FQTermSSHPacketReceiver() { + delete buffer_; + if (is_decrypt_) { + delete cipher_; + } +} + +void FQTermSSHPacketReceiver::getRawData(char *data, int length) { + buffer_->getRawData(data, length); +} + +u_char FQTermSSHPacketReceiver::getByte() { + return buffer_->getByte(); +} + +u_int FQTermSSHPacketReceiver::getInt() { + return buffer_->getInt(); +} + +void *FQTermSSHPacketReceiver::getString(int *length) { + return buffer_->getString(length); +} + +void FQTermSSHPacketReceiver::getBN(BIGNUM *bignum) { + buffer_->getSSH1BN(bignum); +} + +void FQTermSSHPacketReceiver::getBN2(BIGNUM *bignum) { + buffer_->getSSH2BN(bignum); +} + +void FQTermSSHPacketReceiver::consume(int len) { + buffer_->consume(len); +} + +void FQTermSSHPacketReceiver::setEncryptionType(int cipherType) { + cipher_type_ = cipherType; + + delete cipher_; + cipher_ = NULL; + + switch (cipher_type_) { + case SSH_CIPHER_3DES: + cipher_ = new FQTermSSH1DES3; + break; + } +} + +void FQTermSSHPacketReceiver::startEncryption(const u_char *key, const u_char *IV) { + is_decrypt_ = true; + cipher_->setIV(IV); + cipher_->setKey(key); +} + +void FQTermSSHPacketReceiver::resetEncryption() { + is_decrypt_ = false; +} + +void FQTermSSHPacketReceiver::setMacType(int macType) { + mac_type_ = macType; + delete mac_; + mac_ = NULL; + + switch (mac_type_) { + case FQTERM_SSH_HMAC_SHA1: + mac_ = new FQTermSSHSHA1; + break; + } +} + +void FQTermSSHPacketReceiver::startMac(const u_char *key) { + is_mac_ = true; + mac_->setKey(key); +} + +void FQTermSSHPacketReceiver::resetMac() { + is_mac_ = false; +} + +} // namespace FQTerm + +#include "fqterm_ssh_packet.moc" diff --git a/src/protocol/internal/fqterm_ssh_packet.h b/src/protocol/internal/fqterm_ssh_packet.h new file mode 100644 index 0000000..ed5a488 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_packet.h @@ -0,0 +1,148 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_PACKET_H +#define FQTERM_SSH_PACKET_H + +#include <openssl/bn.h> + +#include <QObject> + +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_buffer.h" +#include "fqterm_ssh_mac.h" +#include "fqterm_ssh_cipher.h" +#include "fqterm_serialization.h" + +namespace FQTerm { + +class FQTermSSHPacketSender: public QObject { + Q_OBJECT; + public: + FQTermSSHBuffer *output_buffer_; + FQTermSSHBuffer *buffer_; + + FQTermSSHPacketSender(); + virtual ~FQTermSSHPacketSender(); + + void startPacket(int pkt_type); + void putByte(int data); + void putInt(u_int data); + void putString(const char *string, int len = -1); + void putRawData(const char *data, int length); + void putBN(BIGNUM *bignum); + void putBN2(BIGNUM *bignum); + void write(); + + int getIVSize() const { return cipher_->getIVSize();} + int getKeySize() const { return cipher_->getKeySize();} + int getMacKeySize() const { return mac_->keySize();} + + public slots: + virtual void setEncryptionType(int cipherType); + void startEncryption(const u_char *key, const u_char *IV = NULL); + void resetEncryption(); + + void setMacType(int macType); + void startMac(const u_char *sessionkey); + void resetMac(); + + void enableCompress(int enable) {is_compressed_ = enable;}; + + signals: + void dataToWrite(); + + protected: + bool is_encrypt_; + int cipher_type_; + FQTermSSHCipher *cipher_; + + bool is_mac_; + int mac_type_; + FQTermSSHMac *mac_; + + bool is_compressed_; + + u_int32_t sequence_no_; + + virtual void makePacket() = 0; +}; + +class FQTermSSHPacketReceiver: public QObject { + Q_OBJECT; + public: + FQTermSSHBuffer *buffer_; + + FQTermSSHPacketReceiver(); + virtual ~FQTermSSHPacketReceiver(); + + int packetType()const { + return packet_type_; + } + + u_char getByte(); + u_int getInt(); + void *getString(int *length = NULL); + void getRawData(char *data, int length); + void getBN(BIGNUM *bignum); + void getBN2(BIGNUM *bignum); + void consume(int len); + + virtual int packetDataLen() const { return real_data_len_;} + int getIVSize() const { return cipher_->getIVSize();} + int getKeySize() const { return cipher_->getKeySize();} + int getMacKeySize() const { return mac_->keySize();} + + virtual void parseData(FQTermSSHBuffer *input) = 0; + public slots: + virtual void setEncryptionType(int cipherType); + void startEncryption(const u_char *key, const u_char *IV = NULL); + void resetEncryption(); + + void setMacType(int macType); + void startMac(const u_char *sessionkey); + void resetMac(); + + void enableCompress(int enable) {is_compressed_ = enable;}; + + signals: + void packetAvaliable(int type); + void packetError(QString); + + protected: + bool is_decrypt_; + int cipher_type_; + FQTermSSHCipher *cipher_; + + bool is_mac_; + int mac_type_; + FQTermSSHMac *mac_; + + bool is_compressed_; + + int packet_type_; + int real_data_len_; + + u_int32_t sequence_no_; +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_PACKET diff --git a/src/protocol/internal/fqterm_ssh_pubkey.h b/src/protocol/internal/fqterm_ssh_pubkey.h new file mode 100644 index 0000000..0de957c --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_pubkey.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_PUB_KEY_H +#define FQTERM_SSH_PUB_KEY_H + +#include <openssl/bn.h> + +namespace FQTerm { + +class FQTermSSHPubKey { +public: + FQTermSSHPubKey() {} + virtual ~FQTermSSHPubKey() {} + virtual void publicEncrypt(BIGNUM *, BIGNUM*) = 0; +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_PUB_KEY_H diff --git a/src/protocol/internal/fqterm_ssh_rsa.cpp b/src/protocol/internal/fqterm_ssh_rsa.cpp new file mode 100644 index 0000000..dd36898 --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_rsa.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include <QGlobalStatic> + +#include "fqterm_trace.h" +#include "fqterm_ssh_types.h" +#include "fqterm_ssh_rsa.h" + +namespace FQTerm { + +FQTermSSHRSA::FQTermSSHRSA() { + d_rsa = RSA_new(); + d_rsa->n = BN_new(); + d_rsa->e = BN_new(); +} + +FQTermSSHRSA::~FQTermSSHRSA() { + if (d_rsa != NULL) { + RSA_free(d_rsa); + } +} + +void FQTermSSHRSA::publicEncrypt(BIGNUM *out, BIGNUM *in) { + u_char *inbuf, *outbuf; + int len, ilen, olen; + + if (BN_num_bits(d_rsa->e) < 2 || !BN_is_odd(d_rsa->e)) { + FQ_VERIFY(false); // public_encrypt() exponent too small or not odd. + } + + olen = BN_num_bytes(d_rsa->n); + outbuf = new u_char[olen]; + + ilen = BN_num_bytes(in); + inbuf = new u_char[ilen]; + BN_bn2bin(in, inbuf); + + if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, d_rsa, RSA_PKCS1_PADDING)) <= 0) { + //RSA_PKCS1_PADDING = 1 + FQ_VERIFY(false); // "rsa_public_encrypt() failed. + } + + BN_bin2bn(outbuf, len, out); + + delete [] outbuf; + delete [] inbuf; +} + +} // namespace FQTerm diff --git a/src/protocol/internal/fqterm_ssh_rsa.h b/src/protocol/internal/fqterm_ssh_rsa.h new file mode 100644 index 0000000..bfe89ce --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_rsa.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_RSA_H +#define FQTERM_SSH_RSA_H + +#include <openssl/rsa.h> + +#include "fqterm_ssh_pubkey.h" + +namespace FQTerm { + +class FQTermSSHRSA: public FQTermSSHPubKey { +public: + RSA *d_rsa; + FQTermSSHRSA(); + virtual ~FQTermSSHRSA(); + + virtual void publicEncrypt(BIGNUM *, BIGNUM*); +}; + +} // namespace FQTerm + +#endif // FQTERM_SSH_RSA_H diff --git a/src/protocol/internal/fqterm_ssh_types.h b/src/protocol/internal/fqterm_ssh_types.h new file mode 100644 index 0000000..c10bfac --- /dev/null +++ b/src/protocol/internal/fqterm_ssh_types.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef FQTERM_SSH_TYPES_H +#define FQTERM_SSH_TYPES_H + +#include <QGlobalStatic> +#if !defined(Q_OS_WIN32) && !defined(_OS_WIN32_) +#include <sys/types.h> +#else +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +#ifdef QT3_SUPPORT +typedef Q_UINT32 u_int32_t; +typedef Q_UINT64 u_int64_t; +#else +typedef quint32 u_int32_t; +typedef quint64 u_int64_t; +#endif // QT3_SUPPORT + +#endif // Q_OS_WIN32 + +#endif // FQTERM_SSH_TYPES_H |