1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-29 01:03:57 +03:00

options.c: Add support for openssh config +,-,^

These features allow for options Ciphers, HostKeyAlgorithms, KexAlgorithms and
MACs to append, remove and prepend to the default list of algorithms
respectively

Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Norbert Pocs
2022-11-07 13:13:20 +01:00
committed by Jakub Jelen
parent 039d1b2775
commit 01e9341d10
3 changed files with 161 additions and 89 deletions

View File

@@ -29,7 +29,8 @@ int ssh_config_parse_file(ssh_session session, const char *filename);
int ssh_config_parse_string(ssh_session session, const char *input); int ssh_config_parse_string(ssh_session session, const char *input);
int ssh_options_set_algo(ssh_session session, int ssh_options_set_algo(ssh_session session,
enum ssh_kex_types_e algo, enum ssh_kex_types_e algo,
const char *list); const char *list,
char **place);
int ssh_options_apply(ssh_session session); int ssh_options_apply(ssh_session session);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -221,15 +221,31 @@ int ssh_options_copy(ssh_session src, ssh_session *dest)
int ssh_options_set_algo(ssh_session session, int ssh_options_set_algo(ssh_session session,
enum ssh_kex_types_e algo, enum ssh_kex_types_e algo,
const char *list) const char *list,
char **place)
{ {
char *p = NULL; /* When the list start with +,-,^ the filtration of unknown algorithms
* gets handled inside the helper functions, otherwise the list is taken
* as it is. */
char *p = (char *)list;
if (algo < SSH_COMP_C_S) {
if (list[0] == '+') {
p = ssh_add_to_default_algos(algo, list+1);
} else if (list[0] == '-') {
p = ssh_remove_from_default_algos(algo, list+1);
} else if (list[0] == '^') {
p = ssh_prefix_default_algos(algo, list+1);
}
}
if (p == list) {
if (ssh_fips_mode()) { if (ssh_fips_mode()) {
p = ssh_keep_fips_algos(algo, list); p = ssh_keep_fips_algos(algo, list);
} else { } else {
p = ssh_keep_known_algos(algo, list); p = ssh_keep_known_algos(algo, list);
} }
}
if (p == NULL) { if (p == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
@@ -238,8 +254,8 @@ int ssh_options_set_algo(ssh_session session,
return -1; return -1;
} }
SAFE_FREE(session->opts.wanted_methods[algo]); SAFE_FREE(*place);
session->opts.wanted_methods[algo] = p; *place = p;
return 0; return 0;
} }
@@ -356,34 +372,60 @@ int ssh_options_set_algo(ssh_session session,
* *
* - SSH_OPTIONS_CIPHERS_C_S: * - SSH_OPTIONS_CIPHERS_C_S:
* Set the symmetric cipher client to server (const char *, * Set the symmetric cipher client to server (const char *,
* comma-separated list). * comma-separated list). The list can be prepended by +,-,^
* which can append, remove or move to the beginning
* (prioritizing) of the default list respectively. Giving an
* empty list after + and ^ will cause error.
* *
* - SSH_OPTIONS_CIPHERS_S_C: * - SSH_OPTIONS_CIPHERS_S_C:
* Set the symmetric cipher server to client (const char *, * Set the symmetric cipher server to client (const char *,
* comma-separated list). * comma-separated list). The list can be prepended by +,-,^
* which can append, remove or move to the beginning
* (prioritizing) of the default list respectively. Giving an
* empty list after + and ^ will cause error.
* *
* - SSH_OPTIONS_KEY_EXCHANGE: * - SSH_OPTIONS_KEY_EXCHANGE:
* Set the key exchange method to be used (const char *, * Set the key exchange method to be used (const char *,
* comma-separated list). ex: * comma-separated list). ex:
* "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" * "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
* The list can be prepended by +,-,^ which will append,
* remove or move to the beginning (prioritizing) of the
* default list respectively. Giving an empty list
* after + and ^ will cause error.
* *
* - SSH_OPTIONS_HMAC_C_S: * - SSH_OPTIONS_HMAC_C_S:
* Set the Message Authentication Code algorithm client to server * Set the Message Authentication Code algorithm client to server
* (const char *, comma-separated list). * (const char *, comma-separated list). The list can be
* prepended by +,-,^ which will append, remove or move to
* the beginning (prioritizing) of the default list
* respectively. Giving an empty list after + and ^ will
* cause error.
* *
* - SSH_OPTIONS_HMAC_S_C: * - SSH_OPTIONS_HMAC_S_C:
* Set the Message Authentication Code algorithm server to client * Set the Message Authentication Code algorithm server to client
* (const char *, comma-separated list). * (const char *, comma-separated list). The list can be
* prepended by +,-,^ which will append, remove or move to
* the beginning (prioritizing) of the default list
* respectively. Giving an empty list after + and ^ will
* cause error.
* *
* - SSH_OPTIONS_HOSTKEYS: * - SSH_OPTIONS_HOSTKEYS:
* Set the preferred server host key types (const char *, * Set the preferred server host key types (const char *,
* comma-separated list). ex: * comma-separated list). ex:
* "ssh-rsa,ssh-dss,ecdh-sha2-nistp256" * "ssh-rsa,ssh-dss,ecdh-sha2-nistp256". The list can be
* prepended by +,-,^ which will append, remove or move to
* the beginning (prioritizing) of the default list
* respectively. Giving an empty list after + and ^ will
* cause error.
* *
* - SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES: * - SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES:
* Set the preferred public key algorithms to be used for * Set the preferred public key algorithms to be used for
* authentication (const char *, comma-separated list). ex: * authentication (const char *, comma-separated list). ex:
* "ssh-rsa,rsa-sha2-256,ssh-dss,ecdh-sha2-nistp256" * "ssh-rsa,rsa-sha2-256,ssh-dss,ecdh-sha2-nistp256"
* The list can be prepended by +,-,^ which will append,
* remove or move to the beginning (prioritizing) of the
* default list respectively. Giving an empty list
* after + and ^ will cause error.
* *
* - SSH_OPTIONS_COMPRESSION_C_S: * - SSH_OPTIONS_COMPRESSION_C_S:
* Set the compression to use for client to server * Set the compression to use for client to server
@@ -501,6 +543,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
long int i; long int i;
unsigned int u; unsigned int u;
int rc; int rc;
char **wanted_methods = session->opts.wanted_methods;
if (session == NULL) { if (session == NULL) {
return -1; return -1;
@@ -784,7 +827,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_options_set_algo(session, SSH_CRYPT_C_S, v) < 0) rc = ssh_options_set_algo(session,
SSH_CRYPT_C_S,
v,
&wanted_methods[SSH_CRYPT_C_S]);
if (rc < 0)
return -1; return -1;
} }
break; break;
@@ -794,7 +841,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_options_set_algo(session, SSH_CRYPT_S_C, v) < 0) rc = ssh_options_set_algo(session,
SSH_CRYPT_S_C,
v,
&wanted_methods[SSH_CRYPT_S_C]);
if (rc < 0)
return -1; return -1;
} }
break; break;
@@ -804,7 +855,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_options_set_algo(session, SSH_KEX, v) < 0) rc = ssh_options_set_algo(session,
SSH_KEX,
v,
&wanted_methods[SSH_KEX]);
if (rc < 0)
return -1; return -1;
} }
break; break;
@@ -814,7 +869,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_options_set_algo(session, SSH_HOSTKEYS, v) < 0) rc = ssh_options_set_algo(session,
SSH_HOSTKEYS,
v,
&wanted_methods[SSH_HOSTKEYS]);
if (rc < 0)
return -1; return -1;
} }
break; break;
@@ -824,21 +883,13 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_fips_mode()) { rc = ssh_options_set_algo(session,
p = ssh_keep_fips_algos(SSH_HOSTKEYS, v); SSH_HOSTKEYS,
} else { v,
p = ssh_keep_known_algos(SSH_HOSTKEYS, v); &session->opts.pubkey_accepted_types);
} if (rc < 0)
if (p == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Setting method: no known public key algorithm (%s)",
v);
return -1; return -1;
} }
SAFE_FREE(session->opts.pubkey_accepted_types);
session->opts.pubkey_accepted_types = p;
}
break; break;
case SSH_OPTIONS_HMAC_C_S: case SSH_OPTIONS_HMAC_C_S:
v = value; v = value;
@@ -846,7 +897,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_options_set_algo(session, SSH_MAC_C_S, v) < 0) rc = ssh_options_set_algo(session,
SSH_MAC_C_S,
v,
&wanted_methods[SSH_MAC_C_S]);
if (rc < 0)
return -1; return -1;
} }
break; break;
@@ -856,7 +911,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
if (ssh_options_set_algo(session, SSH_MAC_S_C, v) < 0) rc = ssh_options_set_algo(session,
SSH_MAC_S_C,
v,
&wanted_methods[SSH_MAC_S_C]);
if (rc < 0)
return -1; return -1;
} }
break; break;
@@ -866,16 +925,18 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
const char *tmp = v;
if (strcasecmp(value, "yes") == 0){ if (strcasecmp(value, "yes") == 0){
if(ssh_options_set_algo(session,SSH_COMP_C_S,"zlib@openssh.com,zlib,none") < 0) tmp = "zlib@openssh.com,zlib,none";
return -1;
} else if (strcasecmp(value, "no") == 0){ } else if (strcasecmp(value, "no") == 0){
if(ssh_options_set_algo(session,SSH_COMP_C_S,"none,zlib@openssh.com,zlib") < 0) tmp = "none,zlib@openssh.com,zlib";
return -1;
} else {
if (ssh_options_set_algo(session, SSH_COMP_C_S, v) < 0)
return -1;
} }
rc = ssh_options_set_algo(session,
SSH_COMP_C_S,
tmp,
&wanted_methods[SSH_COMP_C_S]);
if (rc < 0)
return -1;
} }
break; break;
case SSH_OPTIONS_COMPRESSION_S_C: case SSH_OPTIONS_COMPRESSION_S_C:
@@ -884,16 +945,19 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session); ssh_set_error_invalid(session);
return -1; return -1;
} else { } else {
const char *tmp = v;
if (strcasecmp(value, "yes") == 0){ if (strcasecmp(value, "yes") == 0){
if(ssh_options_set_algo(session,SSH_COMP_S_C,"zlib@openssh.com,zlib,none") < 0) tmp = "zlib@openssh.com,zlib,none";
return -1;
} else if (strcasecmp(value, "no") == 0){ } else if (strcasecmp(value, "no") == 0){
if(ssh_options_set_algo(session,SSH_COMP_S_C,"none,zlib@openssh.com,zlib") < 0) tmp = "none,zlib@openssh.com,zlib";
return -1;
} else {
if (ssh_options_set_algo(session, SSH_COMP_S_C, v) < 0)
return -1;
} }
rc = ssh_options_set_algo(session,
SSH_COMP_S_C,
tmp,
&wanted_methods[SSH_COMP_S_C]);
if (rc < 0)
return -1;
} }
break; break;
case SSH_OPTIONS_COMPRESSION: case SSH_OPTIONS_COMPRESSION:
@@ -1618,26 +1682,12 @@ ssh_bind_set_key(ssh_bind sshbind, char **key_loc, const void *value)
static int ssh_bind_set_algo(ssh_bind sshbind, static int ssh_bind_set_algo(ssh_bind sshbind,
enum ssh_kex_types_e algo, enum ssh_kex_types_e algo,
const char *list) const char *list,
char **place)
{ {
char *p = NULL; /* sshbind is needed only for ssh_set_error which takes void*
* the typecast is only to satisfy function parameter type */
if (ssh_fips_mode()) { return ssh_options_set_algo((ssh_session)sshbind, algo, list, place);
p = ssh_keep_fips_algos(algo, list);
} else {
p = ssh_keep_known_algos(algo, list);
}
if (p == NULL) {
ssh_set_error(sshbind, SSH_REQUEST_DENIED,
"Setting method: no algorithm for method \"%s\" (%s)",
ssh_kex_get_description(algo), list);
return -1;
}
SAFE_FREE(sshbind->wanted_methods[algo]);
sshbind->wanted_methods[algo] = p;
return 0;
} }
/** /**
@@ -1779,6 +1829,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
char *p, *q; char *p, *q;
const char *v; const char *v;
int i, rc; int i, rc;
char **wanted_methods = sshbind->wanted_methods;
if (sshbind == NULL) { if (sshbind == NULL) {
return -1; return -1;
@@ -2028,9 +2079,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
if (ssh_bind_set_algo(sshbind, SSH_CRYPT_C_S, v) < 0) rc = ssh_bind_set_algo(sshbind,
SSH_CRYPT_C_S,
v,
&wanted_methods[SSH_CRYPT_C_S]);
if (rc < 0) {
return -1; return -1;
} }
}
break; break;
case SSH_BIND_OPTIONS_CIPHERS_S_C: case SSH_BIND_OPTIONS_CIPHERS_S_C:
v = value; v = value;
@@ -2038,9 +2094,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
if (ssh_bind_set_algo(sshbind, SSH_CRYPT_S_C, v) < 0) rc = ssh_bind_set_algo(sshbind,
SSH_CRYPT_S_C,
v,
&wanted_methods[SSH_CRYPT_S_C]);
if (rc < 0) {
return -1; return -1;
} }
}
break; break;
case SSH_BIND_OPTIONS_KEY_EXCHANGE: case SSH_BIND_OPTIONS_KEY_EXCHANGE:
v = value; v = value;
@@ -2048,7 +2109,10 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
rc = ssh_bind_set_algo(sshbind, SSH_KEX, v); rc = ssh_bind_set_algo(sshbind,
SSH_KEX,
v,
&wanted_methods[SSH_KEX]);
if (rc < 0) { if (rc < 0) {
return -1; return -1;
} }
@@ -2060,9 +2124,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
if (ssh_bind_set_algo(sshbind, SSH_MAC_C_S, v) < 0) rc = ssh_bind_set_algo(sshbind,
SSH_MAC_C_S,
v,
&wanted_methods[SSH_MAC_C_S]);
if (rc < 0) {
return -1; return -1;
} }
}
break; break;
case SSH_BIND_OPTIONS_HMAC_S_C: case SSH_BIND_OPTIONS_HMAC_S_C:
v = value; v = value;
@@ -2070,9 +2139,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
if (ssh_bind_set_algo(sshbind, SSH_MAC_S_C, v) < 0) rc = ssh_bind_set_algo(sshbind,
SSH_MAC_S_C,
v,
&wanted_methods[SSH_MAC_S_C]);
if (rc < 0) {
return -1; return -1;
} }
}
break; break;
case SSH_BIND_OPTIONS_CONFIG_DIR: case SSH_BIND_OPTIONS_CONFIG_DIR:
v = value; v = value;
@@ -2096,20 +2170,13 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
if (ssh_fips_mode()) { rc = ssh_bind_set_algo(sshbind,
p = ssh_keep_fips_algos(SSH_HOSTKEYS, v); SSH_HOSTKEYS,
} else { v,
p = ssh_keep_known_algos(SSH_HOSTKEYS, v); &sshbind->pubkey_accepted_key_types);
} if (rc < 0) {
if (p == NULL) {
ssh_set_error(sshbind, SSH_REQUEST_DENIED,
"Setting method: no known public key algorithm (%s)",
v);
return -1; return -1;
} }
SAFE_FREE(sshbind->pubkey_accepted_key_types);
sshbind->pubkey_accepted_key_types = p;
} }
break; break;
case SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS: case SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
@@ -2118,7 +2185,10 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind); ssh_set_error_invalid(sshbind);
return -1; return -1;
} else { } else {
rc = ssh_bind_set_algo(sshbind, SSH_HOSTKEYS, v); rc = ssh_bind_set_algo(sshbind,
SSH_HOSTKEYS,
v,
&wanted_methods[SSH_HOSTKEYS]);
if (rc < 0) { if (rc < 0) {
return -1; return -1;
} }

View File

@@ -160,7 +160,8 @@ int server_set_kex(ssh_session session)
rc = ssh_options_set_algo(session, rc = ssh_options_set_algo(session,
SSH_HOSTKEYS, SSH_HOSTKEYS,
kept); kept,
&session->opts.wanted_methods[SSH_HOSTKEYS]);
SAFE_FREE(kept); SAFE_FREE(kept);
if (rc < 0) { if (rc < 0) {
return -1; return -1;