aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--readme.md22
-rw-r--r--src/server_lds.c86
-rw-r--r--src/server_register.c88
-rw-r--r--tests/nosec_anon/client.conf9
-rw-r--r--tests/nosec_anon/server_lds.conf8
-rw-r--r--tests/nosec_anon/server_register.conf12
-rw-r--r--tests/nosec_anon/server_register_client.conf13
8 files changed, 173 insertions, 69 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab6f4fd..5da5a4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -67,9 +67,9 @@ enable_testing()
set(_test_script "${CMAKE_SOURCE_DIR}/tests/run_test.sh")
-set(_test_names none_anon none_user basic256sha256_anon aes128_user)
+set(_test_names nosec_anon none_anon none_user basic256sha256_anon aes128_user)
-set(_test_policies None None Basic256Sha256 Aes128_Sha256_RsaOaep)
+set(_test_policies None None None Basic256Sha256 Aes128_Sha256_RsaOaep)
foreach(_name _policy IN ZIP_LISTS _test_names _test_policies)
add_test(NAME "${_name}" COMMAND bash "${_test_script}" "tests/${_name}"
diff --git a/readme.md b/readme.md
index 4156e51..bb99256 100644
--- a/readme.md
+++ b/readme.md
@@ -25,8 +25,11 @@ cd opcua_c
### Generate certificates
-The programs use TLS certificates for mutual authentication. Four identities
-are needed — run these from the project root:
+The programs use TLS certificates for mutual authentication. ServerLDS and
+ServerRegister can also run without certificates (SecurityPolicy#None only) by
+omitting the `certificate`, `privateKey`, and `trustStore` keys from their
+config files. For encrypted operation, four identities are needed — run these
+from the project root:
```sh
tools/generate_certificate.sh certs ServerLDS
@@ -37,22 +40,22 @@ tools/generate_certificate.sh certs ClientFindServers
### Populate the trust stores
-Each program trusts a specific set of peers. Copy the certificates into the
-trust store directories so they can find each other:
+Each program trusts a specific set of peers. Create symlinks to the
+certificates in the trust store directories so they can find each other:
```sh
mkdir -p certs/trust/{server_lds,server_register,server_register_client,client}
-cp certs/ServerRegisterClient_cert.der certs/ClientFindServers_cert.der \
+ln -s ../../ServerRegisterClient_cert.der ../../ClientFindServers_cert.der \
certs/trust/server_lds/
-cp certs/ServerLDS_cert.der certs/ClientFindServers_cert.der \
+ln -s ../../ServerLDS_cert.der ../../ClientFindServers_cert.der \
certs/trust/server_register/
-cp certs/ServerLDS_cert.der \
+ln -s ../../ServerLDS_cert.der \
certs/trust/server_register_client/
-cp certs/ServerLDS_cert.der certs/ServerRegister_cert.der \
+ln -s ../../ServerLDS_cert.der ../../ServerRegister_cert.der \
certs/trust/client/
```
@@ -93,10 +96,11 @@ All three programs accept an optional log level as the last argument
## Tests
-Integration tests exercise four combinations of security and authentication:
+Integration tests exercise five combinations of security and authentication:
| Test | Security | Auth |
|------|----------|------|
+| `nosec_anon` | LDS unsecured / None | anonymous |
| `none_anon` | None | anonymous |
| `none_user` | None | user/password |
| `basic256sha256_anon` | SignAndEncrypt / Basic256Sha256 | anonymous |
diff --git a/src/server_lds.c b/src/server_lds.c
index a9a68bc..e3407d5 100644
--- a/src/server_lds.c
+++ b/src/server_lds.c
@@ -2,8 +2,10 @@
* @file server_lds.c
* @brief Local Discovery Server implementation.
*
- * This program runs an OPC UA Local Discovery Server (LDS) configured with
- * encryption and a configurable cleanup timeout. Other OPC UA servers register
+ * This program runs an OPC UA Local Discovery Server (LDS) with a configurable
+ * cleanup timeout. Encryption is optional: when certificate, privateKey, and
+ * trustStore are provided, the server offers all security policies; otherwise
+ * it runs with SecurityPolicy#None only. Other OPC UA servers register
* with this LDS using the RegisterServer2 service. Clients can query this LDS
* using the FindServers service to discover registered servers.
*/
@@ -60,18 +62,33 @@ main (int argc, char *argv[])
int port = configRequireInt (&cfg, "port", "ServerLDS");
const char *applicationUri
= configRequire (&cfg, "applicationUri", "ServerLDS");
- const char *certPath = configRequire (&cfg, "certificate", "ServerLDS");
- const char *keyPath = configRequire (&cfg, "privateKey", "ServerLDS");
int cleanupTimeout = configRequireInt (&cfg, "cleanupTimeout", "ServerLDS");
const char *authMode = configRequire (&cfg, "authMode", "ServerLDS");
- if (!applicationUri || !certPath || !keyPath || !authMode || port < 0
- || cleanupTimeout < 0)
+ if (!applicationUri || !authMode || port < 0 || cleanupTimeout < 0)
{
configFree (&cfg);
return EXIT_FAILURE;
}
+ /* Security configuration (optional). When certificate, privateKey, and
+ trustStore are all omitted the server runs with SecurityPolicy#None
+ only. When any of the three is present, all three are required. */
+ const char *certPath = configGet (&cfg, "certificate");
+ const char *keyPath = configGet (&cfg, "privateKey");
+ const char *trustStore = configGet (&cfg, "trustStore");
+ UA_Boolean secure
+ = (certPath != NULL || keyPath != NULL || trustStore != NULL);
+
+ if (secure && (!certPath || !keyPath || !trustStore))
+ {
+ UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Incomplete security config: certificate, privateKey, and "
+ "trustStore must all be set, or all omitted");
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
+
/* The OPC UA specification requires the cleanup timeout to exceed the
register-server interval. open62541 enforces a floor of 10 seconds. */
if (cleanupTimeout <= 10)
@@ -111,30 +128,41 @@ main (int argc, char *argv[])
return EXIT_FAILURE;
}
- const char *trustStore = configRequire (&cfg, "trustStore", "ServerLDS");
- if (!trustStore)
- {
- configFree (&cfg);
- return EXIT_FAILURE;
- }
-
char **trustPaths = NULL;
size_t trustSize = 0;
- if (loadTrustStore (trustStore, &trustPaths, &trustSize) != 0)
+ UA_StatusCode retval;
+ UA_Server *server;
+
+ if (secure)
{
- configFree (&cfg);
- return EXIT_FAILURE;
+ if (loadTrustStore (trustStore, &trustPaths, &trustSize) != 0)
+ {
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
+ server = createSecureServer ((UA_UInt16)port, applicationUri, certPath,
+ keyPath, trustPaths, trustSize, &retval);
+ if (!server)
+ {
+ freeTrustStore (trustPaths, trustSize);
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
}
-
- UA_StatusCode retval;
- UA_Server *server
- = createSecureServer ((UA_UInt16)port, applicationUri, certPath, keyPath,
- trustPaths, trustSize, &retval);
- if (!server)
+ else
{
- freeTrustStore (trustPaths, trustSize);
- configFree (&cfg);
- return EXIT_FAILURE;
+ server = UA_Server_new ();
+ UA_ServerConfig *config = UA_Server_getConfig (server);
+ retval = UA_ServerConfig_setMinimal (config, (UA_UInt16)port, NULL);
+ if (retval != UA_STATUSCODE_GOOD)
+ {
+ UA_Server_delete (server);
+ configFree (&cfg);
+ return EXIT_FAILURE;
+ }
+ UA_String_clear (&config->applicationDescription.applicationUri);
+ config->applicationDescription.applicationUri
+ = UA_String_fromChars (applicationUri);
}
UA_ServerConfig *serverConfig = UA_Server_getConfig (server);
@@ -145,10 +173,10 @@ main (int argc, char *argv[])
Downgrade to a warning so third-party servers can still register. */
serverConfig->verifyRequestTimestamp = UA_RULEHANDLING_WARN;
- /* Configure access control after server creation because
- UA_ServerConfig_setDefaultWithSecurityPolicies (called by
- createSecureServer) resets the access control plugin. The credential
- list is deep-copied by UA_AccessControl_default. */
+ /* Configure access control after server creation because both
+ UA_ServerConfig_setDefaultWithSecurityPolicies and
+ UA_ServerConfig_setMinimal reset the access control plugin. The
+ credential list is deep-copied by UA_AccessControl_default. */
if (!allowAnonymous)
{
UA_UsernamePasswordLogin logins[1];
diff --git a/src/server_register.c b/src/server_register.c
index 6e1eb6d..cea7124 100644
--- a/src/server_register.c
+++ b/src/server_register.c
@@ -73,22 +73,36 @@ main (int argc, char **argv)
int port = configRequireInt (&serverCfg, "port", "ServerRegister");
const char *applicationUri
= configRequire (&serverCfg, "applicationUri", "ServerRegister");
- const char *serverCertPath
- = configRequire (&serverCfg, "certificate", "ServerRegister");
- const char *serverKeyPath
- = configRequire (&serverCfg, "privateKey", "ServerRegister");
int registerInterval
= configRequireInt (&serverCfg, "registerInterval", "ServerRegister");
const char *serverAuthMode
= configRequire (&serverCfg, "authMode", "ServerRegister");
- if (!applicationUri || !serverCertPath || !serverKeyPath || !serverAuthMode
- || port < 0 || registerInterval < 0)
+ if (!applicationUri || !serverAuthMode || port < 0 || registerInterval < 0)
{
configFree (&serverCfg);
return EXIT_FAILURE;
}
+ /* Security configuration (optional). When certificate, privateKey, and
+ trustStore are all omitted the server runs with SecurityPolicy#None
+ only. When any of the three is present, all three are required. */
+ const char *serverCertPath = configGet (&serverCfg, "certificate");
+ const char *serverKeyPath = configGet (&serverCfg, "privateKey");
+ const char *serverTrustStore = configGet (&serverCfg, "trustStore");
+ UA_Boolean serverSecure = (serverCertPath != NULL || serverKeyPath != NULL
+ || serverTrustStore != NULL);
+
+ if (serverSecure && (!serverCertPath || !serverKeyPath || !serverTrustStore))
+ {
+ UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Incomplete server security config: certificate, "
+ "privateKey, and trustStore must all be set, or all "
+ "omitted");
+ configFree (&serverCfg);
+ return EXIT_FAILURE;
+ }
+
/* Parse server-side auth mode (what clients connecting to this server
need). "anonymous" allows unauthenticated sessions; "user" requires
a username/password pair. */
@@ -122,18 +136,11 @@ main (int argc, char **argv)
return EXIT_FAILURE;
}
- const char *serverTrustStore
- = configRequire (&serverCfg, "trustStore", "ServerRegister");
- if (!serverTrustStore)
- {
- configFree (&serverCfg);
- return EXIT_FAILURE;
- }
-
char **serverTrustPaths = NULL;
size_t serverTrustSize = 0;
- if (loadTrustStore (serverTrustStore, &serverTrustPaths, &serverTrustSize)
- != 0)
+ if (serverSecure
+ && loadTrustStore (serverTrustStore, &serverTrustPaths, &serverTrustSize)
+ != 0)
{
configFree (&serverCfg);
return EXIT_FAILURE;
@@ -251,25 +258,48 @@ main (int argc, char **argv)
/* ── Create and configure server ────────────────────────────── */
UA_StatusCode retval;
- UA_Server *server = createSecureServer (
- (UA_UInt16)port, applicationUri, serverCertPath, serverKeyPath,
- serverTrustPaths, serverTrustSize, &retval);
- if (!server)
+ UA_Server *server;
+
+ if (serverSecure)
{
- freeTrustStore (clientTrustPaths, clientTrustSize);
- freeTrustStore (serverTrustPaths, serverTrustSize);
- configFree (&clientCfg);
- configFree (&serverCfg);
- return EXIT_FAILURE;
+ server = createSecureServer ((UA_UInt16)port, applicationUri,
+ serverCertPath, serverKeyPath,
+ serverTrustPaths, serverTrustSize, &retval);
+ if (!server)
+ {
+ freeTrustStore (clientTrustPaths, clientTrustSize);
+ freeTrustStore (serverTrustPaths, serverTrustSize);
+ configFree (&clientCfg);
+ configFree (&serverCfg);
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ server = UA_Server_new ();
+ UA_ServerConfig *config = UA_Server_getConfig (server);
+ retval = UA_ServerConfig_setMinimal (config, (UA_UInt16)port, NULL);
+ if (retval != UA_STATUSCODE_GOOD)
+ {
+ UA_Server_delete (server);
+ freeTrustStore (clientTrustPaths, clientTrustSize);
+ freeTrustStore (serverTrustPaths, serverTrustSize);
+ configFree (&clientCfg);
+ configFree (&serverCfg);
+ return EXIT_FAILURE;
+ }
+ UA_String_clear (&config->applicationDescription.applicationUri);
+ config->applicationDescription.applicationUri
+ = UA_String_fromChars (applicationUri);
}
UA_ServerConfig *serverConfig = UA_Server_getConfig (server);
serverConfig->logging->context = (void *)(uintptr_t)logLevel;
- /* Configure access control after server creation because
- UA_ServerConfig_setDefaultWithSecurityPolicies (called by
- createSecureServer) resets the access control plugin. The credential
- list is deep-copied by UA_AccessControl_default. */
+ /* Configure access control after server creation because both
+ UA_ServerConfig_setDefaultWithSecurityPolicies and
+ UA_ServerConfig_setMinimal reset the access control plugin. The
+ credential list is deep-copied by UA_AccessControl_default. */
if (!serverAllowAnonymous)
{
UA_UsernamePasswordLogin logins[1];
diff --git a/tests/nosec_anon/client.conf b/tests/nosec_anon/client.conf
new file mode 100644
index 0000000..72679c9
--- /dev/null
+++ b/tests/nosec_anon/client.conf
@@ -0,0 +1,9 @@
+# Client — test: nosec_anon
+
+applicationUri = urn:localhost:bobink:ClientFindServers
+certificate = certs/ClientFindServers_cert.der
+privateKey = certs/ClientFindServers_key.der
+securityMode = None
+securityPolicy = None
+authMode = anonymous
+trustStore = certs/trust/client
diff --git a/tests/nosec_anon/server_lds.conf b/tests/nosec_anon/server_lds.conf
new file mode 100644
index 0000000..aa4b6ec
--- /dev/null
+++ b/tests/nosec_anon/server_lds.conf
@@ -0,0 +1,8 @@
+# ServerLDS — test: nosec_anon
+# No certificate/privateKey/trustStore: runs with SecurityPolicy#None only.
+
+port = 14840
+applicationUri = urn:localhost:bobink:ServerLDS
+cleanupTimeout = 60
+
+authMode = anonymous
diff --git a/tests/nosec_anon/server_register.conf b/tests/nosec_anon/server_register.conf
new file mode 100644
index 0000000..0e8ed59
--- /dev/null
+++ b/tests/nosec_anon/server_register.conf
@@ -0,0 +1,12 @@
+# ServerRegister server config — test: nosec_anon
+
+port = 14841
+applicationUri = urn:localhost:bobink:ServerRegister
+certificate = certs/ServerRegister_cert.der
+privateKey = certs/ServerRegister_key.der
+
+registerInterval = 10
+
+authMode = anonymous
+
+trustStore = certs/trust/server_register
diff --git a/tests/nosec_anon/server_register_client.conf b/tests/nosec_anon/server_register_client.conf
new file mode 100644
index 0000000..8bdc05e
--- /dev/null
+++ b/tests/nosec_anon/server_register_client.conf
@@ -0,0 +1,13 @@
+# ServerRegister client config — test: nosec_anon
+# Connects to an unsecured LDS, so no trust store for the LDS cert is needed.
+
+applicationUri = urn:localhost:bobink:ServerRegister
+certificate = certs/ServerRegisterClient_cert.der
+privateKey = certs/ServerRegisterClient_key.der
+
+securityMode = None
+securityPolicy = None
+
+authMode = anonymous
+
+trustStore = certs/trust/server_register_client