aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) {