engine, messages, util, imsd: the reregistration carries the last challenge answer and new SA parameters

The keepalive refresh and the resume's re-REGISTER carried an initial
registration's first-REGISTER Authorization — an empty nonce and
response — in the second REGISTER's frame, with a Security-Client
naming the SPIs and ports in use. TS 24.229 5.1.1.4.2 has a
reregistration carry the Authorization
of the last successful authentication — the last received nonce and
the last calculated response — and a Security-Client with the new
parameter values for the two SA pairs a re-authentication would set
up; TS 33.203 7.4.0 keeps the server ports and changes the client
ports. O2 UK refused the refresh of the old shape with 503 on every
occasion on record (alyx, 2026-09-24 to 10-08, a stationary phone
included) and accepted the fresh registrations that followed; KPN
accepted the old shape without a challenge.

The fresh registration now records the 401's nonce, our cnonce and
the response in the registration state (auth_nonce, auth_cnonce,
auth_response in the state file); a reregistration sends them
verbatim, mints new SPIs and proposes PortUcNext (45063) as the
client port with the server port unchanged. A registration resumed from a
state file written before this change has no answer: its
reregistrations carry the empty digest, as before, until its next
fresh registration, and the resume says so. A 401 to a reregistration asks
for re-authentication over temporary SAs on the proposed ports (TS
24.229 5.1.1.5.1), which imsd does not implement: the refresh throws
it as a refusal and RegRecovery makes the next step the fresh
registration, replacing the in-place answer over the old SAs.

Tested with the Messages and Engine suites and on the dev phone (KPN)
with a build of this commit's tree: a resume from the previous state
file, a fresh registration, a resume that sent the stored answer,
three refreshes at a 120-s interval, an outgoing call to a bench line
and an incoming call's ring.
This commit is contained in:
Jorijn van der Graaf 2026-10-10 21:00:28 +02:00
commit 799fd1a802
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
8 changed files with 185 additions and 72 deletions

View file

@ -14,8 +14,10 @@ negotiated ealg keyed with CK. Both come from the Security-Server mechanism
the P-CSCF selected in its 401 (parsed here), and this module turns the
negotiated SPIs/ports/keys into the exact argv lists the daemon shell hands to
`ip`; for a warm resume it reconstructs the SPIs, ports, and Security-Server
value back out of `ip xfrm state`/`policy` text so a refresh re-REGISTER can
advertise the SPIs actually in use.
value back out of `ip xfrm state`/`policy` text — the Security-Verify and
the P-CSCF ports for the resume's flow, and the SPIs in use, which a
reregistration's new SPIs must differ from (and the state file falls back
to).
Pure std C++ (the shell runs the commands and captures the text). Command
shapes and the parser are pinned by tests/Ipsec.
@ -309,7 +311,7 @@ export namespace imsd::ipsec {
std::string securityServer; // reconstructed Security-Server header value
int portPs = 0;
int portPc = 0;
std::uint32_t spiUc = 0; // our inbound client SPI (advertise on refresh)
std::uint32_t spiUc = 0; // our inbound client SPI (a reregistration offers a different one)
std::uint32_t spiUs = 0; // our inbound server SPI
std::uint32_t spiPs = 0;
std::uint32_t spiPc = 0;