diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/client.c | 107 | ||||
| -rw-r--r-- | src/common.c | 150 | ||||
| -rw-r--r-- | src/common.h | 206 | ||||
| -rw-r--r-- | src/server_lds.c | 65 | ||||
| -rw-r--r-- | src/server_register.c | 167 |
5 files changed, 330 insertions, 365 deletions
diff --git a/src/client.c b/src/client.c index f2166a6..ed8b12a 100644 --- a/src/client.c +++ b/src/client.c @@ -108,19 +108,15 @@ opGetEndpoints (UA_Client *client, const char *url) /** * Connects to a server and reads the current time node. * - * @param username Username for session auth, or NULL for anonymous. - * @param password Password for session auth (ignored when username is NULL). + * Authentication (anonymous, username/password, or X509 certificate) is + * configured in the client config before this function is called. + * * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise. */ static int -opReadTime (UA_Client *client, const char *url, const char *username, - const char *password) +opReadTime (UA_Client *client, const char *url) { - UA_StatusCode retval; - if (username) - retval = UA_Client_connectUsername (client, url, username, password); - else - retval = UA_Client_connect (client, url); + UA_StatusCode retval = UA_Client_connect (client, url); if (retval != UA_STATUSCODE_GOOD) { @@ -212,34 +208,20 @@ main (int argc, char **argv) return EXIT_FAILURE; } - /* Security configuration (optional). When certificate, privateKey, and - trustStore are all omitted the client connects without encryption. - 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)) + SecurityConfig sec; + if (parseSecurityConfig (&cfg, "Client", true, &sec) != 0) { - 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; } /* ---- Auth config (read-time only) ---- */ - const char *username = NULL, *password = NULL; - UA_Boolean certAuth = false; + AuthConfig auth = { .mode = AUTH_ANONYMOUS }; - if (op == OP_READ_TIME - && parseAuthConfig (&cfg, "Client", NULL, &username, &password, - &certAuth) - != 0) + if (op == OP_READ_TIME && parseAuthConfig (&cfg, "Client", &auth) != 0) { + freeTrustStore (sec.trustPaths, sec.trustSize); configFree (&cfg); return EXIT_FAILURE; } @@ -247,62 +229,21 @@ main (int argc, char **argv) /* ---- Create client ---- */ UA_Client *client = UA_Client_new (); - char **trustPaths = NULL; - size_t trustSize = 0; - if (secure) - { - const char *secModeStr = configRequire (&cfg, "securityMode", "Client"); - const char *secPolStr = configRequire (&cfg, "securityPolicy", "Client"); - if (!secModeStr || !secPolStr) - { - UA_Client_delete (client); - configFree (&cfg); - return EXIT_FAILURE; - } - - UA_MessageSecurityMode secMode = parseSecurityMode (secModeStr); - if (secMode == UA_MESSAGESECURITYMODE_INVALID) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown security mode: %s", secModeStr); - UA_Client_delete (client); - configFree (&cfg); - return EXIT_FAILURE; - } - - const char *secPolUri = resolveSecurityPolicyUri (secPolStr); - if (!secPolUri) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown security policy: %s", secPolStr); - UA_Client_delete (client); - configFree (&cfg); - return EXIT_FAILURE; - } - - if (loadTrustStore (trustStore, &trustPaths, &trustSize) != 0) - { - UA_Client_delete (client); - configFree (&cfg); - return EXIT_FAILURE; - } - - UA_StatusCode retval = createSecureClientConfig ( - UA_Client_getConfig (client), applicationUri, certPath, keyPath, - trustPaths, trustSize, secMode, secPolUri, certAuth); - if (retval != UA_STATUSCODE_GOOD) - { - UA_Client_delete (client); - freeTrustStore (trustPaths, trustSize); - configFree (&cfg); - return EXIT_FAILURE; - } - } + UA_StatusCode retval; + if (sec.certPath) + retval = createSecureClientConfig (UA_Client_getConfig (client), + applicationUri, &sec, &auth); else + retval = createUnsecureClientConfig (UA_Client_getConfig (client), + applicationUri, &auth); + + if (retval != UA_STATUSCODE_GOOD) { - createUnsecureClientConfig (UA_Client_getConfig (client), - applicationUri); + UA_Client_delete (client); + freeTrustStore (sec.trustPaths, sec.trustSize); + configFree (&cfg); + return EXIT_FAILURE; } UA_Client_getConfig (client)->logging->context = (void *)(uintptr_t)logLevel; @@ -319,7 +260,7 @@ main (int argc, char **argv) rc = opGetEndpoints (client, endpointUrl); break; case OP_READ_TIME: - rc = opReadTime (client, endpointUrl, username, password); + rc = opReadTime (client, endpointUrl); break; default: rc = EXIT_FAILURE; @@ -329,7 +270,7 @@ main (int argc, char **argv) /* ---- Cleanup ---- */ UA_Client_delete (client); - freeTrustStore (trustPaths, trustSize); + freeTrustStore (sec.trustPaths, sec.trustSize); configFree (&cfg); return rc; diff --git a/src/common.c b/src/common.c index 865fc55..cf364bb 100644 --- a/src/common.c +++ b/src/common.c @@ -172,43 +172,33 @@ parseLogLevel (const char *name) } int -parseAuthConfig (const Config *cfg, const char *program, - UA_Boolean *allowAnonymous, const char **username, - const char **password, UA_Boolean *certAuth) +parseAuthConfig (const Config *cfg, const char *program, AuthConfig *auth) { const char *authMode = configRequire (cfg, "authMode", program); if (!authMode) return -1; - *username = NULL; - *password = NULL; - if (certAuth) - *certAuth = false; + memset (auth, 0, sizeof (*auth)); if (strcmp (authMode, "anonymous") == 0) { - if (allowAnonymous) - *allowAnonymous = true; + auth->mode = AUTH_ANONYMOUS; return 0; } if (strcmp (authMode, "user") == 0) { - if (allowAnonymous) - *allowAnonymous = false; - *username = configRequire (cfg, "username", program); - *password = configRequire (cfg, "password", program); - if (!*username || !*password) + auth->mode = AUTH_USER; + auth->user.username = configRequire (cfg, "username", program); + auth->user.password = configRequire (cfg, "password", program); + if (!auth->user.username || !auth->user.password) return -1; return 0; } if (strcmp (authMode, "cert") == 0) { - if (allowAnonymous) - *allowAnonymous = false; - if (certAuth) - *certAuth = true; + auth->mode = AUTH_CERT; return 0; } @@ -219,6 +209,63 @@ parseAuthConfig (const Config *cfg, const char *program, return -1; } +int +parseSecurityConfig (const Config *cfg, const char *program, + UA_Boolean needsModePolicy, SecurityConfig *sec) +{ + memset (sec, 0, sizeof (*sec)); + + 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) + return 0; + + if (!certPath || !keyPath || !trustStore) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "%s: incomplete security config: certificate, privateKey, " + "and trustStore must all be set, or all omitted", + program); + return -1; + } + + sec->certPath = certPath; + sec->keyPath = keyPath; + + if (needsModePolicy) + { + const char *secModeStr = configRequire (cfg, "securityMode", program); + const char *secPolStr = configRequire (cfg, "securityPolicy", program); + if (!secModeStr || !secPolStr) + return -1; + + sec->securityMode = parseSecurityMode (secModeStr); + if (sec->securityMode == UA_MESSAGESECURITYMODE_INVALID) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "%s: unknown security mode: %s", program, secModeStr); + return -1; + } + + sec->securityPolicyUri = resolveSecurityPolicyUri (secPolStr); + if (!sec->securityPolicyUri) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "%s: unknown security policy: %s", program, secPolStr); + return -1; + } + } + + if (loadTrustStore (trustStore, &sec->trustPaths, &sec->trustSize) != 0) + return -1; + + return 0; +} + UA_MessageSecurityMode parseSecurityMode (const char *name) { @@ -351,26 +398,26 @@ printEndpoint (const UA_EndpointDescription *endpoint, size_t index) * ======================================================================== */ UA_Server * -createServer (UA_UInt16 port, const char *applicationUri, const char *certPath, - const char *keyPath, char **trustPaths, size_t trustSize, - UA_Boolean discovery, UA_StatusCode *retval) +createServer (UA_UInt16 port, const char *applicationUri, + const SecurityConfig *sec, UA_Boolean discovery, + UA_StatusCode *retval) { UA_Server *server = UA_Server_new (); UA_ServerConfig *config = UA_Server_getConfig (server); - if (certPath) + if (sec && sec->certPath) { - UA_ByteString certificate = loadFile (certPath); - UA_ByteString privateKey = loadFile (keyPath); + UA_ByteString certificate = loadFile (sec->certPath); + UA_ByteString privateKey = loadFile (sec->keyPath); /* +1: UA_STACKARRAY requires a strictly positive size for VLA. */ - UA_STACKARRAY (UA_ByteString, trustList, trustSize + 1); - for (size_t i = 0; i < trustSize; i++) - trustList[i] = loadFile (trustPaths[i]); + UA_STACKARRAY (UA_ByteString, trustList, sec->trustSize + 1); + for (size_t i = 0; i < sec->trustSize; i++) + trustList[i] = loadFile (sec->trustPaths[i]); *retval = UA_ServerConfig_setDefaultWithSecureSecurityPolicies ( - config, port, &certificate, &privateKey, trustList, trustSize, NULL, - 0, NULL, 0); + config, port, &certificate, &privateKey, trustList, sec->trustSize, + NULL, 0, NULL, 0); /* When discovery is true (LDS) add SecurityPolicy#None restricted to discovery services so that unencrypted clients @@ -390,7 +437,7 @@ createServer (UA_UInt16 port, const char *applicationUri, const char *certPath, UA_ByteString_clear (&certificate); UA_ByteString_clear (&privateKey); - for (size_t i = 0; i < trustSize; i++) + for (size_t i = 0; i < sec->trustSize; i++) UA_ByteString_clear (&trustList[i]); } else @@ -412,8 +459,16 @@ createServer (UA_UInt16 port, const char *applicationUri, const char *certPath, } UA_StatusCode -createUnsecureClientConfig (UA_ClientConfig *cc, const char *applicationUri) +createUnsecureClientConfig (UA_ClientConfig *cc, const char *applicationUri, + const AuthConfig *auth) { + if (auth && auth->mode == AUTH_CERT) + { + UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, + "Certificate authentication requires encryption"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + UA_StatusCode retval = UA_ClientConfig_setDefault (cc); if (retval != UA_STATUSCODE_GOOD) return retval; @@ -426,38 +481,39 @@ createUnsecureClientConfig (UA_ClientConfig *cc, const char *applicationUri) cc->securityPolicyUri = UA_String_fromChars ( "http://opcfoundation.org/UA/SecurityPolicy#None"); + if (auth && auth->mode == AUTH_USER) + UA_ClientConfig_setAuthenticationUsername (cc, auth->user.username, + auth->user.password); + return UA_STATUSCODE_GOOD; } UA_StatusCode createSecureClientConfig (UA_ClientConfig *cc, const char *applicationUri, - const char *certPath, const char *keyPath, - char **trustPaths, size_t trustSize, - UA_MessageSecurityMode securityMode, - const char *securityPolicyUri, UA_Boolean certAuth) + const SecurityConfig *sec, const AuthConfig *auth) { - UA_ByteString certificate = loadFile (certPath); - UA_ByteString privateKey = loadFile (keyPath); + UA_ByteString certificate = loadFile (sec->certPath); + UA_ByteString privateKey = loadFile (sec->keyPath); /* +1: UA_STACKARRAY requires a strictly positive size for VLA. */ - UA_STACKARRAY (UA_ByteString, trustList, trustSize + 1); - for (size_t i = 0; i < trustSize; i++) - trustList[i] = loadFile (trustPaths[i]); + UA_STACKARRAY (UA_ByteString, trustList, sec->trustSize + 1); + for (size_t i = 0; i < sec->trustSize; i++) + trustList[i] = loadFile (sec->trustPaths[i]); UA_StatusCode retval = UA_ClientConfig_setDefaultEncryption ( - cc, certificate, privateKey, trustList, trustSize, NULL, 0); + cc, certificate, privateKey, trustList, sec->trustSize, NULL, 0); /* X509 identity token: reuse the application certificate. open62541 requires that the identity cert matches the SecureChannel cert, so a separate user cert cannot be used. Call before clearing the local buffers since setAuthenticationCert makes its own copy. */ - if (retval == UA_STATUSCODE_GOOD && certAuth) + if (retval == UA_STATUSCODE_GOOD && auth && auth->mode == AUTH_CERT) retval = UA_ClientConfig_setAuthenticationCert (cc, certificate, privateKey); UA_ByteString_clear (&certificate); UA_ByteString_clear (&privateKey); - for (size_t i = 0; i < trustSize; i++) + for (size_t i = 0; i < sec->trustSize; i++) UA_ByteString_clear (&trustList[i]); if (retval != UA_STATUSCODE_GOOD) @@ -471,8 +527,12 @@ createSecureClientConfig (UA_ClientConfig *cc, const char *applicationUri, UA_String_clear (&cc->clientDescription.applicationUri); cc->clientDescription.applicationUri = UA_String_fromChars (applicationUri); - cc->securityMode = securityMode; - cc->securityPolicyUri = UA_String_fromChars (securityPolicyUri); + cc->securityMode = sec->securityMode; + cc->securityPolicyUri = UA_String_fromChars (sec->securityPolicyUri); + + if (auth && auth->mode == AUTH_USER) + UA_ClientConfig_setAuthenticationUsername (cc, auth->user.username, + auth->user.password); return retval; } diff --git a/src/common.h b/src/common.h index aff6ff4..b8643d7 100644 --- a/src/common.h +++ b/src/common.h @@ -17,6 +17,66 @@ #include "config.h" +/* ======================================================================== + * Aggregate Types + * ======================================================================== */ + +/** + * @brief Session-level authentication mode. + */ +typedef enum +{ + AUTH_ANONYMOUS, + AUTH_USER, + AUTH_CERT +} AuthMode; + +/** + * @brief Session-level authentication configuration (tagged union). + * + * AUTH_ANONYMOUS carries no payload. AUTH_USER carries borrowed pointers + * to username/password strings (owned by the Config that was parsed). + * AUTH_CERT carries no payload — the application certificate is reused + * as the X509 identity token. + */ +typedef struct +{ + AuthMode mode; + union + { + struct + { + const char *username; + const char *password; + } user; + }; +} AuthConfig; + +/** + * @brief Transport-level security configuration. + * + * Groups the certificate, private key, trust list, security mode, and + * security policy URI. All pointers are borrowed (owned by Config or + * returned by loadTrustStore / resolveSecurityPolicyUri). The caller + * must free trustPaths with freeTrustStore() when done. + * + * securityMode and securityPolicyUri are only meaningful for client + * configs; server-side callers may leave them zeroed. + */ +typedef struct +{ + const char *certPath; + const char *keyPath; + char **trustPaths; + size_t trustSize; + UA_MessageSecurityMode securityMode; + const char *securityPolicyUri; +} SecurityConfig; + +/* ======================================================================== + * File Loading + * ======================================================================== */ + /** * @brief Loads a DER-encoded certificate or key file into a UA_ByteString. * @@ -48,34 +108,9 @@ int loadTrustStore (const char *dirPath, char ***outPaths, size_t *outSize); */ void freeTrustStore (char **paths, size_t size); -/** - * @brief Creates a UA_Server, optionally configured with security policies. - * - * When @p certPath is non-NULL the server is initialized with encryption - * (certificate, private key, trustlist). When @p discovery is true the - * server additionally offers SecurityPolicy#None restricted to discovery - * services (FindServers, GetEndpoints) so that unencrypted clients can - * still discover the server. When @p discovery is false the server is - * purely secure — no None security policy, no None endpoint. When - * @p certPath is NULL the server runs with SecurityPolicy#None only - * (keyPath, trustPaths and discovery are ignored). The applicationUri - * is set in both cases. - * - * @param port Server port number. - * @param applicationUri OPC UA application URI. - * @param certPath Path to server certificate (.der), or NULL for unsecure. - * @param keyPath Path to private key (.der), or NULL when certPath is NULL. - * @param trustPaths Array of trustlist file paths (may be NULL). - * @param trustSize Number of entries in trustPaths. - * @param discovery When true and certPath is non-NULL, add a None - * endpoint restricted to discovery services. - * @param retval Output parameter set to the status code on failure. - * @return A configured UA_Server, or NULL on error. - */ -UA_Server *createServer (UA_UInt16 port, const char *applicationUri, - const char *certPath, const char *keyPath, - char **trustPaths, size_t trustSize, - UA_Boolean discovery, UA_StatusCode *retval); +/* ======================================================================== + * Parsing Helpers + * ======================================================================== */ /** * @brief Parses a log-level name into the corresponding UA_LogLevel value. @@ -91,25 +126,37 @@ int parseLogLevel (const char *name); /** * @brief Parses the authMode key from a configuration file. * - * When authMode is "anonymous", sets *allowAnonymous to true and leaves - * *username / *password as NULL. When authMode is "user", sets - * *allowAnonymous to false and loads the username/password keys. When - * authMode is "cert", sets *allowAnonymous to false and *certAuth to true. + * Populates an AuthConfig struct. When authMode is "anonymous", sets + * mode to AUTH_ANONYMOUS. When "user", sets mode to AUTH_USER and reads + * the username/password keys. When "cert", sets mode to AUTH_CERT. * Logs errors internally. * - * @param cfg Parsed configuration. - * @param program Program name (for error messages). - * @param allowAnonymous Output: true for anonymous, false otherwise. - * May be NULL (ignored — useful for client callers). - * @param username Output: username string (owned by cfg), or NULL. - * @param password Output: password string (owned by cfg), or NULL. - * @param certAuth Output: true when authMode is "cert", false otherwise. - * May be NULL (ignored — useful for server callers). + * @param cfg Parsed configuration. + * @param program Program name (for error messages). + * @param auth Output: populated AuthConfig. + * @return 0 on success, -1 on error. + */ +int parseAuthConfig (const Config *cfg, const char *program, AuthConfig *auth); + +/** + * @brief Parses security configuration from a config file. + * + * Reads certificate, privateKey, and trustStore keys. When all three + * are omitted, zeroes @p sec and returns 0 (unsecure). When any of the + * three is present, all three are required. When @p needsModePolicy is + * true, also reads and resolves securityMode and securityPolicy keys. + * Calls loadTrustStore() internally; the caller must free + * sec->trustPaths with freeTrustStore(). + * + * @param cfg Parsed configuration. + * @param program Program name (for error messages). + * @param needsModePolicy When true, require securityMode and + * securityPolicy keys (client configs). + * @param sec Output: populated SecurityConfig. * @return 0 on success, -1 on error. */ -int parseAuthConfig (const Config *cfg, const char *program, - UA_Boolean *allowAnonymous, const char **username, - const char **password, UA_Boolean *certAuth); +int parseSecurityConfig (const Config *cfg, const char *program, + UA_Boolean needsModePolicy, SecurityConfig *sec); /** * @brief Parses a security mode name into the corresponding enum value. @@ -133,49 +180,76 @@ UA_MessageSecurityMode parseSecurityMode (const char *name); */ const char *resolveSecurityPolicyUri (const char *shortName); +/* ======================================================================== + * Factory Functions + * ======================================================================== */ + +/** + * @brief Creates a UA_Server, optionally configured with security policies. + * + * When @p sec is non-NULL the server is initialized with encryption + * (certificate, private key, trustlist). When @p discovery is true the + * server additionally offers SecurityPolicy#None restricted to discovery + * services (FindServers, GetEndpoints) so that unencrypted clients can + * still discover the server. When @p discovery is false the server is + * purely secure — no None security policy, no None endpoint. When + * @p sec is NULL the server runs with SecurityPolicy#None only + * (discovery is ignored). The applicationUri is set in both cases. + * + * @param port Server port number. + * @param applicationUri OPC UA application URI. + * @param sec Security configuration, or NULL for unsecure. + * @param discovery When true and sec is non-NULL, add a None + * endpoint restricted to discovery services. + * @param retval Output parameter set to the status code on failure. + * @return A configured UA_Server, or NULL on error. + */ +UA_Server *createServer (UA_UInt16 port, const char *applicationUri, + const SecurityConfig *sec, UA_Boolean discovery, + UA_StatusCode *retval); + /** * @brief Initializes a UA_ClientConfig without encryption. * * Sets up a default client config with SecurityPolicy#None and the given * application URI. Explicitly sets securityMode and securityPolicyUri so - * that internal endpoint negotiation matches None endpoints. + * that internal endpoint negotiation matches None endpoints. When @p auth + * is non-NULL and mode is AUTH_USER, configures username/password + * authentication. AUTH_CERT returns an error (requires encryption). * * @param cc Pointer to a zero-initialized UA_ClientConfig. * @param applicationUri OPC UA application URI. + * @param auth Authentication config, or NULL for anonymous. * @return UA_STATUSCODE_GOOD on success, error code otherwise. */ UA_StatusCode createUnsecureClientConfig (UA_ClientConfig *cc, - const char *applicationUri); + const char *applicationUri, + const AuthConfig *auth); /** - * @brief Initializes a UA_ClientConfig with encryption from file paths. + * @brief Initializes a UA_ClientConfig with encryption. * * The config must be zero-initialized by the caller before calling this - * function. Loads the certificate, private key, and trustlist, then applies - * default encryption settings. When @p certAuth is true, also configures - * X509 certificate identity-token authentication using the same application - * certificate (mutually exclusive with username/password authentication). + * function. Loads the certificate, private key, and trustlist, then + * applies default encryption settings. When @p auth is non-NULL: + * AUTH_CERT configures X509 certificate identity-token authentication + * using the same application certificate; AUTH_USER configures + * username/password authentication. Both are mutually exclusive. * * @param cc Pointer to a zero-initialized UA_ClientConfig. * @param applicationUri OPC UA application URI. - * @param certPath Path to client certificate (.der). - * @param keyPath Path to private key (.der). - * @param trustPaths Array of trustlist file paths (may be NULL if trustSize is - * 0). - * @param trustSize Number of entries in trustPaths. - * @param securityMode Requested message security mode. - * @param securityPolicyUri Security policy URI string (e.g. - * "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"). - * @param certAuth When true, use the application certificate as X509 identity - * token. + * @param sec Security configuration (cert, key, trust, mode, policy). + * @param auth Authentication config, or NULL for anonymous. * @return UA_STATUSCODE_GOOD on success, error code otherwise. */ -UA_StatusCode -createSecureClientConfig (UA_ClientConfig *cc, const char *applicationUri, - const char *certPath, const char *keyPath, - char **trustPaths, size_t trustSize, - UA_MessageSecurityMode securityMode, - const char *securityPolicyUri, UA_Boolean certAuth); +UA_StatusCode createSecureClientConfig (UA_ClientConfig *cc, + const char *applicationUri, + const SecurityConfig *sec, + const AuthConfig *auth); + +/* ======================================================================== + * Output Formatting + * ======================================================================== */ /** * @brief Logs a UA_ApplicationDescription (server info from FindServers). diff --git a/src/server_lds.c b/src/server_lds.c index 3307073..311be4b 100644 --- a/src/server_lds.c +++ b/src/server_lds.c @@ -67,24 +67,6 @@ main (int argc, char *argv[]) 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) @@ -96,31 +78,27 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } - UA_Boolean allowAnonymous; - const char *username = NULL, *password = NULL; - if (parseAuthConfig (&cfg, "ServerLDS", &allowAnonymous, &username, - &password, NULL) - != 0) + SecurityConfig sec; + if (parseSecurityConfig (&cfg, "ServerLDS", false, &sec) != 0) { configFree (&cfg); return EXIT_FAILURE; } - char **trustPaths = NULL; - size_t trustSize = 0; - if (secure && loadTrustStore (trustStore, &trustPaths, &trustSize) != 0) + AuthConfig auth; + if (parseAuthConfig (&cfg, "ServerLDS", &auth) != 0) { + freeTrustStore (sec.trustPaths, sec.trustSize); configFree (&cfg); return EXIT_FAILURE; } UA_StatusCode retval; - UA_Server *server - = createServer ((UA_UInt16)port, applicationUri, certPath, keyPath, - trustPaths, trustSize, true, &retval); + UA_Server *server = createServer ((UA_UInt16)port, applicationUri, + sec.certPath ? &sec : NULL, true, &retval); if (!server) { - freeTrustStore (trustPaths, trustSize); + freeTrustStore (sec.trustPaths, sec.trustSize); configFree (&cfg); return EXIT_FAILURE; } @@ -136,21 +114,28 @@ main (int argc, char *argv[]) /* Configure access control. UA_ServerConfig_setDefaultWithSecure- SecurityPolicies sets certificate-only auth by default, so we must always call UA_AccessControl_default to get the desired policy. */ - if (allowAnonymous) + switch (auth.mode) { + case AUTH_ANONYMOUS: retval = UA_AccessControl_default (serverConfig, true, NULL, 0, NULL); - } - else - { - UA_UsernamePasswordLogin logins[1]; - logins[0].username = UA_STRING ((char *)username); - logins[0].password = UA_STRING ((char *)password); - retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); + break; + case AUTH_USER: + { + UA_UsernamePasswordLogin logins[1]; + logins[0].username = UA_STRING ((char *)auth.user.username); + logins[0].password = UA_STRING ((char *)auth.user.password); + retval + = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); + break; + } + case AUTH_CERT: + retval = UA_AccessControl_default (serverConfig, false, NULL, 0, NULL); + break; } if (retval != UA_STATUSCODE_GOOD) { UA_Server_delete (server); - freeTrustStore (trustPaths, trustSize); + freeTrustStore (sec.trustPaths, sec.trustSize); configFree (&cfg); return EXIT_FAILURE; } @@ -166,7 +151,7 @@ main (int argc, char *argv[]) retval = UA_Server_run (server, &running); UA_Server_delete (server); - freeTrustStore (trustPaths, trustSize); + freeTrustStore (sec.trustPaths, sec.trustSize); configFree (&cfg); return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/server_register.c b/src/server_register.c index 705fc18..8a64d08 100644 --- a/src/server_register.c +++ b/src/server_register.c @@ -41,16 +41,9 @@ stopHandler (int sign) typedef struct { const char *appUri; - const char *certPath; - const char *keyPath; - char **trustPaths; - size_t trustSize; - UA_MessageSecurityMode securityMode; - const char *securityPolicyUri; + SecurityConfig sec; + AuthConfig auth; int logLevel; - const char *username; - const char *password; - UA_Boolean certAuth; } LdsClientParams; /** @@ -64,21 +57,13 @@ makeLdsClientConfig (UA_ClientConfig *cc, const LdsClientParams *p) { memset (cc, 0, sizeof (UA_ClientConfig)); UA_StatusCode rv; - if (p->certPath) - { - rv = createSecureClientConfig ( - cc, p->appUri, p->certPath, p->keyPath, p->trustPaths, p->trustSize, - p->securityMode, p->securityPolicyUri, p->certAuth); - } + if (p->sec.certPath) + rv = createSecureClientConfig (cc, p->appUri, &p->sec, &p->auth); else - { - rv = createUnsecureClientConfig (cc, p->appUri); - } + rv = createUnsecureClientConfig (cc, p->appUri, &p->auth); if (rv != UA_STATUSCODE_GOOD) return rv; cc->logging->context = (void *)(uintptr_t)p->logLevel; - if (p->username) - UA_ClientConfig_setAuthenticationUsername (cc, p->username, p->password); return UA_STATUSCODE_GOOD; } @@ -119,10 +104,8 @@ main (int argc, char **argv) int rc = EXIT_FAILURE; Config serverCfg = { 0 }; Config clientCfg = { 0 }; - char **serverTrustPaths = NULL; - size_t serverTrustSize = 0; - char **clientTrustPaths = NULL; - size_t clientTrustSize = 0; + SecurityConfig serverSec = { 0 }; + SecurityConfig clientSec = { 0 }; UA_Server *server = NULL; if (configLoad (argv[1], &serverCfg) != 0) @@ -137,34 +120,12 @@ main (int argc, char **argv) if (!applicationUri || port < 0 || registerInterval < 0) goto cleanup; - /* 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"); - goto cleanup; - } - - UA_Boolean serverAllowAnonymous; - const char *serverUsername = NULL, *serverPassword = NULL; - if (parseAuthConfig (&serverCfg, "ServerRegister", &serverAllowAnonymous, - &serverUsername, &serverPassword, NULL) + if (parseSecurityConfig (&serverCfg, "ServerRegister", false, &serverSec) != 0) goto cleanup; - if (serverSecure - && loadTrustStore (serverTrustStore, &serverTrustPaths, &serverTrustSize) - != 0) + AuthConfig serverAuth; + if (parseAuthConfig (&serverCfg, "ServerRegister", &serverAuth) != 0) goto cleanup; /* ── Load client config ─────────────────────────────────────── */ @@ -177,72 +138,20 @@ main (int argc, char **argv) if (!clientAppUri) goto cleanup; - /* Security configuration (optional). When certificate, privateKey, and - trustStore are all omitted the client connects without encryption. - When any of the three is present, all three are required. */ - const char *clientCertPath = configGet (&clientCfg, "certificate"); - const char *clientKeyPath = configGet (&clientCfg, "privateKey"); - const char *clientTrustStore = configGet (&clientCfg, "trustStore"); - UA_Boolean clientSecure = (clientCertPath != NULL || clientKeyPath != NULL - || clientTrustStore != NULL); - - if (clientSecure && (!clientCertPath || !clientKeyPath || !clientTrustStore)) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Incomplete client security config: certificate, " - "privateKey, and trustStore must all be set, or all " - "omitted"); - goto cleanup; - } - - UA_MessageSecurityMode securityMode = UA_MESSAGESECURITYMODE_NONE; - const char *securityPolicyUri - = "http://opcfoundation.org/UA/SecurityPolicy#None"; - - if (clientSecure) - { - const char *securityModeStr - = configRequire (&clientCfg, "securityMode", "ServerRegister"); - const char *securityPolicyStr - = configRequire (&clientCfg, "securityPolicy", "ServerRegister"); - if (!securityModeStr || !securityPolicyStr) - goto cleanup; - - securityMode = parseSecurityMode (securityModeStr); - if (securityMode == UA_MESSAGESECURITYMODE_INVALID) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown security mode: %s", securityModeStr); - goto cleanup; - } - - securityPolicyUri = resolveSecurityPolicyUri (securityPolicyStr); - if (!securityPolicyUri) - { - UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, - "Unknown security policy: %s", securityPolicyStr); - goto cleanup; - } - - if (loadTrustStore (clientTrustStore, &clientTrustPaths, - &clientTrustSize) - != 0) - goto cleanup; - } - - const char *clientUsername = NULL, *clientPassword = NULL; - UA_Boolean clientCertAuth = false; - if (parseAuthConfig (&clientCfg, "ServerRegister", NULL, &clientUsername, - &clientPassword, &clientCertAuth) + if (parseSecurityConfig (&clientCfg, "ServerRegister", true, &clientSec) != 0) goto cleanup; + AuthConfig clientAuth; + if (parseAuthConfig (&clientCfg, "ServerRegister", &clientAuth) != 0) + goto cleanup; + /* ── Create and configure server ────────────────────────────── */ UA_StatusCode retval; - server = createServer ((UA_UInt16)port, applicationUri, serverCertPath, - serverKeyPath, serverTrustPaths, serverTrustSize, - true, &retval); + server + = createServer ((UA_UInt16)port, applicationUri, + serverSec.certPath ? &serverSec : NULL, true, &retval); if (!server) goto cleanup; @@ -252,23 +161,26 @@ main (int argc, char **argv) /* Configure access control. UA_ServerConfig_setDefaultWithSecure- SecurityPolicies sets certificate-only auth by default, so we must always call UA_AccessControl_default to get the desired policy. */ - if (serverAllowAnonymous) + switch (serverAuth.mode) { + case AUTH_ANONYMOUS: retval = UA_AccessControl_default (serverConfig, true, NULL, 0, NULL); - } - else if (serverUsername) - { - UA_UsernamePasswordLogin logins[1]; - logins[0].username = UA_STRING ((char *)serverUsername); - logins[0].password = UA_STRING ((char *)serverPassword); - retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); - } - else - { + break; + case AUTH_USER: + { + UA_UsernamePasswordLogin logins[1]; + logins[0].username = UA_STRING ((char *)serverAuth.user.username); + logins[0].password = UA_STRING ((char *)serverAuth.user.password); + retval + = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); + break; + } + case AUTH_CERT: /* cert auth — sessionPKI.verifyCertificate is set by createServer via setDefaultWithSecureSecurityPolicies, so UA_AccessControl_default will automatically advertise the X509 certificate token policy. */ retval = UA_AccessControl_default (serverConfig, false, NULL, 0, NULL); + break; } if (retval != UA_STATUSCODE_GOOD) goto cleanup; @@ -278,16 +190,9 @@ main (int argc, char **argv) LdsClientParams ldsParams = { .appUri = clientAppUri, - .certPath = clientCertPath, - .keyPath = clientKeyPath, - .trustPaths = clientTrustPaths, - .trustSize = clientTrustSize, - .securityMode = securityMode, - .securityPolicyUri = securityPolicyUri, + .sec = clientSec, + .auth = clientAuth, .logLevel = logLevel, - .username = clientUsername, - .password = clientPassword, - .certAuth = clientCertAuth, }; /* Use run_startup + manual event loop (instead of UA_Server_run) so we @@ -360,8 +265,8 @@ main (int argc, char **argv) cleanup: if (server) UA_Server_delete (server); - freeTrustStore (clientTrustPaths, clientTrustSize); - freeTrustStore (serverTrustPaths, serverTrustSize); + freeTrustStore (clientSec.trustPaths, clientSec.trustSize); + freeTrustStore (serverSec.trustPaths, serverSec.trustSize); configFree (&clientCfg); configFree (&serverCfg); return rc; |
