#ifndef DISCOVERY_COMMON_H #define DISCOVERY_COMMON_H /** * @file common.h * @brief Shared helpers for the OPC UA discovery demo programs. * * Provides file-loading, factory, and output formatting functions used by * the LDS, the registering server, and the FindServers client. */ #include #include #include #include #include "config.h" /* ======================================================================== * Aggregate Types * ======================================================================== */ /** * @brief Session-level authentication mode. */ typedef enum { AUTH_ANONYMOUS, AUTH_USER, AUTH_CERT } auth_mode; /** * @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 { auth_mode mode; union { struct { const char *username; const char *password; } user; }; } auth_config; /** * @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 load_trust_store / resolve_security_policy_uri). The caller * must free trust_paths with free_trust_store() when done. * * security_mode and security_policy_uri are only meaningful for client * configs; server-side callers may leave them zeroed. */ typedef struct { const char *cert_path; const char *key_path; char **trust_paths; size_t trust_size; UA_MessageSecurityMode security_mode; const char *security_policy_uri; } security_config; /* ======================================================================== * File Loading * ======================================================================== */ /** * @brief Loads a DER-encoded certificate or key file into a UA_ByteString. * * @param path File path to read. * @return The file contents, or UA_BYTESTRING_NULL on error. */ UA_ByteString load_file (const char *const path); /** * @brief Collects all *.der file paths from a trust store directory. * * Opens the directory, finds every file ending in ".der", and builds * heap-allocated full paths (dir_path/filename). The caller must free * the result with free_trust_store(). * * @param dir_path Path to the trust store directory. * @param out_paths Output: heap-allocated array of heap-allocated strings. * Set to NULL when the directory is empty. * @param out_size Output: number of entries in out_paths. * @return 0 on success, -1 on error (logged via UA_LOG_ERROR). */ int load_trust_store (const char *dir_path, char ***out_paths, size_t *out_size); /** * @brief Frees the array returned by load_trust_store(). * * @param paths The array of strings (may be NULL). * @param size Number of entries. */ void free_trust_store (char **paths, size_t size); /* ======================================================================== * Parsing Helpers * ======================================================================== */ /** * @brief Parses a log-level name into the corresponding UA_LogLevel value. * * Accepted names (case-sensitive): "trace", "debug", "info", "warning", * "error", "fatal". * * @param name Log-level name string. * @return The matching UA_LogLevel, or -1 if the name is not recognized. */ int parse_log_level (const char *name); /** * @brief Parses the authMode key from a configuration file. * * Populates an auth_config 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 auth Output: populated auth_config. * @return 0 on success, -1 on error. */ int parse_auth_config (const config *cfg, const char *program, auth_config *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 needs_mode_policy is * true, also reads and resolves securityMode and securityPolicy keys. * Calls load_trust_store() internally; the caller must free * sec->trust_paths with free_trust_store(). * * @param cfg Parsed configuration. * @param program Program name (for error messages). * @param needs_mode_policy When true, require securityMode and * securityPolicy keys (client configs). * @param sec Output: populated security_config. * @return 0 on success, -1 on error. */ int parse_security_config (const config *cfg, const char *program, UA_Boolean needs_mode_policy, security_config *sec); /** * @brief Parses a security mode name into the corresponding enum value. * * Accepted names: "None", "Sign", "SignAndEncrypt". * * @param name Mode name string. * @return The matching UA_MessageSecurityMode, or * UA_MESSAGESECURITYMODE_INVALID if the name is not recognized. */ UA_MessageSecurityMode parse_security_mode (const char *name); /** * @brief Maps a short security policy name to its full OPC UA URI. * * Accepted names: "None", "Basic256Sha256", "Aes256_Sha256_RsaPss", * "Aes128_Sha256_RsaOaep", "ECC_nistP256". * * @param short_name Short policy name. * @return The full URI string, or NULL if the name is not recognized. */ const char *resolve_security_policy_uri (const char *short_name); /* ======================================================================== * 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 application_uri 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 *create_server (UA_UInt16 port, const char *application_uri, const security_config *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. Always uses * anonymous authentication (credentials over plaintext are insecure). * * @param cc Pointer to a zero-initialized UA_ClientConfig. * @param application_uri OPC UA application URI. * @return UA_STATUSCODE_GOOD on success, error code otherwise. */ UA_StatusCode create_unsecure_client_config (UA_ClientConfig *cc, const char *application_uri); /** * @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 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 application_uri OPC UA application URI. * @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 create_secure_client_config (UA_ClientConfig *cc, const char *application_uri, const security_config *sec, const auth_config *auth); /** * @brief Configures server access control from an auth_config. * * UA_ServerConfig_setDefaultWithSecureSecurityPolicies installs * certificate-only authentication by default. This function * overrides that with the desired policy: anonymous, username/password, * or X509 certificate. For AUTH_CERT the sessionPKI verifier set by * create_server is preserved, so UA_AccessControl_default automatically * advertises the X509 certificate token policy. * * @param srv_config Server configuration to modify. * @param auth Authentication configuration. * @return UA_STATUSCODE_GOOD on success, error code otherwise. */ UA_StatusCode configure_access_control (UA_ServerConfig *srv_config, const auth_config *auth); /* ======================================================================== * Output Formatting * ======================================================================== */ /** * @brief Logs a UA_ApplicationDescription (server info from FindServers). * * Outputs the application URI, name, product URI, type, and discovery URLs * via UA_LOG_INFO. * * @param description The application description to print. * @param index Display index (e.g. position in the FindServers result array). */ void print_application_description (const UA_ApplicationDescription *description, size_t index); /** * @brief Logs a UA_EndpointDescription in a compact one-line format. * * Outputs the endpoint URL, security level, security mode, and the short * policy name (the part after '#') via UA_LOG_INFO. * * @param endpoint The endpoint description to print. * @param index Display index (e.g. position in the GetEndpoints result array). */ void print_endpoint (const UA_EndpointDescription *endpoint, size_t index); #endif /* DISCOVERY_COMMON_H */