ikev2: reject simultaneous IKE_AUTH requests
Resolves: RHEL-89969 Signed-off-by: Ondrej Moris <omoris@redhat.com> Signed-off-by: Daiki Ueno <dueno@redhat.com>
This commit is contained in:
parent
0d7aa35ef3
commit
1a895c84df
354
libreswan-5.3-outstanding-ike-auth-crossing.patch
Normal file
354
libreswan-5.3-outstanding-ike-auth-crossing.patch
Normal file
@ -0,0 +1,354 @@
|
||||
From a671b9ce5ff86ffc31142436e9c93031083d7221 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Moris <omoris@redhat.com>
|
||||
Date: Fri, 21 Nov 2025 22:42:33 +0100
|
||||
Subject: [PATCH 1/2] Add option reject-simultaneous-ike-auth
|
||||
|
||||
Newly added option (default values is yes) decides what to
|
||||
do when IKE_AUTH request is received from the peer while having
|
||||
an outstanding IKE_AUTH request for the same connection.
|
||||
|
||||
Signed-off-by: Ondrej Moris <omoris@redhat.com>
|
||||
Signed-off-by: Andrew Cagney <cagney@gnu.org>
|
||||
---
|
||||
.../reject-simultaneous-ike-auth.xml | 21 +++++++++++++++++++
|
||||
configs/ipsec.conf.5.xml | 2 ++
|
||||
include/ipsecconf/keywords.h | 1 +
|
||||
include/whack.h | 1 +
|
||||
lib/libswan/ipsecconf/keywords.c | 1 +
|
||||
lib/libswan/ipsecconf/starterwhack.c | 1 +
|
||||
programs/pluto/connections.c | 6 ++++++
|
||||
programs/pluto/connections.h | 2 ++
|
||||
programs/whack/whack.c | 7 +++++++
|
||||
9 files changed, 42 insertions(+)
|
||||
create mode 100644 configs/d.ipsec.conf/reject-simultaneous-ike-auth.xml
|
||||
|
||||
diff --git a/configs/d.ipsec.conf/reject-simultaneous-ike-auth.xml b/configs/d.ipsec.conf/reject-simultaneous-ike-auth.xml
|
||||
new file mode 100644
|
||||
index 0000000000..7c3f68c42d
|
||||
--- /dev/null
|
||||
+++ b/configs/d.ipsec.conf/reject-simultaneous-ike-auth.xml
|
||||
@@ -0,0 +1,21 @@
|
||||
+<varlistentry>
|
||||
+ <term>
|
||||
+ <option>reject-simultaneous-ike-auth</option>
|
||||
+ </term>
|
||||
+ <listitem>
|
||||
+
|
||||
+ <para>
|
||||
+ When libreswan receives IKE_AUTH request from the peer while having
|
||||
+ an outstanding IKE_AUTH request for the same connection, reject with
|
||||
+ AUTHENTICATION_FAILED to avoid potential SA mismatch issues. This only
|
||||
+ applies to permanent IKEv2 connections so that the revival mechanism
|
||||
+ ensures connection retry.
|
||||
+ </para>
|
||||
+
|
||||
+ <para>
|
||||
+ The accepted values are <option>yes</option> (the default) or
|
||||
+ <option>no</option>.
|
||||
+ </para>
|
||||
+
|
||||
+ </listitem>
|
||||
+</varlistentry>
|
||||
diff --git a/configs/ipsec.conf.5.xml b/configs/ipsec.conf.5.xml
|
||||
index 03f04106ae..eb0f69007d 100644
|
||||
--- a/configs/ipsec.conf.5.xml
|
||||
+++ b/configs/ipsec.conf.5.xml
|
||||
@@ -25,6 +25,7 @@
|
||||
<!ENTITY accept-redirect-to SYSTEM "d.ipsec.conf/accept-redirect-to.xml">
|
||||
<!ENTITY aggressive SYSTEM "d.ipsec.conf/aggressive.xml">
|
||||
<!ENTITY ah SYSTEM "d.ipsec.conf/ah.xml">
|
||||
+<!ENTITY reject-simultaneous-ike-auth SYSTEM "d.ipsec.conf/reject-simultaneous-ike-auth.xml">
|
||||
<!ENTITY audit-log SYSTEM "d.ipsec.conf/audit-log.xml">
|
||||
<!ENTITY authby SYSTEM "d.ipsec.conf/authby.xml">
|
||||
<!ENTITY author SYSTEM "d.ipsec.conf/author.xml">
|
||||
@@ -377,6 +378,7 @@
|
||||
&failureshunt;
|
||||
&negotiationshunt;
|
||||
&debug;
|
||||
+ &reject-simultaneous-ike-auth;
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
diff --git a/include/ipsecconf/keywords.h b/include/ipsecconf/keywords.h
|
||||
index bdbc00ee98..21b5954c52 100644
|
||||
--- a/include/ipsecconf/keywords.h
|
||||
+++ b/include/ipsecconf/keywords.h
|
||||
@@ -201,6 +201,7 @@ enum config_conn_keyword {
|
||||
KWS_CISCO_SPLIT, /* send cisco unity VID */
|
||||
|
||||
KWYN_SEND_ESP_TFC_PADDING_NOT_SUPPORTED,
|
||||
+ KWYN_REJECT_SIMULTANEOUS_IKE_AUTH,
|
||||
KWYN_FAKE_STRONGSWAN, /* send strongswan VID (required for twofish/serpent) */
|
||||
KWYN_SEND_VENDORID, /* per conn sending of our own libreswan vendorid */
|
||||
KNCF_IKEPAD, /* pad IKE packets to 4 bytes */
|
||||
diff --git a/include/whack.h b/include/whack.h
|
||||
index 85f38da0aa..76d6eb2908 100644
|
||||
--- a/include/whack.h
|
||||
+++ b/include/whack.h
|
||||
@@ -409,6 +409,7 @@ struct whack_message {
|
||||
const char *priority;
|
||||
const char *tfc;
|
||||
enum yn_options send_esp_tfc_padding_not_supported;
|
||||
+ enum yn_options reject_simultaneous_ike_auth;
|
||||
|
||||
enum yn_options iptfs;
|
||||
enum yn_options iptfs_fragmentation;
|
||||
diff --git a/lib/libswan/ipsecconf/keywords.c b/lib/libswan/ipsecconf/keywords.c
|
||||
index 1e42bf2a4a..6c662a9688 100644
|
||||
--- a/lib/libswan/ipsecconf/keywords.c
|
||||
+++ b/lib/libswan/ipsecconf/keywords.c
|
||||
@@ -162,6 +162,7 @@ static const struct keyword_def config_conn_keyword[] = {
|
||||
|
||||
K("initial-contact", LEMPTY, kt_sparse_name, KWYN_INITIAL_CONTACT, .sparse_names = &yn_option_names),
|
||||
K("send-esp-tfc-padding-not-supported", LEMPTY, kt_sparse_name, KWYN_SEND_ESP_TFC_PADDING_NOT_SUPPORTED, .sparse_names = &yn_option_names),
|
||||
+ K("reject-simultaneous-ike-auth", LEMPTY, kt_sparse_name, KWYN_REJECT_SIMULTANEOUS_IKE_AUTH, .sparse_names = &yn_option_names),
|
||||
|
||||
K("iptfs", LEMPTY, kt_sparse_name, KWYN_IPTFS, .sparse_names = &yn_option_names),
|
||||
K("iptfs-fragmentation", LEMPTY, kt_sparse_name, KWYN_IPTFS_FRAGMENTATION, .sparse_names = &yn_option_names),
|
||||
diff --git a/lib/libswan/ipsecconf/starterwhack.c b/lib/libswan/ipsecconf/starterwhack.c
|
||||
index 0e09a8e8d5..9a73769c15 100644
|
||||
--- a/lib/libswan/ipsecconf/starterwhack.c
|
||||
+++ b/lib/libswan/ipsecconf/starterwhack.c
|
||||
@@ -232,6 +232,7 @@ int starter_whack_add_conn(const char *ctlsocket,
|
||||
conn->values[KWYN_SEND_ESP_TFC_PADDING_NOT_SUPPORTED].option;
|
||||
msg.nflog_group = conn->values[KWS_NFLOG_GROUP].string;
|
||||
msg.reqid = conn->values[KWS_REQID].string;
|
||||
+ msg.reject_simultaneous_ike_auth = conn->values[KWYN_REJECT_SIMULTANEOUS_IKE_AUTH].option;
|
||||
|
||||
if (conn->values[KNCF_TCP_REMOTEPORT].set) {
|
||||
msg.tcp_remoteport = conn->values[KNCF_TCP_REMOTEPORT].option;
|
||||
diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
|
||||
index e949f56ebd..ca98dfb1e9 100644
|
||||
--- a/programs/pluto/connections.c
|
||||
+++ b/programs/pluto/connections.c
|
||||
@@ -4894,6 +4894,12 @@ static diag_t extract_connection(const struct whack_message *wm,
|
||||
wm->send_esp_tfc_padding_not_supported,
|
||||
YN_NO, wm, c->logger);
|
||||
|
||||
+ if (wm->reject_simultaneous_ike_auth && ike_version < IKEv2) {
|
||||
+ return diag("cannot specify reject-simultaneous-ike-auth for IKEv1");
|
||||
+ }
|
||||
+ config->reject_simultaneous_ike_auth = extract_yn("", "reject-simultaneous-ike-auth",
|
||||
+ wm->reject_simultaneous_ike_auth, /*value_when_unset*/YN_YES, wm, c->logger);
|
||||
+
|
||||
/*
|
||||
* Since security labels use the same REQID for everything,
|
||||
* pre-assign it.
|
||||
diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
|
||||
index 0910fc9930..cd9cb331b6 100644
|
||||
--- a/programs/pluto/connections.h
|
||||
+++ b/programs/pluto/connections.h
|
||||
@@ -431,6 +431,8 @@ struct config {
|
||||
uint32_t id;
|
||||
} ipsec_interface;
|
||||
|
||||
+ bool reject_simultaneous_ike_auth;
|
||||
+
|
||||
struct end_config end[END_ROOF];
|
||||
};
|
||||
|
||||
diff --git a/programs/whack/whack.c b/programs/whack/whack.c
|
||||
index a5a95045bf..5e47e009b8 100644
|
||||
--- a/programs/whack/whack.c
|
||||
+++ b/programs/whack/whack.c
|
||||
@@ -111,6 +111,7 @@ static void help(void)
|
||||
" [--mtu <mtu>] \\\n"
|
||||
" [--priority <prio>] [--reqid <reqid>] \\\n"
|
||||
" [--tfc <size>] [--send-esp-tfc-padding-not-supported] \\\n"
|
||||
+ " [--reject-simultaneous-ike-auth] \\\n"
|
||||
" [--iptfs[={yes,no}] \\\n"
|
||||
" [--iptfs-fragmentation[={yes,no}]] \\\n"
|
||||
" [--iptfs-packet-size <size>] \\\n"
|
||||
@@ -516,6 +517,7 @@ enum opt {
|
||||
CD_PRIORITY,
|
||||
CD_TFC,
|
||||
CD_SEND_ESP_TFC_PADDING_NOT_SUPPORTED,
|
||||
+ CD_REJECT_SIMULTANEOUS_IKE_AUTH,
|
||||
CD_PFS,
|
||||
CD_REQID,
|
||||
CD_NFLOG_GROUP,
|
||||
@@ -898,6 +900,7 @@ const struct option optarg_options[] = {
|
||||
{ "tfc\0", required_argument, NULL, CD_TFC },
|
||||
{ "send-esp-tfc-padding-not-supported\0yes|no", optional_argument, NULL, CD_SEND_ESP_TFC_PADDING_NOT_SUPPORTED },
|
||||
{ "send-no-esp-tfc\0", no_argument, NULL, CD_SEND_ESP_TFC_PADDING_NOT_SUPPORTED },
|
||||
+ { "reject-simultaneous-ike-auth\0yes|no", optional_argument, NULL, CD_REJECT_SIMULTANEOUS_IKE_AUTH },
|
||||
{ "pfs\0", optional_argument, NULL, CD_PFS },
|
||||
{ "reqid\01-65535", required_argument, NULL, CD_REQID },
|
||||
#ifdef USE_NFLOG
|
||||
@@ -2085,6 +2088,10 @@ int main(int argc, char **argv)
|
||||
optarg_yn(logger, YN_YES);
|
||||
continue;
|
||||
|
||||
+ case CD_REJECT_SIMULTANEOUS_IKE_AUTH: /* --reject-simultaneous-ike-auth */
|
||||
+ msg.reject_simultaneous_ike_auth = optarg_yn(logger, YN_YES);
|
||||
+ continue;
|
||||
+
|
||||
case CD_PFS: /* --pfs */
|
||||
msg.pfs = optarg_yn(logger, YN_YES);
|
||||
continue;
|
||||
--
|
||||
2.52.0
|
||||
|
||||
|
||||
From 6d1d06ef085cbdfdfeb24f677cec9d4540db2903 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Moris <omoris@redhat.com>
|
||||
Date: Fri, 21 Nov 2025 22:42:33 +0100
|
||||
Subject: [PATCH 2/2] ikev2: reject simultaneous IKE_AUTH requests
|
||||
|
||||
If initiator has another IKE SA with IKE_AUTH request
|
||||
outstanding for the same permanent connection then send
|
||||
AUTHENTICATION_FAILED instead of IKE_AUTH response for this
|
||||
IKE_AUTH request and terminate current IKE SA. This is to
|
||||
prevent potential crossing streams scenario.
|
||||
|
||||
This is now the default behavior and can be disabled by
|
||||
a connection option reject-simultaneous-ike-auth.
|
||||
|
||||
Signed-off-by: Ondrej Moris <omoris@redhat.com>
|
||||
---
|
||||
programs/pluto/ikev2_auth.c | 53 +++++++++++++++++++++++++++++++++
|
||||
programs/pluto/ikev2_auth.h | 3 ++
|
||||
programs/pluto/ikev2_child.c | 13 ++++++++
|
||||
programs/pluto/ikev2_ike_auth.c | 15 +++++++++-
|
||||
4 files changed, 83 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/programs/pluto/ikev2_auth.c b/programs/pluto/ikev2_auth.c
|
||||
index 6e89bce58b..2e1b6df655 100644
|
||||
--- a/programs/pluto/ikev2_auth.c
|
||||
+++ b/programs/pluto/ikev2_auth.c
|
||||
@@ -1044,3 +1044,56 @@ lset_t proposed_v2AUTH(struct ike_sa *ike,
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * Check if a given permanent connection has another IKE SA with
|
||||
+ * IKE_AUTH request outstanding. This is useful to detect potential
|
||||
+ * IKE_AUTH crossing streams scenarios.
|
||||
+ */
|
||||
+bool has_outstanding_ike_auth_request(const struct connection *c,
|
||||
+ const struct ike_sa *ike,
|
||||
+ const struct msg_digest *md)
|
||||
+{
|
||||
+ /* Check can be disabled in a connection config */
|
||||
+ if (!c->config->reject_simultaneous_ike_auth) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Connection must be permanent and request must be incoming */
|
||||
+ if (v2_msg_role(md) != MESSAGE_REQUEST || !is_permanent(c)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ struct state_filter sf = {
|
||||
+ .connection_serialno = c->serialno,
|
||||
+ .search = {
|
||||
+ .order = NEW2OLD,
|
||||
+ .verbose.logger = ike->sa.logger,
|
||||
+ .where = HERE,
|
||||
+ },
|
||||
+ };
|
||||
+
|
||||
+ while (next_state(&sf)) {
|
||||
+ if (!IS_IKE_SA(sf.st)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ struct ike_sa *simultaneous_ike = pexpect_ike_sa(sf.st);
|
||||
+ if (simultaneous_ike == NULL || simultaneous_ike == ike) {
|
||||
+ continue;
|
||||
+ } else if (simultaneous_ike->sa.st_sa_role != SA_INITIATOR) {
|
||||
+ continue;
|
||||
+ } else if (!v2_msgid_request_outstanding(simultaneous_ike)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ const struct v2_exchange *outstanding_request =
|
||||
+ simultaneous_ike->sa.st_v2_msgid_windows.initiator.exchange;
|
||||
+ if (outstanding_request != NULL && outstanding_request->type == ISAKMP_v2_IKE_AUTH) {
|
||||
+ llog(RC_LOG, ike->sa.logger, "IKE SA "PRI_SO" has outstanding IKE_AUTH request",
|
||||
+ pri_so(simultaneous_ike->sa.st_serialno));
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
diff --git a/programs/pluto/ikev2_auth.h b/programs/pluto/ikev2_auth.h
|
||||
index 13ee71c36d..d616534507 100644
|
||||
--- a/programs/pluto/ikev2_auth.h
|
||||
+++ b/programs/pluto/ikev2_auth.h
|
||||
@@ -85,4 +85,7 @@ struct crypt_mac v2_remote_id_hash(const struct ike_sa *ike, const char *why,
|
||||
|
||||
lset_t proposed_v2AUTH(struct ike_sa *ike, struct msg_digest *md);
|
||||
|
||||
+bool has_outstanding_ike_auth_request(const struct connection *c,
|
||||
+ const struct ike_sa *ike,
|
||||
+ const struct msg_digest *md);
|
||||
#endif
|
||||
diff --git a/programs/pluto/ikev2_child.c b/programs/pluto/ikev2_child.c
|
||||
index 49aaff98a2..5b2c0d7028 100644
|
||||
--- a/programs/pluto/ikev2_child.c
|
||||
+++ b/programs/pluto/ikev2_child.c
|
||||
@@ -66,6 +66,7 @@
|
||||
#include "ikev2_parent.h"
|
||||
#include "ikev2_states.h"
|
||||
#include "ikev2_notification.h"
|
||||
+#include "ikev2_auth.h"
|
||||
#include "iface.h"
|
||||
#include "nat_traversal.h"
|
||||
|
||||
@@ -1029,6 +1030,18 @@ static v2_notification_t process_v2_IKE_AUTH_request_child_sa_payloads(struct ik
|
||||
ldbg_sa(child, "skipping TS processing, mainly to stop tests failing but rumored to cause connection flips?!?");
|
||||
}
|
||||
|
||||
+ /* It is possible that Child SA switched to permanent connection
|
||||
+ * where initiator has IKE SA with IKE_AUTH request outstanding,
|
||||
+ * in that case send AUTHENTICATION_FAILED and terminate this IKE SA.
|
||||
+ * This is to prevent potential crossing streams scenario for
|
||||
+ * IKE AUTH exchange.
|
||||
+ */
|
||||
+ if (has_outstanding_ike_auth_request(child->sa.st_connection, ike, md)) {
|
||||
+ record_v2N_response(ike->sa.logger, ike, md, v2N_AUTHENTICATION_FAILED,
|
||||
+ empty_shunk, ENCRYPTED_PAYLOAD);
|
||||
+ return v2N_AUTHENTICATION_FAILED;
|
||||
+ }
|
||||
+
|
||||
n = process_childs_v2SA_payload("IKE_AUTH responder matching remote ESP/AH proposals",
|
||||
ike, child, md,
|
||||
child->sa.st_connection->config->child_sa.v2_ike_auth_proposals,
|
||||
diff --git a/programs/pluto/ikev2_ike_auth.c b/programs/pluto/ikev2_ike_auth.c
|
||||
index ba5aeace88..08f7c79739 100644
|
||||
--- a/programs/pluto/ikev2_ike_auth.c
|
||||
+++ b/programs/pluto/ikev2_ike_auth.c
|
||||
@@ -674,6 +674,20 @@ stf_status process_v2_IKE_AUTH_request_standard_payloads(struct ike_sa *ike, str
|
||||
return STF_FATAL;
|
||||
}
|
||||
|
||||
+ const struct connection *c = ike->sa.st_connection;
|
||||
+
|
||||
+ /* If initiator has another IKE SA with IKE_AUTH request
|
||||
+ * outstanding for the same permanent connection then send
|
||||
+ * AUTHENTICATION_FAILED instead of IKE_AUTH response for this
|
||||
+ * IKE_AUTH request and terminate current IKE SA. This is to
|
||||
+ * prevent potential crossing streams scenario.
|
||||
+ */
|
||||
+ if (has_outstanding_ike_auth_request(c, ike, md)) {
|
||||
+ record_v2N_response(ike->sa.logger, ike, md, v2N_AUTHENTICATION_FAILED,
|
||||
+ empty_shunk, ENCRYPTED_PAYLOAD);
|
||||
+ return STF_FATAL;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* This both decodes the initiator's ID and, when necessary,
|
||||
* switches connection based on that ID.
|
||||
@@ -682,7 +696,6 @@ stf_status process_v2_IKE_AUTH_request_standard_payloads(struct ike_sa *ike, str
|
||||
* switch based on the contents of the CERTREQ.
|
||||
*/
|
||||
|
||||
- const struct connection *c = ike->sa.st_connection;
|
||||
bool found_ppk = false;
|
||||
|
||||
/*
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -45,6 +45,7 @@ Source5: https://download.libreswan.org/cavs/ikev2.fax.bz2
|
||||
%endif
|
||||
|
||||
Patch1: libreswan-4.15-ipsec_import.patch
|
||||
Patch2: libreswan-5.3-outstanding-ike-auth-crossing.patch
|
||||
|
||||
BuildRequires: audit-libs-devel
|
||||
BuildRequires: bison
|
||||
|
||||
Loading…
Reference in New Issue
Block a user