A client certificate validates, the first exchange completes, and then the connection stops with an error about an additional authentication round. Nothing in the certificate chain is wrong and nothing in the network changed. The gateway has been configured to demand a second proof from the connecting side, and the client never sends one. Deciding who proves what, in which order, is the whole task, and it starts by reading the policy from the endpoint you are standing on. Two proofs of different kinds, in a fixed order, is a design decision rather than a checkbox.

The symptom: failure after a successful first proof

The first exchange completes and the log looks healthy, until the gateway asks for a user identity through EAP. The handshake then stalls or returns a protocol error naming the extra round. A perfectly valid machine certificate is being rejected for a reason that has nothing to do with its validity. The policy asked for a second proof, and the client's answer never arrived.

Both descriptions of that failure are accurate depending on where you stand. From the client's side it looks like a server rejecting a valid certificate, and from the server's side it looks like a client that cannot finish the login. The same event reads as a trust problem in one log and a capability problem in the other. Only the configured policy tells you which it is.

What the extension adds, and what it does not

IKEv2 carries an extension for running more than one authentication exchange inside a single session. RFC 4739 sketches, among other sequences, a client proving a certificate identity and then authenticating a person through EAP. The document is Experimental, which means no implementation owes you the feature. Assume nothing about support until the peer negotiates it.

Both sides have to support the extension and agree on it during the exchange. A gateway configured for a second round cannot make a client perform one, and a client that supports it will not use it unless the server asks. That asymmetry is why the failure usually surfaces as a timeout or a protocol error instead of a clear statement about capability. Reading one side's configuration tells you half of what will happen.

One proof per endpoint is the normal shape, and it is not this design. The gateway presents its certificate, the user answers EAP, and each side has authenticated the other exactly once. Those two proofs come from opposite endpoints, so neither one says anything separate about the machine and the person using it.

EAP-TLS is a third shape, and it is also not this one. There, a client certificate is presented inside an EAP method, so the client still completes a single IKE authentication. The credentials can look identical to the multiple-round case while the protocol carries one round instead of two. That is why a design copied from an EAP-TLS deployment fails at the point where the second proof is expected.

The same file reads differently on the gateway

The same swanctl file reads differently depending on where it runs, which is the part that trips people. On the laptop the gateway is the peer, and on the gateway the laptop is, so write the local side as who I am and the remote side as who I will accept. A local block describes how this endpoint authenticates itself, and a remote block states what it requires from the other end. Copying a block between the two files inverts its meaning without changing a single character. Diffing the two files tells you almost nothing, because the same words mean opposite things in each.

A section's position sets its order unless a round number overrides it. Additional local or remote sections therefore describe additional rounds rather than alternatives, and the explicit round number in the swanctl.conf reference exists precisely to make that ordering deliberate. Without it, moving a block changes behaviour. That is also why two configurations that look equivalent on paper can behave in opposite orders.

That ordering rule produces the failure mode worth remembering. A second remote block is not another acceptable option; it is a second demand, which is why a policy that reads like either/or behaves as and-then. A gateway policy might accept the enrolled machine's certificate and then require that user's EAP exchange, in that order.

Distinguish rounds from independent factors

Two rounds are not automatically two independent factors. Repeating a proof, or holding two credentials in the same store, does not deliver the strength the design was supposed to add. Independence is a property of how the secrets are held and what compromises them, not of how many exchanges the protocol runs. A design that counts rounds as factors overstates what it has. That distinction matters most when a compliance question asks how many factors the login actually uses.

A machine certificate proves possession of its accepted key, and nothing more. It is not a hardware attestation and not a device-health report, so a policy that needs posture information needs a different mechanism. Nor is the subject field an inventory tag you can trust, because the subject is chosen by whoever issued or enrolled the certificate. If the design needs proof that the machine is healthy, that proof has to come from a component that measures the machine.

Write down what each round actually proves before adding it. When two rounds prove the same thing twice, the second one adds latency and support tickets rather than assurance. That note is also what stops an argument about whether the extra round earns its cost.

Write the pairing rule and test the denials

Decide which machine identities may pair with which people, and write the rule where the enforcement lives. Two valid credentials sitting side by side prove nothing about the pairing, because the pairing is an authorization decision rather than an authentication result. The enrollment records or the authentication backend has to enforce the relationship the organisation wants.

Then test what should fail: an accepted user on an unapproved machine, an unapproved user holding the machine credential, and a peer that cannot perform the additional round. If all three quietly receive the same access, the policy describes an intention instead of enforcing one. Compare the declared configuration with what the daemon reports, since a connection that never matched looks identical to a rule that passed:

swanctl --list-conns
swanctl --list-sas

Check the negotiated rounds and the resulting authorization, not just the successful login. And do not reach for legacy IKEv1 XAuth settings as a shortcut: match the protocol, the roles, the order and the client's real behaviour instead of deleting a required round until a connection succeeds. Deleting the round that fails is how a two-proof design quietly becomes a one-proof design that nobody reviewed. Keep the deletion in the change record.

Inyandiko zihuye