From 22c5e6c7472d8f2d74603a0f28dfe3a9a7794a73 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 7 Feb 2024 15:29:56 +0000 Subject: [PATCH] Apply random patches from some unknown source --- include/libssh/libssh.h | 5 +++ include/libssh/pki.h | 2 +- include/libssh/session.h | 1 + include/libssh/socket.h | 1 + src/options.c | 9 +++++ src/pki.c | 80 ++++++++++++++++++++++++++++++++++++++++ src/pki_crypto.c | 11 ++++-- src/session.c | 3 +- src/socket.c | 16 ++++++-- 9 files changed, 120 insertions(+), 8 deletions(-) diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index 1664dfce..d914efef 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -400,6 +400,7 @@ enum ssh_options_e { SSH_OPTIONS_PROCESS_CONFIG, SSH_OPTIONS_REKEY_DATA, SSH_OPTIONS_REKEY_TIME, + SSH_OPTIONS_OWNS_SOCKET, }; enum { @@ -653,6 +654,7 @@ LIBSSH_API int ssh_key_is_private(const ssh_key k); LIBSSH_API int ssh_key_cmp(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what); +LIBSSH_API ssh_key ssh_key_dup(const ssh_key key); LIBSSH_API int ssh_pki_generate(enum ssh_keytypes_e type, int parameter, ssh_key *pkey); @@ -822,6 +824,9 @@ LIBSSH_API uint32_t ssh_buffer_get_data(ssh_buffer buffer, void *data, uint32_t LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer); LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer); +LIBSSH_API int pki_sign_string(ssh_key privkey, ssh_string input, ssh_string* output); +LIBSSH_API int pki_verify_string(ssh_key pubkey, ssh_string sig_blob, ssh_string input); + #ifndef LIBSSH_LEGACY_0_4 #include "libssh/legacy.h" #endif diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 2fa7582c..2ff3a6bd 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -101,7 +101,6 @@ struct ssh_signature_struct { typedef struct ssh_signature_struct *ssh_signature; /* SSH Key Functions */ -ssh_key ssh_key_dup(const ssh_key key); void ssh_key_clean (ssh_key key); const char * @@ -111,6 +110,7 @@ enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name); enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type); enum ssh_digest_e ssh_key_type_to_hash(ssh_session session, enum ssh_keytypes_e type); +enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type); enum ssh_digest_e ssh_key_hash_from_name(const char *name); #define is_ecdsa_key_type(t) \ diff --git a/include/libssh/session.h b/include/libssh/session.h index 64e118ef..447d2cb6 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -244,6 +244,7 @@ struct ssh_session_struct { uint8_t options_seen[SOC_MAX]; uint64_t rekey_data; uint32_t rekey_time; + bool owns_socket; } opts; /* counters */ ssh_counter socket_counter; diff --git a/include/libssh/socket.h b/include/libssh/socket.h index 5e345c68..9d7f98c0 100644 --- a/include/libssh/socket.h +++ b/include/libssh/socket.h @@ -34,6 +34,7 @@ ssh_socket ssh_socket_new(ssh_session session); void ssh_socket_reset(ssh_socket s); void ssh_socket_free(ssh_socket s); void ssh_socket_set_fd(ssh_socket s, socket_t fd); +int ssh_socket_owns_fd(ssh_socket s); socket_t ssh_socket_get_fd(ssh_socket s); #ifndef _WIN32 int ssh_socket_unix(ssh_socket s, const char *path); diff --git a/src/options.c b/src/options.c index b5f951ac..6d4a07af 100644 --- a/src/options.c +++ b/src/options.c @@ -484,6 +484,15 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type, } switch (type) { + case SSH_OPTIONS_OWNS_SOCKET: + if (value == NULL) { + ssh_set_error_invalid(session); + return -1; + } else { + bool *x = (bool *)value; + session->opts.owns_socket = *x; + } + break; case SSH_OPTIONS_HOST: v = value; if (v == NULL || v[0] == '\0') { diff --git a/src/pki.c b/src/pki.c index 932abf2c..a8e62686 100644 --- a/src/pki.c +++ b/src/pki.c @@ -2304,6 +2304,86 @@ ssh_signature pki_do_sign(const ssh_key privkey, return pki_sign_data(privkey, hash_type, input, input_len); } +enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type) +{ + switch (type) { + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_DSS: + return SSH_DIGEST_SHA1; + case SSH_KEYTYPE_RSA_CERT01: + case SSH_KEYTYPE_RSA: + return SSH_DIGEST_SHA512; + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_ECDSA_P256: + return SSH_DIGEST_SHA256; + case SSH_KEYTYPE_ECDSA_P384_CERT01: + case SSH_KEYTYPE_ECDSA_P384: + return SSH_DIGEST_SHA384; + case SSH_KEYTYPE_ECDSA_P521_CERT01: + case SSH_KEYTYPE_ECDSA_P521: + return SSH_DIGEST_SHA512; + case SSH_KEYTYPE_ED25519_CERT01: + case SSH_KEYTYPE_ED25519: + return SSH_DIGEST_AUTO; + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + default: + SSH_LOG(SSH_LOG_WARN, "Digest algorithm to be used with key type %u " + "is not defined", type); + } + + /* We should never reach this */ + return SSH_DIGEST_AUTO; +} + +int pki_sign_string(ssh_key privkey, ssh_string input, ssh_string* output) +{ + enum ssh_digest_e hash_type = key_type_to_hash(privkey->type); + int rc; + ssh_signature sig = pki_do_sign(privkey, ssh_string_data(input), ssh_string_len(input), hash_type); + if (sig == NULL) { + return SSH_ERROR; + } + rc = ssh_pki_export_signature_blob(sig, output); + ssh_signature_free(sig); + return rc; +} + +int pki_verify_string(ssh_key pubkey, ssh_string sig_blob, ssh_string input) +{ + int rc; + ssh_signature sig; + rc = ssh_pki_import_signature_blob(sig_blob, pubkey, &sig); + if (rc != SSH_OK) { + return rc; + } + SSH_LOG(SSH_LOG_FUNCTIONS, + "Going to verify a %s type signature", + sig->type_c); + + if (pubkey->type != sig->type) { + SSH_LOG(SSH_LOG_WARN, + "Can not verify %s signature with %s key", + sig->type_c, pubkey->type_c); + rc = SSH_ERROR; + goto end; + } + + /* Check if public key and hash type are compatible */ + rc = pki_key_check_hash_compatible(pubkey, sig->hash_type); + if (rc != SSH_OK) { + rc = SSH_ERROR; + goto end; + } + + rc = pki_verify_data_signature(sig, pubkey, ssh_string_data(input), ssh_string_len(input)); +end: + ssh_signature_free(sig); + return rc; + +} + /* * This function signs the session id as a string then * the content of sigbuf */ diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 1edae351..fc5047e8 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -1373,7 +1373,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key) return NULL; } - +#ifdef HAVE_DSA static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig) { char buffer[40] = { 0 }; @@ -1459,6 +1459,7 @@ static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig) SSH_STRING_FREE(s); return NULL; } +#endif static ssh_string pki_ecdsa_signature_to_blob(const ssh_signature sig) { @@ -1552,9 +1553,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) ssh_string sig_blob = NULL; switch(sig->type) { +#ifdef HAVE_DSA case SSH_KEYTYPE_DSS: sig_blob = pki_dsa_signature_to_blob(sig); break; +#endif case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: sig_blob = ssh_string_copy(sig->raw_sig); @@ -1646,7 +1649,7 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey, SSH_STRING_FREE(sig_blob_padded); return SSH_ERROR; } - +#ifdef HAVE_DSA static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey), const ssh_string sig_blob, ssh_signature sig) @@ -1773,7 +1776,7 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey), DSA_SIG_free(dsa_sig); return SSH_ERROR; } - +#endif static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey), const ssh_string sig_blob, ssh_signature sig) @@ -1938,12 +1941,14 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, sig->hash_type = hash_type; switch(type) { +#ifdef HAVE_DSA case SSH_KEYTYPE_DSS: rc = pki_signature_from_dsa_blob(pubkey, sig_blob, sig); if (rc != SSH_OK) { goto error; } break; +#endif case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: rc = pki_signature_from_rsa_blob(pubkey, sig_blob, sig); diff --git a/src/session.c b/src/session.c index 3199096a..c6aad08c 100644 --- a/src/session.c +++ b/src/session.c @@ -108,6 +108,7 @@ ssh_session ssh_new(void) session->opts.StrictHostKeyChecking = 1; session->opts.port = 0; session->opts.fd = -1; + session->opts.owns_socket = true; session->opts.compressionlevel = 7; session->opts.nodelay = 0; @@ -1039,7 +1040,7 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) /** * @brief Deallocate the hash obtained by ssh_get_pubkey_hash. * - * This is required under Microsoft platform as this library might use a + * This is required under Microsoft platform as this library might use a * different C library than your software, hence a different heap. * * @param[in] hash The buffer to deallocate. diff --git a/src/socket.c b/src/socket.c index 2fef8e7e..3c33888d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -78,6 +78,7 @@ enum ssh_socket_states_e { struct ssh_socket_struct { socket_t fd; int fd_is_socket; + int owns_fd; int last_errno; int read_wontblock; /* reading now on socket will not block */ @@ -155,6 +156,10 @@ ssh_socket ssh_socket_new(ssh_session session) return NULL; } s->fd = SSH_INVALID_SOCKET; + if (session->opts.owns_socket) + s->owns_fd = 1; + else + s->owns_fd = 0; s->last_errno = -1; s->fd_is_socket = 1; s->session = session; @@ -446,7 +451,7 @@ int ssh_socket_unix(ssh_socket s, const char *path) */ void ssh_socket_close(ssh_socket s) { - if (ssh_socket_is_open(s)) { + if (ssh_socket_is_open(s) && ssh_socket_owns_fd(s)) { #ifdef _WIN32 CLOSE_SOCKET(s->fd); s->last_errno = WSAGetLastError(); @@ -511,6 +516,11 @@ void ssh_socket_set_fd(ssh_socket s, socket_t fd) } } +int ssh_socket_owns_fd(ssh_socket s) +{ + return s->owns_fd; +} + /** \internal * \brief returns the input file descriptor of the socket */ @@ -842,7 +852,7 @@ int ssh_socket_connect(ssh_socket s, const char *bind_addr) { socket_t fd; - + if (s->state != SSH_SOCKET_NONE) { ssh_set_error(s->session, SSH_FATAL, "ssh_socket_connect called on socket not unconnected"); @@ -854,7 +864,7 @@ int ssh_socket_connect(ssh_socket s, return SSH_ERROR; } ssh_socket_set_fd(s,fd); - + return SSH_OK; }