summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2012-12-23 23:09:50 +0100
committerAris Adamantiadis <aris@0xbadc0de.be>2012-12-23 23:09:50 +0100
commit63c3f0e7368c7286a960c65422513850ce192124 (patch)
tree2267e176dac25d4c9e14512282a4723d94a063d6 /src
parente934ab0816e871253cd3d0538638f0b7cf98c375 (diff)
downloadlibssh-63c3f0e7368c7286a960c65422513850ce192124.tar.gz
libssh-63c3f0e7368c7286a960c65422513850ce192124.tar.xz
libssh-63c3f0e7368c7286a960c65422513850ce192124.zip
Implement key re-exchange
Diffstat (limited to 'src')
-rw-r--r--src/auth.c2
-rw-r--r--src/client.c5
-rw-r--r--src/dh.c32
-rw-r--r--src/kex.c5
-rw-r--r--src/packet_cb.c9
-rw-r--r--src/wrapper.c5
6 files changed, 44 insertions, 14 deletions
diff --git a/src/auth.c b/src/auth.c
index 7c33537..9d099a5 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -252,6 +252,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
session->auth_state=SSH_AUTH_STATE_SUCCESS;
session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
+ session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
+
if(session->current_crypto && session->current_crypto->delayed_compress_out){
SSH_LOG(session, SSH_LOG_DEBUG, "Enabling delayed compression OUT");
session->current_crypto->do_compress_out=1;
diff --git a/src/client.c b/src/client.c
index f571b2d..ac1b83d 100644
--- a/src/client.c
+++ b/src/client.c
@@ -409,7 +409,10 @@ static void ssh_client_connection_callback(ssh_session session){
if(session->dh_handshake_state==DH_STATE_FINISHED){
set_status(session,1.0f);
session->connected = 1;
- session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
+ if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
+ session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
+ else
+ session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
diff --git a/src/dh.c b/src/dh.c
index 997ae85..e4f2062 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -788,31 +788,43 @@ int make_sessionid(ssh_session session) {
case SSH_KEX_DH_GROUP14_SHA1:
session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA1;
- session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
- if(session->next_crypto->session_id == NULL){
+ session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
+ if(session->next_crypto->secret_hash == NULL){
ssh_set_error_oom(session);
goto error;
}
sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
- session->next_crypto->session_id);
+ session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
- session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
- if(session->next_crypto->session_id == NULL){
+ session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
+ if(session->next_crypto->secret_hash == NULL){
ssh_set_error_oom(session);
goto error;
}
sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
- session->next_crypto->session_id);
+ session->next_crypto->secret_hash);
break;
}
-
-
+ /* During the first kex, secret hash and session ID are equal. However, after
+ * a key re-exchange, a new secret hash is calculated. This hash will not replace
+ * but complement existing session id.
+ */
+ if (!session->next_crypto->session_id){
+ session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
+ if (session->next_crypto->session_id == NULL){
+ ssh_set_error_oom(session);
+ goto error;
+ }
+ memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
+ session->next_crypto->digest_len);
+ }
#ifdef DEBUG_CRYPTO
printf("Session hash: ");
- ssh_print_hexa("session id", session->next_crypto->session_id, SHA_DIGEST_LEN);
+ ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
+ ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
#endif
rc = SSH_OK;
@@ -888,7 +900,7 @@ static int generate_one_key(ssh_string k,
}
ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
- ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
+ ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
ssh_mac_update(ctx, &letter, 1);
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
ssh_mac_final(output, ctx);
diff --git a/src/kex.c b/src/kex.c
index d26fd1f..e900a91 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -276,7 +276,9 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
(void)type;
(void)user;
memset(strings, 0, sizeof(strings));
- if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
+ if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){
+ ssh_log(session,SSH_LOG_WARNING, "Other side initiating key re-exchange");
+ } else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
goto error;
}
@@ -335,6 +337,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
leave_function();
session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
+ session->dh_handshake_state=DH_STATE_INIT;
session->ssh_connection_callback(session);
return SSH_PACKET_USED;
error:
diff --git a/src/packet_cb.c b/src/packet_cb.c
index dd77dd7..41d0985 100644
--- a/src/packet_cb.c
+++ b/src/packet_cb.c
@@ -179,7 +179,7 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
rc = ssh_pki_signature_verify_blob(session,
sig_blob,
key,
- session->next_crypto->session_id,
+ session->next_crypto->secret_hash,
session->next_crypto->digest_len);
/* Set the server public key type for known host checking */
session->next_crypto->server_pubkey_type = key->type_c;
@@ -210,6 +210,13 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
ssh_set_error_oom(session);
goto error;
}
+ session->next_crypto->session_id = malloc(session->current_crypto->digest_len);
+ if (session->next_crypto->session_id == NULL) {
+ ssh_set_error_oom(session);
+ goto error;
+ }
+ memcpy(session->next_crypto->session_id, session->current_crypto->session_id,
+ session->current_crypto->digest_len);
}
session->dh_handshake_state = DH_STATE_FINISHED;
session->ssh_connection_callback(session);
diff --git a/src/wrapper.c b/src/wrapper.c
index e27579d..b8a489d 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -121,7 +121,10 @@ void crypto_free(struct ssh_crypto_struct *crypto){
memset(crypto->session_id, '\0', crypto->digest_len);
SAFE_FREE(crypto->session_id);
}
-
+ if(crypto->secret_hash != NULL){
+ memset(crypto->secret_hash, '\0', crypto->digest_len);
+ SAFE_FREE(crypto->secret_hash);
+ }
#ifdef WITH_ZLIB
if (crypto->compress_out_ctx &&
(deflateEnd(crypto->compress_out_ctx) != 0)) {