OPC UA Cross-SDK Interoperability Test Specification
Purpose
Validate that the open62541 C SDK can communicate correctly with other OPC UA
SDK implementations. The test suite covers transport-level security, user
authentication, data access, and method invocation.
The specification is SDK-agnostic: any conformant OPC UA server or client can
be substituted. The current reference implementation tests against the
OPC Foundation .NET Standard SDK.
Test Server Requirements
The server under test must provide:
| Item |
Details |
| Endpoint |
opc.tcp://<host>:<port>; optionally opc.wss://<host>:<port>/<path> or opc.https://<host>:<port>/<path> |
| SecurityPolicies |
None, Basic256Sha256, Aes128_Sha256_RsaOaep, Aes256_Sha256_RsaPss |
| SecurityModes |
None (only with policy None), Sign, SignAndEncrypt |
| Anonymous access |
Enabled |
| Username/Password |
user1 / password |
| X509 certificate auth |
Enabled; trust store must contain the client auth certificate |
| Variable |
ns=1;s=the.answer — Int32, value 43, readable |
| Method |
ns=1;i=62541 under ns=1;i=1000 (InteropTests) — HelloWorld(String) → String |
Test Matrix
T-1: Anonymous Connection (No Security)
| # |
Step |
Expected |
| 1 |
Connect with SecurityPolicy#None, anonymous |
Good |
| 2 |
Read Server_ServerStatus_State |
Good, value is ServerState |
| 3 |
Read Server_NamespaceArray |
Good, length > 0, index 0 = http://opcfoundation.org/UA/ |
| 4 |
Disconnect |
Clean close |
T-2: Username/Password Authentication (No Security)
Note: Many secure servers (including the open62541 interop_server) correctly
reject username/password credentials over the None policy to prevent
credential leaking. Both outcomes (accept or reject) are valid.
| # |
Step |
Expected |
| 1 |
Connect with SecurityPolicy#None, user user1/password |
Good or rejection (server-dependent) |
| 2 |
Read Server_ServerStatus_State (if connected) |
Good |
| 3 |
Disconnect |
Clean close |
T-3: Read Custom Variable
| # |
Step |
Expected |
| 1 |
Connect anonymous (any policy) |
Good |
| 2 |
Read ns=1;s=the.answer |
Good, Int32, value = 43 |
| 3 |
Disconnect |
Clean close |
T-4: Call Method
| # |
Step |
Expected |
| 1 |
Connect anonymous (any policy) |
Good |
| 2 |
Call ns=1;i=62541.HelloWorld("World") on ns=1;i=1000 |
Output contains "Hello World" |
| 3 |
Disconnect |
Clean close |
T-5: Encrypted Connection — Basic256Sha256
| # |
Step |
Expected |
| 1 |
Discover endpoints |
Server offers Basic256Sha256 / SignAndEncrypt |
| 2 |
Connect with Basic256Sha256, SignAndEncrypt, anonymous |
Good |
| 3 |
Read Server_ServerStatus_State |
Good |
| 4 |
Disconnect |
Clean close |
T-6: Encrypted Connection — Aes128_Sha256_RsaOaep
| # |
Step |
Expected |
| 1 |
Connect with Aes128_Sha256_RsaOaep, SignAndEncrypt, anonymous |
Good |
| 2 |
Read Server_ServerStatus_State |
Good |
| 3 |
Disconnect |
Clean close |
T-7: Encrypted Connection — Aes256_Sha256_RsaPss
| # |
Step |
Expected |
| 1 |
Connect with Aes256_Sha256_RsaPss, SignAndEncrypt, anonymous |
Good |
| 2 |
Read Server_ServerStatus_State |
Good |
| 3 |
Disconnect |
Clean close |
T-8: Username/Password over Encrypted Channel
| # |
Step |
Expected |
| 1 |
Connect with Basic256Sha256, SignAndEncrypt, user user1/password |
Good |
| 2 |
Read Server_ServerStatus_State |
Good |
| 3 |
Disconnect |
Clean close |
T-9: X509 Certificate Authentication
| # |
Step |
Expected |
| 1 |
Connect with Basic256Sha256, SignAndEncrypt, X509 cert identity |
Good |
| 2 |
Read Server_ServerStatus_State |
Good |
| 3 |
Disconnect |
Clean close |
H-1: .NET Client to open62541 HTTPS Server
| # |
Step |
Expected |
| 1 |
Connect over opc.https, anonymous; read CurrentTime |
Good, DateTime value |
| 2 |
Create a subscription and monitored item for ns=1;s=the.answer |
Initial value and two written data changes arrive; Publish requests are replenished |
| 3 |
Repeat with user1 / password |
Session, read, and subscription succeed |
| 4 |
Connect with user1 / wrong-password |
Authentication-specific rejection |
H-2: open62541 Client to .NET HTTPS Server
| # |
Step |
Expected |
| 1 |
Connect over the server's advertised opc.https URL, anonymous; read CurrentTime |
Good, DateTime value |
| 2 |
Subscribe to CurrentTime |
At least three notifications arrive, proving repeated long-running Publish requests work |
| 3 |
Repeat with user1 / password |
Session, read, and subscription succeed |
| 4 |
Connect with user1 / wrong-password |
Authentication-specific rejection; transport/DNS failures do not count as a pass |
Certificate Setup
The test infrastructure generates these RSA-2048 certificate/key pairs:
| Name |
CN |
ApplicationUri SAN |
Usage |
server_c |
open62541 CI Server |
urn:open62541.unconfigured.application |
C server SecureChannel |
client_c |
open62541 CI Client |
urn:open62541.client.application |
C client SecureChannel + X509 auth |
server_dotnet |
OPC UA .NET Reference Server |
urn:localhost:UA:ReferenceServer |
.NET server SecureChannel |
client_dotnet |
OPC UA .NET Interop Client |
urn:localhost:UA:InteropClient |
.NET client SecureChannel |
server_nodeopcua |
node-opcua Interop Server |
urn:localhost:node-opcua:interop |
node-opcua server SecureChannel |
client_nodeopcua |
node-opcua Interop Client |
urn:localhost:node-opcua:client |
node-opcua client SecureChannel |
Trust Relationships
- C server trusts:
client_c, client_dotnet, client_nodeopcua (for both SecureChannel and session/X509 auth)
- .NET server trusts:
server_c, client_c
- node-opcua server trusts:
client_c
CI Integration
The orchestration script tools/ci/cross-sdk/interop_test.sh runs:
- Scenario A: C server ↔ C / .NET / node-opcua clients (all tests T-1 through T-9)
- Scenario B: .NET server ↔ C client (all tests T-1 through T-9)
- Scenario C: node-opcua server ↔ C client (all tests T-1 through T-9)
- Scenario H1: C HTTPS server ↔ .NET HTTPS client (H-1)
- Scenario H2: .NET HTTPS server ↔ C HTTPS client (H-2)
The CI workflow (.github/workflows/interop_tests.yml) runs all scenarios
with OpenSSL and mbedTLS encryption backends.
Before the transport scenarios, a bidirectional Compact JSON wire test checks
scalar ExtensionObjects, ExtensionObjects in Variants, and ExtensionObject
arrays between open62541 and the OPC Foundation .NET Standard SDK.
The same C and .NET client tests can be repeated over secure WebSockets by
setting INTEROP_ENABLE_WSS=1. This path remains experimental and is not
enabled by the CI workflow until WSS support is available in a released
OPC Foundation .NET Standard SDK package. The C SDK must be built with
UA_ENABLE_LWS=ON. The WebSocket run uses the separate
interop_server_wss and check_interop_client_wss binaries. Their test and
address-space implementations are shared with the TCP binaries through the
sources under tests/interop/common.
The WebSocket TLS certificate protects the outer opc.wss transport. It is
configured and trusted separately from certificates used by OPC UA message
SecurityPolicies. Clients use the system trust store unless an explicit
WebSocket CA certificate is configured.
The node-opcua client can be tested independently against the C WSS server by
setting INTEROP_ENABLE_NODE_WSS=1. This local, opt-in path runs the same
T-1 through T-17 client suite through the separate
node-opcua/websocket/client_wss.mjs entry point. It is not enabled by the CI
workflow. The node-opcua server direction remains TCP-only.
Environment Variables
| Variable |
Description |
Default |
OPCUA_INTEROP_SERVER_URL |
Target server endpoint |
opc.tcp://localhost:4840 |
OPCUA_INTEROP_WSS_SERVER_URL |
Target endpoint for the experimental .NET WSS fixture |
— |
OPCUA_INTEROP_HTTPS_SERVER_URL |
Target C HTTPS endpoint for the .NET HTTPS fixture |
— |
OPCUA_INTEROP_CERT_DIR |
Directory with generated certificates |
— |
INTEROP_ENABLE_WSS |
Repeat the existing interop suites over WSS |
0 |
INTEROP_ENABLE_NODE_WSS |
Run the node-opcua client suite against the C WSS server |
0 |
DOTNET_CONFIG |
.NET build configuration |
Debug |
Adding a New SDK
To test against a new OPC UA SDK:
- Implement a server matching the requirements above
- Implement a client exercising tests T-1 through T-9
- Add a new scenario to
interop_test.sh
- Generate SDK-specific certificates in
generate_interop_certs.sh