From 41b4d50e52d151ac4eafcd30a39a1ddeaaa4bddb Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Tue, 10 May 2022 08:37:52 +0200 Subject: [PATCH] Allow limiting RSA Key size also for server Thanks to Harry Sintonen from WithSecure for pointing this out. Signed-off-by: Jakub Jelen Reviewed-by: Andreas Schneider --- include/libssh/bind.h | 1 + include/libssh/server.h | 1 + src/bind.c | 2 ++ src/options.c | 61 +++++++++++++++++++++++++++++++++++++++++ src/pki.c | 37 +++++++++++++++---------- 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/include/libssh/bind.h b/include/libssh/bind.h index 94256d4a..86f4d03a 100644 --- a/include/libssh/bind.h +++ b/include/libssh/bind.h @@ -51,6 +51,7 @@ struct ssh_bind_struct { char *config_dir; char *pubkey_accepted_key_types; char* moduli_file; + unsigned int rsa_min_size; }; struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct diff --git a/include/libssh/server.h b/include/libssh/server.h index 1c18b38c..0e8412f7 100644 --- a/include/libssh/server.h +++ b/include/libssh/server.h @@ -57,6 +57,7 @@ enum ssh_bind_options_e { SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, SSH_BIND_OPTIONS_PROCESS_CONFIG, SSH_BIND_OPTIONS_MODULI, + SSH_BIND_OPTIONS_RSA_MIN_SIZE, }; typedef struct ssh_bind_struct* ssh_bind; diff --git a/src/bind.c b/src/bind.c index 54508391..6e1a926d 100644 --- a/src/bind.c +++ b/src/bind.c @@ -503,6 +503,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){ } } + session->opts.rsa_min_size = sshbind->rsa_min_size; + ssh_socket_free(session->socket); session->socket = ssh_socket_new(session); if (session->socket == NULL) { diff --git a/src/options.c b/src/options.c index 395ff39f..9e09703c 100644 --- a/src/options.c +++ b/src/options.c @@ -32,6 +32,7 @@ #include #endif #include +#include "libssh/pki_priv.h" #include "libssh/priv.h" #include "libssh/session.h" #include "libssh/misc.h" @@ -1524,6 +1525,20 @@ int ssh_options_apply(ssh_session session) { /** @} */ #ifdef WITH_SERVER +static bool ssh_bind_key_size_allowed(ssh_bind sshbind, ssh_key key) +{ + int min_size = 0; + + switch (ssh_key_type(key)) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA_CERT01: + min_size = sshbind->rsa_min_size; + return ssh_key_size_allowed_rsa(min_size, key); + default: + return true; + } +} + /** * @addtogroup libssh_server * @{ @@ -1683,6 +1698,17 @@ static int ssh_bind_set_algo(ssh_bind sshbind, * Set the path to the moduli file. Defaults to * /etc/ssh/moduli if not specified (const char *). * + * - SSH_BIND_OPTIONS_RSA_MIN_SIZE + * Set the minimum RSA key size in bits to be accepted by + * the server for both authentication and hostkey + * operations. The values under 768 bits are not accepted + * even with this configuration option as they are + * considered completely broken. Setting 0 will revert + * the value to defaults. + * Default is 1024 bits or 2048 bits in FIPS mode. + * (unsigned int) + * + * * @param value The value to set. This is a generic pointer and the * datatype which should be used is described at the * corresponding value of type above. @@ -1692,6 +1718,7 @@ static int ssh_bind_set_algo(ssh_bind sshbind, int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, const void *value) { + bool allowed; char *p, *q; const char *v; int i, rc; @@ -1715,6 +1742,16 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, if (rc != SSH_OK) { return -1; } + allowed = ssh_bind_key_size_allowed(sshbind, key); + if (!allowed) { + ssh_set_error(sshbind, + SSH_FATAL, + "The host key size %d is too small.", + ssh_key_size(key)); + ssh_key_free(key); + return -1; + } + key_type = ssh_key_type(key); switch (key_type) { case SSH_KEYTYPE_DSS: @@ -1780,6 +1817,15 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, ssh_key *bind_key_loc = NULL; ssh_key key = (ssh_key)value; + allowed = ssh_bind_key_size_allowed(sshbind, key); + if (!allowed) { + ssh_set_error(sshbind, + SSH_FATAL, + "The host key size %d is too small.", + ssh_key_size(key)); + return -1; + } + key_type = ssh_key_type(key); switch (key_type) { case SSH_KEYTYPE_DSS: @@ -2043,6 +2089,21 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, } } break; + case SSH_BIND_OPTIONS_RSA_MIN_SIZE: + if (value == NULL) { + ssh_set_error_invalid(sshbind); + return -1; + } else { + unsigned int *x = (unsigned int *)value; + if (*x > 0 && *x < 768) { + ssh_set_error(sshbind, SSH_REQUEST_DENIED, + "The provided value (%u) for minimal RSA key " + "size is too small. Use at least 768 bits.", *x); + return -1; + } + sshbind->rsa_min_size = *x; + } + break; default: ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); return -1; diff --git a/src/pki.c b/src/pki.c index 773a427f..6d47a499 100644 --- a/src/pki.c +++ b/src/pki.c @@ -404,6 +404,20 @@ int ssh_key_algorithm_allowed(ssh_session session, const char *type) return ssh_match_group(allowed_list, type); } +bool ssh_key_size_allowed_rsa(int min_size, ssh_key key) +{ + int key_size = ssh_key_size(key); + + if (min_size < 768) { + if (ssh_fips_mode()) { + min_size = 2048; + } else { + min_size = 1024; + } + } + return (key_size >= min_size); +} + /** * @brief Check the given key is acceptable in regards to the key size policy * specified by the configuration @@ -414,24 +428,13 @@ int ssh_key_algorithm_allowed(ssh_session session, const char *type) */ bool ssh_key_size_allowed(ssh_session session, ssh_key key) { - int key_size = ssh_key_size(key); int min_size = 0; - switch (key->type) { + switch (ssh_key_type(key)) { case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA_CERT01: min_size = session->opts.rsa_min_size; - if (min_size < 768) { - if (ssh_fips_mode()) { - min_size = 2048; - } else { - min_size = 1024; - } - } - if (key_size < min_size) { - return false; - } - /* fall through */ + return ssh_key_size_allowed_rsa(min_size, key); default: return true; } @@ -2704,7 +2707,7 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session, const enum ssh_digest_e digest) { struct ssh_crypto_struct *crypto = NULL; - + bool allowed; ssh_signature sig = NULL; ssh_string sig_blob = NULL; @@ -2716,6 +2719,12 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session, return NULL; } + allowed = ssh_key_size_allowed(session, privkey); + if (!allowed) { + ssh_set_error(session, SSH_FATAL, "The hostkey size too small"); + return NULL; + } + crypto = session->next_crypto ? session->next_crypto : session->current_crypto;