Provide a way to skip unsupported ML-KEM hybrid algorithms in FIPS mode

Resolves: RHEL-151580
This commit is contained in:
Dmitry Belyavskiy 2026-02-25 14:04:45 +01:00
parent 9b2158d190
commit 08d29bf220
2 changed files with 109 additions and 2 deletions

View File

@ -0,0 +1,101 @@
diff -up openssh-9.9p1/compat.c.xxx openssh-9.9p1/compat.c
--- openssh-9.9p1/compat.c.xxx 2026-02-25 12:58:14.083760269 +0100
+++ openssh-9.9p1/compat.c 2026-02-25 13:28:21.154300255 +0100
@@ -36,6 +36,9 @@
#include "compat.h"
#include "log.h"
#include "match.h"
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/fips.h>
/* determine bug flags from SSH protocol banner */
void
@@ -143,13 +145,40 @@ compat_banner(struct ssh *ssh, const cha
ssh->compat |= SSH_RH_RSASIGSHA;
}
+/*
+ * 0 - unavailable
+ * 1 - available in non-FIPS mode
+ * 2 - available always
+ */
+static int is_mlkem768_available()
+{
+ static int is_fetched = -1;
+
+ if (is_fetched == -1) {
+ EVP_KEM *mlkem768 = NULL;
+
+ ERR_set_mark();
+ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL);
+ is_fetched = (mlkem768 == NULL) ? 0 : 2;
+ if (is_fetched == 0 && FIPS_mode() == 1) {
+ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", "provider=default,-fips");
+ is_fetched = (mlkem768 == NULL) ? 0 : 1;
+ }
+ EVP_KEM_free(mlkem768);
+ ERR_pop_to_mark();
+ }
+
+ return is_fetched;
+}
+
/* Always returns pointer to allocated memory, caller must free. */
char *
compat_kex_proposal(struct ssh *ssh, const char *p)
{
char *cp = NULL, *cp2 = NULL;
+ int ml_kem_available = is_mlkem768_available();
- if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
+ if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0 && is_mlkem768_available() == 2)
return xstrdup(p);
debug2_f("original KEX proposal: %s", p);
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
@@ -164,6 +199,25 @@ compat_kex_proposal(struct ssh *ssh, con
free(cp);
cp = cp2;
}
+ if (ml_kem_available == 2)
+ return cp ? cp : xstrdup(p);
+ if (ml_kem_available == 1 && FIPS_mode()) {
+ if ((cp2 = match_filter_denylist(cp ? cp : p,
+ "mlkem768x25519-sha256")) == NULL)
+ fatal("match_filter_denylist failed");
+ free(cp);
+ cp = cp2;
+ }
+ if (ml_kem_available == 0) {
+ if ((cp2 = match_filter_denylist(cp ? cp : p,
+ "mlkem768x25519-sha256,"
+ "mlkem768nistp256-sha256,"
+ "mlkem1024nistp384-sha384")) == NULL)
+ fatal("match_filter_denylist failed");
+ free(cp);
+ cp = cp2;
+ }
+
if (cp == NULL || *cp == '\0')
fatal("No supported key exchange algorithms found");
debug2_f("compat KEX proposal: %s", cp);
diff -up openssh-9.9p1/kex-names.c.xxx openssh-9.9p1/kex-names.c
--- openssh-9.9p1/kex-names.c.xxx 2026-02-25 14:52:59.802597974 +0100
+++ openssh-9.9p1/kex-names.c 2026-02-25 15:31:13.376020525 +0100
@@ -291,8 +291,14 @@ kex_names_valid(const char *names)
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
if (kex_alg_by_name(p) == NULL) {
- if (FIPS_mode())
- error("\"%.100s\" is not allowed in FIPS mode", p);
+ if (FIPS_mode()) {
+ if ((strcmp(p, KEX_MLKEM768X25519_SHA256) == 0)) {
+ debug("\"%.100s\" is not allowed in FIPS mode", p);
+ continue;
+ }
+ else
+ error("\"%.100s\" is not allowed in FIPS mode", p);
+ }
else
error("Unsupported KEX algorithm \"%.100s\"", p);
free(s);

View File

@ -47,9 +47,9 @@
# Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1
%global openssh_ver 9.9p1
%global openssh_rel 3
%global openssh_rel 4
%global pam_ssh_agent_ver 0.10.4
%global pam_ssh_agent_rel 6
%global pam_ssh_agent_rel 7
Summary: An open source implementation of SSH protocol version 2
Name: openssh
@ -244,6 +244,7 @@ Patch1036: openssh-9.9p1-canonical-match-user.patch
Patch1037: openssh-9.9p1-reject-cntrl-chars-in-username.patch
# upstream 43b3bff47bb029f2299bacb6a36057981b39fdb0
Patch1038: openssh-9.9p1-reject-null-char-in-url-string.patch
Patch1039: openssh-9.9p1-compat-mlkem.patch
License: BSD
Requires: /sbin/nologin
@ -458,6 +459,7 @@ popd
%patch1036 -p1 -b .canonical-match-user
%patch1037 -p1 -b .reject-cntrl-chars-in-username
%patch1038 -p1 -b .reject-null-char-in-url-string
%patch1039 -p1 -b .skip-mlkem-when-na
autoreconf
pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}
@ -746,6 +748,10 @@ test -f %{sysconfig_anaconda} && \
%endif
%changelog
* Wed Feb 25 2026 Dmitry Belyavskiy <dbelyavs@redhat.com> - 9.9p1-4
- Provide a way to skip unsupported ML-KEM hybrid algorithms in FIPS mode
Resolves: RHEL-151580
* Tue Dec 09 2025 Zoltan Fridrich <zfridric@redhat.com> - 9.9p1-3
- Enable support for DSA keys
Resolves: RHEL-127624