aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2016-01-01 21:51:57 +0100
committerAris Adamantiadis <aris@0xbadc0de.be>2016-09-09 14:27:49 +0200
commit2e6e472254645f3b4548d815777d6cfd1bfb8f3d (patch)
tree97bda569295ada2497f9b688170374fc2d7fc447
parent37ab6fd8fc3f5f1633faadb468bb2ab65a5a268b (diff)
downloadlibssh-2e6e472254645f3b4548d815777d6cfd1bfb8f3d.tar.gz
libssh-2e6e472254645f3b4548d815777d6cfd1bfb8f3d.tar.xz
libssh-2e6e472254645f3b4548d815777d6cfd1bfb8f3d.zip
dh: big cleanup
-rw-r--r--include/libssh/dh.h11
-rw-r--r--src/bignum.c9
-rw-r--r--src/dh.c418
-rw-r--r--src/kex.c1
-rw-r--r--src/server.c2
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
diff --git a/src/dh.c b/src/dh.c
index 42b7d137..a6d10263 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -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;
}
diff --git a/src/kex.c b/src/kex.c
index 758baac1..8ffa7007 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -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;
}