From 19e4a435c122a5eed34154ecfbbd3314a0789bc5 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Tue, 17 Feb 2026 14:59:05 +0100 Subject: Decouple LDS and server clients in ClientFindServers Create two independent UA_Client instances in client_find_servers.c: one for LDS discovery calls (FindServers, GetEndpoints) and one for server session calls (readServerTime). This allows different security modes, policies, auth, and trust lists for the LDS vs discovered servers. Config keys are now prefixed: discovery* for LDS connection settings, server* for discovered server settings. All config files updated accordingly with split trust lists (discoveryTrustList for LDS cert, serverTrustList for server cert). --- config/client_find_servers.conf | 61 ++++--- src/client_find_servers.c | 179 ++++++++++++++++----- tests/aes128_anon/client_find_servers.conf | 22 ++- tests/aes128_user/client_find_servers.conf | 28 ++-- tests/basic256sha256_anon/client_find_servers.conf | 22 ++- tests/basic256sha256_user/client_find_servers.conf | 28 ++-- tests/none_anon/client_find_servers.conf | 22 ++- tests/none_user/client_find_servers.conf | 28 ++-- 8 files changed, 272 insertions(+), 118 deletions(-) diff --git a/config/client_find_servers.conf b/config/client_find_servers.conf index a9e29c8..bc16b18 100644 --- a/config/client_find_servers.conf +++ b/config/client_find_servers.conf @@ -1,29 +1,50 @@ # ClientFindServers configuration # -# Keys: +# Shared keys: # discoveryEndpoint LDS endpoint URL (e.g. opc.tcp://localhost:4840) # applicationUri OPC UA application URI -# certificate Path to client certificate (.der) -# privateKey Path to client private key (.der) -# securityMode None, Sign, or SignAndEncrypt -# securityPolicy None, Basic256Sha256, Aes256_Sha256_RsaPss, -# Aes128_Sha256_RsaOaep, or ECC_nistP256 -# authMode "anonymous" or "user" -# username Username (required when authMode = user) -# password Password (required when authMode = user) -# trustList Trusted certificate path (repeat for multiple) +# +# Discovery-side keys (LDS connection): +# discoveryCertificate Path to certificate for LDS connections (.der) +# discoveryPrivateKey Path to private key for LDS connections (.der) +# discoverySecurityMode None, Sign, or SignAndEncrypt +# discoverySecurityPolicy None, Basic256Sha256, Aes256_Sha256_RsaPss, +# Aes128_Sha256_RsaOaep, or ECC_nistP256 +# discoveryAuthMode "anonymous" or "user" +# discoveryUsername Username (required when discoveryAuthMode = user) +# discoveryPassword Password (required when discoveryAuthMode = user) +# discoveryTrustList Trusted certificate path (repeat for multiple) +# +# Server-side keys (connections to discovered servers): +# serverCertificate Path to certificate for server connections (.der) +# serverPrivateKey Path to private key for server connections (.der) +# serverSecurityMode None, Sign, or SignAndEncrypt +# serverSecurityPolicy None, Basic256Sha256, Aes256_Sha256_RsaPss, +# Aes128_Sha256_RsaOaep, or ECC_nistP256 +# serverAuthMode "anonymous" or "user" +# serverUsername Username (required when serverAuthMode = user) +# serverPassword Password (required when serverAuthMode = user) +# serverTrustList Trusted certificate path (repeat for multiple) discoveryEndpoint = opc.tcp://localhost:4840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der - -securityMode = SignAndEncrypt -securityPolicy = Aes128_Sha256_RsaOaep -authMode = user -username = user -password = password +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = SignAndEncrypt +discoverySecurityPolicy = Aes128_Sha256_RsaOaep +discoveryAuthMode = user +discoveryUsername = user +discoveryPassword = password +discoveryTrustList = certs/ServerLDS_cert.der -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = SignAndEncrypt +serverSecurityPolicy = Aes128_Sha256_RsaOaep +serverAuthMode = user +serverUsername = user +serverPassword = password +serverTrustList = certs/ServerRegister_cert.der diff --git a/src/client_find_servers.c b/src/client_find_servers.c index a85b63f..2212026 100644 --- a/src/client_find_servers.c +++ b/src/client_find_servers.c @@ -233,56 +233,110 @@ main (int argc, char **argv) if (configLoad (argv[1], &cfg) != 0) return EXIT_FAILURE; + /* ---- Shared keys ---- */ + const char *discoveryServerEndpoint = configRequire (&cfg, "discoveryEndpoint", "ClientFindServers"); const char *applicationUri = configRequire (&cfg, "applicationUri", "ClientFindServers"); - const char *certPath - = configRequire (&cfg, "certificate", "ClientFindServers"); - const char *keyPath - = configRequire (&cfg, "privateKey", "ClientFindServers"); - const char *securityModeStr - = configRequire (&cfg, "securityMode", "ClientFindServers"); - const char *securityPolicyStr - = configRequire (&cfg, "securityPolicy", "ClientFindServers"); - const char *authMode = configRequire (&cfg, "authMode", "ClientFindServers"); - - if (!discoveryServerEndpoint || !applicationUri || !certPath || !keyPath - || !securityModeStr || !securityPolicyStr || !authMode) + + if (!discoveryServerEndpoint || !applicationUri) + { + configFree (&cfg); + return EXIT_FAILURE; + } + + /* ---- Discovery-side config (LDS connection) ---- */ + + const char *discCertPath + = configRequire (&cfg, "discoveryCertificate", "ClientFindServers"); + const char *discKeyPath + = configRequire (&cfg, "discoveryPrivateKey", "ClientFindServers"); + const char *discSecModeStr + = configRequire (&cfg, "discoverySecurityMode", "ClientFindServers"); + const char *discSecPolStr + = configRequire (&cfg, "discoverySecurityPolicy", "ClientFindServers"); + const char *discAuthMode + = configRequire (&cfg, "discoveryAuthMode", "ClientFindServers"); + + if (!discCertPath || !discKeyPath || !discSecModeStr || !discSecPolStr + || !discAuthMode) + { + configFree (&cfg); + return EXIT_FAILURE; + } + + UA_MessageSecurityMode discSecMode = parseSecurityMode (discSecModeStr); + if (discSecMode == UA_MESSAGESECURITYMODE_INVALID) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown discovery security mode: %s", discSecModeStr); + configFree (&cfg); + return EXIT_FAILURE; + } + + const char *discSecPolUri = resolveSecurityPolicyUri (discSecPolStr); + if (!discSecPolUri) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown discovery security policy: %s", discSecPolStr); + configFree (&cfg); + return EXIT_FAILURE; + } + + /* ---- Server-side config (connections to discovered servers) ---- */ + + const char *srvCertPath + = configRequire (&cfg, "serverCertificate", "ClientFindServers"); + const char *srvKeyPath + = configRequire (&cfg, "serverPrivateKey", "ClientFindServers"); + const char *srvSecModeStr + = configRequire (&cfg, "serverSecurityMode", "ClientFindServers"); + const char *srvSecPolStr + = configRequire (&cfg, "serverSecurityPolicy", "ClientFindServers"); + const char *srvAuthMode + = configRequire (&cfg, "serverAuthMode", "ClientFindServers"); + + if (!srvCertPath || !srvKeyPath || !srvSecModeStr || !srvSecPolStr + || !srvAuthMode) { configFree (&cfg); return EXIT_FAILURE; } - UA_MessageSecurityMode securityMode = parseSecurityMode (securityModeStr); - if (securityMode == UA_MESSAGESECURITYMODE_INVALID) + UA_MessageSecurityMode srvSecMode = parseSecurityMode (srvSecModeStr); + if (srvSecMode == UA_MESSAGESECURITYMODE_INVALID) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown security mode: %s", securityModeStr); + "Unknown server security mode: %s", srvSecModeStr); configFree (&cfg); return EXIT_FAILURE; } - const char *securityPolicyUri = resolveSecurityPolicyUri (securityPolicyStr); - if (!securityPolicyUri) + const char *srvSecPolUri = resolveSecurityPolicyUri (srvSecPolStr); + if (!srvSecPolUri) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown security policy: %s", securityPolicyStr); + "Unknown server security policy: %s", srvSecPolStr); configFree (&cfg); return EXIT_FAILURE; } - const char *username = NULL, *password = NULL; + /* ---- Server-side auth ---- */ - if (strcmp (authMode, "anonymous") == 0) + const char *srvUsername = NULL, *srvPassword = NULL; + + if (strcmp (srvAuthMode, "anonymous") == 0) { /* No credentials needed */ } - else if (strcmp (authMode, "user") == 0) + else if (strcmp (srvAuthMode, "user") == 0) { - username = configRequire (&cfg, "username", "ClientFindServers"); - password = configRequire (&cfg, "password", "ClientFindServers"); - if (!username || !password) + srvUsername + = configRequire (&cfg, "serverUsername", "ClientFindServers"); + srvPassword + = configRequire (&cfg, "serverPassword", "ClientFindServers"); + if (!srvUsername || !srvPassword) { configFree (&cfg); return EXIT_FAILURE; @@ -291,56 +345,93 @@ main (int argc, char **argv) else { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown auth mode: %s " + "Unknown server auth mode: %s " "(expected 'anonymous' or 'user')", - authMode); + srvAuthMode); configFree (&cfg); return EXIT_FAILURE; } - char **trustPaths = NULL; - size_t trustSize = 0; - configGetAll (&cfg, "trustList", &trustPaths, &trustSize); + /* ---- Trust lists ---- */ + + char **discTrustPaths = NULL; + size_t discTrustSize = 0; + configGetAll (&cfg, "discoveryTrustList", &discTrustPaths, &discTrustSize); + + char **srvTrustPaths = NULL; + size_t srvTrustSize = 0; + configGetAll (&cfg, "serverTrustList", &srvTrustPaths, &srvTrustSize); - UA_Client *client = UA_Client_new (); + /* ---- Create discovery client (LDS) ---- */ + + UA_Client *discoveryClient = UA_Client_new (); UA_StatusCode retval = createSecureClientConfig ( - UA_Client_getConfig (client), applicationUri, certPath, keyPath, - trustPaths, trustSize, securityMode, securityPolicyUri); + UA_Client_getConfig (discoveryClient), applicationUri, discCertPath, + discKeyPath, discTrustPaths, discTrustSize, discSecMode, discSecPolUri); if (retval != UA_STATUSCODE_GOOD) { - UA_Client_delete (client); - free (trustPaths); + UA_Client_delete (discoveryClient); + free (discTrustPaths); + free (srvTrustPaths); configFree (&cfg); return EXIT_FAILURE; } - UA_ClientConfig *clientConfig = UA_Client_getConfig (client); - clientConfig->logging->context = (void *)(uintptr_t)logLevel; + UA_Client_getConfig (discoveryClient)->logging->context + = (void *)(uintptr_t)logLevel; + + /* ---- Create server client (discovered servers) ---- */ + + UA_Client *serverClient = UA_Client_new (); + retval = createSecureClientConfig ( + UA_Client_getConfig (serverClient), applicationUri, srvCertPath, + srvKeyPath, srvTrustPaths, srvTrustSize, srvSecMode, srvSecPolUri); + if (retval != UA_STATUSCODE_GOOD) + { + UA_Client_delete (discoveryClient); + UA_Client_delete (serverClient); + free (discTrustPaths); + free (srvTrustPaths); + configFree (&cfg); + return EXIT_FAILURE; + } + UA_Client_getConfig (serverClient)->logging->context + = (void *)(uintptr_t)logLevel; + + /* ---- Discovery calls (use discoveryClient) ---- */ UA_ApplicationDescription *applicationDescriptionArray = NULL; size_t applicationDescriptionArraySize = 0; - retval = findServers (client, discoveryServerEndpoint, + retval = findServers (discoveryClient, discoveryServerEndpoint, &applicationDescriptionArraySize, &applicationDescriptionArray); if (retval != UA_STATUSCODE_GOOD) { - UA_Client_delete (client); - free (trustPaths); + UA_Client_delete (discoveryClient); + UA_Client_delete (serverClient); + free (discTrustPaths); + free (srvTrustPaths); configFree (&cfg); return EXIT_FAILURE; } - getServersEndpoints (client, applicationDescriptionArray, + getServersEndpoints (discoveryClient, applicationDescriptionArray, applicationDescriptionArraySize); - readServerTime (client, applicationDescriptionArray, - applicationDescriptionArraySize, username, password); + /* ---- Server calls (use serverClient) ---- */ + + readServerTime (serverClient, applicationDescriptionArray, + applicationDescriptionArraySize, srvUsername, srvPassword); + + /* ---- Cleanup ---- */ - UA_Client_delete (client); + UA_Client_delete (discoveryClient); + UA_Client_delete (serverClient); UA_Array_delete (applicationDescriptionArray, applicationDescriptionArraySize, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]); - free (trustPaths); + free (discTrustPaths); + free (srvTrustPaths); configFree (&cfg); return EXIT_SUCCESS; diff --git a/tests/aes128_anon/client_find_servers.conf b/tests/aes128_anon/client_find_servers.conf index 87eed56..2cc096d 100644 --- a/tests/aes128_anon/client_find_servers.conf +++ b/tests/aes128_anon/client_find_servers.conf @@ -2,13 +2,19 @@ discoveryEndpoint = opc.tcp://localhost:14840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der -securityMode = SignAndEncrypt -securityPolicy = Aes128_Sha256_RsaOaep +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = SignAndEncrypt +discoverySecurityPolicy = Aes128_Sha256_RsaOaep +discoveryAuthMode = anonymous +discoveryTrustList = certs/ServerLDS_cert.der -authMode = anonymous - -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = SignAndEncrypt +serverSecurityPolicy = Aes128_Sha256_RsaOaep +serverAuthMode = anonymous +serverTrustList = certs/ServerRegister_cert.der diff --git a/tests/aes128_user/client_find_servers.conf b/tests/aes128_user/client_find_servers.conf index 58d7bd1..4ecff56 100644 --- a/tests/aes128_user/client_find_servers.conf +++ b/tests/aes128_user/client_find_servers.conf @@ -2,15 +2,23 @@ discoveryEndpoint = opc.tcp://localhost:14840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der -securityMode = SignAndEncrypt -securityPolicy = Aes128_Sha256_RsaOaep +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = SignAndEncrypt +discoverySecurityPolicy = Aes128_Sha256_RsaOaep +discoveryAuthMode = user +discoveryUsername = user +discoveryPassword = password +discoveryTrustList = certs/ServerLDS_cert.der -authMode = user -username = user -password = password - -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = SignAndEncrypt +serverSecurityPolicy = Aes128_Sha256_RsaOaep +serverAuthMode = user +serverUsername = user +serverPassword = password +serverTrustList = certs/ServerRegister_cert.der diff --git a/tests/basic256sha256_anon/client_find_servers.conf b/tests/basic256sha256_anon/client_find_servers.conf index fb3d9d4..332c3da 100644 --- a/tests/basic256sha256_anon/client_find_servers.conf +++ b/tests/basic256sha256_anon/client_find_servers.conf @@ -2,13 +2,19 @@ discoveryEndpoint = opc.tcp://localhost:14840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der -securityMode = SignAndEncrypt -securityPolicy = Basic256Sha256 +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = SignAndEncrypt +discoverySecurityPolicy = Basic256Sha256 +discoveryAuthMode = anonymous +discoveryTrustList = certs/ServerLDS_cert.der -authMode = anonymous - -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = SignAndEncrypt +serverSecurityPolicy = Basic256Sha256 +serverAuthMode = anonymous +serverTrustList = certs/ServerRegister_cert.der diff --git a/tests/basic256sha256_user/client_find_servers.conf b/tests/basic256sha256_user/client_find_servers.conf index 93f511c..403dfa4 100644 --- a/tests/basic256sha256_user/client_find_servers.conf +++ b/tests/basic256sha256_user/client_find_servers.conf @@ -2,15 +2,23 @@ discoveryEndpoint = opc.tcp://localhost:14840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der -securityMode = SignAndEncrypt -securityPolicy = Basic256Sha256 +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = SignAndEncrypt +discoverySecurityPolicy = Basic256Sha256 +discoveryAuthMode = user +discoveryUsername = user +discoveryPassword = password +discoveryTrustList = certs/ServerLDS_cert.der -authMode = user -username = user -password = password - -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = SignAndEncrypt +serverSecurityPolicy = Basic256Sha256 +serverAuthMode = user +serverUsername = user +serverPassword = password +serverTrustList = certs/ServerRegister_cert.der diff --git a/tests/none_anon/client_find_servers.conf b/tests/none_anon/client_find_servers.conf index 8d874e7..6ea7d2d 100644 --- a/tests/none_anon/client_find_servers.conf +++ b/tests/none_anon/client_find_servers.conf @@ -2,13 +2,19 @@ discoveryEndpoint = opc.tcp://localhost:14840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der -securityMode = None -securityPolicy = None +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = None +discoverySecurityPolicy = None +discoveryAuthMode = anonymous +discoveryTrustList = certs/ServerLDS_cert.der -authMode = anonymous - -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = None +serverSecurityPolicy = None +serverAuthMode = anonymous +serverTrustList = certs/ServerRegister_cert.der diff --git a/tests/none_user/client_find_servers.conf b/tests/none_user/client_find_servers.conf index 10e9888..b538952 100644 --- a/tests/none_user/client_find_servers.conf +++ b/tests/none_user/client_find_servers.conf @@ -2,15 +2,23 @@ discoveryEndpoint = opc.tcp://localhost:14840 applicationUri = urn:bobink.ClientFindServers -certificate = certs/ClientFindServers_cert.der -privateKey = certs/ClientFindServers_key.der -securityMode = None -securityPolicy = None +# Discovery (LDS) side +discoveryCertificate = certs/ClientFindServers_cert.der +discoveryPrivateKey = certs/ClientFindServers_key.der +discoverySecurityMode = None +discoverySecurityPolicy = None +discoveryAuthMode = user +discoveryUsername = user +discoveryPassword = password +discoveryTrustList = certs/ServerLDS_cert.der -authMode = user -username = user -password = password - -trustList = certs/ServerLDS_cert.der -trustList = certs/ServerRegister_cert.der +# Server side +serverCertificate = certs/ClientFindServers_cert.der +serverPrivateKey = certs/ClientFindServers_key.der +serverSecurityMode = None +serverSecurityPolicy = None +serverAuthMode = user +serverUsername = user +serverPassword = password +serverTrustList = certs/ServerRegister_cert.der -- cgit v1.2.3