diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2016-01-01 21:51:57 +0100 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2016-09-09 14:27:49 +0200 |
commit | 2e6e472254645f3b4548d815777d6cfd1bfb8f3d (patch) | |
tree | 97bda569295ada2497f9b688170374fc2d7fc447 | |
parent | 37ab6fd8fc3f5f1633faadb468bb2ab65a5a268b (diff) | |
download | libssh-2e6e472254645f3b4548d815777d6cfd1bfb8f3d.tar.gz libssh-2e6e472254645f3b4548d815777d6cfd1bfb8f3d.tar.xz libssh-2e6e472254645f3b4548d815777d6cfd1bfb8f3d.zip |
dh: big cleanup
-rw-r--r-- | include/libssh/dh.h | 11 | ||||
-rw-r--r-- | src/bignum.c | 9 | ||||
-rw-r--r-- | src/dh.c | 418 | ||||
-rw-r--r-- | src/kex.c | 1 | ||||
-rw-r--r-- | src/server.c | 2 |
5 files changed, 144 insertions, 297 deletions
diff --git a/include/libssh/dh.h b/include/libssh/dh.h index d64f93fe..101ceecd 100644 --- a/include/libssh/dh.h +++ b/include/libssh/dh.h @@ -25,20 +25,9 @@ #include "libssh/crypto.h" -int ssh_dh_generate_e(ssh_session session); -int ssh_dh_generate_f(ssh_session session); -int ssh_dh_generate_x(ssh_session session); -int ssh_dh_generate_y(ssh_session session); - int ssh_dh_init(void); void ssh_dh_finalize(void); -ssh_string ssh_dh_get_e(ssh_session session); -ssh_string ssh_dh_get_f(ssh_session session); -int ssh_dh_import_f(ssh_session session,ssh_string f_string); -int ssh_dh_import_e(ssh_session session, ssh_string e_string); -void ssh_dh_import_pubkey(ssh_session session,ssh_string pubkey_string); -int ssh_dh_build_k(ssh_session session); int ssh_client_dh_init(ssh_session session); #ifdef WITH_SERVER diff --git a/src/bignum.c b/src/bignum.c index abc77255..44fd6ad4 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -74,11 +74,12 @@ bignum ssh_make_string_bn(ssh_string string){ } /* prints the bignum on stderr */ -void ssh_print_bignum(const char *which, bignum num) { +void ssh_print_bignum(const char *name, bignum num) { unsigned char *hex = NULL; - bignum_bn2hex(num, &hex); - fprintf(stderr, "%s value: ", which); - fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex); + if (num != NULL){ + bignum_bn2hex(num, &hex); + } + fprintf(stderr, "%s value: %s\n", name, (hex == NULL) ? "(null)" : (char *) hex); #ifdef HAVE_LIBGCRYPT SAFE_FREE(hex); #elif defined HAVE_LIBCRYPTO @@ -130,26 +130,23 @@ int ssh_dh_init(void) { if (dh_crypto_initialized == 0) { g = bignum_new(); if (g == NULL) { - return SSH_ERROR; + goto error; } bignum_set_word(g,g_int); bignum_bin2bn(p_group1_value, P_GROUP1_LEN, &p_group1); - if (p_group1 == NULL) { - bignum_safe_free(g); - return SSH_ERROR; - } bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14); - if (p_group14 == NULL) { - bignum_safe_free(g); - bignum_safe_free(p_group1); - return SSH_ERROR; + if (p_group1 == NULL || p_group14 == NULL) { + goto error; } - dh_crypto_initialized = 1; } - return 0; + +error: + bignum_safe_free(g); + bignum_safe_free(p_group1); + return SSH_ERROR; } /** @@ -165,150 +162,56 @@ void ssh_dh_finalize(void) { } } -int ssh_dh_generate_x(ssh_session session) { - int keysize; - if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) { - keysize = 1023; - } else { - keysize = 2047; - } - session->next_crypto->x = bignum_new(); - if (session->next_crypto->x == NULL) { - return -1; - } - - bignum_rand(session->next_crypto->x, keysize); - - /* not harder than this */ -#ifdef DEBUG_CRYPTO - ssh_print_bignum("x", session->next_crypto->x); -#endif - - return 0; -} - -/* used by server */ -int ssh_dh_generate_y(ssh_session session) { - int keysize; - if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) { - keysize = 1023; - } else { - keysize = 2047; - } - session->next_crypto->y = bignum_new(); - if (session->next_crypto->y == NULL) { - return -1; - } - - bignum_rand(session->next_crypto->y, keysize); - - /* not harder than this */ -#ifdef DEBUG_CRYPTO - ssh_print_bignum("y", session->next_crypto->y); -#endif - - return 0; -} - -/* used by server */ -int ssh_dh_generate_e(ssh_session session) { - bignum_CTX ctx = bignum_ctx_new(); - if (bignum_ctx_invalid(ctx)) { - return -1; - } - - session->next_crypto->e = bignum_new(); - if (session->next_crypto->e == NULL) { - bignum_ctx_free(ctx); - return -1; - } - - bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x, - select_p(session->next_crypto->kex_type), ctx); - -#ifdef DEBUG_CRYPTO - ssh_print_bignum("e", session->next_crypto->e); -#endif - - bignum_ctx_free(ctx); - - return 0; -} - -int ssh_dh_generate_f(ssh_session session) { - bignum_CTX ctx = bignum_ctx_new(); - if (bignum_ctx_invalid(ctx)) { - return -1; - } - - session->next_crypto->f = bignum_new(); - if (session->next_crypto->f == NULL) { - bignum_ctx_free(ctx); - return -1; - } - - bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y, - select_p(session->next_crypto->kex_type), ctx); -#ifdef DEBUG_CRYPTO - ssh_print_bignum("f", session->next_crypto->f); -#endif - - bignum_ctx_free(ctx); - return 0; -} - -ssh_string ssh_dh_get_e(ssh_session session) { - return ssh_make_bignum_string(session->next_crypto->e); -} - -/* used by server */ -ssh_string ssh_dh_get_f(ssh_session session) { - return ssh_make_bignum_string(session->next_crypto->f); +/** + * @internal + * @brief allocate and initialize ephemeral values used in dh kex + */ +static int ssh_dh_init_common(ssh_session session){ + struct ssh_crypto_struct *crypto=session->next_crypto; + crypto->x = bignum_new(); + crypto->y = bignum_new(); + crypto->e = bignum_new(); + crypto->f = bignum_new(); + crypto->k = bignum_new(); + if (crypto->x == NULL || crypto->y == NULL || crypto->e == NULL || + crypto->f == NULL || crypto->k == NULL){ + return SSH_ERROR; + } else { + return SSH_OK; + } } -void ssh_dh_import_pubkey(ssh_session session, ssh_string pubkey_string) { - session->next_crypto->server_pubkey = pubkey_string; +static void ssh_dh_cleanup(ssh_session session){ + struct ssh_crypto_struct *crypto=session->next_crypto; + bignum_safe_free(crypto->x); + bignum_safe_free(crypto->y); + bignum_safe_free(crypto->e); + bignum_safe_free(crypto->f); } -int ssh_dh_import_f(ssh_session session, ssh_string f_string) { - session->next_crypto->f = ssh_make_string_bn(f_string); - if (session->next_crypto->f == NULL) { - return -1; - } - #ifdef DEBUG_CRYPTO - ssh_print_bignum("f",session->next_crypto->f); -#endif +static void ssh_dh_debug(ssh_session session){ + ssh_print_bignum("x", session->next_crypto->x); + ssh_print_bignum("y", session->next_crypto->y); + ssh_print_bignum("e", session->next_crypto->e); + ssh_print_bignum("f", session->next_crypto->f); - return 0; + ssh_print_hexa("Session server cookie", + session->next_crypto->server_kex.cookie, 16); + ssh_print_hexa("Session client cookie", + session->next_crypto->client_kex.cookie, 16); + ssh_print_bignum("k", session->next_crypto->k); } - -/* used by the server implementation */ -int ssh_dh_import_e(ssh_session session, ssh_string e_string) { - session->next_crypto->e = ssh_make_string_bn(e_string); - if (session->next_crypto->e == NULL) { - return -1; - } - -#ifdef DEBUG_CRYPTO - ssh_print_bignum("e",session->next_crypto->e); +#else +#define ssh_dh_debug(session) #endif - return 0; -} - -int ssh_dh_build_k(ssh_session session) { +static int dh_build_k(ssh_session session) { bignum_CTX ctx = bignum_ctx_new(); if (bignum_ctx_invalid(ctx)) { return -1; } - session->next_crypto->k = bignum_new(); - if (session->next_crypto->k == NULL) { - bignum_ctx_free(ctx); - return -1; - } - /* the server and clients don't use the same numbers */ if (session->client) { bignum_mod_exp(session->next_crypto->k, session->next_crypto->f, @@ -317,16 +220,8 @@ int ssh_dh_build_k(ssh_session session) { bignum_mod_exp(session->next_crypto->k, session->next_crypto->e, session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx); } - -#ifdef DEBUG_CRYPTO - ssh_print_hexa("Session server cookie", - session->next_crypto->server_kex.cookie, 16); - ssh_print_hexa("Session client cookie", - session->next_crypto->client_kex.cookie, 16); - ssh_print_bignum("Shared secret key", session->next_crypto->k); -#endif - bignum_ctx_free(ctx); + ssh_dh_debug(); return 0; } @@ -348,82 +243,56 @@ static struct ssh_packet_callbacks_struct ssh_dh_client_callbacks = { * @brief Starts diffie-hellman-group1 key exchange */ int ssh_client_dh_init(ssh_session session){ - ssh_string e = NULL; int rc; + bignum_CTX ctx = bignum_ctx_new(); - if (ssh_dh_generate_x(session) < 0) { + if (bignum_ctx_invalid(ctx)) { goto error; } - if (ssh_dh_generate_e(session) < 0) { + rc = ssh_dh_init_common(session); + if (rc == SSH_ERROR){ goto error; } + bignum_rand(session->next_crypto->x, 128); - e = ssh_dh_get_e(session); - if (e == NULL) { - goto error; - } + bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x, + select_p(session->next_crypto->kex_type), ctx); - rc = ssh_buffer_pack(session->out_buffer, "bS", SSH2_MSG_KEXDH_INIT, e); + bignum_ctx_free(ctx); + + rc = ssh_buffer_pack(session->out_buffer, "bB", SSH2_MSG_KEXDH_INIT, session->next_crypto->e); if (rc != SSH_OK) { goto error; } - ssh_string_burn(e); - ssh_string_free(e); - e=NULL; - /* register the packet callbacks */ ssh_packet_set_callbacks(session, &ssh_dh_client_callbacks); rc = ssh_packet_send(session); return rc; - error: - if(e != NULL){ - ssh_string_burn(e); - ssh_string_free(e); - } - +error: + ssh_dh_cleanup(session); return SSH_ERROR; } SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){ - ssh_string f; - ssh_string pubkey = NULL; - ssh_string signature = NULL; + struct ssh_crypto_struct *crypto=session->next_crypto; int rc; (void)type; (void)user; ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks); - pubkey = ssh_buffer_get_ssh_string(packet); - if (pubkey == NULL){ - ssh_set_error(session,SSH_FATAL, "No public key in packet"); - goto error; - } - ssh_dh_import_pubkey(session, pubkey); + rc = ssh_buffer_unpack(packet, "SBS", &crypto->server_pubkey, &crypto->f, + &crypto->dh_server_signature); - f = ssh_buffer_get_ssh_string(packet); - if (f == NULL) { - ssh_set_error(session,SSH_FATAL, "No F number in packet"); - goto error; - } - rc = ssh_dh_import_f(session, f); - ssh_string_burn(f); - ssh_string_free(f); - if (rc < 0) { - ssh_set_error(session, SSH_FATAL, "Cannot import f number"); + if (rc == SSH_ERROR){ + ssh_set_error(session, SSH_FATAL, "Invalid DH_REPLY packet"); goto error; } - signature = ssh_buffer_get_ssh_string(packet); - if (signature == NULL) { - ssh_set_error(session, SSH_FATAL, "No signature in packet"); - goto error; - } - session->next_crypto->dh_server_signature = signature; - signature=NULL; /* ownership changed */ - if (ssh_dh_build_k(session) < 0) { - ssh_set_error(session, SSH_FATAL, "Cannot build k number"); + rc = dh_build_k(session); + if (rc == SSH_ERROR) { + ssh_set_error(session, SSH_FATAL, "Could not generate shared secret"); goto error; } @@ -441,6 +310,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){ return SSH_PACKET_USED; error: + ssh_dh_cleanup(session); session->session_state=SSH_SESSION_STATE_ERROR; return SSH_PACKET_USED; } @@ -466,109 +336,95 @@ static struct ssh_packet_callbacks_struct ssh_dh_server_callbacks = { void ssh_server_dh_init(ssh_session session){ /* register the packet callbacks */ ssh_packet_set_callbacks(session, &ssh_dh_server_callbacks); + ssh_dh_init_common(session); } -static int dh_handshake_server(ssh_session session) { - ssh_key privkey; - ssh_string sig_blob; - ssh_string f; - int rc; - - if (ssh_dh_generate_y(session) < 0) { - ssh_set_error(session, SSH_FATAL, "Could not create y number"); - return -1; - } - if (ssh_dh_generate_f(session) < 0) { - ssh_set_error(session, SSH_FATAL, "Could not create f number"); - return -1; - } +/** @internal + * @brief parse an incoming SSH_MSG_KEXDH_INIT packet and complete + * Diffie-Hellman key exchange + **/ +static SSH_PACKET_CALLBACK(ssh_packet_server_dh_init){ + ssh_key privkey; + ssh_string sig_blob; + bignum_CTX ctx = bignum_ctx_new(); + int rc; - f = ssh_dh_get_f(session); - if (f == NULL) { - ssh_set_error(session, SSH_FATAL, "Could not get the f number"); - return -1; - } + (void)type; + (void)user; - if (ssh_get_key_params(session,&privkey) != SSH_OK){ - ssh_string_free(f); - return -1; - } + if (bignum_ctx_invalid(ctx)) { + goto error; + } + ssh_packet_remove_callbacks(session, &ssh_dh_server_callbacks); - if (ssh_dh_build_k(session) < 0) { - ssh_set_error(session, SSH_FATAL, "Could not import the public key"); - ssh_string_free(f); - return -1; - } + rc = ssh_buffer_unpack(packet, "B", &session->next_crypto->e); + if (rc == SSH_ERROR) { + ssh_set_error(session, SSH_FATAL, "No e number in client request"); + goto error; + } - if (ssh_make_sessionid(session) != SSH_OK) { - ssh_set_error(session, SSH_FATAL, "Could not create a session id"); - ssh_string_free(f); - return -1; - } + bignum_rand(session->next_crypto->y, 128); - sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); - if (sig_blob == NULL) { - ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); - ssh_string_free(f); - return -1; - } + bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y, + select_p(session->next_crypto->kex_type), ctx); + bignum_ctx_free(ctx); + ctx = NULL; - rc = ssh_buffer_pack(session->out_buffer, - "bSSS", - SSH2_MSG_KEXDH_REPLY, - session->next_crypto->server_pubkey, - f, - sig_blob); - ssh_string_free(f); - ssh_string_free(sig_blob); - if(rc != SSH_OK){ - ssh_set_error_oom(session); - ssh_buffer_reinit(session->out_buffer); - return -1; - } + if (ssh_get_key_params(session,&privkey) != SSH_OK){ + goto error; + } - if (ssh_packet_send(session) == SSH_ERROR) { - return -1; - } + rc = dh_build_k(session); + if (rc == SSH_ERROR) { + ssh_set_error(session, SSH_FATAL, "Could not generate shared secret"); + goto error; + } - if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { - ssh_buffer_reinit(session->out_buffer); - return -1; - } + if (ssh_make_sessionid(session) != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Could not create a session id"); + goto error; + } - if (ssh_packet_send(session) == SSH_ERROR) { - return -1; - } - SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); - session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; + sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); + if (sig_blob == NULL) { + ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); + goto error; + } - return 0; -} + rc = ssh_buffer_pack(session->out_buffer, + "bSBS", + SSH2_MSG_KEXDH_REPLY, + session->next_crypto->server_pubkey, + session->next_crypto->f, + sig_blob); + ssh_string_free(sig_blob); + if(rc != SSH_OK){ + ssh_set_error_oom(session); + ssh_buffer_reinit(session->out_buffer); + goto error; + } -/** @internal - * @brief parse an incoming SSH_MSG_KEXDH_INIT packet and complete - * Diffie-Hellman key exchange - **/ -static SSH_PACKET_CALLBACK(ssh_packet_server_dh_init){ - ssh_string e; - (void)type; - (void)user; + if (ssh_packet_send(session) == SSH_ERROR) { + goto error; + } - ssh_packet_remove_callbacks(session, &ssh_dh_server_callbacks); - e = ssh_buffer_get_ssh_string(packet); - if (e == NULL) { - ssh_set_error(session, SSH_FATAL, "No e number in client request"); - return -1; + if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { + ssh_buffer_reinit(session->out_buffer); + goto error; } - if (ssh_dh_import_e(session, e) < 0) { - ssh_set_error(session, SSH_FATAL, "Cannot import e number"); - goto error; + + if (ssh_packet_send(session) == SSH_ERROR) { + goto error; } - session->dh_handshake_state=DH_STATE_INIT_SENT; - dh_handshake_server(session); - ssh_string_free(e); + SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); + session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; + ssh_dh_cleanup(session); return SSH_PACKET_USED; error: + ssh_dh_cleanup(session); + if (!bignum_ctx_invalid(ctx)){ + bignum_ctx_free(ctx); + } session->session_state=SSH_SESSION_STATE_ERROR; return SSH_PACKET_USED; } @@ -1036,6 +1036,7 @@ int ssh_generate_session_keys(ssh_session session) { rc = 0; error: + ssh_string_burn(k_string); ssh_string_free(k_string); return rc; diff --git a/src/server.c b/src/server.c index af84830a..92a1a2f7 100644 --- a/src/server.c +++ b/src/server.c @@ -207,7 +207,7 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){ return -1; } - ssh_dh_import_pubkey(session, pubkey_blob); + session->next_crypto->server_pubkey = pubkey_blob; return SSH_OK; } |