Malicious servers could otherwise block the fetching thread indefinitely
after the initial TCP handshake (which has a default timeout of 10s
in the curl and winhttp plugins, the soup plugin actually has a default
overall timeout of 10s).
This avoids querying URLs of potentially untrusted certificates, e.g. if
an attacker sends a specially crafted end-entity and intermediate CA
certificate with a CDP that points to a server that completes the
TCP handshake but then does not send any further data, which will block
the fetcher thread (depending on the plugin) for as long as the default
timeout for TCP. Doing that multiple times will block all worker threads,
leading to a DoS attack.
The logging during the certificate verification obviously changes. The
following example shows the output of `pki --verify` for the current
strongswan.org certificate:
new:
using certificate "CN=www.strongswan.org"
using trusted intermediate ca certificate "C=US, O=Let's Encrypt, CN=R3"
using trusted ca certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1"
reached self-signed root ca with a path length of 1
checking certificate status of "CN=www.strongswan.org"
requesting ocsp status from 'http://r3.o.lencr.org' ...
ocsp response correctly signed by "C=US, O=Let's Encrypt, CN=R3"
ocsp response is valid: until Jul 27 12:59:58 2022
certificate status is good
checking certificate status of "C=US, O=Let's Encrypt, CN=R3"
ocsp response verification failed, no signer certificate 'C=US, O=Let's Encrypt, CN=R3' found
fetching crl from 'http://x1.c.lencr.org/' ...
using trusted certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1"
crl correctly signed by "C=US, O=Internet Security Research Group, CN=ISRG Root X1"
crl is valid: until Apr 18 01:59:59 2023
certificate status is good
certificate trusted, lifetimes valid, certificate not revoked
old:
using certificate "CN=www.strongswan.org"
using trusted intermediate ca certificate "C=US, O=Let's Encrypt, CN=R3"
checking certificate status of "CN=www.strongswan.org"
requesting ocsp status from 'http://r3.o.lencr.org' ...
ocsp response correctly signed by "C=US, O=Let's Encrypt, CN=R3"
ocsp response is valid: until Jul 27 12:59:58 2022
certificate status is good
using trusted ca certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1"
checking certificate status of "C=US, O=Let's Encrypt, CN=R3"
ocsp response verification failed, no signer certificate 'C=US, O=Let's Encrypt, CN=R3' found
fetching crl from 'http://x1.c.lencr.org/' ...
using trusted certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1"
crl correctly signed by "C=US, O=Internet Security Research Group, CN=ISRG Root X1"
crl is valid: until Apr 18 01:59:59 2023
certificate status is good
reached self-signed root ca with a path length of 1
certificate trusted, lifetimes valid, certificate not revoked
Note that this also fixes an issue with the previous dual-use of the
`trusted` flag. It not only indicated whether the chain is trusted but
also whether the current issuer is the root anchor (the corresponding
flag in the `cert_validator_t` interface is called `anchor`). This was
a problem when building multi-level trust chains for pre-trusted
end-entity certificates (i.e. where `trusted` is TRUE from the start).
This caused the main loop to get aborted after the first intermediate CA
certificate and the mentioned `anchor` flag wasn't correct in any calls
to `cert_validator_t` implementations.
Fixes: CVE-2022-40617
This forces the use of a semicolon after INIT() and makes existing ones,
which was the case for basically all instances, necessary so e.g.
sonarcloud won't complain about an empty statement after every one of
them.
By evaluating to the allocated object, it would theoretically also allow
constructs like this:
struct_t *this;
return INIT(this,
.a = x,
.b = y,
);
or this:
array_insert(a, ARRAY_TAIL, INIT(this,
.a = x,
.b = y,
));
If e.g. the hmac plugin is loaded before the third-party crypto lib
plugin, we might not use the latter's HMAC implementation in some
cases (e.g. in the libtls tests).
This makes sure the event is only triggered after the IKE_SA is fully
established and e.g. virtual IPs, additional peer addresses or
a modified reauth time (on the initiator) are assigned to it. This was
e.g. a problem for the selinux plugin if virtual IPs are used.
We use a separate task to trigger the event that's queued before the
child-create task so the event is triggered before the child_updown()
event. Same goes for the state change to IKE_ESTABLISHED.
A new condition is used to indicate the successful completion of all
authentication rounds, so we don't have to set the IKE_ESTABLISHED state
in the ike-auth task (it was used as condition in other tasks).
Since set_state() also sets the rekey and reauth times, this required
some minor changes in regards to how AUTH_LIFETIME notifies are handled.
Since e334bd46b1 ("ike-auth: Move packet collection to post_build()
method") tasks and plugins can modify the IKE_SA_INIT message independent
of the ike-auth task.
Otherwise, we can't open a dedicated IPv4 socket on the same port as the
IPv6 socket already is set up do receive IPv4 packets (unless we'd again
enable SO_REUSEADDR).
Fixes: 83da133712 ("socket-default: Don't set SO_REUSEADDR on IKE sockets anymore")
The default is apparently "Connection: keep-alive", which somehow keeps
the socket around, which leaks file descriptors with every connection
that fetches OCSP and/or CRLs. Over time that could result in the number
of FDs reaching a limit e.g. imposed by FD_SET().
Closesstrongswan/strongswan#1160
The linter complained that two of the strings don't actually contain any
printf-specifiers (i.e. don't expect any arguments) and therefore
shouldn't be used with String.format().
This was originally required when pluto and charon both bound sockets to
the same port to send messages. Pluto also received messages on them but
charon didn't and used a raw socket instead. Since the removal of pluto
we don't need to set this option anymore, which might actually mask
mistakes like running charon and charon-systemd concurrently (that could
result in messages getting sent fine by both daemons but only received
by one).
Note that a failure to create/bind the sockets will not immediately
result in a shutdown of the daemon. Instead, there will be an error
once the receiver tries to read any messages and also whenever the sender
attempts to send a request.
Changes the type for EAP vendor IDs from uint32_t to pen_t, which has
explicitly been added to represent three-byte IANA-allocated Private
Enterprise Numbers (PEN), which the EAP RFC called "SMI Network
Management Private Enterprise Codes".
References strongswan/strongswan#581
There should be no need for such a persistent documentation on a removed
component in the repository. The commit history is enough. And besides
that, there is user-facing documentation about it in the docs and the
changelog/NEWS.
There are a lot of calls like this:
this->dispatcher->raise_event(this->dispatcher, "...", 0,
b->finalize(b));
However, if finalize() fails, e.g. because a previous call to add()
failed due to the size limit, it returns NULL. This then caused a
segmentation fault in raise_event() when it interacted with that value.
Closesstrongswan/strongswan#1278
This fixes a race condition during shutdown between the main thread
flushing the IKE_SA manager and worker threads still creating IKE_SAs.
Closesstrongswan/strongswan#1252
Because flush() has to release the segment locks intermittently, threads
might add new entries (even with the change in the previous commit as the
IKE_SA might already be created, just not registered/checked in yet).
Since those entries are added to the front of the segment lists, the
enumerator in the previous step 2 didn't notice them and did not wait
for them to get checked in. However, step 3 and 4 then proceeded to
delete and destroy the entry and IKE_SA, which could lead to a crash
once the other thread attempts to check in the already destroyed IKE_SA.
This change combines the three loops of steps 2-4 but then loops over
the whole table until it's actually empty. This way we wait for and
destroy newly added entries.
Without ability to create SPIs, other threads are prevented from creating
new IKE_SAs while we are flushing existing IKE_SAs. However, there could
still be IKE_SAs already created that might get checked in while the
segments are temporarily unlocked to wait for threads to check existing
SAs in.
This is more consistent and e.g. allows to properly take into account
some settings that are also relevant during IKE_AUTH (e.g. childless).
We also already use the peer_cfg_t's ike_cfg_t when rekeying,
reauthenticating and reestablishing an IKE_SA (and e.g. for DSCP).
Also changed are some IKEv1 cases where get_ike_cfg() is called before
set_peer_cfg() without taking a reference to the ike_cfg_t that might
get replaced/destroyed (none of the cases were problematic, though, but
it also wasn't necessary to keep the ike_cfg_t around).
Closesstrongswan/strongswan#1238
The pattern currently is to call get_cache(), generate the encoding
if that failed and then store it with cache(). The latter adopts the
passed encoding and frees any stored encoding. However, the latter means
that if two threads concurrently fail to get a cached encoding and then
both generate and store one, one of the threads might use an encoding
that was freed by the other thread.
Since encodings are not expected to change, we can avoid this issue by
not replacing an existing cache entry and instead return that (while
freeing the passed value instead of the cached one).
Closesstrongswan/strongswan#1231
At least for the tests where it is available and works. It conflicts
with the instrumentation used by the coverage and fuzzing (and possibly
sonarcloud) tests, the toolchain for the Windows builds doesn't seem to
support it, and on FreeBSD the test executables hang due to a
compatibility issue with FreeBSD's qsort(), which has been fixed [1],
but that has not made it into the clang version in the base system.
For the custom OpenSSL build, debug symbols are enabled so we can
suppress some leaks properly.
[1] https://github.com/llvm/llvm-project/issues/46176
Only the second was reported by the compiler (depending on the version
and similarly to the previous commit only with AddressSanitizer active).
The strncpy() call for UTUN_CONTROL_NAME was simply wrong.
Normally, GCC sees that we terminate the destination with a zero byte.
However, when using `-fsanitize=address`, there seems to be additional
instrumentation code after strncpy() so GCC produces warnings like
these:
‘__builtin_strncpy’ specified bound 16 equals destination size [-Wstringop-truncation]
This causes odr-violation errors with libasan as some symbols will be
defined twice, once in the linked libimcv and once in the test
executable itself.
Closing the socket from the main thread, while the server thread is
still in accept() (or is just about to enter it), seems to
occasionally cause a deadlock on macOS.
Seems to be required on macOS (libtls tests didn't run before the recent
implicit enabling via pki). Other platforms apparently let accept() fail
if the socket is shutdown/closed in teardown_creds(), macOS apparently
doesn't do that.
Since the allocated data was smaller than sizeof(eap_mschapv2_header_t),
the following compile error was triggered (with newer GCC versions):
eap_mschapv2.c: In function 'process_peer_success':
eap_mschapv2.c:945:12: error: array subscript 'eap_mschapv2_header_t[0]' is partly outside array bounds of 'unsigned char[6]' [-Werror=array-bounds]
945 | eap->code = EAP_RESPONSE;
| ^~
In file included from /usr/include/stdlib.h:587,
from ../../../../src/libstrongswan/utils/printf_hook/printf_hook.h:26,
from ../../../../src/libstrongswan/library.h:101,
from ../../../../src/libcharon/sa/eap/eap_method.h:28,
from eap_mschapv2.h:27,
from eap_mschapv2.c:18:
eap_mschapv2.c:944:15: note: object of size 6 allocated by '__builtin_alloca'
944 | eap = alloca(len);
| ^~~~~~
Closesstrongswan/strongswan#1188Closesstrongswan/strongswan#1215
The previous code did not ensure that there was a delay of at least
`try` seconds after each sent request. Instead, whenever the condvar was
signaled, which could be due to retransmitted responses or messages for
unrelated transactions (there could even be spurious wakeups), the counter
was increased and a retransmit sent. So instead of actually waiting for
15 seconds for a response (and sending 4 retransmits over that timespan),
it could happen that all five messages were sent within a second without
enough time to actually receive a response.
Using an absolute timeout that we reuse as long as there was no timeout
and the condvar was signaled for something unrelated, should ensure we
wait at least the intended delay after each sent message.
Closesstrongswan/strongswan#1154
This allows using the upper parts of the marks for other purposes. For
instance, with `mark_in=mark_out=%unique/0x0000ffff` mark values in the
upper two bytes would not get reset by the rules installed by this plugin.
However, note that in this example the daemon would have to get restarted
after 65'535 CHILD_SAs to reset the counter for unique marks, which is a
global 32-bit counter that's unaware of any masks.
Closesstrongswan/strongswan#1087
get_traffic_selectors() is called the same way also as responder when
selecting child configs via peer_cfg_t::select_child_cfg(). Replacing
TS for all child configs could lead to selecting one that later fails
to actually narrow the traffic selectors. Ignoring non-matching TS also
helps if we have a trap config with multiple remote subnets (otherwise,
we'd have to filter duplicates afterwards).
When installing traps, the hosts might be %any, in which case we allow
the configured (technically non-matching) TS for the wildcard use case.
Fixes: da82786b2d ("child-cfg: Always apply hosts to traffic selectors if proposing transport mode")
Closesstrongswan/strongswan#1143
Setting -Werror in CFLAGS passed to configure is not ideal as that affects
all the checks performed by the script.
This caused an issue with newer versions of Autoconf and the AC_PROG_LEX
macro that insisted on finding a lexer library. But due to warnings from
the generated test lexer (misleading indentation) that got turned into
errors no library was found (none would have been necessary), so LEX was
not set and no lexers were built.
With this option enabled, we add -Werror to CFLAGS after all tests ran.
It also enables additional warnings via -Wextra.
The option is auto-enabled when building from the repository.
Making the variable volatile avoids a "variable ‘failure’ might be
clobbered by ‘longjmp’" warning (or error when compiling with
-Werror) that's triggered via -Wextra.
The 5.4.0 update changed the default bignum implementation to what
could explicitly be enabled via `--enable-sp-math-all`. Since this uses
fixed-sized buffers sufficient for key sizes of SP_INT_BITS, with a default
of 4096, modp6144 and modp8192 didn't work anymore (wc_DhGenerateKeyPair()
returned MP_EXPTMOD_E). So we have to adapt the feature checks for this.
To support the larger DH groups we can either increase the buffer size
via `--with-max-rsa-bits` or add `--enable-heapmath` so buffers get
(re-)allocated as needed. We go with the latter for now.
This merge includes changes that were created for the upcoming IKEv2
extension for multiple key exchanges over the last four years, but which
are not directly related to the actual protocol changes.
Changes include renaming diffie_hellman_t to the more generic
key_exchange_t (also renamed are some of the interface's methods),
making utility functions that deal with DH groups more generic, and let
tasks handle the first IKE_AUTH message more reliably by not depending
on e.g. specific message IDs.
One significant change is delaying the IKEv2 key derivation until
the keys are actually needed to process or send the next message. So
instead of deriving the keys directly while processing an IKE_SA_INIT
request (which could come from a spoofed address), this is delayed until
the corresponding IKE_AUTH request is received. Implementations of the
key_exchange_t interface are now expected to do the key derivation and
any costly public key validation in get_shared_secret() and not
set_public_key().
Sent IKE_SA_INIT messages are now also not pre-generated anymore to collect
their encoding for the authentication. Instead, a new post_build() hook
allows the ike-auth task to do so after the actual message has been built,
which allows later tasks and plugins (via message() hook) to modify the
message (e.g. add notifies) after the ike-auth task's build() method
already ran.
Also changed is how inbound requests are processed and retransmits are
detected. Instead of parsing all inbound messages right away (which
might trigger a key derivation or require keys we don't have anymore in
the multi-KE use case), we now first check a request's message ID and
compare its hash to that of the previous request to decide if it's a
valid retransmit. For fragmented messages, we only keep track of the
first fragment so we can send the corresponding response immediately if
a retransmit of it is received, instead of waiting for all fragments
and reconstructing the message, which we did before.
This way we avoid having to pre-generate the message when it could
theoretically still get modified by a task that follows or from a plugin
via message() hook.
In particular as responder, this delays costly cryptographic operations
until the IKE_AUTH request is received, which is preferable to reduce
the impact of DoS attacks.
Another advantage is that the key material is not changed until all tasks
built or processed a message.
This way we avoid parsing messages with unexpected message IDs, which
might not even be possible if we don't have the keys anymore. However,
the next commit should avoid the latter and this way we avoid deriving
keys for retransmits or unexpected messages.
This also changes how retransmits for fragmented messages are triggered.
Previously, we waited for all fragments and reconstructed the message
before retransmitting the response. Now we only track the first
fragment and if we receive a retransmit of it respond immediately
without waiting for other fragments (which are now ignored). This is in
compliance with RFC 7383, section 2.6.1, and can avoid issues if there
are lots of fragments.
This way we can use the IKE_REKEYED state for both redundant and old SAs
to suppress ike_updown().
In the ike-delete task we don't suppress events in state IKE_REKEYING as
that's the case when we delete an SA the peer is currently rekeying with
multiple key exchanges.
This gives us more flexibility with tasks that return NEED_MORE (currently
none of the colliding tasks do, but that will change with multi-KE
rekeyings). The active task has to check itself if the passive task is
done and should be removed from the task manager.
Since f67199378d ("ike-rekey: Handle undetected collisions also if
delete is delayed") we only ever track tasks of type TASK_IKE_REKEY, so
there is no need to check the type or use the generic task_t interface.
Also changed some of the comments to clarify collision handling.