From 63c3f0e7368c7286a960c65422513850ce192124 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Sun, 23 Dec 2012 23:09:50 +0100 Subject: Implement key re-exchange --- src/auth.c | 2 ++ src/client.c | 5 ++++- src/dh.c | 32 ++++++++++++++++++++++---------- src/kex.c | 5 ++++- src/packet_cb.c | 9 ++++++++- src/wrapper.c | 5 ++++- 6 files changed, 44 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/auth.c b/src/auth.c index 7c335370..9d099a53 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 f571b2d9..ac1b83db 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 997ae852..e4f2062b 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 d26fd1f1..e900a91a 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 dd77dd7c..41d0985c 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 e27579db..b8a489d4 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)) { -- cgit v1.2.3