# ECC Testing with the Console Reference Server and Client This guide describes how to use the **ConsoleReferenceServer** and **ConsoleReferenceClient** to exercise the Elliptic Curve Cryptography (ECC) security profiles of the OPC UA stack, how to generate the user certificates the tests rely on, and how to enable the detailed cryptographic tracing that helps diagnose interoperability problems. Both applications live under `Applications/`: | Application | Folder | | --- | --- | | Reference Server | `Applications/ConsoleReferenceServer` | | Reference Client | `Applications/ConsoleReferenceClient` | ## Overview The reference server exposes the full matrix of OPC UA security policies, including the ECC policies: - `ECC_nistP256_AesGcm` / `ECC_nistP256_ChaChaPoly` - `ECC_nistP384_AesGcm` / `ECC_nistP384_ChaChaPoly` - `ECC_brainpoolP256r1_AesGcm` / `ECC_brainpoolP256r1_ChaChaPoly` - `ECC_brainpoolP384r1_AesGcm` / `ECC_brainpoolP384r1_ChaChaPoly` (in addition to the RSA-based `Basic256Sha256` and `Aes*_RSA` policies). The client's `--testall` mode connects to **every** endpoint the server advertises, with every applicable user identity, so a single run validates the complete security matrix end to end. ## 1. Build Build both projects from the repository root (or open the solution and build the two console projects): ```powershell dotnet build Applications\ConsoleReferenceServer\ConsoleReferenceServer.csproj dotnet build Applications\ConsoleReferenceClient\ConsoleReferenceClient.csproj ``` > **Debug vs. Release matters for crypto tracing.** The detailed crypto trace > (see [Section 5](#5-debugging-crypto-with-the-debug-build)) is only compiled > into **Debug** builds of `Opc.Ua.Core`. Build in Debug when you need to > inspect the inputs to the cryptographic operations. ## 2. Run the Reference Server From `Applications/ConsoleReferenceServer`: ```powershell dotnet run -- -c -a ``` Useful options (see `--help` for the full list): | Option | Meaning | | --- | --- | | `-c`, `--console` | Log to the console. | | `-a`, `--autoaccept` | Auto-accept client/peer certificates (testing only). | | `-r`, `--renew` | Renew (regenerate) the application instance certificate. | | `--rc ` | Reverse connect to the supplied client endpoint. | The server listens on `opc.tcp://:62541/Quickstarts/ReferenceServer` by default. The endpoints offered (including the ECC policies listed above) are configured in `Quickstarts.ReferenceServer.Config.xml`. ### Trusting the test user certificates For X.509 user-token authentication to succeed, the server must **trust** the user certificates the client presents. The server reads its user trust list from the `TrustedUserCertificates` store configured in `Quickstarts.ReferenceServer.Config.xml`: ```xml Directory ../../pki/trustedUser ``` The generation script (next section) writes the public certificates into `pki/trustedUser/certs`, which is exactly the directory the server trusts. Make sure the server and client resolve the **same** `pki/trustedUser` directory (they share it by default when both run from the repository tree). If you point the client at a different machine or container, copy the generated `*.der` files from `pki/trustedUser/certs` into the server's trust store. ## 3. Generate the User Certificates The `--testall` mode authenticates each ECC endpoint with a user certificate whose key matches the endpoint's curve. These certificates are produced by: ``` Applications/ConsoleReferenceClient/generate_user_certificate.ps1 ``` Run it from the `ConsoleReferenceClient` folder: ```powershell .\generate_user_certificate.ps1 ``` The script: 1. Creates `./bin/pki/trustedUser/certs` and `./bin/pki/trustedUser/private`. 2. Generates a self-signed user certificate for each supported curve — `nistP256`, `nistP384`, `brainpoolP256r1`, `brainpoolP384r1` — plus an RSA-2048 certificate, all with subject `CN=iama.tester@example.com` and a client-authentication EKU. Each certificate is rebuilt to include an Authority Key Identifier so it validates as a proper end-entity certificate. 3. Writes, per curve: - the public certificate (DER) to `bin/pki/trustedUser/certs/iama.tester..der`, and - the PKCS#12 private key (PFX, password `password`) to `bin/pki/trustedUser/private/iama.tester..pfx`. The client (`ConnectTester`) selects the matching PFX for each endpoint based on the endpoint's security policy — for example an `ECC_nistP384_*` endpoint uses `iama.tester.nistP384.pfx`, while an RSA endpoint uses `iama.tester.rsa.pfx`. > The PFX files are protected with the password `password` (the default of the > `UserCertificatePassword` setting). Change both together if you customize it. After generating, ensure the `certs` files end up in the server's `pki/trustedUser/certs` trust store so the server accepts them (see [Trusting the test user certificates](#trusting-the-test-user-certificates)). ## 4. Run `--testall` (Test All Endpoints) With the server running and the user certificates generated and trusted, start the client in test-all mode from `Applications/ConsoleReferenceClient`: ```powershell dotnet run -- --testall -l -c ``` > **`-l -c` are required to see the test output.** `ConnectTester` writes its > per-endpoint results (and reconnect/diagnostic messages) through the telemetry > logger. That logger is only routed to the console when **both** `-l` > (`--log`, log app output) **and** `-c` (`--console`, log to console) are > supplied. Running plain `--testall` performs the same tests but prints almost > nothing — always use `--testall -l -c` when you want to watch the matrix run > or capture a trace. `--testall` (alias `--ea`) takes the following path through the code (`ConnectTester.cs`): 1. Loads the client application configuration and certificate. 2. Calls `GetEndpoints` on the configured server and enumerates **every** endpoint it advertises (optionally filtered — see `SecurityPolicyFilter` below). 3. For each endpoint, it builds the candidate user identities: - **Anonymous**, - **Username/Password** (when `UserName` is set), and - **X.509 user certificate** (when `SupportsX509` is `true`), automatically choosing the PFX whose key algorithm matches the endpoint's curve. 4. For every (endpoint × identity) combination it opens a session, forces a secure-channel renewal, reads `Server_ServerStatus_CurrentTime`, browses the address space, then closes the session — logging a clearly delimited `SECURITY-POLICY=… IDENTITY=…` / `TEST COMPLETE` block for each. Each combination is reported independently, so a failure on one policy or identity does not stop the rest of the matrix from running. When the matrix finishes, the client prints `Ctrl-C to stop.` and waits. ## 5. Configure the Connection with the Settings File The `--testall` behavior is driven by an external JSON settings file rather than command-line arguments. By default the loader looks for **`ConnectTester.Settings.json`** next to the executable; the path can be overridden with the `REFCLIENT_CONNECTTESTER_SETTINGS_FILE` environment variable. A missing or unparseable file falls back to the compiled-in defaults. Example `ConnectTester.Settings.json`: ```json { "ServerUrl": "opc.tcp://whitecat:62541/Quickstarts/ReferenceServer", "UserName": "sysadmin", "Password": "demo", "SupportsX509": true, "ReconnectPeriod": 1000, "ReconnectPeriodExponentialBackoff": 15000, "UserCertificatePath": "../../pki/trustedUser/private", "UserCertificatePassword": "password" } ``` | Setting | Purpose | | --- | --- | | `ServerUrl` | **The server the client connects to.** Set this to point the test run at a particular server (local, remote host, or container). | | `UserName` / `Password` | Credentials used for the username/password identity. Leave `UserName` empty to skip that identity. | | `SupportsX509` | When `true`, also test the X.509 user-certificate identity on each endpoint. | | `SecurityPolicyFilter` | Substring filter applied to the endpoint security-policy URIs; only matching endpoints are tested (empty = test all). Useful to focus on, e.g., `ECC_nistP384`. | | `UserCertificatePath` | Directory holding the user PFX files (relative paths resolve against the working directory). | | `UserCertificatePassword` | Password protecting the user PFX files (matches `generate_user_certificate.ps1`, default `password`). | | `ReconnectPeriod` / `ReconnectPeriodExponentialBackoff` | Reconnect timing for the session reconnect handler. | > The single most important field is **`ServerUrl`** — it specifies which server > the client tests against. Edit it (or supply an alternate settings file via > `REFCLIENT_CONNECTTESTER_SETTINGS_FILE`) to retarget a run without rebuilding. ## 6. Debugging Crypto with the Debug Build When a security policy fails to negotiate or messages fail to decrypt, build `Opc.Ua.Core` in **Debug** and run the test. Debug builds define the `OPCUA_CryptoTrace` symbol, which compiles in the `CryptoTrace` instrumentation in `CryptoUtils.cs`. With tracing active the stack writes the **detailed inputs to each cryptographic operation directly to the console**, for example: ``` EncryptWithAesGcm Data Offset/Count=… TokenId/LastSequenceNumber=… EncryptingKey=… IV=… EncryptedData=… Tag=… ExtraData=… ``` The same is emitted for the ChaCha20-Poly1305 encrypt/decrypt and AES-GCM decrypt paths, so you can line up the client's and server's view of the keys, IVs, ciphertext, tags, and associated data and pinpoint exactly where they diverge. Notes: - The trace is gated by both `#if DEBUG` / `OPCUA_CryptoTrace` **and** the runtime flag `CryptoTrace.Enabled` (default `true`). A **Release** build of `Opc.Ua.Core` strips the trace entirely. - The output includes secret key material — only use it on test systems with throw-away certificates, and never share raw traces from production keys. ## Quick Start (local, all ECC policies) ```powershell # 1. Generate the user certificates (once, or after changing curves/passwords) cd Applications\ConsoleReferenceClient .\generate_user_certificate.ps1 # 2. Start the server (Debug build for crypto tracing) cd ..\ConsoleReferenceServer dotnet run -- -c -a # 3. In another terminal, point ConnectTester.Settings.json at the server, # then run the full endpoint/identity matrix cd ..\ConsoleReferenceClient dotnet run -- --testall -l -c ``` > Remember the `-l -c` pair: without them `--testall` runs silently. See > [Section 4](#4-run---testall-test-all-endpoints).