diff options
Diffstat (limited to 'src/protocol/internal/fqterm_ssh2_kex.cpp')
-rw-r--r-- | src/protocol/internal/fqterm_ssh2_kex.cpp | 128 |
1 files changed, 46 insertions, 82 deletions
diff --git a/src/protocol/internal/fqterm_ssh2_kex.cpp b/src/protocol/internal/fqterm_ssh2_kex.cpp index f51f459..8566e92 100644 --- a/src/protocol/internal/fqterm_ssh2_kex.cpp +++ b/src/protocol/internal/fqterm_ssh2_kex.cpp @@ -44,14 +44,7 @@ FQTermSSH2Kex::FQTermSSH2Kex(const char *V_C, const char *V_S) I_S_ = NULL; K_S_ = NULL; - bn_x_ = BN_new(); - bn_e_ = BN_new(); - ctx_ = BN_CTX_new(); - - bn_K_ = BN_new(); - bn_f_ = BN_new(); - - session_id_ = NULL; + sess.session_id = NULL; } FQTermSSH2Kex::~FQTermSSH2Kex() { @@ -60,14 +53,8 @@ FQTermSSH2Kex::~FQTermSSH2Kex() { if (K_S_) delete [] K_S_; - BN_clear_free(bn_x_); - BN_clear_free(bn_e_); - BN_CTX_free(ctx_); - - BN_clear_free(bn_K_); - BN_clear_free(bn_f_); - - delete[] session_id_; + if (sess.session_id != NULL) + delete[] sess.session_id; } void FQTermSSH2Kex::initKex(FQTermSSHPacketReceiver *packetReceiver, @@ -156,7 +143,7 @@ bool FQTermSSH2Kex::negotiateAlgorithms() { emit kexError(tr("No matching KEX algorithms!")); return false; } - this->dh = new_dh(); + sess.dh = new_dh(); // TODO: host key algorithms size_t hk_algo_len = packet_receiver_->getInt(); @@ -258,12 +245,23 @@ bool FQTermSSH2Kex::negotiateAlgorithms() { return true; } -void FQTermSSH2Kex::exchangeKey() { - BN_pseudo_rand_range(bn_x_, dh->p); - BN_mod_exp(bn_e_, dh->g, bn_x_, dh->p, ctx_); +/* RFC 4253 section 8: + * client generate x and compute e=g^x + * server generate y and compute f=g^y + * + * client sends: + * byte SSH_MSG_KEXDH_INIT + * mpint e + * server sends: + * byte SSH_MSG_KEXDH_REPLY + * string server public host key and certificates (K_S) + * mpint f + * string signature of H + */ +void FQTermSSH2Kex::exchangeKey() { packet_sender_->startPacket(SSH2_MSG_KEXDH_INIT); - packet_sender_->putBN2(bn_e_); + packet_sender_->putRawData((const char*)sess.dh->mpint_e, sess.dh->e_len); packet_sender_->write(); } @@ -275,19 +273,22 @@ bool FQTermSSH2Kex::verifyKey() { return false; } - // Extract data if (K_S_) delete [] K_S_; K_S_ = (char*)packet_receiver_->getString(&K_S_len_); - packet_receiver_->getBN2(bn_f_); + int mpint_f_len; + unsigned char *mpint_f = (unsigned char *)packet_receiver_->getString(&mpint_f_len); + if (ssh_dh_compute_secret(sess.dh, mpint_f, mpint_f_len) < 0) { + emit kexError(tr("Error when computing shared secret")); + delete mpint_f; + return false; + } int s_len = -1; unsigned char *s = (unsigned char *)packet_receiver_->getString(&s_len); - BN_mod_exp(bn_K_, bn_f_, bn_x_, dh->p, ctx_); - FQTermSSHBuffer *buffer = packet_sender_->output_buffer_; buffer->clear(); @@ -296,16 +297,16 @@ bool FQTermSSH2Kex::verifyKey() { buffer->putString(I_C_, I_C_len_); buffer->putString(I_S_, I_S_len_); buffer->putString(K_S_, K_S_len_); - buffer->putSSH2BN(bn_e_); - buffer->putSSH2BN(bn_f_); - buffer->putSSH2BN(bn_K_); + buffer->putRawData((const char*)sess.dh->mpint_e, sess.dh->e_len); + buffer->putString((const char*)mpint_f, mpint_f_len); + buffer->putRawData((const char*)sess.dh->secret, sess.dh->secret_len); - ssh_dh_hash(dh, buffer->data(), H_, buffer->len()); + ssh_dh_hash(sess.dh, buffer->data(), sess.H, buffer->len()); // Start verify // ssh-rsa specifies SHA-1 hashing unsigned char s_H[SHA_DIGEST_LENGTH]; - SHA1(H_, dh->digest.hashlen, s_H); + SHA1(sess.H, sess.dh->digest.hashlen, 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]. @@ -317,6 +318,7 @@ bool FQTermSSH2Kex::verifyKey() { RSA_free(rsactx); + delete [] mpint_f; delete [] s; return res == 1; @@ -365,14 +367,16 @@ void FQTermSSH2Kex::sendNewKeys(){ } bool FQTermSSH2Kex::changeKeyAlg() { + unsigned char IV_c2s[128], IV_s2c[128], key_c2s[128], key_s2c[128], mac_c2s[128], mac_s2c[128]; + 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[dh->digest.hashlen]; - memcpy(session_id_, H_, dh->digest.hashlen); + if (sess.session_id == NULL) { + sess.session_id = new unsigned char[sess.dh->digest.hashlen]; + memcpy(sess.session_id, sess.H, sess.dh->digest.hashlen); } // From RFC 4253 section 7.2: @@ -391,75 +395,35 @@ bool FQTermSSH2Kex::changeKeyAlg() { // 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'); + computeKey(&sess, IV_c2s_len, 'A', IV_c2s); int IV_s2c_len = packet_receiver_->getIVSize(); - unsigned char *IV_s2c = computeKey(IV_s2c_len, 'B'); + computeKey(&sess, IV_s2c_len, 'B', IV_s2c); int key_c2s_len = packet_sender_->getKeySize(); - unsigned char *key_c2s = computeKey(key_c2s_len, 'C'); + computeKey(&sess, key_c2s_len, 'C', key_c2s); int key_s2c_len = packet_receiver_->getKeySize(); - unsigned char *key_s2c = computeKey(key_s2c_len, 'D'); + computeKey(&sess, key_s2c_len, 'D', key_s2c); int mac_key_c2s_len = packet_sender_->getMacKeySize(); - unsigned char *mac_key_c2s = computeKey(mac_key_c2s_len, 'E'); + computeKey(&sess, mac_key_c2s_len, 'E', mac_c2s); int mac_key_s2c_len = packet_receiver_->getMacKeySize(); - unsigned char *mac_key_s2c = computeKey(mac_key_s2c_len, 'F'); - + computeKey(&sess, mac_key_s2c_len, 'F', mac_s2c); packet_sender_->startEncryption(key_c2s, IV_c2s); - packet_sender_->startMac(mac_key_c2s); + packet_sender_->startMac(mac_c2s); packet_receiver_->startEncryption(key_s2c, IV_s2c); - packet_receiver_->startMac(mac_key_s2c); + packet_receiver_->startMac(mac_s2c); /* now key exchange ends */ - ssh_dh_free(dh); - - delete[] IV_c2s; - delete[] IV_s2c; - delete[] key_c2s; - delete[] key_s2c; - delete[] mac_key_c2s; - delete[] mac_key_s2c; + ssh_dh_free(sess.dh); 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; - - EVP_MD_CTX *mdctx = dh->digest.mdctx; - const EVP_MD *md = dh->digest.md; - int hashlen = dh->digest.hashlen; - - FQTermSSHBuffer K(BN_num_bytes(bn_K_) + 5); - K.putSSH2BN(bn_K_); - - while (len < expected_len) { - EVP_DigestInit_ex(mdctx, md, NULL); - EVP_DigestUpdate(mdctx, K.data(), K.len()); - EVP_DigestUpdate(mdctx, H_, hashlen); - - if (len == 0) { - EVP_DigestUpdate(mdctx, &flag, 1); - EVP_DigestUpdate(mdctx, session_id_, hashlen); - } else { - EVP_DigestUpdate(mdctx, key, len); - } - - EVP_DigestFinal_ex(mdctx, key+len, NULL); - len += SHA_DIGEST_LENGTH; - } - - return key; -} - } // namespace FQTerm #include "fqterm_ssh2_kex.moc" |