From 24024cf9c5ce280a05ba7e7cf2723beb325cabcd Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Sun, 3 Feb 2019 11:05:26 +0100 Subject: socket: Add support for writing packet streams to files This will be needed to get fuzzing behind the key exchange. Signed-off-by: Andreas Schneider --- include/libssh/libssh.h | 2 ++ include/libssh/session.h | 2 ++ src/ecdh_crypto.c | 6 ++--- src/options.c | 50 +++++++++++++++++++++++++++++++++++++ src/pki.c | 2 +- src/socket.c | 64 ++++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 115 insertions(+), 11 deletions(-) diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index e80214c9..711f5c1e 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -415,6 +415,8 @@ enum ssh_options_e { SSH_OPTIONS_PROCESS_CONFIG, SSH_OPTIONS_REKEY_DATA, SSH_OPTIONS_REKEY_TIME, + SSH_OPTIONS_CLIENT_TRACE, + SSH_OPTIONS_SERVER_TRACE, }; enum { diff --git a/include/libssh/session.h b/include/libssh/session.h index 944213c9..7e0298b8 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -231,6 +231,8 @@ struct ssh_session_struct { uint8_t options_seen[SOC_MAX]; uint64_t rekey_data; uint32_t rekey_time; + char *client_trace; + char *server_trace; } opts; /* counters */ ssh_counter socket_counter; diff --git a/src/ecdh_crypto.c b/src/ecdh_crypto.c index 23654d02..91d3624f 100644 --- a/src/ecdh_crypto.c +++ b/src/ecdh_crypto.c @@ -119,9 +119,9 @@ int ssh_client_ecdh_init(ssh_session session){ int ecdh_build_k(ssh_session session) { const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey); - EC_POINT *pubkey; - void *buffer; - int rc; + EC_POINT *pubkey = NULL; + void *buffer = NULL; + int rc = -1; int len = (EC_GROUP_get_degree(group) + 7) / 8; bignum_CTX ctx = bignum_ctx_new(); if (ctx == NULL) { diff --git a/src/options.c b/src/options.c index 672735a4..2b491336 100644 --- a/src/options.c +++ b/src/options.c @@ -465,6 +465,16 @@ int ssh_options_set_algo(ssh_session session, * in seconds. RFC 4253 Section 9 recommends one hour. * (uint32_t, 0=off) * + * - SSH_OPTIONS_CLIENT_TRACE + * Set the path to a file to dump all packets a client sends. + * This is only working on a SSH client implementation. It is + * useful to create traces for fuzzing. + * + * - SSH_OPTIONS_SERVER_TRACE + * Set the path to a file to dump all packets a client receives. + * This is only working on a SSH client implementation. It is + * useful to create traces for fuzzing. + * * @param value The value to set. This is a generic pointer and the * datatype which is used should be set according to the * type set. @@ -1030,6 +1040,46 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type, session->opts.rekey_time = (*x) * 1000; } break; + case SSH_OPTIONS_CLIENT_TRACE: + if (value == NULL) { + ssh_set_error_invalid(session); + return -1; + } else { + switch(session->type) { + case SSH_SESSION_TYPE_CLIENT: + break; + case SSH_SESSION_TYPE_SERVER: + return -1; + } + q = strdup(value); + if (q == NULL) { + ssh_set_error_oom(session); + return -1; + } + SAFE_FREE(session->opts.client_trace); + session->opts.client_trace = q; + } + break; + case SSH_OPTIONS_SERVER_TRACE: + if (value == NULL) { + ssh_set_error_invalid(session); + return -1; + } else { + switch(session->type) { + case SSH_SESSION_TYPE_CLIENT: + break; + case SSH_SESSION_TYPE_SERVER: + return -1; + } + q = strdup(value); + if (q == NULL) { + ssh_set_error_oom(session); + return -1; + } + SAFE_FREE(session->opts.server_trace); + session->opts.server_trace = q; + } + break; default: ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); return -1; diff --git a/src/pki.c b/src/pki.c index 1d99ee56..c07b186f 100644 --- a/src/pki.c +++ b/src/pki.c @@ -339,7 +339,7 @@ static enum ssh_digest_e ssh_key_hash_from_name(const char *name) */ int ssh_key_algorithm_allowed(ssh_session session, const char *type) { - const char *allowed_list; + const char *allowed_list = NULL; switch(session->type) { case SSH_SESSION_TYPE_CLIENT: diff --git a/src/socket.c b/src/socket.c index 974e712a..e862584c 100644 --- a/src/socket.c +++ b/src/socket.c @@ -81,6 +81,8 @@ struct ssh_socket_struct { not block */ int write_wontblock; int data_except; + FILE *client_fp; + FILE *server_fp; enum ssh_socket_states_e state; ssh_buffer out_buffer; ssh_buffer in_buffer; @@ -156,15 +158,26 @@ ssh_socket ssh_socket_new(ssh_session session) s->in_buffer = ssh_buffer_new(); if (s->in_buffer == NULL) { ssh_set_error_oom(session); - SAFE_FREE(s); - return NULL; + goto error; } s->out_buffer=ssh_buffer_new(); if (s->out_buffer == NULL) { ssh_set_error_oom(session); - ssh_buffer_free(s->in_buffer); - SAFE_FREE(s); - return NULL; + goto error; + } + + if (session->opts.client_trace != NULL) { + s->client_fp = fopen(session->opts.client_trace, "wb"); + if (s->client_fp == NULL) { + goto error; + }; + } + + if (session->opts.server_trace != NULL) { + s->server_fp = fopen(session->opts.server_trace, "wb"); + if (s->server_fp == NULL) { + goto error; + }; } s->read_wontblock = 0; s->write_wontblock = 0; @@ -172,6 +185,10 @@ ssh_socket ssh_socket_new(ssh_session session) s->poll_handle = NULL; s->state=SSH_SOCKET_NONE; return s; +error: + ssh_socket_free(s); + + return NULL; } /** @@ -393,8 +410,16 @@ void ssh_socket_free(ssh_socket s) return; } ssh_socket_close(s); - ssh_buffer_free(s->in_buffer); - ssh_buffer_free(s->out_buffer); + + if (s->client_fp != NULL) { + fclose(s->client_fp); + } + if (s->server_fp != NULL) { + fclose(s->server_fp); + } + SSH_BUFFER_FREE(s->in_buffer); + SSH_BUFFER_FREE(s->out_buffer); + SAFE_FREE(s); } @@ -525,6 +550,18 @@ static ssize_t ssh_socket_unbuffered_read(ssh_socket s, s->data_except = 1; } + if (rc > 0) { + switch(s->session->type) { + case SSH_SESSION_TYPE_CLIENT: + if (s->server_fp != NULL) { + fwrite(buffer, rc, 1, s->server_fp); + } + break; + case SSH_SESSION_TYPE_SERVER: + break; + } + } + return rc; } @@ -557,6 +594,19 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s, s->last_errno = errno; #endif s->write_wontblock = 0; + + if (w > 0) { + switch(s->session->type) { + case SSH_SESSION_TYPE_CLIENT: + if (s->client_fp != NULL) { + fwrite(buffer, w, 1, s->client_fp); + } + break; + case SSH_SESSION_TYPE_SERVER: + break; + } + } + /* Reactive the POLLOUT detector in the poll multiplexer system */ if (s->poll_handle) { SSH_LOG(SSH_LOG_PACKET, "Enabling POLLOUT for socket"); -- cgit v1.2.3