diff options
Diffstat (limited to 'src/common.c')
| -rw-r--r-- | src/common.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..d102868 --- /dev/null +++ b/src/common.c @@ -0,0 +1,280 @@ +/** + * @file common.c + * @brief Implements shared helpers declared in common.h. + */ + +#include "common.h" + +#include <open62541/client_config_default.h> +#include <open62541/plugin/log_stdout.h> +#include <open62541/server_config_default.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* ======================================================================== + * File Loading + * ======================================================================== */ + +UA_ByteString +loadFile (const char *const path) +{ + UA_ByteString fileContents = UA_STRING_NULL; + + FILE *fp = fopen (path, "rb"); + if (!fp) + { + /* fopen sets errno on failure. Callers like createSecureServer use + loadFile for optional trustlist entries where a missing file is not + an error. Clear errno so open62541's logging does not pick up + a stale value and emit misleading error messages. */ + errno = 0; + return fileContents; + } + + fseek (fp, 0, SEEK_END); + fileContents.length = (size_t)ftell (fp); + fileContents.data + = (UA_Byte *)UA_malloc (fileContents.length * sizeof (UA_Byte)); + if (fileContents.data) + { + fseek (fp, 0, SEEK_SET); + size_t read = fread (fileContents.data, sizeof (UA_Byte), + fileContents.length, fp); + if (read != fileContents.length) + UA_ByteString_clear (&fileContents); + } + else + { + fileContents.length = 0; + } + fclose (fp); + + return fileContents; +} + +/* ======================================================================== + * Security Helpers + * ======================================================================== */ + +UA_MessageSecurityMode +parseSecurityMode (const char *name) +{ + if (strcmp (name, "None") == 0) + return UA_MESSAGESECURITYMODE_NONE; + if (strcmp (name, "Sign") == 0) + return UA_MESSAGESECURITYMODE_SIGN; + if (strcmp (name, "SignAndEncrypt") == 0) + return UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + return UA_MESSAGESECURITYMODE_INVALID; +} + +const char * +resolveSecurityPolicyUri (const char *shortName) +{ + static const struct + { + const char *name; + const char *uri; + } policies[] = { + { "None", "http://opcfoundation.org/UA/SecurityPolicy#None" }, + { "Basic256Sha256", + "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256" }, + { "Aes256_Sha256_RsaPss", + "http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss" }, + { "Aes128_Sha256_RsaOaep", + "http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep" }, + { "ECC_nistP256", + "http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256" }, + }; + for (size_t i = 0; i < sizeof (policies) / sizeof (policies[0]); i++) + { + if (strcmp (shortName, policies[i].name) == 0) + return policies[i].uri; + } + return NULL; +} + +/* ======================================================================== + * Output Formatting + * ======================================================================== */ + +void +printApplicationDescription (const UA_ApplicationDescription *description, + size_t index) +{ + const char *type = "Unknown"; + switch (description->applicationType) + { + case UA_APPLICATIONTYPE_SERVER: + type = "Server"; + break; + case UA_APPLICATIONTYPE_CLIENT: + type = "Client"; + break; + case UA_APPLICATIONTYPE_CLIENTANDSERVER: + type = "Client and Server"; + break; + case UA_APPLICATIONTYPE_DISCOVERYSERVER: + type = "Discovery Server"; + break; + default: + break; + } + + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, "Server[%lu]: %.*s", + (unsigned long)index, (int)description->applicationUri.length, + description->applicationUri.data); + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, " Name: %.*s", + (int)description->applicationName.text.length, + description->applicationName.text.data); + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, + " Application URI: %.*s", + (int)description->applicationUri.length, + description->applicationUri.data); + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, + " Product URI: %.*s", (int)description->productUri.length, + description->productUri.data); + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, " Type: %s", type); + for (size_t j = 0; j < description->discoveryUrlsSize; j++) + { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, + " Discovery URL[%lu]: %.*s", (unsigned long)j, + (int)description->discoveryUrls[j].length, + description->discoveryUrls[j].data); + } +} + +void +printEndpoint (const UA_EndpointDescription *endpoint, size_t index) +{ + const char *mode = "Unknown"; + switch (endpoint->securityMode) + { + case UA_MESSAGESECURITYMODE_NONE: + mode = "None"; + break; + case UA_MESSAGESECURITYMODE_SIGN: + mode = "Sign"; + break; + case UA_MESSAGESECURITYMODE_SIGNANDENCRYPT: + mode = "SignAndEncrypt"; + break; + default: + break; + } + + /* Extract policy name after the '#' */ + const char *policy = (const char *)endpoint->securityPolicyUri.data; + size_t policyLen = endpoint->securityPolicyUri.length; + for (size_t k = 0; k < endpoint->securityPolicyUri.length; k++) + { + if (endpoint->securityPolicyUri.data[k] == '#') + { + policy = (const char *)&endpoint->securityPolicyUri.data[k + 1]; + policyLen = endpoint->securityPolicyUri.length - k - 1; + break; + } + } + + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, + " [%4lu] %.*s | Level: %2d | %-14s | %.*s", + (unsigned long)index, (int)endpoint->endpointUrl.length, + endpoint->endpointUrl.data, endpoint->securityLevel, mode, + (int)policyLen, policy); +} + +/* ======================================================================== + * Factory Functions + * ======================================================================== */ + +UA_Server * +createSecureServer (UA_UInt16 port, const char *applicationUri, + const char *certPath, const char *keyPath, + char **trustPaths, size_t trustSize, UA_StatusCode *retval) +{ + UA_ByteString certificate = loadFile (certPath); + UA_ByteString privateKey = loadFile (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]); + + /* Issuer and revocation lists are unused in this demo. */ + size_t issuerListSize = 0; + UA_ByteString *issuerList = NULL; + UA_ByteString *revocationList = NULL; + size_t revocationListSize = 0; + + UA_Server *server = UA_Server_new (); + UA_ServerConfig *config = UA_Server_getConfig (server); + + *retval = UA_ServerConfig_setDefaultWithSecurityPolicies ( + config, port, &certificate, &privateKey, trustList, trustSize, + issuerList, issuerListSize, revocationList, revocationListSize); + + UA_ByteString_clear (&certificate); + UA_ByteString_clear (&privateKey); + for (size_t i = 0; i < trustSize; i++) + UA_ByteString_clear (&trustList[i]); + + if (*retval != UA_STATUSCODE_GOOD) + { + UA_Server_delete (server); + return NULL; + } + + UA_String_clear (&config->applicationDescription.applicationUri); + config->applicationDescription.applicationUri + = UA_String_fromChars (applicationUri); + + return server; +} + +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_ByteString certificate = loadFile (certPath); + UA_ByteString privateKey = loadFile (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]); + + /* Revocation list is unused in this demo. */ + UA_ByteString *revocationList = NULL; + size_t revocationListSize = 0; + + UA_StatusCode retval = UA_ClientConfig_setDefaultEncryption ( + cc, certificate, privateKey, trustList, trustSize, revocationList, + revocationListSize); + + UA_ByteString_clear (&certificate); + UA_ByteString_clear (&privateKey); + for (size_t i = 0; i < trustSize; i++) + UA_ByteString_clear (&trustList[i]); + + if (retval != UA_STATUSCODE_GOOD) + { + UA_LOG_ERROR (UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION, + "Failed to set client encryption. StatusCode %s", + UA_StatusCode_name (retval)); + return retval; + } + + UA_String_clear (&cc->clientDescription.applicationUri); + cc->clientDescription.applicationUri = UA_String_fromChars (applicationUri); + + cc->securityMode = securityMode; + cc->securityPolicyUri = UA_String_fromChars (securityPolicyUri); + + return retval; +} |
