[Chinese-commits] [fqterm] 10/16: better handling of errors when KEX fails, use EVP digest

Boyuan Yang hosiet-guest at moszumanska.debian.org
Sun Dec 18 15:36:26 UTC 2016


This is an automated email from the git hooks/post-receive script.

hosiet-guest pushed a commit to branch master
in repository fqterm.

commit 88fed792b68835ea7805bcfed6762f0ee9496bab
Author: Iru Cai <mytbk920423 at gmail.com>
Date:   Tue Nov 8 14:59:15 2016 +0800

    better handling of errors when KEX fails, use EVP digest
---
 src/protocol/internal/fqterm_ssh2_kex.cpp  | 130 ++++++++++++++++-------------
 src/protocol/internal/fqterm_ssh2_kex.h    |   7 +-
 src/protocol/internal/ssh_diffie-hellman.c |  23 ++++-
 src/protocol/internal/ssh_diffie-hellman.h |  20 ++++-
 4 files changed, 109 insertions(+), 71 deletions(-)

diff --git a/src/protocol/internal/fqterm_ssh2_kex.cpp b/src/protocol/internal/fqterm_ssh2_kex.cpp
index 59ec85e..fe35452 100644
--- a/src/protocol/internal/fqterm_ssh2_kex.cpp
+++ b/src/protocol/internal/fqterm_ssh2_kex.cpp
@@ -60,7 +60,6 @@ FQTermSSH2Kex::~FQTermSSH2Kex() {
 
   BN_clear_free(bn_x_);
   BN_clear_free(bn_e_);
-  ssh_dh_free(dh);
   BN_CTX_free(ctx_);
 
   BN_clear_free(bn_K_);
@@ -80,39 +79,41 @@ void FQTermSSH2Kex::initKex(FQTermSSHPacketReceiver *packetReceiver,
   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::handlePacket(int type)
+{
+	switch (kex_state_) {
+	case FQTermSSH2Kex::BEFORE_KEXINIT:
+		if (!negotiateAlgorithms())
+			return;
+		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() {
+bool 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 ;
+    return false;
   }
 
   // 0. Backup the payload of this server packet.
@@ -130,12 +131,12 @@ void FQTermSSH2Kex::negotiateAlgorithms() {
   char kex_algos[kl_len+1];
   packet_receiver_->getRawData(kex_algos, kl_len);
   kex_algos[kl_len] = '\0';
-  NEW_DH dh = search_dh(kex_algos);
-  if (dh==NULL) {
+  NEW_DH new_dh = search_dh(kex_algos);
+  if (new_dh==NULL) {
 	  emit kexError(tr("No matching KEX algorithms!"));
-	  return;
+	  return false;
   }
-  this->dh = dh();
+  this->dh = new_dh();
 
   // TODO: host key algorithms
   size_t hk_algo_len = packet_receiver_->getInt();
@@ -151,7 +152,7 @@ void FQTermSSH2Kex::negotiateAlgorithms() {
   NEW_CIPHER c2s = search_cipher(el_c2s);
   if (c2s==NULL) {
 	  emit kexError(tr("No matching c2s cipher algorithms!"));
-	  return;
+	  return false;
   }
   packet_sender_->cipher = c2s(1);
 
@@ -163,7 +164,7 @@ void FQTermSSH2Kex::negotiateAlgorithms() {
   NEW_CIPHER s2c = search_cipher(el_s2c);
   if (s2c==NULL) {
 	  emit kexError(tr("No matching s2c cipher algorithms!"));
-	  return;
+	  return false;
   }
   packet_receiver_->cipher = s2c(0);
 
@@ -209,6 +210,8 @@ void FQTermSSH2Kex::negotiateAlgorithms() {
 
   // 4. send packet to server
   packet_sender_->write();
+
+  return true;
 }
 
 void FQTermSSH2Kex::exchangeKey() {
@@ -252,11 +255,12 @@ bool FQTermSSH2Kex::verifyKey() {
   buffer->putSSH2BN(bn_f_);
   buffer->putSSH2BN(bn_K_);
 
-  dh->hash(buffer->data(), buffer->len(), H_);
+  ssh_dh_hash(dh, buffer->data(), H_, buffer->len());
 
   // Start verify
+  // ssh-rsa specifies SHA-1 hashing
   unsigned char s_H[SHA_DIGEST_LENGTH];
-  SHA1(H_, dh->hashlen, s_H);
+  SHA1(H_, 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].
@@ -323,8 +327,8 @@ bool FQTermSSH2Kex::changeKeyAlg() {
   }
 
   if (session_id_ == NULL) {
-    session_id_ = new unsigned char[SHA_DIGEST_LENGTH];
-    memcpy(session_id_, H_, SHA_DIGEST_LENGTH);
+	  session_id_ = new unsigned char[dh->digest.hashlen];
+	  memcpy(session_id_, H_, dh->digest.hashlen);
   }
 
   packet_sender_->setMacType(FQTERM_SSH_HMAC_SHA1);
@@ -370,6 +374,8 @@ bool FQTermSSH2Kex::changeKeyAlg() {
   packet_receiver_->startEncryption(key_s2c, IV_s2c);
   packet_receiver_->startMac(mac_key_s2c);
 
+  /* now key exchange ends */
+  ssh_dh_free(dh);
 
   delete[] IV_c2s;
   delete[] IV_s2c;
@@ -381,32 +387,36 @@ bool FQTermSSH2Kex::changeKeyAlg() {
   return true;
 }
 
-unsigned char *FQTermSSH2Kex::computeKey(int expected_len, char flag) {
-  unsigned char *key = new unsigned char[expected_len + SHA_DIGEST_LENGTH];
+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;
+	int len = 0;
 
-  FQTermSSHBuffer K(BN_num_bytes(bn_K_) + 5);
-  K.putSSH2BN(bn_K_);
+	EVP_MD_CTX *mdctx = dh->digest.mdctx;
+	const EVP_MD *md = dh->digest.md;
+	int hashlen = dh->digest.hashlen;
 
-  while (len < expected_len) {
-    SHA1_Init(&hash);
-    SHA1_Update(&hash, K.data(), K.len()); 
-    SHA1_Update(&hash, H_, SHA_DIGEST_LENGTH);
+	FQTermSSHBuffer K(BN_num_bytes(bn_K_) + 5);
+	K.putSSH2BN(bn_K_);
 
-    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;
-  }
+	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;
+	return key;
 }
 
 }  // namespace FQTerm
diff --git a/src/protocol/internal/fqterm_ssh2_kex.h b/src/protocol/internal/fqterm_ssh2_kex.h
index 59e3330..0a09cc1 100644
--- a/src/protocol/internal/fqterm_ssh2_kex.h
+++ b/src/protocol/internal/fqterm_ssh2_kex.h
@@ -68,9 +68,6 @@ private:
 
   unsigned char *session_id_;
 
-
-
-
   bool is_first_kex_;
 
   ssh_pubkey_t *host_key_;
@@ -80,8 +77,8 @@ private:
   int server_flag_, ciphers_, auth_;
 //  u_char session_id_[16];
   u_char session_key_[32];
-  
-  void negotiateAlgorithms();
+
+  bool negotiateAlgorithms();
   void exchangeKey();
   bool verifyKey();
   void sendNewKeys();
diff --git a/src/protocol/internal/ssh_diffie-hellman.c b/src/protocol/internal/ssh_diffie-hellman.c
index 1866b2f..72bd253 100644
--- a/src/protocol/internal/ssh_diffie-hellman.c
+++ b/src/protocol/internal/ssh_diffie-hellman.c
@@ -63,6 +63,7 @@ ssh_dh_free(SSH_DH *dh)
 {
 	BN_free(dh->g);
 	BN_free(dh->p);
+	ssh_md_ctx_free(dh->digest.mdctx);
 	free(dh);
 }
 
@@ -72,8 +73,11 @@ ssh_dh_group1_sha1(void)
 	SSH_DH *dh = (SSH_DH*)malloc(sizeof(SSH_DH));
 	dh->g = BN_new();
 	dh->p = BN_new();
-	dh->hash = SHA1;
-	dh->hashlen = SHA_DIGEST_LENGTH;
+	dh->digest = (evp_md_t) {
+		.mdctx = ssh_md_ctx_new(),
+		.md = EVP_sha1(),
+		.hashlen = SHA_DIGEST_LENGTH
+	};
 	BN_set_word(dh->g, g);
 	BN_bin2bn(prime_group1, 128, dh->p);
 	return dh;
@@ -85,13 +89,24 @@ ssh_dh_group14_sha1(void)
 	SSH_DH *dh = (SSH_DH*)malloc(sizeof(SSH_DH));
 	dh->g = BN_new();
 	dh->p = BN_new();
-	dh->hash = SHA1;
-	dh->hashlen = SHA_DIGEST_LENGTH;
+	dh->digest = (evp_md_t) {
+		.mdctx = ssh_md_ctx_new(),
+		.md = EVP_sha1(),
+		.hashlen = SHA_DIGEST_LENGTH
+	};
 	BN_set_word(dh->g, g);
 	BN_bin2bn(prime_group14, 256, dh->p);
 	return dh;
 }
 
+void
+ssh_dh_hash(SSH_DH *dh, const unsigned char *in, unsigned char *out, size_t n)
+{
+	EVP_DigestInit_ex(dh->digest.mdctx, dh->digest.md, NULL);
+	EVP_DigestUpdate(dh->digest.mdctx, in, n);
+	EVP_DigestFinal_ex(dh->digest.mdctx, out, NULL);
+}
+
 struct
 {
 	const char *name;
diff --git a/src/protocol/internal/ssh_diffie-hellman.h b/src/protocol/internal/ssh_diffie-hellman.h
index 5468fdb..f132493 100644
--- a/src/protocol/internal/ssh_diffie-hellman.h
+++ b/src/protocol/internal/ssh_diffie-hellman.h
@@ -3,6 +3,15 @@
 
 #include <openssl/bn.h>
 #include <openssl/sha.h>
+#include <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#define ssh_md_ctx_new EVP_MD_CTX_new
+#define ssh_md_ctx_free EVP_MD_CTX_free
+#else
+#define ssh_md_ctx_new EVP_MD_CTX_create
+#define ssh_md_ctx_free EVP_MD_CTX_destroy
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -10,17 +19,24 @@ extern "C" {
 
 	typedef unsigned char* (*hash_t)(const unsigned char *, size_t, unsigned char *);
 
+	typedef struct
+	{
+		EVP_MD_CTX *mdctx;
+		const EVP_MD *md;
+		unsigned int hashlen;
+	} evp_md_t;
+
 	typedef struct ssh_diffie_hellman
 	{
 		BIGNUM *g; // generator
 		BIGNUM *p; // prime
-		hash_t hash; // can be SHA1 or SHA256
-		size_t hashlen;
+		evp_md_t digest;
 	} SSH_DH;
 
 	void ssh_dh_free(SSH_DH*);
 	SSH_DH *ssh_dh_group1_sha1(void);
 	SSH_DH *ssh_dh_group14_sha1(void);
+	void ssh_dh_hash(SSH_DH*, const unsigned char* data, unsigned char*, size_t len);
 
 	typedef SSH_DH*(*NEW_DH)(void);
 	extern const char all_dh_list[];

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/chinese/fqterm.git



More information about the Chinese-commits mailing list