As the winner of a rekey collision, we previously always triggered the
child_rekey() event once when creating the redundant SA on behalf of the
peer in the passive child-rekey task and then a second time when
creating the winning SA in the active task. However, both calls passed
the replaced CHILD_SA as "old". This made tracking CHILD_SAs impossible
because there was no transition from the redundant, "new" SA of the
first event to the "new", winning SA of the second. Of course, when the
second event was triggered, the redundant SA might not have existed
anymore because the peer is expected to delete it, which could happen
before the CREATE_CHILD_SA response arrives at the initiator.
This refactoring ensures that the child_rekey() event is triggered in
a way that makes the CHILD_SAs trackable in all reasonable (and even
some unreasonable) scenarios. The event is generally only triggered
once after installing the outbound SA for the new/winning CHILD_SA.
This can be when processing the CREATE_CHILD_SA in the active child-rekey
task, or when processing the DELETE for the old SA in a passive
child-delete task. There are some cases where the event is still
triggered twice, but it is now ensured that listeners can properly
transition to the winning SA.
Some corner cases are now also handled correctly, e.g. if a responder's
DELETE for the new CHILD_SA arrives before its CREATE_CHILD_SA response
that actually creates it on the initiator. Also handled properly are
responders of rekeyings that incorrectly send a DELETE for the old
CHILD_SA (previously this caused both, the new and the old SA, to get
deleted).
We currently only support these exchanges for additional key exchanges,
so once we have the final keys derived and the ike-init task is removed,
we don't expect any more of them.
The calculation of the timeout is also shared now and the total
timeout in seconds is corrected in case retransmit_base is <= 1.
This could make it easier in the future to apply different retransmission
settings to messages/exchanges.
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 e334bd46b184 ("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.
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 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.
We don't actually check that SA out (i.e. it's not registered with the
manager). That was originally different but had to be changed with
86993d6b9037 to avoid that SAs created for rekeying don't block other
threads on the manager.
This allows more fine grained control over what's updated and does not
require multiple calls of the method. Plus we'll be able to use it in
the ike-mobike task.
The message_t object used for defragmentation was only cleared after
all fragments have been received and the message was delivered. So
if we received only some fragments of a retransmitted message, the
fragments of the next message were not processed (message_t returns
INVALID_ARG if the message ID does not match causing the message to
get ignored). This rendered the IKE_SA unusable as the client
obviously never retransmitted the fragments of that previous message
after it received our response.
If a MOBIKE task is deferred, the retransmission counter is reset to 0
when reinitiating. So if there were retransmits before, this alert would
not be triggered if a response is received now without retransmits.
Retransmission jobs for old requests for which we already received a
response previously left the impression that messages were sent more
recently than was actually the case.
task_manager_t always defined INVALID_STATE as possible return value if
no retransmit was sent, this just was never actually returned.
I guess we could further differentiate between actual invalid states
(e.g. if we already received the response) and when we don't send a
retransmit for other reasons e.g. because the IKE_SA became stale.
Due to the exponential backoff a high number of retransmits only
makes sense if retransmit_limit is set. However, even with that there
was a problem.
We first calculated the timeout for the next retransmit and only then
compared that to the configured limit. Depending on the configured
base and timeout the calculation overflowed the range of uint32_t after
a relatively low number of retransmits (with the default values after 23)
causing the timeout to first get lower (on a high level) before constantly
resulting in 0 (with the default settings after 60 retransmits).
Since that's obviously lower than any configured limit, all remaining
retransmits were then sent without any delay, causing a lot of concurrent
messages if the number of retransmits was high.
This change determines the maximum number of retransmits until an
overflow occurs based on the configuration and defaults to UINT32_MAX
if that value is exceeded. Note that since the timeout is in milliseconds
UINT32_MAX equals nearly 50 days.
The calculation in task_manager_total_retransmit_timeout() uses a double
variable and the result is in seconds so the maximum number would be higher
there (with the default settings 1205). However, we want its result to
be based on the actual IKE retransmission behavior.
RFC 7296, section 2.21.3:
If a peer parsing a request notices that it is badly formatted (after
it has passed the message authentication code checks and window
checks) and it returns an INVALID_SYNTAX notification, then this
error notification is considered fatal in both peers, meaning that
the IKE SA is deleted without needing an explicit Delete payload.
RFC 7296, section 2.21.3:
If a peer parsing a request notices that it is badly formatted (after
it has passed the message authentication code checks and window
checks) and it returns an INVALID_SYNTAX notification, then this
error notification is considered fatal in both peers, meaning that
the IKE SA is deleted without needing an explicit Delete payload.
This allows switching to probing mode if the client is on a public IP
and this is the active task and connectivity gets restored. We only add
NAT-D payloads if we are currently behind a NAT (to detect changed NAT
mappings), a MOBIKE update that might follow will add them in case we
move behind a NAT.
Since these are installed overlapping (like during a rekeying) we have to use
the same (unique) marks (and possibly reqid) that were used previously,
otherwise, the policy installation will fail.
Fixes#2610.
Instead of destroying the new task and keeping the existing one we
update any already queued task, so we don't loose any work (e.g. if a
DPD task is active and address update is queued and we'd actually like
to queue a roam task).
We do something similar in reestablish() for break-before-make reauth.
If we don't abort we'd be sending an IKE_AUTH without any TS payloads.
References #2430.
If this is the first message by the peer, i.e. we expect MID 0, the
message is not pre-processed in the task manager so we ignore it in the
task.
We also make sure to ignore such messages if the extension is disabled
and the peer already sent us one INFORMATIONAL, e.g. a DPD (we'd otherwise
consider the message with MID 0 as a retransmit).
If the responder never sent a message the expected MID is 0. While
the sent MID (M1) SHOULD be increased beyond the known value, it's
not necessarily the case.
Since M2 - 1 would then equal UINT_MAX setting that MID would get ignored
and while we'd return 0 in the notify we'd actually expect 1 afterwards.