aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2019-05-22 18:33:14 +0200
committerAndreas Schneider <asn@cryptomilk.org>2019-06-12 11:13:52 +0200
commit54d76098edda33a2b526e8eae069992abc470bb6 (patch)
treeafeaf652d3afc1e939f99da366d97da5b937ef61
parent56041dc7840ade64b16c9c299bd64504daa79599 (diff)
downloadlibssh-54d76098edda33a2b526e8eae069992abc470bb6.tar.gz
libssh-54d76098edda33a2b526e8eae069992abc470bb6.tar.xz
libssh-54d76098edda33a2b526e8eae069992abc470bb6.zip
kex, pki, server, options: Filter algorithms in FIPS mode
When in FIPS mode, filter the algorithms to enable only the allowed ones. If any algorithm is explicitly set through options or configuration file, they are kept. Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--include/libssh/kex.h2
-rw-r--r--src/kex.c82
-rw-r--r--src/options.c27
-rw-r--r--src/pki.c25
-rw-r--r--src/server.c15
5 files changed, 137 insertions, 14 deletions
diff --git a/include/libssh/kex.h b/include/libssh/kex.h
index 19a67c81..3a1f4a6f 100644
--- a/include/libssh/kex.h
+++ b/include/libssh/kex.h
@@ -39,11 +39,13 @@ int ssh_set_client_kex(ssh_session session);
int ssh_kex_select_methods(ssh_session session);
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
+char *ssh_keep_fips_algos(enum ssh_kex_types_e algo, const char *list);
char **ssh_space_tokenize(const char *chain);
int ssh_get_kex1(ssh_session session);
char *ssh_find_matching(const char *in_d, const char *what_d);
const char *ssh_kex_get_supported_method(uint32_t algo);
const char *ssh_kex_get_default_methods(uint32_t algo);
+const char *ssh_kex_get_fips_methods(uint32_t algo);
const char *ssh_kex_get_description(uint32_t algo);
char *ssh_client_select_hostkeys(ssh_session session);
int ssh_send_rekex(ssh_session session);
diff --git a/src/kex.c b/src/kex.c
index 321187d9..d24237c1 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -136,11 +136,55 @@
#define KEY_EXCHANGE_SUPPORTED \
GEX_SHA1 \
KEY_EXCHANGE
+
#define KEX_METHODS_SIZE 10
/* RFC 8308 */
#define KEX_EXTENSION_CLIENT "ext-info-c"
+/* Allowed algorithms in FIPS mode */
+#define FIPS_ALLOWED_CIPHERS "aes256-gcm@openssh.com,"\
+ "aes256-ctr,"\
+ "aes256-cbc,"\
+ "aes128-gcm@openssh.com,"\
+ "aes128-ctr,"\
+ "aes128-cbc"
+
+#define FIPS_ALLOWED_PUBLIC_KEY_ALGORITHMS "ecdsa-sha2-nistp521,"\
+ "ecdsa-sha2-nistp384,"\
+ "ecdsa-sha2-nistp256,"\
+ "rsa-sha2-512,"\
+ "rsa-sha2-256"
+
+#define FIPS_ALLOWED_KEX "ecdh-sha2-nistp256,"\
+ "ecdh-sha2-nistp384,"\
+ "ecdh-sha2-nistp521,"\
+ "diffie-hellman-group-exchange-sha256,"\
+ "diffie-hellman-group16-sha512,"\
+ "diffie-hellman-group18-sha512"
+
+#define FIPS_ALLOWED_MACS "hmac-sha2-256-etm@openssh.com,"\
+ "hmac-sha1-etm@openssh.com,"\
+ "hmac-sha2-512-etm@openssh.com,"\
+ "hmac-sha2-256,"\
+ "hmac-sha1,"\
+ "hmac-sha2-512"
+
+/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
+static const char *fips_methods[] = {
+ FIPS_ALLOWED_KEX,
+ FIPS_ALLOWED_PUBLIC_KEY_ALGORITHMS,
+ FIPS_ALLOWED_CIPHERS,
+ FIPS_ALLOWED_CIPHERS,
+ FIPS_ALLOWED_MACS,
+ FIPS_ALLOWED_MACS,
+ ZLIB,
+ ZLIB,
+ "",
+ "",
+ NULL
+};
+
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
static const char *default_methods[] = {
KEY_EXCHANGE,
@@ -211,6 +255,14 @@ const char *ssh_kex_get_description(uint32_t algo) {
return ssh_kex_descriptions[algo];
}
+const char *ssh_kex_get_fips_methods(uint32_t algo) {
+ if (algo >= KEX_METHODS_SIZE) {
+ return NULL;
+ }
+
+ return fips_methods[algo];
+}
+
/**
* @internal
* @brief returns whether the first client key exchange algorithm or
@@ -600,8 +652,13 @@ int ssh_set_client_kex(ssh_session session)
for (i = 0; i < KEX_METHODS_SIZE; i++) {
wanted = session->opts.wanted_methods[i];
- if (wanted == NULL)
- wanted = default_methods[i];
+ if (wanted == NULL) {
+ if (ssh_fips_mode()) {
+ wanted = fips_methods[i];
+ } else {
+ wanted = default_methods[i];
+ }
+ }
client->methods[i] = strdup(wanted);
if (client->methods[i] == NULL) {
ssh_set_error_oom(session);
@@ -823,6 +880,27 @@ char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list)
return ssh_find_all_matching(supported_methods[algo], list);
}
+/**
+ * @internal
+ *
+ * @brief Return a new allocated string containing only the FIPS allowed
+ * algorithms from the list.
+ *
+ * @param[in] algo The type of the methods to filter
+ * @param[in] list The list to be filtered
+ *
+ * @return A new allocated list containing only the FIPS allowed algorithms from
+ * the list; NULL in case of error.
+ */
+char *ssh_keep_fips_algos(enum ssh_kex_types_e algo, const char *list)
+{
+ if (algo > SSH_LANG_S_C) {
+ return NULL;
+ }
+
+ return ssh_find_all_matching(fips_methods[algo], list);
+}
+
int ssh_make_sessionid(ssh_session session)
{
ssh_string num = NULL;
diff --git a/src/options.c b/src/options.c
index 9af7b22b..672735a4 100644
--- a/src/options.c
+++ b/src/options.c
@@ -223,10 +223,15 @@ int ssh_options_set_algo(ssh_session session,
{
char *p = NULL;
- p = ssh_keep_known_algos(algo, list);
+ if (ssh_fips_mode()) {
+ p = ssh_keep_fips_algos(algo, list);
+ } else {
+ p = ssh_keep_known_algos(algo, list);
+ }
+
if (p == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED,
- "Setting method: no algorithm for method \"%s\" (%s)",
+ "Setting method: no allowed algorithm for method \"%s\" (%s)",
ssh_kex_get_description(algo), list);
return -1;
}
@@ -796,7 +801,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session);
return -1;
} else {
- p = ssh_keep_known_algos(SSH_HOSTKEYS, v);
+ if (ssh_fips_mode()) {
+ p = ssh_keep_fips_algos(SSH_HOSTKEYS, v);
+ } else {
+ p = ssh_keep_known_algos(SSH_HOSTKEYS, v);
+ }
if (p == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Setting method: no known public key algorithm (%s)",
@@ -1503,7 +1512,11 @@ static int ssh_bind_set_algo(ssh_bind sshbind,
{
char *p = NULL;
- p = ssh_keep_known_algos(algo, list);
+ if (ssh_fips_mode()) {
+ 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)",
@@ -1938,7 +1951,11 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
ssh_set_error_invalid(sshbind);
return -1;
} else {
- p = ssh_keep_known_algos(SSH_HOSTKEYS, v);
+ if (ssh_fips_mode()) {
+ p = ssh_keep_fips_algos(SSH_HOSTKEYS, v);
+ } else {
+ p = ssh_keep_known_algos(SSH_HOSTKEYS, v);
+ }
if (p == NULL) {
ssh_set_error(sshbind, SSH_REQUEST_DENIED,
"Setting method: no known public key algorithm (%s)",
diff --git a/src/pki.c b/src/pki.c
index a65e8a48..d49eaa19 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -323,7 +323,11 @@ int ssh_key_algorithm_allowed(ssh_session session, const char *type)
if (session->client) {
allowed_list = session->opts.pubkey_accepted_types;
if (allowed_list == NULL) {
- allowed_list = ssh_kex_get_default_methods(SSH_HOSTKEYS);
+ if (ssh_fips_mode()) {
+ allowed_list = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
+ } else {
+ allowed_list = ssh_kex_get_default_methods(SSH_HOSTKEYS);
+ }
}
}
#ifdef WITH_SERVER
@@ -2111,13 +2115,26 @@ int pki_key_check_hash_compatible(ssh_key key,
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_DSS:
if (hash_type == SSH_DIGEST_SHA1) {
- return SSH_OK;
+ if (ssh_fips_mode()) {
+ SSH_LOG(SSH_LOG_WARN, "SHA1 is not allowed in FIPS mode");
+ return SSH_ERROR;
+ } else {
+ return SSH_OK;
+ }
}
break;
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_RSA:
- if (hash_type == SSH_DIGEST_SHA1 ||
- hash_type == SSH_DIGEST_SHA256 ||
+ if (hash_type == SSH_DIGEST_SHA1) {
+ if (ssh_fips_mode()) {
+ SSH_LOG(SSH_LOG_WARN, "SHA1 is not allowed in FIPS mode");
+ return SSH_ERROR;
+ } else {
+ return SSH_OK;
+ }
+ }
+
+ if (hash_type == SSH_DIGEST_SHA256 ||
hash_type == SSH_DIGEST_SHA512)
{
return SSH_OK;
diff --git a/src/server.c b/src/server.c
index 1fb68118..f5a12bdf 100644
--- a/src/server.c
+++ b/src/server.c
@@ -142,7 +142,11 @@ int server_set_kex(ssh_session session)
if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
allowed = session->opts.wanted_methods[SSH_HOSTKEYS];
} else {
- allowed = ssh_kex_get_default_methods(SSH_HOSTKEYS);
+ if (ssh_fips_mode()) {
+ allowed = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
+ } else {
+ allowed = ssh_kex_get_default_methods(SSH_HOSTKEYS);
+ }
}
/* It is expected for the list of allowed hostkeys to be ordered by
@@ -163,8 +167,13 @@ int server_set_kex(ssh_session session)
}
for (i = 0; i < 10; i++) {
- if ((wanted = session->opts.wanted_methods[i]) == NULL) {
- wanted = ssh_kex_get_default_methods(i);
+ wanted = session->opts.wanted_methods[i];
+ if (wanted == NULL) {
+ if (ssh_fips_mode()) {
+ wanted = ssh_kex_get_fips_methods(i);
+ } else {
+ wanted = ssh_kex_get_default_methods(i);
+ }
}
server->methods[i] = strdup(wanted);
if (server->methods[i] == NULL) {