> ## Documentation Index
> Fetch the complete documentation index at: https://docs.futurex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure the responder and the initiator

> Create and transfer a file-based certificate for the peer, then write the swanctl.conf connection definitions on the CryptoHub-backed responder and the initiator.

Build a two-host tunnel to prove the CryptoHub-backed key authenticates a real IKEv2 exchange. The **responder** authenticates with the key inside the CryptoHub. The **initiator** uses a file-based key, which keeps the test focused on the HSM side.

Substitute your own addresses for these placeholders throughout:

* `RESPONDER_IP` — the strongSwan host with the CryptoHub endpoint
* `INITIATOR_IP` — the peer host

## On the responder: create the initiator's key and certificate

The initiator's certificate is issued by the same CryptoHub-resident CA, so both peers trust one root.

```shell expandable lines wrap title="Shell" theme={null}
cd ~/strongswan-certs

ipsec pki --gen --type rsa --size 3072 --outform pem > peer-key.pem

ipsec pki --pub \
--in peer-key.pem \
--type rsa \
--outform der > peer-pub.der
```

Issue the certificate with the CryptoHub CA key:

```shell expandable lines wrap title="Shell" theme={null}
sudo env FXPKCS11_CFG=/etc/fxpkcs11.cfg HOME=/root \
ipsec pki --issue \
--in peer-pub.der \
--type pub \
--cacert strongswanCert.pem \
--cakeyid 01 \
--dn "CN=Peer" \
--flag clientAuth \
--serial 03 \
--outform pem > peer-cert.pem
```

Verify it:

```shell expandable lines wrap title="Shell" theme={null}
ipsec pki --print --in peer-cert.pem

ipsec pki --verify \
--in peer-cert.pem \
--cacert strongswanCert.pem
```

<Check>
  `--verify` reports `certificate trusted, lifetimes valid`.
</Check>

## Transfer the initiator's files

Copy these three files from the responder to the initiator:

* `peer-key.pem`
* `peer-cert.pem`
* `strongswanCert.pem`

Use `scp` where available:

```shell expandable lines wrap title="Shell" theme={null}
scp peer-key.pem peer-cert.pem strongswanCert.pem user@INITIATOR_IP:~/
```

<Warning>
  `peer-key.pem` is an unprotected private key. Transfer it over an encrypted channel, and delete the copy from the responder once the initiator has it:

  ```shell expandable lines wrap title="Shell" theme={null}
  shred -u ~/strongswan-certs/peer-key.pem
  ```
</Warning>

If SSH is unavailable on an isolated test network, serve the files briefly over HTTP from the responder with `python3 -m http.server 8080 --bind RESPONDER_IP`, fetch them with `wget`, then stop the server with `Ctrl+C`. Do not use this method for a key you intend to keep.

## On the responder: configure the HSM-backed connection

```shell expandable lines wrap title="Shell" theme={null}
sudo mkdir -p /etc/swanctl/x509 /etc/swanctl/x509ca

sudo cp ~/strongswan-certs/strongswan-cert.pem /etc/swanctl/x509/strongswan-cert.pem
sudo cp ~/strongswan-certs/strongswanCert.pem /etc/swanctl/x509ca/strongswanCert.pem

sudo chmod 644 /etc/swanctl/x509/strongswan-cert.pem
sudo chmod 644 /etc/swanctl/x509ca/strongswanCert.pem
```

<Note>
  You already ran these commands in [Validate charon can load the HSM-backed private key](/Integrations/CryptoHub/VPN/strongSwan/Validate_charon_can_load_the_HSM_backed_private_key). They are idempotent; re-run them if you are picking up from a fresh host.
</Note>

Replace `/etc/swanctl/swanctl.conf` with a configuration that has both a connection and the token credential:

```shell expandable lines wrap title="swanctl.conf" theme={null}
sudo tee /etc/swanctl/swanctl.conf > /dev/null << 'EOF'
connections {
    responder {
        version = 2
        local_addrs = RESPONDER_IP
        remote_addrs = INITIATOR_IP

        proposals = aes256-sha256-modp2048

        local {
            auth = pubkey
            id = "CN=StrongSwan"
            certs = strongswan-cert.pem
        }

        remote {
            auth = pubkey
            id = "CN=Peer"
        }

        children {
            net {
                local_ts = RESPONDER_IP/32
                remote_ts = INITIATOR_IP/32
                esp_proposals = aes256-sha256
                mode = tunnel
                start_action = trap
            }
        }
    }
}

secrets {
    token-strongswan {
        module = futurex
        handle = 02
        pin = "REPLACE_WITH_PKCS11_PIN"
    }
}
EOF

sudo chmod 600 /etc/swanctl/swanctl.conf
sudo chown root:root /etc/swanctl/swanctl.conf
```

Substitute the two addresses and the PKCS #11 PIN.

<Warning>
  This file holds the PIN in cleartext. Keep the mode at `600`.
</Warning>

Load it:

```shell expandable lines wrap title="Shell" theme={null}
sudo systemctl daemon-reload
sudo systemctl restart strongswan-starter
sleep 8

sudo swanctl --load-all --debug 2
sudo swanctl --list-conns
```

<Check>
  `--load-all` reports `loaded certificate`, `loaded token`, and `loaded connection 'responder'`. `--list-conns` lists the `responder` connection with the `net` child.
</Check>

## On the initiator: configure the file-based connection

```shell expandable lines wrap title="Shell" theme={null}
sudo mkdir -p /etc/swanctl/x509 /etc/swanctl/x509ca /etc/swanctl/private

sudo cp ~/peer-cert.pem /etc/swanctl/x509/peer-cert.pem
sudo cp ~/strongswanCert.pem /etc/swanctl/x509ca/strongswanCert.pem
sudo cp ~/peer-key.pem /etc/swanctl/private/peer-key.pem

sudo chmod 644 /etc/swanctl/x509/peer-cert.pem
sudo chmod 644 /etc/swanctl/x509ca/strongswanCert.pem
sudo chmod 600 /etc/swanctl/private/peer-key.pem
```

```shell expandable lines wrap title="swanctl.conf" theme={null}
sudo tee /etc/swanctl/swanctl.conf > /dev/null << 'EOF'
connections {
    initiator {
        version = 2
        local_addrs = INITIATOR_IP
        remote_addrs = RESPONDER_IP

        proposals = aes256-sha256-modp2048

        local {
            auth = pubkey
            id = "CN=Peer"
            certs = peer-cert.pem
        }

        remote {
            auth = pubkey
            id = "CN=StrongSwan"
        }

        children {
            net {
                local_ts = INITIATOR_IP/32
                remote_ts = RESPONDER_IP/32
                esp_proposals = aes256-sha256
                mode = tunnel
                start_action = start
            }
        }
    }
}

secrets {
    private-peer {
        file = peer-key.pem
    }
}
EOF

sudo chmod 600 /etc/swanctl/swanctl.conf
```

Load it:

```shell expandable lines wrap title="Shell" theme={null}
sudo systemctl daemon-reload
sudo systemctl restart strongswan-starter
sleep 8

sudo swanctl --load-all --debug 2
sudo swanctl --list-conns
```

<Check>
  Both hosts list their connection, and the local `id` on each matches the remote `id` on the other. A mismatch here is the most common cause of an authentication failure in the next section.
</Check>
