#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 } 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. * * @param path File path to read. * @return The file contents, or UA_BYTESTRING_NULL on error. */ UA_ByteString loadFile (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 (dirPath/filename). The caller must free * the result with freeTrustStore(). * * @param dirPath Path to the trust store directory. * @param outPaths Output: heap-allocated array of heap-allocated strings. * Set to NULL when the directory is empty. * @param outSize Output: number of entries in outPaths. * @return 0 on success, -1 on error (logged via UA_LOG_ERROR). */ int loadTrustStore (const char *dirPath, char ***outPaths, size_t *outSize); /** * @brief Frees the array returned by loadTrustStore(). * * @param paths The array of strings (may be NULL). * @param size Number of entries. */ void freeTrustStore (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 parseLogLevel (const char *name); /** * @brief Parses the authMode key from a configuration file. * * 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 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 parseSecurityConfig (const Config *cfg, const char *program, UA_Boolean needsModePolicy, SecurityConfig *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 parseSecurityMode (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 shortName Short policy name. * @return The full URI string, or NULL if the name is not recognized. */ 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. 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 AuthConfig *auth); /** * @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 applicationUri 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 createSecureClientConfig (UA_ClientConfig *cc, const char *applicationUri, const SecurityConfig *sec, const AuthConfig *auth); /** * @brief Configures server access control from an AuthConfig. * * 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 * createServer is preserved, so UA_AccessControl_default automatically * advertises the X509 certificate token policy. * * @param config Server configuration to modify. * @param auth Authentication configuration. * @return UA_STATUSCODE_GOOD on success, error code otherwise. */ UA_StatusCode configureAccessControl (UA_ServerConfig *config, const AuthConfig *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 printApplicationDescription (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 printEndpoint (const UA_EndpointDescription *endpoint, size_t index); #endif /* DISCOVERY_COMMON_H */