As the previous issue, this can be triggered via IKEv1 CERT payloads.
Fixes: d7aa09104f ("Implement PKCS#7 enveloped-data parsing and decryption")
Fixes: CVE-2026-35329
Can be triggered via empty PKCS#7 encrypted content in IKEv1 CERT payload.
Fixes: 4076e3ee91 ("Extract PKCS#5 handling from pkcs8 plugin to separate helper class")
Fixes: CVE-2026-35329
If the extension doesn't contain a multiple of two bytes, the previous
code would get stuck in an infinite loop as `remaining()` continued to
return TRUE while `read_uint16()` failed to parse a value. Initiating
several connections with such an extension allows a DoS attack as no
threads would eventually be available to handle packets/events.
Fixes: 7fbe2e27ec ("tls-server: TLS 1.3 support for TLS server implementation")
Fixes: CVE-2026-35328
There is an issue similar to the one fixed with the previous commit when
using directoryName (DN) name constraints. Some RDNs have to be matched
in a case-insensitive manner, which we e.g. do in
`identification.c::rdn_equals`. By not doing it for name constraints,
a malicious intermediate CA could evade an excluded name constraint
just by modifying the case in such an RDN.
While we could use the mentioned function in `dn_matches`, this doesn't
properly fix the problem because the function is basically too strict.
Especially in regards to RDNs of type UTF8String, which are only compared
binary. To match these properly, we'd have to implement the string
preparation described in RFC 5280, section 7.1 and the referenced RFCs.
Until that's the case, we reject excluded name constraints of type
directoryName as we are unable to enforce them.
Fixes: a2b340764f ("Implemented NameConstraint matching in constraints plugin")
Fixes: CVE-2026-35331
The case is generally ignored when matching such identities. So this is
an issue with excluded name constraints where a malicious intermediate
CA could evade the constraints by issuing certificates with names that
just modify the case (e.g. strongSwan.org instead strongswan.org).
Note that it's likely that permitted name constraints are preferred over
excluded name constraints as it might be difficult to come up with a
conclusive list of names to exclude.
Fixes: a2b340764f ("Implemented NameConstraint matching in constraints plugin")
Fixes: CVE-2026-35331
This prevents a crash due to a null-pointer dereference when processing
an empty ECDH public key.
The previous length check only applied in the `!ec` case, so in the `ec`
case, the access to `pub.ptr[0]` was unguarded. If a crafted TLS
record ends with an empty ClientKeyExchange, then `read_data8` sets
`pub` to `chunk_empty`, causing a null-pointer dereference.
Note that if some data follows the empty ClientKeyExchange, this just
causes a 1-byte out-of-bounds read that has no further effect as the
TLS session is aborted immediately. Either because the read value
doesn't equal TLS_ANSI_UNCOMPRESSED or because the empty public key
is rejected by `set_public_key()`.
The referenced commit that introduced the pointer access, added the
check for `pub.len` specifically to the `!ec` case, while the pointer
access was initially unconditional (probably because the code was just
copied from `tls_peer.c` which processes ECDH public keys in a separate
function, so there was no `ec` flag). The latter was fixed a couple of
days later with 7b3c01845f ("Read the compression type byte for EC
groups, only"). However, that commit didn't change the length check.
Anyway, it's possible that the original intention was to add the check
to the `ec` case on the previous line, or that there was some confusion
with the parenthesis and something like the current code was intended to
begin with.
Fixes: e6cce7ff0d ("Prepend point format to ECDH public key")
Fixes: CVE-2026-35332
These are quite a bit faster than on AppVeyor (with ccache about a fifth,
without less than half - and they run concurrently).
We only keep the AppVeyor builds for now to test against those old
OpenSSL versions (1.1.1 and 1.0.2) for which there is still extended
support available. Even simplified like that they still take longer
than the builds on GA.
This reduces the cache storage for active branches and since caches for
different branches are separate and we abort previous builds of the same
branch, this is not necessary to ensure caches can successfully be stored.
We are still too close to the limit of 1 hour (at least with the 2019
image and the 2022 image is about the same), so reduce the build time by
not building libimcv natively, which saves about 10 minutes.
Also, only build against OpenSSL 1.0.2 (on the 2017 image) and 1.1.1 (on
the 2019 image) as these are the only versions for which OpenSSL provides
extended support.
wolfSSL 5.9.1 starts to enforce a minimum (and maximum) length for the
hash when signing. Since we'll always require SHA-1, use 20 bytes as
input in the tests to succeed with SIGN_ECDSA_WITH_NULL.
All the plugins are linked statically into the binaries, so there
is no reason to set the directories that are only required when loading
them from files.
The pa_tnc fuzzer does not rely on any plugins and the pb_tnc fuzzer is
a bit special in that it does use code from the tnccs-20 plugin, but that
doesn't actually have to be loaded as such. The fuzzer directly calls
statically linked code from the plugin.
The `cipher_suites` field has a 16-bit length field, so up to 32k 2-byte
cipher suites could technically be proposed. With `tls_cipher_suite_t`
typically being 4 bytes wide, the necessary allocation for the temporary
array can be up to 128 KiB. Even though this should be fine on typical
systems, we avoid potentially overflowing the stack by using malloc()
instead of alloca().
These certificate requests also contain SHA-1 hashes, which is assumed
in `ike_cert_pre.c::process_certreq()` when enumerating key IDs.
Because the parser allocates a separate chunk for the data and the
enumerator doesn't read beyond that chunk's length after the first
iteration, only lengths between 1 and 19 are problematic (0 doesn't
cause an enumeration because chunk_empty is assigned).
Whether the OOB read then can cause a segmentation fault depends on the
allocator, its alignment rules, and its minimum overhead. For instance,
with glibc on a typical 64-bit system (8 bytes for pointers and size_t),
the alignment is 16 bytes and the minimum allocated size is 32 bytes,
with typically 24 that are technically available for data, even if only
0 bytes are allocated (as returned by `malloc_usable_size()`). So with
an allocation between 1 and 19, we can always safely read 20 bytes.
Assuming that other allocators behave similar for small allocations, it
seems unlikely that this causes a crash.
Fixes: 15612b3a42 ("Add support for IKEv2 OCSP extensions (RFC 4806)")
`xmlNodeGetContent()` returns `NULL` if `child` is `NULL`, which causes
a segmentation fault in `chunk_from_str()`.
Fixes: ec1eab0319 ("fixed XML parsing of TNCCS 1.1 ReasonString message")
The RFC only allows that the number of fragments increases (if the
sender reduces the MTU).
Not enforcing this before could cause early reassembly as the trigger was
that the number of received fragments matches the total count of the
current packet (which was a bit weird anyway). Only an active MITM could
trigger this as individual fragments are encrypted and authenticated.
This mainly intended as defense-in-depth measure to avoid parsing
massively nested structures that could cause a call stack overflow due
to the massive recursion. In particular PKCS#7 signed data is prone to
this as these can be nested basically infinitely. When used in IKEv1 via
ENC_PKCS7_WRAPPED_X509 CERT payloads, our default of 10000 bytes for IKE
messages guards against this, but that's configurable and there might be
a chance for some bug that triggers problematic recursive parsing for
smaller input.
The upper limit is chosen arbitrarily, but there are currently no known
cases that require a depth of more than 10 levels.
If nothing was read from the message, the previous code could result in
a crash depending on where `ext.ptr` pointed to, as determined by the
current stack contents. Since TLS 1.3 is still disabled by default and
this is usually used for TLS-based EAP methods after validating the
IKEv2 server's certificate, the real world impact seems relatively low.
Fixes: 9ef46cfaf9 ("tls-peer: Mutual authentication support for TLS 1.3")
These attributes contain a 16-bit length field for the actual length of
the data in bits or bytes, as compared to the length in 4-byte blocks in
the attribute header. The previous code didn't correctly account for the
length of the fixed header (4 bytes) when it compared the parsed length
to the length in the header. This could cause an out-of-bounds read of
up to four bytes beyond the end of the attribute/message.
Fixes: f8330d0395 ("Added a libsimaka library with shared message handling code for EAP-SIM/AKA")
The length field in the AVP header includes the 8 bytes of the header
itself. Not checking for that and later subtracting it causes an
integer underflow that usually triggers a crash when accessing a
NULL pointer that resulted from the failing chunk_alloc() call because
of the high value.
The attempted allocations for invalid lengths (0-7) are 0xfffffff8,
0xfffffffc, or 0x100000000 (0 on 32-bit hosts), so this doesn't result
in a buffer overflow even if the allocation succeeds.
Fixes: 79f2102cb4 ("implemented server side support for EAP-TTLS")
Fixes: CVE-2026-25075
To make the default strongswan.conf, with `load_modular` enabled, work
if charon itself is not built, we enable generating the charon-specific
snippets also for the two other daemons that fall back on reading
options from the `charon` section.
VICI_END (7) shouldn't be encoded in a message. However, if we encounter
it, we should at least set `out` accordingly so callers can abort the
enumeration. By not doing so previously and returning TRUE, callers
might access the possibly uninitialized name/value arguments passed to
the enumerator.
This ensures that we don't load a key with e=1, which basically renders
RSA into a no-op. Since keys are universally generated with e=65537 and
no reputable CA will sign keys with e=1, allowing this before didn't have
any real world impact.
This doesn't really seem useful (perhaps it was before we started to
configure the outbound interface on our routes). And it can actually
cause the route installation to fail e.g. for routes over point-to-point
interfaces where we'd get "Error: Nexthop has invalid gateway" errors.
Note that we can't return NULL if we find an interface as e.g. the updown
plugin uses this method to determine the outbound interface (it ignores
the nexthop), which it passes to the script. If we returned NULL, it
would pass "unknown" instead, which would cause the firewall rules to
mismatch. While it seems that 0.0.0.0/:: is ignored as nexthop by the
kernel on the installed route, I still explicitly ignore such addresses
to avoid any unintended side-effects.
The automatic route installation in the ikev2/shunt-manual-prio scenario
had to be disabled on the clients. The reason is that the route in table
220 won't have a nexthop set (the peers are directly connected), so when
trying to reach alice or venus via SSH, which matches the port-specific
bypass policies for which we don't install throw routes, the hosts will
do ARP requests for the target IPs instead of routing the packets via
moon.
Closesstrongswan/strongswan#2548
The action causes errors because it is not compatible to the Docker
version used in the runner images. Unfortunately, it doesn't seem
maintained anymore. The action is simple enough, though, so instead of
switching to a fork, we just use "docker run" directly.
Adds support for ICMP error forwarding that the kernel supports properly
since v6.9 (it still sends locally generated errors from the wrong source
IP, though).
While 3c12905103 ("ipsec: Add function to compare two ipsec_sa_cfg_t
instances") added a comparison function to avoid issues with non-zeroed
padding, hashes were still calculated using chunk_hash().
Uses a separate default plugin list for swanctl (instead of just loading
all of libstrongswan's plugins) to avoid some side-effects of loaded but
unused plugins. The load statements in the regression tests have been
updated accordingly.
A new configure option for maintainers of distributions that ship
plugins in separate packages changes the message if a plugin is not
found and reduces its log level. This confused users of tools that don't
use modular plugin loading (e.g. pki or swanctl).
Also changes command line handling in pki and swanctl so that the shared
options can be passed before the actual command and that the debug level
also affects library/plugin initialization.
References strongswan/strongswan#2971
Similarly to the previous commit for pki, this allows setting these
options before the command, and by pre-parsing them we can see log
messages during the initialization.
This allows setting the log level before initializing the library and
loading the plugins, as well as having the top-level command itself in
an options file.
Distributions like Debian/Ubuntu ship the plugins in multiple packages
that are not all installed by default. When running tools like pki or
swanctl, which don't use modular loading with config snippets by default,
there are errors in the output if these packages and plugins are
currently not available. In order to not alarm users, this change adds
a configure option that package maintainers can use. It causes the log
level of the message to increase and also adds a note that mentions that
plugins are potentially available in other packages (which should be the
case unless the user tried to load a plugin, e.g. via load statement,
that is not actually built and shipped by the package maintainers).
Loading all libstrongswan plugins isn't necessary as the tool only uses
the plugins to parse/decrypt credentials. So it's similar to pki, but
it doesn't do (online) certificate validation, access tokens, or need
access to databases.
While it's usually not an issue to load unnecessary plugins, one thing
that came up recently are the new capabilities required by the agent
plugin. Since Debian's AppArmor policy for swanctl doesn't grant them,
this produces an error message that might confuse users.
This is useful during make-before-break reauthentication, where the
new SA is created before the old one is terminated and the virtual IP
gets released.
This also changes the hash() and equals() functions to avoid potential
collisions.
References strongswan/strongswan#2967
The referenced commit ignored that INVALID_ARG was returned by this
authenticator if an unsupported signature scheme is encountered. This
caused a crash in find_alternative_eap_cfg() as no EAP identity is
stored in the current auth config.
Since we don't distinguish the situation outside of the authenticator,
we can just return FAILED.
Closesstrongswan/strongswan#2979
Fixes: 2f2e4abe3c ("ikev2: Add support to switch peer configs based on EAP-Identities")
In particular with the 2019 image, the time required often exceeded the
maximum of 60 minutes. Using lld reduces the runtime quite a bit (it's
still close to the limit, though).
This doesn't work with the old OpenSSL version we use with the 2015
image (that libeay32.lib file just doesn't seem to work), so continue
to use ld (the build on that image is the quickest anyway).
Such a recursive call occurs when sorting the array of Child SAs inside
an IKE SA that causes comparisons of the child configs and their
proposals, which in turn creates a merged array of all transform types
and that uses array_sort() and array_bsearch().
Closesstrongswan/strongswan#2926
Fixes: 8e7f379f71 ("ike-sa: Sort CHILD_SAs by CPU ID")
We explicitly use untoh16() so this warning isn't relevant:
ip_packet.c:313:42: error: taking address of packed member 'ip_len' of class or structure 'ip' may result in an unaligned pointer value [-Werror,-Waddress-of-packed-member]