10 KiB
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_ChaChaPolyECC_nistP384_AesGcm/ECC_nistP384_ChaChaPolyECC_brainpoolP256r1_AesGcm/ECC_brainpoolP256r1_ChaChaPolyECC_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):
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) 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:
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 <url> |
Reverse connect to the supplied client endpoint. |
The server listens on opc.tcp://<hostname>: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:
<TrustedUserCertificates>
<StoreType>Directory</StoreType>
<StorePath>../../pki/trustedUser</StorePath>
</TrustedUserCertificates>
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:
.\generate_user_certificate.ps1
The script:
- Creates
./bin/pki/trustedUser/certsand./bin/pki/trustedUser/private. - Generates a self-signed user certificate for each supported curve —
nistP256,nistP384,brainpoolP256r1,brainpoolP384r1— plus an RSA-2048 certificate, all with subjectCN=iama.tester@example.comand a client-authentication EKU. Each certificate is rebuilt to include an Authority Key Identifier so it validates as a proper end-entity certificate. - Writes, per curve:
- the public certificate (DER) to
bin/pki/trustedUser/certs/iama.tester.<curve>.der, and - the PKCS#12 private key (PFX, password
password) tobin/pki/trustedUser/private/iama.tester.<curve>.pfx.
- the public certificate (DER) to
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 theUserCertificatePasswordsetting). 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).
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:
dotnet run -- --testall -l -c
-l -care required to see the test output.ConnectTesterwrites 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--testallperforms the same tests but prints almost nothing — always use--testall -l -cwhen you want to watch the matrix run or capture a trace.
--testall (alias --ea) takes the following path through the code
(ConnectTester.cs):
- Loads the client application configuration and certificate.
- Calls
GetEndpointson the configured server and enumerates every endpoint it advertises (optionally filtered — seeSecurityPolicyFilterbelow). - For each endpoint, it builds the candidate user identities:
- Anonymous,
- Username/Password (when
UserNameis set), and - X.509 user certificate (when
SupportsX509istrue), automatically choosing the PFX whose key algorithm matches the endpoint's curve.
- 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 delimitedSECURITY-POLICY=… IDENTITY=…/TEST COMPLETEblock 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:
{
"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 viaREFCLIENT_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_CryptoTraceand the runtime flagCryptoTrace.Enabled(defaulttrue). A Release build ofOpc.Ua.Corestrips 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)
# 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 -cpair: without them--testallruns silently. See Section 4.