From 47239db132de3db30b975d65853a5a2ee295124c Mon Sep 17 00:00:00 2001 From: Norbert Greiner Date: Mon, 4 Dec 2023 10:09:59 +0100 Subject: [PATCH 01/98] fix(server): memory handling in the server mdns implementation Fixes some issues, if the discovery url includes a path (size calculation and memcpy fix). --- src/server/ua_server_discovery_mdns.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/server/ua_server_discovery_mdns.c b/src/server/ua_server_discovery_mdns.c index fccb9c73145..ca39fe06bde 100644 --- a/src/server/ua_server_discovery_mdns.c +++ b/src/server/ua_server_discovery_mdns.c @@ -214,8 +214,10 @@ UA_DiscoveryManager_removeEntryFromServersOnNetwork(UA_Server *server, const cha /* Remove from list */ LIST_REMOVE(entry, pointers); UA_ServerOnNetwork_clear(&entry->serverOnNetwork); - if(entry->pathTmp) + if(entry->pathTmp) { UA_free(entry->pathTmp); + entry->pathTmp = NULL; + } UA_free(entry); return UA_STATUSCODE_GOOD; } @@ -223,12 +225,13 @@ UA_DiscoveryManager_removeEntryFromServersOnNetwork(UA_Server *server, const cha static void mdns_append_path_to_url(UA_String *url, const char *path) { size_t pathLen = strlen(path); + size_t newUrlLen = url->length + pathLen; //size of the new url string incl. the path /* todo: malloc may fail: return a statuscode */ char *newUrl = (char *)UA_malloc(url->length + pathLen); memcpy(newUrl, url->data, url->length); memcpy(newUrl + url->length, path, pathLen); UA_String_clear(url); - url->length = url->length + pathLen; + url->length = newUrlLen; url->data = (UA_Byte *) newUrl; } @@ -251,7 +254,7 @@ setTxt(UA_Server *server, const struct resource *r, UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Cannot alloc memory for mDNS srv path"); return; } - memcpy(&(entry->pathTmp), &path, pathLen); + memcpy(entry->pathTmp, path, pathLen); entry->pathTmp[pathLen] = '\0'; } } else { @@ -322,6 +325,7 @@ setSrv(UA_Server *server, const struct resource *r, if(entry->pathTmp) { mdns_append_path_to_url(&entry->serverOnNetwork.discoveryUrl, entry->pathTmp); UA_free(entry->pathTmp); + entry->pathTmp = NULL; } } From 66eb2d192138fa192408c5d3f51ca494f5b00c79 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 5 Dec 2023 12:29:05 +0100 Subject: [PATCH 02/98] feat(core): Add a consistency check to UA_Array_copy Users might have manually created an inconsistent array. Defensive programming is good practice. --- src/ua_types.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ua_types.c b/src/ua_types.c index b8f6739bb5d..5e5f174ef00 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -1752,7 +1752,9 @@ UA_Array_copy(const void *src, size_t size, return UA_STATUSCODE_GOOD; } - if(!type) + /* Check the array consistency -- defensive programming in case the user + * manually created an inconsistent array */ + if(UA_UNLIKELY(!type || !src)) return UA_STATUSCODE_BADINTERNALERROR; /* calloc, so we don't have to check retval in every iteration of copying */ From 16a182ea2e2fb872a0d0a826dc4b498f125ee697 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 15 Dec 2023 21:44:15 +0100 Subject: [PATCH 03/98] fix(core): Reset sequence numbers in UA_SecureChannel_close This was missed when the client reuses its SecureChannel structure. Some servers want the client to start the sequence number close to zero. Reported by Mike Granby in #6177. --- src/ua_securechannel.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/ua_securechannel.c b/src/ua_securechannel.c index f62aaf58fcb..6cef858ebc1 100644 --- a/src/ua_securechannel.c +++ b/src/ua_securechannel.c @@ -102,6 +102,22 @@ void UA_SecureChannel_close(UA_SecureChannel *channel) { /* Set the status to closed */ channel->state = UA_SECURECHANNELSTATE_CLOSED; + channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; + + /* Reset the SecurityMode and config */ + channel->securityMode = UA_MESSAGESECURITYMODE_INVALID; + memset(&channel->config, 0, sizeof(UA_ConnectionConfig)); + + /* Clean up the SecurityToken */ + UA_ChannelSecurityToken_clear(&channel->securityToken); + UA_ChannelSecurityToken_clear(&channel->altSecurityToken); + + /* Delete the channel context for the security policy */ + if(channel->securityPolicy) { + channel->securityPolicy->channelModule.deleteContext(channel->channelContext); + channel->securityPolicy = NULL; + channel->channelContext = NULL; + } /* Detach from the connection and close the connection */ if(channel->connection) { @@ -110,6 +126,15 @@ UA_SecureChannel_close(UA_SecureChannel *channel) { UA_Connection_detachSecureChannel(channel->connection); } + /* Clean up certificate and nonces */ + UA_ByteString_clear(&channel->remoteCertificate); + UA_ByteString_clear(&channel->localNonce); + UA_ByteString_clear(&channel->remoteNonce); + + /* Reset the sequence numbers */ + channel->receiveSequenceNumber = 0; + channel->sendSequenceNumber = 0; + /* Detach Sessions from the SecureChannel. This also removes outstanding * Publish requests whose RequestId is valid only for the SecureChannel. */ UA_SessionHeader *sh; @@ -122,19 +147,7 @@ UA_SecureChannel_close(UA_SecureChannel *channel) { } } - /* Delete the channel context for the security policy */ - if(channel->securityPolicy) { - channel->securityPolicy->channelModule.deleteContext(channel->channelContext); - channel->securityPolicy = NULL; - channel->channelContext = NULL; - } - - /* Delete members */ - UA_ByteString_clear(&channel->remoteCertificate); - UA_ByteString_clear(&channel->localNonce); - UA_ByteString_clear(&channel->remoteNonce); - UA_ChannelSecurityToken_clear(&channel->securityToken); - UA_ChannelSecurityToken_clear(&channel->altSecurityToken); + /* Delete remaining chunks */ UA_SecureChannel_deleteBuffered(channel); } From fe5415395ed748bb5519a0cce3764cc8fea5ee23 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 20 Feb 2024 11:37:35 +0100 Subject: [PATCH 04/98] fix(server): Add required locks to readSessionDiagnostics --- src/server/ua_server_ns0_diagnostics.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/server/ua_server_ns0_diagnostics.c b/src/server/ua_server_ns0_diagnostics.c index 72ac9aecb77..63d9ee95823 100644 --- a/src/server/ua_server_ns0_diagnostics.c +++ b/src/server/ua_server_ns0_diagnostics.c @@ -328,16 +328,22 @@ readSessionDiagnostics(UA_Server *server, const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp, const UA_NumericRange *range, UA_DataValue *value) { + UA_LOCK(&server->serviceMutex); + /* Get the Session */ UA_Session *session = UA_Server_getSessionById(server, sessionId); - if(!session) + if(!session) { + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINTERNALERROR; + } /* Read the BrowseName */ UA_QualifiedName bn; UA_StatusCode res = readWithReadValue(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &bn); - if(res != UA_STATUSCODE_GOOD) + if(res != UA_STATUSCODE_GOOD) { + UA_UNLOCK(&server->serviceMutex); return res; + } union { UA_SessionDiagnosticsDataType sddt; @@ -412,6 +418,7 @@ readSessionDiagnostics(UA_Server *server, cleanup: UA_QualifiedName_clear(&bn); + UA_UNLOCK(&server->serviceMutex); return res; } From 05b48e41ddaec3bdb9c15e83402966a57c25b0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20L=C3=B6tzsch?= Date: Mon, 19 Feb 2024 17:16:19 +0100 Subject: [PATCH 05/98] Use correct address when reading array members of session diagnostic types. --- src/server/ua_server_ns0_diagnostics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/ua_server_ns0_diagnostics.c b/src/server/ua_server_ns0_diagnostics.c index 63d9ee95823..aa764b43a7d 100644 --- a/src/server/ua_server_ns0_diagnostics.c +++ b/src/server/ua_server_ns0_diagnostics.c @@ -405,7 +405,7 @@ readSessionDiagnostics(UA_Server *server, res = UA_Variant_setScalarCopy(&value->value, content, type); } else { size_t len = *(size_t*)content; - content = (void*)(((uintptr_t)content) + sizeof(size_t)); + content = *(void**)((uintptr_t)content + sizeof(size_t)); res = UA_Variant_setArrayCopy(&value->value, content, len, type); } if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) From cb77551ecace056a1cb31e54def208755a2d5e0e Mon Sep 17 00:00:00 2001 From: m-obi Date: Mon, 4 Mar 2024 16:49:33 +0100 Subject: [PATCH 06/98] adding floating point number representation for ESP platform --- include/open62541/architecture_definitions.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/open62541/architecture_definitions.h b/include/open62541/architecture_definitions.h index 0bbde78b795..c7e9e10e98b 100644 --- a/include/open62541/architecture_definitions.h +++ b/include/open62541/architecture_definitions.h @@ -356,10 +356,11 @@ UA_STATIC_ASSERT(sizeof(bool) == 1, cannot_overlay_integers_with_large_bool); * Float Endianness * ^^^^^^^^^^^^^^^^ * The definition ``UA_FLOAT_IEEE754`` is set to true when the floating point - * number representation of the target architecture is IEEE 754. The definition - * ``UA_FLOAT_LITTLE_ENDIAN`` is set to true when the floating point number - * representation is in little-endian encoding. */ - + * number representation of the target architecture is IEEE 754. This can be + * set from outside with ``-DUA_FLOAT_IEEE754=1``. + * The definition ``UA_FLOAT_LITTLE_ENDIAN`` is set to true when the floating + * point number representation is in little-endian encoding. */ +#ifndef UA_FLOAT_IEEE754 #if defined(_WIN32) # define UA_FLOAT_IEEE754 1 #elif defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \ @@ -368,9 +369,12 @@ UA_STATIC_ASSERT(sizeof(bool) == 1, cannot_overlay_integers_with_large_bool); # define UA_FLOAT_IEEE754 1 #elif defined(__STDC_IEC_559__) # define UA_FLOAT_IEEE754 1 +#elif defined(ESP_PLATFORM) +# define UA_FLOAT_IEEE754 1 #else # define UA_FLOAT_IEEE754 0 #endif +#endif /* Wikipedia says (https://en.wikipedia.org/wiki/Endianness): Although the * ubiquitous x86 processors of today use little-endian storage for all types of From 2405c6588f8d8093e3e0e49e920db64daf479799 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 8 Apr 2024 16:48:20 +0200 Subject: [PATCH 07/98] Bump version to 1.3.10 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a051f12f6f..986ed1731cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 9) +set(OPEN62541_VER_PATCH 10) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 239aafff40f9d8d2610b33a4c7f457f3de6a9ffe Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 13 May 2024 09:49:20 +0200 Subject: [PATCH 08/98] fix(server): Add missing lock handling for the subscription diagnostics --- src/server/ua_server_ns0_diagnostics.c | 46 ++++++++++++++++++++------ 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/server/ua_server_ns0_diagnostics.c b/src/server/ua_server_ns0_diagnostics.c index aa764b43a7d..c35c1f4e95f 100644 --- a/src/server/ua_server_ns0_diagnostics.c +++ b/src/server/ua_server_ns0_diagnostics.c @@ -73,16 +73,22 @@ readSubscriptionDiagnostics(UA_Server *server, const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp, const UA_NumericRange *range, UA_DataValue *value) { + UA_LOCK(&server->serviceMutex); + /* Check the Subscription pointer */ UA_Subscription *sub = (UA_Subscription*)nodeContext; - if(!sub) + if(!sub) { + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINTERNALERROR; + } /* Read the BrowseName */ UA_QualifiedName bn; UA_StatusCode res = readWithReadValue(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &bn); - if(res != UA_STATUSCODE_GOOD) + if(res != UA_STATUSCODE_GOOD) { + UA_UNLOCK(&server->serviceMutex); return res; + } /* Set the value */ UA_SubscriptionDiagnosticsDataType sddt; @@ -112,17 +118,21 @@ readSubscriptionDiagnostics(UA_Server *server, UA_SubscriptionDiagnosticsDataType_clear(&sddt); UA_QualifiedName_clear(&bn); + + UA_UNLOCK(&server->serviceMutex); return res; } /* If the nodeContext == NULL, return all subscriptions in the server. * Otherwise only for the current session. */ -UA_StatusCode -readSubscriptionDiagnosticsArray(UA_Server *server, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, void *nodeContext, - UA_Boolean sourceTimestamp, - const UA_NumericRange *range, UA_DataValue *value) { +static UA_StatusCode +readSubscriptionDiagnosticsArrayLocked(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + /* Get the current session */ size_t sdSize = 0; UA_Session *session = NULL; @@ -168,6 +178,20 @@ readSubscriptionDiagnosticsArray(UA_Server *server, return UA_STATUSCODE_GOOD; } +UA_StatusCode +readSubscriptionDiagnosticsArray(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode res = readSubscriptionDiagnosticsArrayLocked( + server, sessionId, sessionContext, nodeId, nodeContext, + sourceTimestamp, range, value); + UA_UNLOCK(&server->serviceMutex); + return res; +} + void createSubscriptionObject(UA_Server *server, UA_Session *session, UA_Subscription *sub) { @@ -362,9 +386,9 @@ readSessionDiagnostics(UA_Server *server, /* Reuse the datasource callback. Forward a non-null nodeContext to * indicate that we want to see only the subscriptions for the current * session. */ - res = readSubscriptionDiagnosticsArray(server, sessionId, sessionContext, - nodeId, (void*)0x01, - sourceTimestamp, range, value); + res = readSubscriptionDiagnosticsArrayLocked(server, sessionId, sessionContext, + nodeId, (void*)0x01, + sourceTimestamp, range, value); goto cleanup; } else if(equalBrowseName(&bn.name, "SessionDiagnostics")) { setSessionDiagnostics(session, &data.sddt); From 1d5066d7efbbb199802e6fa86bfe80191a7eae58 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 13 May 2024 11:09:17 +0200 Subject: [PATCH 09/98] refactor(core): Bump version to 1.3.11 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 986ed1731cf..0f58b4f017d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 10) +set(OPEN62541_VER_PATCH 11) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 548a2ef985d85f1c7b3e41baa8281402919077e6 Mon Sep 17 00:00:00 2001 From: Andreas Ebner Date: Fri, 21 Jun 2024 09:42:28 +0200 Subject: [PATCH 10/98] fix(server) check history backend for event support in history-read service --- src/server/ua_services_attribute.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/server/ua_services_attribute.c b/src/server/ua_services_attribute.c index 2cf5f459964..091f5abe0ef 100644 --- a/src/server/ua_services_attribute.c +++ b/src/server/ua_services_attribute.c @@ -1833,6 +1833,14 @@ Service_HistoryRead(UA_Server *server, UA_Session *session, return; } + /* Check if the configured History-Backend supports the requested history type */ + if(!readHistory){ + UA_LOG_INFO_SESSION(server->config.logging, session, + "The configured HistoryBackend does not support the selected history-type."); + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED; + return; + } + /* Something to do? */ if(request->nodesToReadSize == 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; From 8d7fabcefe8d94d3a929567f42e4b591acbb83e6 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 2 Aug 2024 14:52:05 +0200 Subject: [PATCH 11/98] refactor(deps): Use only base64 routines under the BSD license The code from stackoverflow was (by default) under CC-BY-SA license. This has raised some unclear points concerning copyleft. --- deps/base64.c | 116 ++++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/deps/base64.c b/deps/base64.c index ce60b663e1c..2cf8ec803e8 100644 --- a/deps/base64.c +++ b/deps/base64.c @@ -1,10 +1,9 @@ /* - * Base64 encoding: Copyright (c) 2005-2011, Jouni Malinen - * This software may be distributed under the terms of the BSD license. + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen * - * Base64 decoding: Copyright (c) 2016, polfosol - * Posted at https://stackoverflow.com/a/37109258 under the CC-BY-SA Creative - * Commons license. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "base64.h" @@ -55,61 +54,68 @@ UA_base64(const unsigned char *src, size_t len, size_t *out_len) { return out; } -static const uint32_t from_b64[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, - 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; +static unsigned char dtable[256] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 62 , 0x80, 62 , 0x80, 63 , + 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , 0x80, 0x80, 0x80, 0, 0x80, 0x80, + 0x80, 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , + 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 0x80, 0x80, 0x80, 0x80, 63 , + 0x80, 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , + 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 , 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 +}; unsigned char * UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { - // we need a minimum length - if(len <= 2) { - *out_len = 0; - return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; - } - - const unsigned char *p = src; - size_t pad1 = len % 4 || p[len - 1] == '='; - size_t pad2 = pad1 && (len % 4 > 2 || p[len - 2] != '='); - const size_t last = (len - pad1) / 4 << 2; + if(len == 0) + return NULL; - unsigned char *str = (unsigned char*)UA_malloc(last / 4 * 3 + pad1 + pad2); - if(!str) - return NULL; + unsigned char *out, *pos; + size_t olen = len / 4 * 3; + pos = out = (unsigned char*)UA_malloc(olen); + if(!out) + return NULL; - unsigned char *pos = str; - for(size_t i = 0; i < last; i += 4) { - uint32_t n = from_b64[p[i]] << 18 | from_b64[p[i + 1]] << 12 | - from_b64[p[i + 2]] << 6 | from_b64[p[i + 3]]; - *pos++ = (unsigned char)(n >> 16); - *pos++ = (unsigned char)(n >> 8 & 0xFF); - *pos++ = (unsigned char)(n & 0xFF); - } + int pad = 0; + size_t count = 0; + unsigned char block[4]; + for(size_t i = 0; i < len; i++) { + unsigned char tmp = dtable[src[i]]; + if(tmp == 0x80) + continue; - if(pad1) { - if (last + 1 >= len) { - UA_free(str); - *out_len = 0; - return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; - } - uint32_t n = from_b64[p[last]] << 18 | from_b64[p[last + 1]] << 12; - *pos++ = (unsigned char)(n >> 16); - if(pad2) { - if (last + 2 >= len) { - UA_free(str); - *out_len = 0; - return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; - } - n |= from_b64[p[last + 2]] << 6; - *pos++ = (unsigned char)(n >> 8 & 0xFF); - } - } + if(src[i] == '=') + pad++; + block[count] = tmp; + count++; + if(count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if(pad) { + if(pad == 1) + pos--; + else if(pad == 2) + pos -= 2; + else { + /* Invalid padding */ + UA_free(out); + return NULL; + } + break; + } + } + } - *out_len = (uintptr_t)(pos - str); - return str; + *out_len = (size_t)(pos - out); + return out; } From 5131c69f3696afd745c2440d4333693a067d8d41 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 2 Aug 2024 15:24:29 +0200 Subject: [PATCH 12/98] feat(deps): Better validation during base64 decoding --- deps/base64.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/deps/base64.c b/deps/base64.c index 2cf8ec803e8..1dac29f8a92 100644 --- a/deps/base64.c +++ b/deps/base64.c @@ -75,7 +75,7 @@ static unsigned char dtable[256] = { unsigned char * UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { - if(len == 0) + if(len == 0 || len % 4 != 0) return NULL; unsigned char *out, *pos; @@ -84,38 +84,40 @@ UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { if(!out) return NULL; - int pad = 0; - size_t count = 0; + size_t pad = 0; + unsigned char count = 0; unsigned char block[4]; for(size_t i = 0; i < len; i++) { unsigned char tmp = dtable[src[i]]; - if(tmp == 0x80) - continue; + if(tmp == 0x80) + goto error; /* Invalid input */ if(src[i] == '=') pad++; + block[count] = tmp; count++; if(count == 4) { *pos++ = (block[0] << 2) | (block[1] >> 4); *pos++ = (block[1] << 4) | (block[2] >> 2); *pos++ = (block[2] << 6) | block[3]; - count = 0; if(pad) { - if(pad == 1) - pos--; - else if(pad == 2) - pos -= 2; - else { - /* Invalid padding */ - UA_free(out); - return NULL; - } + if(pad == 1) + pos--; + else if(pad == 2) + pos -= 2; + else + goto error; /* Invalid padding */ break; - } + } + count = 0; } } *out_len = (size_t)(pos - out); return out; + + error: + UA_free(out); + return NULL; } From 253fcabd400fe87db0cfa27535929d432aabc963 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 2 Aug 2024 15:52:05 +0200 Subject: [PATCH 13/98] fix(tests): Fix decoding of bad JSON --- tests/check_types_builtin_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check_types_builtin_json.c b/tests/check_types_builtin_json.c index 28b54484a91..ccf3fbaf828 100644 --- a/tests/check_types_builtin_json.c +++ b/tests/check_types_builtin_json.c @@ -4339,7 +4339,7 @@ START_TEST(UA_ByteString_bad_json_decode) { UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_BYTESTRING]); // then - ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); + ck_assert_int_ne(retval, UA_STATUSCODE_GOOD); UA_ByteString_clear(&out); } END_TEST From d445afa6bbe6761399755ff27a2a4f00ef469571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20V=C3=B6lker?= Date: Mon, 5 Aug 2024 17:08:42 +0200 Subject: [PATCH 14/98] Fix binary encoding and decoding for DiagnosticInfo The order of the locale and localizedText fields is different between the encoding mask and the encoded values in the body. --- src/ua_types_encoding_binary.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ua_types_encoding_binary.c b/src/ua_types_encoding_binary.c index 7b3a4f6b84e..7e1509267a6 100644 --- a/src/ua_types_encoding_binary.c +++ b/src/ua_types_encoding_binary.c @@ -1199,10 +1199,10 @@ ENCODE_BINARY(DiagnosticInfo) { ret |= ENCODE_DIRECT(&src->symbolicId, UInt32); /* Int32 */ if(src->hasNamespaceUri) ret |= ENCODE_DIRECT(&src->namespaceUri, UInt32); /* Int32 */ - if(src->hasLocalizedText) - ret |= ENCODE_DIRECT(&src->localizedText, UInt32); /* Int32 */ if(src->hasLocale) ret |= ENCODE_DIRECT(&src->locale, UInt32); /* Int32 */ + if(src->hasLocalizedText) + ret |= ENCODE_DIRECT(&src->localizedText, UInt32); /* Int32 */ if(ret != UA_STATUSCODE_GOOD) return ret; @@ -1245,14 +1245,14 @@ DECODE_BINARY(DiagnosticInfo) { dst->hasNamespaceUri = true; ret |= DECODE_DIRECT(&dst->namespaceUri, UInt32); /* Int32 */ } - if(encodingMask & 0x04u) { - dst->hasLocalizedText = true; - ret |= DECODE_DIRECT(&dst->localizedText, UInt32); /* Int32 */ - } if(encodingMask & 0x08u) { dst->hasLocale = true; ret |= DECODE_DIRECT(&dst->locale, UInt32); /* Int32 */ } + if(encodingMask & 0x04u) { + dst->hasLocalizedText = true; + ret |= DECODE_DIRECT(&dst->localizedText, UInt32); /* Int32 */ + } if(encodingMask & 0x10u) { dst->hasAdditionalInfo = true; ret |= DECODE_DIRECT(&dst->additionalInfo, String); From 0a522e44b109f175a0502912121d8d704efee945 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 7 Aug 2024 09:58:57 +0200 Subject: [PATCH 15/98] fix(server): Fix a build error for the historizing feature --- src/server/ua_services_attribute.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/ua_services_attribute.c b/src/server/ua_services_attribute.c index 091f5abe0ef..5c9f5d08349 100644 --- a/src/server/ua_services_attribute.c +++ b/src/server/ua_services_attribute.c @@ -1834,8 +1834,8 @@ Service_HistoryRead(UA_Server *server, UA_Session *session, } /* Check if the configured History-Backend supports the requested history type */ - if(!readHistory){ - UA_LOG_INFO_SESSION(server->config.logging, session, + if(!readHistory) { + UA_LOG_INFO_SESSION(&server->config.logger, session, "The configured HistoryBackend does not support the selected history-type."); response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED; return; From 73dc1b06b4fa1d58285f4acde320041ac0245f7e Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 7 Aug 2024 10:03:45 +0200 Subject: [PATCH 16/98] fix(deps): Fix a (false positive) type conversion warning in base64.c --- deps/base64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/base64.c b/deps/base64.c index 1dac29f8a92..ded1af55a69 100644 --- a/deps/base64.c +++ b/deps/base64.c @@ -98,9 +98,9 @@ UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { block[count] = tmp; count++; if(count == 4) { - *pos++ = (block[0] << 2) | (block[1] >> 4); - *pos++ = (block[1] << 4) | (block[2] >> 2); - *pos++ = (block[2] << 6) | block[3]; + *pos++ = (unsigned char)((block[0] << 2) | (block[1] >> 4)); + *pos++ = (unsigned char)((block[1] << 4) | (block[2] >> 2)); + *pos++ = (unsigned char)((block[2] << 6) | block[3]); if(pad) { if(pad == 1) pos--; From 07f5f4030d031680843e0fdd175ab136e51d275a Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 7 Aug 2024 10:03:45 +0200 Subject: [PATCH 17/98] fix(deps): Fix a (false positive) type conversion warning in base64.c --- deps/base64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/base64.c b/deps/base64.c index 1dac29f8a92..ded1af55a69 100644 --- a/deps/base64.c +++ b/deps/base64.c @@ -98,9 +98,9 @@ UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { block[count] = tmp; count++; if(count == 4) { - *pos++ = (block[0] << 2) | (block[1] >> 4); - *pos++ = (block[1] << 4) | (block[2] >> 2); - *pos++ = (block[2] << 6) | block[3]; + *pos++ = (unsigned char)((block[0] << 2) | (block[1] >> 4)); + *pos++ = (unsigned char)((block[1] << 4) | (block[2] >> 2)); + *pos++ = (unsigned char)((block[2] << 6) | block[3]); if(pad) { if(pad == 1) pos--; From 41ee330400bd67898bea61981c8fd85ad35b97ec Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Thu, 8 Aug 2024 16:45:16 +0200 Subject: [PATCH 18/98] fix(deps): Re-enable support for empty base64 strings --- deps/base64.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/deps/base64.c b/deps/base64.c index ded1af55a69..2b5d6b70870 100644 --- a/deps/base64.c +++ b/deps/base64.c @@ -75,18 +75,27 @@ static unsigned char dtable[256] = { unsigned char * UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { - if(len == 0 || len % 4 != 0) + /* Empty base64 results in an empty byte-string */ + if(len == 0) { + *out_len = 0; + return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; + } + + /* The input length must be a multiple of four */ + if(len % 4 != 0) return NULL; - unsigned char *out, *pos; + /* Allocate the output string */ size_t olen = len / 4 * 3; - pos = out = (unsigned char*)UA_malloc(olen); + unsigned char *out = (unsigned char*)UA_malloc(olen); if(!out) return NULL; + /* Iterate over the input */ size_t pad = 0; unsigned char count = 0; unsigned char block[4]; + unsigned char *pos = out; for(size_t i = 0; i < len; i++) { unsigned char tmp = dtable[src[i]]; if(tmp == 0x80) From a7f5371888c5beca5c952182bf2dd7baabbd54f3 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 9 Aug 2024 11:21:08 +0200 Subject: [PATCH 19/98] refactor(build): Bump version to v1.2.10 --- tools/cmake/SetGitBasedVersion.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cmake/SetGitBasedVersion.cmake b/tools/cmake/SetGitBasedVersion.cmake index c8eec383260..fb07baf573d 100644 --- a/tools/cmake/SetGitBasedVersion.cmake +++ b/tools/cmake/SetGitBasedVersion.cmake @@ -73,10 +73,10 @@ function(set_open62541_version) set(OPEN62541_VER_COMMIT ${OPEN62541_VERSION} PARENT_SCOPE) else() # Final fallback - set(OPEN62541_VERSION "v1.2.9-unknown" PARENT_SCOPE) + set(OPEN62541_VERSION "v1.2.10-unknown" PARENT_SCOPE) set(OPEN62541_VER_MAJOR 1 PARENT_SCOPE) set(OPEN62541_VER_MINOR 2 PARENT_SCOPE) - set(OPEN62541_VER_PATCH 9 PARENT_SCOPE) + set(OPEN62541_VER_PATCH 10 PARENT_SCOPE) set(OPEN62541_VER_LABEL "-unknown" PARENT_SCOPE) set(OPEN62541_VER_COMMIT "undefined" PARENT_SCOPE) message(WARNING "Failed to determine OPEN62541_VERSION from repository tags. Using default version \"${OPEN62541_VERSION}\".") From f9385773e9037aa31ec4ee7b4f3261b57d85ef09 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 9 Aug 2024 11:27:02 +0200 Subject: [PATCH 20/98] refactor(build): Bump version to v1.3.12 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f58b4f017d..1b9863ed34f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 11) +set(OPEN62541_VER_PATCH 12) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From f5de42a64360870c83468f7f725360ca58366769 Mon Sep 17 00:00:00 2001 From: Maddin-619 Date: Mon, 26 Aug 2024 16:58:42 +0200 Subject: [PATCH 21/98] fix(server): Select the right sp to check userTokenSignature --- src/server/ua_services_session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/ua_services_session.c b/src/server/ua_services_session.c index 0a940ea5a9b..3626efd44cd 100644 --- a/src/server/ua_services_session.c +++ b/src/server/ua_services_session.c @@ -781,7 +781,7 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, /* Check the user token signature */ response->responseHeader.serviceResult = - checkSignature(server, channel->securityPolicy, tempChannelContext, + checkSignature(server, securityPolicy, tempChannelContext, &session->serverNonce, &request->userTokenSignature); /* Delete the temporary channel context */ From acbf68420ac9fbf617f237407a56ebd5b6125479 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 2 Sep 2024 11:05:39 +0200 Subject: [PATCH 22/98] fix(core): add UA_EXPORT for UA_DataType_getStructMember --- src/ua_types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ua_types.c b/src/ua_types.c index 5e5f174ef00..ea5d3ca27af 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -1882,7 +1882,7 @@ UA_Array_delete(void *p, size_t size, const UA_DataType *type) { } #ifdef UA_ENABLE_TYPEDESCRIPTION -UA_Boolean +UA_Boolean UA_EXPORT UA_DataType_getStructMember(const UA_DataType *type, const char *memberName, size_t *outOffset, const UA_DataType **outMemberType, UA_Boolean *outIsArray) { From 317819b7d3b7c575b57310220c1be236acbfbac0 Mon Sep 17 00:00:00 2001 From: soekkle Date: Tue, 10 Sep 2024 09:07:58 +0200 Subject: [PATCH 23/98] fix(plugin): Avoid memmory read access errors (#6688) Check for null pointer befor passing then into a openssl function. --- plugins/crypto/openssl/ua_pki_openssl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index d85f4617a5f..478b50e5df7 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -556,11 +556,13 @@ UA_CertificateVerification_Verify (void * verificationContext, /* Fetch the Subject key identifier of the remote certificate */ remote_cert_keyid = X509_get0_subject_key_id(certificateX509); - /* Check remote certificate is present in the trust list */ - cmpVal = ASN1_OCTET_STRING_cmp(trusted_cert_keyid, remote_cert_keyid); - if (cmpVal == 0){ - ret = UA_STATUSCODE_GOOD; - goto cleanup; + if(trusted_cert_keyid && remote_cert_keyid) { + /* Check remote certificate is present in the trust list */ + cmpVal = ASN1_OCTET_STRING_cmp(trusted_cert_keyid, remote_cert_keyid); + if(cmpVal == 0) { + ret = UA_STATUSCODE_GOOD; + goto cleanup; + } } } } From 9b6848a7e89167be03bbc2229faf5ccfd07601e5 Mon Sep 17 00:00:00 2001 From: Romain Gauci Date: Tue, 10 Sep 2024 17:31:24 +0200 Subject: [PATCH 24/98] fix(plugin): Proper error handling when checking all CRLs If a chain of Certificate Authorities (CAs) longer than one is present, all CRL checks on the additional CAs were bypassed. This resulted in the potential acceptance of certificates that have been revoked or have expired CRLs. --- plugins/crypto/openssl/ua_pki_openssl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 478b50e5df7..3b2749f14ea 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -532,6 +532,8 @@ UA_CertificateVerification_Verify (void * verificationContext, opensslRet = X509_STORE_CTX_get_error (storeCtx); if (opensslRet == X509_V_ERR_UNABLE_TO_GET_CRL) { ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; + } else { + ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet); } } } From 083e4e93a235679a3b746934ba5b34f46d680dc1 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 11 Sep 2024 08:57:26 +0200 Subject: [PATCH 25/98] fix(core): Fix UA_EXPORT annotations for UA_DataType handling --- include/open62541/types.h | 6 +++--- src/ua_types.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/open62541/types.h b/include/open62541/types.h index 6374480a33f..9ea3c3c38bb 100644 --- a/include/open62541/types.h +++ b/include/open62541/types.h @@ -1067,7 +1067,7 @@ typedef struct UA_DataTypeArray { * If the member is an array, the offset points to the (size_t) length field. * (The array pointer comes after the length field without any padding.) */ #ifdef UA_ENABLE_TYPEDESCRIPTION -UA_Boolean +UA_Boolean UA_EXPORT UA_DataType_getStructMember(const UA_DataType *type, const char *memberName, size_t *outOffset, @@ -1078,12 +1078,12 @@ UA_DataType_getStructMember(const UA_DataType *type, /* Test if the data type is a numeric builtin data type (via the typeKind field * of UA_DataType). This includes integers and floating point numbers. Not * included are Boolean, DateTime, StatusCode and Enums. */ -UA_Boolean +UA_Boolean UA_EXPORT UA_DataType_isNumeric(const UA_DataType *type); /* Return the Data Type Precedence-Rank defined in Part 4. * If there is no Precedence-Rank assigned with the type -1 is returned.*/ -UA_Int16 +UA_Int16 UA_EXPORT UA_DataType_getPrecedence(const UA_DataType *type); /** diff --git a/src/ua_types.c b/src/ua_types.c index ea5d3ca27af..c2c14cccac0 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -1850,7 +1850,7 @@ UA_Array_append(void **p, size_t *size, void *newElem, return UA_STATUSCODE_GOOD; } -UA_StatusCode UA_EXPORT +UA_StatusCode UA_Array_appendCopy(void **p, size_t *size, const void *newElem, const UA_DataType *type) { char scratch[512]; @@ -1882,7 +1882,7 @@ UA_Array_delete(void *p, size_t size, const UA_DataType *type) { } #ifdef UA_ENABLE_TYPEDESCRIPTION -UA_Boolean UA_EXPORT +UA_Boolean UA_DataType_getStructMember(const UA_DataType *type, const char *memberName, size_t *outOffset, const UA_DataType **outMemberType, UA_Boolean *outIsArray) { From e613a90d97d7d06396dee1a1bca6fabccd8f778f Mon Sep 17 00:00:00 2001 From: Andreas Ebner Date: Thu, 18 Jan 2024 15:25:43 +0100 Subject: [PATCH 26/98] feat(core) update mdnsd submodule refernce (cherry picked from commit 012b62cb28c5cae3ebc07201075f0ef629a66518) --- deps/mdnsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/mdnsd b/deps/mdnsd index 3151afe5899..488d24fb9d4 160000 --- a/deps/mdnsd +++ b/deps/mdnsd @@ -1 +1 @@ -Subproject commit 3151afe5899dba5125dffa9f4cf3ae1fe2edc0f0 +Subproject commit 488d24fb9d427aec77df180268f0291eeee7fb8b From 44e1987e1221c47ec5a202a84e02db1b6a2d7580 Mon Sep 17 00:00:00 2001 From: Noel Graf Date: Mon, 16 Sep 2024 09:38:33 +0200 Subject: [PATCH 27/98] fix(ci): Fix azure pipeline build for 1.3 --- tools/azure-devops/win/build.ps1 | 4 ++-- tools/azure-devops/win/install.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/azure-devops/win/build.ps1 b/tools/azure-devops/win/build.ps1 index 8986d409101..17d71c4424d 100644 --- a/tools/azure-devops/win/build.ps1 +++ b/tools/azure-devops/win/build.ps1 @@ -47,8 +47,8 @@ try { Copy-Item AUTHORS pack Copy-Item README.md pack - # Only execute unit tests on vs2017 to save compilation time - if ($env:CC_SHORTNAME -eq "vs2017") { + # Only execute unit tests on vs2019 to save compilation time + if ($env:CC_SHORTNAME -eq "vs2019") { Write-Host -ForegroundColor Green "`n###################################################################" Write-Host -ForegroundColor Green "`n##### Testing $env:CC_NAME with unit tests #####`n" New-Item -ItemType directory -Path "build" diff --git a/tools/azure-devops/win/install.ps1 b/tools/azure-devops/win/install.ps1 index 7e029ca61dd..8936000664f 100644 --- a/tools/azure-devops/win/install.ps1 +++ b/tools/azure-devops/win/install.ps1 @@ -28,7 +28,7 @@ try { exit $LASTEXITCODE } - } elseif ($env:CC_SHORTNAME -eq "vs2015" -or $env:CC_SHORTNAME -eq "vs2017") { + } else { Write-Host -ForegroundColor Green "`n### Installing mbedtls via vcpkg ###`n" & vcpkg install mbedtls:x86-windows-static if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { From 24de47803bf2a2ac69f5b516fbd112f759b0848f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6tz=20G=C3=B6risch?= <47734341+GoetzGoerisch@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:47:03 +0000 Subject: [PATCH 28/98] fix(ci): Updates azure pipelines * now using ubuntu-20.04 (cherry picked from commit 13b412558ff026d73e0d44bd162690cc043997a6) --- .azure-pipelines/azure-pipelines-dist.yml | 2 +- .azure-pipelines/azure-pipelines-linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.azure-pipelines/azure-pipelines-dist.yml b/.azure-pipelines/azure-pipelines-dist.yml index de12655b011..9b07fb6b54c 100644 --- a/.azure-pipelines/azure-pipelines-dist.yml +++ b/.azure-pipelines/azure-pipelines-dist.yml @@ -5,7 +5,7 @@ jobs: - job: 'dist_debian' displayName: 'Dist (debian)' pool: - vmImage: 'ubuntu-18.04' + vmImage: 'ubuntu-20.04' steps: - checkout: self submodules: recursive diff --git a/.azure-pipelines/azure-pipelines-linux.yml b/.azure-pipelines/azure-pipelines-linux.yml index 4240cfcae6d..6625754ea2f 100644 --- a/.azure-pipelines/azure-pipelines-linux.yml +++ b/.azure-pipelines/azure-pipelines-linux.yml @@ -5,7 +5,7 @@ jobs: - job: 'cross_freeRTOS' displayName: 'Arch (freeRTOS)' pool: - vmImage: 'ubuntu-18.04' + vmImage: 'ubuntu-20.04' variables: IDF_PATH: $(Build.BinariesDirectory)/esp-idf steps: From eb7e4277757b18337a8c41717dbae47edcd5db42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6tz=20G=C3=B6risch?= <47734341+GoetzGoerisch@users.noreply.github.com> Date: Wed, 11 Jan 2023 17:05:41 +0000 Subject: [PATCH 29/98] fix(ci): Adapts install script to ubuntu-20.04 * updates mbedTLS to 2.28.2 (cherry picked from commit b87738545a9975d91a33a4a07ec847c41cb50347) --- tools/azure-devops/debian/install.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/azure-devops/debian/install.sh b/tools/azure-devops/debian/install.sh index 19935fa6299..6168486c9a5 100644 --- a/tools/azure-devops/debian/install.sh +++ b/tools/azure-devops/debian/install.sh @@ -12,17 +12,17 @@ sudo apt install -y \ graphviz \ latexmk \ libsubunit-dev \ - python-sphinx \ + python3-sphinx \ python3-pip \ tar \ texlive-fonts-recommended \ - texlive-generic-extra \ + texlive-extra-utils \ texlive-latex-extra \ wget -wget https://github.com/ARMmbed/mbedtls/archive/mbedtls-2.7.1.tar.gz -tar xf mbedtls-2.7.1.tar.gz -cd mbedtls-mbedtls-2.7.1 +wget https://github.com/ARMmbed/mbedtls/archive/mbedtls-2.28.2.tar.gz +tar xf mbedtls-2.28.2.tar.gz +cd mbedtls-mbedtls-2.28.2 cmake -DENABLE_TESTING=Off . make -j sudo make install From bb20fb7b1def065b69996292f38dbc802f204706 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 24 Dec 2023 00:58:51 +0100 Subject: [PATCH 30/98] refactor(build): Switch to x64 VS2019 builds (cherry picked from commit fd37838e2bb4445dff76dd7acc8d04d835b38f90) --- tools/azure-devops/win/build.ps1 | 22 +++++++-------- tools/azure-devops/win/install.ps1 | 43 +++++++++++++++++------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/tools/azure-devops/win/build.ps1 b/tools/azure-devops/win/build.ps1 index 17d71c4424d..d2091f93ad2 100644 --- a/tools/azure-devops/win/build.ps1 +++ b/tools/azure-devops/win/build.ps1 @@ -26,18 +26,16 @@ try { if ($env:CC_SHORTNAME -eq "mingw") { - } elseif ($env:CC_SHORTNAME -eq "clang-mingw") { - # Setup clang - $env:CC = "clang --target=x86_64-w64-mingw32" - $env:CXX = "clang++ --target=x86_64-w64-mingw32" - clang --version - } else { - $vcpkg_toolchain = '-DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake"' - $vcpkg_triplet = '-DVCPKG_TARGET_TRIPLET="x86-windows-static"' - # since https://github.com/Microsoft/vcpkg/commit/0334365f516c5f229ff4fcf038c7d0190979a38a#diff-464a170117fa96bf98b2f8d224bf503c - # vcpkg need to have "C:\Tools\vcpkg\installed\x86-windows-static" - New-Item -Force -ItemType directory -Path "C:/vcpkg/installed/x86-windows-static" - } +} elseif ($env:CC_SHORTNAME -eq "clang-mingw") { + # Setup clang + $env:CC = "clang --target=x86_64-w64-mingw32" + $env:CXX = "clang++ --target=x86_64-w64-mingw32" + clang --version +} else { + $vcpkg_toolchain = '-DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake"' + $vcpkg_triplet = '-DVCPKG_TARGET_TRIPLET="x64-windows"' + New-Item -Force -ItemType directory -Path "C:/vcpkg/installed/x64-windows" +} $cmake_cnf="$vcpkg_toolchain", "$vcpkg_triplet", "-G`"$env:GENERATOR`"", "-DUA_FORCE_CPP:BOOL=$env:FORCE_CXX" diff --git a/tools/azure-devops/win/install.ps1 b/tools/azure-devops/win/install.ps1 index 8936000664f..02a73cf3329 100644 --- a/tools/azure-devops/win/install.ps1 +++ b/tools/azure-devops/win/install.ps1 @@ -21,27 +21,32 @@ try { # Otherwise we run into issue: https://github.com/msys2/MINGW-packages/issues/6576 & C:\msys64\usr\bin\pacman -Syu - Write-Host -ForegroundColor Green "`n### Installing mbedtls via PacMan ###`n" - & C:\msys64\usr\bin\pacman --noconfirm --needed -S mingw-w64-x86_64-mbedtls - if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { - Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" - exit $LASTEXITCODE - } + Write-Host -ForegroundColor Green "`n### Installing mbedtls via PacMan ###`n" + & C:\msys64\usr\bin\pacman --noconfirm --needed -S mingw-w64-x86_64-mbedtls + if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { + Write-Host -ForegroundColor Red "`n`n*** Install of mbedTLS failed. Exiting ... ***" + exit $LASTEXITCODE + } - } else { - Write-Host -ForegroundColor Green "`n### Installing mbedtls via vcpkg ###`n" - & vcpkg install mbedtls:x86-windows-static - if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { - Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" - exit $LASTEXITCODE - } + & C:\msys64\usr\bin\pacman --noconfirm --needed -S mingw-w64-x86_64-check + if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { + Write-Host -ForegroundColor Red "`n`n*** Install of check failed. Exiting ... ***" + exit $LASTEXITCODE + } +} else { + Write-Host -ForegroundColor Green "`n### Installing mbedtls via vcpkg ###`n" + & vcpkg install mbedtls:x64-windows + if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { + Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" + exit $LASTEXITCODE + } - Write-Host -ForegroundColor Green "`n### Installing libcheck via vcpkg ###`n" - & vcpkg install check:x86-windows-static - if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { - Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" - exit $LASTEXITCODE - } + Write-Host -ForegroundColor Green "`n### Installing libcheck via vcpkg ###`n" + & vcpkg install check:x64-windows + if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { + Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" + exit $LASTEXITCODE + } Write-Host -ForegroundColor Green "`n### Installing DrMemory ###`n" & choco install -y --no-progress drmemory.portable From 5d5ab15293e777c6cfb0c83d81a1fa44d0107edf Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 24 Dec 2023 01:49:50 +0100 Subject: [PATCH 31/98] refactor(ci): Pin vcpkg triplet to x64-windows-static (cherry picked from commit 7c657977b91bf990258383bbabfbded2150baf9e) --- tools/azure-devops/win/build.ps1 | 3 +-- tools/azure-devops/win/install.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/azure-devops/win/build.ps1 b/tools/azure-devops/win/build.ps1 index d2091f93ad2..39d1bb051a7 100644 --- a/tools/azure-devops/win/build.ps1 +++ b/tools/azure-devops/win/build.ps1 @@ -33,8 +33,7 @@ try { clang --version } else { $vcpkg_toolchain = '-DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake"' - $vcpkg_triplet = '-DVCPKG_TARGET_TRIPLET="x64-windows"' - New-Item -Force -ItemType directory -Path "C:/vcpkg/installed/x64-windows" + $vcpkg_triplet = '-DVCPKG_TARGET_TRIPLET="x64-windows-static"' } $cmake_cnf="$vcpkg_toolchain", "$vcpkg_triplet", "-G`"$env:GENERATOR`"", "-DUA_FORCE_CPP:BOOL=$env:FORCE_CXX" diff --git a/tools/azure-devops/win/install.ps1 b/tools/azure-devops/win/install.ps1 index 02a73cf3329..2ac25c03f06 100644 --- a/tools/azure-devops/win/install.ps1 +++ b/tools/azure-devops/win/install.ps1 @@ -35,14 +35,14 @@ try { } } else { Write-Host -ForegroundColor Green "`n### Installing mbedtls via vcpkg ###`n" - & vcpkg install mbedtls:x64-windows + & vcpkg install mbedtls:x64-windows-static if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" exit $LASTEXITCODE } Write-Host -ForegroundColor Green "`n### Installing libcheck via vcpkg ###`n" - & vcpkg install check:x64-windows + & vcpkg install check:x64-windows-static if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" exit $LASTEXITCODE From 46b1d0d4192cb27da51a32e03e95d711415a60ed Mon Sep 17 00:00:00 2001 From: estr Eckerstorfer Andreas Date: Thu, 12 Sep 2024 09:09:16 +0200 Subject: [PATCH 32/98] fix(ci): Add bcrypt library for windows (cherry picked from commit 5849f46e9c520e5fc376d78ec93014775eb18191) --- CMakeLists.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b9863ed34f..fbced8259ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -605,8 +605,12 @@ if(UA_ENABLE_ENCRYPTION_OPENSSL OR UA_ENABLE_MQTT_TLS_OPENSSL) # use the OpenSSL encryption library # https://cmake.org/cmake/help/v3.0/module/FindOpenSSL.html find_package(OpenSSL REQUIRED) - list(APPEND open62541_LIBRARIES ${OPENSSL_LIBRARIES}) - endif () + list(APPEND open62541_LIBRARIES "${OPENSSL_LIBRARIES}") + if(WIN32) + # Add bestcrypt for windows systems + list(APPEND open62541_LIBRARIES bcrypt) + endif() +endif() if(UA_ENABLE_ENCRYPTION_LIBRESSL) # See https://github.com/libressl-portable/portable/blob/master/FindLibreSSL.cmake @@ -624,6 +628,10 @@ if(UA_ENABLE_ENCRYPTION_MBEDTLS OR UA_ENABLE_PUBSUB_ENCRYPTION) # defined in /tools/cmake/FindMbedTLS.cmake. find_package(MbedTLS REQUIRED) list(APPEND open62541_LIBRARIES ${MBEDTLS_LIBRARIES}) + if(WIN32) + # Add bestcrypt for windows systems + list(APPEND open62541_LIBRARIES bcrypt) + endif() endif() if(UA_ENABLE_TPM2_SECURITY) From d04e8156c4ecac526477bad8e0b2448b3c69f298 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 24 Dec 2023 02:16:26 +0100 Subject: [PATCH 33/98] fix(test): Remove use of raw sleep() in all unit tests (cherry picked from commit c136967af3f062df41dc278af5721e7e61a87482) --- tests/client/check_client_async_connect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/client/check_client_async_connect.c b/tests/client/check_client_async_connect.c index 8c86a51d36e..e9045ff73cc 100644 --- a/tests/client/check_client_async_connect.c +++ b/tests/client/check_client_async_connect.c @@ -77,6 +77,8 @@ START_TEST(Client_connect_async) { UA_Client_sendAsyncBrowseRequest(client, &bReq, asyncBrowseCallback, &asyncCounter, &reqId); } + /* Give network a chance to process packet */ + UA_realSleep(100); /* Manual clock for unit tests */ UA_Server_run_iterate(server, false); retval = UA_Client_run_iterate(client, 0); @@ -182,7 +184,7 @@ START_TEST(Client_run_iterate) { UA_Server_run_iterate(server, false); retval = UA_Client_run_iterate(client, 0); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); - sleep(0); + UA_realSleep(100); } UA_Client_delete(client); } From 2c9b91aaff3f8571d76a9ede211839e963fc18b7 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 24 Dec 2023 02:49:50 +0100 Subject: [PATCH 34/98] refactor(ci): Don't use DrMemory on Azure, takes too long (cherry picked from commit d2e62e238676e547400f3414108c761bdfa6b5bc) --- tools/azure-devops/win/build.ps1 | 3 +-- tools/azure-devops/win/install.ps1 | 9 --------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/tools/azure-devops/win/build.ps1 b/tools/azure-devops/win/build.ps1 index 39d1bb051a7..b443eee5930 100644 --- a/tools/azure-devops/win/build.ps1 +++ b/tools/azure-devops/win/build.ps1 @@ -63,8 +63,7 @@ try { -DUA_ENABLE_PUBSUB:BOOL=ON ` -DUA_ENABLE_PUBSUB_DELTAFRAMES:BOOL=ON ` -DUA_ENABLE_PUBSUB_INFORMATIONMODEL:BOOL=ON ` - -DUA_ENABLE_PUBSUB_MONITORING:BOOL=ON ` - -DUA_ENABLE_UNIT_TESTS_MEMCHECK=ON .. + -DUA_ENABLE_PUBSUB_MONITORING:BOOL=ON .. & cmake --build . --config Debug if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Write-Host -ForegroundColor Red "`n`n*** Make failed. Exiting ... ***" diff --git a/tools/azure-devops/win/install.ps1 b/tools/azure-devops/win/install.ps1 index 2ac25c03f06..93a9791ef8c 100644 --- a/tools/azure-devops/win/install.ps1 +++ b/tools/azure-devops/win/install.ps1 @@ -47,15 +47,6 @@ try { Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" exit $LASTEXITCODE } - - Write-Host -ForegroundColor Green "`n### Installing DrMemory ###`n" - & choco install -y --no-progress drmemory.portable - if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { - Write-Host -ForegroundColor Red "`n`n*** Install failed. Exiting ... ***" - exit $LASTEXITCODE - } - #$env:Path = 'C:\Program Files (x86)\Dr. Memory\bin;' + $env:Path - #[System.Environment]::SetEnvironmentVariable('Path', $path, 'Machine') } if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { From f4af493b579b02700ba6cfdb47845747fd01e8f8 Mon Sep 17 00:00:00 2001 From: Christian von Arnim Date: Fri, 3 Jun 2022 12:16:16 +0200 Subject: [PATCH 35/98] fix(core): LibreSSL 3.5 (cherry picked from commit 35939a5b688d9647dbc96db88df5df27ebcced7a) --- plugins/crypto/openssl/ua_openssl_version_abstraction.h | 4 ++-- plugins/crypto/openssl/ua_pki_openssl.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/crypto/openssl/ua_openssl_version_abstraction.h b/plugins/crypto/openssl/ua_openssl_version_abstraction.h index a6fa45bdf70..c3eb7fd7dc5 100644 --- a/plugins/crypto/openssl/ua_openssl_version_abstraction.h +++ b/plugins/crypto/openssl/ua_openssl_version_abstraction.h @@ -21,11 +21,11 @@ #define X509_STORE_CTX_set0_trusted_stack(STORE_CTX, CTX_SKTRUSTED) X509_STORE_CTX_trusted_stack(STORE_CTX, CTX_SKTRUSTED) #endif -#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050000fL) #define X509_STORE_CTX_get_check_issued(STORE_CTX) STORE_CTX->check_issued #endif -#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050000fL) #define get_pkey_rsa(evp) ((evp)->pkey.rsa) #else #define get_pkey_rsa(evp) EVP_PKEY_get0_RSA(evp) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 3b2749f14ea..87b91e03c1e 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -485,7 +485,7 @@ UA_CertificateVerification_Verify (void * verificationContext, /* Set flag to check if the certificate has an invalid signature */ X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CHECK_SS_SIGNATURE); - if (X509_STORE_CTX_get_check_issued(storeCtx) (storeCtx,certificateX509, certificateX509) != 1) { + if (X509_check_issued(certificateX509,certificateX509) != X509_V_OK) { X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK); } @@ -505,7 +505,7 @@ UA_CertificateVerification_Verify (void * verificationContext, /* Check if the not trusted certificate has a CRL file. If there is no CRL file available for the corresponding * parent certificate then return status code UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN. Refer the test * case CTT/Security/Security Certificate Validation/002.js */ - if (X509_STORE_CTX_get_check_issued (storeCtx) (storeCtx,certificateX509, certificateX509) != 1) { + if (X509_check_issued(certificateX509,certificateX509) != X509_V_OK) { /* Free X509_STORE_CTX and reuse it for certification verification */ if (storeCtx != NULL) { X509_STORE_CTX_free(storeCtx); From 86db884eb48925dc2751ce5ed293218f0053ac30 Mon Sep 17 00:00:00 2001 From: Noel Graf Date: Fri, 13 Sep 2024 11:38:50 +0200 Subject: [PATCH 36/98] fix(deps): Bump LibreSSL to 3.7.2 --- .github/workflows/build_linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 50201b43225..59a26d4fe99 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -41,9 +41,9 @@ jobs: - build_name: "Encryption (LibreSSL) Build & Unit Tests (gcc)" cmd_deps: | sudo apt-get install -y -qq curl - curl https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.4.2.tar.gz --output libressl.tar.gz + curl https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.7.2.tar.gz --output libressl.tar.gz tar -xvz -f libressl.tar.gz - cd libressl-3.4.2 + cd libressl-3.7.2 ./configure sudo make install cmd_action: unit_tests_encryption LIBRESSL From f199580223c5c5e81d69de26929ba702713db7aa Mon Sep 17 00:00:00 2001 From: Noel Graf Date: Thu, 12 Sep 2024 14:48:04 +0200 Subject: [PATCH 37/98] fix(plugin): Proper error handling when checking parent CRL for the mbedTLS backend --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index c990ea14305..b5cb09c6321 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -375,7 +375,13 @@ certificateVerification_verify(void *verificationContext, /* If the CRL file corresponding to the parent certificate is not present * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */ - if(!issuerKnown) { + if(issuerKnown) { + flags = 0; + mbedErr = mbedtls_x509_crt_verify_with_profile(parentCert, + &ci->certificateIssuerList, + &ci->certificateRevocationList, + &crtProfile, NULL, &flags, NULL, NULL); + } else { return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; } @@ -417,8 +423,14 @@ certificateVerification_verify(void *verificationContext, /* If the CRL file corresponding to the parent certificate is not present * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */ - if(!issuerKnown) { - return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; + if(issuerKnown) { + flags = 0; + mbedErr = mbedtls_x509_crt_verify_with_profile(parentCert, + &ci->certificateIssuerList, + &ci->certificateRevocationList, + &crtProfile, NULL, &flags, NULL, NULL); + } else { + return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; } } From 90661da2b2e8f07d8bfe31f3431ce8498fccd48a Mon Sep 17 00:00:00 2001 From: Noel Graf Date: Wed, 11 Sep 2024 15:08:45 +0200 Subject: [PATCH 38/98] feat(test): Add test cases for CRL validation --- tests/CMakeLists.txt | 4 + tests/encryption/certificates.h | 1172 ++++++++++++++++++++--- tests/encryption/check_crl_validation.c | 337 +++++++ 3 files changed, 1377 insertions(+), 136 deletions(-) create mode 100644 tests/encryption/check_crl_validation.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 89c23af6b0d..4e9cf9c9aca 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -585,6 +585,10 @@ if(UA_ENABLE_ENCRYPTION) add_executable(check_client_encryption client/check_client_encryption.c $ $) target_link_libraries(check_client_encryption ${LIBS}) add_test_valgrind(client_encryption ${TESTS_BINARY_DIR}/check_client_encryption) + + add_executable(check_crl_validation encryption/check_crl_validation.c $ $) + target_link_libraries(check_crl_validation ${LIBS}) + add_test_valgrind(crl_validation ${TESTS_BINARY_DIR}/check_crl_validation) endif() if(UA_ENABLE_ENCRYPTION_MBEDTLS) diff --git a/tests/encryption/certificates.h b/tests/encryption/certificates.h index a3810e9deb8..75089746058 100644 --- a/tests/encryption/certificates.h +++ b/tests/encryption/certificates.h @@ -7,146 +7,146 @@ _UA_BEGIN_DECLS #define KEY_DER_LENGTH 1193 UA_Byte KEY_DER_DATA[1193] = { - 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe0, 0xc9, 0x91, 0x62, - 0xcd, 0x91, 0x68, 0x75, 0x2c, 0x32, 0x7a, 0xdd, 0xf1, 0xd6, 0x64, 0x77, 0x8b, 0x72, 0x9e, 0x14, - 0x2a, 0x62, 0x08, 0xd1, 0x89, 0x7d, 0xe2, 0x17, 0xdc, 0xb3, 0xda, 0xbc, 0x3a, 0x9f, 0x84, 0x03, - 0xd3, 0x2e, 0x68, 0xbe, 0xc1, 0x57, 0xcb, 0x2a, 0xe2, 0xd6, 0xcf, 0xc4, 0x7f, 0xbd, 0x53, 0x3f, - 0xeb, 0x39, 0x98, 0x69, 0xb0, 0x40, 0x14, 0xbf, 0xf5, 0x5a, 0x23, 0x23, 0xf4, 0x4c, 0xf8, 0xf1, - 0x03, 0x56, 0x6d, 0x7d, 0x1b, 0x93, 0xd7, 0x0f, 0xc1, 0x8c, 0x70, 0xe0, 0x2c, 0x55, 0x7e, 0xa1, - 0xfc, 0x05, 0xe9, 0xd7, 0xea, 0xb1, 0x5c, 0x0f, 0x9b, 0xac, 0x6a, 0x2e, 0xb4, 0xc5, 0xbf, 0x41, - 0x8f, 0xda, 0xfc, 0x85, 0xc6, 0xaa, 0x25, 0xe4, 0xb9, 0x9a, 0xc6, 0xd8, 0x9a, 0x31, 0x8a, 0x17, - 0x8b, 0x8c, 0x4e, 0x20, 0xd9, 0x71, 0xfc, 0x66, 0x3a, 0xfd, 0x49, 0x95, 0x54, 0xa8, 0xaf, 0x42, - 0x5e, 0xba, 0x26, 0xe6, 0xd3, 0xa0, 0xd2, 0x02, 0x3b, 0x51, 0x8b, 0x39, 0xd3, 0x97, 0xd2, 0xe4, - 0xd1, 0x01, 0x65, 0xab, 0x8e, 0xa2, 0x80, 0x5b, 0x5e, 0xbb, 0x11, 0x7f, 0x50, 0x1b, 0x2b, 0x0d, - 0x20, 0x40, 0xb5, 0xbf, 0xd1, 0x32, 0xfa, 0x25, 0xe1, 0x0d, 0x75, 0xfc, 0x11, 0xcf, 0x21, 0xdd, - 0x45, 0x16, 0xe4, 0x56, 0x58, 0x49, 0x33, 0xca, 0xaf, 0xe3, 0x17, 0x7b, 0x7a, 0x8f, 0xb1, 0xec, - 0x1c, 0x4d, 0xa2, 0xc2, 0xce, 0x8b, 0x19, 0x4b, 0xc0, 0xc4, 0x36, 0x6a, 0x7c, 0x5b, 0x89, 0x14, - 0x98, 0xcb, 0xa9, 0xca, 0x66, 0xf2, 0xaa, 0xf9, 0x12, 0x40, 0x0e, 0x6a, 0x78, 0x4d, 0x1f, 0x54, - 0x3c, 0x03, 0x7a, 0x91, 0xf5, 0xb7, 0x3d, 0xe2, 0xfc, 0x65, 0xb7, 0xaa, 0xa9, 0x39, 0x68, 0xa7, - 0xdb, 0x29, 0xc1, 0x40, 0x0b, 0x4e, 0xfb, 0xce, 0x74, 0xa5, 0x46, 0xb9, 0x02, 0x03, 0x01, 0x00, - 0x01, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb4, 0xc8, 0x07, 0x60, 0x01, 0xd9, 0xb6, 0xbb, 0xbd, 0x8e, - 0xdf, 0x97, 0xcd, 0xde, 0x51, 0xb0, 0x7e, 0xfa, 0xf0, 0x3d, 0x61, 0x94, 0xb4, 0x68, 0xe8, 0x7d, - 0xd0, 0x2e, 0xc6, 0xb5, 0xf2, 0xed, 0xbc, 0xeb, 0xfb, 0x3d, 0x24, 0x43, 0x47, 0xc4, 0x5a, 0x34, - 0x64, 0x56, 0x1a, 0x57, 0x0e, 0x83, 0x87, 0x04, 0x59, 0x86, 0xa7, 0x84, 0x0b, 0x9a, 0xbc, 0x3f, - 0xdd, 0x30, 0x40, 0x7f, 0x7c, 0x91, 0x76, 0xf1, 0xcc, 0xa7, 0xf0, 0xba, 0x3a, 0x96, 0x0a, 0x6e, - 0xcc, 0xe0, 0x84, 0x15, 0x91, 0xd6, 0x08, 0x71, 0xbd, 0xc5, 0x42, 0xad, 0xf2, 0xd2, 0x4e, 0x92, - 0xd3, 0x6a, 0x4e, 0x15, 0xcc, 0xd3, 0xc1, 0x58, 0xe4, 0x27, 0x33, 0x2d, 0xb8, 0x37, 0x52, 0x7e, - 0x16, 0xb9, 0xab, 0xb7, 0xd9, 0xc1, 0xeb, 0xc8, 0x79, 0xb9, 0xd3, 0xe6, 0x44, 0x13, 0x51, 0x2d, - 0xc6, 0x02, 0xe5, 0xe0, 0x3c, 0xa3, 0x15, 0x9b, 0x49, 0xae, 0x85, 0xbe, 0x8c, 0x84, 0xf9, 0x87, - 0x5d, 0x91, 0x9e, 0xf4, 0xf9, 0xf2, 0x8d, 0x81, 0x77, 0x7c, 0xfc, 0x60, 0x09, 0x48, 0x43, 0x2e, - 0xbb, 0xaf, 0xc9, 0xd6, 0x90, 0x2d, 0x40, 0x80, 0x59, 0xbd, 0x3b, 0x04, 0xda, 0x50, 0x2a, 0x53, - 0xf5, 0xc0, 0x97, 0x54, 0x04, 0x14, 0xb1, 0x8e, 0xd1, 0x6b, 0x53, 0x9e, 0xa4, 0xaa, 0x5e, 0x6e, - 0x1c, 0x11, 0x6b, 0x0a, 0xc4, 0xec, 0x5b, 0x77, 0xa8, 0x00, 0x83, 0x77, 0xdb, 0xf4, 0xfb, 0x00, - 0xf4, 0x06, 0x57, 0x25, 0x8e, 0x1c, 0x87, 0xb4, 0xbe, 0xb8, 0x04, 0x35, 0x93, 0x67, 0xaa, 0x36, - 0xa5, 0x62, 0xe4, 0xf6, 0xcb, 0xc8, 0xa6, 0x58, 0x77, 0x96, 0xc4, 0x6c, 0x0b, 0xc8, 0x41, 0xe2, - 0x36, 0x01, 0x94, 0xa5, 0xe9, 0x46, 0x17, 0xd3, 0x0b, 0x18, 0x7e, 0x06, 0x88, 0x9b, 0x7e, 0xdd, - 0x92, 0x20, 0xc6, 0xe3, 0x7e, 0xb1, 0x02, 0x81, 0x81, 0x00, 0xf5, 0xa6, 0xda, 0x32, 0xb9, 0x37, - 0x61, 0xe9, 0x7c, 0x99, 0xf7, 0x4a, 0x37, 0xee, 0x52, 0x30, 0x4f, 0xbf, 0x57, 0x6f, 0xfe, 0x20, - 0xdc, 0xa3, 0xfe, 0x51, 0xbf, 0x72, 0x13, 0x8a, 0xb1, 0xd7, 0x99, 0x7d, 0x67, 0xa8, 0xd4, 0xb0, - 0x35, 0x40, 0x7c, 0xc8, 0xdc, 0x03, 0x6b, 0x90, 0xb5, 0x65, 0x04, 0x7f, 0x97, 0x8b, 0xa8, 0x69, - 0x20, 0x04, 0xcb, 0x48, 0x39, 0xb7, 0x57, 0xe0, 0xd9, 0xbb, 0x15, 0xe1, 0x59, 0x16, 0xf3, 0xe1, - 0xab, 0x91, 0xea, 0x8a, 0x88, 0xad, 0x8d, 0xa3, 0x24, 0x4a, 0x35, 0xa5, 0xd2, 0x32, 0x19, 0x66, - 0xa8, 0xbb, 0x32, 0x9d, 0xf4, 0x94, 0x99, 0xc1, 0x2e, 0x2b, 0xf8, 0x98, 0x6a, 0x6e, 0x72, 0x77, - 0xd0, 0xc9, 0xfc, 0x5f, 0xd7, 0x69, 0xd1, 0x08, 0x12, 0xbf, 0x81, 0xc1, 0xa1, 0x1b, 0x3b, 0x41, - 0xb0, 0x24, 0x11, 0x0a, 0x65, 0xab, 0x81, 0x39, 0xb3, 0xd5, 0x02, 0x81, 0x81, 0x00, 0xea, 0x41, - 0xb5, 0xed, 0xac, 0xa0, 0x43, 0xd7, 0xde, 0x1e, 0x6b, 0x95, 0xbe, 0x88, 0x02, 0xaf, 0x2f, 0xbb, - 0x37, 0xf7, 0x2f, 0xf6, 0x4f, 0xa0, 0xaa, 0x43, 0x03, 0x7d, 0x33, 0xdd, 0x1e, 0x7a, 0xba, 0xa0, - 0x10, 0x77, 0x1f, 0x4a, 0xc9, 0x88, 0x58, 0x9d, 0x81, 0x3a, 0xe8, 0xac, 0x86, 0x2f, 0x80, 0x6c, - 0xc7, 0xa0, 0xe5, 0xed, 0x8d, 0x90, 0xa9, 0xa7, 0x36, 0x23, 0xd7, 0xb5, 0x89, 0xfc, 0xad, 0x4d, - 0xae, 0x0e, 0xec, 0xdc, 0xe7, 0x7e, 0x69, 0xfe, 0x62, 0x4b, 0x81, 0xfe, 0x52, 0x81, 0x77, 0x6a, - 0x35, 0xab, 0x52, 0x6f, 0x56, 0x41, 0x6c, 0x57, 0x3d, 0x75, 0x92, 0x14, 0x42, 0xa2, 0xc9, 0x50, - 0x52, 0x57, 0x9f, 0x26, 0x3c, 0xcd, 0x61, 0xa9, 0xda, 0x9b, 0x2c, 0xda, 0xc1, 0xd0, 0x26, 0x07, - 0x90, 0x15, 0x8c, 0x81, 0xe2, 0xde, 0xc0, 0x98, 0x58, 0x9d, 0x96, 0x0f, 0xcd, 0x55, 0x02, 0x81, - 0x81, 0x00, 0x87, 0xfb, 0xf8, 0x77, 0xf1, 0xcd, 0xf5, 0xb6, 0xa1, 0xd2, 0x3d, 0x71, 0x69, 0x6a, - 0xd5, 0x36, 0x87, 0x3e, 0xdd, 0xb1, 0x52, 0x55, 0x70, 0xae, 0x9b, 0x9f, 0x37, 0x42, 0x78, 0x0c, - 0xe4, 0x0b, 0xfc, 0x9c, 0xce, 0x20, 0x48, 0xb4, 0xce, 0x95, 0xc7, 0x3e, 0x0d, 0x85, 0x1b, 0x2b, - 0x7d, 0x2e, 0xd1, 0x81, 0xac, 0x2b, 0x94, 0x6b, 0xb5, 0x5c, 0xd2, 0x07, 0x46, 0x63, 0xf7, 0x12, - 0xb2, 0x94, 0xfd, 0x34, 0xc4, 0xf3, 0x8e, 0xc8, 0x13, 0x08, 0xf0, 0x74, 0x05, 0xdb, 0x45, 0x37, - 0xd5, 0x63, 0xfb, 0x34, 0xb3, 0x1a, 0x26, 0xb3, 0x8c, 0x9e, 0x2c, 0x14, 0x02, 0x8b, 0xac, 0x5d, - 0xa3, 0x28, 0x96, 0x32, 0x11, 0x60, 0xd8, 0x9e, 0xf9, 0x06, 0x87, 0x5d, 0xaa, 0xca, 0x99, 0xfb, - 0x45, 0x1d, 0x9c, 0x3f, 0xca, 0xe6, 0x5f, 0x34, 0x2a, 0xc4, 0x9c, 0x66, 0x4c, 0x07, 0xd7, 0xbe, - 0x50, 0x8d, 0x02, 0x81, 0x80, 0x51, 0xdb, 0x96, 0x6c, 0x30, 0x37, 0x6c, 0x9d, 0xa1, 0x43, 0x76, - 0x0a, 0xc4, 0xa2, 0x98, 0x75, 0x89, 0x33, 0x5d, 0xd2, 0x25, 0xd3, 0x67, 0x6d, 0xd8, 0x31, 0x44, - 0xa5, 0xda, 0x9a, 0xb9, 0x0c, 0xdf, 0xec, 0x10, 0xf4, 0xdf, 0x5d, 0x6d, 0xe1, 0x14, 0x3e, 0x2d, - 0xab, 0x5d, 0x24, 0xf4, 0x5a, 0xe3, 0x00, 0xa0, 0x1d, 0x8c, 0x5b, 0x1f, 0x6d, 0xde, 0xaa, 0xcc, - 0x93, 0x67, 0xcc, 0x4b, 0x24, 0x9d, 0x96, 0x98, 0x6d, 0x24, 0xbd, 0xe8, 0xb2, 0xd6, 0xed, 0x0a, - 0x82, 0x22, 0x31, 0xb1, 0xb9, 0x05, 0xf6, 0x7a, 0x3c, 0x9c, 0xb8, 0xc5, 0x26, 0x65, 0x6a, 0x72, - 0xd2, 0x83, 0xb2, 0x4a, 0xba, 0xc1, 0xa8, 0x2c, 0xad, 0xeb, 0xb2, 0x1b, 0xeb, 0x14, 0xe6, 0x9a, - 0xba, 0x40, 0xc9, 0x4c, 0x92, 0xa4, 0xc7, 0x5d, 0xc4, 0xf9, 0xed, 0x65, 0x4e, 0xbb, 0x74, 0x40, - 0xfb, 0x08, 0x36, 0x0b, 0x65, 0x02, 0x81, 0x81, 0x00, 0xeb, 0x60, 0x01, 0x21, 0x22, 0xa1, 0xde, - 0x89, 0x62, 0xfa, 0x68, 0x03, 0x09, 0xf1, 0xa6, 0x14, 0xf0, 0xbe, 0xf7, 0x71, 0x3a, 0x01, 0x85, - 0x1f, 0x2c, 0x86, 0xde, 0x4a, 0xfb, 0x35, 0x16, 0xc4, 0x84, 0x22, 0x83, 0x49, 0xeb, 0x0d, 0xf7, - 0x33, 0x47, 0x8f, 0x96, 0x37, 0x32, 0xd3, 0xd2, 0xec, 0xea, 0x0f, 0xd0, 0xde, 0x0d, 0x27, 0x9e, - 0xc1, 0xf1, 0xe0, 0x39, 0xa6, 0x3e, 0x6c, 0xd4, 0x39, 0xdf, 0xde, 0xbd, 0x4c, 0xb8, 0xe7, 0xb7, - 0x4e, 0x2a, 0x32, 0x92, 0x83, 0xd3, 0x12, 0xb9, 0xa1, 0x91, 0x52, 0x46, 0x24, 0x58, 0x05, 0x35, - 0x22, 0x5f, 0x10, 0x3c, 0x13, 0x5b, 0xbe, 0x47, 0x5e, 0xbf, 0x85, 0xd6, 0xac, 0xfc, 0xbb, 0xd9, - 0x91, 0xf9, 0x50, 0x8f, 0xfc, 0xc2, 0x2c, 0x81, 0x5c, 0xa5, 0xc3, 0xc2, 0x15, 0xbe, 0xf4, 0x72, - 0xfd, 0x4d, 0xf0, 0x10, 0x6f, 0xe5, 0xbf, 0x8c, 0xb1 + 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe0, 0xc9, 0x91, 0x62, + 0xcd, 0x91, 0x68, 0x75, 0x2c, 0x32, 0x7a, 0xdd, 0xf1, 0xd6, 0x64, 0x77, 0x8b, 0x72, 0x9e, 0x14, + 0x2a, 0x62, 0x08, 0xd1, 0x89, 0x7d, 0xe2, 0x17, 0xdc, 0xb3, 0xda, 0xbc, 0x3a, 0x9f, 0x84, 0x03, + 0xd3, 0x2e, 0x68, 0xbe, 0xc1, 0x57, 0xcb, 0x2a, 0xe2, 0xd6, 0xcf, 0xc4, 0x7f, 0xbd, 0x53, 0x3f, + 0xeb, 0x39, 0x98, 0x69, 0xb0, 0x40, 0x14, 0xbf, 0xf5, 0x5a, 0x23, 0x23, 0xf4, 0x4c, 0xf8, 0xf1, + 0x03, 0x56, 0x6d, 0x7d, 0x1b, 0x93, 0xd7, 0x0f, 0xc1, 0x8c, 0x70, 0xe0, 0x2c, 0x55, 0x7e, 0xa1, + 0xfc, 0x05, 0xe9, 0xd7, 0xea, 0xb1, 0x5c, 0x0f, 0x9b, 0xac, 0x6a, 0x2e, 0xb4, 0xc5, 0xbf, 0x41, + 0x8f, 0xda, 0xfc, 0x85, 0xc6, 0xaa, 0x25, 0xe4, 0xb9, 0x9a, 0xc6, 0xd8, 0x9a, 0x31, 0x8a, 0x17, + 0x8b, 0x8c, 0x4e, 0x20, 0xd9, 0x71, 0xfc, 0x66, 0x3a, 0xfd, 0x49, 0x95, 0x54, 0xa8, 0xaf, 0x42, + 0x5e, 0xba, 0x26, 0xe6, 0xd3, 0xa0, 0xd2, 0x02, 0x3b, 0x51, 0x8b, 0x39, 0xd3, 0x97, 0xd2, 0xe4, + 0xd1, 0x01, 0x65, 0xab, 0x8e, 0xa2, 0x80, 0x5b, 0x5e, 0xbb, 0x11, 0x7f, 0x50, 0x1b, 0x2b, 0x0d, + 0x20, 0x40, 0xb5, 0xbf, 0xd1, 0x32, 0xfa, 0x25, 0xe1, 0x0d, 0x75, 0xfc, 0x11, 0xcf, 0x21, 0xdd, + 0x45, 0x16, 0xe4, 0x56, 0x58, 0x49, 0x33, 0xca, 0xaf, 0xe3, 0x17, 0x7b, 0x7a, 0x8f, 0xb1, 0xec, + 0x1c, 0x4d, 0xa2, 0xc2, 0xce, 0x8b, 0x19, 0x4b, 0xc0, 0xc4, 0x36, 0x6a, 0x7c, 0x5b, 0x89, 0x14, + 0x98, 0xcb, 0xa9, 0xca, 0x66, 0xf2, 0xaa, 0xf9, 0x12, 0x40, 0x0e, 0x6a, 0x78, 0x4d, 0x1f, 0x54, + 0x3c, 0x03, 0x7a, 0x91, 0xf5, 0xb7, 0x3d, 0xe2, 0xfc, 0x65, 0xb7, 0xaa, 0xa9, 0x39, 0x68, 0xa7, + 0xdb, 0x29, 0xc1, 0x40, 0x0b, 0x4e, 0xfb, 0xce, 0x74, 0xa5, 0x46, 0xb9, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb4, 0xc8, 0x07, 0x60, 0x01, 0xd9, 0xb6, 0xbb, 0xbd, 0x8e, + 0xdf, 0x97, 0xcd, 0xde, 0x51, 0xb0, 0x7e, 0xfa, 0xf0, 0x3d, 0x61, 0x94, 0xb4, 0x68, 0xe8, 0x7d, + 0xd0, 0x2e, 0xc6, 0xb5, 0xf2, 0xed, 0xbc, 0xeb, 0xfb, 0x3d, 0x24, 0x43, 0x47, 0xc4, 0x5a, 0x34, + 0x64, 0x56, 0x1a, 0x57, 0x0e, 0x83, 0x87, 0x04, 0x59, 0x86, 0xa7, 0x84, 0x0b, 0x9a, 0xbc, 0x3f, + 0xdd, 0x30, 0x40, 0x7f, 0x7c, 0x91, 0x76, 0xf1, 0xcc, 0xa7, 0xf0, 0xba, 0x3a, 0x96, 0x0a, 0x6e, + 0xcc, 0xe0, 0x84, 0x15, 0x91, 0xd6, 0x08, 0x71, 0xbd, 0xc5, 0x42, 0xad, 0xf2, 0xd2, 0x4e, 0x92, + 0xd3, 0x6a, 0x4e, 0x15, 0xcc, 0xd3, 0xc1, 0x58, 0xe4, 0x27, 0x33, 0x2d, 0xb8, 0x37, 0x52, 0x7e, + 0x16, 0xb9, 0xab, 0xb7, 0xd9, 0xc1, 0xeb, 0xc8, 0x79, 0xb9, 0xd3, 0xe6, 0x44, 0x13, 0x51, 0x2d, + 0xc6, 0x02, 0xe5, 0xe0, 0x3c, 0xa3, 0x15, 0x9b, 0x49, 0xae, 0x85, 0xbe, 0x8c, 0x84, 0xf9, 0x87, + 0x5d, 0x91, 0x9e, 0xf4, 0xf9, 0xf2, 0x8d, 0x81, 0x77, 0x7c, 0xfc, 0x60, 0x09, 0x48, 0x43, 0x2e, + 0xbb, 0xaf, 0xc9, 0xd6, 0x90, 0x2d, 0x40, 0x80, 0x59, 0xbd, 0x3b, 0x04, 0xda, 0x50, 0x2a, 0x53, + 0xf5, 0xc0, 0x97, 0x54, 0x04, 0x14, 0xb1, 0x8e, 0xd1, 0x6b, 0x53, 0x9e, 0xa4, 0xaa, 0x5e, 0x6e, + 0x1c, 0x11, 0x6b, 0x0a, 0xc4, 0xec, 0x5b, 0x77, 0xa8, 0x00, 0x83, 0x77, 0xdb, 0xf4, 0xfb, 0x00, + 0xf4, 0x06, 0x57, 0x25, 0x8e, 0x1c, 0x87, 0xb4, 0xbe, 0xb8, 0x04, 0x35, 0x93, 0x67, 0xaa, 0x36, + 0xa5, 0x62, 0xe4, 0xf6, 0xcb, 0xc8, 0xa6, 0x58, 0x77, 0x96, 0xc4, 0x6c, 0x0b, 0xc8, 0x41, 0xe2, + 0x36, 0x01, 0x94, 0xa5, 0xe9, 0x46, 0x17, 0xd3, 0x0b, 0x18, 0x7e, 0x06, 0x88, 0x9b, 0x7e, 0xdd, + 0x92, 0x20, 0xc6, 0xe3, 0x7e, 0xb1, 0x02, 0x81, 0x81, 0x00, 0xf5, 0xa6, 0xda, 0x32, 0xb9, 0x37, + 0x61, 0xe9, 0x7c, 0x99, 0xf7, 0x4a, 0x37, 0xee, 0x52, 0x30, 0x4f, 0xbf, 0x57, 0x6f, 0xfe, 0x20, + 0xdc, 0xa3, 0xfe, 0x51, 0xbf, 0x72, 0x13, 0x8a, 0xb1, 0xd7, 0x99, 0x7d, 0x67, 0xa8, 0xd4, 0xb0, + 0x35, 0x40, 0x7c, 0xc8, 0xdc, 0x03, 0x6b, 0x90, 0xb5, 0x65, 0x04, 0x7f, 0x97, 0x8b, 0xa8, 0x69, + 0x20, 0x04, 0xcb, 0x48, 0x39, 0xb7, 0x57, 0xe0, 0xd9, 0xbb, 0x15, 0xe1, 0x59, 0x16, 0xf3, 0xe1, + 0xab, 0x91, 0xea, 0x8a, 0x88, 0xad, 0x8d, 0xa3, 0x24, 0x4a, 0x35, 0xa5, 0xd2, 0x32, 0x19, 0x66, + 0xa8, 0xbb, 0x32, 0x9d, 0xf4, 0x94, 0x99, 0xc1, 0x2e, 0x2b, 0xf8, 0x98, 0x6a, 0x6e, 0x72, 0x77, + 0xd0, 0xc9, 0xfc, 0x5f, 0xd7, 0x69, 0xd1, 0x08, 0x12, 0xbf, 0x81, 0xc1, 0xa1, 0x1b, 0x3b, 0x41, + 0xb0, 0x24, 0x11, 0x0a, 0x65, 0xab, 0x81, 0x39, 0xb3, 0xd5, 0x02, 0x81, 0x81, 0x00, 0xea, 0x41, + 0xb5, 0xed, 0xac, 0xa0, 0x43, 0xd7, 0xde, 0x1e, 0x6b, 0x95, 0xbe, 0x88, 0x02, 0xaf, 0x2f, 0xbb, + 0x37, 0xf7, 0x2f, 0xf6, 0x4f, 0xa0, 0xaa, 0x43, 0x03, 0x7d, 0x33, 0xdd, 0x1e, 0x7a, 0xba, 0xa0, + 0x10, 0x77, 0x1f, 0x4a, 0xc9, 0x88, 0x58, 0x9d, 0x81, 0x3a, 0xe8, 0xac, 0x86, 0x2f, 0x80, 0x6c, + 0xc7, 0xa0, 0xe5, 0xed, 0x8d, 0x90, 0xa9, 0xa7, 0x36, 0x23, 0xd7, 0xb5, 0x89, 0xfc, 0xad, 0x4d, + 0xae, 0x0e, 0xec, 0xdc, 0xe7, 0x7e, 0x69, 0xfe, 0x62, 0x4b, 0x81, 0xfe, 0x52, 0x81, 0x77, 0x6a, + 0x35, 0xab, 0x52, 0x6f, 0x56, 0x41, 0x6c, 0x57, 0x3d, 0x75, 0x92, 0x14, 0x42, 0xa2, 0xc9, 0x50, + 0x52, 0x57, 0x9f, 0x26, 0x3c, 0xcd, 0x61, 0xa9, 0xda, 0x9b, 0x2c, 0xda, 0xc1, 0xd0, 0x26, 0x07, + 0x90, 0x15, 0x8c, 0x81, 0xe2, 0xde, 0xc0, 0x98, 0x58, 0x9d, 0x96, 0x0f, 0xcd, 0x55, 0x02, 0x81, + 0x81, 0x00, 0x87, 0xfb, 0xf8, 0x77, 0xf1, 0xcd, 0xf5, 0xb6, 0xa1, 0xd2, 0x3d, 0x71, 0x69, 0x6a, + 0xd5, 0x36, 0x87, 0x3e, 0xdd, 0xb1, 0x52, 0x55, 0x70, 0xae, 0x9b, 0x9f, 0x37, 0x42, 0x78, 0x0c, + 0xe4, 0x0b, 0xfc, 0x9c, 0xce, 0x20, 0x48, 0xb4, 0xce, 0x95, 0xc7, 0x3e, 0x0d, 0x85, 0x1b, 0x2b, + 0x7d, 0x2e, 0xd1, 0x81, 0xac, 0x2b, 0x94, 0x6b, 0xb5, 0x5c, 0xd2, 0x07, 0x46, 0x63, 0xf7, 0x12, + 0xb2, 0x94, 0xfd, 0x34, 0xc4, 0xf3, 0x8e, 0xc8, 0x13, 0x08, 0xf0, 0x74, 0x05, 0xdb, 0x45, 0x37, + 0xd5, 0x63, 0xfb, 0x34, 0xb3, 0x1a, 0x26, 0xb3, 0x8c, 0x9e, 0x2c, 0x14, 0x02, 0x8b, 0xac, 0x5d, + 0xa3, 0x28, 0x96, 0x32, 0x11, 0x60, 0xd8, 0x9e, 0xf9, 0x06, 0x87, 0x5d, 0xaa, 0xca, 0x99, 0xfb, + 0x45, 0x1d, 0x9c, 0x3f, 0xca, 0xe6, 0x5f, 0x34, 0x2a, 0xc4, 0x9c, 0x66, 0x4c, 0x07, 0xd7, 0xbe, + 0x50, 0x8d, 0x02, 0x81, 0x80, 0x51, 0xdb, 0x96, 0x6c, 0x30, 0x37, 0x6c, 0x9d, 0xa1, 0x43, 0x76, + 0x0a, 0xc4, 0xa2, 0x98, 0x75, 0x89, 0x33, 0x5d, 0xd2, 0x25, 0xd3, 0x67, 0x6d, 0xd8, 0x31, 0x44, + 0xa5, 0xda, 0x9a, 0xb9, 0x0c, 0xdf, 0xec, 0x10, 0xf4, 0xdf, 0x5d, 0x6d, 0xe1, 0x14, 0x3e, 0x2d, + 0xab, 0x5d, 0x24, 0xf4, 0x5a, 0xe3, 0x00, 0xa0, 0x1d, 0x8c, 0x5b, 0x1f, 0x6d, 0xde, 0xaa, 0xcc, + 0x93, 0x67, 0xcc, 0x4b, 0x24, 0x9d, 0x96, 0x98, 0x6d, 0x24, 0xbd, 0xe8, 0xb2, 0xd6, 0xed, 0x0a, + 0x82, 0x22, 0x31, 0xb1, 0xb9, 0x05, 0xf6, 0x7a, 0x3c, 0x9c, 0xb8, 0xc5, 0x26, 0x65, 0x6a, 0x72, + 0xd2, 0x83, 0xb2, 0x4a, 0xba, 0xc1, 0xa8, 0x2c, 0xad, 0xeb, 0xb2, 0x1b, 0xeb, 0x14, 0xe6, 0x9a, + 0xba, 0x40, 0xc9, 0x4c, 0x92, 0xa4, 0xc7, 0x5d, 0xc4, 0xf9, 0xed, 0x65, 0x4e, 0xbb, 0x74, 0x40, + 0xfb, 0x08, 0x36, 0x0b, 0x65, 0x02, 0x81, 0x81, 0x00, 0xeb, 0x60, 0x01, 0x21, 0x22, 0xa1, 0xde, + 0x89, 0x62, 0xfa, 0x68, 0x03, 0x09, 0xf1, 0xa6, 0x14, 0xf0, 0xbe, 0xf7, 0x71, 0x3a, 0x01, 0x85, + 0x1f, 0x2c, 0x86, 0xde, 0x4a, 0xfb, 0x35, 0x16, 0xc4, 0x84, 0x22, 0x83, 0x49, 0xeb, 0x0d, 0xf7, + 0x33, 0x47, 0x8f, 0x96, 0x37, 0x32, 0xd3, 0xd2, 0xec, 0xea, 0x0f, 0xd0, 0xde, 0x0d, 0x27, 0x9e, + 0xc1, 0xf1, 0xe0, 0x39, 0xa6, 0x3e, 0x6c, 0xd4, 0x39, 0xdf, 0xde, 0xbd, 0x4c, 0xb8, 0xe7, 0xb7, + 0x4e, 0x2a, 0x32, 0x92, 0x83, 0xd3, 0x12, 0xb9, 0xa1, 0x91, 0x52, 0x46, 0x24, 0x58, 0x05, 0x35, + 0x22, 0x5f, 0x10, 0x3c, 0x13, 0x5b, 0xbe, 0x47, 0x5e, 0xbf, 0x85, 0xd6, 0xac, 0xfc, 0xbb, 0xd9, + 0x91, 0xf9, 0x50, 0x8f, 0xfc, 0xc2, 0x2c, 0x81, 0x5c, 0xa5, 0xc3, 0xc2, 0x15, 0xbe, 0xf4, 0x72, + 0xfd, 0x4d, 0xf0, 0x10, 0x6f, 0xe5, 0xbf, 0x8c, 0xb1 }; #define CERT_DER_LENGTH 968 UA_Byte CERT_DER_DATA[968] = { - 0x30, 0x82, 0x03, 0xc4, 0x30, 0x82, 0x02, 0xac, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, - 0xa7, 0x17, 0x44, 0x2f, 0x8e, 0x6b, 0x74, 0xba, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, - 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, - 0x09, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, 0x31, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, - 0x55, 0x04, 0x03, 0x0c, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, 0x31, 0x2e, 0x6f, - 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x33, 0x32, 0x38, 0x30, 0x38, 0x33, 0x33, - 0x35, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x33, 0x32, 0x35, 0x30, 0x38, 0x33, 0x33, 0x35, - 0x37, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, - 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x6f, 0x70, 0x65, 0x6e, - 0x36, 0x32, 0x35, 0x34, 0x31, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, - 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x40, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, - 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe0, 0xc9, 0x91, 0x62, 0xcd, 0x91, - 0x68, 0x75, 0x2c, 0x32, 0x7a, 0xdd, 0xf1, 0xd6, 0x64, 0x77, 0x8b, 0x72, 0x9e, 0x14, 0x2a, 0x62, - 0x08, 0xd1, 0x89, 0x7d, 0xe2, 0x17, 0xdc, 0xb3, 0xda, 0xbc, 0x3a, 0x9f, 0x84, 0x03, 0xd3, 0x2e, - 0x68, 0xbe, 0xc1, 0x57, 0xcb, 0x2a, 0xe2, 0xd6, 0xcf, 0xc4, 0x7f, 0xbd, 0x53, 0x3f, 0xeb, 0x39, - 0x98, 0x69, 0xb0, 0x40, 0x14, 0xbf, 0xf5, 0x5a, 0x23, 0x23, 0xf4, 0x4c, 0xf8, 0xf1, 0x03, 0x56, - 0x6d, 0x7d, 0x1b, 0x93, 0xd7, 0x0f, 0xc1, 0x8c, 0x70, 0xe0, 0x2c, 0x55, 0x7e, 0xa1, 0xfc, 0x05, - 0xe9, 0xd7, 0xea, 0xb1, 0x5c, 0x0f, 0x9b, 0xac, 0x6a, 0x2e, 0xb4, 0xc5, 0xbf, 0x41, 0x8f, 0xda, - 0xfc, 0x85, 0xc6, 0xaa, 0x25, 0xe4, 0xb9, 0x9a, 0xc6, 0xd8, 0x9a, 0x31, 0x8a, 0x17, 0x8b, 0x8c, - 0x4e, 0x20, 0xd9, 0x71, 0xfc, 0x66, 0x3a, 0xfd, 0x49, 0x95, 0x54, 0xa8, 0xaf, 0x42, 0x5e, 0xba, - 0x26, 0xe6, 0xd3, 0xa0, 0xd2, 0x02, 0x3b, 0x51, 0x8b, 0x39, 0xd3, 0x97, 0xd2, 0xe4, 0xd1, 0x01, - 0x65, 0xab, 0x8e, 0xa2, 0x80, 0x5b, 0x5e, 0xbb, 0x11, 0x7f, 0x50, 0x1b, 0x2b, 0x0d, 0x20, 0x40, - 0xb5, 0xbf, 0xd1, 0x32, 0xfa, 0x25, 0xe1, 0x0d, 0x75, 0xfc, 0x11, 0xcf, 0x21, 0xdd, 0x45, 0x16, - 0xe4, 0x56, 0x58, 0x49, 0x33, 0xca, 0xaf, 0xe3, 0x17, 0x7b, 0x7a, 0x8f, 0xb1, 0xec, 0x1c, 0x4d, - 0xa2, 0xc2, 0xce, 0x8b, 0x19, 0x4b, 0xc0, 0xc4, 0x36, 0x6a, 0x7c, 0x5b, 0x89, 0x14, 0x98, 0xcb, - 0xa9, 0xca, 0x66, 0xf2, 0xaa, 0xf9, 0x12, 0x40, 0x0e, 0x6a, 0x78, 0x4d, 0x1f, 0x54, 0x3c, 0x03, - 0x7a, 0x91, 0xf5, 0xb7, 0x3d, 0xe2, 0xfc, 0x65, 0xb7, 0xaa, 0xa9, 0x39, 0x68, 0xa7, 0xdb, 0x29, - 0xc1, 0x40, 0x0b, 0x4e, 0xfb, 0xce, 0x74, 0xa5, 0x46, 0xb9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, - 0x81, 0xc2, 0x30, 0x81, 0xbf, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, - 0x60, 0x6e, 0x44, 0x94, 0xa8, 0xa2, 0x4e, 0x7a, 0x3e, 0xe2, 0x4b, 0x84, 0x5e, 0xec, 0x01, 0xc9, - 0xa3, 0xf9, 0x69, 0xaf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, - 0x14, 0x53, 0x77, 0xe0, 0xa2, 0xf2, 0x49, 0x38, 0xcf, 0x71, 0x58, 0x0a, 0x67, 0xa6, 0xc0, 0x17, - 0xd7, 0xb5, 0xdc, 0x52, 0x4b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, - 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xe0, 0x30, 0x1d, 0x06, - 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, - 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06, 0x03, - 0x55, 0x1d, 0x11, 0x04, 0x3f, 0x30, 0x3d, 0x82, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, - 0x73, 0x74, 0x82, 0x06, 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x87, 0x04, 0x7f, 0x00, 0x00, 0x01, - 0x87, 0x04, 0x00, 0x00, 0x00, 0x00, 0x86, 0x1c, 0x75, 0x72, 0x6e, 0x3a, 0x75, 0x6e, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x64, 0x3a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa4, 0xc1, 0x4f, 0x0e, 0xfe, 0xce, 0x2d, 0x91, - 0x8a, 0x51, 0x25, 0xd2, 0x6c, 0x07, 0x86, 0x95, 0xba, 0xc5, 0xe0, 0xad, 0x9b, 0x09, 0x3e, 0x7f, - 0x36, 0xc4, 0xa8, 0x10, 0x5b, 0x33, 0x77, 0xe5, 0xb5, 0x3b, 0xd8, 0x98, 0x7c, 0x42, 0x05, 0xcb, - 0xb7, 0x91, 0x07, 0x3f, 0x47, 0xff, 0x13, 0x15, 0x45, 0xff, 0x05, 0x03, 0x3d, 0xed, 0x63, 0x96, - 0x3a, 0x5c, 0xf8, 0x59, 0xd0, 0xbc, 0x68, 0x8c, 0xfb, 0xf8, 0x29, 0x07, 0x76, 0x63, 0xa7, 0x39, - 0xc1, 0x82, 0xc1, 0x10, 0x8b, 0x17, 0xf2, 0x1d, 0x14, 0xdd, 0x88, 0xe7, 0xdc, 0x2f, 0xa7, 0x9d, - 0xa3, 0xaa, 0xfd, 0x1a, 0x70, 0xce, 0x57, 0xb5, 0x9f, 0xc3, 0x7b, 0xd0, 0xc0, 0x6f, 0x73, 0x81, - 0x74, 0x41, 0x93, 0x0d, 0x0d, 0x1a, 0x95, 0xf6, 0xe4, 0x1c, 0x04, 0x2b, 0x37, 0x4f, 0xf9, 0x99, - 0x82, 0x57, 0xf0, 0x4f, 0x14, 0xcb, 0x0f, 0x3d, 0x1a, 0x52, 0x69, 0x18, 0x3f, 0xbe, 0x1c, 0x1c, - 0x1b, 0xca, 0xbd, 0xe7, 0xe0, 0x81, 0x44, 0x6d, 0x4a, 0x08, 0x8a, 0xe2, 0x7e, 0x59, 0x9f, 0x89, - 0x44, 0x7e, 0x4d, 0xaf, 0x5a, 0x8e, 0xe8, 0xd2, 0x2e, 0x98, 0x72, 0x86, 0xef, 0x7b, 0xcf, 0x88, - 0xd0, 0xe2, 0xd5, 0xd9, 0xd5, 0x19, 0xa2, 0x8c, 0xf4, 0x40, 0x98, 0x86, 0x32, 0x9f, 0x3e, 0x25, - 0x05, 0xd0, 0xdc, 0xf8, 0x1a, 0x0f, 0xdf, 0xc0, 0x54, 0x46, 0x20, 0xbd, 0xd4, 0xf6, 0xf5, 0xdd, - 0x10, 0x2e, 0xa7, 0x1a, 0xf4, 0xbb, 0xed, 0x5d, 0xf3, 0x1c, 0x96, 0x44, 0x81, 0x69, 0xd4, 0x0b, - 0xbe, 0x59, 0x07, 0x1b, 0x7f, 0x93, 0xc3, 0x4e, 0x7b, 0x32, 0x51, 0xd0, 0x13, 0x47, 0x57, 0x52, - 0xf0, 0x5c, 0x54, 0x36, 0x22, 0xb6, 0xf5, 0x67, 0xbb, 0xd3, 0xa6, 0x43, 0xf0, 0xca, 0x98, 0x91, - 0xda, 0x31, 0x3e, 0xd2, 0x8c, 0xfe, 0xd7, 0x51 + 0x30, 0x82, 0x03, 0xc4, 0x30, 0x82, 0x02, 0xac, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0xa7, 0x17, 0x44, 0x2f, 0x8e, 0x6b, 0x74, 0xba, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x09, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, 0x31, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, 0x31, 0x2e, 0x6f, + 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x33, 0x32, 0x38, 0x30, 0x38, 0x33, 0x33, + 0x35, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x33, 0x32, 0x35, 0x30, 0x38, 0x33, 0x33, 0x35, + 0x37, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x6f, 0x70, 0x65, 0x6e, + 0x36, 0x32, 0x35, 0x34, 0x31, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, + 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x40, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe0, 0xc9, 0x91, 0x62, 0xcd, 0x91, + 0x68, 0x75, 0x2c, 0x32, 0x7a, 0xdd, 0xf1, 0xd6, 0x64, 0x77, 0x8b, 0x72, 0x9e, 0x14, 0x2a, 0x62, + 0x08, 0xd1, 0x89, 0x7d, 0xe2, 0x17, 0xdc, 0xb3, 0xda, 0xbc, 0x3a, 0x9f, 0x84, 0x03, 0xd3, 0x2e, + 0x68, 0xbe, 0xc1, 0x57, 0xcb, 0x2a, 0xe2, 0xd6, 0xcf, 0xc4, 0x7f, 0xbd, 0x53, 0x3f, 0xeb, 0x39, + 0x98, 0x69, 0xb0, 0x40, 0x14, 0xbf, 0xf5, 0x5a, 0x23, 0x23, 0xf4, 0x4c, 0xf8, 0xf1, 0x03, 0x56, + 0x6d, 0x7d, 0x1b, 0x93, 0xd7, 0x0f, 0xc1, 0x8c, 0x70, 0xe0, 0x2c, 0x55, 0x7e, 0xa1, 0xfc, 0x05, + 0xe9, 0xd7, 0xea, 0xb1, 0x5c, 0x0f, 0x9b, 0xac, 0x6a, 0x2e, 0xb4, 0xc5, 0xbf, 0x41, 0x8f, 0xda, + 0xfc, 0x85, 0xc6, 0xaa, 0x25, 0xe4, 0xb9, 0x9a, 0xc6, 0xd8, 0x9a, 0x31, 0x8a, 0x17, 0x8b, 0x8c, + 0x4e, 0x20, 0xd9, 0x71, 0xfc, 0x66, 0x3a, 0xfd, 0x49, 0x95, 0x54, 0xa8, 0xaf, 0x42, 0x5e, 0xba, + 0x26, 0xe6, 0xd3, 0xa0, 0xd2, 0x02, 0x3b, 0x51, 0x8b, 0x39, 0xd3, 0x97, 0xd2, 0xe4, 0xd1, 0x01, + 0x65, 0xab, 0x8e, 0xa2, 0x80, 0x5b, 0x5e, 0xbb, 0x11, 0x7f, 0x50, 0x1b, 0x2b, 0x0d, 0x20, 0x40, + 0xb5, 0xbf, 0xd1, 0x32, 0xfa, 0x25, 0xe1, 0x0d, 0x75, 0xfc, 0x11, 0xcf, 0x21, 0xdd, 0x45, 0x16, + 0xe4, 0x56, 0x58, 0x49, 0x33, 0xca, 0xaf, 0xe3, 0x17, 0x7b, 0x7a, 0x8f, 0xb1, 0xec, 0x1c, 0x4d, + 0xa2, 0xc2, 0xce, 0x8b, 0x19, 0x4b, 0xc0, 0xc4, 0x36, 0x6a, 0x7c, 0x5b, 0x89, 0x14, 0x98, 0xcb, + 0xa9, 0xca, 0x66, 0xf2, 0xaa, 0xf9, 0x12, 0x40, 0x0e, 0x6a, 0x78, 0x4d, 0x1f, 0x54, 0x3c, 0x03, + 0x7a, 0x91, 0xf5, 0xb7, 0x3d, 0xe2, 0xfc, 0x65, 0xb7, 0xaa, 0xa9, 0x39, 0x68, 0xa7, 0xdb, 0x29, + 0xc1, 0x40, 0x0b, 0x4e, 0xfb, 0xce, 0x74, 0xa5, 0x46, 0xb9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x81, 0xc2, 0x30, 0x81, 0xbf, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x60, 0x6e, 0x44, 0x94, 0xa8, 0xa2, 0x4e, 0x7a, 0x3e, 0xe2, 0x4b, 0x84, 0x5e, 0xec, 0x01, 0xc9, + 0xa3, 0xf9, 0x69, 0xaf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0x53, 0x77, 0xe0, 0xa2, 0xf2, 0x49, 0x38, 0xcf, 0x71, 0x58, 0x0a, 0x67, 0xa6, 0xc0, 0x17, + 0xd7, 0xb5, 0xdc, 0x52, 0x4b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, + 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xe0, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x3f, 0x30, 0x3d, 0x82, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, + 0x73, 0x74, 0x82, 0x06, 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x87, 0x04, 0x7f, 0x00, 0x00, 0x01, + 0x87, 0x04, 0x00, 0x00, 0x00, 0x00, 0x86, 0x1c, 0x75, 0x72, 0x6e, 0x3a, 0x75, 0x6e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x64, 0x3a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa4, 0xc1, 0x4f, 0x0e, 0xfe, 0xce, 0x2d, 0x91, + 0x8a, 0x51, 0x25, 0xd2, 0x6c, 0x07, 0x86, 0x95, 0xba, 0xc5, 0xe0, 0xad, 0x9b, 0x09, 0x3e, 0x7f, + 0x36, 0xc4, 0xa8, 0x10, 0x5b, 0x33, 0x77, 0xe5, 0xb5, 0x3b, 0xd8, 0x98, 0x7c, 0x42, 0x05, 0xcb, + 0xb7, 0x91, 0x07, 0x3f, 0x47, 0xff, 0x13, 0x15, 0x45, 0xff, 0x05, 0x03, 0x3d, 0xed, 0x63, 0x96, + 0x3a, 0x5c, 0xf8, 0x59, 0xd0, 0xbc, 0x68, 0x8c, 0xfb, 0xf8, 0x29, 0x07, 0x76, 0x63, 0xa7, 0x39, + 0xc1, 0x82, 0xc1, 0x10, 0x8b, 0x17, 0xf2, 0x1d, 0x14, 0xdd, 0x88, 0xe7, 0xdc, 0x2f, 0xa7, 0x9d, + 0xa3, 0xaa, 0xfd, 0x1a, 0x70, 0xce, 0x57, 0xb5, 0x9f, 0xc3, 0x7b, 0xd0, 0xc0, 0x6f, 0x73, 0x81, + 0x74, 0x41, 0x93, 0x0d, 0x0d, 0x1a, 0x95, 0xf6, 0xe4, 0x1c, 0x04, 0x2b, 0x37, 0x4f, 0xf9, 0x99, + 0x82, 0x57, 0xf0, 0x4f, 0x14, 0xcb, 0x0f, 0x3d, 0x1a, 0x52, 0x69, 0x18, 0x3f, 0xbe, 0x1c, 0x1c, + 0x1b, 0xca, 0xbd, 0xe7, 0xe0, 0x81, 0x44, 0x6d, 0x4a, 0x08, 0x8a, 0xe2, 0x7e, 0x59, 0x9f, 0x89, + 0x44, 0x7e, 0x4d, 0xaf, 0x5a, 0x8e, 0xe8, 0xd2, 0x2e, 0x98, 0x72, 0x86, 0xef, 0x7b, 0xcf, 0x88, + 0xd0, 0xe2, 0xd5, 0xd9, 0xd5, 0x19, 0xa2, 0x8c, 0xf4, 0x40, 0x98, 0x86, 0x32, 0x9f, 0x3e, 0x25, + 0x05, 0xd0, 0xdc, 0xf8, 0x1a, 0x0f, 0xdf, 0xc0, 0x54, 0x46, 0x20, 0xbd, 0xd4, 0xf6, 0xf5, 0xdd, + 0x10, 0x2e, 0xa7, 0x1a, 0xf4, 0xbb, 0xed, 0x5d, 0xf3, 0x1c, 0x96, 0x44, 0x81, 0x69, 0xd4, 0x0b, + 0xbe, 0x59, 0x07, 0x1b, 0x7f, 0x93, 0xc3, 0x4e, 0x7b, 0x32, 0x51, 0xd0, 0x13, 0x47, 0x57, 0x52, + 0xf0, 0x5c, 0x54, 0x36, 0x22, 0xb6, 0xf5, 0x67, 0xbb, 0xd3, 0xa6, 0x43, 0xf0, 0xca, 0x98, 0x91, + 0xda, 0x31, 0x3e, 0xd2, 0x8c, 0xfe, 0xd7, 0x51 }; #define KEY_PEM_LENGTH 1679 @@ -348,6 +348,906 @@ UA_Byte CERT_PEM_DATA[1367] = { 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a }; +/* Generated from KEY_PEM_DATA via: openssl pkcs8 -topk8 -v2 des3 -in key.pem -out key-password.pem + The password is pass1234 */ +#define KEY_PEM_PASSWORD_LENGTH 1854 +UA_Byte KEY_PEM_PASSWORD_DATA[KEY_PEM_PASSWORD_LENGTH] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x45, 0x4e, 0x43, 0x52, 0x59, + 0x50, 0x54, 0x45, 0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x48, 0x44, 0x42, 0x4f, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x42, 0x51, 0x30, 0x77, 0x51, 0x54, + 0x41, 0x70, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x42, 0x51, + 0x77, 0x77, 0x48, 0x41, 0x51, 0x49, 0x71, 0x77, 0x7a, 0x47, 0x38, 0x51, 0x68, 0x69, 0x56, 0x58, + 0x38, 0x43, 0x41, 0x67, 0x67, 0x41, 0x0a, 0x4d, 0x41, 0x77, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x49, 0x4a, 0x42, 0x51, 0x41, 0x77, 0x46, 0x41, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x77, 0x63, 0x45, 0x43, 0x4a, 0x5a, 0x52, 0x51, + 0x57, 0x78, 0x4c, 0x47, 0x62, 0x31, 0x39, 0x42, 0x49, 0x49, 0x45, 0x79, 0x4e, 0x7a, 0x72, 0x52, + 0x4b, 0x31, 0x77, 0x4b, 0x42, 0x65, 0x51, 0x0a, 0x59, 0x48, 0x48, 0x36, 0x45, 0x37, 0x45, 0x7a, + 0x5a, 0x67, 0x43, 0x57, 0x4f, 0x64, 0x62, 0x53, 0x7a, 0x30, 0x44, 0x50, 0x78, 0x33, 0x52, 0x6a, + 0x48, 0x6c, 0x62, 0x53, 0x67, 0x48, 0x64, 0x30, 0x55, 0x34, 0x6f, 0x36, 0x4f, 0x76, 0x74, 0x71, + 0x31, 0x36, 0x55, 0x46, 0x43, 0x4c, 0x65, 0x74, 0x77, 0x4d, 0x6e, 0x30, 0x35, 0x72, 0x56, 0x41, + 0x68, 0x4c, 0x61, 0x44, 0x73, 0x39, 0x43, 0x75, 0x0a, 0x61, 0x65, 0x7a, 0x78, 0x42, 0x4d, 0x4a, + 0x77, 0x78, 0x77, 0x37, 0x6d, 0x32, 0x43, 0x4b, 0x42, 0x6f, 0x49, 0x79, 0x33, 0x41, 0x41, 0x39, + 0x47, 0x46, 0x58, 0x49, 0x5a, 0x71, 0x79, 0x75, 0x37, 0x63, 0x65, 0x5a, 0x4e, 0x52, 0x36, 0x64, + 0x53, 0x39, 0x4c, 0x49, 0x50, 0x73, 0x73, 0x71, 0x75, 0x54, 0x4f, 0x54, 0x76, 0x76, 0x48, 0x6f, + 0x4b, 0x45, 0x6a, 0x64, 0x30, 0x56, 0x51, 0x71, 0x42, 0x0a, 0x33, 0x66, 0x66, 0x38, 0x5a, 0x72, + 0x4d, 0x49, 0x6a, 0x2b, 0x33, 0x7a, 0x43, 0x4b, 0x6f, 0x78, 0x45, 0x62, 0x38, 0x38, 0x50, 0x70, + 0x68, 0x54, 0x61, 0x65, 0x75, 0x31, 0x62, 0x4e, 0x66, 0x6c, 0x49, 0x72, 0x6a, 0x79, 0x79, 0x78, + 0x70, 0x30, 0x4c, 0x5a, 0x79, 0x45, 0x36, 0x51, 0x75, 0x66, 0x75, 0x76, 0x4c, 0x42, 0x72, 0x4a, + 0x53, 0x66, 0x41, 0x46, 0x4c, 0x71, 0x63, 0x32, 0x6d, 0x4e, 0x0a, 0x45, 0x45, 0x45, 0x5a, 0x55, + 0x79, 0x43, 0x77, 0x74, 0x78, 0x4e, 0x6d, 0x31, 0x42, 0x2f, 0x37, 0x75, 0x52, 0x2b, 0x72, 0x36, + 0x2f, 0x50, 0x64, 0x36, 0x74, 0x58, 0x6c, 0x2f, 0x57, 0x6d, 0x45, 0x47, 0x4c, 0x68, 0x76, 0x2b, + 0x36, 0x45, 0x52, 0x58, 0x74, 0x35, 0x61, 0x61, 0x61, 0x39, 0x47, 0x51, 0x30, 0x67, 0x32, 0x78, + 0x7a, 0x4a, 0x42, 0x36, 0x54, 0x50, 0x30, 0x41, 0x5a, 0x45, 0x6d, 0x0a, 0x73, 0x7a, 0x42, 0x4a, + 0x72, 0x62, 0x4f, 0x31, 0x4e, 0x57, 0x79, 0x73, 0x33, 0x6e, 0x5a, 0x4f, 0x65, 0x64, 0x31, 0x2f, + 0x46, 0x49, 0x38, 0x43, 0x6e, 0x42, 0x55, 0x32, 0x4b, 0x6f, 0x61, 0x62, 0x67, 0x65, 0x6b, 0x6c, + 0x64, 0x37, 0x69, 0x61, 0x39, 0x61, 0x58, 0x4b, 0x5a, 0x54, 0x65, 0x76, 0x44, 0x78, 0x70, 0x46, + 0x4b, 0x75, 0x61, 0x36, 0x73, 0x35, 0x77, 0x43, 0x75, 0x58, 0x32, 0x4a, 0x0a, 0x54, 0x4d, 0x2b, + 0x41, 0x43, 0x76, 0x46, 0x65, 0x6d, 0x52, 0x71, 0x71, 0x68, 0x4f, 0x48, 0x6c, 0x69, 0x43, 0x4d, + 0x65, 0x70, 0x38, 0x41, 0x6c, 0x4a, 0x6e, 0x2f, 0x4a, 0x66, 0x45, 0x78, 0x38, 0x48, 0x6a, 0x74, + 0x53, 0x6a, 0x7a, 0x77, 0x42, 0x35, 0x52, 0x71, 0x56, 0x4f, 0x6b, 0x33, 0x6b, 0x72, 0x72, 0x44, + 0x71, 0x6e, 0x79, 0x31, 0x36, 0x41, 0x6d, 0x64, 0x78, 0x50, 0x34, 0x61, 0x56, 0x0a, 0x75, 0x68, + 0x6a, 0x67, 0x44, 0x62, 0x58, 0x4e, 0x66, 0x33, 0x31, 0x39, 0x63, 0x75, 0x43, 0x71, 0x32, 0x74, + 0x35, 0x68, 0x38, 0x31, 0x6e, 0x72, 0x48, 0x6d, 0x6a, 0x4b, 0x63, 0x6c, 0x55, 0x52, 0x59, 0x54, + 0x30, 0x2f, 0x6d, 0x64, 0x34, 0x43, 0x6b, 0x51, 0x6e, 0x64, 0x50, 0x51, 0x7a, 0x51, 0x33, 0x4c, + 0x61, 0x51, 0x73, 0x62, 0x38, 0x47, 0x4f, 0x63, 0x67, 0x35, 0x58, 0x45, 0x76, 0x67, 0x0a, 0x78, + 0x73, 0x68, 0x39, 0x65, 0x55, 0x58, 0x64, 0x75, 0x4f, 0x65, 0x45, 0x46, 0x6f, 0x72, 0x32, 0x54, + 0x6d, 0x73, 0x2f, 0x6b, 0x55, 0x62, 0x77, 0x76, 0x73, 0x66, 0x2b, 0x63, 0x30, 0x4f, 0x50, 0x58, + 0x53, 0x65, 0x70, 0x5a, 0x6b, 0x46, 0x35, 0x4b, 0x47, 0x51, 0x4d, 0x43, 0x50, 0x39, 0x36, 0x4b, + 0x32, 0x32, 0x4f, 0x43, 0x69, 0x43, 0x4b, 0x78, 0x58, 0x59, 0x37, 0x4b, 0x57, 0x56, 0x75, 0x0a, + 0x73, 0x6b, 0x47, 0x6a, 0x62, 0x70, 0x34, 0x65, 0x63, 0x58, 0x56, 0x57, 0x56, 0x47, 0x67, 0x4f, + 0x48, 0x6a, 0x4e, 0x51, 0x67, 0x73, 0x47, 0x75, 0x64, 0x45, 0x66, 0x75, 0x50, 0x63, 0x30, 0x49, + 0x71, 0x53, 0x42, 0x66, 0x6b, 0x46, 0x7a, 0x79, 0x71, 0x35, 0x63, 0x54, 0x36, 0x2b, 0x63, 0x6a, + 0x36, 0x31, 0x78, 0x73, 0x49, 0x76, 0x58, 0x53, 0x61, 0x35, 0x36, 0x78, 0x69, 0x69, 0x59, 0x51, + 0x0a, 0x39, 0x4b, 0x38, 0x2b, 0x61, 0x30, 0x75, 0x68, 0x58, 0x4d, 0x32, 0x66, 0x4f, 0x32, 0x49, + 0x57, 0x55, 0x78, 0x74, 0x2b, 0x70, 0x33, 0x35, 0x42, 0x73, 0x5a, 0x4d, 0x56, 0x44, 0x31, 0x7a, + 0x6f, 0x30, 0x67, 0x63, 0x6d, 0x31, 0x36, 0x6b, 0x73, 0x78, 0x77, 0x31, 0x36, 0x32, 0x73, 0x37, + 0x75, 0x61, 0x55, 0x74, 0x6a, 0x53, 0x56, 0x39, 0x61, 0x2f, 0x30, 0x58, 0x6d, 0x62, 0x65, 0x7a, + 0x45, 0x0a, 0x55, 0x53, 0x50, 0x36, 0x4c, 0x2f, 0x6a, 0x74, 0x57, 0x6a, 0x50, 0x50, 0x52, 0x52, + 0x33, 0x56, 0x57, 0x42, 0x70, 0x44, 0x34, 0x4a, 0x4d, 0x53, 0x61, 0x79, 0x77, 0x58, 0x67, 0x47, + 0x6b, 0x53, 0x34, 0x31, 0x69, 0x4e, 0x79, 0x68, 0x70, 0x50, 0x6f, 0x72, 0x35, 0x54, 0x6f, 0x69, + 0x34, 0x66, 0x4d, 0x41, 0x43, 0x49, 0x7a, 0x75, 0x34, 0x59, 0x4a, 0x59, 0x4b, 0x70, 0x69, 0x72, + 0x51, 0x52, 0x0a, 0x4f, 0x47, 0x71, 0x2b, 0x6e, 0x49, 0x54, 0x6e, 0x70, 0x6b, 0x75, 0x6a, 0x53, + 0x4e, 0x78, 0x34, 0x51, 0x4b, 0x66, 0x39, 0x49, 0x49, 0x4d, 0x4f, 0x4e, 0x6c, 0x36, 0x57, 0x33, + 0x52, 0x78, 0x31, 0x56, 0x4b, 0x6b, 0x2f, 0x76, 0x71, 0x50, 0x30, 0x59, 0x45, 0x4a, 0x64, 0x47, + 0x4a, 0x58, 0x44, 0x75, 0x70, 0x50, 0x41, 0x43, 0x49, 0x42, 0x77, 0x4e, 0x58, 0x38, 0x2f, 0x54, + 0x59, 0x78, 0x6b, 0x0a, 0x6c, 0x79, 0x34, 0x50, 0x71, 0x32, 0x43, 0x6e, 0x53, 0x31, 0x33, 0x39, + 0x6e, 0x59, 0x44, 0x31, 0x32, 0x4f, 0x50, 0x71, 0x32, 0x56, 0x41, 0x77, 0x47, 0x55, 0x7a, 0x56, + 0x6e, 0x72, 0x32, 0x32, 0x61, 0x74, 0x54, 0x73, 0x4e, 0x6a, 0x4d, 0x6a, 0x48, 0x4e, 0x79, 0x72, + 0x2f, 0x6b, 0x63, 0x6d, 0x34, 0x32, 0x4c, 0x72, 0x58, 0x5a, 0x65, 0x33, 0x79, 0x6a, 0x4c, 0x31, + 0x32, 0x58, 0x78, 0x2b, 0x0a, 0x5a, 0x46, 0x48, 0x74, 0x36, 0x77, 0x45, 0x71, 0x45, 0x33, 0x70, + 0x77, 0x5a, 0x66, 0x77, 0x46, 0x72, 0x4c, 0x75, 0x43, 0x38, 0x36, 0x48, 0x52, 0x73, 0x51, 0x7a, + 0x52, 0x4f, 0x4d, 0x46, 0x57, 0x34, 0x43, 0x32, 0x69, 0x4e, 0x76, 0x73, 0x56, 0x36, 0x48, 0x61, + 0x6e, 0x63, 0x34, 0x73, 0x70, 0x74, 0x56, 0x55, 0x6f, 0x58, 0x4a, 0x4b, 0x38, 0x74, 0x52, 0x68, + 0x39, 0x33, 0x70, 0x72, 0x67, 0x0a, 0x58, 0x47, 0x5a, 0x64, 0x64, 0x2f, 0x57, 0x58, 0x51, 0x70, + 0x64, 0x32, 0x6e, 0x76, 0x6f, 0x75, 0x76, 0x4d, 0x42, 0x70, 0x56, 0x6c, 0x6a, 0x63, 0x6d, 0x6a, + 0x4e, 0x47, 0x57, 0x56, 0x54, 0x72, 0x68, 0x54, 0x48, 0x75, 0x4a, 0x4d, 0x4f, 0x34, 0x6a, 0x56, + 0x44, 0x31, 0x34, 0x74, 0x73, 0x30, 0x36, 0x72, 0x37, 0x48, 0x46, 0x6c, 0x6d, 0x56, 0x47, 0x31, + 0x57, 0x50, 0x6c, 0x4c, 0x69, 0x44, 0x0a, 0x42, 0x6d, 0x41, 0x6d, 0x31, 0x68, 0x57, 0x64, 0x61, + 0x75, 0x38, 0x59, 0x52, 0x59, 0x4b, 0x50, 0x34, 0x4a, 0x38, 0x47, 0x57, 0x57, 0x52, 0x45, 0x34, + 0x35, 0x68, 0x64, 0x71, 0x52, 0x74, 0x7a, 0x43, 0x37, 0x51, 0x44, 0x65, 0x68, 0x65, 0x74, 0x78, + 0x62, 0x54, 0x67, 0x6a, 0x46, 0x6a, 0x64, 0x48, 0x4b, 0x34, 0x38, 0x57, 0x46, 0x71, 0x53, 0x2b, + 0x38, 0x6b, 0x5a, 0x53, 0x42, 0x63, 0x34, 0x0a, 0x2b, 0x4a, 0x6d, 0x4b, 0x56, 0x51, 0x46, 0x57, + 0x39, 0x79, 0x6d, 0x35, 0x32, 0x54, 0x54, 0x70, 0x61, 0x43, 0x5a, 0x57, 0x6b, 0x47, 0x71, 0x5a, + 0x6a, 0x30, 0x61, 0x47, 0x48, 0x54, 0x6e, 0x31, 0x63, 0x4f, 0x33, 0x6e, 0x4c, 0x65, 0x4f, 0x35, + 0x34, 0x44, 0x6f, 0x47, 0x6f, 0x76, 0x66, 0x70, 0x57, 0x38, 0x47, 0x64, 0x4c, 0x4d, 0x47, 0x70, + 0x5a, 0x59, 0x6b, 0x30, 0x48, 0x63, 0x76, 0x49, 0x0a, 0x78, 0x76, 0x4e, 0x70, 0x73, 0x2b, 0x58, + 0x54, 0x46, 0x55, 0x30, 0x50, 0x7a, 0x46, 0x6f, 0x55, 0x4d, 0x33, 0x54, 0x63, 0x73, 0x2b, 0x4f, + 0x66, 0x4b, 0x52, 0x6c, 0x61, 0x35, 0x62, 0x47, 0x4f, 0x31, 0x67, 0x48, 0x49, 0x2f, 0x5a, 0x79, + 0x39, 0x54, 0x78, 0x5a, 0x68, 0x6a, 0x35, 0x5a, 0x33, 0x6c, 0x75, 0x46, 0x42, 0x44, 0x58, 0x45, + 0x75, 0x34, 0x72, 0x56, 0x45, 0x6e, 0x4b, 0x34, 0x52, 0x0a, 0x41, 0x56, 0x35, 0x47, 0x4f, 0x45, + 0x72, 0x51, 0x49, 0x41, 0x6c, 0x70, 0x77, 0x76, 0x61, 0x64, 0x70, 0x52, 0x34, 0x73, 0x57, 0x31, + 0x30, 0x42, 0x72, 0x54, 0x2b, 0x50, 0x72, 0x4f, 0x44, 0x6c, 0x51, 0x36, 0x42, 0x6a, 0x4a, 0x71, + 0x75, 0x46, 0x4e, 0x46, 0x61, 0x5a, 0x31, 0x56, 0x35, 0x39, 0x78, 0x4f, 0x53, 0x30, 0x35, 0x39, + 0x6d, 0x6e, 0x35, 0x79, 0x79, 0x36, 0x31, 0x56, 0x71, 0x38, 0x0a, 0x39, 0x72, 0x54, 0x61, 0x33, + 0x78, 0x69, 0x78, 0x6c, 0x52, 0x47, 0x59, 0x46, 0x78, 0x45, 0x70, 0x4c, 0x65, 0x73, 0x4d, 0x59, + 0x66, 0x4a, 0x5a, 0x59, 0x41, 0x46, 0x39, 0x37, 0x35, 0x4e, 0x31, 0x68, 0x74, 0x71, 0x76, 0x53, + 0x4c, 0x6e, 0x49, 0x73, 0x70, 0x38, 0x36, 0x70, 0x74, 0x48, 0x59, 0x59, 0x63, 0x50, 0x74, 0x42, + 0x72, 0x4a, 0x4f, 0x34, 0x63, 0x53, 0x63, 0x4e, 0x79, 0x72, 0x6e, 0x0a, 0x49, 0x64, 0x53, 0x58, + 0x54, 0x58, 0x6d, 0x79, 0x4c, 0x33, 0x55, 0x43, 0x78, 0x56, 0x4e, 0x4b, 0x4f, 0x2f, 0x68, 0x73, + 0x6f, 0x65, 0x2f, 0x75, 0x4c, 0x32, 0x42, 0x61, 0x79, 0x68, 0x73, 0x45, 0x66, 0x4e, 0x7a, 0x63, + 0x34, 0x69, 0x55, 0x6c, 0x6b, 0x6c, 0x67, 0x30, 0x39, 0x6b, 0x2b, 0x44, 0x58, 0x51, 0x4f, 0x4e, + 0x50, 0x6b, 0x68, 0x61, 0x71, 0x52, 0x37, 0x34, 0x74, 0x75, 0x39, 0x47, 0x0a, 0x77, 0x55, 0x57, + 0x4f, 0x4d, 0x48, 0x68, 0x77, 0x6c, 0x32, 0x6e, 0x62, 0x35, 0x47, 0x65, 0x52, 0x64, 0x73, 0x39, + 0x76, 0x79, 0x39, 0x70, 0x63, 0x78, 0x63, 0x71, 0x38, 0x52, 0x6e, 0x67, 0x2b, 0x79, 0x46, 0x70, + 0x54, 0x46, 0x75, 0x56, 0x53, 0x64, 0x41, 0x43, 0x6e, 0x35, 0x75, 0x39, 0x62, 0x4d, 0x5a, 0x46, + 0x4f, 0x46, 0x6b, 0x64, 0x56, 0x75, 0x32, 0x6e, 0x36, 0x38, 0x42, 0x63, 0x65, 0x0a, 0x31, 0x4e, + 0x68, 0x75, 0x49, 0x31, 0x53, 0x48, 0x79, 0x6c, 0x42, 0x7a, 0x35, 0x30, 0x79, 0x4e, 0x6b, 0x43, + 0x4b, 0x4c, 0x33, 0x77, 0x51, 0x44, 0x47, 0x72, 0x38, 0x6b, 0x69, 0x2f, 0x54, 0x73, 0x75, 0x74, + 0x59, 0x30, 0x31, 0x48, 0x46, 0x30, 0x30, 0x76, 0x41, 0x36, 0x73, 0x4e, 0x75, 0x66, 0x4d, 0x66, + 0x6c, 0x6e, 0x61, 0x77, 0x79, 0x61, 0x67, 0x31, 0x4a, 0x69, 0x34, 0x46, 0x37, 0x6f, 0x0a, 0x41, + 0x4c, 0x49, 0x55, 0x39, 0x4e, 0x69, 0x47, 0x67, 0x41, 0x66, 0x6f, 0x33, 0x4a, 0x79, 0x4b, 0x52, + 0x6c, 0x56, 0x48, 0x6c, 0x71, 0x52, 0x2b, 0x63, 0x6b, 0x47, 0x74, 0x34, 0x6a, 0x66, 0x75, 0x51, + 0x59, 0x52, 0x5a, 0x4b, 0x46, 0x31, 0x34, 0x43, 0x51, 0x38, 0x66, 0x78, 0x65, 0x64, 0x62, 0x53, + 0x77, 0x44, 0x6d, 0x36, 0x33, 0x54, 0x77, 0x37, 0x58, 0x41, 0x49, 0x50, 0x43, 0x35, 0x39, 0x0a, + 0x4c, 0x32, 0x56, 0x49, 0x54, 0x45, 0x77, 0x46, 0x59, 0x51, 0x70, 0x6f, 0x4f, 0x77, 0x30, 0x4c, + 0x48, 0x45, 0x50, 0x78, 0x63, 0x53, 0x70, 0x36, 0x71, 0x4f, 0x53, 0x6a, 0x51, 0x76, 0x42, 0x4c, + 0x47, 0x6c, 0x68, 0x71, 0x4c, 0x46, 0x77, 0x38, 0x73, 0x4a, 0x50, 0x38, 0x69, 0x68, 0x59, 0x36, + 0x73, 0x6d, 0x41, 0x42, 0x53, 0x6d, 0x42, 0x76, 0x49, 0x45, 0x59, 0x4a, 0x5a, 0x79, 0x55, 0x35, + 0x0a, 0x56, 0x36, 0x47, 0x61, 0x31, 0x76, 0x4e, 0x62, 0x51, 0x43, 0x57, 0x67, 0x65, 0x43, 0x6f, + 0x71, 0x4b, 0x6f, 0x39, 0x5a, 0x5a, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x20, 0x50, 0x52, 0x49, + 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +#define ROOT_CERT_DER_LENGTH 2000 +UA_Byte ROOT_CERT_DER_DATA[2000] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, + 0x6d, 0x54, 0x43, 0x43, 0x41, 0x34, 0x47, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, + 0x44, 0x4f, 0x39, 0x78, 0x48, 0x76, 0x72, 0x67, 0x31, 0x4d, 0x48, 0x57, 0x74, 0x4e, 0x7a, 0x4c, + 0x49, 0x73, 0x30, 0x39, 0x35, 0x67, 0x58, 0x6b, 0x6d, 0x69, 0x4d, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, + 0x77, 0x5a, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x52, 0x45, 0x55, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, + 0x4d, 0x42, 0x56, 0x4e, 0x30, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x52, 0x44, 0x61, 0x58, 0x52, 0x35, 0x0a, 0x4d, 0x52, + 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x78, 0x50, 0x63, 0x6d, + 0x64, 0x68, 0x62, 0x6d, 0x6c, 0x36, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x45, 0x44, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x42, 0x30, 0x39, 0x79, 0x5a, 0x31, + 0x56, 0x75, 0x61, 0x58, 0x51, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, + 0x41, 0x4d, 0x4d, 0x42, 0x6c, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, + 0x77, 0x30, 0x79, 0x4e, 0x44, 0x41, 0x35, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x54, 0x55, 0x31, 0x4e, + 0x44, 0x64, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x44, 0x41, 0x35, 0x4d, 0x44, 0x6b, 0x78, 0x4d, + 0x54, 0x55, 0x31, 0x4e, 0x44, 0x64, 0x61, 0x4d, 0x47, 0x59, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x52, 0x46, 0x4d, 0x51, 0x34, 0x77, + 0x44, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x56, 0x54, 0x64, 0x47, 0x46, 0x30, + 0x5a, 0x54, 0x45, 0x4e, 0x4d, 0x41, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x45, + 0x51, 0x32, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0a, 0x43, 0x67, 0x77, 0x4d, 0x54, 0x33, 0x4a, 0x6e, 0x59, 0x57, 0x35, 0x70, 0x65, 0x6d, 0x46, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x44, 0x41, 0x64, 0x50, 0x63, 0x6d, 0x64, 0x56, 0x62, 0x6d, 0x6c, 0x30, 0x4d, 0x51, 0x38, + 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x41, 0x5a, 0x53, 0x62, 0x32, 0x39, + 0x30, 0x0a, 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, + 0x44, 0x4f, 0x78, 0x50, 0x54, 0x36, 0x4b, 0x6d, 0x52, 0x4e, 0x34, 0x51, 0x67, 0x4e, 0x55, 0x61, + 0x37, 0x54, 0x0a, 0x59, 0x2f, 0x56, 0x5a, 0x76, 0x68, 0x58, 0x6e, 0x53, 0x35, 0x75, 0x2f, 0x5a, + 0x47, 0x73, 0x37, 0x6d, 0x47, 0x37, 0x53, 0x4d, 0x6f, 0x50, 0x6f, 0x71, 0x49, 0x44, 0x44, 0x7a, + 0x4d, 0x74, 0x44, 0x57, 0x32, 0x66, 0x51, 0x78, 0x62, 0x34, 0x36, 0x48, 0x43, 0x76, 0x63, 0x38, + 0x55, 0x4f, 0x68, 0x38, 0x2f, 0x37, 0x34, 0x70, 0x50, 0x59, 0x48, 0x4c, 0x41, 0x34, 0x59, 0x58, + 0x67, 0x58, 0x37, 0x0a, 0x36, 0x49, 0x6f, 0x34, 0x6a, 0x52, 0x6b, 0x79, 0x6e, 0x6d, 0x50, 0x7a, + 0x44, 0x66, 0x43, 0x31, 0x37, 0x43, 0x56, 0x4c, 0x53, 0x63, 0x64, 0x42, 0x58, 0x35, 0x51, 0x48, + 0x57, 0x43, 0x6c, 0x5a, 0x56, 0x48, 0x43, 0x58, 0x77, 0x4c, 0x75, 0x42, 0x45, 0x59, 0x49, 0x47, + 0x6f, 0x30, 0x78, 0x33, 0x65, 0x66, 0x75, 0x39, 0x6c, 0x75, 0x69, 0x73, 0x70, 0x70, 0x73, 0x4c, + 0x7a, 0x59, 0x54, 0x4d, 0x0a, 0x38, 0x31, 0x62, 0x79, 0x6a, 0x2b, 0x78, 0x74, 0x49, 0x64, 0x42, + 0x72, 0x68, 0x4c, 0x68, 0x39, 0x48, 0x5a, 0x4f, 0x73, 0x57, 0x6b, 0x63, 0x70, 0x79, 0x68, 0x38, + 0x75, 0x52, 0x55, 0x6d, 0x35, 0x43, 0x50, 0x76, 0x2f, 0x74, 0x78, 0x4f, 0x36, 0x4f, 0x6a, 0x6e, + 0x41, 0x67, 0x4f, 0x2b, 0x47, 0x33, 0x38, 0x38, 0x56, 0x71, 0x55, 0x4b, 0x59, 0x38, 0x76, 0x54, + 0x46, 0x54, 0x30, 0x49, 0x61, 0x0a, 0x76, 0x36, 0x4d, 0x36, 0x6b, 0x62, 0x57, 0x45, 0x78, 0x49, + 0x50, 0x5a, 0x52, 0x62, 0x6d, 0x51, 0x52, 0x64, 0x74, 0x5a, 0x74, 0x59, 0x57, 0x72, 0x54, 0x43, + 0x2f, 0x50, 0x54, 0x43, 0x45, 0x6b, 0x73, 0x34, 0x61, 0x76, 0x6e, 0x47, 0x38, 0x44, 0x61, 0x52, + 0x4f, 0x39, 0x66, 0x42, 0x6c, 0x79, 0x65, 0x37, 0x61, 0x32, 0x45, 0x6f, 0x62, 0x35, 0x33, 0x34, + 0x42, 0x76, 0x4d, 0x2f, 0x74, 0x76, 0x0a, 0x30, 0x74, 0x63, 0x6f, 0x38, 0x2b, 0x50, 0x69, 0x58, + 0x52, 0x70, 0x61, 0x6a, 0x66, 0x71, 0x56, 0x68, 0x31, 0x43, 0x70, 0x61, 0x68, 0x7a, 0x7a, 0x78, + 0x5a, 0x35, 0x65, 0x76, 0x4d, 0x7a, 0x77, 0x78, 0x4d, 0x43, 0x2f, 0x74, 0x75, 0x61, 0x69, 0x54, + 0x76, 0x76, 0x4d, 0x56, 0x44, 0x62, 0x33, 0x63, 0x68, 0x53, 0x77, 0x41, 0x4a, 0x55, 0x6c, 0x75, + 0x33, 0x48, 0x73, 0x59, 0x35, 0x5a, 0x4d, 0x0a, 0x72, 0x52, 0x59, 0x31, 0x6b, 0x56, 0x30, 0x4a, + 0x74, 0x4f, 0x35, 0x68, 0x64, 0x58, 0x44, 0x57, 0x61, 0x79, 0x35, 0x59, 0x52, 0x78, 0x75, 0x42, + 0x2f, 0x76, 0x45, 0x65, 0x2f, 0x36, 0x77, 0x2b, 0x4b, 0x4e, 0x42, 0x35, 0x75, 0x4e, 0x62, 0x73, + 0x55, 0x78, 0x6f, 0x6a, 0x35, 0x79, 0x48, 0x44, 0x6b, 0x45, 0x67, 0x75, 0x42, 0x4b, 0x4a, 0x38, + 0x59, 0x77, 0x42, 0x36, 0x44, 0x47, 0x4e, 0x31, 0x0a, 0x32, 0x53, 0x57, 0x57, 0x5a, 0x45, 0x47, + 0x34, 0x38, 0x4b, 0x67, 0x30, 0x6e, 0x52, 0x68, 0x6b, 0x54, 0x35, 0x6d, 0x62, 0x45, 0x44, 0x45, + 0x68, 0x49, 0x57, 0x43, 0x2f, 0x61, 0x30, 0x50, 0x6e, 0x73, 0x6a, 0x49, 0x71, 0x69, 0x49, 0x68, + 0x6a, 0x5a, 0x6a, 0x61, 0x77, 0x35, 0x6f, 0x62, 0x74, 0x30, 0x38, 0x71, 0x58, 0x2b, 0x63, 0x79, + 0x67, 0x32, 0x52, 0x31, 0x4e, 0x66, 0x51, 0x77, 0x7a, 0x0a, 0x74, 0x35, 0x33, 0x68, 0x79, 0x47, + 0x6c, 0x48, 0x65, 0x35, 0x4e, 0x35, 0x61, 0x61, 0x7a, 0x77, 0x57, 0x4b, 0x4a, 0x42, 0x73, 0x72, + 0x78, 0x48, 0x50, 0x74, 0x77, 0x38, 0x79, 0x48, 0x56, 0x64, 0x4a, 0x64, 0x73, 0x66, 0x59, 0x6c, + 0x38, 0x70, 0x7a, 0x39, 0x63, 0x34, 0x76, 0x54, 0x50, 0x59, 0x6e, 0x5a, 0x33, 0x4d, 0x41, 0x41, + 0x46, 0x59, 0x44, 0x76, 0x57, 0x70, 0x33, 0x45, 0x52, 0x44, 0x0a, 0x30, 0x70, 0x48, 0x48, 0x57, + 0x6d, 0x67, 0x30, 0x73, 0x6c, 0x76, 0x41, 0x66, 0x4f, 0x6e, 0x6f, 0x35, 0x31, 0x55, 0x41, 0x32, + 0x53, 0x65, 0x77, 0x2b, 0x51, 0x52, 0x37, 0x53, 0x53, 0x30, 0x33, 0x70, 0x49, 0x55, 0x69, 0x58, + 0x53, 0x68, 0x75, 0x2b, 0x38, 0x51, 0x56, 0x66, 0x6b, 0x6f, 0x6b, 0x66, 0x4a, 0x66, 0x67, 0x71, + 0x30, 0x4f, 0x45, 0x30, 0x33, 0x31, 0x78, 0x46, 0x77, 0x66, 0x41, 0x0a, 0x5a, 0x46, 0x68, 0x39, + 0x53, 0x49, 0x4b, 0x48, 0x38, 0x51, 0x31, 0x32, 0x47, 0x55, 0x61, 0x6c, 0x34, 0x53, 0x55, 0x73, + 0x65, 0x4d, 0x4d, 0x43, 0x34, 0x73, 0x76, 0x55, 0x4f, 0x48, 0x4d, 0x36, 0x6d, 0x58, 0x2b, 0x32, + 0x4f, 0x64, 0x5a, 0x33, 0x64, 0x32, 0x77, 0x79, 0x4c, 0x77, 0x55, 0x34, 0x43, 0x37, 0x6a, 0x2b, + 0x32, 0x6e, 0x71, 0x51, 0x66, 0x53, 0x39, 0x45, 0x4f, 0x63, 0x65, 0x66, 0x0a, 0x42, 0x58, 0x76, + 0x53, 0x4e, 0x59, 0x33, 0x71, 0x2f, 0x36, 0x61, 0x34, 0x37, 0x48, 0x49, 0x47, 0x5a, 0x4d, 0x62, + 0x6b, 0x4a, 0x75, 0x35, 0x7a, 0x65, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x7a, 0x38, + 0x77, 0x50, 0x54, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x73, 0x47, 0x0a, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x30, 0x6c, 0x76, 0x57, 0x4b, 0x57, + 0x53, 0x77, 0x72, 0x4c, 0x51, 0x74, 0x44, 0x30, 0x2f, 0x64, 0x76, 0x57, 0x56, 0x5a, 0x67, 0x73, + 0x64, 0x42, 0x39, 0x43, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, + 0x42, 0x44, 0x44, 0x68, 0x4b, 0x76, 0x57, 0x30, 0x73, 0x55, 0x70, 0x64, 0x75, 0x49, 0x47, 0x74, + 0x68, 0x4e, 0x34, 0x6f, 0x38, 0x62, 0x37, 0x61, 0x45, 0x41, 0x6e, 0x4e, 0x77, 0x2f, 0x2b, 0x62, + 0x61, 0x5a, 0x30, 0x54, 0x38, 0x32, 0x6e, 0x59, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x50, 0x76, 0x0a, + 0x42, 0x76, 0x30, 0x4e, 0x48, 0x50, 0x6a, 0x53, 0x5a, 0x37, 0x33, 0x4d, 0x43, 0x56, 0x6c, 0x4d, + 0x61, 0x2b, 0x66, 0x39, 0x65, 0x62, 0x71, 0x65, 0x73, 0x54, 0x49, 0x45, 0x77, 0x47, 0x41, 0x65, + 0x78, 0x4a, 0x45, 0x39, 0x76, 0x4b, 0x49, 0x5a, 0x68, 0x31, 0x30, 0x53, 0x70, 0x79, 0x78, 0x61, + 0x62, 0x77, 0x68, 0x56, 0x6f, 0x47, 0x41, 0x71, 0x30, 0x74, 0x44, 0x51, 0x68, 0x7a, 0x47, 0x77, + 0x0a, 0x71, 0x6d, 0x34, 0x4d, 0x30, 0x34, 0x4c, 0x62, 0x33, 0x53, 0x46, 0x42, 0x75, 0x76, 0x52, + 0x70, 0x46, 0x34, 0x6f, 0x68, 0x62, 0x4d, 0x51, 0x64, 0x47, 0x49, 0x76, 0x71, 0x2b, 0x75, 0x34, + 0x72, 0x6d, 0x6d, 0x39, 0x54, 0x62, 0x69, 0x70, 0x41, 0x63, 0x43, 0x33, 0x47, 0x37, 0x50, 0x32, + 0x6a, 0x4c, 0x42, 0x53, 0x38, 0x37, 0x55, 0x48, 0x7a, 0x32, 0x74, 0x71, 0x42, 0x74, 0x4b, 0x64, + 0x4d, 0x0a, 0x64, 0x39, 0x44, 0x47, 0x73, 0x78, 0x78, 0x7a, 0x6b, 0x50, 0x75, 0x4c, 0x77, 0x48, + 0x50, 0x52, 0x36, 0x58, 0x75, 0x77, 0x75, 0x30, 0x78, 0x35, 0x5a, 0x38, 0x37, 0x4f, 0x58, 0x6e, + 0x6e, 0x6e, 0x6a, 0x38, 0x75, 0x59, 0x77, 0x61, 0x31, 0x2b, 0x55, 0x56, 0x6f, 0x65, 0x59, 0x7a, + 0x4a, 0x4c, 0x30, 0x75, 0x31, 0x51, 0x38, 0x46, 0x2f, 0x6c, 0x47, 0x63, 0x7a, 0x39, 0x65, 0x57, + 0x44, 0x6d, 0x0a, 0x6e, 0x58, 0x78, 0x75, 0x36, 0x64, 0x35, 0x79, 0x68, 0x70, 0x6c, 0x64, 0x4a, + 0x6f, 0x2b, 0x67, 0x42, 0x71, 0x72, 0x4d, 0x58, 0x6c, 0x32, 0x58, 0x4e, 0x4e, 0x5a, 0x61, 0x39, + 0x6e, 0x4d, 0x4a, 0x52, 0x54, 0x64, 0x2b, 0x6f, 0x57, 0x69, 0x54, 0x47, 0x65, 0x4e, 0x74, 0x4e, + 0x48, 0x6f, 0x41, 0x44, 0x7a, 0x34, 0x30, 0x2b, 0x41, 0x64, 0x62, 0x69, 0x47, 0x35, 0x48, 0x35, + 0x35, 0x30, 0x77, 0x0a, 0x4d, 0x45, 0x54, 0x57, 0x64, 0x54, 0x4e, 0x63, 0x4d, 0x6d, 0x4c, 0x31, + 0x77, 0x57, 0x6a, 0x30, 0x67, 0x35, 0x35, 0x49, 0x57, 0x7a, 0x65, 0x65, 0x48, 0x68, 0x73, 0x4e, + 0x54, 0x75, 0x66, 0x46, 0x55, 0x70, 0x48, 0x44, 0x4d, 0x34, 0x33, 0x61, 0x2f, 0x33, 0x7a, 0x53, + 0x48, 0x6e, 0x41, 0x44, 0x6f, 0x75, 0x5a, 0x78, 0x6e, 0x53, 0x67, 0x72, 0x71, 0x30, 0x31, 0x76, + 0x55, 0x75, 0x69, 0x70, 0x0a, 0x31, 0x6b, 0x45, 0x72, 0x35, 0x65, 0x53, 0x59, 0x64, 0x47, 0x6f, + 0x64, 0x34, 0x36, 0x78, 0x58, 0x35, 0x30, 0x56, 0x56, 0x4c, 0x79, 0x61, 0x53, 0x72, 0x39, 0x2b, + 0x37, 0x71, 0x4a, 0x64, 0x75, 0x77, 0x2b, 0x7a, 0x73, 0x41, 0x6d, 0x67, 0x50, 0x55, 0x58, 0x65, + 0x58, 0x7a, 0x79, 0x31, 0x7a, 0x44, 0x34, 0x46, 0x47, 0x61, 0x54, 0x2f, 0x56, 0x62, 0x57, 0x63, + 0x70, 0x37, 0x76, 0x65, 0x4c, 0x0a, 0x56, 0x48, 0x58, 0x53, 0x38, 0x35, 0x6b, 0x72, 0x72, 0x5a, + 0x6c, 0x4f, 0x64, 0x6c, 0x4b, 0x56, 0x4a, 0x6d, 0x45, 0x78, 0x4a, 0x45, 0x30, 0x6e, 0x4c, 0x4d, + 0x6b, 0x38, 0x55, 0x50, 0x53, 0x63, 0x75, 0x46, 0x35, 0x4c, 0x48, 0x36, 0x69, 0x61, 0x39, 0x51, + 0x67, 0x41, 0x53, 0x34, 0x6d, 0x35, 0x43, 0x66, 0x55, 0x33, 0x76, 0x69, 0x35, 0x77, 0x6d, 0x37, + 0x71, 0x6e, 0x59, 0x56, 0x77, 0x37, 0x0a, 0x45, 0x55, 0x4e, 0x50, 0x39, 0x36, 0x72, 0x78, 0x31, + 0x44, 0x66, 0x64, 0x2f, 0x41, 0x58, 0x73, 0x6a, 0x4a, 0x44, 0x62, 0x50, 0x6e, 0x4a, 0x57, 0x53, + 0x45, 0x69, 0x73, 0x4e, 0x35, 0x63, 0x31, 0x64, 0x67, 0x30, 0x56, 0x74, 0x48, 0x51, 0x56, 0x70, + 0x33, 0x67, 0x77, 0x39, 0x52, 0x56, 0x4e, 0x74, 0x66, 0x6d, 0x2b, 0x59, 0x2b, 0x31, 0x72, 0x33, + 0x2f, 0x44, 0x61, 0x44, 0x42, 0x48, 0x54, 0x0a, 0x49, 0x65, 0x33, 0x30, 0x79, 0x51, 0x50, 0x6c, + 0x41, 0x56, 0x72, 0x56, 0x6a, 0x57, 0x44, 0x77, 0x6e, 0x48, 0x73, 0x35, 0x31, 0x34, 0x50, 0x47, + 0x75, 0x69, 0x4d, 0x42, 0x51, 0x42, 0x67, 0x61, 0x6a, 0x67, 0x6e, 0x64, 0x4f, 0x45, 0x70, 0x54, + 0x67, 0x5a, 0x56, 0x48, 0x2f, 0x46, 0x33, 0x6a, 0x34, 0x59, 0x39, 0x6b, 0x37, 0x36, 0x4c, 0x44, + 0x62, 0x35, 0x45, 0x49, 0x54, 0x68, 0x51, 0x59, 0x0a, 0x59, 0x53, 0x63, 0x33, 0x31, 0x5a, 0x41, + 0x6b, 0x63, 0x49, 0x65, 0x79, 0x53, 0x66, 0x6f, 0x33, 0x2b, 0x51, 0x39, 0x4a, 0x69, 0x78, 0x59, + 0x51, 0x42, 0x78, 0x2f, 0x78, 0x4a, 0x57, 0x34, 0x4d, 0x37, 0x6a, 0x51, 0x33, 0x79, 0x6d, 0x42, + 0x65, 0x58, 0x59, 0x6d, 0x67, 0x66, 0x49, 0x76, 0x2b, 0x2f, 0x51, 0x53, 0x32, 0x59, 0x34, 0x4d, + 0x6d, 0x53, 0x63, 0x6b, 0x50, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +/* Contains the intermediateCA certificate */ +#define ROOT_CRL_PEM_LENGTH 1109 +UA_Byte ROOT_CRL_PEM_DATA[1109] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, + 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x43, 0x6a, 0x43, + 0x42, 0x38, 0x77, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x6d, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52, 0x54, 0x45, + 0x4f, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x41, 0x77, 0x46, 0x55, 0x33, + 0x52, 0x68, 0x64, 0x47, 0x55, 0x78, 0x44, 0x54, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x63, 0x4d, 0x42, 0x45, 0x4e, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x39, 0x79, 0x5a, 0x32, 0x46, 0x75, 0x61, 0x58, + 0x70, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x51, 0x0a, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x48, 0x54, 0x33, 0x4a, 0x6e, 0x56, 0x57, 0x35, 0x70, 0x64, + 0x44, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x47, 0x55, + 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x44, 0x41, 0x35, 0x4d, + 0x54, 0x45, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, 0x6a, 0x42, 0x61, 0x0a, 0x46, 0x77, 0x30, 0x79, + 0x4e, 0x44, 0x45, 0x77, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, 0x6a, 0x42, 0x61, + 0x4d, 0x43, 0x63, 0x77, 0x4a, 0x51, 0x49, 0x55, 0x54, 0x32, 0x55, 0x75, 0x68, 0x65, 0x71, 0x72, + 0x77, 0x30, 0x34, 0x50, 0x76, 0x54, 0x56, 0x79, 0x32, 0x73, 0x46, 0x44, 0x4e, 0x56, 0x4e, 0x38, + 0x5a, 0x30, 0x63, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, 0x44, 0x6b, 0x78, 0x0a, 0x4d, 0x54, 0x45, + 0x79, 0x4d, 0x44, 0x41, 0x77, 0x4f, 0x56, 0x71, 0x67, 0x4d, 0x44, 0x41, 0x75, 0x4d, 0x42, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x4e, 0x4a, + 0x62, 0x31, 0x69, 0x6c, 0x6b, 0x73, 0x4b, 0x79, 0x30, 0x4c, 0x51, 0x39, 0x50, 0x33, 0x62, 0x31, + 0x6c, 0x57, 0x59, 0x4c, 0x48, 0x51, 0x66, 0x51, 0x6d, 0x4d, 0x41, 0x73, 0x47, 0x0a, 0x41, 0x31, + 0x55, 0x64, 0x46, 0x41, 0x51, 0x45, 0x41, 0x67, 0x49, 0x51, 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, + 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x59, 0x30, 0x58, 0x6c, 0x44, 0x31, 0x34, 0x4b, 0x71, 0x32, + 0x51, 0x41, 0x70, 0x77, 0x61, 0x70, 0x68, 0x56, 0x53, 0x58, 0x4b, 0x33, 0x53, 0x39, 0x0a, 0x55, + 0x58, 0x7a, 0x57, 0x41, 0x48, 0x2b, 0x2f, 0x68, 0x39, 0x61, 0x38, 0x46, 0x58, 0x2b, 0x65, 0x45, + 0x61, 0x6f, 0x68, 0x6f, 0x6a, 0x47, 0x51, 0x36, 0x62, 0x57, 0x34, 0x72, 0x68, 0x42, 0x4e, 0x5a, + 0x75, 0x4f, 0x2b, 0x57, 0x31, 0x38, 0x79, 0x78, 0x6b, 0x47, 0x33, 0x2f, 0x61, 0x55, 0x75, 0x68, + 0x30, 0x58, 0x65, 0x77, 0x58, 0x4a, 0x6f, 0x46, 0x67, 0x39, 0x4a, 0x2f, 0x6e, 0x51, 0x6c, 0x0a, + 0x6a, 0x67, 0x5a, 0x70, 0x70, 0x46, 0x6f, 0x54, 0x6b, 0x4a, 0x6d, 0x49, 0x53, 0x64, 0x2f, 0x75, + 0x34, 0x65, 0x70, 0x4b, 0x6b, 0x31, 0x63, 0x4d, 0x2f, 0x71, 0x33, 0x32, 0x6e, 0x42, 0x63, 0x70, + 0x58, 0x7a, 0x6a, 0x6f, 0x5a, 0x33, 0x66, 0x57, 0x6a, 0x43, 0x37, 0x55, 0x5a, 0x4b, 0x62, 0x46, + 0x32, 0x63, 0x31, 0x43, 0x4e, 0x53, 0x61, 0x44, 0x6a, 0x64, 0x35, 0x65, 0x59, 0x2b, 0x36, 0x53, + 0x0a, 0x59, 0x6c, 0x4b, 0x36, 0x45, 0x47, 0x66, 0x6b, 0x57, 0x58, 0x74, 0x66, 0x30, 0x68, 0x50, + 0x46, 0x42, 0x4f, 0x39, 0x69, 0x69, 0x65, 0x32, 0x33, 0x68, 0x41, 0x71, 0x58, 0x4a, 0x6e, 0x67, + 0x46, 0x56, 0x75, 0x67, 0x50, 0x53, 0x39, 0x78, 0x68, 0x38, 0x6d, 0x47, 0x53, 0x64, 0x39, 0x6e, + 0x4d, 0x32, 0x6e, 0x50, 0x68, 0x46, 0x43, 0x49, 0x67, 0x50, 0x6a, 0x37, 0x41, 0x32, 0x73, 0x58, + 0x76, 0x0a, 0x78, 0x79, 0x33, 0x37, 0x36, 0x48, 0x67, 0x6b, 0x2b, 0x66, 0x73, 0x55, 0x59, 0x39, + 0x51, 0x6d, 0x66, 0x42, 0x41, 0x55, 0x46, 0x6e, 0x6c, 0x2b, 0x2b, 0x36, 0x79, 0x6c, 0x54, 0x39, + 0x6c, 0x4d, 0x4e, 0x62, 0x78, 0x2b, 0x50, 0x5a, 0x73, 0x33, 0x30, 0x78, 0x78, 0x64, 0x48, 0x6d, + 0x4f, 0x6f, 0x61, 0x38, 0x69, 0x4a, 0x73, 0x46, 0x56, 0x4a, 0x67, 0x34, 0x71, 0x4c, 0x33, 0x31, + 0x39, 0x6a, 0x0a, 0x55, 0x63, 0x4b, 0x49, 0x67, 0x41, 0x6e, 0x56, 0x48, 0x6e, 0x41, 0x4a, 0x32, + 0x59, 0x42, 0x61, 0x30, 0x4a, 0x30, 0x56, 0x79, 0x38, 0x33, 0x38, 0x30, 0x77, 0x48, 0x64, 0x43, + 0x54, 0x50, 0x5a, 0x32, 0x43, 0x74, 0x77, 0x2f, 0x76, 0x62, 0x74, 0x75, 0x54, 0x56, 0x54, 0x4b, + 0x36, 0x62, 0x44, 0x4b, 0x37, 0x72, 0x76, 0x6a, 0x58, 0x58, 0x4c, 0x34, 0x7a, 0x56, 0x66, 0x71, + 0x7a, 0x32, 0x78, 0x0a, 0x30, 0x63, 0x6e, 0x66, 0x70, 0x64, 0x55, 0x49, 0x57, 0x37, 0x4a, 0x36, + 0x68, 0x64, 0x4e, 0x70, 0x58, 0x77, 0x33, 0x76, 0x4c, 0x67, 0x4c, 0x66, 0x76, 0x57, 0x6b, 0x59, + 0x4b, 0x65, 0x79, 0x35, 0x61, 0x79, 0x72, 0x7a, 0x36, 0x32, 0x37, 0x45, 0x4c, 0x32, 0x47, 0x36, + 0x65, 0x77, 0x51, 0x53, 0x78, 0x71, 0x71, 0x53, 0x4c, 0x73, 0x6b, 0x67, 0x52, 0x52, 0x55, 0x74, + 0x6a, 0x4e, 0x66, 0x79, 0x0a, 0x38, 0x2b, 0x71, 0x34, 0x47, 0x49, 0x32, 0x71, 0x47, 0x4e, 0x71, + 0x4d, 0x48, 0x75, 0x79, 0x32, 0x39, 0x53, 0x70, 0x31, 0x74, 0x4c, 0x78, 0x76, 0x73, 0x71, 0x56, + 0x6e, 0x30, 0x52, 0x55, 0x58, 0x46, 0x42, 0x44, 0x69, 0x62, 0x6c, 0x31, 0x5a, 0x74, 0x67, 0x4f, + 0x65, 0x2b, 0x33, 0x2f, 0x4c, 0x2f, 0x58, 0x7a, 0x6a, 0x76, 0x73, 0x45, 0x78, 0x66, 0x73, 0x77, + 0x4e, 0x54, 0x73, 0x50, 0x4f, 0x0a, 0x2b, 0x54, 0x49, 0x69, 0x42, 0x55, 0x71, 0x5a, 0x4a, 0x4a, + 0x4c, 0x78, 0x61, 0x6d, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x53, 0x45, 0x4d, 0x4e, 0x67, 0x6a, 0x69, + 0x77, 0x75, 0x33, 0x62, 0x45, 0x79, 0x4e, 0x65, 0x6d, 0x63, 0x6b, 0x6c, 0x31, 0x74, 0x70, 0x64, + 0x6a, 0x67, 0x36, 0x2b, 0x79, 0x36, 0x68, 0x56, 0x71, 0x6b, 0x74, 0x76, 0x65, 0x37, 0x4a, 0x42, + 0x33, 0x45, 0x64, 0x67, 0x4f, 0x4c, 0x0a, 0x45, 0x4c, 0x68, 0x7a, 0x50, 0x41, 0x54, 0x38, 0x48, + 0x52, 0x61, 0x75, 0x43, 0x6b, 0x71, 0x47, 0x41, 0x67, 0x61, 0x57, 0x62, 0x58, 0x43, 0x38, 0x31, + 0x65, 0x6d, 0x56, 0x55, 0x52, 0x51, 0x4e, 0x42, 0x71, 0x74, 0x55, 0x30, 0x30, 0x75, 0x77, 0x4a, + 0x45, 0x75, 0x4c, 0x35, 0x73, 0x47, 0x32, 0x4c, 0x4c, 0x53, 0x43, 0x50, 0x2f, 0x78, 0x30, 0x52, + 0x76, 0x46, 0x63, 0x73, 0x32, 0x79, 0x68, 0x0a, 0x73, 0x4a, 0x6f, 0x59, 0x4d, 0x31, 0x61, 0x6f, + 0x6c, 0x43, 0x52, 0x2f, 0x32, 0x52, 0x33, 0x2f, 0x72, 0x2b, 0x57, 0x39, 0x55, 0x52, 0x39, 0x37, + 0x59, 0x72, 0x59, 0x74, 0x75, 0x4a, 0x62, 0x6a, 0x52, 0x42, 0x71, 0x69, 0x56, 0x4d, 0x49, 0x52, + 0x70, 0x53, 0x2f, 0x49, 0x62, 0x49, 0x77, 0x72, 0x50, 0x72, 0x5a, 0x45, 0x47, 0x75, 0x58, 0x67, + 0x35, 0x44, 0x48, 0x56, 0x33, 0x6e, 0x36, 0x63, 0x0a, 0x66, 0x6d, 0x58, 0x2f, 0x76, 0x4b, 0x45, + 0x62, 0x6d, 0x72, 0x74, 0x49, 0x6c, 0x57, 0x6a, 0x45, 0x36, 0x67, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, 0x43, 0x52, 0x4c, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +#define ROOT_EMPTY_CRL_PEM_LENGTH 1052 +UA_Byte ROOT_EMPTY_CRL_PEM_DATA[1052] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, + 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x34, 0x54, 0x43, + 0x42, 0x79, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x6d, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52, 0x54, 0x45, + 0x4f, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x41, 0x77, 0x46, 0x55, 0x33, + 0x52, 0x68, 0x64, 0x47, 0x55, 0x78, 0x44, 0x54, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x63, 0x4d, 0x42, 0x45, 0x4e, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x39, 0x79, 0x5a, 0x32, 0x46, 0x75, 0x61, 0x58, + 0x70, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x51, 0x0a, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x48, 0x54, 0x33, 0x4a, 0x6e, 0x56, 0x57, 0x35, 0x70, 0x64, + 0x44, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x47, 0x55, + 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x44, 0x41, 0x35, 0x4d, + 0x54, 0x45, 0x78, 0x4d, 0x6a, 0x41, 0x30, 0x4e, 0x44, 0x56, 0x61, 0x0a, 0x46, 0x77, 0x30, 0x79, + 0x4e, 0x44, 0x45, 0x77, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x6a, 0x41, 0x30, 0x4e, 0x44, 0x56, 0x61, + 0x6f, 0x44, 0x41, 0x77, 0x4c, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, + 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x54, 0x53, 0x57, 0x39, 0x59, 0x70, 0x5a, 0x4c, 0x43, 0x73, + 0x74, 0x43, 0x30, 0x50, 0x54, 0x39, 0x32, 0x39, 0x5a, 0x56, 0x6d, 0x43, 0x0a, 0x78, 0x30, 0x48, + 0x30, 0x4a, 0x6a, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x51, 0x45, 0x42, 0x41, 0x49, + 0x43, 0x45, 0x41, 0x4d, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x42, 0x59, + 0x65, 0x48, 0x74, 0x57, 0x61, 0x5a, 0x33, 0x6b, 0x4c, 0x46, 0x45, 0x30, 0x63, 0x0a, 0x77, 0x66, + 0x66, 0x42, 0x4b, 0x37, 0x32, 0x62, 0x50, 0x48, 0x6c, 0x6f, 0x34, 0x31, 0x79, 0x2f, 0x6d, 0x48, + 0x38, 0x65, 0x52, 0x63, 0x47, 0x66, 0x57, 0x46, 0x6a, 0x45, 0x6d, 0x50, 0x58, 0x49, 0x67, 0x36, + 0x71, 0x31, 0x44, 0x79, 0x37, 0x66, 0x54, 0x6f, 0x54, 0x69, 0x44, 0x71, 0x72, 0x52, 0x6e, 0x49, + 0x41, 0x68, 0x53, 0x44, 0x6e, 0x4c, 0x6a, 0x56, 0x64, 0x4f, 0x34, 0x74, 0x52, 0x66, 0x0a, 0x73, + 0x6a, 0x64, 0x72, 0x58, 0x2f, 0x32, 0x67, 0x52, 0x30, 0x4e, 0x6f, 0x57, 0x66, 0x48, 0x63, 0x78, + 0x58, 0x61, 0x6b, 0x41, 0x42, 0x4e, 0x31, 0x51, 0x35, 0x45, 0x4e, 0x39, 0x61, 0x4f, 0x74, 0x35, + 0x45, 0x2b, 0x6d, 0x4d, 0x4b, 0x46, 0x59, 0x46, 0x74, 0x4a, 0x55, 0x50, 0x79, 0x76, 0x67, 0x36, + 0x57, 0x63, 0x7a, 0x44, 0x57, 0x52, 0x50, 0x6d, 0x75, 0x32, 0x67, 0x69, 0x44, 0x6c, 0x6d, 0x0a, + 0x31, 0x4c, 0x5a, 0x31, 0x35, 0x56, 0x67, 0x49, 0x77, 0x78, 0x64, 0x55, 0x6d, 0x39, 0x48, 0x35, + 0x32, 0x6e, 0x44, 0x4a, 0x35, 0x54, 0x64, 0x38, 0x4e, 0x4b, 0x6e, 0x53, 0x43, 0x67, 0x58, 0x4b, + 0x62, 0x52, 0x33, 0x47, 0x61, 0x4e, 0x79, 0x66, 0x75, 0x74, 0x73, 0x73, 0x58, 0x72, 0x74, 0x6d, + 0x58, 0x33, 0x42, 0x53, 0x55, 0x78, 0x54, 0x62, 0x6c, 0x5a, 0x48, 0x4e, 0x31, 0x6b, 0x4b, 0x33, + 0x0a, 0x44, 0x52, 0x71, 0x79, 0x74, 0x79, 0x44, 0x52, 0x61, 0x72, 0x4b, 0x49, 0x37, 0x52, 0x58, + 0x52, 0x48, 0x35, 0x46, 0x79, 0x55, 0x32, 0x76, 0x4d, 0x79, 0x49, 0x4c, 0x5a, 0x2b, 0x7a, 0x6b, + 0x45, 0x51, 0x69, 0x75, 0x68, 0x36, 0x62, 0x54, 0x79, 0x43, 0x2b, 0x57, 0x52, 0x37, 0x42, 0x30, + 0x72, 0x44, 0x6a, 0x6f, 0x38, 0x4c, 0x78, 0x72, 0x30, 0x72, 0x72, 0x31, 0x2b, 0x78, 0x59, 0x67, + 0x43, 0x0a, 0x32, 0x4c, 0x50, 0x68, 0x59, 0x63, 0x36, 0x4e, 0x71, 0x6b, 0x6f, 0x76, 0x73, 0x78, + 0x6a, 0x63, 0x33, 0x34, 0x37, 0x72, 0x2f, 0x7a, 0x4e, 0x32, 0x58, 0x45, 0x6d, 0x4b, 0x74, 0x67, + 0x46, 0x44, 0x59, 0x49, 0x71, 0x65, 0x59, 0x5a, 0x47, 0x31, 0x75, 0x4b, 0x36, 0x65, 0x53, 0x59, + 0x4c, 0x32, 0x4d, 0x48, 0x69, 0x32, 0x39, 0x77, 0x33, 0x49, 0x4a, 0x55, 0x4a, 0x64, 0x57, 0x44, + 0x41, 0x4d, 0x0a, 0x48, 0x46, 0x55, 0x64, 0x58, 0x64, 0x77, 0x43, 0x63, 0x2f, 0x62, 0x67, 0x49, + 0x6b, 0x6c, 0x72, 0x35, 0x31, 0x4d, 0x45, 0x69, 0x39, 0x4d, 0x42, 0x70, 0x4a, 0x39, 0x55, 0x43, + 0x77, 0x55, 0x41, 0x68, 0x2b, 0x78, 0x6b, 0x63, 0x42, 0x48, 0x70, 0x4d, 0x76, 0x6f, 0x34, 0x38, + 0x34, 0x75, 0x6c, 0x6f, 0x61, 0x36, 0x6d, 0x77, 0x74, 0x36, 0x32, 0x69, 0x79, 0x57, 0x36, 0x70, + 0x6e, 0x4c, 0x58, 0x0a, 0x78, 0x74, 0x4e, 0x6f, 0x61, 0x53, 0x6a, 0x4b, 0x2b, 0x52, 0x43, 0x4f, + 0x4b, 0x74, 0x57, 0x64, 0x61, 0x7a, 0x70, 0x73, 0x77, 0x36, 0x39, 0x45, 0x44, 0x6d, 0x39, 0x76, + 0x70, 0x4e, 0x32, 0x47, 0x34, 0x4e, 0x52, 0x47, 0x6f, 0x6a, 0x62, 0x4b, 0x59, 0x6a, 0x66, 0x33, + 0x44, 0x6e, 0x2b, 0x6e, 0x43, 0x6d, 0x54, 0x64, 0x36, 0x71, 0x4c, 0x75, 0x41, 0x63, 0x53, 0x62, + 0x4d, 0x31, 0x62, 0x77, 0x0a, 0x4b, 0x43, 0x65, 0x64, 0x70, 0x56, 0x6f, 0x55, 0x6c, 0x6a, 0x72, + 0x43, 0x68, 0x50, 0x62, 0x50, 0x55, 0x39, 0x30, 0x2b, 0x46, 0x50, 0x2b, 0x59, 0x54, 0x33, 0x6e, + 0x6a, 0x51, 0x2f, 0x2b, 0x52, 0x36, 0x68, 0x59, 0x55, 0x78, 0x31, 0x6e, 0x53, 0x62, 0x6c, 0x7a, + 0x37, 0x4f, 0x6d, 0x75, 0x2b, 0x62, 0x2b, 0x57, 0x35, 0x79, 0x71, 0x72, 0x72, 0x69, 0x6f, 0x30, + 0x38, 0x78, 0x50, 0x64, 0x37, 0x0a, 0x2f, 0x51, 0x70, 0x37, 0x32, 0x30, 0x52, 0x35, 0x43, 0x61, + 0x6a, 0x34, 0x4d, 0x70, 0x57, 0x65, 0x44, 0x42, 0x65, 0x78, 0x32, 0x68, 0x41, 0x51, 0x32, 0x39, + 0x44, 0x30, 0x39, 0x70, 0x53, 0x66, 0x5a, 0x35, 0x63, 0x52, 0x32, 0x63, 0x4c, 0x4a, 0x6b, 0x70, + 0x50, 0x53, 0x66, 0x4f, 0x76, 0x62, 0x76, 0x74, 0x4f, 0x56, 0x61, 0x6c, 0x30, 0x6d, 0x36, 0x6c, + 0x34, 0x30, 0x48, 0x4a, 0x52, 0x6c, 0x0a, 0x2f, 0x56, 0x67, 0x2f, 0x63, 0x42, 0x51, 0x67, 0x46, + 0x47, 0x54, 0x39, 0x66, 0x6d, 0x45, 0x4c, 0x36, 0x38, 0x5a, 0x37, 0x48, 0x61, 0x31, 0x76, 0x34, + 0x44, 0x61, 0x7a, 0x47, 0x44, 0x32, 0x2b, 0x71, 0x52, 0x58, 0x69, 0x45, 0x2b, 0x49, 0x5a, 0x53, + 0x55, 0x47, 0x7a, 0x33, 0x4a, 0x4e, 0x7a, 0x59, 0x6d, 0x42, 0x48, 0x75, 0x53, 0x43, 0x51, 0x6d, + 0x39, 0x66, 0x2f, 0x74, 0x69, 0x4a, 0x35, 0x0a, 0x53, 0x51, 0x46, 0x78, 0x6b, 0x47, 0x38, 0x49, + 0x32, 0x45, 0x33, 0x68, 0x73, 0x6c, 0x38, 0x4b, 0x33, 0x65, 0x4d, 0x4d, 0x61, 0x6b, 0x45, 0x43, + 0x66, 0x34, 0x79, 0x53, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x58, 0x35, + 0x30, 0x39, 0x20, 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +#define INTERMEDIATE_CERT_DER_LENGTH 2057 +UA_Byte INTERMEDIATE_CERT_DER_DATA[2057] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, + 0x77, 0x6a, 0x43, 0x43, 0x41, 0x36, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, + 0x54, 0x32, 0x55, 0x75, 0x68, 0x65, 0x71, 0x72, 0x77, 0x30, 0x34, 0x50, 0x76, 0x54, 0x56, 0x79, + 0x32, 0x73, 0x46, 0x44, 0x4e, 0x56, 0x4e, 0x38, 0x5a, 0x30, 0x63, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, + 0x77, 0x5a, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x52, 0x45, 0x55, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, + 0x4d, 0x42, 0x56, 0x4e, 0x30, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x52, 0x44, 0x61, 0x58, 0x52, 0x35, 0x0a, 0x4d, 0x52, + 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x78, 0x50, 0x63, 0x6d, + 0x64, 0x68, 0x62, 0x6d, 0x6c, 0x36, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x45, 0x44, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x42, 0x30, 0x39, 0x79, 0x5a, 0x31, + 0x56, 0x75, 0x61, 0x58, 0x51, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, + 0x41, 0x4d, 0x4d, 0x42, 0x6c, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, + 0x77, 0x30, 0x79, 0x4e, 0x44, 0x41, 0x35, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x54, 0x55, 0x33, 0x4d, + 0x7a, 0x5a, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x44, 0x41, 0x35, 0x4d, 0x44, 0x6b, 0x78, 0x4d, + 0x54, 0x55, 0x33, 0x4d, 0x7a, 0x5a, 0x61, 0x4d, 0x47, 0x34, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x52, 0x46, 0x4d, 0x51, 0x34, 0x77, + 0x44, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x56, 0x54, 0x64, 0x47, 0x46, 0x30, + 0x5a, 0x54, 0x45, 0x4e, 0x4d, 0x41, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x45, + 0x51, 0x32, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0a, 0x43, 0x67, 0x77, 0x4d, 0x54, 0x33, 0x4a, 0x6e, 0x59, 0x57, 0x35, 0x70, 0x65, 0x6d, 0x46, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x44, 0x41, 0x64, 0x50, 0x63, 0x6d, 0x64, 0x56, 0x62, 0x6d, 0x6c, 0x30, 0x4d, 0x52, 0x63, + 0x77, 0x46, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x41, 0x35, 0x4a, 0x62, 0x6e, 0x52, + 0x6c, 0x0a, 0x63, 0x6d, 0x31, 0x6c, 0x5a, 0x47, 0x6c, 0x68, 0x64, 0x47, 0x56, 0x44, 0x51, 0x54, + 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4e, 0x31, 0x4e, 0x4f, 0x55, + 0x72, 0x63, 0x0a, 0x66, 0x68, 0x4e, 0x51, 0x4a, 0x46, 0x74, 0x42, 0x4a, 0x55, 0x39, 0x51, 0x47, + 0x35, 0x34, 0x4f, 0x2f, 0x46, 0x63, 0x67, 0x61, 0x4a, 0x4a, 0x2b, 0x53, 0x69, 0x79, 0x73, 0x4c, + 0x36, 0x4d, 0x49, 0x37, 0x50, 0x42, 0x4e, 0x55, 0x45, 0x31, 0x56, 0x6a, 0x6d, 0x59, 0x59, 0x38, + 0x35, 0x2f, 0x34, 0x57, 0x43, 0x57, 0x58, 0x66, 0x69, 0x47, 0x39, 0x75, 0x58, 0x79, 0x42, 0x6c, + 0x6b, 0x31, 0x55, 0x0a, 0x62, 0x70, 0x5a, 0x61, 0x4b, 0x72, 0x76, 0x51, 0x59, 0x4b, 0x64, 0x59, + 0x52, 0x50, 0x5a, 0x39, 0x48, 0x71, 0x66, 0x76, 0x42, 0x43, 0x6b, 0x6d, 0x68, 0x4a, 0x53, 0x36, + 0x6e, 0x4a, 0x57, 0x75, 0x38, 0x53, 0x39, 0x41, 0x43, 0x4a, 0x34, 0x47, 0x47, 0x51, 0x6d, 0x63, + 0x54, 0x69, 0x68, 0x71, 0x35, 0x6f, 0x72, 0x5a, 0x6f, 0x57, 0x73, 0x75, 0x32, 0x2b, 0x46, 0x7a, + 0x4d, 0x71, 0x45, 0x6b, 0x0a, 0x4d, 0x69, 0x2f, 0x47, 0x52, 0x6a, 0x2b, 0x4d, 0x53, 0x70, 0x6f, + 0x57, 0x39, 0x68, 0x55, 0x74, 0x44, 0x6a, 0x42, 0x33, 0x6a, 0x74, 0x63, 0x4b, 0x31, 0x73, 0x68, + 0x38, 0x53, 0x46, 0x74, 0x66, 0x48, 0x49, 0x44, 0x42, 0x66, 0x31, 0x4b, 0x53, 0x4c, 0x5a, 0x46, + 0x6b, 0x4c, 0x6a, 0x55, 0x43, 0x4a, 0x75, 0x65, 0x6b, 0x6d, 0x67, 0x31, 0x47, 0x78, 0x63, 0x34, + 0x70, 0x37, 0x6f, 0x78, 0x65, 0x0a, 0x6f, 0x45, 0x43, 0x49, 0x6b, 0x57, 0x4e, 0x54, 0x30, 0x52, + 0x4e, 0x53, 0x64, 0x4a, 0x6f, 0x2b, 0x73, 0x4f, 0x63, 0x6d, 0x6a, 0x59, 0x38, 0x6a, 0x32, 0x77, + 0x43, 0x4e, 0x69, 0x7a, 0x6c, 0x32, 0x76, 0x36, 0x42, 0x43, 0x72, 0x41, 0x57, 0x6f, 0x75, 0x4d, + 0x68, 0x6f, 0x78, 0x6a, 0x6c, 0x54, 0x41, 0x33, 0x33, 0x66, 0x43, 0x73, 0x2b, 0x2b, 0x6c, 0x58, + 0x6b, 0x4d, 0x2b, 0x79, 0x38, 0x6e, 0x0a, 0x46, 0x7a, 0x41, 0x6f, 0x75, 0x67, 0x68, 0x4b, 0x62, + 0x56, 0x31, 0x43, 0x69, 0x71, 0x59, 0x6a, 0x65, 0x68, 0x36, 0x6d, 0x56, 0x6a, 0x38, 0x68, 0x69, + 0x30, 0x39, 0x32, 0x55, 0x66, 0x33, 0x6a, 0x62, 0x43, 0x78, 0x6c, 0x4a, 0x73, 0x6f, 0x73, 0x46, + 0x2b, 0x4a, 0x65, 0x78, 0x54, 0x59, 0x56, 0x64, 0x41, 0x4e, 0x36, 0x74, 0x72, 0x50, 0x75, 0x4c, + 0x2f, 0x4a, 0x51, 0x4b, 0x66, 0x4b, 0x54, 0x0a, 0x4a, 0x39, 0x74, 0x31, 0x44, 0x62, 0x71, 0x6e, + 0x44, 0x74, 0x38, 0x50, 0x75, 0x43, 0x55, 0x45, 0x67, 0x63, 0x44, 0x76, 0x71, 0x48, 0x51, 0x4a, + 0x58, 0x58, 0x34, 0x53, 0x33, 0x59, 0x66, 0x65, 0x57, 0x62, 0x6e, 0x74, 0x51, 0x63, 0x36, 0x62, + 0x5a, 0x34, 0x4a, 0x5a, 0x44, 0x5a, 0x63, 0x46, 0x35, 0x6f, 0x67, 0x39, 0x47, 0x69, 0x6f, 0x61, + 0x5a, 0x2b, 0x75, 0x55, 0x45, 0x63, 0x4e, 0x62, 0x0a, 0x47, 0x4d, 0x32, 0x76, 0x33, 0x31, 0x5a, + 0x44, 0x74, 0x31, 0x45, 0x46, 0x41, 0x7a, 0x74, 0x6d, 0x74, 0x46, 0x74, 0x72, 0x70, 0x68, 0x52, + 0x50, 0x79, 0x5a, 0x4e, 0x61, 0x76, 0x39, 0x73, 0x63, 0x52, 0x77, 0x75, 0x50, 0x37, 0x51, 0x72, + 0x49, 0x62, 0x63, 0x66, 0x45, 0x63, 0x63, 0x51, 0x55, 0x70, 0x33, 0x61, 0x2f, 0x62, 0x62, 0x31, + 0x49, 0x51, 0x50, 0x4b, 0x2b, 0x4b, 0x59, 0x50, 0x67, 0x0a, 0x31, 0x50, 0x61, 0x67, 0x58, 0x57, + 0x59, 0x44, 0x62, 0x69, 0x6c, 0x55, 0x42, 0x4a, 0x57, 0x6d, 0x69, 0x32, 0x52, 0x31, 0x69, 0x52, + 0x4b, 0x78, 0x39, 0x59, 0x4e, 0x61, 0x68, 0x34, 0x45, 0x51, 0x49, 0x6f, 0x49, 0x72, 0x61, 0x61, + 0x66, 0x54, 0x6a, 0x78, 0x73, 0x6f, 0x6e, 0x50, 0x2f, 0x30, 0x55, 0x79, 0x62, 0x6b, 0x71, 0x65, + 0x6e, 0x73, 0x4b, 0x4d, 0x47, 0x71, 0x58, 0x54, 0x2f, 0x55, 0x0a, 0x64, 0x34, 0x52, 0x33, 0x36, + 0x50, 0x31, 0x64, 0x44, 0x43, 0x6b, 0x6b, 0x4e, 0x2b, 0x4b, 0x59, 0x64, 0x55, 0x42, 0x4d, 0x44, + 0x72, 0x76, 0x66, 0x69, 0x51, 0x34, 0x47, 0x64, 0x4e, 0x6a, 0x4c, 0x5a, 0x61, 0x2b, 0x49, 0x32, + 0x75, 0x50, 0x50, 0x6c, 0x55, 0x6e, 0x76, 0x72, 0x38, 0x7a, 0x67, 0x43, 0x73, 0x45, 0x77, 0x4f, + 0x7a, 0x75, 0x46, 0x32, 0x5a, 0x73, 0x32, 0x4f, 0x6f, 0x32, 0x50, 0x0a, 0x50, 0x52, 0x63, 0x7a, + 0x50, 0x50, 0x5a, 0x44, 0x2b, 0x61, 0x36, 0x46, 0x64, 0x74, 0x39, 0x44, 0x65, 0x74, 0x73, 0x47, + 0x77, 0x36, 0x35, 0x32, 0x49, 0x47, 0x38, 0x65, 0x49, 0x59, 0x70, 0x33, 0x63, 0x47, 0x2f, 0x4b, + 0x43, 0x74, 0x66, 0x6b, 0x6f, 0x30, 0x76, 0x58, 0x6f, 0x46, 0x4a, 0x73, 0x43, 0x4e, 0x4b, 0x36, + 0x2f, 0x45, 0x6e, 0x65, 0x31, 0x4e, 0x66, 0x72, 0x45, 0x6e, 0x7a, 0x79, 0x0a, 0x32, 0x30, 0x67, + 0x7a, 0x7a, 0x39, 0x4a, 0x55, 0x6d, 0x35, 0x7a, 0x68, 0x73, 0x38, 0x54, 0x68, 0x59, 0x63, 0x34, + 0x75, 0x35, 0x6f, 0x41, 0x2f, 0x78, 0x48, 0x6f, 0x79, 0x76, 0x79, 0x57, 0x46, 0x38, 0x74, 0x39, + 0x31, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x44, 0x42, 0x65, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x42, 0x41, + 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x52, 0x6c, 0x76, 0x43, 0x32, 0x55, 0x61, 0x31, 0x32, 0x64, 0x34, 0x59, + 0x51, 0x31, 0x4f, 0x51, 0x79, 0x2b, 0x32, 0x43, 0x76, 0x4c, 0x6e, 0x4c, 0x47, 0x72, 0x0a, 0x41, + 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x54, 0x53, 0x57, 0x39, 0x59, 0x70, 0x5a, 0x4c, 0x43, 0x73, 0x74, 0x43, 0x30, 0x50, 0x54, + 0x39, 0x32, 0x39, 0x5a, 0x56, 0x6d, 0x43, 0x78, 0x30, 0x48, 0x30, 0x4a, 0x6a, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x0a, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x67, 0x65, 0x48, 0x74, 0x75, 0x57, 0x4b, 0x38, + 0x35, 0x31, 0x68, 0x4f, 0x48, 0x58, 0x55, 0x52, 0x62, 0x59, 0x71, 0x43, 0x75, 0x37, 0x4f, 0x58, + 0x6c, 0x35, 0x61, 0x73, 0x69, 0x2b, 0x61, 0x39, 0x44, 0x59, 0x72, 0x4b, 0x66, 0x34, 0x4c, 0x50, + 0x71, 0x35, 0x50, 0x78, 0x72, 0x48, 0x38, 0x2b, 0x64, 0x56, 0x33, 0x6c, 0x49, 0x44, 0x6a, 0x38, + 0x0a, 0x59, 0x47, 0x5a, 0x6c, 0x34, 0x34, 0x64, 0x37, 0x34, 0x6f, 0x6c, 0x38, 0x4a, 0x72, 0x71, + 0x2f, 0x4b, 0x59, 0x64, 0x39, 0x34, 0x71, 0x53, 0x46, 0x76, 0x71, 0x30, 0x39, 0x39, 0x43, 0x66, + 0x42, 0x6c, 0x53, 0x65, 0x61, 0x6d, 0x44, 0x4d, 0x71, 0x4a, 0x30, 0x54, 0x4d, 0x76, 0x68, 0x4d, + 0x62, 0x37, 0x38, 0x68, 0x75, 0x7a, 0x48, 0x4f, 0x63, 0x59, 0x73, 0x72, 0x73, 0x6e, 0x4c, 0x4f, + 0x77, 0x0a, 0x45, 0x32, 0x6f, 0x46, 0x43, 0x65, 0x41, 0x45, 0x2b, 0x78, 0x77, 0x2f, 0x68, 0x2f, + 0x53, 0x4c, 0x75, 0x62, 0x76, 0x6e, 0x59, 0x6d, 0x43, 0x43, 0x5a, 0x67, 0x4f, 0x50, 0x54, 0x4f, + 0x32, 0x74, 0x51, 0x5a, 0x72, 0x34, 0x4d, 0x39, 0x75, 0x44, 0x6e, 0x52, 0x37, 0x7a, 0x49, 0x66, + 0x38, 0x6c, 0x59, 0x47, 0x56, 0x33, 0x50, 0x6d, 0x43, 0x6e, 0x78, 0x63, 0x78, 0x2b, 0x4a, 0x68, + 0x76, 0x65, 0x0a, 0x6d, 0x74, 0x47, 0x62, 0x6b, 0x2f, 0x6d, 0x35, 0x6a, 0x73, 0x68, 0x52, 0x6c, + 0x2b, 0x44, 0x30, 0x62, 0x53, 0x64, 0x76, 0x52, 0x36, 0x52, 0x56, 0x37, 0x71, 0x4b, 0x72, 0x70, + 0x4c, 0x50, 0x5a, 0x38, 0x74, 0x42, 0x79, 0x46, 0x2b, 0x53, 0x2b, 0x63, 0x45, 0x4d, 0x6f, 0x6b, + 0x6f, 0x47, 0x35, 0x6d, 0x63, 0x59, 0x38, 0x68, 0x75, 0x39, 0x38, 0x7a, 0x36, 0x79, 0x65, 0x73, + 0x43, 0x73, 0x70, 0x0a, 0x79, 0x43, 0x64, 0x46, 0x74, 0x55, 0x45, 0x34, 0x69, 0x77, 0x64, 0x70, + 0x4b, 0x2f, 0x55, 0x56, 0x48, 0x61, 0x31, 0x39, 0x44, 0x52, 0x72, 0x6f, 0x48, 0x64, 0x41, 0x48, + 0x61, 0x36, 0x37, 0x79, 0x38, 0x79, 0x73, 0x50, 0x46, 0x69, 0x34, 0x65, 0x76, 0x63, 0x50, 0x32, + 0x44, 0x65, 0x48, 0x50, 0x70, 0x32, 0x6f, 0x78, 0x4a, 0x73, 0x2b, 0x38, 0x4b, 0x73, 0x73, 0x4c, + 0x44, 0x31, 0x30, 0x6f, 0x0a, 0x78, 0x6a, 0x4a, 0x37, 0x6b, 0x43, 0x64, 0x6e, 0x70, 0x78, 0x4a, + 0x5a, 0x64, 0x49, 0x74, 0x41, 0x39, 0x76, 0x54, 0x44, 0x75, 0x69, 0x48, 0x57, 0x79, 0x66, 0x69, + 0x79, 0x4a, 0x75, 0x35, 0x6f, 0x30, 0x71, 0x4e, 0x4d, 0x49, 0x50, 0x50, 0x57, 0x4d, 0x76, 0x51, + 0x46, 0x45, 0x74, 0x6f, 0x61, 0x76, 0x34, 0x42, 0x67, 0x2b, 0x32, 0x74, 0x66, 0x4b, 0x70, 0x61, + 0x52, 0x41, 0x33, 0x57, 0x64, 0x0a, 0x42, 0x65, 0x53, 0x2f, 0x37, 0x4d, 0x45, 0x6e, 0x36, 0x65, + 0x72, 0x37, 0x73, 0x43, 0x64, 0x2b, 0x42, 0x35, 0x2b, 0x4d, 0x79, 0x4b, 0x78, 0x46, 0x4f, 0x66, + 0x75, 0x52, 0x74, 0x5a, 0x70, 0x6c, 0x71, 0x35, 0x41, 0x42, 0x4c, 0x69, 0x37, 0x53, 0x35, 0x64, + 0x76, 0x6d, 0x6e, 0x79, 0x48, 0x37, 0x51, 0x2f, 0x76, 0x4b, 0x53, 0x51, 0x53, 0x75, 0x39, 0x34, + 0x66, 0x66, 0x52, 0x78, 0x61, 0x4c, 0x0a, 0x56, 0x69, 0x63, 0x6e, 0x6f, 0x6f, 0x4a, 0x4d, 0x38, + 0x44, 0x6e, 0x47, 0x6c, 0x70, 0x43, 0x75, 0x35, 0x35, 0x61, 0x50, 0x46, 0x56, 0x6e, 0x54, 0x46, + 0x6a, 0x37, 0x30, 0x43, 0x47, 0x61, 0x50, 0x72, 0x61, 0x4b, 0x72, 0x69, 0x6a, 0x62, 0x68, 0x35, + 0x4e, 0x4a, 0x51, 0x43, 0x7a, 0x6c, 0x62, 0x31, 0x2f, 0x65, 0x52, 0x48, 0x31, 0x6c, 0x4d, 0x55, + 0x6b, 0x31, 0x57, 0x37, 0x6d, 0x41, 0x68, 0x0a, 0x75, 0x39, 0x33, 0x44, 0x2b, 0x79, 0x2f, 0x65, + 0x72, 0x46, 0x4f, 0x75, 0x2f, 0x6a, 0x58, 0x73, 0x44, 0x6e, 0x69, 0x34, 0x4a, 0x4c, 0x68, 0x72, + 0x4d, 0x65, 0x34, 0x45, 0x7a, 0x6d, 0x78, 0x75, 0x2b, 0x6c, 0x7a, 0x6b, 0x6b, 0x58, 0x43, 0x68, + 0x36, 0x39, 0x36, 0x58, 0x6a, 0x59, 0x49, 0x45, 0x62, 0x41, 0x42, 0x6f, 0x66, 0x62, 0x45, 0x4c, + 0x30, 0x74, 0x46, 0x56, 0x50, 0x6e, 0x68, 0x37, 0x0a, 0x51, 0x55, 0x42, 0x37, 0x65, 0x59, 0x4a, + 0x63, 0x67, 0x6b, 0x61, 0x42, 0x6e, 0x39, 0x64, 0x6b, 0x31, 0x38, 0x61, 0x73, 0x6f, 0x78, 0x73, + 0x54, 0x41, 0x51, 0x73, 0x30, 0x6b, 0x41, 0x61, 0x52, 0x71, 0x79, 0x70, 0x73, 0x63, 0x4a, 0x46, + 0x44, 0x56, 0x6d, 0x67, 0x74, 0x45, 0x78, 0x53, 0x4e, 0x54, 0x72, 0x4a, 0x78, 0x50, 0x62, 0x7a, + 0x52, 0x33, 0x6d, 0x72, 0x2f, 0x69, 0x6f, 0x64, 0x6d, 0x0a, 0x5a, 0x7a, 0x57, 0x37, 0x54, 0x39, + 0x59, 0x33, 0x4f, 0x4e, 0x45, 0x31, 0x67, 0x79, 0x74, 0x38, 0x75, 0x51, 0x53, 0x44, 0x58, 0x62, + 0x4d, 0x6c, 0x6b, 0x71, 0x6d, 0x55, 0x76, 0x49, 0x61, 0x6f, 0x42, 0x4d, 0x79, 0x43, 0x4c, 0x56, + 0x31, 0x31, 0x6a, 0x44, 0x66, 0x6a, 0x6b, 0x51, 0x47, 0x78, 0x41, 0x53, 0x77, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +/* Contains the application certificate */ +#define INTERMEDIATE_CRL_PEM_LENGTH 1121 +UA_Byte INTERMEDIATE_CRL_PEM_DATA[1121] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, + 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x45, 0x6a, 0x43, + 0x42, 0x2b, 0x77, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x75, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52, 0x54, 0x45, + 0x4f, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x41, 0x77, 0x46, 0x55, 0x33, + 0x52, 0x68, 0x64, 0x47, 0x55, 0x78, 0x44, 0x54, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x63, 0x4d, 0x42, 0x45, 0x4e, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x39, 0x79, 0x5a, 0x32, 0x46, 0x75, 0x61, 0x58, + 0x70, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x51, 0x0a, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x48, 0x54, 0x33, 0x4a, 0x6e, 0x56, 0x57, 0x35, 0x70, 0x64, + 0x44, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x4f, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x58, 0x4a, 0x74, 0x5a, 0x57, 0x52, 0x70, 0x59, 0x58, 0x52, 0x6c, 0x51, + 0x30, 0x45, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, 0x44, 0x6b, 0x78, 0x0a, 0x4d, 0x54, 0x45, 0x30, + 0x4d, 0x44, 0x49, 0x7a, 0x4d, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, 0x54, 0x41, 0x78, + 0x4d, 0x54, 0x45, 0x30, 0x4d, 0x44, 0x49, 0x7a, 0x4d, 0x6c, 0x6f, 0x77, 0x4a, 0x7a, 0x41, 0x6c, + 0x41, 0x68, 0x51, 0x49, 0x69, 0x49, 0x59, 0x35, 0x35, 0x39, 0x4e, 0x34, 0x73, 0x6f, 0x6d, 0x6b, + 0x2b, 0x49, 0x76, 0x32, 0x63, 0x51, 0x44, 0x44, 0x64, 0x6e, 0x67, 0x4d, 0x0a, 0x6f, 0x52, 0x63, + 0x4e, 0x4d, 0x6a, 0x51, 0x77, 0x4f, 0x54, 0x45, 0x78, 0x4d, 0x54, 0x51, 0x77, 0x4d, 0x6a, 0x49, + 0x32, 0x57, 0x71, 0x41, 0x77, 0x4d, 0x43, 0x34, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x5a, 0x62, 0x77, 0x74, 0x6c, 0x47, 0x74, + 0x64, 0x6e, 0x65, 0x47, 0x45, 0x4e, 0x54, 0x6b, 0x4d, 0x76, 0x74, 0x67, 0x72, 0x0a, 0x79, 0x35, + 0x79, 0x78, 0x71, 0x77, 0x41, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x55, 0x42, 0x41, + 0x51, 0x43, 0x41, 0x68, 0x41, 0x46, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, 0x51, + 0x41, 0x73, 0x6b, 0x45, 0x4f, 0x65, 0x36, 0x4d, 0x56, 0x36, 0x62, 0x54, 0x79, 0x6c, 0x0a, 0x41, + 0x56, 0x50, 0x48, 0x71, 0x47, 0x55, 0x69, 0x42, 0x64, 0x41, 0x53, 0x76, 0x75, 0x68, 0x33, 0x6e, + 0x6a, 0x68, 0x48, 0x4f, 0x6d, 0x5a, 0x42, 0x43, 0x32, 0x31, 0x77, 0x34, 0x51, 0x71, 0x73, 0x7a, + 0x43, 0x32, 0x48, 0x65, 0x38, 0x33, 0x4d, 0x58, 0x66, 0x63, 0x41, 0x7a, 0x4b, 0x6b, 0x51, 0x55, + 0x61, 0x6d, 0x4c, 0x5a, 0x45, 0x76, 0x43, 0x4d, 0x32, 0x2f, 0x77, 0x4e, 0x74, 0x58, 0x6c, 0x0a, + 0x59, 0x55, 0x67, 0x79, 0x66, 0x53, 0x70, 0x52, 0x4e, 0x6b, 0x70, 0x56, 0x6e, 0x6a, 0x4a, 0x66, + 0x35, 0x4f, 0x6d, 0x6a, 0x50, 0x75, 0x53, 0x75, 0x46, 0x76, 0x39, 0x69, 0x64, 0x78, 0x46, 0x68, + 0x34, 0x66, 0x44, 0x35, 0x37, 0x71, 0x41, 0x38, 0x2f, 0x51, 0x70, 0x4f, 0x31, 0x61, 0x61, 0x44, + 0x65, 0x71, 0x4d, 0x41, 0x74, 0x47, 0x37, 0x72, 0x53, 0x77, 0x4a, 0x69, 0x2b, 0x67, 0x7a, 0x69, + 0x0a, 0x36, 0x35, 0x38, 0x36, 0x6d, 0x73, 0x33, 0x58, 0x72, 0x72, 0x7a, 0x51, 0x2b, 0x33, 0x69, + 0x54, 0x69, 0x50, 0x52, 0x49, 0x44, 0x45, 0x4b, 0x71, 0x2b, 0x72, 0x69, 0x69, 0x2b, 0x52, 0x4b, + 0x68, 0x41, 0x4b, 0x64, 0x79, 0x57, 0x63, 0x2f, 0x79, 0x6f, 0x4a, 0x6c, 0x4b, 0x75, 0x30, 0x2f, + 0x6f, 0x42, 0x6b, 0x73, 0x63, 0x77, 0x67, 0x65, 0x58, 0x42, 0x61, 0x52, 0x33, 0x4c, 0x4f, 0x6b, + 0x5a, 0x0a, 0x53, 0x6b, 0x2b, 0x73, 0x76, 0x70, 0x4a, 0x6f, 0x32, 0x36, 0x75, 0x59, 0x4d, 0x45, + 0x52, 0x36, 0x43, 0x31, 0x70, 0x37, 0x42, 0x48, 0x79, 0x43, 0x78, 0x62, 0x59, 0x4c, 0x4a, 0x30, + 0x58, 0x61, 0x4d, 0x46, 0x51, 0x54, 0x54, 0x57, 0x76, 0x37, 0x37, 0x34, 0x6f, 0x33, 0x63, 0x4a, + 0x42, 0x53, 0x45, 0x58, 0x79, 0x74, 0x2b, 0x58, 0x78, 0x52, 0x69, 0x75, 0x6e, 0x6c, 0x43, 0x49, + 0x42, 0x31, 0x0a, 0x75, 0x46, 0x77, 0x36, 0x43, 0x44, 0x44, 0x2f, 0x57, 0x63, 0x76, 0x72, 0x43, + 0x76, 0x59, 0x55, 0x77, 0x71, 0x63, 0x43, 0x77, 0x31, 0x2b, 0x53, 0x47, 0x66, 0x46, 0x2b, 0x68, + 0x51, 0x74, 0x6f, 0x77, 0x4d, 0x33, 0x6a, 0x4c, 0x73, 0x33, 0x71, 0x50, 0x57, 0x59, 0x61, 0x2b, + 0x66, 0x67, 0x69, 0x58, 0x33, 0x71, 0x70, 0x38, 0x72, 0x53, 0x77, 0x65, 0x39, 0x32, 0x69, 0x5a, + 0x76, 0x44, 0x4e, 0x0a, 0x7a, 0x4e, 0x72, 0x6f, 0x34, 0x64, 0x5a, 0x4a, 0x46, 0x42, 0x59, 0x65, + 0x61, 0x55, 0x70, 0x30, 0x46, 0x48, 0x6c, 0x6e, 0x71, 0x56, 0x2b, 0x46, 0x6c, 0x72, 0x77, 0x32, + 0x5a, 0x6c, 0x38, 0x41, 0x48, 0x53, 0x4e, 0x33, 0x69, 0x75, 0x70, 0x53, 0x33, 0x74, 0x74, 0x2b, + 0x39, 0x56, 0x31, 0x76, 0x63, 0x75, 0x45, 0x34, 0x2b, 0x70, 0x78, 0x64, 0x68, 0x73, 0x32, 0x44, + 0x4c, 0x78, 0x38, 0x46, 0x0a, 0x78, 0x6d, 0x6d, 0x39, 0x41, 0x67, 0x66, 0x50, 0x32, 0x49, 0x71, + 0x33, 0x62, 0x47, 0x4c, 0x4a, 0x69, 0x42, 0x32, 0x76, 0x39, 0x74, 0x4d, 0x76, 0x70, 0x63, 0x32, + 0x63, 0x4e, 0x61, 0x45, 0x58, 0x33, 0x4b, 0x34, 0x4a, 0x48, 0x4f, 0x48, 0x78, 0x38, 0x6a, 0x6b, + 0x65, 0x34, 0x6b, 0x6f, 0x66, 0x66, 0x4f, 0x44, 0x70, 0x77, 0x36, 0x70, 0x48, 0x71, 0x71, 0x61, + 0x64, 0x73, 0x47, 0x54, 0x63, 0x0a, 0x6d, 0x55, 0x56, 0x75, 0x4f, 0x45, 0x66, 0x35, 0x47, 0x72, + 0x70, 0x77, 0x37, 0x67, 0x54, 0x68, 0x70, 0x41, 0x52, 0x2b, 0x38, 0x37, 0x32, 0x45, 0x66, 0x41, + 0x43, 0x58, 0x72, 0x4a, 0x6f, 0x33, 0x63, 0x73, 0x45, 0x2b, 0x48, 0x74, 0x49, 0x2b, 0x50, 0x69, + 0x4b, 0x48, 0x58, 0x37, 0x6f, 0x38, 0x47, 0x75, 0x61, 0x49, 0x63, 0x56, 0x6d, 0x77, 0x42, 0x74, + 0x59, 0x33, 0x35, 0x52, 0x75, 0x44, 0x0a, 0x4e, 0x56, 0x6f, 0x34, 0x58, 0x36, 0x36, 0x49, 0x52, + 0x47, 0x6d, 0x65, 0x38, 0x4a, 0x56, 0x58, 0x64, 0x50, 0x4c, 0x35, 0x6b, 0x76, 0x6b, 0x78, 0x6e, + 0x63, 0x4f, 0x72, 0x73, 0x77, 0x30, 0x42, 0x75, 0x61, 0x48, 0x61, 0x63, 0x76, 0x41, 0x58, 0x6f, + 0x2b, 0x79, 0x42, 0x49, 0x66, 0x4e, 0x78, 0x6b, 0x54, 0x37, 0x67, 0x35, 0x78, 0x69, 0x46, 0x74, + 0x58, 0x49, 0x41, 0x70, 0x36, 0x74, 0x72, 0x0a, 0x36, 0x63, 0x36, 0x52, 0x30, 0x6e, 0x78, 0x70, + 0x63, 0x7a, 0x77, 0x6c, 0x68, 0x43, 0x55, 0x39, 0x34, 0x37, 0x4c, 0x48, 0x34, 0x62, 0x51, 0x74, + 0x66, 0x33, 0x6e, 0x51, 0x6f, 0x30, 0x4e, 0x6e, 0x6e, 0x39, 0x73, 0x74, 0x44, 0x39, 0x38, 0x67, + 0x31, 0x33, 0x6e, 0x63, 0x54, 0x59, 0x59, 0x73, 0x73, 0x32, 0x73, 0x78, 0x35, 0x64, 0x61, 0x5a, + 0x75, 0x56, 0x53, 0x45, 0x79, 0x57, 0x64, 0x72, 0x0a, 0x4e, 0x6a, 0x66, 0x7a, 0x56, 0x33, 0x5a, + 0x49, 0x4d, 0x77, 0x4a, 0x4f, 0x2f, 0x2b, 0x39, 0x6f, 0x67, 0x4e, 0x51, 0x45, 0x37, 0x42, 0x69, + 0x75, 0x35, 0x78, 0x2f, 0x55, 0x62, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a +}; + +#define INTERMEDIATE_EMPTY_CRL_PEM_LENGTH 1064 +UA_Byte INTERMEDIATE_EMPTY_CRL_PEM_DATA[1064] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, + 0x43, 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x36, 0x54, 0x43, + 0x42, 0x30, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x75, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52, 0x54, 0x45, + 0x4f, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x41, 0x77, 0x46, 0x55, 0x33, + 0x52, 0x68, 0x64, 0x47, 0x55, 0x78, 0x44, 0x54, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x63, 0x4d, 0x42, 0x45, 0x4e, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x39, 0x79, 0x5a, 0x32, 0x46, 0x75, 0x61, 0x58, + 0x70, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x51, 0x0a, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x48, 0x54, 0x33, 0x4a, 0x6e, 0x56, 0x57, 0x35, 0x70, 0x64, + 0x44, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x4f, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x58, 0x4a, 0x74, 0x5a, 0x57, 0x52, 0x70, 0x59, 0x58, 0x52, 0x6c, 0x51, + 0x30, 0x45, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, 0x44, 0x6b, 0x78, 0x0a, 0x4d, 0x54, 0x45, 0x79, + 0x4d, 0x44, 0x51, 0x77, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, 0x54, 0x41, 0x78, + 0x4d, 0x54, 0x45, 0x79, 0x4d, 0x44, 0x51, 0x77, 0x4e, 0x6c, 0x71, 0x67, 0x4d, 0x44, 0x41, 0x75, + 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, + 0x46, 0x47, 0x57, 0x38, 0x4c, 0x5a, 0x52, 0x72, 0x58, 0x5a, 0x33, 0x68, 0x0a, 0x68, 0x44, 0x55, + 0x35, 0x44, 0x4c, 0x37, 0x59, 0x4b, 0x38, 0x75, 0x63, 0x73, 0x61, 0x73, 0x41, 0x4d, 0x41, 0x73, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x46, 0x41, 0x51, 0x45, 0x41, 0x67, 0x49, 0x51, 0x41, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x64, 0x2b, 0x45, 0x39, 0x0a, 0x65, 0x56, + 0x4b, 0x44, 0x58, 0x4a, 0x6b, 0x62, 0x4c, 0x6b, 0x61, 0x65, 0x35, 0x41, 0x42, 0x70, 0x36, 0x4d, + 0x79, 0x4e, 0x44, 0x43, 0x6d, 0x54, 0x75, 0x39, 0x44, 0x6b, 0x2f, 0x56, 0x75, 0x4b, 0x72, 0x56, + 0x79, 0x78, 0x4e, 0x39, 0x69, 0x4c, 0x36, 0x52, 0x34, 0x69, 0x62, 0x41, 0x79, 0x52, 0x6a, 0x43, + 0x2b, 0x7a, 0x57, 0x6e, 0x42, 0x39, 0x6b, 0x66, 0x54, 0x73, 0x4b, 0x36, 0x77, 0x77, 0x0a, 0x6c, + 0x6a, 0x4b, 0x74, 0x31, 0x30, 0x75, 0x67, 0x47, 0x62, 0x67, 0x76, 0x33, 0x37, 0x72, 0x57, 0x57, + 0x78, 0x49, 0x45, 0x71, 0x57, 0x72, 0x68, 0x69, 0x35, 0x50, 0x58, 0x4d, 0x76, 0x63, 0x6b, 0x49, + 0x62, 0x59, 0x47, 0x35, 0x63, 0x77, 0x5a, 0x59, 0x7a, 0x61, 0x2f, 0x4f, 0x6b, 0x36, 0x2b, 0x66, + 0x34, 0x31, 0x61, 0x2b, 0x76, 0x51, 0x4d, 0x43, 0x48, 0x4a, 0x4a, 0x72, 0x6a, 0x44, 0x58, 0x0a, + 0x32, 0x41, 0x79, 0x6e, 0x6d, 0x45, 0x2b, 0x6b, 0x45, 0x72, 0x59, 0x52, 0x32, 0x54, 0x6d, 0x61, + 0x74, 0x4c, 0x7a, 0x49, 0x72, 0x62, 0x4f, 0x4f, 0x32, 0x66, 0x56, 0x61, 0x46, 0x36, 0x6d, 0x2f, + 0x61, 0x6f, 0x6b, 0x33, 0x2b, 0x70, 0x54, 0x64, 0x2f, 0x39, 0x4b, 0x7a, 0x61, 0x68, 0x52, 0x48, + 0x4f, 0x34, 0x4e, 0x55, 0x34, 0x78, 0x6b, 0x58, 0x38, 0x4a, 0x74, 0x5a, 0x69, 0x30, 0x4b, 0x54, + 0x0a, 0x68, 0x56, 0x6e, 0x44, 0x2f, 0x6a, 0x6a, 0x51, 0x36, 0x62, 0x54, 0x33, 0x58, 0x6a, 0x35, + 0x4a, 0x53, 0x45, 0x38, 0x6f, 0x35, 0x72, 0x59, 0x71, 0x4a, 0x2f, 0x74, 0x4c, 0x55, 0x47, 0x2b, + 0x4d, 0x4d, 0x39, 0x4e, 0x31, 0x4c, 0x75, 0x32, 0x6a, 0x4f, 0x57, 0x6e, 0x6d, 0x4e, 0x78, 0x55, + 0x44, 0x72, 0x4b, 0x70, 0x56, 0x6b, 0x6c, 0x59, 0x76, 0x37, 0x59, 0x6e, 0x52, 0x61, 0x33, 0x41, + 0x64, 0x0a, 0x5a, 0x4d, 0x2b, 0x7a, 0x75, 0x34, 0x35, 0x56, 0x4e, 0x69, 0x76, 0x4b, 0x4f, 0x30, + 0x79, 0x59, 0x33, 0x7a, 0x35, 0x74, 0x73, 0x4a, 0x74, 0x48, 0x48, 0x34, 0x36, 0x4a, 0x69, 0x46, + 0x49, 0x79, 0x54, 0x68, 0x43, 0x67, 0x35, 0x42, 0x6c, 0x68, 0x70, 0x47, 0x51, 0x6a, 0x54, 0x41, + 0x73, 0x72, 0x68, 0x64, 0x49, 0x61, 0x47, 0x4d, 0x50, 0x64, 0x39, 0x49, 0x6d, 0x58, 0x73, 0x44, + 0x65, 0x2f, 0x0a, 0x4c, 0x35, 0x51, 0x79, 0x58, 0x41, 0x4f, 0x58, 0x62, 0x4e, 0x31, 0x33, 0x74, + 0x39, 0x64, 0x74, 0x72, 0x72, 0x76, 0x76, 0x70, 0x6b, 0x38, 0x48, 0x34, 0x5a, 0x48, 0x43, 0x73, + 0x61, 0x4f, 0x39, 0x53, 0x36, 0x36, 0x43, 0x43, 0x67, 0x4a, 0x7a, 0x59, 0x47, 0x55, 0x47, 0x34, + 0x75, 0x54, 0x35, 0x79, 0x61, 0x54, 0x61, 0x75, 0x54, 0x34, 0x50, 0x67, 0x77, 0x6b, 0x2f, 0x78, + 0x68, 0x32, 0x55, 0x0a, 0x74, 0x59, 0x52, 0x72, 0x4f, 0x39, 0x2b, 0x72, 0x51, 0x50, 0x4d, 0x62, + 0x4d, 0x45, 0x79, 0x33, 0x52, 0x74, 0x45, 0x67, 0x44, 0x79, 0x4c, 0x59, 0x70, 0x38, 0x6b, 0x69, + 0x6d, 0x44, 0x77, 0x71, 0x5a, 0x6d, 0x31, 0x45, 0x53, 0x72, 0x4a, 0x6e, 0x51, 0x6b, 0x7a, 0x71, + 0x76, 0x64, 0x78, 0x74, 0x46, 0x5a, 0x64, 0x54, 0x4b, 0x7a, 0x62, 0x32, 0x2b, 0x2b, 0x46, 0x6c, + 0x79, 0x5a, 0x45, 0x73, 0x0a, 0x56, 0x6d, 0x51, 0x73, 0x78, 0x70, 0x75, 0x4d, 0x4c, 0x67, 0x6a, + 0x73, 0x57, 0x35, 0x30, 0x49, 0x39, 0x2b, 0x46, 0x2f, 0x63, 0x68, 0x6a, 0x48, 0x37, 0x64, 0x77, + 0x65, 0x77, 0x37, 0x36, 0x39, 0x72, 0x50, 0x4c, 0x44, 0x62, 0x45, 0x79, 0x36, 0x4d, 0x6f, 0x74, + 0x4c, 0x62, 0x72, 0x67, 0x48, 0x69, 0x61, 0x66, 0x67, 0x44, 0x54, 0x61, 0x37, 0x6a, 0x76, 0x52, + 0x46, 0x55, 0x36, 0x54, 0x56, 0x0a, 0x78, 0x2f, 0x77, 0x68, 0x61, 0x6e, 0x50, 0x2f, 0x7a, 0x59, + 0x34, 0x65, 0x49, 0x4c, 0x72, 0x4f, 0x62, 0x43, 0x7a, 0x31, 0x4e, 0x50, 0x4c, 0x52, 0x6f, 0x35, + 0x70, 0x54, 0x6c, 0x6d, 0x49, 0x7a, 0x58, 0x36, 0x4d, 0x2f, 0x37, 0x79, 0x51, 0x45, 0x79, 0x34, + 0x34, 0x6a, 0x2f, 0x4a, 0x39, 0x53, 0x35, 0x62, 0x4d, 0x6a, 0x4e, 0x67, 0x2b, 0x75, 0x36, 0x72, + 0x43, 0x30, 0x54, 0x77, 0x53, 0x55, 0x0a, 0x6b, 0x64, 0x41, 0x68, 0x68, 0x64, 0x61, 0x48, 0x4e, + 0x75, 0x52, 0x4d, 0x35, 0x6a, 0x4f, 0x68, 0x6a, 0x57, 0x35, 0x4d, 0x46, 0x63, 0x71, 0x56, 0x36, + 0x4e, 0x35, 0x4d, 0x46, 0x6e, 0x34, 0x38, 0x69, 0x79, 0x52, 0x4b, 0x46, 0x54, 0x50, 0x78, 0x37, + 0x54, 0x4b, 0x68, 0x46, 0x38, 0x34, 0x6d, 0x64, 0x53, 0x2b, 0x56, 0x39, 0x2b, 0x43, 0x47, 0x52, + 0x51, 0x53, 0x65, 0x46, 0x70, 0x70, 0x38, 0x0a, 0x4a, 0x6e, 0x69, 0x49, 0x73, 0x6a, 0x71, 0x50, + 0x59, 0x6a, 0x68, 0x6e, 0x34, 0x6f, 0x74, 0x38, 0x52, 0x37, 0x6b, 0x64, 0x68, 0x79, 0x74, 0x38, + 0x31, 0x69, 0x31, 0x56, 0x53, 0x6e, 0x78, 0x33, 0x73, 0x70, 0x74, 0x33, 0x7a, 0x77, 0x30, 0x3d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x58, 0x35, 0x30, 0x39, 0x20, 0x43, + 0x52, 0x4c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +#define APPLICATION_KEY_DER_LENGTH 1704 +UA_Byte APPLICATION_KEY_DER_DATA[1704] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, + 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, + 0x76, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x53, 0x43, 0x42, 0x4b, 0x67, 0x77, + 0x67, 0x67, 0x53, 0x6b, 0x41, 0x67, 0x45, 0x41, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44, 0x55, + 0x55, 0x6a, 0x55, 0x6c, 0x68, 0x39, 0x46, 0x73, 0x6f, 0x70, 0x49, 0x6d, 0x0a, 0x50, 0x4b, 0x5a, + 0x44, 0x59, 0x66, 0x46, 0x75, 0x76, 0x2f, 0x58, 0x70, 0x46, 0x68, 0x58, 0x55, 0x36, 0x63, 0x4f, + 0x74, 0x4f, 0x30, 0x6e, 0x75, 0x65, 0x79, 0x4d, 0x4b, 0x65, 0x5a, 0x4a, 0x39, 0x66, 0x50, 0x78, + 0x4b, 0x36, 0x52, 0x62, 0x4e, 0x49, 0x52, 0x65, 0x7a, 0x6e, 0x79, 0x78, 0x61, 0x44, 0x2b, 0x44, + 0x2f, 0x4d, 0x6c, 0x72, 0x46, 0x44, 0x54, 0x73, 0x7a, 0x44, 0x66, 0x71, 0x4b, 0x0a, 0x4c, 0x61, + 0x50, 0x70, 0x4d, 0x42, 0x49, 0x52, 0x44, 0x48, 0x76, 0x32, 0x51, 0x52, 0x68, 0x59, 0x73, 0x52, + 0x49, 0x57, 0x30, 0x61, 0x69, 0x46, 0x70, 0x66, 0x70, 0x38, 0x38, 0x30, 0x68, 0x53, 0x74, 0x42, + 0x41, 0x69, 0x52, 0x2f, 0x43, 0x59, 0x4f, 0x73, 0x37, 0x6e, 0x34, 0x34, 0x5a, 0x66, 0x73, 0x50, + 0x6f, 0x75, 0x75, 0x4f, 0x34, 0x66, 0x79, 0x33, 0x6a, 0x5a, 0x6f, 0x37, 0x79, 0x75, 0x0a, 0x35, + 0x6e, 0x65, 0x4c, 0x4f, 0x47, 0x46, 0x32, 0x72, 0x75, 0x73, 0x72, 0x7a, 0x75, 0x42, 0x35, 0x62, + 0x45, 0x6f, 0x71, 0x44, 0x58, 0x6c, 0x67, 0x62, 0x7a, 0x35, 0x74, 0x31, 0x49, 0x4f, 0x54, 0x58, + 0x49, 0x4d, 0x62, 0x62, 0x52, 0x52, 0x41, 0x4f, 0x39, 0x63, 0x52, 0x54, 0x50, 0x48, 0x75, 0x72, + 0x4c, 0x67, 0x53, 0x73, 0x45, 0x63, 0x37, 0x6e, 0x58, 0x6e, 0x35, 0x79, 0x43, 0x59, 0x37, 0x0a, + 0x68, 0x54, 0x2f, 0x34, 0x6c, 0x2f, 0x50, 0x61, 0x7a, 0x65, 0x70, 0x68, 0x70, 0x4e, 0x77, 0x6b, + 0x33, 0x44, 0x72, 0x31, 0x4d, 0x4b, 0x53, 0x4a, 0x70, 0x32, 0x42, 0x59, 0x69, 0x34, 0x73, 0x45, + 0x7a, 0x6a, 0x77, 0x4b, 0x69, 0x44, 0x4f, 0x41, 0x4b, 0x65, 0x67, 0x58, 0x6a, 0x52, 0x6f, 0x4d, + 0x6a, 0x79, 0x42, 0x64, 0x61, 0x6b, 0x56, 0x63, 0x67, 0x62, 0x35, 0x35, 0x6d, 0x77, 0x64, 0x7a, + 0x0a, 0x48, 0x30, 0x65, 0x36, 0x78, 0x64, 0x70, 0x64, 0x71, 0x45, 0x79, 0x49, 0x42, 0x6b, 0x4f, + 0x48, 0x39, 0x65, 0x51, 0x67, 0x32, 0x32, 0x73, 0x2b, 0x75, 0x68, 0x70, 0x39, 0x38, 0x56, 0x71, + 0x46, 0x41, 0x35, 0x7a, 0x6b, 0x52, 0x61, 0x32, 0x73, 0x74, 0x74, 0x35, 0x58, 0x36, 0x62, 0x76, + 0x53, 0x37, 0x4d, 0x62, 0x33, 0x47, 0x31, 0x42, 0x54, 0x66, 0x47, 0x4e, 0x4f, 0x7a, 0x4f, 0x5a, + 0x55, 0x0a, 0x42, 0x6f, 0x56, 0x4a, 0x2f, 0x30, 0x74, 0x50, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, + 0x45, 0x43, 0x67, 0x67, 0x45, 0x41, 0x55, 0x52, 0x4e, 0x52, 0x4d, 0x78, 0x4d, 0x68, 0x62, 0x39, + 0x50, 0x47, 0x62, 0x69, 0x35, 0x7a, 0x71, 0x4d, 0x42, 0x69, 0x51, 0x70, 0x47, 0x76, 0x74, 0x41, + 0x46, 0x59, 0x64, 0x64, 0x53, 0x4d, 0x41, 0x58, 0x37, 0x6c, 0x31, 0x4e, 0x69, 0x56, 0x67, 0x56, + 0x37, 0x36, 0x0a, 0x42, 0x73, 0x77, 0x75, 0x78, 0x4f, 0x59, 0x72, 0x37, 0x45, 0x6d, 0x71, 0x4e, + 0x4d, 0x39, 0x66, 0x7a, 0x73, 0x5a, 0x49, 0x65, 0x76, 0x70, 0x39, 0x2b, 0x63, 0x66, 0x37, 0x4a, + 0x70, 0x77, 0x38, 0x59, 0x76, 0x35, 0x5a, 0x6e, 0x47, 0x5a, 0x63, 0x52, 0x38, 0x46, 0x57, 0x4a, + 0x71, 0x73, 0x6c, 0x77, 0x6c, 0x78, 0x66, 0x56, 0x58, 0x4a, 0x61, 0x34, 0x53, 0x6f, 0x48, 0x74, + 0x43, 0x58, 0x73, 0x0a, 0x4a, 0x4a, 0x53, 0x59, 0x6f, 0x70, 0x61, 0x49, 0x38, 0x34, 0x42, 0x6c, + 0x57, 0x4e, 0x77, 0x6a, 0x69, 0x43, 0x2f, 0x61, 0x34, 0x50, 0x4f, 0x43, 0x44, 0x6f, 0x63, 0x53, + 0x6a, 0x7a, 0x7a, 0x38, 0x68, 0x47, 0x63, 0x43, 0x47, 0x42, 0x6e, 0x2f, 0x38, 0x61, 0x4f, 0x4b, + 0x72, 0x74, 0x42, 0x52, 0x48, 0x46, 0x79, 0x7a, 0x46, 0x30, 0x72, 0x4d, 0x34, 0x66, 0x75, 0x6f, + 0x77, 0x61, 0x51, 0x57, 0x0a, 0x47, 0x71, 0x42, 0x77, 0x36, 0x43, 0x46, 0x41, 0x4a, 0x6a, 0x46, + 0x33, 0x64, 0x4e, 0x2f, 0x61, 0x4d, 0x66, 0x7a, 0x71, 0x35, 0x37, 0x42, 0x32, 0x67, 0x69, 0x67, + 0x49, 0x32, 0x36, 0x41, 0x4b, 0x39, 0x70, 0x62, 0x32, 0x5a, 0x4c, 0x74, 0x4f, 0x45, 0x59, 0x49, + 0x52, 0x2b, 0x46, 0x51, 0x56, 0x4b, 0x33, 0x57, 0x6f, 0x36, 0x75, 0x66, 0x2f, 0x48, 0x67, 0x59, + 0x4a, 0x47, 0x38, 0x2b, 0x75, 0x0a, 0x43, 0x33, 0x2f, 0x67, 0x70, 0x4d, 0x5a, 0x49, 0x58, 0x6a, + 0x67, 0x6b, 0x66, 0x30, 0x78, 0x74, 0x32, 0x41, 0x37, 0x39, 0x2f, 0x54, 0x74, 0x30, 0x37, 0x69, + 0x39, 0x62, 0x73, 0x5a, 0x4b, 0x54, 0x6a, 0x67, 0x78, 0x76, 0x2b, 0x73, 0x41, 0x70, 0x32, 0x69, + 0x79, 0x74, 0x6a, 0x6f, 0x6e, 0x34, 0x65, 0x74, 0x41, 0x4d, 0x49, 0x49, 0x49, 0x70, 0x58, 0x36, + 0x4c, 0x46, 0x75, 0x68, 0x6f, 0x68, 0x0a, 0x52, 0x54, 0x76, 0x6e, 0x45, 0x57, 0x2f, 0x4f, 0x5a, + 0x37, 0x4a, 0x70, 0x44, 0x32, 0x53, 0x35, 0x77, 0x50, 0x37, 0x4d, 0x54, 0x36, 0x48, 0x4c, 0x2b, + 0x72, 0x35, 0x50, 0x6c, 0x64, 0x52, 0x47, 0x39, 0x35, 0x63, 0x61, 0x39, 0x55, 0x47, 0x5a, 0x69, + 0x51, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x65, 0x72, 0x77, 0x66, 0x59, 0x63, 0x72, 0x37, 0x30, 0x75, + 0x51, 0x59, 0x55, 0x4d, 0x74, 0x32, 0x53, 0x0a, 0x66, 0x51, 0x54, 0x46, 0x31, 0x77, 0x39, 0x68, + 0x36, 0x66, 0x36, 0x75, 0x6d, 0x41, 0x77, 0x31, 0x45, 0x51, 0x31, 0x52, 0x42, 0x35, 0x71, 0x38, + 0x6b, 0x6a, 0x6d, 0x61, 0x41, 0x59, 0x62, 0x2b, 0x32, 0x2b, 0x75, 0x69, 0x59, 0x70, 0x4c, 0x53, + 0x4b, 0x64, 0x56, 0x67, 0x4a, 0x66, 0x44, 0x38, 0x67, 0x37, 0x49, 0x39, 0x32, 0x64, 0x76, 0x4f, + 0x78, 0x5a, 0x39, 0x66, 0x59, 0x6a, 0x73, 0x59, 0x0a, 0x6a, 0x56, 0x4a, 0x33, 0x6e, 0x68, 0x59, + 0x42, 0x44, 0x79, 0x6a, 0x73, 0x6c, 0x2b, 0x71, 0x2b, 0x73, 0x78, 0x68, 0x56, 0x48, 0x61, 0x37, + 0x44, 0x2f, 0x61, 0x44, 0x31, 0x66, 0x47, 0x4f, 0x48, 0x4a, 0x2b, 0x79, 0x4c, 0x44, 0x79, 0x75, + 0x49, 0x49, 0x41, 0x47, 0x4d, 0x79, 0x51, 0x31, 0x47, 0x51, 0x36, 0x30, 0x37, 0x48, 0x47, 0x30, + 0x56, 0x38, 0x61, 0x50, 0x69, 0x49, 0x34, 0x59, 0x47, 0x0a, 0x48, 0x37, 0x6b, 0x49, 0x49, 0x6b, + 0x31, 0x77, 0x37, 0x39, 0x52, 0x74, 0x46, 0x71, 0x67, 0x39, 0x6b, 0x48, 0x34, 0x68, 0x30, 0x4e, + 0x77, 0x48, 0x46, 0x77, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x30, 0x46, 0x6b, 0x66, 0x2f, 0x4f, 0x64, + 0x74, 0x48, 0x57, 0x6a, 0x6c, 0x72, 0x2f, 0x76, 0x54, 0x77, 0x68, 0x73, 0x4e, 0x36, 0x37, 0x66, + 0x54, 0x74, 0x2f, 0x4c, 0x62, 0x6d, 0x65, 0x53, 0x41, 0x45, 0x0a, 0x57, 0x5a, 0x39, 0x58, 0x79, + 0x74, 0x79, 0x4c, 0x64, 0x5a, 0x76, 0x46, 0x67, 0x2b, 0x64, 0x39, 0x4f, 0x55, 0x65, 0x31, 0x42, + 0x54, 0x31, 0x61, 0x41, 0x31, 0x56, 0x50, 0x72, 0x59, 0x65, 0x4c, 0x35, 0x69, 0x6d, 0x30, 0x52, + 0x6c, 0x78, 0x67, 0x57, 0x47, 0x53, 0x36, 0x65, 0x78, 0x67, 0x71, 0x6d, 0x73, 0x71, 0x2b, 0x41, + 0x79, 0x6c, 0x32, 0x38, 0x6f, 0x41, 0x57, 0x56, 0x2f, 0x73, 0x46, 0x0a, 0x4a, 0x45, 0x47, 0x71, + 0x52, 0x66, 0x6c, 0x48, 0x41, 0x32, 0x4f, 0x77, 0x72, 0x31, 0x62, 0x53, 0x63, 0x55, 0x6e, 0x55, + 0x6f, 0x76, 0x57, 0x54, 0x79, 0x72, 0x4c, 0x70, 0x30, 0x4a, 0x31, 0x52, 0x51, 0x57, 0x6d, 0x52, + 0x7a, 0x4d, 0x53, 0x4d, 0x71, 0x74, 0x34, 0x48, 0x65, 0x58, 0x6f, 0x67, 0x57, 0x4a, 0x6b, 0x73, + 0x62, 0x6e, 0x6f, 0x4c, 0x6d, 0x49, 0x39, 0x35, 0x56, 0x64, 0x69, 0x64, 0x0a, 0x58, 0x70, 0x4a, + 0x43, 0x64, 0x57, 0x79, 0x41, 0x69, 0x51, 0x4b, 0x42, 0x67, 0x46, 0x68, 0x4b, 0x37, 0x41, 0x42, + 0x74, 0x56, 0x72, 0x74, 0x76, 0x6c, 0x54, 0x4a, 0x7a, 0x44, 0x4a, 0x6c, 0x6c, 0x69, 0x6e, 0x76, + 0x72, 0x44, 0x6f, 0x56, 0x54, 0x49, 0x78, 0x45, 0x55, 0x35, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x69, + 0x51, 0x4c, 0x46, 0x45, 0x79, 0x5a, 0x54, 0x5a, 0x6a, 0x2f, 0x71, 0x4f, 0x55, 0x0a, 0x6a, 0x54, + 0x52, 0x41, 0x67, 0x31, 0x68, 0x6a, 0x44, 0x2b, 0x42, 0x6b, 0x69, 0x73, 0x32, 0x45, 0x5a, 0x69, + 0x72, 0x52, 0x38, 0x36, 0x35, 0x6a, 0x65, 0x78, 0x4a, 0x31, 0x76, 0x31, 0x71, 0x33, 0x78, 0x67, + 0x66, 0x35, 0x6e, 0x56, 0x33, 0x6b, 0x4a, 0x65, 0x54, 0x52, 0x51, 0x31, 0x6c, 0x44, 0x5a, 0x35, + 0x56, 0x77, 0x42, 0x48, 0x68, 0x66, 0x57, 0x75, 0x2b, 0x61, 0x31, 0x31, 0x65, 0x69, 0x0a, 0x67, + 0x38, 0x36, 0x4c, 0x51, 0x45, 0x5a, 0x6a, 0x38, 0x6c, 0x6c, 0x67, 0x36, 0x69, 0x74, 0x2b, 0x37, + 0x2f, 0x4f, 0x74, 0x44, 0x4b, 0x2b, 0x54, 0x74, 0x4e, 0x67, 0x59, 0x48, 0x36, 0x37, 0x54, 0x36, + 0x79, 0x69, 0x48, 0x65, 0x55, 0x38, 0x62, 0x4f, 0x49, 0x33, 0x63, 0x57, 0x75, 0x36, 0x32, 0x47, + 0x4e, 0x7a, 0x4e, 0x6c, 0x45, 0x41, 0x58, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4d, 0x42, 0x58, 0x0a, + 0x43, 0x6e, 0x62, 0x78, 0x5a, 0x58, 0x7a, 0x4e, 0x65, 0x54, 0x42, 0x44, 0x34, 0x55, 0x6e, 0x6b, + 0x4f, 0x41, 0x67, 0x58, 0x6d, 0x51, 0x6b, 0x73, 0x4f, 0x67, 0x68, 0x56, 0x62, 0x45, 0x68, 0x68, + 0x51, 0x7a, 0x49, 0x51, 0x4e, 0x6b, 0x68, 0x69, 0x37, 0x64, 0x50, 0x77, 0x42, 0x43, 0x74, 0x6d, + 0x52, 0x72, 0x34, 0x37, 0x6d, 0x63, 0x50, 0x6a, 0x6d, 0x6f, 0x64, 0x46, 0x36, 0x2b, 0x6a, 0x75, + 0x0a, 0x2f, 0x76, 0x41, 0x43, 0x2f, 0x65, 0x6f, 0x68, 0x33, 0x59, 0x59, 0x68, 0x56, 0x38, 0x4c, + 0x43, 0x35, 0x58, 0x35, 0x6a, 0x79, 0x58, 0x6e, 0x6b, 0x7a, 0x39, 0x42, 0x4c, 0x6c, 0x67, 0x2f, + 0x51, 0x4b, 0x54, 0x70, 0x2f, 0x46, 0x31, 0x62, 0x42, 0x4d, 0x66, 0x35, 0x5a, 0x76, 0x4f, 0x58, + 0x70, 0x78, 0x63, 0x38, 0x63, 0x64, 0x72, 0x33, 0x32, 0x58, 0x5a, 0x50, 0x6f, 0x41, 0x76, 0x2b, + 0x7a, 0x0a, 0x74, 0x76, 0x66, 0x67, 0x54, 0x77, 0x57, 0x31, 0x34, 0x32, 0x34, 0x71, 0x61, 0x48, + 0x55, 0x79, 0x75, 0x38, 0x6b, 0x4b, 0x61, 0x58, 0x76, 0x58, 0x78, 0x54, 0x39, 0x4d, 0x79, 0x58, + 0x77, 0x41, 0x75, 0x4f, 0x70, 0x4c, 0x30, 0x36, 0x74, 0x5a, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4e, + 0x75, 0x61, 0x68, 0x64, 0x65, 0x75, 0x61, 0x51, 0x6d, 0x6d, 0x6f, 0x6f, 0x51, 0x72, 0x70, 0x38, + 0x52, 0x45, 0x0a, 0x46, 0x6a, 0x63, 0x53, 0x6e, 0x7a, 0x64, 0x43, 0x41, 0x64, 0x50, 0x37, 0x79, + 0x74, 0x63, 0x58, 0x71, 0x77, 0x51, 0x62, 0x4c, 0x53, 0x64, 0x76, 0x48, 0x54, 0x73, 0x54, 0x57, + 0x71, 0x64, 0x6b, 0x67, 0x34, 0x55, 0x70, 0x51, 0x5a, 0x4c, 0x4d, 0x4f, 0x61, 0x37, 0x32, 0x4b, + 0x6b, 0x2b, 0x47, 0x42, 0x77, 0x67, 0x45, 0x2f, 0x6c, 0x39, 0x4f, 0x6f, 0x61, 0x32, 0x37, 0x65, + 0x69, 0x79, 0x45, 0x0a, 0x38, 0x4f, 0x75, 0x43, 0x65, 0x55, 0x41, 0x32, 0x37, 0x57, 0x6b, 0x55, + 0x54, 0x31, 0x31, 0x6f, 0x7a, 0x58, 0x65, 0x43, 0x72, 0x61, 0x55, 0x71, 0x4f, 0x55, 0x43, 0x4e, + 0x6e, 0x33, 0x37, 0x4a, 0x46, 0x30, 0x43, 0x31, 0x77, 0x51, 0x63, 0x4d, 0x7a, 0x76, 0x65, 0x69, + 0x69, 0x79, 0x45, 0x58, 0x33, 0x61, 0x67, 0x64, 0x51, 0x6f, 0x57, 0x67, 0x34, 0x55, 0x52, 0x67, + 0x37, 0x36, 0x79, 0x4d, 0x0a, 0x30, 0x48, 0x2f, 0x48, 0x45, 0x77, 0x73, 0x33, 0x46, 0x45, 0x56, + 0x55, 0x55, 0x35, 0x6a, 0x6f, 0x43, 0x69, 0x79, 0x51, 0x2f, 0x65, 0x65, 0x30, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, + 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a +}; + +#define APPLICATION_CERT_DER_LENGTH 1732 +UA_Byte APPLICATION_CERT_DER_DATA[1732] = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, + 0x30, 0x6a, 0x43, 0x43, 0x41, 0x72, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, + 0x43, 0x49, 0x69, 0x47, 0x4f, 0x65, 0x66, 0x54, 0x65, 0x4c, 0x4b, 0x4a, 0x70, 0x50, 0x69, 0x4c, + 0x39, 0x6e, 0x45, 0x41, 0x77, 0x33, 0x5a, 0x34, 0x44, 0x4b, 0x45, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, + 0x77, 0x62, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x52, 0x45, 0x55, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, + 0x4d, 0x42, 0x56, 0x4e, 0x30, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x52, 0x44, 0x61, 0x58, 0x52, 0x35, 0x0a, 0x4d, 0x52, + 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x78, 0x50, 0x63, 0x6d, + 0x64, 0x68, 0x62, 0x6d, 0x6c, 0x36, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x45, 0x44, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x42, 0x30, 0x39, 0x79, 0x5a, 0x31, + 0x56, 0x75, 0x61, 0x58, 0x51, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, + 0x41, 0x4d, 0x4d, 0x44, 0x6b, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x79, 0x62, 0x57, 0x56, 0x6b, 0x61, + 0x57, 0x46, 0x30, 0x5a, 0x55, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, + 0x44, 0x6b, 0x78, 0x4d, 0x54, 0x45, 0x30, 0x4d, 0x44, 0x41, 0x31, 0x4e, 0x46, 0x6f, 0x58, 0x44, + 0x54, 0x4d, 0x30, 0x4d, 0x44, 0x6b, 0x77, 0x4f, 0x54, 0x45, 0x30, 0x4d, 0x44, 0x41, 0x31, 0x0a, + 0x4e, 0x46, 0x6f, 0x77, 0x61, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x52, 0x45, 0x55, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x67, 0x4d, 0x42, 0x56, 0x4e, 0x30, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x51, 0x30, 0x77, + 0x43, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x52, 0x44, 0x61, 0x58, 0x52, 0x35, + 0x0a, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x78, + 0x50, 0x63, 0x6d, 0x64, 0x68, 0x62, 0x6d, 0x6c, 0x36, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, + 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x42, 0x30, 0x39, + 0x79, 0x5a, 0x31, 0x56, 0x75, 0x61, 0x58, 0x51, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, + 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x4d, 0x43, 0x30, 0x46, 0x77, 0x63, 0x47, 0x78, 0x70, 0x59, 0x32, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, + 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, + 0x45, 0x41, 0x0a, 0x31, 0x46, 0x49, 0x31, 0x4a, 0x59, 0x66, 0x52, 0x62, 0x4b, 0x4b, 0x53, 0x4a, + 0x6a, 0x79, 0x6d, 0x51, 0x32, 0x48, 0x78, 0x62, 0x72, 0x2f, 0x31, 0x36, 0x52, 0x59, 0x56, 0x31, + 0x4f, 0x6e, 0x44, 0x72, 0x54, 0x74, 0x4a, 0x37, 0x6e, 0x73, 0x6a, 0x43, 0x6e, 0x6d, 0x53, 0x66, + 0x58, 0x7a, 0x38, 0x53, 0x75, 0x6b, 0x57, 0x7a, 0x53, 0x45, 0x58, 0x73, 0x35, 0x38, 0x73, 0x57, + 0x67, 0x2f, 0x67, 0x0a, 0x2f, 0x7a, 0x4a, 0x61, 0x78, 0x51, 0x30, 0x37, 0x4d, 0x77, 0x33, 0x36, + 0x69, 0x69, 0x32, 0x6a, 0x36, 0x54, 0x41, 0x53, 0x45, 0x51, 0x78, 0x37, 0x39, 0x6b, 0x45, 0x59, + 0x57, 0x4c, 0x45, 0x53, 0x46, 0x74, 0x47, 0x6f, 0x68, 0x61, 0x58, 0x36, 0x66, 0x50, 0x4e, 0x49, + 0x55, 0x72, 0x51, 0x51, 0x49, 0x6b, 0x66, 0x77, 0x6d, 0x44, 0x72, 0x4f, 0x35, 0x2b, 0x4f, 0x47, + 0x58, 0x37, 0x44, 0x36, 0x0a, 0x4c, 0x72, 0x6a, 0x75, 0x48, 0x38, 0x74, 0x34, 0x32, 0x61, 0x4f, + 0x38, 0x72, 0x75, 0x5a, 0x33, 0x69, 0x7a, 0x68, 0x68, 0x64, 0x71, 0x37, 0x72, 0x4b, 0x38, 0x37, + 0x67, 0x65, 0x57, 0x78, 0x4b, 0x4b, 0x67, 0x31, 0x35, 0x59, 0x47, 0x38, 0x2b, 0x62, 0x64, 0x53, + 0x44, 0x6b, 0x31, 0x79, 0x44, 0x47, 0x32, 0x30, 0x55, 0x51, 0x44, 0x76, 0x58, 0x45, 0x55, 0x7a, + 0x78, 0x37, 0x71, 0x79, 0x34, 0x0a, 0x45, 0x72, 0x42, 0x48, 0x4f, 0x35, 0x31, 0x35, 0x2b, 0x63, + 0x67, 0x6d, 0x4f, 0x34, 0x55, 0x2f, 0x2b, 0x4a, 0x66, 0x7a, 0x32, 0x73, 0x33, 0x71, 0x59, 0x61, + 0x54, 0x63, 0x4a, 0x4e, 0x77, 0x36, 0x39, 0x54, 0x43, 0x6b, 0x69, 0x61, 0x64, 0x67, 0x57, 0x49, + 0x75, 0x4c, 0x42, 0x4d, 0x34, 0x38, 0x43, 0x6f, 0x67, 0x7a, 0x67, 0x43, 0x6e, 0x6f, 0x46, 0x34, + 0x30, 0x61, 0x44, 0x49, 0x38, 0x67, 0x0a, 0x58, 0x57, 0x70, 0x46, 0x58, 0x49, 0x47, 0x2b, 0x65, + 0x5a, 0x73, 0x48, 0x63, 0x78, 0x39, 0x48, 0x75, 0x73, 0x58, 0x61, 0x58, 0x61, 0x68, 0x4d, 0x69, + 0x41, 0x5a, 0x44, 0x68, 0x2f, 0x58, 0x6b, 0x49, 0x4e, 0x74, 0x72, 0x50, 0x72, 0x6f, 0x61, 0x66, + 0x66, 0x46, 0x61, 0x68, 0x51, 0x4f, 0x63, 0x35, 0x45, 0x57, 0x74, 0x72, 0x4c, 0x62, 0x65, 0x56, + 0x2b, 0x6d, 0x37, 0x30, 0x75, 0x7a, 0x47, 0x0a, 0x39, 0x78, 0x74, 0x51, 0x55, 0x33, 0x78, 0x6a, + 0x54, 0x73, 0x7a, 0x6d, 0x56, 0x41, 0x61, 0x46, 0x53, 0x66, 0x39, 0x4c, 0x54, 0x77, 0x49, 0x44, + 0x41, 0x51, 0x41, 0x42, 0x6f, 0x32, 0x73, 0x77, 0x61, 0x54, 0x41, 0x6e, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x45, 0x45, 0x49, 0x44, 0x41, 0x65, 0x68, 0x68, 0x78, 0x31, 0x63, 0x6d, 0x34, 0x36, + 0x64, 0x57, 0x35, 0x6a, 0x62, 0x32, 0x35, 0x6d, 0x0a, 0x61, 0x57, 0x64, 0x31, 0x63, 0x6d, 0x56, + 0x6b, 0x4f, 0x6d, 0x46, 0x77, 0x63, 0x47, 0x78, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, + 0x75, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, + 0x4e, 0x74, 0x2f, 0x68, 0x36, 0x7a, 0x4f, 0x62, 0x54, 0x76, 0x46, 0x33, 0x7a, 0x67, 0x75, 0x65, + 0x5a, 0x75, 0x44, 0x75, 0x38, 0x51, 0x43, 0x4a, 0x30, 0x0a, 0x6f, 0x7a, 0x41, 0x66, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x52, 0x6c, 0x76, 0x43, + 0x32, 0x55, 0x61, 0x31, 0x32, 0x64, 0x34, 0x59, 0x51, 0x31, 0x4f, 0x51, 0x79, 0x2b, 0x32, 0x43, + 0x76, 0x4c, 0x6e, 0x4c, 0x47, 0x72, 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x0a, 0x41, 0x41, 0x4f, 0x43, 0x41, + 0x67, 0x45, 0x41, 0x72, 0x62, 0x55, 0x4c, 0x61, 0x54, 0x44, 0x46, 0x39, 0x69, 0x30, 0x70, 0x66, + 0x34, 0x7a, 0x6d, 0x62, 0x55, 0x53, 0x69, 0x64, 0x34, 0x6f, 0x57, 0x7a, 0x6e, 0x45, 0x42, 0x77, + 0x55, 0x5a, 0x69, 0x6e, 0x37, 0x59, 0x69, 0x54, 0x76, 0x67, 0x38, 0x73, 0x34, 0x41, 0x31, 0x43, + 0x42, 0x76, 0x2f, 0x31, 0x75, 0x72, 0x75, 0x41, 0x62, 0x39, 0x6d, 0x0a, 0x4a, 0x52, 0x52, 0x59, + 0x35, 0x37, 0x61, 0x32, 0x65, 0x6c, 0x7a, 0x68, 0x31, 0x37, 0x45, 0x76, 0x51, 0x39, 0x72, 0x30, + 0x4a, 0x48, 0x6e, 0x49, 0x66, 0x73, 0x35, 0x41, 0x56, 0x68, 0x57, 0x2f, 0x4e, 0x45, 0x62, 0x6e, + 0x75, 0x5a, 0x73, 0x39, 0x59, 0x6a, 0x53, 0x6c, 0x6a, 0x55, 0x58, 0x74, 0x44, 0x64, 0x47, 0x63, + 0x6b, 0x6f, 0x48, 0x61, 0x34, 0x53, 0x4d, 0x55, 0x44, 0x44, 0x2f, 0x44, 0x0a, 0x76, 0x78, 0x4e, + 0x46, 0x44, 0x31, 0x6f, 0x72, 0x67, 0x2b, 0x79, 0x39, 0x75, 0x2b, 0x2f, 0x6b, 0x64, 0x52, 0x4d, + 0x64, 0x67, 0x66, 0x6d, 0x5a, 0x45, 0x69, 0x32, 0x59, 0x55, 0x62, 0x57, 0x68, 0x51, 0x53, 0x37, + 0x78, 0x34, 0x34, 0x31, 0x57, 0x73, 0x52, 0x30, 0x33, 0x32, 0x66, 0x4d, 0x54, 0x42, 0x44, 0x2b, + 0x64, 0x6b, 0x33, 0x38, 0x77, 0x42, 0x31, 0x4e, 0x2b, 0x42, 0x6e, 0x56, 0x54, 0x0a, 0x54, 0x43, + 0x50, 0x4c, 0x68, 0x43, 0x74, 0x6c, 0x76, 0x6d, 0x54, 0x46, 0x68, 0x34, 0x47, 0x48, 0x38, 0x71, + 0x48, 0x79, 0x57, 0x79, 0x77, 0x47, 0x48, 0x6a, 0x76, 0x38, 0x6e, 0x45, 0x45, 0x65, 0x70, 0x47, + 0x72, 0x68, 0x49, 0x49, 0x56, 0x66, 0x7a, 0x53, 0x57, 0x38, 0x51, 0x66, 0x53, 0x66, 0x4b, 0x6c, + 0x6a, 0x4d, 0x30, 0x36, 0x62, 0x76, 0x71, 0x4d, 0x58, 0x31, 0x2f, 0x46, 0x6b, 0x70, 0x0a, 0x38, + 0x76, 0x48, 0x41, 0x4e, 0x53, 0x67, 0x54, 0x69, 0x57, 0x2f, 0x4b, 0x58, 0x59, 0x7a, 0x33, 0x36, + 0x67, 0x71, 0x59, 0x57, 0x70, 0x44, 0x2f, 0x32, 0x41, 0x74, 0x57, 0x35, 0x75, 0x44, 0x4e, 0x58, + 0x56, 0x62, 0x76, 0x70, 0x5a, 0x48, 0x4b, 0x57, 0x59, 0x76, 0x34, 0x30, 0x67, 0x63, 0x73, 0x2f, + 0x59, 0x6b, 0x37, 0x66, 0x6a, 0x33, 0x38, 0x44, 0x65, 0x76, 0x4b, 0x46, 0x57, 0x35, 0x49, 0x0a, + 0x65, 0x71, 0x6c, 0x43, 0x55, 0x59, 0x6f, 0x50, 0x30, 0x2f, 0x41, 0x37, 0x47, 0x77, 0x43, 0x45, + 0x63, 0x58, 0x4a, 0x2f, 0x6b, 0x4a, 0x70, 0x5a, 0x50, 0x30, 0x45, 0x6d, 0x45, 0x37, 0x41, 0x51, + 0x6a, 0x6c, 0x61, 0x46, 0x6e, 0x44, 0x41, 0x51, 0x54, 0x71, 0x50, 0x57, 0x57, 0x2f, 0x4b, 0x72, + 0x73, 0x68, 0x2f, 0x61, 0x42, 0x65, 0x39, 0x2b, 0x5a, 0x41, 0x54, 0x46, 0x71, 0x50, 0x4f, 0x72, + 0x0a, 0x38, 0x32, 0x43, 0x43, 0x6d, 0x63, 0x4f, 0x59, 0x73, 0x32, 0x45, 0x2f, 0x2f, 0x6d, 0x77, + 0x30, 0x76, 0x59, 0x6d, 0x4c, 0x78, 0x68, 0x38, 0x4f, 0x61, 0x50, 0x37, 0x30, 0x62, 0x63, 0x4f, + 0x65, 0x65, 0x37, 0x64, 0x67, 0x51, 0x66, 0x4c, 0x53, 0x77, 0x75, 0x68, 0x71, 0x51, 0x44, 0x79, + 0x61, 0x44, 0x57, 0x2b, 0x67, 0x77, 0x75, 0x61, 0x61, 0x2f, 0x79, 0x7a, 0x71, 0x6b, 0x63, 0x4f, + 0x6c, 0x0a, 0x6c, 0x44, 0x30, 0x2f, 0x73, 0x51, 0x6e, 0x59, 0x68, 0x6a, 0x50, 0x53, 0x72, 0x62, + 0x49, 0x33, 0x36, 0x41, 0x54, 0x4a, 0x2f, 0x73, 0x36, 0x34, 0x4f, 0x41, 0x6e, 0x6d, 0x74, 0x70, + 0x4a, 0x53, 0x6d, 0x68, 0x51, 0x50, 0x67, 0x4a, 0x59, 0x63, 0x5a, 0x6a, 0x65, 0x32, 0x49, 0x6c, + 0x48, 0x42, 0x36, 0x77, 0x34, 0x38, 0x4c, 0x5a, 0x48, 0x34, 0x57, 0x79, 0x57, 0x4e, 0x30, 0x61, + 0x52, 0x4b, 0x0a, 0x32, 0x36, 0x70, 0x43, 0x53, 0x67, 0x49, 0x6a, 0x58, 0x74, 0x64, 0x7a, 0x43, + 0x47, 0x71, 0x48, 0x57, 0x53, 0x6c, 0x72, 0x55, 0x57, 0x59, 0x70, 0x6c, 0x77, 0x71, 0x46, 0x73, + 0x59, 0x33, 0x77, 0x6b, 0x34, 0x35, 0x6c, 0x58, 0x66, 0x53, 0x32, 0x30, 0x62, 0x6c, 0x45, 0x4d, + 0x30, 0x47, 0x41, 0x55, 0x7a, 0x2f, 0x56, 0x58, 0x33, 0x78, 0x58, 0x35, 0x6d, 0x51, 0x69, 0x64, + 0x41, 0x65, 0x72, 0x0a, 0x4a, 0x67, 0x47, 0x68, 0x46, 0x5a, 0x68, 0x2f, 0x55, 0x73, 0x56, 0x50, + 0x37, 0x41, 0x66, 0x4c, 0x4c, 0x6e, 0x75, 0x4f, 0x57, 0x68, 0x70, 0x35, 0x4d, 0x67, 0x58, 0x70, + 0x6b, 0x38, 0x72, 0x7a, 0x38, 0x50, 0x31, 0x4e, 0x69, 0x50, 0x4a, 0x49, 0x38, 0x6d, 0x57, 0x6c, + 0x6f, 0x55, 0x61, 0x75, 0x34, 0x4d, 0x6c, 0x35, 0x2b, 0x70, 0x71, 0x5a, 0x66, 0x76, 0x39, 0x57, + 0x35, 0x68, 0x76, 0x74, 0x0a, 0x48, 0x4a, 0x79, 0x31, 0x41, 0x59, 0x32, 0x2b, 0x35, 0x58, 0x53, + 0x70, 0x58, 0x7a, 0x2f, 0x36, 0x71, 0x66, 0x61, 0x4a, 0x41, 0x4d, 0x67, 0x2b, 0x38, 0x78, 0x71, + 0x66, 0x32, 0x64, 0x67, 0x55, 0x74, 0x77, 0x5a, 0x72, 0x42, 0x55, 0x2b, 0x5a, 0x52, 0x6e, 0x79, + 0x47, 0x6e, 0x32, 0x33, 0x6a, 0x67, 0x35, 0x67, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a +}; + _UA_END_DECLS #endif /* CERTIFICATES_H_ */ diff --git a/tests/encryption/check_crl_validation.c b/tests/encryption/check_crl_validation.c new file mode 100644 index 00000000000..c9af7c63a71 --- /dev/null +++ b/tests/encryption/check_crl_validation.c @@ -0,0 +1,337 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf) + * + */ + +#include +#include +#include +#include +#include +#include + +#include "certificates.h" +#include "check.h" +#include "thread_wrapper.h" + +UA_Server *server; +UA_Boolean running; +THREAD_HANDLE server_thread; + +THREAD_CALLBACK(serverloop) { + while(running) + UA_Server_run_iterate(server, true); + return 0; +} + +static void setup1(void) { + running = true; + + /* Load certificate and private key */ + UA_ByteString certificate; + certificate.length = CERT_DER_LENGTH; + certificate.data = CERT_DER_DATA; + + UA_ByteString privateKey; + privateKey.length = KEY_DER_LENGTH; + privateKey.data = KEY_DER_DATA; + + UA_ByteString rootCa; + rootCa.length = ROOT_CERT_DER_LENGTH; + rootCa.data = ROOT_CERT_DER_DATA; + + UA_ByteString rootCaCrl; + rootCaCrl.length = ROOT_EMPTY_CRL_PEM_LENGTH; + rootCaCrl.data = ROOT_EMPTY_CRL_PEM_DATA; + + UA_ByteString intermediateCa; + intermediateCa.length = INTERMEDIATE_CERT_DER_LENGTH; + intermediateCa.data = INTERMEDIATE_CERT_DER_DATA; + + UA_ByteString intermediateCaCrl; + intermediateCaCrl.length = INTERMEDIATE_EMPTY_CRL_PEM_LENGTH; + intermediateCaCrl.data = INTERMEDIATE_EMPTY_CRL_PEM_DATA; + + /* Load the trustlist */ + size_t trustListSize = 2; + UA_STACKARRAY(UA_ByteString, trustList, trustListSize); + trustList[0] = intermediateCa; + trustList[1] = rootCa; + + /* Load the issuerList */ + size_t issuerListSize = 2; + UA_STACKARRAY(UA_ByteString, issuerList, issuerListSize); + issuerList[0] = intermediateCa; + issuerList[1] = rootCa; + + /* Loading of a revocation list currently unsupported */ + size_t revocationListSize = 2; + UA_STACKARRAY(UA_ByteString, revocationList, revocationListSize); + revocationList[0] = rootCaCrl; + revocationList[1] = intermediateCaCrl; + + server = UA_Server_new(); + ck_assert(server != NULL); + UA_ServerConfig *config = UA_Server_getConfig(server); + UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840, &certificate, &privateKey, + trustList, trustListSize, + issuerList, issuerListSize, + revocationList, revocationListSize); + + /* Set the ApplicationUri used in the certificate */ + UA_String_clear(&config->applicationDescription.applicationUri); + config->applicationDescription.applicationUri = + UA_STRING_ALLOC("urn:unconfigured:application"); + + UA_Server_run_startup(server); + THREAD_CREATE(server_thread, serverloop); +} + +static void setup2(void) { + running = true; + + /* Load certificate and private key */ + UA_ByteString certificate; + certificate.length = CERT_DER_LENGTH; + certificate.data = CERT_DER_DATA; + + UA_ByteString privateKey; + privateKey.length = KEY_DER_LENGTH; + privateKey.data = KEY_DER_DATA; + + UA_ByteString rootCa; + rootCa.length = ROOT_CERT_DER_LENGTH; + rootCa.data = ROOT_CERT_DER_DATA; + + UA_ByteString rootCaCrl; + rootCaCrl.length = ROOT_EMPTY_CRL_PEM_LENGTH; + rootCaCrl.data = ROOT_EMPTY_CRL_PEM_DATA; + + UA_ByteString intermediateCa; + intermediateCa.length = INTERMEDIATE_CERT_DER_LENGTH; + intermediateCa.data = INTERMEDIATE_CERT_DER_DATA; + + UA_ByteString intermediateCaCrl; + intermediateCaCrl.length = INTERMEDIATE_CRL_PEM_LENGTH; + intermediateCaCrl.data = INTERMEDIATE_CRL_PEM_DATA; + + /* Load the trustlist */ + size_t trustListSize = 2; + UA_STACKARRAY(UA_ByteString, trustList, trustListSize); + trustList[0] = intermediateCa; + trustList[1] = rootCa; + + /* Load the issuerList */ + size_t issuerListSize = 2; + UA_STACKARRAY(UA_ByteString, issuerList, issuerListSize); + issuerList[0] = intermediateCa; + issuerList[1] = rootCa; + + /* Loading of a revocation list currently unsupported */ + size_t revocationListSize = 2; + UA_STACKARRAY(UA_ByteString, revocationList, revocationListSize); + revocationList[0] = rootCaCrl; + revocationList[1] = intermediateCaCrl; + + server = UA_Server_new(); + ck_assert(server != NULL); + UA_ServerConfig *config = UA_Server_getConfig(server); + UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840, &certificate, &privateKey, + trustList, trustListSize, + issuerList, issuerListSize, + revocationList, revocationListSize); + + /* Set the ApplicationUri used in the certificate */ + UA_String_clear(&config->applicationDescription.applicationUri); + config->applicationDescription.applicationUri = + UA_STRING_ALLOC("urn:unconfigured:application"); + + UA_Server_run_startup(server); + THREAD_CREATE(server_thread, serverloop); +} + +static void setup3(void) { + running = true; + + /* Load certificate and private key */ + UA_ByteString certificate; + certificate.length = CERT_DER_LENGTH; + certificate.data = CERT_DER_DATA; + + UA_ByteString privateKey; + privateKey.length = KEY_DER_LENGTH; + privateKey.data = KEY_DER_DATA; + + UA_ByteString rootCa; + rootCa.length = ROOT_CERT_DER_LENGTH; + rootCa.data = ROOT_CERT_DER_DATA; + + UA_ByteString rootCaCrl; + rootCaCrl.length = ROOT_CRL_PEM_LENGTH; + rootCaCrl.data = ROOT_CRL_PEM_DATA; + + UA_ByteString intermediateCa; + intermediateCa.length = INTERMEDIATE_CERT_DER_LENGTH; + intermediateCa.data = INTERMEDIATE_CERT_DER_DATA; + + UA_ByteString intermediateCaCrl; + intermediateCaCrl.length = INTERMEDIATE_EMPTY_CRL_PEM_LENGTH; + intermediateCaCrl.data = INTERMEDIATE_EMPTY_CRL_PEM_DATA; + + /* Load the trustlist */ + size_t trustListSize = 2; + UA_STACKARRAY(UA_ByteString, trustList, trustListSize); + trustList[0] = intermediateCa; + trustList[1] = rootCa; + + /* Load the issuerList */ + size_t issuerListSize = 2; + UA_STACKARRAY(UA_ByteString, issuerList, issuerListSize); + issuerList[0] = rootCa; + issuerList[1] = intermediateCa; + + /* Loading of a revocation list currently unsupported */ + size_t revocationListSize = 2; + UA_STACKARRAY(UA_ByteString, revocationList, revocationListSize); + revocationList[0] = rootCaCrl; + revocationList[1] = intermediateCaCrl; + + server = UA_Server_new(); + ck_assert(server != NULL); + UA_ServerConfig *config = UA_Server_getConfig(server); + UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840, &certificate, &privateKey, + trustList, trustListSize, + issuerList, issuerListSize, + revocationList, revocationListSize); + + /* Set the ApplicationUri used in the certificate */ + UA_String_clear(&config->applicationDescription.applicationUri); + config->applicationDescription.applicationUri = + UA_STRING_ALLOC("urn:unconfigured:application"); + + UA_Server_run_startup(server); + THREAD_CREATE(server_thread, serverloop); +} + +static void teardown(void) { + running = false; + THREAD_JOIN(server_thread); + UA_Server_run_shutdown(server); + UA_Server_delete(server); +} + +START_TEST(encryption_connect_valid) { +/* Load certificate and private key */ + UA_ByteString certificate; + certificate.length = APPLICATION_CERT_DER_LENGTH; + certificate.data = APPLICATION_CERT_DER_DATA; + ck_assert_uint_ne(certificate.length, 0); + + UA_ByteString privateKey; + privateKey.length = APPLICATION_KEY_DER_LENGTH; + privateKey.data = APPLICATION_KEY_DER_DATA; + ck_assert_uint_ne(privateKey.length, 0); + + /* Load the trustlist */ + UA_ByteString *trustList = NULL; + size_t trustListSize = 0; + UA_ByteString *revocationList = NULL; + size_t revocationListSize = 0; + + /* Secure client initialization */ + UA_Client *client = UA_Client_new(); + UA_ClientConfig *cc = UA_Client_getConfig(client); + UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey, + trustList, trustListSize, + revocationList, revocationListSize); + cc->certificateVerification.clear(&cc->certificateVerification); + UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + cc->securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); + ck_assert(client != NULL); + + /* Secure client connect */ + UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); + ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); + + UA_Variant val; + UA_Variant_init(&val); + UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); + retval = UA_Client_readValueAttribute(client, nodeId, &val); + ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); + UA_Variant_clear(&val); + + UA_Client_disconnect(client); + UA_Client_delete(client); +} +END_TEST + +START_TEST(encryption_connect_revoked) { + UA_ByteString certificate; + certificate.length = APPLICATION_CERT_DER_LENGTH; + certificate.data = APPLICATION_CERT_DER_DATA; + ck_assert_uint_ne(certificate.length, 0); + + UA_ByteString privateKey; + privateKey.length = APPLICATION_KEY_DER_LENGTH; + privateKey.data = APPLICATION_KEY_DER_DATA; + ck_assert_uint_ne(privateKey.length, 0); + + /* Load the trustlist */ + UA_ByteString *trustList = NULL; + size_t trustListSize = 0; + UA_ByteString *revocationList = NULL; + size_t revocationListSize = 0; + + /* Secure client initialization */ + UA_Client *client = UA_Client_new(); + UA_ClientConfig *cc = UA_Client_getConfig(client); + UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey, + trustList, trustListSize, + revocationList, revocationListSize); + cc->certificateVerification.clear(&cc->certificateVerification); + UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + cc->securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); + ck_assert(client != NULL); + + /* Secure client connect */ + UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); + ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONCLOSED); + + UA_Client_disconnect(client); + UA_Client_delete(client); +} +END_TEST + +static Suite* testSuite_encryption(void) { + Suite *s = suite_create("Certificate Revocation List"); + TCase *tc_encryption_valid = tcase_create("Certificate Revocation Valid"); + tcase_add_checked_fixture(tc_encryption_valid, setup1, teardown); + TCase *tc_encryption_revoked = tcase_create("Certificate Revocation Revoked"); + tcase_add_checked_fixture(tc_encryption_revoked, setup2, teardown); + TCase *tc_encryption_revoked2 = tcase_create("Certificate Revocation Revoked2"); + tcase_add_checked_fixture(tc_encryption_revoked2, setup3, teardown); +#ifdef UA_ENABLE_ENCRYPTION + tcase_add_test(tc_encryption_valid, encryption_connect_valid); + tcase_add_test(tc_encryption_revoked, encryption_connect_revoked); + tcase_add_test(tc_encryption_revoked2, encryption_connect_revoked); +#endif /* UA_ENABLE_ENCRYPTION */ + suite_add_tcase(s,tc_encryption_valid); + suite_add_tcase(s,tc_encryption_revoked); + suite_add_tcase(s,tc_encryption_revoked2); + return s; +} + +int main(void) { + Suite *s = testSuite_encryption(); + SRunner *sr = srunner_create(s); + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr,CK_NORMAL); + int number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} From af1abb2e8355e238187a1e771059f26555466364 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 22 Sep 2024 22:03:39 +0200 Subject: [PATCH 39/98] refactor(plugins): Better cleanup of the OpenSSL CertificateVerification plugin --- plugins/crypto/openssl/ua_pki_openssl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 87b91e03c1e..c741efcf820 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -118,9 +118,7 @@ UA_CertificateVerification_clear (UA_CertificateVerification * cv) { UA_CertContext_sk_free (context); UA_free (context); - cv->context = NULL; - - return; + memset(cv, 0, sizeof(UA_CertificateVerification)); } static UA_StatusCode From ee79096b6570337543dcecfe9d0bcf4fb93234d4 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 22 Sep 2024 22:04:14 +0200 Subject: [PATCH 40/98] fix(plugin): Always clean up the previously configured certificate verification plugin --- plugins/ua_config_default.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/ua_config_default.c b/plugins/ua_config_default.c index c4c8f4ffec7..8ab5f547f28 100644 --- a/plugins/ua_config_default.c +++ b/plugins/ua_config_default.c @@ -184,6 +184,8 @@ setDefaultConfig(UA_ServerConfig *conf) { /* Certificate Verification that accepts every certificate. Can be * overwritten when the policy is specialized. */ + if(conf->certificateVerification.clear) + conf->certificateVerification.clear(&conf->certificateVerification); UA_CertificateVerification_AcceptAll(&conf->certificateVerification); /* * Global Node Lifecycle * */ @@ -685,6 +687,8 @@ UA_ServerConfig_setDefaultWithSecurityPolicies(UA_ServerConfig *conf, return retval; } + if(conf->certificateVerification.clear) + conf->certificateVerification.clear(&conf->certificateVerification); retval = UA_CertificateVerification_Trustlist(&conf->certificateVerification, trustList, trustListSize, issuerList, issuerListSize, @@ -758,6 +762,8 @@ UA_ClientConfig_setDefault(UA_ClientConfig *config) { /* Certificate Verification that accepts every certificate. Can be * overwritten when the policy is specialized. */ + if(config->certificateVerification.clear) + config->certificateVerification.clear(&config->certificateVerification); UA_CertificateVerification_AcceptAll(&config->certificateVerification); UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, "AcceptAll Certificate Verification. " @@ -816,6 +822,8 @@ UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config, if(retval != UA_STATUSCODE_GOOD) return retval; + if(config->certificateVerification.clear) + config->certificateVerification.clear(&config->certificateVerification); retval = UA_CertificateVerification_Trustlist(&config->certificateVerification, trustList, trustListSize, NULL, 0, From 19ecf3e5627ae1d0c20ce661aee8e0164b03d86c Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 22 Sep 2024 22:11:45 +0200 Subject: [PATCH 41/98] refactor(plugin): Manual OpenSSL certificate verification steps The previous certificate verification relied on many OpenSSL internals and a forest of feature-flags. The new code is about the same size and makes the certificate verification steps explicit. The only downside is that we no longer auto-retrieve revocation lists if a distribution point is defined in a CA certificate. But revocation is handled by a GDS in OPC UA. And we don't want our certificate verification to do synchronous HTTP calls in the background. --- plugins/crypto/openssl/ua_pki_openssl.c | 369 +++++++++++++----------- 1 file changed, 195 insertions(+), 174 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index c741efcf820..dbfc94e4bad 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -390,196 +390,217 @@ UA_ReloadCertFromFolder (CertContext * ctx) { #endif /* end of __linux__ */ -static UA_StatusCode -UA_X509_Store_CTX_Error_To_UAError (int opensslErr) { - UA_StatusCode ret; - - switch (opensslErr) { - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CRL_NOT_YET_VALID: - case X509_V_ERR_CRL_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: - case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: - ret = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; - break; - case X509_V_ERR_CERT_REVOKED: - ret = UA_STATUSCODE_BADCERTIFICATEREVOKED; - break; - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; - break; - case X509_V_ERR_CERT_SIGNATURE_FAILURE: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED; - break; - case X509_V_ERR_UNABLE_TO_GET_CRL: - ret = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; - break; - default: - ret = UA_STATUSCODE_BADCERTIFICATEINVALID; - break; - } - return ret; - } - -static UA_StatusCode -UA_CertificateVerification_Verify (void * verificationContext, - const UA_ByteString * certificate) { - X509_STORE_CTX* storeCtx; - X509_STORE* store; - CertContext * ctx; - UA_StatusCode ret; - int opensslRet; - X509 * certificateX509 = NULL; +static const unsigned char openssl_PEM_PRE[28] = "-----BEGIN CERTIFICATE-----"; + +/* Extract the leaf certificate from a bytestring that may contain an entire chain */ +static X509 * +openSSLLoadLeafCertificate(UA_ByteString cert, size_t *offset) { + if(cert.length <= *offset) + return NULL; + cert.length -= *offset; + cert.data += *offset; + + /* Detect DER encoding. Extract the encoding length and cut. */ + if(cert.length >= 4 && cert.data[0] == 0x30 && cert.data[1] == 0x82) { + /* The certificate length is encoded after the magic bytes */ + size_t certLen = 4; /* Magic numbers + length bytes */ + certLen += (size_t)(((uint16_t)cert.data[2]) << 8); + certLen += cert.data[3]; + if(certLen > cert.length) + return NULL; + cert.length = certLen; + *offset += certLen; + const UA_Byte *dataPtr = cert.data; + return d2i_X509(NULL, &dataPtr, (long)cert.length); + } + + /* Assume PEM encoding. Detect multiple certificates and cut. */ + if(cert.length > 27 * 4) { + const unsigned char *match = + UA_Bstrstr(openssl_PEM_PRE, 27, &cert.data[27*2], cert.length - (27*2)); + if(match) + cert.length = (uintptr_t)(match - cert.data); + } + *offset += cert.length; + + BIO *bio = BIO_new_mem_buf((void *) cert.data, (int)cert.length); + X509 *result = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + return result; +} - if (verificationContext == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - ctx = (CertContext *) verificationContext; - - store = X509_STORE_new(); - storeCtx = X509_STORE_CTX_new(); - - if (store == NULL || storeCtx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto cleanup; - } -#ifdef __linux__ - ret = UA_ReloadCertFromFolder (ctx); - if (ret != UA_STATUSCODE_GOOD) { - goto cleanup; - } -#endif +/* The bytestring might contain an entire certificate chain. The first + * stack-element is the leaf certificate itself. The remaining ones are + * potential issuer certificates. */ +static STACK_OF(X509) * +openSSLLoadCertificateStack(const UA_ByteString cert) { + size_t offset = 0; + X509 *x509 = NULL; + STACK_OF(X509) *result = sk_X509_new_null(); + if(!result) + return NULL; + while((x509 = openSSLLoadLeafCertificate(cert, &offset))) { + sk_X509_push(result, x509); + } + return result; +} - certificateX509 = UA_OpenSSL_LoadCertificate(certificate); - if (certificateX509 == NULL) { - ret = UA_STATUSCODE_BADCERTIFICATEINVALID; - goto cleanup; - } - - X509_STORE_set_flags(store, 0); - opensslRet = X509_STORE_CTX_init (storeCtx, store, certificateX509, - ctx->skIssue); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto cleanup; - } -#if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT < 0x10100000L - (void) X509_STORE_CTX_trusted_stack (storeCtx, ctx->skTrusted); -#else - (void) X509_STORE_CTX_set0_trusted_stack (storeCtx, ctx->skTrusted); -#endif +/* Return the first matching issuer candidate AFTER prev */ +static X509 * +openSSLFindNextIssuer(CertContext *ctx, STACK_OF(X509) *stack, X509 *x509, X509 *prev) { + /* First check issuers from the stack - provided in the same bytestring as + * the certificate. This can also return x509 itself. */ + do { + int size = sk_X509_num(stack); + for(int i = 0; i < size; i++) { + X509 *candidate = sk_X509_value(stack, i); + if(X509_check_issued(candidate, x509) != 0) + continue; + if(prev == NULL) + return candidate; + prev = NULL; + } + /* Switch to search in the ctx->skIssue list */ + stack = (stack != ctx->skIssue) ? ctx->skIssue : NULL; + } while(stack); + return NULL; +} - /* Set crls to ctx */ - if (sk_X509_CRL_num (ctx->skCrls) > 0) { - X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls); +static UA_Boolean +openSSLCheckRevoked(CertContext *ctx, X509 *cert) { + const ASN1_INTEGER *sn = X509_get0_serialNumber(cert); + const X509_NAME *in = X509_get_issuer_name(cert); + int size = sk_X509_CRL_num(ctx->skCrls); + for(int i = 0; i < size; i++) { + /* The crl contains a list of serial numbers from the same issuer */ + X509_CRL *crl = sk_X509_CRL_value(ctx->skCrls, i); + if(X509_NAME_cmp(in, X509_CRL_get_issuer(crl)) != 0) + continue; + STACK_OF(X509_REVOKED) *rs = X509_CRL_get_REVOKED(crl); + int rsize = sk_X509_REVOKED_num(rs); + for(int j = 0; j < rsize; j++) { + X509_REVOKED *r = sk_X509_REVOKED_value(rs, j); + if(ASN1_INTEGER_cmp(sn, X509_REVOKED_get0_serialNumber(r)) == 0) + return true; + } } + return false; +} - /* Set flag to check if the certificate has an invalid signature */ - X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CHECK_SS_SIGNATURE); - - if (X509_check_issued(certificateX509,certificateX509) != X509_V_OK) { - X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK); - } +#define UA_OPENSSL_MAX_CHAIN_LENGTH 10 - /* This condition will check whether the certificate is a User certificate or a CA certificate. - * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the certificate shall be - * condidered as CA Certificate and cannot be used to establish a connection. Refer the test case - * CTT/Security/Security Certificate Validation/029.js for more details */ - /** \todo Can the ca-parameter of X509_check_purpose can be used? */ - if(X509_check_purpose(certificateX509, X509_PURPOSE_CRL_SIGN, 0) && X509_check_ca(certificateX509)) { - return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; - } +static UA_StatusCode +openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, + X509 *x509, int depth) { + /* Maxiumum chain length */ + if(depth == UA_OPENSSL_MAX_CHAIN_LENGTH) + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + + /* Verification Step: Validity Period */ + ASN1_TIME *notBefore = X509_get_notBefore(x509); + ASN1_TIME *notAfter = X509_get_notAfter(x509); + if(X509_cmp_current_time(notBefore) != -1 || X509_cmp_current_time(notAfter) != 1) + return UA_STATUSCODE_BADCERTIFICATETIMEINVALID; + + /* Verification Step: Revocation Check */ + if(openSSLCheckRevoked(ctx, x509)) + return UA_STATUSCODE_BADCERTIFICATEREVOKED; + + /* Is the certificate in the trust list? If yes, then we are done. */ + for(int i = 0; i < sk_X509_num(ctx->skTrusted); i++) { + if(X509_cmp(x509, sk_X509_value(ctx->skTrusted, i)) == 0) + return UA_STATUSCODE_GOOD; + } + + /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is + * returned only if all possible chains are incomplete. */ + X509 *issuer = NULL; + UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + while(ret != UA_STATUSCODE_GOOD) { + /* Find the issuer. We jump back here to find a different path if a + * subsequent check fails. */ + issuer = openSSLFindNextIssuer(ctx, stack, x509, issuer); + if(!issuer) + break; - opensslRet = X509_verify_cert (storeCtx); - if (opensslRet == 1) { - ret = UA_STATUSCODE_GOOD; + /* Detect (endless) loops of issuers */ + for(int i = 0; i < depth; i++) { + if(old_issuers[i] == issuer) + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + } + old_issuers[depth] = issuer; + + /* Verification Step: Signature */ + int opensslRet = X509_verify(x509, X509_get0_pubkey(issuer)); + if(opensslRet == -1) { + return UA_STATUSCODE_BADCERTIFICATEINVALID; /* Ill-formed signature */ + } else if(opensslRet == 0) { + ret = UA_STATUSCODE_BADCERTIFICATEINVALID; /* Wrong issuer, try again */ + continue; + } - /* Check if the not trusted certificate has a CRL file. If there is no CRL file available for the corresponding - * parent certificate then return status code UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN. Refer the test - * case CTT/Security/Security Certificate Validation/002.js */ - if (X509_check_issued(certificateX509,certificateX509) != X509_V_OK) { - /* Free X509_STORE_CTX and reuse it for certification verification */ - if (storeCtx != NULL) { - X509_STORE_CTX_free(storeCtx); - } + /* We have found the issuer certificate used for the signature. Recurse + * to the next certificate in the chain (verify the current issuer). */ + ret = openSSL_verifyChain(ctx, stack, old_issuers, issuer, depth + 1); - /* Initialised X509_STORE_CTX sructure*/ - storeCtx = X509_STORE_CTX_new(); + /* Problems where x509 != leaf are reported as "untrusted" without the + * detailed reason */ + if(ret != UA_STATUSCODE_GOOD && + ret != UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE) + ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + } - /* Sets up X509_STORE_CTX structure for a subsequent verification operation */ - X509_STORE_set_flags(store, 0); - X509_STORE_CTX_init (storeCtx, store, certificateX509,ctx->skIssue); + return ret; +} - /* Set trust list to ctx */ - (void) X509_STORE_CTX_trusted_stack (storeCtx, ctx->skTrusted); +/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted. + * It defines a sequence of steps for certificate verification. */ +static UA_StatusCode +UA_CertificateVerification_Verify(void *verificationContext, + const UA_ByteString *certificate) { + if(!verificationContext || !certificate) + return UA_STATUSCODE_BADINTERNALERROR; - /* Set crls to ctx */ - X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls); + UA_StatusCode ret = UA_STATUSCODE_GOOD; + CertContext *ctx = (CertContext *)verificationContext; - /* Set flags for CRL check */ - X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); +#ifdef __linux__ + ret = UA_ReloadCertFromFolder(ctx); + if(ret != UA_STATUSCODE_GOOD) + return ret; +#endif - opensslRet = X509_verify_cert (storeCtx); - if (opensslRet != 1) { - opensslRet = X509_STORE_CTX_get_error (storeCtx); - if (opensslRet == X509_V_ERR_UNABLE_TO_GET_CRL) { - ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; - } else { - ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet); - } - } - } + /* Verification Step: Certificate Structure */ + STACK_OF(X509) *stack = openSSLLoadCertificateStack(*certificate); + if(!stack || sk_X509_num(stack) < 1) { + if(stack) + sk_X509_pop_free(stack, X509_free); + return UA_STATUSCODE_BADCERTIFICATEINVALID; + } + + /* Verification Step: Certificate Usage + * Check whether the certificate is a User certificate or a CA certificate. + * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the + * certificate shall be condidered as CA Certificate and cannot be used to + * establish a connection. Refer the test case CTT/Security/Security + * Certificate Validation/029.js for more details */ + X509 *leaf = sk_X509_value(stack, 0); + if(X509_check_purpose(leaf, X509_PURPOSE_CRL_SIGN, 0) && X509_check_ca(leaf)) { + sk_X509_pop_free(stack, X509_free); + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; } - else { - opensslRet = X509_STORE_CTX_get_error (storeCtx); - - /* Check the issued certificate of a CA that is not trusted but available */ - if(opensslRet == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN){ - int trusted_cert_len = sk_X509_num(ctx->skTrusted); - int cmpVal; - X509 *trusted_cert; - const ASN1_OCTET_STRING *trusted_cert_keyid; - const ASN1_OCTET_STRING *remote_cert_keyid; - - for (int i = 0; i < trusted_cert_len; i++) { - trusted_cert = sk_X509_value(ctx->skTrusted, i); - - /* Fetch the Subject key identifier of the certificate in trust list */ - trusted_cert_keyid = X509_get0_subject_key_id(trusted_cert); - - /* Fetch the Subject key identifier of the remote certificate */ - remote_cert_keyid = X509_get0_subject_key_id(certificateX509); - - if(trusted_cert_keyid && remote_cert_keyid) { - /* Check remote certificate is present in the trust list */ - cmpVal = ASN1_OCTET_STRING_cmp(trusted_cert_keyid, remote_cert_keyid); - if(cmpVal == 0) { - ret = UA_STATUSCODE_GOOD; - goto cleanup; - } - } - } - } - /* Return expected OPCUA error code */ - ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet); - } -cleanup: - if (store != NULL) { - X509_STORE_free (store); - } - if (storeCtx != NULL) { - X509_STORE_CTX_free (storeCtx); - } - if (certificateX509 != NULL) { - X509_free (certificateX509); - } + /* These steps are performed outside of this method. + * Because we need the server or client context. + * - Security Policy + * - Host Name + * - URI */ + + /* Verification Step: Build Certificate Chain + * We perform the checks for each certificate inside. */ + X509 *old_issuers[UA_OPENSSL_MAX_CHAIN_LENGTH]; + ret = openSSL_verifyChain(ctx, stack, old_issuers, leaf, 0); + sk_X509_pop_free(stack, X509_free); return ret; } From 01086d6de8091351dbc768b731e968976baa7e23 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 24 Sep 2024 20:46:26 +0200 Subject: [PATCH 42/98] refactor(plugins): Refactor mbedTLS certificate verification to include intermediate steps --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 410 +++++++++++------------- 1 file changed, 180 insertions(+), 230 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index b5cb09c6321..ac3bf38814e 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -3,7 +3,7 @@ * * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB * Copyright 2019 (c) Kalycito Infotech Private Limited - * Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2019, 2024 (c) Julius Pfrommer, Fraunhofer IOSB */ #include @@ -16,11 +16,7 @@ #include #include #include - -#define REMOTECERTIFICATETRUSTED 1 -#define ISSUERKNOWN 2 -#define DUALPARENT 3 -#define PARENTFOUND 4 +#include /* Find binary substring. Taken and adjusted from * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */ @@ -236,251 +232,204 @@ reloadCertificates(CertInfo *ci) { #endif -static UA_StatusCode -certificateVerification_verify(void *verificationContext, - const UA_ByteString *certificate) { - CertInfo *ci = (CertInfo*)verificationContext; - if(!ci) - return UA_STATUSCODE_BADINTERNALERROR; - -#ifdef __linux__ /* Reload certificates if folder paths are specified */ - UA_StatusCode certFlag = reloadCertificates(ci); - if(certFlag != UA_STATUSCODE_GOOD) { - return certFlag; - } +/* We need to access some private fields below */ +#ifndef MBEDTLS_PRIVATE +#define MBEDTLS_PRIVATE(x) x #endif - if(ci->trustListFolder.length == 0 && - ci->issuerListFolder.length == 0 && - ci->revocationListFolder.length == 0 && - ci->certificateTrustList.raw.len == 0 && - ci->certificateIssuerList.raw.len == 0 && - ci->certificateRevocationList.raw.len == 0) { - UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "PKI plugin unconfigured. Accepting the certificate."); - return UA_STATUSCODE_GOOD; - } - - /* Parse the certificate */ - mbedtls_x509_crt remoteCertificate; - - /* Temporary Object to parse the trustList */ - mbedtls_x509_crt *tempCert = NULL; - - /* Temporary Object to parse the revocationList */ - mbedtls_x509_crl *tempCrl = NULL; - - /* Temporary Object to identify the parent CA when there is no intermediate CA */ - mbedtls_x509_crt *parentCert = NULL; - - /* Temporary Object to identify the parent CA when there is intermediate CA */ - mbedtls_x509_crt *parentCert_2 = NULL; - - /* Flag value to identify if the issuer certificate is found */ - int issuerKnown = 0; - - /* Flag value to identify if the parent certificate found */ - int parentFound = 0; - - mbedtls_x509_crt_init(&remoteCertificate); - int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data, - certificate->length); - if(mbedErr) { - /* char errBuff[300]; */ - /* mbedtls_strerror(mbedErr, errBuff, 300); */ - /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */ - /* "Could not parse the remote certificate with error: %s", errBuff); */ - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - - /* Verify */ - mbedtls_x509_crt_profile crtProfile = { - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256), - 0xFFFFFF, 0x000000, 128 * 8 // in bits - }; // TODO: remove magic numbers - - uint32_t flags = 0; - mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, - &ci->certificateTrustList, - &ci->certificateRevocationList, - &crtProfile, NULL, &flags, NULL, NULL); - - /* Flag to check if the remote certificate is trusted or not */ - int TRUSTED = 0; - - /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */ - if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) { - for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) { - if(remoteCertificate.raw.len == tempCert->raw.len && - memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) { - TRUSTED = REMOTECERTIFICATETRUSTED; - break; - } +/* Return the first matching issuer candidate AFTER prev */ +static mbedtls_x509_crt * +mbedtlsFindNextIssuer(CertInfo *ci, mbedtls_x509_crt *stack, + mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) { + char inbuf[512], snbuf[512]; + if(mbedtls_x509_dn_gets(inbuf, 512, &cert->issuer) < 0) + return NULL; + do { + for(mbedtls_x509_crt *i = stack; i; i = i->next) { + /* Compare issuer name and subject name */ + if(mbedtls_x509_dn_gets(snbuf, 512, &i->subject) < 0) + continue; + if(strncmp(inbuf, snbuf, 512) != 0) + continue; + /* Skip when the key does not match the signature */ + if(!mbedtls_pk_can_do(&i->pk, cert->MBEDTLS_PRIVATE(sig_pk))) + continue; + if(prev == NULL) + return i; + prev = NULL; /* This was the last issuer we tried to verify */ } + /* Switch from the stack that came with the cert to the ctx->skIssue list */ + stack = (stack != &ci->certificateIssuerList) ? &ci->certificateIssuerList : NULL; + } while(stack); + return NULL; +} + +static UA_Boolean +mbedtlsCheckRevoked(CertInfo *ci, mbedtls_x509_crt *cert) { + char inbuf[512], inbuf2[512]; + if(mbedtls_x509_dn_gets(inbuf, 512, &cert->issuer) < 0) + return true; + for(mbedtls_x509_crl *crl = &ci->certificateRevocationList; crl; crl = crl->next) { + /* Is the CRL for the issuer of the certificate? */ + if(mbedtls_x509_dn_gets(inbuf2, 512, &crl->issuer) < 0) + return true; + if(strncmp(inbuf, inbuf2, 512) != 0) + continue; + /* Is the serial number of the certificate contained in the CRL? */ + if(mbedtls_x509_crt_is_revoked(cert, crl) != 0) + return true; } + return false; +} - /* If the remote certificate is present in the trustList then check if the issuer certificate - * of remoteCertificate is present in issuerList */ - if(TRUSTED && mbedErr) { - mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, - &ci->certificateIssuerList, - &ci->certificateRevocationList, - &crtProfile, NULL, &flags, NULL, NULL); - - /* Check if the parent certificate has a CRL file available */ - if(!mbedErr) { - /* Flag value to identify if that there is an intermediate CA present */ - int dualParent = 0; - - /* Identify the topmost parent certificate for the remoteCertificate */ - for(parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) { - if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) { - for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) { - if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) { - dualParent = DUALPARENT; - break; - } - } - parentFound = PARENTFOUND; - } - - if(parentFound == PARENTFOUND) - break; - } +/* Verify that the public key of the issuer was used to sign the certificate */ +static UA_Boolean +mbedtlsCheckSignature(const mbedtls_x509_crt *cert, mbedtls_x509_crt *issuer) { + size_t hash_len; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + mbedtls_md_type_t md = cert->MBEDTLS_PRIVATE(sig_md); +#if !defined(MBEDTLS_USE_PSA_CRYPTO) + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md); + hash_len = mbedtls_md_get_size(md_info); + if(mbedtls_md(md_info, cert->tbs.p, cert->tbs.len, hash) != 0) + return false; +#else + if(psa_hash_compute(mbedtls_md_psa_alg_from_type(md), cert->tbs.p, + cert->tbs.len, hash, sizeof(hash), &hash_len) != PSA_SUCCESS) + return false; +#endif + const mbedtls_x509_buf *sig = &cert->MBEDTLS_PRIVATE(sig); + void *sig_opts = cert->MBEDTLS_PRIVATE(sig_opts); + mbedtls_pk_type_t pktype = cert->MBEDTLS_PRIVATE(sig_pk); + return (mbedtls_pk_verify_ext(pktype, sig_opts, &issuer->pk, md, + hash, hash_len, sig->p, sig->len) == 0); +} - /* Check if there is an intermediate certificate between the topmost parent - * certificate and child certificate - * If yes the topmost parent certificate is to be checked whether it has a - * CRL file avaiable */ - if(dualParent == DUALPARENT && parentFound == PARENTFOUND) { - parentCert = parentCert_2; - } +#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10 - /* If a parent certificate is found traverse the revocationList and identify - * if there is any CRL file that corresponds to the parentCertificate */ - if(parentFound == PARENTFOUND) { - tempCrl = &ci->certificateRevocationList; - while(tempCrl != NULL) { - if(tempCrl->version != 0 && - tempCrl->issuer_raw.len == parentCert->subject_raw.len && - memcmp(tempCrl->issuer_raw.p, - parentCert->subject_raw.p, - tempCrl->issuer_raw.len) == 0) { - issuerKnown = ISSUERKNOWN; - break; - } - - tempCrl = tempCrl->next; - } - - /* If the CRL file corresponding to the parent certificate is not present - * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */ - if(issuerKnown) { - flags = 0; - mbedErr = mbedtls_x509_crt_verify_with_profile(parentCert, - &ci->certificateIssuerList, - &ci->certificateRevocationList, - &crtProfile, NULL, &flags, NULL, NULL); - } else { - return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; - } +static UA_StatusCode +mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old_issuers, + mbedtls_x509_crt *cert, int depth) { + /* Maxiumum chain length */ + if(depth == UA_MBEDTLS_MAX_CHAIN_LENGTH) + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + + /* Verification Step: Validity Period */ + if(mbedtls_x509_time_is_future(&cert->valid_from) || + mbedtls_x509_time_is_past(&cert->valid_to)) + return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID : + UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID; + + /* Verification Step: Revocation Check */ + if(mbedtlsCheckRevoked(ci, cert)) + return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATEREVOKED : + UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED; + + /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is + * returned only if all possible chains are incomplete. */ + mbedtls_x509_crt *issuer = NULL; + UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + while(ret != UA_STATUSCODE_GOOD) { + /* Find the issuer. This can return the same certificate if it is + * self-signed (subject == issuer). We come back here to try a different + * "path" if a subsequent verification fails. */ + issuer = mbedtlsFindNextIssuer(ci, stack, cert, issuer); + if(!issuer) + break; + + /* Verification Step: Signature */ + if(!mbedtlsCheckSignature(cert, issuer)) { + ret = UA_STATUSCODE_BADCERTIFICATEINVALID; /* Wrong issuer, try again */ + continue; + } - } + /* The certificate is self-signed. We have arrived at the top of the + * chain. We check whether the certificate is trusted below. This is the + * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. + * This sinals that the chain is complete (but can be still + * untrusted). */ + if(issuer == cert || (cert->tbs.len == issuer->tbs.len && + memcmp(cert->tbs.p, issuer->tbs.p, cert->tbs.len) == 0)) { + ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + continue; + } + /* Detect (endless) loops of issuers. The last one can be skipped by the + * check for self-signed just before. */ + for(int i = 0; i < depth - 1; i++) { + if(old_issuers[i] == issuer) + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; } + old_issuers[depth] = issuer; + /* We have found the issuer certificate used for the signature. Recurse + * to the next certificate in the chain (verify the current issuer). */ + ret = mbedtlsVerifyChain(ci, stack, old_issuers, issuer, depth + 1); } - else if(!mbedErr && !TRUSTED) { - /* This else if section is to identify if the parent certificate which is present in trustList - * has CRL file corresponding to it */ - - /* Identify the parent certificate of the remoteCertificate */ - for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) { - if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) { - parentFound = PARENTFOUND; - break; - } + /* The chain is complete, but we haven't yet identified a trusted + * certificate "on the way down". Can we trust this certificate? */ + if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) { + for(mbedtls_x509_crt *t = &ci->certificateTrustList; t; t = t->next) { + if(cert->tbs.len == t->tbs.len && + memcmp(cert->tbs.p, t->tbs.p, cert->tbs.len) == 0) + return UA_STATUSCODE_GOOD; } + } - /* If the parent certificate is found traverse the revocationList and identify - * if there is any CRL file that corresponds to the parentCertificate */ - if(parentFound == PARENTFOUND && - memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) { - tempCrl = &ci->certificateRevocationList; - while(tempCrl != NULL) { - if(tempCrl->version != 0 && - tempCrl->issuer_raw.len == parentCert->subject_raw.len && - memcmp(tempCrl->issuer_raw.p, - parentCert->subject_raw.p, - tempCrl->issuer_raw.len) == 0) { - issuerKnown = ISSUERKNOWN; - break; - } - - tempCrl = tempCrl->next; - } - - /* If the CRL file corresponding to the parent certificate is not present - * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */ - if(issuerKnown) { - flags = 0; - mbedErr = mbedtls_x509_crt_verify_with_profile(parentCert, - &ci->certificateIssuerList, - &ci->certificateRevocationList, - &crtProfile, NULL, &flags, NULL, NULL); - } else { - return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; - } + return ret; +} - } +/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted. + * It defines a sequence of steps for certificate verification. */ +static UA_StatusCode +certificateVerification_verify(void *verificationContext, + const UA_ByteString *certificate) { + if(!verificationContext || !certificate) + return UA_STATUSCODE_BADINTERNALERROR; - } + UA_StatusCode ret = UA_STATUSCODE_GOOD; + CertInfo *ci = (CertInfo*)verificationContext; - // TODO: Extend verification - - /* This condition will check whether the certificate is a User certificate - * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and - * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate - * shall be condidered as CA Certificate and cannot be used to establish a - * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js - * for more details */ -#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 - if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) && - (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) { - return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; - } -#else - if((remoteCertificate.private_key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) && - (remoteCertificate.private_key_usage & MBEDTLS_X509_KU_CRL_SIGN)) { - return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; - } +#ifdef __linux__ /* Reload certificates if folder paths are specified */ + ret = reloadCertificates(ci); + if(ret != UA_STATUSCODE_GOOD) + return ret; #endif - - UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(mbedErr) { -#if UA_LOGLEVEL <= 400 - char buff[100]; - int len = mbedtls_x509_crt_verify_info(buff, 100, "", flags); - UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, - "Verifying the certificate failed with error: %.*s", len-1, buff); -#endif - if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) { - retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; - } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE || - flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) { - retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; - } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED || - flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) { - retval = UA_STATUSCODE_BADCERTIFICATEREVOKED; - } else { - retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } + /* Verification Step: Certificate Structure + * This parses the entire certificate chain contained in the bytestring. */ + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); + int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, + certificate->length); + if(mbedErr) + return UA_STATUSCODE_BADCERTIFICATEINVALID; + + /* Verification Step: Certificate Usage + * Check whether the certificate is a User certificate or a CA certificate. + * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the + * certificate shall be condidered as CA Certificate and cannot be used to + * establish a connection. Refer the test case CTT/Security/Security + * Certificate Validation/029.js for more details */ + unsigned int ca_flags = MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN; + if(mbedtls_x509_crt_check_key_usage(&cert, ca_flags)) { + mbedtls_x509_crt_free(&cert); + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; } - mbedtls_x509_crt_free(&remoteCertificate); - return retval; + /* These steps are performed outside of this method. + * Because we need the server or client context. + * - Security Policy + * - Host Name + * - URI */ + + /* Verification Step: Build Certificate Chain + * We perform the checks for each certificate inside. */ + mbedtls_x509_crt *old_issuers[UA_MBEDTLS_MAX_CHAIN_LENGTH]; + ret = mbedtlsVerifyChain(ci, &cert, old_issuers, &cert, 0); + mbedtls_x509_crt_free(&cert); + return ret; } static UA_StatusCode @@ -619,4 +568,5 @@ UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv, } #endif -#endif + +#endif /* UA_ENABLE_ENCRYPTION_MBEDTLS */ From c63520c407632b4e0c2a4d5520e193cb61a28f9a Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 27 Sep 2024 20:46:20 +0200 Subject: [PATCH 43/98] refactor(plugins): Use the same certificate verification logic for mbedTLS and OpenSSL Walk the tree to find a complete chain of unrevoked and current certificates. The chain must end in a self-signed certificate. Then, on the "way down", check that at least one certificate in the chain is trusted. --- plugins/crypto/openssl/ua_pki_openssl.c | 61 ++++++++++++++----------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index dbfc94e4bad..3c05aaa2777 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -491,26 +491,22 @@ openSSLCheckRevoked(CertContext *ctx, X509 *cert) { static UA_StatusCode openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, - X509 *x509, int depth) { + X509 *cert, int depth) { /* Maxiumum chain length */ if(depth == UA_OPENSSL_MAX_CHAIN_LENGTH) return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; /* Verification Step: Validity Period */ - ASN1_TIME *notBefore = X509_get_notBefore(x509); - ASN1_TIME *notAfter = X509_get_notAfter(x509); + ASN1_TIME *notBefore = X509_get_notBefore(cert); + ASN1_TIME *notAfter = X509_get_notAfter(cert); if(X509_cmp_current_time(notBefore) != -1 || X509_cmp_current_time(notAfter) != 1) - return UA_STATUSCODE_BADCERTIFICATETIMEINVALID; + return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID : + UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID; /* Verification Step: Revocation Check */ - if(openSSLCheckRevoked(ctx, x509)) - return UA_STATUSCODE_BADCERTIFICATEREVOKED; - - /* Is the certificate in the trust list? If yes, then we are done. */ - for(int i = 0; i < sk_X509_num(ctx->skTrusted); i++) { - if(X509_cmp(x509, sk_X509_value(ctx->skTrusted, i)) == 0) - return UA_STATUSCODE_GOOD; - } + if(openSSLCheckRevoked(ctx, cert)) + return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATEREVOKED : + UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED; /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is * returned only if all possible chains are incomplete. */ @@ -519,19 +515,12 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, while(ret != UA_STATUSCODE_GOOD) { /* Find the issuer. We jump back here to find a different path if a * subsequent check fails. */ - issuer = openSSLFindNextIssuer(ctx, stack, x509, issuer); + issuer = openSSLFindNextIssuer(ctx, stack, cert, issuer); if(!issuer) break; - /* Detect (endless) loops of issuers */ - for(int i = 0; i < depth; i++) { - if(old_issuers[i] == issuer) - return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; - } - old_issuers[depth] = issuer; - /* Verification Step: Signature */ - int opensslRet = X509_verify(x509, X509_get0_pubkey(issuer)); + int opensslRet = X509_verify(cert, X509_get0_pubkey(issuer)); if(opensslRet == -1) { return UA_STATUSCODE_BADCERTIFICATEINVALID; /* Ill-formed signature */ } else if(opensslRet == 0) { @@ -539,15 +528,35 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, continue; } + /* The certificate is self-signed. We have arrived at the top of the + * chain. We check whether the certificate is trusted below. This is the + * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. + * This sinals that the chain is complete (but can be still + * untrusted). */ + if(cert == issuer || X509_cmp(cert, issuer) == 0) { + ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + continue; + } + + /* Detect (endless) loops of issuers. The last one can be skipped by the + * check for self-signed just before. */ + for(int i = 0; i < depth; i++) { + if(old_issuers[i] == issuer) + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + } + old_issuers[depth] = issuer; + /* We have found the issuer certificate used for the signature. Recurse * to the next certificate in the chain (verify the current issuer). */ ret = openSSL_verifyChain(ctx, stack, old_issuers, issuer, depth + 1); + } - /* Problems where x509 != leaf are reported as "untrusted" without the - * detailed reason */ - if(ret != UA_STATUSCODE_GOOD && - ret != UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE) - ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + /* Is the certificate in the trust list? If yes, then we are done. */ + if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) { + for(int i = 0; i < sk_X509_num(ctx->skTrusted); i++) { + if(X509_cmp(cert, sk_X509_value(ctx->skTrusted, i)) == 0) + return UA_STATUSCODE_GOOD; + } } return ret; From dfe4eea31e725010336894be5c7bf21fa3764166 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 30 Sep 2024 00:27:51 +0200 Subject: [PATCH 44/98] fix(core): Fix type access when comparing ExtensionObjects --- src/ua_types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ua_types.c b/src/ua_types.c index c2c14cccac0..2fff32e18bb 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -1436,7 +1436,7 @@ extensionObjectOrder(const UA_ExtensionObject *p1, const UA_ExtensionObject *p2, case UA_EXTENSIONOBJECT_DECODED: default: { const UA_DataType *type1 = p1->content.decoded.type; - const UA_DataType *type2 = p1->content.decoded.type; + const UA_DataType *type2 = p2->content.decoded.type; if(type1 != type2) return ((uintptr_t)type1 < (uintptr_t)type2) ? UA_ORDER_LESS : UA_ORDER_MORE; if(!type1) From f9d4c1631032f1d1232cb75ab38d74081e87882f Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Fri, 27 Sep 2024 22:54:10 +0200 Subject: [PATCH 45/98] fix(plugins): More thorough validation that the issuer is a valid CA --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 94 +++++++++++++++++-------- plugins/crypto/openssl/ua_pki_openssl.c | 28 +++++--- 2 files changed, 83 insertions(+), 39 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index ac3bf38814e..2abc1bf4323 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -13,6 +13,7 @@ #ifdef UA_ENABLE_ENCRYPTION_MBEDTLS #include +#include #include #include #include @@ -232,31 +233,63 @@ reloadCertificates(CertInfo *ci) { #endif +#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10 +#define UA_MBEDTLS_MAX_DN_LENGTH 256 + /* We need to access some private fields below */ #ifndef MBEDTLS_PRIVATE #define MBEDTLS_PRIVATE(x) x #endif -/* Return the first matching issuer candidate AFTER prev */ +/* Is the certificate a CA? */ +static UA_Boolean +mbedtlsCheckCA(mbedtls_x509_crt *cert) { + /* The Basic Constraints extension must be set and the cert acts as CA */ + if(!(cert->MBEDTLS_PRIVATE(ext_types) & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) || + !cert->MBEDTLS_PRIVATE(ca_istrue)) + return false; + + /* The Key Usage extension must be set to cert signing and CRL issuing */ + if(!(cert->MBEDTLS_PRIVATE(ext_types) & MBEDTLS_X509_EXT_KEY_USAGE) || + mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0 || + mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_CRL_SIGN) != 0) + return false; + + return true; +} + +static UA_Boolean +mbedtlsSameName(UA_String name, const mbedtls_x509_name *name2) { + char buf[UA_MBEDTLS_MAX_DN_LENGTH]; + int len = mbedtls_x509_dn_gets(buf, UA_MBEDTLS_MAX_DN_LENGTH, name2); + if(len < 0) + return false; + UA_String nameString = {(size_t)len, (UA_Byte*)buf}; + return UA_String_equal(&name, &nameString); +} + +/* Return the first matching issuer candidate AFTER prev. + * This can return the cert itself if self-signed. */ static mbedtls_x509_crt * mbedtlsFindNextIssuer(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) { - char inbuf[512], snbuf[512]; - if(mbedtls_x509_dn_gets(inbuf, 512, &cert->issuer) < 0) + char inbuf[UA_MBEDTLS_MAX_DN_LENGTH]; + int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer); + if(nameLen < 0) return NULL; + UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf}; do { for(mbedtls_x509_crt *i = stack; i; i = i->next) { - /* Compare issuer name and subject name */ - if(mbedtls_x509_dn_gets(snbuf, 512, &i->subject) < 0) - continue; - if(strncmp(inbuf, snbuf, 512) != 0) - continue; - /* Skip when the key does not match the signature */ - if(!mbedtls_pk_can_do(&i->pk, cert->MBEDTLS_PRIVATE(sig_pk))) + if(prev) { + if(prev == i) + prev = NULL; /* This was the last issuer we tried to verify */ continue; - if(prev == NULL) + } + /* Compare issuer name and subject name. + * Skip when the key does not match the signature. */ + if(mbedtlsSameName(issuerName, &i->subject) && + mbedtls_pk_can_do(&i->pk, cert->MBEDTLS_PRIVATE(sig_pk))) return i; - prev = NULL; /* This was the last issuer we tried to verify */ } /* Switch from the stack that came with the cert to the ctx->skIssue list */ stack = (stack != &ci->certificateIssuerList) ? &ci->certificateIssuerList : NULL; @@ -266,17 +299,16 @@ mbedtlsFindNextIssuer(CertInfo *ci, mbedtls_x509_crt *stack, static UA_Boolean mbedtlsCheckRevoked(CertInfo *ci, mbedtls_x509_crt *cert) { - char inbuf[512], inbuf2[512]; - if(mbedtls_x509_dn_gets(inbuf, 512, &cert->issuer) < 0) + char inbuf[UA_MBEDTLS_MAX_DN_LENGTH]; + int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer); + if(nameLen < 0) return true; + UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf}; for(mbedtls_x509_crl *crl = &ci->certificateRevocationList; crl; crl = crl->next) { - /* Is the CRL for the issuer of the certificate? */ - if(mbedtls_x509_dn_gets(inbuf2, 512, &crl->issuer) < 0) - return true; - if(strncmp(inbuf, inbuf2, 512) != 0) - continue; - /* Is the serial number of the certificate contained in the CRL? */ - if(mbedtls_x509_crt_is_revoked(cert, crl) != 0) + /* Is the CRL for certificates from the cert issuer? + * Is the serial number of the certificate contained in the CRL? */ + if(mbedtlsSameName(issuerName, &crl->issuer) && + mbedtls_x509_crt_is_revoked(cert, crl) != 0) return true; } return false; @@ -305,8 +337,6 @@ mbedtlsCheckSignature(const mbedtls_x509_crt *cert, mbedtls_x509_crt *issuer) { hash, hash_len, sig->p, sig->len) == 0); } -#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10 - static UA_StatusCode mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old_issuers, mbedtls_x509_crt *cert, int depth) { @@ -337,6 +367,13 @@ mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old if(!issuer) break; + /* Verification Step: Certificate Usage + * Can the issuer act as CA? Omit for self-signed leaf certificates. */ + if((depth > 0 || issuer != cert) && !mbedtlsCheckCA(issuer)) { + ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED; + continue; + } + /* Verification Step: Signature */ if(!mbedtlsCheckSignature(cert, issuer)) { ret = UA_STATUSCODE_BADCERTIFICATEINVALID; /* Wrong issuer, try again */ @@ -346,7 +383,7 @@ mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old /* The certificate is self-signed. We have arrived at the top of the * chain. We check whether the certificate is trusted below. This is the * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. - * This sinals that the chain is complete (but can be still + * This signals that the chain is complete (but can be still * untrusted). */ if(issuer == cert || (cert->tbs.len == issuer->tbs.len && memcmp(cert->tbs.p, issuer->tbs.p, cert->tbs.len) == 0)) { @@ -408,12 +445,9 @@ certificateVerification_verify(void *verificationContext, /* Verification Step: Certificate Usage * Check whether the certificate is a User certificate or a CA certificate. - * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the - * certificate shall be condidered as CA Certificate and cannot be used to - * establish a connection. Refer the test case CTT/Security/Security - * Certificate Validation/029.js for more details */ - unsigned int ca_flags = MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN; - if(mbedtls_x509_crt_check_key_usage(&cert, ca_flags)) { + * Refer the test case CTT/Security/Security Certificate Validation/029.js + * for more details. */ + if(mbedtlsCheckCA(&cert)) { mbedtls_x509_crt_free(&cert); return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; } diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 3c05aaa2777..d7bb1297e5d 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -454,11 +454,16 @@ openSSLFindNextIssuer(CertContext *ctx, STACK_OF(X509) *stack, X509 *x509, X509 int size = sk_X509_num(stack); for(int i = 0; i < size; i++) { X509 *candidate = sk_X509_value(stack, i); - if(X509_check_issued(candidate, x509) != 0) + if(prev) { + if(prev == candidate) + prev = NULL; /* This was the last issuer we tried to verify */ continue; - if(prev == NULL) + } + /* This checks subject/issuer name and the key usage of the issuer. + * It does not verify the validity period and if the issuer key was + * used for the signature. We check that afterwards. */ + if(X509_check_issued(candidate, x509) == 0) return candidate; - prev = NULL; } /* Switch to search in the ctx->skIssue list */ stack = (stack != ctx->skIssue) ? ctx->skIssue : NULL; @@ -519,6 +524,13 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, if(!issuer) break; + /* Verification Step: Certificate Usage + * Can the issuer act as CA? Omit for self-signed leaf certificates. */ + if((depth > 0 || issuer != cert) && !X509_check_ca(issuer)) { + ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED; + continue; + } + /* Verification Step: Signature */ int opensslRet = X509_verify(cert, X509_get0_pubkey(issuer)); if(opensslRet == -1) { @@ -531,7 +543,7 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, /* The certificate is self-signed. We have arrived at the top of the * chain. We check whether the certificate is trusted below. This is the * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. - * This sinals that the chain is complete (but can be still + * This signals that the chain is complete (but can be still * untrusted). */ if(cert == issuer || X509_cmp(cert, issuer) == 0) { ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; @@ -589,12 +601,10 @@ UA_CertificateVerification_Verify(void *verificationContext, /* Verification Step: Certificate Usage * Check whether the certificate is a User certificate or a CA certificate. - * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the - * certificate shall be condidered as CA Certificate and cannot be used to - * establish a connection. Refer the test case CTT/Security/Security - * Certificate Validation/029.js for more details */ + * Refer the test case CTT/Security/Security Certificate Validation/029.js + * for more details. */ X509 *leaf = sk_X509_value(stack, 0); - if(X509_check_purpose(leaf, X509_PURPOSE_CRL_SIGN, 0) && X509_check_ca(leaf)) { + if(X509_check_ca(leaf)) { sk_X509_pop_free(stack, X509_free); return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; } From 47336a788068960d8171a29ded8698ee81ba5703 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 2 Oct 2024 21:47:05 +0200 Subject: [PATCH 46/98] refactor(build): Bump version to v1.3.13 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbced8259ea..3ff203aeee4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 12) +set(OPEN62541_VER_PATCH 13) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 0a485919909f9db2be916b5ee7c57c3e98c85aa9 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Thu, 3 Oct 2024 11:12:07 +0200 Subject: [PATCH 47/98] fix(plugins): Disable the Basic128Rsa15 and Basic256 SecurityPolicy --- .../mbedtls/ua_securitypolicy_basic128rsa15.c | 4 ++ .../mbedtls/ua_securitypolicy_basic256.c | 5 ++ .../crypto/openssl/ua_openssl_basic128rsa15.c | 4 ++ plugins/crypto/openssl/ua_openssl_basic256.c | 5 ++ plugins/ua_config_default.c | 68 ++++++++++--------- .../check_encryption_basic128rsa15.c | 31 ++++++++- tests/encryption/check_encryption_basic256.c | 26 +++++++ 7 files changed, 109 insertions(+), 34 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_securitypolicy_basic128rsa15.c b/plugins/crypto/mbedtls/ua_securitypolicy_basic128rsa15.c index e708c78fdc1..5ede408d31b 100644 --- a/plugins/crypto/mbedtls/ua_securitypolicy_basic128rsa15.c +++ b/plugins/crypto/mbedtls/ua_securitypolicy_basic128rsa15.c @@ -746,6 +746,10 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l memset(policy, 0, sizeof(UA_SecurityPolicy)); policy->logger = logger; + UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "!! WARNING !! The Basic128Rsa15 SecurityPolicy is unsecure. " + "There are known attacks that break the encryption."); + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15\0"); UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule; diff --git a/plugins/crypto/mbedtls/ua_securitypolicy_basic256.c b/plugins/crypto/mbedtls/ua_securitypolicy_basic256.c index bf0196bb7f8..fd4ddc008a4 100644 --- a/plugins/crypto/mbedtls/ua_securitypolicy_basic256.c +++ b/plugins/crypto/mbedtls/ua_securitypolicy_basic256.c @@ -667,6 +667,11 @@ policyContext_newContext_sp_basic256(UA_SecurityPolicy *securityPolicy, UA_StatusCode UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localCertificate, const UA_ByteString localPrivateKey, const UA_Logger *logger) { + + UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "!! WARNING !! The Basic256 SecurityPolicy is unsecure. " + "There are known attacks that break the encryption."); + memset(policy, 0, sizeof(UA_SecurityPolicy)); policy->logger = logger; diff --git a/plugins/crypto/openssl/ua_openssl_basic128rsa15.c b/plugins/crypto/openssl/ua_openssl_basic128rsa15.c index 71affd31655..7e47e4d0729 100644 --- a/plugins/crypto/openssl/ua_openssl_basic128rsa15.c +++ b/plugins/crypto/openssl/ua_openssl_basic128rsa15.c @@ -500,6 +500,10 @@ UA_SecurityPolicy_Basic128Rsa15 (UA_SecurityPolicy * policy, const UA_ByteString localPrivateKey, const UA_Logger * logger) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "!! WARNING !! The Basic128Rsa15 SecurityPolicy is unsecure. " + "There are known attacks that break the encryption."); + UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; diff --git a/plugins/crypto/openssl/ua_openssl_basic256.c b/plugins/crypto/openssl/ua_openssl_basic256.c index e54042a7a02..a3c8903364c 100644 --- a/plugins/crypto/openssl/ua_openssl_basic256.c +++ b/plugins/crypto/openssl/ua_openssl_basic256.c @@ -501,6 +501,11 @@ UA_SecurityPolicy_Basic256 (UA_SecurityPolicy * policy, const UA_ByteString localCertificate, const UA_ByteString localPrivateKey, const UA_Logger * logger) { + + UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "!! WARNING !! The Basic256 SecurityPolicy is unsecure. " + "There are known attacks that break the encryption."); + UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; diff --git a/plugins/ua_config_default.c b/plugins/ua_config_default.c index 8ab5f547f28..b1445975c63 100644 --- a/plugins/ua_config_default.c +++ b/plugins/ua_config_default.c @@ -639,19 +639,21 @@ UA_ServerConfig_addAllSecurityPolicies(UA_ServerConfig *config, UA_StatusCode_name(retval)); } - retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &localCertificate, &localPrivateKey); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", - UA_StatusCode_name(retval)); - } - - retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &localCertificate, &localPrivateKey); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic256 with error code %s", - UA_StatusCode_name(retval)); - } + /* Basic128Rsa15 should no longer be used */ + /* retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &localCertificate, &localPrivateKey); */ + /* if(retval != UA_STATUSCODE_GOOD) { */ + /* UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, */ + /* "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", */ + /* UA_StatusCode_name(retval)); */ + /* } */ + + /* Basic256 should no longer be used */ + /* retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &localCertificate, &localPrivateKey); */ + /* if(retval != UA_STATUSCODE_GOOD) { */ + /* UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, */ + /* "Could not add SecurityPolicy#Basic256 with error code %s", */ + /* UA_StatusCode_name(retval)); */ + /* } */ retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &localCertificate, &localPrivateKey); if(retval != UA_STATUSCODE_GOOD) { @@ -838,25 +840,27 @@ UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config, return UA_STATUSCODE_BADOUTOFMEMORY; config->securityPolicies = sp; - retval = UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, privateKey, &config->logger); - if(retval == UA_STATUSCODE_GOOD) { - ++config->securityPoliciesSize; - } else { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", - UA_StatusCode_name(retval)); - } - - retval = UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, privateKey, &config->logger); - if(retval == UA_STATUSCODE_GOOD) { - ++config->securityPoliciesSize; - } else { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic256 with error code %s", - UA_StatusCode_name(retval)); - } + /* Basic128Rsa15 should no longer be used */ + /* retval = UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize], */ + /* localCertificate, privateKey, &config->logger); */ + /* if(retval == UA_STATUSCODE_GOOD) { */ + /* ++config->securityPoliciesSize; */ + /* } else { */ + /* UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, */ + /* "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", */ + /* UA_StatusCode_name(retval)); */ + /* } */ + + /* Basic256 should no longer be used */ + /* retval = UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize], */ + /* localCertificate, privateKey, &config->logger); */ + /* if(retval == UA_STATUSCODE_GOOD) { */ + /* ++config->securityPoliciesSize; */ + /* } else { */ + /* UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, */ + /* "Could not add SecurityPolicy#Basic256 with error code %s", */ + /* UA_StatusCode_name(retval)); */ + /* } */ retval = UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize], localCertificate, privateKey, &config->logger); diff --git a/tests/encryption/check_encryption_basic128rsa15.c b/tests/encryption/check_encryption_basic128rsa15.c index 9c547fa5411..80bb043163f 100644 --- a/tests/encryption/check_encryption_basic128rsa15.c +++ b/tests/encryption/check_encryption_basic128rsa15.c @@ -75,6 +75,11 @@ static void setup(void) { config->certificateVerification.clear(&config->certificateVerification); UA_CertificateVerification_AcceptAll(&config->certificateVerification); + /* Manually add the Basic128Rsa15 SecurityPolicy. + * It does not get added by default as it is considered unsecure. */ + UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &certificate, &privateKey); + UA_ServerConfig_addAllEndpoints(config); + /* Set the ApplicationUri used in the certificate */ UA_String_clear(&config->applicationDescription.applicationUri); config->applicationDescription.applicationUri = @@ -118,7 +123,9 @@ START_TEST(encryption_connect) { * security mode as none to see the server's capability * and certificate */ client = UA_Client_new(); - UA_ClientConfig_setDefault(UA_Client_getConfig(client)); + UA_ClientConfig *cc = UA_Client_getConfig(client); + UA_ClientConfig_setDefault(cc); + ck_assert(client != NULL); UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://localhost:4840", &endpointArraySize, &endpointArray); @@ -147,12 +154,22 @@ START_TEST(encryption_connect) { /* Secure client initialization */ client = UA_Client_new(); - UA_ClientConfig *cc = UA_Client_getConfig(client); + cc = UA_Client_getConfig(client); UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey, trustList, trustListSize, revocationList, revocationListSize); cc->certificateVerification.clear(&cc->certificateVerification); UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + + /* Manually add the Basic128Rsa15 SecurityPolicy. + * It does not get added by default as it is considered unsecure. */ + cc->securityPolicies = (UA_SecurityPolicy *) + UA_realloc(cc->securityPolicies, sizeof(UA_SecurityPolicy) * + (cc->securityPoliciesSize + 1)); + UA_SecurityPolicy_Basic128Rsa15(&cc->securityPolicies[cc->securityPoliciesSize], + certificate, privateKey, &cc->logger); + cc->securityPoliciesSize++; + cc->securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"); ck_assert(client != NULL); @@ -236,6 +253,16 @@ START_TEST(encryption_connect_pem) { revocationList, revocationListSize); cc->certificateVerification.clear(&cc->certificateVerification); UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + + /* Manually add the Basic128Rsa15 SecurityPolicy. + * It does not get added by default as it is considered unsecure. */ + cc->securityPolicies = (UA_SecurityPolicy *) + UA_realloc(cc->securityPolicies, sizeof(UA_SecurityPolicy) * + (cc->securityPoliciesSize + 1)); + UA_SecurityPolicy_Basic128Rsa15(&cc->securityPolicies[cc->securityPoliciesSize], + certificate, privateKey, &cc->logger); + cc->securityPoliciesSize++; + cc->securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"); ck_assert(client != NULL); diff --git a/tests/encryption/check_encryption_basic256.c b/tests/encryption/check_encryption_basic256.c index 48d14a4978b..57335b2d29e 100644 --- a/tests/encryption/check_encryption_basic256.c +++ b/tests/encryption/check_encryption_basic256.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,11 @@ static void setup(void) { config->certificateVerification.clear(&config->certificateVerification); UA_CertificateVerification_AcceptAll(&config->certificateVerification); + /* Manually add the Basic256 SecurityPolicy. + * It does not get added by default as it is considered unsecure. */ + UA_ServerConfig_addSecurityPolicyBasic256(config, &certificate, &privateKey); + UA_ServerConfig_addAllEndpoints(config); + /* Set the ApplicationUri used in the certificate */ UA_String_clear(&config->applicationDescription.applicationUri); config->applicationDescription.applicationUri = @@ -156,6 +162,16 @@ START_TEST(encryption_connect) { revocationList, revocationListSize); cc->certificateVerification.clear(&cc->certificateVerification); UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + + /* Manually add the Basic256 SecurityPolicy. + * It does not get added by default as it is considered unsecure. */ + cc->securityPolicies = (UA_SecurityPolicy *) + UA_realloc(cc->securityPolicies, sizeof(UA_SecurityPolicy) * + (cc->securityPoliciesSize + 1)); + UA_SecurityPolicy_Basic256(&cc->securityPolicies[cc->securityPoliciesSize], + certificate, privateKey, &cc->logger); + cc->securityPoliciesSize++; + cc->securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256"); ck_assert(client != NULL); @@ -239,6 +255,16 @@ START_TEST(encryption_connect_pem) { revocationList, revocationListSize); cc->certificateVerification.clear(&cc->certificateVerification); UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + + /* Manually add the Basic256 SecurityPolicy. + * It does not get added by default as it is considered unsecure. */ + cc->securityPolicies = (UA_SecurityPolicy *) + UA_realloc(cc->securityPolicies, sizeof(UA_SecurityPolicy) * + (cc->securityPoliciesSize + 1)); + UA_SecurityPolicy_Basic256(&cc->securityPolicies[cc->securityPoliciesSize], + certificate, privateKey, &cc->logger); + cc->securityPoliciesSize++; + cc->securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256"); ck_assert(client != NULL); From 43afb0471a81c71dfb1d1e33589308762d5a6d18 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Thu, 3 Oct 2024 11:17:08 +0200 Subject: [PATCH 48/98] refactor(build): Bump version to 1.3.14 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ff203aeee4..bcf1fea7e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 13) +set(OPEN62541_VER_PATCH 14) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 96fbfc8612b7851afb4990569e6b3dc2c0f46ba0 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 22 Oct 2024 21:50:12 +0200 Subject: [PATCH 49/98] fix(tests): Add a missing include to check_crl_validation.c (required for clang) --- tests/encryption/check_crl_validation.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/encryption/check_crl_validation.c b/tests/encryption/check_crl_validation.c index c9af7c63a71..9c4c08d5e45 100644 --- a/tests/encryption/check_crl_validation.c +++ b/tests/encryption/check_crl_validation.c @@ -13,6 +13,8 @@ #include #include +#include + #include "certificates.h" #include "check.h" #include "thread_wrapper.h" From db91b23259ac7ef183b1051eb6e0b4581c23d297 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 22 Oct 2024 23:06:02 +0200 Subject: [PATCH 50/98] fix(plugins): Manually classify certificates as CA for OpenSSL Replace the builtin method with manual classification. We now require the KU_CRL_SIGN flag to detect a CA. Before we rejected the leaf certificates generated by some vendors. --- plugins/crypto/openssl/ua_pki_openssl.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index d7bb1297e5d..84eb66040b4 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -471,6 +471,26 @@ openSSLFindNextIssuer(CertContext *ctx, STACK_OF(X509) *stack, X509 *x509, X509 return NULL; } +/* Is the certificate a CA? */ +static UA_Boolean +openSSLCheckCA(X509 *cert) { + uint32_t flags = X509_get_extension_flags(cert); + /* The basic constraints must be set with the CA flag true */ + if(!(flags & EXFLAG_CA)) + return false; + + /* The Key Usage extension must be set */ + if(!(flags & EXFLAG_KUSAGE)) + return false; + + /* The Key Usage must include cert signing and CRL issuing */ + uint32_t usage = X509_get_key_usage(cert); + if(!(usage & KU_KEY_CERT_SIGN) || !(usage & KU_CRL_SIGN)) + return false; + + return true; +} + static UA_Boolean openSSLCheckRevoked(CertContext *ctx, X509 *cert) { const ASN1_INTEGER *sn = X509_get0_serialNumber(cert); @@ -526,7 +546,7 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, /* Verification Step: Certificate Usage * Can the issuer act as CA? Omit for self-signed leaf certificates. */ - if((depth > 0 || issuer != cert) && !X509_check_ca(issuer)) { + if((depth > 0 || issuer != cert) && !openSSLCheckCA(issuer)) { ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED; continue; } @@ -604,7 +624,7 @@ UA_CertificateVerification_Verify(void *verificationContext, * Refer the test case CTT/Security/Security Certificate Validation/029.js * for more details. */ X509 *leaf = sk_X509_value(stack, 0); - if(X509_check_ca(leaf)) { + if(openSSLCheckCA(leaf)) { sk_X509_pop_free(stack, X509_free); return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; } From b9473527623125b5ca264dae4551f8cc414b3bc3 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 22 Oct 2024 21:47:15 +0200 Subject: [PATCH 51/98] refactor(core): Validate Variant ArrayLength against its ArrayDimensions during binary decode This lead to the fuzzer complaing since we hade the check for _encode but not for _decode. This is not a direct memory issue per se. But the consistency check allows early discovery of problematic values and can potentially remove bugs where the user relies on the array dimensions and the array length to match. --- src/ua_types_encoding_binary.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ua_types_encoding_binary.c b/src/ua_types_encoding_binary.c index 7e1509267a6..ac3f7165b16 100644 --- a/src/ua_types_encoding_binary.c +++ b/src/ua_types_encoding_binary.c @@ -1093,9 +1093,18 @@ DECODE_BINARY(Variant) { } /* Decode array dimensions */ - if(isArray && (encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS) > 0) + if(isArray && (encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS) > 0) { ret |= Array_decodeBinary((void**)&dst->arrayDimensions, &dst->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32], ctx); + /* Validate array length against array dimensions */ + size_t totalSize = 1; + for(size_t i = 0; i < dst->arrayDimensionsSize; ++i) { + if(dst->arrayDimensions[i] == 0) + return UA_STATUSCODE_BADDECODINGERROR; + totalSize *= dst->arrayDimensions[i]; + } + UA_CHECK(totalSize == dst->arrayLength, ret = UA_STATUSCODE_BADDECODINGERROR); + } ctx->depth--; return ret; From cd9088a079b3176f985bf0fb47fcfc943957697f Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 13:39:11 +0100 Subject: [PATCH 52/98] refactor(plugins): Refactor out mbedtlsSameBuf to compare mbedTLS buffers --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index 2abc1bf4323..301939f7d39 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -268,6 +268,13 @@ mbedtlsSameName(UA_String name, const mbedtls_x509_name *name2) { return UA_String_equal(&name, &nameString); } +static UA_Boolean +mbedtlsSameBuf(mbedtls_x509_buf *a, mbedtls_x509_buf *b) { + if(a->len != b->len) + return false; + return (memcmp(a->p, b->p, a->len) == 0); +} + /* Return the first matching issuer candidate AFTER prev. * This can return the cert itself if self-signed. */ static mbedtls_x509_crt * @@ -385,8 +392,7 @@ mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. * This signals that the chain is complete (but can be still * untrusted). */ - if(issuer == cert || (cert->tbs.len == issuer->tbs.len && - memcmp(cert->tbs.p, issuer->tbs.p, cert->tbs.len) == 0)) { + if(issuer == cert || mbedtlsSameBuf(&cert->tbs, &issuer->tbs)) { ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; continue; } @@ -408,8 +414,7 @@ mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old * certificate "on the way down". Can we trust this certificate? */ if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) { for(mbedtls_x509_crt *t = &ci->certificateTrustList; t; t = t->next) { - if(cert->tbs.len == t->tbs.len && - memcmp(cert->tbs.p, t->tbs.p, cert->tbs.len) == 0) + if(mbedtlsSameBuf(&cert->tbs, &t->tbs)) return UA_STATUSCODE_GOOD; } } From ff7dc78d2d1b42b2527a63c52d289ba1cf4bb303 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 17:13:51 +0100 Subject: [PATCH 53/98] refactor(plugins): Small cleanups in ua_pki_mbedtls.c --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index 301939f7d39..eab87c15733 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -19,6 +19,9 @@ #include #include +#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10 +#define UA_MBEDTLS_MAX_DN_LENGTH 256 + /* Find binary substring. Taken and adjusted from * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */ @@ -225,17 +228,11 @@ reloadCertificates(CertInfo *ci) { } } - if(internalErrorFlag) { - retval = UA_STATUSCODE_BADINTERNALERROR; - } - return retval; + return (internalErrorFlag) ? UA_STATUSCODE_BADINTERNALERROR : retval; } #endif -#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10 -#define UA_MBEDTLS_MAX_DN_LENGTH 256 - /* We need to access some private fields below */ #ifndef MBEDTLS_PRIVATE #define MBEDTLS_PRIVATE(x) x From 3ebc92e66ae80357aa96f048be207da3348ae8af Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 17:35:53 +0100 Subject: [PATCH 54/98] fix(plugins): Also consider the trustlist to find issuers in ua_pki_mbedtls.c --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index eab87c15733..7991c8c2c2a 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -295,8 +295,15 @@ mbedtlsFindNextIssuer(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_pk_can_do(&i->pk, cert->MBEDTLS_PRIVATE(sig_pk))) return i; } - /* Switch from the stack that came with the cert to the ctx->skIssue list */ - stack = (stack != &ci->certificateIssuerList) ? &ci->certificateIssuerList : NULL; + + /* Switch from the stack that came with the cert to the issuer list and + * then to the trust list. */ + if(stack == &ci->certificateTrustList) + stack = NULL; + else if(stack == &ci->certificateIssuerList) + stack = &ci->certificateTrustList; + else + stack = &ci->certificateIssuerList; } while(stack); return NULL; } From 2e516fd7bdc53e06dffd38a080835c25ea480cdf Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 17:37:07 +0100 Subject: [PATCH 55/98] fix(plugins): Return detailed status codes for revocation checks in ua_pki_mbedtls.c --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 46 ++++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index 7991c8c2c2a..b768de120af 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -308,21 +308,27 @@ mbedtlsFindNextIssuer(CertInfo *ci, mbedtls_x509_crt *stack, return NULL; } -static UA_Boolean +static UA_StatusCode mbedtlsCheckRevoked(CertInfo *ci, mbedtls_x509_crt *cert) { + /* Parse the Issuer Name */ char inbuf[UA_MBEDTLS_MAX_DN_LENGTH]; int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer); if(nameLen < 0) - return true; + return UA_STATUSCODE_BADINTERNALERROR; UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf}; + + /* Loop over the crl and match the Issuer Name */ + UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; for(mbedtls_x509_crl *crl = &ci->certificateRevocationList; crl; crl = crl->next) { /* Is the CRL for certificates from the cert issuer? * Is the serial number of the certificate contained in the CRL? */ - if(mbedtlsSameName(issuerName, &crl->issuer) && - mbedtls_x509_crt_is_revoked(cert, crl) != 0) - return true; + if(mbedtlsSameName(issuerName, &crl->issuer)) { + if(mbedtls_x509_crt_is_revoked(cert, crl) != 0) + return UA_STATUSCODE_BADCERTIFICATEREVOKED; + res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */ + } } - return false; + return res; } /* Verify that the public key of the issuer was used to sign the certificate */ @@ -361,11 +367,6 @@ mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID : UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID; - /* Verification Step: Revocation Check */ - if(mbedtlsCheckRevoked(ci, cert)) - return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATEREVOKED : - UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED; - /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is * returned only if all possible chains are incomplete. */ mbedtls_x509_crt *issuer = NULL; @@ -395,15 +396,28 @@ mbedtlsVerifyChain(CertInfo *ci, mbedtls_x509_crt *stack, mbedtls_x509_crt **old * chain. We check whether the certificate is trusted below. This is the * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. * This signals that the chain is complete (but can be still - * untrusted). */ + * untrusted). + * + * Break here as we have reached the end of the chain. Omit the + * Revocation Check for self-signed certificates. */ if(issuer == cert || mbedtlsSameBuf(&cert->tbs, &issuer->tbs)) { ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; - continue; + break; } - /* Detect (endless) loops of issuers. The last one can be skipped by the - * check for self-signed just before. */ - for(int i = 0; i < depth - 1; i++) { + /* Verification Step: Revocation Check */ + ret = mbedtlsCheckRevoked(ci, cert); + if(depth > 0) { + if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED) + ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED; + if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN) + ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; + } + if(ret != UA_STATUSCODE_GOOD) + continue; + + /* Detect (endless) loops of issuers */ + for(int i = 0; i < depth; i++) { if(old_issuers[i] == issuer) return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; } From 486a65ee10d7cd0f4e77380c5c29d9484bc1730d Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 20:08:23 +0100 Subject: [PATCH 56/98] fix(plugins): Also consider the trustlist to find issuers in ua_pki_openssl.c --- plugins/crypto/openssl/ua_pki_openssl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 84eb66040b4..38cd710a808 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -465,8 +465,14 @@ openSSLFindNextIssuer(CertContext *ctx, STACK_OF(X509) *stack, X509 *x509, X509 if(X509_check_issued(candidate, x509) == 0) return candidate; } - /* Switch to search in the ctx->skIssue list */ - stack = (stack != ctx->skIssue) ? ctx->skIssue : NULL; + /* Switch from the stack that came with the cert to the issuer list and + * then to the trust list. */ + if(stack == ctx->skTrusted) + stack = NULL; + else if(stack == ctx->skIssue) + stack = ctx->skTrusted; + else + stack = ctx->skIssue; } while(stack); return NULL; } From 80bbdd4170e1c8af83ad894cb2e1ee9ef2cc80ef Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 20:11:53 +0100 Subject: [PATCH 57/98] fix(plugins): Return detailed status codes for revocation checks in ua_pki_openssl.c --- plugins/crypto/openssl/ua_pki_openssl.c | 33 +++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 38cd710a808..048dda550f1 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -497,11 +497,14 @@ openSSLCheckCA(X509 *cert) { return true; } -static UA_Boolean +static UA_StatusCode openSSLCheckRevoked(CertContext *ctx, X509 *cert) { const ASN1_INTEGER *sn = X509_get0_serialNumber(cert); const X509_NAME *in = X509_get_issuer_name(cert); int size = sk_X509_CRL_num(ctx->skCrls); + + /* Loop over the crl and match the Issuer Name */ + UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; for(int i = 0; i < size; i++) { /* The crl contains a list of serial numbers from the same issuer */ X509_CRL *crl = sk_X509_CRL_value(ctx->skCrls, i); @@ -512,10 +515,11 @@ openSSLCheckRevoked(CertContext *ctx, X509 *cert) { for(int j = 0; j < rsize; j++) { X509_REVOKED *r = sk_X509_REVOKED_value(rs, j); if(ASN1_INTEGER_cmp(sn, X509_REVOKED_get0_serialNumber(r)) == 0) - return true; + return UA_STATUSCODE_BADCERTIFICATEREVOKED; } + res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */ } - return false; + return res; } #define UA_OPENSSL_MAX_CHAIN_LENGTH 10 @@ -534,11 +538,6 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID : UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID; - /* Verification Step: Revocation Check */ - if(openSSLCheckRevoked(ctx, cert)) - return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATEREVOKED : - UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED; - /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is * returned only if all possible chains are incomplete. */ X509 *issuer = NULL; @@ -570,11 +569,25 @@ openSSL_verifyChain(CertContext *ctx, STACK_OF(X509) *stack, X509 **old_issuers, * chain. We check whether the certificate is trusted below. This is the * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED. * This signals that the chain is complete (but can be still - * untrusted). */ + * untrusted). + * + * Break here as we have reached the end of the chain. Omit the + * Revocation Check for self-signed certificates. */ if(cert == issuer || X509_cmp(cert, issuer) == 0) { ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; - continue; + break; + } + + /* Verification Step: Revocation Check */ + ret = openSSLCheckRevoked(ctx, cert); + if(depth > 0) { + if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED) + ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED; + if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN) + ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; } + if(ret != UA_STATUSCODE_GOOD) + continue; /* Detect (endless) loops of issuers. The last one can be skipped by the * check for self-signed just before. */ From efbaac086e710ba1777fed1e05541923c10bda0d Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 20:17:23 +0100 Subject: [PATCH 58/98] feat(plugins): Disable revocation lists checks in ua_pki_mbedtls.c if zero crl are loaded Avoid breakage for users of the 1.3 release family but still log a warning. --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index b768de120af..8ab41285f65 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -317,6 +317,13 @@ mbedtlsCheckRevoked(CertInfo *ci, mbedtls_x509_crt *cert) { return UA_STATUSCODE_BADINTERNALERROR; UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf}; + if(ci->certificateRevocationList.raw.len == 0) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, + "Zero revocation lists have been loaded. " + "This seems intentional - omitting the check."); + return UA_STATUSCODE_GOOD; + } + /* Loop over the crl and match the Issuer Name */ UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; for(mbedtls_x509_crl *crl = &ci->certificateRevocationList; crl; crl = crl->next) { From 68142484a35a2a83ef083098ed533abbcc5e98f4 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 20:17:58 +0100 Subject: [PATCH 59/98] feat(plugins): Disable revocation lists checks in ua_pki_openssl.c if zero crl are loaded Avoid breakage for users of the 1.3 release family but still log a warning. --- plugins/crypto/openssl/ua_pki_openssl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 048dda550f1..40cec466e7e 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -503,6 +503,13 @@ openSSLCheckRevoked(CertContext *ctx, X509 *cert) { const X509_NAME *in = X509_get_issuer_name(cert); int size = sk_X509_CRL_num(ctx->skCrls); + if(size == 0) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, + "Zero revocation lists have been loaded. " + "This seems intentional - omitting the check."); + return UA_STATUSCODE_GOOD; + } + /* Loop over the crl and match the Issuer Name */ UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; for(int i = 0; i < size; i++) { From 3eed1a6d5c5b207c531b2d35ed88aa0a4a4541e5 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 23 Nov 2024 20:18:30 +0100 Subject: [PATCH 60/98] refactor(build): Bump version to v1.3.15 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bcf1fea7e06..002efecb75b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 14) +set(OPEN62541_VER_PATCH 15) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 86aa417aabe9e52f519119edd7a794a49d3907cb Mon Sep 17 00:00:00 2001 From: Florian La Roche Date: Wed, 1 Jan 2025 17:31:42 +0100 Subject: [PATCH 61/98] refactor(examples): do not set an invalid IP in server_multicast.c Currently an IP 42.42.42.42 is set and the comment suggests that the network stack resets this to 0.0.0.0 in server_multicast.c. Just set 0.0.0.0 directly. This is a backport of 253fc8abd5855851acc0f0d7fa62c98d2487f4f2 to the 1.3 branch. Signed-off-by: Florian La Roche --- examples/discovery/server_multicast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/discovery/server_multicast.c b/examples/discovery/server_multicast.c index 861e29e01a2..a31777b041f 100644 --- a/examples/discovery/server_multicast.c +++ b/examples/discovery/server_multicast.c @@ -241,7 +241,7 @@ int main(int argc, char **argv) { config->mdnsConfig.mdnsServerName = UA_String_fromChars("Sample Multicast Server"); //setting custom outbound interface - config->mdnsInterfaceIP = UA_String_fromChars("42.42.42.42"); //this line will produce an error and set the interface to 0.0.0.0 + config->mdnsInterfaceIP = UA_String_fromChars("0.0.0.0"); // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv // For a LDS server, you should only indicate the LDS capability. From 491667a5788c9479682bbb7ce8c557428da88770 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 3 Feb 2025 21:01:35 +0100 Subject: [PATCH 62/98] feat(client): Check if the "CreatedAt" timestamp of the SecurityToken matches the current system clock - consistently use monotonic clock internally --- src/client/ua_client_connect.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/client/ua_client_connect.c b/src/client/ua_client_connect.c index 5048262be47..84e85b7cffc 100644 --- a/src/client/ua_client_connect.c +++ b/src/client/ua_client_connect.c @@ -396,13 +396,6 @@ processOPNResponse(UA_Client *client, const UA_ByteString *message) { return; } - /* Response.securityToken.revisedLifetime is UInt32 we need to cast it to - * DateTime=Int64 we take 75% of lifetime to start renewing as described in - * standard */ - client->nextChannelRenewal = UA_DateTime_nowMonotonic() - + (UA_DateTime) (response.securityToken.revisedLifetime - * (UA_Double) UA_DATETIME_MSEC * 0.75); - /* Move the nonce out of the response */ UA_ByteString_clear(&client->channel.remoteNonce); client->channel.remoteNonce = response.serverNonce; @@ -415,6 +408,28 @@ processOPNResponse(UA_Client *client, const UA_ByteString *message) { client->channel.securityToken = response.securityToken; client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT; + /* Log a warning if the SecurityToken is not "fresh". Use the normal system + * clock to do the comparison. */ + UA_DateTime wallClockNow = UA_DateTime_now(); + if(wallClockNow - client->channel.securityToken.createdAt >= UA_DATETIME_SEC * 10 || + wallClockNow - client->channel.securityToken.createdAt <= -UA_DATETIME_SEC * 10) + UA_LOG_WARNING_CHANNEL(&client->config.logger, &client->channel, "The \"CreatedAt\" " + "timestamp of the received ChannelSecurityToken does not match " + "with the local system clock"); + + /* The internal "monotonic" clock is used by the SecureChannel to validate + * that the SecurityToken is still valid. The monotonic clock is independent + * from the system clock getting changed or synchronized to a master clock + * during runtime. */ + client->channel.securityToken.createdAt = UA_DateTime_nowMonotonic(); + + /* Response.securityToken.revisedLifetime is UInt32, we need to cast it to + * DateTime=Int64. After 75% of the lifetime the renewal takes place as + * described in standard */ + client->nextChannelRenewal = client->channel.securityToken.createdAt + + (UA_DateTime) (response.securityToken.revisedLifetime * + (UA_Double) UA_DATETIME_MSEC * 0.75); + /* Compute the new local keys. The remote keys are updated when a message * with the new SecurityToken is received. */ retval = UA_SecureChannel_generateLocalKeys(&client->channel); From 087039e43d1d5fa36e0f0a22aa50450810e038fc Mon Sep 17 00:00:00 2001 From: Marwin Glaser Date: Tue, 18 Feb 2025 17:02:34 +0100 Subject: [PATCH 63/98] feat(ci): remove ubuntu-20.04 ci See https://github.com/actions/runner-images/issues/11101 --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_ubuntu2204.yml | 29 -------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 .github/workflows/build_ubuntu2204.yml diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 59a26d4fe99..bbbaf7bb2f7 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -98,7 +98,7 @@ jobs: cmd_deps: sudo apt-get install -y -qq clang-11 clang-tools-11 libmbedtls-dev cmd_action: build_clang_analyzer name: ${{matrix.build_name}} - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 with: diff --git a/.github/workflows/build_ubuntu2204.yml b/.github/workflows/build_ubuntu2204.yml deleted file mode 100644 index 216c0665c08..00000000000 --- a/.github/workflows/build_ubuntu2204.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Linux Build & Test with OpenSSL3.0 - -on: [push, pull_request] - -jobs: - build: - strategy: - fail-fast: false - matrix: - include: - - build_name: "Encryption (OpenSSL3.0) Build & Unit Tests (gcc)" - cmd_deps: sudo apt-get install -y -qq openssl - cmd_action: unit_tests_encryption OPENSSL - name: ${{matrix.build_name}} - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install -y -qq python3-sphinx graphviz check - ${{ matrix.cmd_deps }} - - name: ${{matrix.build_name}} - run: source tools/ci.sh && ${{matrix.cmd_action}} - env: - ETHERNET_INTERFACE: eth0 - From 22d60f142a87a3aa12593f90a205009e7a90894a Mon Sep 17 00:00:00 2001 From: Marwin Glaser Date: Tue, 11 Mar 2025 11:52:21 +0100 Subject: [PATCH 64/98] fix(ci): update tpm2-tss and tpm2-pkcs11 to fix TPM Tool Build --- .github/workflows/build_linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index bbbaf7bb2f7..acec9fd74c3 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -53,7 +53,7 @@ jobs: cd ${HOME} git clone https://github.com/tpm2-software/tpm2-tss.git cd ${HOME}/tpm2-tss - git checkout 2.4.6 + git checkout 3.2.3 ./bootstrap && ./configure --with-udevrulesdir=/etc/udev/rules.d --with-udevrulesprefix=70- make -j$(nproc) sudo make install @@ -63,7 +63,7 @@ jobs: cd ${HOME} git clone https://github.com/tpm2-software/tpm2-pkcs11.git cd ${HOME}/tpm2-pkcs11 - git checkout 1.6.0 + git checkout 1.7.0 ./bootstrap && ./configure make -j$(nproc) sudo make install From 07677796816070c30589a796d07c4c815a364cde Mon Sep 17 00:00:00 2001 From: Marwin Glaser Date: Tue, 11 Mar 2025 12:04:48 +0100 Subject: [PATCH 65/98] fix(ci): switch to clang-14 to fix clang build --- .github/workflows/build_linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index acec9fd74c3..5a28d453fda 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -24,8 +24,8 @@ jobs: cmd_deps: "" cmd_action: unit_tests_alarms - build_name: "Debug Build & Unit Tests (clang)" - cmd_deps: sudo apt-get install -y -qq clang-11 clang-tools-11 mosquitto - cmd_action: CC=clang-11 CXX=clang++-11 unit_tests + cmd_deps: sudo apt-get install -y -qq clang-14 clang-tools-14 mosquitto + cmd_action: CC=clang-14 CXX=clang++-14 unit_tests - build_name: "Debug Build & Unit Tests (tcc)" cmd_deps: sudo apt-get install -y -qq tcc mosquitto cmd_action: CC=tcc unit_tests From d293259ffbade21451d925da32f10b47b88163fe Mon Sep 17 00:00:00 2001 From: Noel Graf Date: Tue, 17 Oct 2023 09:48:06 +0200 Subject: [PATCH 66/98] fix(ci): Fix an ill-defined regex in valgrind_check_error.py (cherry picked from commit 7f97400486f17e90e4702040e65d0dc9aadf86e4) --- tools/valgrind_check_error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/valgrind_check_error.py b/tools/valgrind_check_error.py index e192cecce3f..3bbc2c5e13e 100755 --- a/tools/valgrind_check_error.py +++ b/tools/valgrind_check_error.py @@ -60,7 +60,7 @@ def execute(command): # Try to parse the output. Look for the following line: # ==17054== FILE DESCRIPTORS: 5 open at exit. -descriptors_re = re.compile(r".*==(\d+)==\s+FILE DESCRIPTORS: (\d+) open at exit\..*") +descriptors_re = re.compile(r".*==(\d+)==\s+FILE DESCRIPTORS: (\d+) open(\s\(\d std\))? at exit\..*") m = descriptors_re.match(log_content) if not m: From f279e939428ac551acf9f9d134f2291648aa68d6 Mon Sep 17 00:00:00 2001 From: Marwin Glaser Date: Tue, 18 Mar 2025 15:50:59 +0100 Subject: [PATCH 67/98] fix(ci): disable pubsub ethernet support for tcc --- tools/ci.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/ci.sh b/tools/ci.sh index b08de97e1d5..2e1a59b5d1d 100644 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -130,6 +130,12 @@ function set_capabilities { } function unit_tests { + if [ "${CC:-x}" = "tcc" ]; then + PUBSUB_ETHERNET=OFF + else + PUBSUB_ETHERNET=ON + fi + mkdir -p build; cd build; rm -rf * cmake -DCMAKE_BUILD_TYPE=Debug \ -DUA_BUILD_EXAMPLES=ON \ @@ -140,7 +146,7 @@ function unit_tests { -DUA_ENABLE_HISTORIZING=ON \ -DUA_ENABLE_JSON_ENCODING=ON \ -DUA_ENABLE_PUBSUB=ON \ - -DUA_ENABLE_PUBSUB_ETH_UADP=ON \ + -DUA_ENABLE_PUBSUB_ETH_UADP=${PUBSUB_ETHERNET} \ -DUA_ENABLE_PUBSUB_DELTAFRAMES=ON \ -DUA_ENABLE_PUBSUB_INFORMATIONMODEL=ON \ -DUA_ENABLE_PUBSUB_MONITORING=ON \ From 5c1882c109937b75680ec43542c6e5c538e45280 Mon Sep 17 00:00:00 2001 From: Marwin Glaser Date: Tue, 25 Mar 2025 13:58:10 +0100 Subject: [PATCH 68/98] fix(ci): suppress invalid valgrind report in pthread_create in tests --- tools/valgrind_suppressions.supp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/valgrind_suppressions.supp b/tools/valgrind_suppressions.supp index 591ffa6647e..b079729b214 100644 --- a/tools/valgrind_suppressions.supp +++ b/tools/valgrind_suppressions.supp @@ -10,6 +10,24 @@ } +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:calloc + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls + fun:allocate_stack + fun:pthread_create@@GLIBC_2.34 + ... + fun:setup* + fun:srunner_run_setup + ... + fun:srunner_run_tagged + fun:main +} + # Custom suppressions added by @Pro From e1b2fee9f574da1e5e5a76556f4f7710fb841bcb Mon Sep 17 00:00:00 2001 From: marwinglaser Date: Wed, 16 Apr 2025 00:08:22 +0200 Subject: [PATCH 69/98] fic(ci) run linux CI in an ubuntu container (#7225) * Revert "fix(ci): suppress invalid valgrind report in pthread_create in tests" This reverts commit 5c1882c109937b75680ec43542c6e5c538e45280. * Revert "fix(ci): disable pubsub ethernet support for tcc" This reverts commit f279e939428ac551acf9f9d134f2291648aa68d6. * Revert "fix(ci): Fix an ill-defined regex in valgrind_check_error.py" This reverts commit d293259ffbade21451d925da32f10b47b88163fe. * Revert "fix(ci): switch to clang-14 to fix clang build" This reverts commit 07677796816070c30589a796d07c4c815a364cde. * Revert "fix(ci): update tpm2-tss and tpm2-pkcs11 to fix TPM Tool Build" This reverts commit 22d60f142a87a3aa12593f90a205009e7a90894a. * Revert "feat(ci): remove ubuntu-20.04 ci" This reverts commit 087039e43d1d5fa36e0f0a22aa50450810e038fc. * feat(ci): use ubuntu 20.04 container * fix(ci): workaround IPv6 being disabled in GHA container networks * refactor(tests): move TEST_MQTT_SERVER to environment variable --- .github/workflows/build_linux.yml | 36 ++++++++++++----- .github/workflows/build_ubuntu2204.yml | 43 +++++++++++++++++++++ tests/pubsub/check_pubsub_connection_mqtt.c | 22 ++++++----- tools/ci.sh | 8 +--- tools/valgrind_check_error.py | 2 +- tools/valgrind_suppressions.supp | 18 --------- 6 files changed, 85 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/build_ubuntu2204.yml diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 5a28d453fda..132149ec9fe 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -9,7 +9,6 @@ jobs: matrix: include: - build_name: "Debug Build & Unit Tests (gcc)" - cmd_deps: sudo apt-get install -y -qq mosquitto cmd_action: unit_tests - build_name: "Debug Build & Unit Tests without Subscriptions (gcc)" cmd_deps: "" @@ -24,10 +23,10 @@ jobs: cmd_deps: "" cmd_action: unit_tests_alarms - build_name: "Debug Build & Unit Tests (clang)" - cmd_deps: sudo apt-get install -y -qq clang-14 clang-tools-14 mosquitto - cmd_action: CC=clang-14 CXX=clang++-14 unit_tests + cmd_deps: sudo apt-get install -y -qq clang-11 clang-tools-11 + cmd_action: CC=clang-11 CXX=clang++-11 unit_tests - build_name: "Debug Build & Unit Tests (tcc)" - cmd_deps: sudo apt-get install -y -qq tcc mosquitto + cmd_deps: sudo apt-get install -y -qq tcc cmd_action: CC=tcc unit_tests - build_name: "Encryption (MbedTLS) Build & Unit Tests (gcc)" cmd_deps: sudo apt-get install -y -qq libmbedtls-dev @@ -53,7 +52,7 @@ jobs: cd ${HOME} git clone https://github.com/tpm2-software/tpm2-tss.git cd ${HOME}/tpm2-tss - git checkout 3.2.3 + git checkout 2.4.6 ./bootstrap && ./configure --with-udevrulesdir=/etc/udev/rules.d --with-udevrulesprefix=70- make -j$(nproc) sudo make install @@ -63,7 +62,7 @@ jobs: cd ${HOME} git clone https://github.com/tpm2-software/tpm2-pkcs11.git cd ${HOME}/tpm2-pkcs11 - git checkout 1.7.0 + git checkout 1.6.0 ./bootstrap && ./configure make -j$(nproc) sudo make install @@ -98,17 +97,36 @@ jobs: cmd_deps: sudo apt-get install -y -qq clang-11 clang-tools-11 libmbedtls-dev cmd_action: build_clang_analyzer name: ${{matrix.build_name}} - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest + container: + image: ghcr.io/marwinglaser/ci:ubuntu-20.04 + options: --privileged + services: + mosquitto: + image: eclipse-mosquitto:1.6-openssl + env: + OPEN62541_TEST_MQTT_BROKER: opc.mqtt://mosquitto:1883 steps: - - uses: actions/checkout@v2 + - name: Work around disabled ipv6 on actions container networks + run: | + IPV6="$(cat /proc/sys/net/ipv6/conf/eth0/disable_ipv6)" + echo "Current IPv6 status on eth0: $IPV6" + [ "$IPV6" = "1" ] || exit + + echo 0 | sudo tee /proc/sys/net/ipv6/conf/eth0/disable_ipv6 > /dev/null + IPV6="$(cat /proc/sys/net/ipv6/conf/eth0/disable_ipv6)" + echo "New IPv6 status on eth0: $IPV6" + [ "$IPV6" = "0" ] || { echo "Failed to enable IPv6 on eth0"; exit 1; } + - uses: actions/checkout@v4 with: submodules: true - name: Install Dependencies run: | sudo apt-get update - sudo apt-get install -y -qq python3-sphinx graphviz check + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq cmake libcap2-bin pkg-config libssl-dev python3-sphinx graphviz check ${{ matrix.cmd_deps }} - name: ${{matrix.build_name}} + shell: bash run: source tools/ci.sh && ${{matrix.cmd_action}} env: ETHERNET_INTERFACE: eth0 diff --git a/.github/workflows/build_ubuntu2204.yml b/.github/workflows/build_ubuntu2204.yml new file mode 100644 index 00000000000..77e4dfeadea --- /dev/null +++ b/.github/workflows/build_ubuntu2204.yml @@ -0,0 +1,43 @@ +name: Linux Build & Test with OpenSSL3.0 + +on: [push, pull_request] + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - build_name: "Encryption (OpenSSL3.0) Build & Unit Tests (gcc)" + cmd_deps: sudo apt-get install -y -qq openssl + cmd_action: unit_tests_encryption OPENSSL + name: ${{matrix.build_name}} + runs-on: ubuntu-latest + container: + image: ghcr.io/marwinglaser/ci:ubuntu-22.04 + options: --privileged + steps: + - name: Work around disabled ipv6 on actions container networks + run: | + IPV6="$(cat /proc/sys/net/ipv6/conf/eth0/disable_ipv6)" + echo "Current IPv6 status on eth0: $IPV6" + [ "$IPV6" = "1" ] || exit + + echo 0 | sudo tee /proc/sys/net/ipv6/conf/eth0/disable_ipv6 > /dev/null + IPV6="$(cat /proc/sys/net/ipv6/conf/eth0/disable_ipv6)" + echo "New IPv6 status on eth0: $IPV6" + [ "$IPV6" = "0" ] || { echo "Failed to enable IPv6 on eth0"; exit 1; } + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Dependencies + run: | + sudo apt-get update + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq cmake pkg-config libssl-dev python3-sphinx graphviz check + ${{ matrix.cmd_deps }} + - name: ${{matrix.build_name}} + shell: bash + run: source tools/ci.sh && ${{matrix.cmd_action}} + env: + ETHERNET_INTERFACE: eth0 + diff --git a/tests/pubsub/check_pubsub_connection_mqtt.c b/tests/pubsub/check_pubsub_connection_mqtt.c index 834caa5c219..a836a8d3515 100644 --- a/tests/pubsub/check_pubsub_connection_mqtt.c +++ b/tests/pubsub/check_pubsub_connection_mqtt.c @@ -15,13 +15,17 @@ #include "ua_server_internal.h" #include - -//#define TEST_MQTT_SERVER "opc.mqtt://test.mosquitto.org:1883" -#define TEST_MQTT_SERVER "opc.mqtt://localhost:1883" +#include UA_Server *server = NULL; UA_ServerConfig *config = NULL; +static char* get_mqtt_broker_address(void) { + char* broker = getenv("OPEN62541_TEST_MQTT_BROKER"); + if (!broker) broker = "opc.mqtt://localhost:1883"; + return broker; +} + static void setup(void) { server = UA_Server_new(); config = UA_Server_getConfig(server); @@ -39,7 +43,7 @@ START_TEST(AddConnectionsWithMinimalValidConfiguration){ memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); connectionConfig.name = UA_STRING("Mqtt Connection"); UA_NetworkAddressUrlDataType networkAddressUrl = - {UA_STRING_NULL, UA_STRING(TEST_MQTT_SERVER)}; + {UA_STRING_NULL, UA_STRING(get_mqtt_broker_address())}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); connectionConfig.transportProfileUri = @@ -60,7 +64,7 @@ START_TEST(AddRemoveAddConnectionWithMinimalValidConfiguration){ memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); connectionConfig.name = UA_STRING("Mqtt Connection"); UA_NetworkAddressUrlDataType networkAddressUrl = - {UA_STRING_NULL, UA_STRING(TEST_MQTT_SERVER)}; + {UA_STRING_NULL, UA_STRING(get_mqtt_broker_address())}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); connectionConfig.transportProfileUri = @@ -86,7 +90,7 @@ START_TEST(AddConnectionWithInvalidAddress){ memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); connectionConfig.name = UA_STRING("MQTT Connection"); UA_NetworkAddressUrlDataType networkAddressUrl = - {UA_STRING_NULL, UA_STRING("opc.mqtt://127.0..1:1883/")}; + {UA_STRING_NULL, UA_STRING(get_mqtt_broker_address())}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); connectionConfig.transportProfileUri = @@ -104,7 +108,7 @@ START_TEST(AddConnectionWithUnknownTransportURL){ memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); connectionConfig.name = UA_STRING("MQTT Connection"); UA_NetworkAddressUrlDataType networkAddressUrl = - {UA_STRING_NULL, UA_STRING(TEST_MQTT_SERVER)}; + {UA_STRING_NULL, UA_STRING(get_mqtt_broker_address())}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); connectionConfig.transportProfileUri = @@ -124,7 +128,7 @@ START_TEST(AddConnectionWithNullConfig){ START_TEST(AddSingleConnectionWithMaximalConfiguration){ UA_NetworkAddressUrlDataType networkAddressUrlData = - {UA_STRING("127.0.0.1"), UA_STRING(TEST_MQTT_SERVER)}; + {UA_STRING("127.0.0.1"), UA_STRING(get_mqtt_broker_address())}; UA_Variant address; UA_Variant_setScalar(&address, &networkAddressUrlData, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_KeyValuePair connectionOptions[3]; @@ -156,7 +160,7 @@ START_TEST(AddSingleConnectionWithMaximalConfiguration){ START_TEST(GetMaximalConnectionConfigurationAndCompareValues){ UA_NetworkAddressUrlDataType networkAddressUrlData = - {UA_STRING("127.0.0.1"), UA_STRING(TEST_MQTT_SERVER)}; + {UA_STRING("127.0.0.1"), UA_STRING(get_mqtt_broker_address())}; UA_Variant address; UA_Variant_setScalar(&address, &networkAddressUrlData, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_KeyValuePair connectionOptions[3]; diff --git a/tools/ci.sh b/tools/ci.sh index 2e1a59b5d1d..b08de97e1d5 100644 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -130,12 +130,6 @@ function set_capabilities { } function unit_tests { - if [ "${CC:-x}" = "tcc" ]; then - PUBSUB_ETHERNET=OFF - else - PUBSUB_ETHERNET=ON - fi - mkdir -p build; cd build; rm -rf * cmake -DCMAKE_BUILD_TYPE=Debug \ -DUA_BUILD_EXAMPLES=ON \ @@ -146,7 +140,7 @@ function unit_tests { -DUA_ENABLE_HISTORIZING=ON \ -DUA_ENABLE_JSON_ENCODING=ON \ -DUA_ENABLE_PUBSUB=ON \ - -DUA_ENABLE_PUBSUB_ETH_UADP=${PUBSUB_ETHERNET} \ + -DUA_ENABLE_PUBSUB_ETH_UADP=ON \ -DUA_ENABLE_PUBSUB_DELTAFRAMES=ON \ -DUA_ENABLE_PUBSUB_INFORMATIONMODEL=ON \ -DUA_ENABLE_PUBSUB_MONITORING=ON \ diff --git a/tools/valgrind_check_error.py b/tools/valgrind_check_error.py index 3bbc2c5e13e..e192cecce3f 100755 --- a/tools/valgrind_check_error.py +++ b/tools/valgrind_check_error.py @@ -60,7 +60,7 @@ def execute(command): # Try to parse the output. Look for the following line: # ==17054== FILE DESCRIPTORS: 5 open at exit. -descriptors_re = re.compile(r".*==(\d+)==\s+FILE DESCRIPTORS: (\d+) open(\s\(\d std\))? at exit\..*") +descriptors_re = re.compile(r".*==(\d+)==\s+FILE DESCRIPTORS: (\d+) open at exit\..*") m = descriptors_re.match(log_content) if not m: diff --git a/tools/valgrind_suppressions.supp b/tools/valgrind_suppressions.supp index b079729b214..591ffa6647e 100644 --- a/tools/valgrind_suppressions.supp +++ b/tools/valgrind_suppressions.supp @@ -10,24 +10,6 @@ } -{ - - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_2.34 - ... - fun:setup* - fun:srunner_run_setup - ... - fun:srunner_run_tagged - fun:main -} - # Custom suppressions added by @Pro From a540be9ce8a64fe856600a404755e4ddf986e9d2 Mon Sep 17 00:00:00 2001 From: Alexander Bluhm Date: Tue, 22 Apr 2025 17:19:26 +0200 Subject: [PATCH 70/98] fix(test): client async connect is not instant Some tests assume that async TCP connect(2) system call succeeds immediately when run over loopback device. This behavior depends on the implementation of the kernel, in OpenBSD this is often not the case. Allow the test client to iterate until the connection is established. Adapt the assertion how many iterations are needed. --- tests/client/check_client.c | 4 ++-- tests/client/check_client_async_connect.c | 6 +++--- tests/client/check_client_subscriptions.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/client/check_client.c b/tests/client/check_client.c index 22b02cdc8d3..4c083a5340d 100644 --- a/tests/client/check_client.c +++ b/tests/client/check_client.c @@ -180,7 +180,7 @@ START_TEST(Client_renewSecureChannel) { UA_fakeSleep((UA_UInt32)((UA_Double)cc->secureChannelLifeTime * 0.8)); /* Make the client renew the channel */ - retval = UA_Client_run_iterate(client, 0); + retval = UA_Client_run_iterate(client, 1); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); /* Now read */ @@ -224,7 +224,7 @@ START_TEST(Client_renewSecureChannelWithActiveSubscription) { for(int i = 0; i < 15; ++i) { UA_fakeSleep(1000); UA_Server_run_iterate(server, true); - retval = UA_Client_run_iterate(client, 0); + retval = UA_Client_run_iterate(client, 1); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } diff --git a/tests/client/check_client_async_connect.c b/tests/client/check_client_async_connect.c index e9045ff73cc..2a5d2472baa 100644 --- a/tests/client/check_client_async_connect.c +++ b/tests/client/check_client_async_connect.c @@ -90,8 +90,8 @@ START_TEST(Client_connect_async) { UA_BrowseRequest_clear(&bReq); ck_assert_uint_eq(connected, true); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); - /* With default setting the client uses 7 iterations to connect */ - ck_assert_uint_eq(asyncCounter, 10-7); + /* With default setting the client uses 7 or 8 iterations to connect */ + ck_assert(asyncCounter == 10-7 || asyncCounter == 10-8); UA_Client_disconnectAsync(client); while(connected) { UA_Server_run_iterate(server, false); @@ -149,7 +149,7 @@ START_TEST(Client_no_connection) { //simulating unconnected server UA_Client_recvTesting_result = UA_STATUSCODE_BADCONNECTIONCLOSED; UA_Server_run_iterate(server, false); - retval = UA_Client_run_iterate(client, 0); /* Open connection */ + retval = UA_Client_run_iterate(client, 1); /* Open connection */ UA_Server_run_iterate(server, false); retval |= UA_Client_run_iterate(client, 0); /* Send HEL */ UA_Server_run_iterate(server, false); diff --git a/tests/client/check_client_subscriptions.c b/tests/client/check_client_subscriptions.c index 6eb101e41d5..8c81e39adce 100644 --- a/tests/client/check_client_subscriptions.c +++ b/tests/client/check_client_subscriptions.c @@ -209,7 +209,7 @@ START_TEST(Client_subscription_async) { ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_Server_run_iterate(server, true); - UA_Client_run_iterate(client, 0); + UA_Client_run_iterate(client, 1); ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD); UA_UInt32 subId = response.subscriptionId; From 4874837ea15fd83a346684bfc2c1be1ec664695d Mon Sep 17 00:00:00 2001 From: Alexander Bluhm Date: Wed, 20 Jul 2022 13:07:38 +0200 Subject: [PATCH 71/98] fix(client): use after free in client asyncServiceCalls Commit de9d691906547c9fc99e0a77198a80fe5bba54b1 fixed a use after free in UA_Client_AsyncService_cancel(). Move all elements to a local list before iterating over the callbacks. Commit 713cdb419f0f844517afc549c7c1ef48d8498cfb fixed the same bug in in asyncServiceTimeoutCheck(). After timeout, remove the async service calls from the global list and store them in a local one. Call UA_Client_AsyncService_cancel() and UA_free() while traversing this local list. Otherwise the callback could free a global list element that asyncServiceTimeoutCheck() is referencing. --- src/client/ua_client.c | 26 +++++++++++++++++++++++--- src/client/ua_client_internal.h | 4 +++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/client/ua_client.c b/src/client/ua_client.c index 778d1a6365d..cfbadfa9e2a 100644 --- a/src/client/ua_client.c +++ b/src/client/ua_client.c @@ -515,8 +515,17 @@ UA_Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac, } void UA_Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode) { + /* Make this function reentrant. One of the async callbacks could indirectly + * operate on the list. Moving all elements to a local list before iterating + * that. */ + UA_AsyncServiceList asyncServiceCalls = client->asyncServiceCalls; + LIST_INIT(&client->asyncServiceCalls); + if(asyncServiceCalls.lh_first) + asyncServiceCalls.lh_first->pointers.le_prev = &asyncServiceCalls.lh_first; + + /* Cancel and remove the elements from the local list */ AsyncServiceCall *ac, *ac_tmp; - LIST_FOREACH_SAFE(ac, &client->asyncServiceCalls, pointers, ac_tmp) { + LIST_FOREACH_SAFE(ac, &asyncServiceCalls, pointers, ac_tmp) { LIST_REMOVE(ac, pointers); UA_Client_AsyncService_cancel(client, ac, statusCode); UA_free(ac); @@ -627,17 +636,28 @@ UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId) { static void asyncServiceTimeoutCheck(UA_Client *client) { + /* Make this function reentrant. One of the async callbacks could indirectly + * operate on the list. Moving all elements to a local list before iterating + * that. */ + UA_AsyncServiceList asyncServiceCalls; AsyncServiceCall *ac, *ac_tmp; UA_DateTime now = UA_DateTime_nowMonotonic(); + LIST_INIT(&asyncServiceCalls); LIST_FOREACH_SAFE(ac, &client->asyncServiceCalls, pointers, ac_tmp) { if(!ac->timeout) continue; if(ac->start + (UA_DateTime)(ac->timeout * UA_DATETIME_MSEC) <= now) { LIST_REMOVE(ac, pointers); - UA_Client_AsyncService_cancel(client, ac, UA_STATUSCODE_BADTIMEOUT); - UA_free(ac); + LIST_INSERT_HEAD(&asyncServiceCalls, ac, pointers); } } + + /* Cancel and remove the elements from the local list */ + LIST_FOREACH_SAFE(ac, &asyncServiceCalls, pointers, ac_tmp) { + LIST_REMOVE(ac, pointers); + UA_Client_AsyncService_cancel(client, ac, UA_STATUSCODE_BADTIMEOUT); + UA_free(ac); + } } static void diff --git a/src/client/ua_client_internal.h b/src/client/ua_client_internal.h index f4a58c777dc..96901a13008 100644 --- a/src/client/ua_client_internal.h +++ b/src/client/ua_client_internal.h @@ -95,6 +95,8 @@ void UA_Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac, UA_StatusCode statusCode); +typedef LIST_HEAD(UA_AsyncServiceList, AsyncServiceCall) UA_AsyncServiceList; + void UA_Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode); @@ -147,7 +149,7 @@ struct UA_Client { UA_Boolean pendingConnectivityCheck; /* Async Service */ - LIST_HEAD(, AsyncServiceCall) asyncServiceCalls; + UA_AsyncServiceList asyncServiceCalls; /* Subscriptions */ #ifdef UA_ENABLE_SUBSCRIPTIONS From 62122caa5fb08185c873078b4fd45807c0404d2d Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 27 May 2025 23:10:02 +0200 Subject: [PATCH 72/98] fix(server): Check the NodeClass before processing an async method --- src/server/ua_services_method.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/server/ua_services_method.c b/src/server/ua_services_method.c index 3418e5855de..0bcdf07941a 100644 --- a/src/server/ua_services_method.c +++ b/src/server/ua_services_method.c @@ -350,6 +350,13 @@ Operation_CallMethodAsync(UA_Server *server, UA_Session *session, UA_UInt32 requ goto cleanup; } + /* Check the NodeClass */ + if(method->head.nodeClass != UA_NODECLASS_METHOD || + object->head.nodeClass != UA_NODECLASS_OBJECT) { + opResult->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; + goto cleanup; + } + /* <-- Async method call --> */ /* No AsyncResponse allocated so far */ From ce345f9f73c3f5a84c4921c92a35e03629f9993f Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 27 May 2025 19:29:52 +0200 Subject: [PATCH 73/98] fix(server): Check access rights for async method execution --- src/server/ua_services_method.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/server/ua_services_method.c b/src/server/ua_services_method.c index 0bcdf07941a..6381df7a314 100644 --- a/src/server/ua_services_method.c +++ b/src/server/ua_services_method.c @@ -357,6 +357,21 @@ Operation_CallMethodAsync(UA_Server *server, UA_Session *session, UA_UInt32 requ goto cleanup; } + /* Check the access rights */ + UA_Boolean executable = method->methodNode.executable; + if(session != &server->adminSession) { + executable = executable && server->config.accessControl. + getUserExecutableOnObject(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + &opRequest->methodId, method->head.context, + &opRequest->objectId, object->head.context); + } + + if(!executable) { + opResult->statusCode = UA_STATUSCODE_BADNOTEXECUTABLE; + goto cleanup; + } + /* <-- Async method call --> */ /* No AsyncResponse allocated so far */ From 02fbcc243cffe170b9dc5fe2e04982ee843b53a4 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Tue, 27 May 2025 20:30:59 +0200 Subject: [PATCH 74/98] feat(tests): Add a test for UA_Server_getSessionParameter --- tests/server/check_accesscontrol.c | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/server/check_accesscontrol.c b/tests/server/check_accesscontrol.c index 9706e8af2a4..1c5f2ddc4f4 100644 --- a/tests/server/check_accesscontrol.c +++ b/tests/server/check_accesscontrol.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -85,6 +86,64 @@ START_TEST(Client_pass_fail) { UA_Client_delete(client); } END_TEST +static UA_Boolean +allowBrowseNode(UA_Server *s, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext) { + UA_Variant attribute; + UA_Variant_init(&attribute); + UA_Server_getSessionParameter(s, sessionId, "my_custom_attribute", &attribute); + return true; +} + +static void setCustomAccessControl(UA_ServerConfig* config) { + UA_Boolean allowAnonymous = true; + UA_AccessControl_default(config, allowAnonymous, NULL, NULL, 0, NULL); + config->accessControl.allowBrowseNode = allowBrowseNode; +} + +START_TEST(Server_sessionParameter) { + server = UA_Server_new(); + UA_ServerConfig *config = UA_Server_getConfig(server); + UA_ServerConfig_setDefault(config); + setCustomAccessControl(config); + UA_Server_run_startup(server); + + running = true; + THREAD_CREATE(server_thread, serverloop); + + UA_Client *client = UA_Client_new(); + UA_ClientConfig_setDefault(UA_Client_getConfig(client)); + UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); + + ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); + + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER); + bd.browseDirection = UA_BROWSEDIRECTION_BOTH; + bd.includeSubtypes = true; + bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); + + UA_BrowseRequest request; + UA_BrowseRequest_init(&request); + request.nodesToBrowse = &bd; + request.nodesToBrowseSize = 1; + + UA_BrowseResponse br = UA_Client_Service_browse(client, request); + UA_assert(br.resultsSize == 1); + UA_assert(br.results[0].referencesSize > 0); + UA_assert(br.results[0].statusCode == UA_STATUSCODE_GOOD); + UA_BrowseResponse_clear(&br); + + UA_Client_disconnect(client); + UA_Client_delete(client); + + running = false; + THREAD_JOIN(server_thread); + UA_Server_run_shutdown(server); + UA_Server_delete(server); +} END_TEST static Suite* testSuite_Client(void) { Suite *s = suite_create("Client"); @@ -95,6 +154,10 @@ static Suite* testSuite_Client(void) { tcase_add_test(tc_client_user, Client_user_fail); tcase_add_test(tc_client_user, Client_pass_fail); suite_add_tcase(s,tc_client_user); + + TCase *tc_server = tcase_create("Server-Side Access Control"); + tcase_add_test(tc_server, Server_sessionParameter); + suite_add_tcase(s,tc_server); return s; } From 199a59af17f3ef33aa7eb87bb81109d2a181b35a Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Thu, 9 Oct 2025 08:39:43 +0200 Subject: [PATCH 75/98] fix(server): Fix a locking issue in browseWithContinuation --- src/server/ua_services_view.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/server/ua_services_view.c b/src/server/ua_services_view.c index c8f632588a1..9b0436c2c51 100644 --- a/src/server/ua_services_view.c +++ b/src/server/ua_services_view.c @@ -675,14 +675,17 @@ browseWithContinuation(UA_Server *server, UA_Session *session, return true; } - if(session != &server->adminSession && - !server->config.accessControl. - allowBrowseNode(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, - &descr->nodeId, node->head.context)) { - result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED; - UA_NODESTORE_RELEASE(server, node); - return true; + if(session != &server->adminSession) { + UA_UNLOCK(&server->serviceMutex); + UA_Boolean allowed = server->config.accessControl.allowBrowseNode( + server, &server->config.accessControl, &session->sessionId, + session->sessionHandle, &descr->nodeId, node->head.context); + UA_LOCK(&server->serviceMutex); + if(!allowed) { + result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED; + UA_NODESTORE_RELEASE(server, node); + return true; + } } RefResult rr; From d10add6fc53d65a00964a774dd6329d00ba15123 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 29 Sep 2024 23:02:32 +0200 Subject: [PATCH 76/98] fix(core): Ensure that only quiet NAN are used for float/double This was problematic on MSVC where different NAN representations can be used as default. --- src/ua_types_encoding_binary.c | 46 +++++++++++++++++++++++----------- tests/check_types_builtin.c | 4 --- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/ua_types_encoding_binary.c b/src/ua_types_encoding_binary.c index ac3f7165b16..65de4375803 100644 --- a/src/ua_types_encoding_binary.c +++ b/src/ua_types_encoding_binary.c @@ -281,16 +281,14 @@ DECODE_BINARY(UInt64) { /************************/ /* Can we reuse the integer encoding mechanism by casting floating point - * values? */ -#if (UA_FLOAT_IEEE754 == 1) && (UA_LITTLE_ENDIAN == UA_FLOAT_LITTLE_ENDIAN) -# define Float_encodeBinary UInt32_encodeBinary -# define Float_decodeBinary UInt32_decodeBinary -# define Double_encodeBinary UInt64_encodeBinary -# define Double_decodeBinary UInt64_decodeBinary -#else + * values? For single float values we ensure that only quiet NAN are used. + * For float arrays we want to have the speed advantage of just memcpy (if + * the processor architecture uses IEE754). We get array-memcpy by the + * "overlayable" bit in the datatype description. */ +#if (UA_FLOAT_IEEE754 < 1) || (UA_LITTLE_ENDIAN != UA_FLOAT_LITTLE_ENDIAN) #include - +#define UA_SLOW_IEEE754 1 #pragma message "No native IEEE 754 format detected. Use slow generic encoding." /* Handling of IEEE754 floating point values was taken from Beej's Guide to @@ -326,6 +324,8 @@ unpack754(uint64_t i, unsigned bits, unsigned expbits) { return result; } +#endif + /* Float */ #define FLOAT_NAN 0xffc00000 #define FLOAT_INF 0x7f800000 @@ -335,19 +335,26 @@ unpack754(uint64_t i, unsigned bits, unsigned expbits) { ENCODE_BINARY(Float) { UA_Float f = *src; u32 encoded; - /* cppcheck-suppress duplicateExpression */ - if(f != f) encoded = FLOAT_NAN; + if(UA_UNLIKELY(f != f)) encoded = FLOAT_NAN; /* quit NAN */ +#ifndef UA_SLOW_IEEE754 + else memcpy(&encoded, &f, sizeof(UA_Float)); +#else else if(f == 0.0f) encoded = signbit(f) ? FLOAT_NEG_ZERO : 0; else if(f/f != f/f) encoded = f > 0 ? FLOAT_INF : FLOAT_NEG_INF; else encoded = (u32)pack754(f, 32, 8); +#endif return ENCODE_DIRECT(&encoded, UInt32); } DECODE_BINARY(Float) { u32 decoded; status ret = DECODE_DIRECT(&decoded, UInt32); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); +#ifndef UA_SLOW_IEEE754 + if(UA_UNLIKELY((decoded >= 0x7f800001 && decoded <= 0x7fffffff) || + (decoded >= 0xff800001))) decoded = FLOAT_NAN; + memcpy(dst, &decoded, sizeof(UA_Float)); +#else if(decoded == 0) *dst = 0.0f; else if(decoded == FLOAT_NEG_ZERO) *dst = -0.0f; else if(decoded == FLOAT_INF) *dst = INFINITY; @@ -355,6 +362,7 @@ DECODE_BINARY(Float) { else if((decoded >= 0x7f800001 && decoded <= 0x7fffffff) || (decoded >= 0xff800001)) *dst = NAN; else *dst = (UA_Float)unpack754(decoded, 32, 8); +#endif return UA_STATUSCODE_GOOD; } @@ -368,10 +376,14 @@ ENCODE_BINARY(Double) { UA_Double d = *src; u64 encoded; /* cppcheck-suppress duplicateExpression */ - if(d != d) encoded = DOUBLE_NAN; + if(UA_UNLIKELY(d != d)) encoded = DOUBLE_NAN; /* quiet NAN*/ +#ifndef UA_SLOW_IEEE754 + else memcpy(&encoded, &d, sizeof(UA_Double)); +#else else if(d == 0.0) encoded = signbit(d) ? DOUBLE_NEG_ZERO : 0; else if(d/d != d/d) encoded = d > 0 ? DOUBLE_INF : DOUBLE_NEG_INF; else encoded = pack754(d, 64, 11); + #endif return ENCODE_DIRECT(&encoded, UInt64); } @@ -379,6 +391,11 @@ DECODE_BINARY(Double) { u64 decoded; status ret = DECODE_DIRECT(&decoded, UInt64); UA_CHECK_STATUS(ret, return ret); +#ifndef UA_SLOW_IEEE754 + if(UA_UNLIKELY((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) || + (decoded >= 0xfff0000000000001L))) decoded = DOUBLE_NAN; + memcpy(dst, &decoded, sizeof(UA_Double)); +#else if(decoded == 0) *dst = 0.0; else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0; else if(decoded == DOUBLE_INF) *dst = INFINITY; @@ -386,11 +403,10 @@ DECODE_BINARY(Double) { else if((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) || (decoded >= 0xfff0000000000001L)) *dst = NAN; else *dst = (UA_Double)unpack754(decoded, 64, 11); +#endif return UA_STATUSCODE_GOOD; } -#endif - /******************/ /* Array Handling */ /******************/ diff --git a/tests/check_types_builtin.c b/tests/check_types_builtin.c index ef124812bb5..a365cc1266c 100644 --- a/tests/check_types_builtin.c +++ b/tests/check_types_builtin.c @@ -809,10 +809,6 @@ START_TEST(UA_Float_encodeShallWorkOnExample) { {0x00, 0x00, 0x80, 0x7F}, // INF {0x00, 0x00, 0x80, 0xFF} // -INF }; -#if defined(_MSC_VER) - /* On Visual Studio, -NAN is encoded differently */ - result[4][3] = 127; -#endif UA_Byte data[] = {0x55, 0x55, 0x55, 0x55}; UA_ByteString dst = {4, data}; From f1eed9d6aef91444a206cfae66f62b2dadf1bef0 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 8 Oct 2025 23:02:27 +0200 Subject: [PATCH 77/98] fix(build): Pacify compiler warnings related to goto (but harmless) --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 002efecb75b..0aa73c0d09f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -690,6 +690,12 @@ if(NOT UA_FORCE_CPP AND (CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" ST # Use a strict subset of the C and C++ languages check_add_cc_flag("-Wc++-compat") + # Wc++-compat enables additional goto/jump restrictions. + # But modern compilers do a detailed analysis of values + # are actually used uninitialized after a jump: + # TODO: The following flag should not be required + check_add_cc_flag("-Wno-jump-misses-init") + # Check that format strings (printf/scanf) are sane check_add_cc_flag("-Wformat") check_add_cc_flag("-Wformat-security") From 59d7cc5f2124b9721dd4e5c8f3056d3eb470455d Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 8 Oct 2025 23:34:38 +0200 Subject: [PATCH 78/98] fix(plugins): Pacify a clang warning in ua_pki_mbedtls.c --- plugins/crypto/mbedtls/ua_pki_mbedtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/crypto/mbedtls/ua_pki_mbedtls.c b/plugins/crypto/mbedtls/ua_pki_mbedtls.c index 8ab41285f65..bcd4c04f720 100644 --- a/plugins/crypto/mbedtls/ua_pki_mbedtls.c +++ b/plugins/crypto/mbedtls/ua_pki_mbedtls.c @@ -42,7 +42,7 @@ UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l const unsigned char *ss2 = s2; /* handle special case */ if(l1 == 0) - return (NULL); + return NULL; if(l2 == 0) return s1; From e5a7dc0653de8513e045421457f908be194a68b8 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 20 Oct 2025 14:07:58 +0200 Subject: [PATCH 79/98] refactor(build): Bump the release version to v1.3.16 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aa73c0d09f..e9f0b9ea5b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 15) +set(OPEN62541_VER_PATCH 16) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 1aceacf57fcbea1054611fb066d521dd5981127a Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 5 Nov 2025 10:31:20 +0100 Subject: [PATCH 80/98] fix(plugins): Use the session parameters feature instead of storing data in the SessionContext This fixes #7361 --- plugins/ua_accesscontrol_default.c | 60 ++++++++++++++++++++------- src/server/ua_services_subscription.c | 19 ++++++--- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/plugins/ua_accesscontrol_default.c b/plugins/ua_accesscontrol_default.c index c3e9183486e..bc11203d7c0 100644 --- a/plugins/ua_accesscontrol_default.c +++ b/plugins/ua_accesscontrol_default.c @@ -53,6 +53,13 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac, /* No userdata atm */ *sessionContext = NULL; + + /* Set the clientUserId to the empty string for anonymous */ + UA_String emptyStr = UA_STRING_NULL; + UA_Variant userIdVar; + UA_Variant_setScalar(&userIdVar, &emptyStr, &UA_TYPES[UA_TYPES_STRING]); + UA_Server_setSessionParameter(server, sessionId, "clientUserId", &userIdVar); + return UA_STATUSCODE_GOOD; } @@ -76,6 +83,13 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac, /* No userdata atm */ *sessionContext = NULL; + + /* Set the clientUserId to the empty string for anonymous */ + UA_String emptyStr = UA_STRING_NULL; + UA_Variant userIdVar; + UA_Variant_setScalar(&userIdVar, &emptyStr, &UA_TYPES[UA_TYPES_STRING]); + UA_Server_setSessionParameter(server, sessionId, "clientUserId", &userIdVar); + return UA_STATUSCODE_GOOD; } @@ -99,8 +113,8 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac, UA_Boolean match = false; if(context->loginCallback) { if(context->loginCallback(&userToken->userName, &userToken->password, - context->usernamePasswordLoginSize, context->usernamePasswordLogin, - sessionContext, context->loginContext) == UA_STATUSCODE_GOOD) + context->usernamePasswordLoginSize, context->usernamePasswordLogin, + sessionContext, context->loginContext) == UA_STATUSCODE_GOOD) match = true; } else { for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) { @@ -114,11 +128,10 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac, if(!match) return UA_STATUSCODE_BADUSERACCESSDENIED; - /* For the CTT, recognize whether two sessions are */ - UA_ByteString *username = UA_ByteString_new(); - if(username) - UA_ByteString_copy(&userToken->userName, username); - *sessionContext = username; + /* Set the clientUserId to the username */ + UA_Variant userIdVar; + UA_Variant_setScalar(&userIdVar, (void*)(uintptr_t)&userToken->userName, &UA_TYPES[UA_TYPES_STRING]); + UA_Server_setSessionParameter(server, sessionId, "clientUserId", &userIdVar); return UA_STATUSCODE_GOOD; } @@ -133,9 +146,18 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac, if(!context->verifyX509.verifyCertificate) return UA_STATUSCODE_BADIDENTITYTOKENINVALID; - return context->verifyX509. + UA_Boolean verified = + context->verifyX509. verifyCertificate(context->verifyX509.context, &userToken->certificateData); + if(!verified) + return false; + + /* Set the clientUserId to the certificate data */ + UA_Variant userIdVar; + UA_Variant_setScalar(&userIdVar, (void*)(uintptr_t)&userToken->certificateData, &UA_TYPES[UA_TYPES_BYTESTRING]); + UA_Server_setSessionParameter(server, sessionId, "clientUserId", &userIdVar); + return true; } /* Unsupported token type */ @@ -145,8 +167,6 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac, static void closeSession_default(UA_Server *server, UA_AccessControl *ac, const UA_NodeId *sessionId, void *sessionContext) { - if(sessionContext) - UA_ByteString_delete((UA_ByteString*)sessionContext); } static UA_UInt32 @@ -218,12 +238,20 @@ static UA_Boolean allowTransferSubscription_default(UA_Server *server, UA_AccessControl *ac, const UA_NodeId *oldSessionId, void *oldSessionContext, const UA_NodeId *newSessionId, void *newSessionContext) { - if(oldSessionContext == newSessionContext) - return true; - if(oldSessionContext && newSessionContext) - return UA_ByteString_equal((UA_ByteString*)oldSessionContext, - (UA_ByteString*)newSessionContext); - return false; + UA_Variant userId1; + UA_Variant userId2; + UA_Variant_init(&userId1); + UA_Variant_init(&userId2); + + UA_StatusCode res = UA_STATUSCODE_GOOD; + res |= UA_Server_getSessionParameter(server, oldSessionId, "userClientId", &userId1); + res |= UA_Server_getSessionParameter(server, newSessionId, "userClientId", &userId2); + + UA_Boolean allow = (res == UA_STATUSCODE_GOOD && + UA_order(&userId1, &userId2, &UA_TYPES[UA_TYPES_VARIANT]) == UA_ORDER_EQ); + UA_Variant_clear(&userId1); + UA_Variant_clear(&userId2); + return allow; } #endif diff --git a/src/server/ua_services_subscription.c b/src/server/ua_services_subscription.c index cb485c7705b..ecec4b151bc 100644 --- a/src/server/ua_services_subscription.c +++ b/src/server/ua_services_subscription.c @@ -482,12 +482,19 @@ Operation_TransferSubscription(UA_Server *server, UA_Session *session, } /* Check with AccessControl if the transfer is allowed */ - if(!server->config.accessControl.allowTransferSubscription || - !server->config.accessControl. - allowTransferSubscription(server, &server->config.accessControl, - oldSession ? &oldSession->sessionId : NULL, - oldSession ? oldSession->sessionHandle : NULL, - &session->sessionId, session->sessionHandle)) { + UA_Boolean transferAllowed = + (server->config.accessControl.allowTransferSubscription != NULL); + if(transferAllowed) { + UA_UNLOCK(&server->serviceMutex); + transferAllowed = server->config.accessControl. + allowTransferSubscription(server, &server->config.accessControl, + oldSession ? &oldSession->sessionId : NULL, + oldSession ? oldSession->sessionHandle : NULL, + &session->sessionId, session->sessionHandle); + UA_LOCK(&server->serviceMutex); + } + + if(!transferAllowed) { result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED; return; } From 51ff6593ec45880342e039adb761f8ec79af2713 Mon Sep 17 00:00:00 2001 From: Marvin Gnad Date: Mon, 19 May 2025 13:41:53 +0200 Subject: [PATCH 81/98] fix(plugin): fix namelist allocated from scandir not freed (cherry picked from commit bcb02196fbed8ba2fd77eb0d119372b6f74c9760) --- plugins/crypto/openssl/ua_pki_openssl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/crypto/openssl/ua_pki_openssl.c b/plugins/crypto/openssl/ua_pki_openssl.c index 40cec466e7e..1ad5c1fc909 100644 --- a/plugins/crypto/openssl/ua_pki_openssl.c +++ b/plugins/crypto/openssl/ua_pki_openssl.c @@ -312,6 +312,10 @@ UA_ReloadCertFromFolder (CertContext * ctx) { } UA_ByteString_clear (&strCert); } + for (i = 0; i < numCertificates; i++) { + free(dirlist[i]); + } + free(dirlist); } if (ctx->issuerListFolder.length > 0) { @@ -347,6 +351,10 @@ UA_ReloadCertFromFolder (CertContext * ctx) { } UA_ByteString_clear (&strCert); } + for (i = 0; i < numCertificates; i++) { + free(dirlist[i]); + } + free(dirlist); } if (ctx->revocationListFolder.length > 0) { @@ -382,6 +390,10 @@ UA_ReloadCertFromFolder (CertContext * ctx) { } UA_ByteString_clear (&strCert); } + for (i = 0; i < numCertificates; i++) { + free(dirlist[i]); + } + free(dirlist); } ret = UA_STATUSCODE_GOOD; From ff411f0734c4438e20ec89bc14c4c084d61ae73f Mon Sep 17 00:00:00 2001 From: dpazj Date: Wed, 14 Jan 2026 12:57:16 +0000 Subject: [PATCH 82/98] fix(server): Avoid comparing a scalar value and a null-array when detecting deadband value changes --- src/server/ua_subscription_datachange.c | 13 +++- tests/server/check_monitoreditem_filter.c | 84 +++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/server/ua_subscription_datachange.c b/src/server/ua_subscription_datachange.c index 5fb1fe6dbb4..677b7d6de80 100644 --- a/src/server/ua_subscription_datachange.c +++ b/src/server/ua_subscription_datachange.c @@ -54,13 +54,20 @@ detectScalarDeadBand(const void *data1, const void *data2, static UA_Boolean detectVariantDeadband(const UA_Variant *value, const UA_Variant *oldValue, const UA_Double deadbandValue) { + /* Be careful to avoid a NULL access. We could have the value a scalar and + * oldValue an empty array. Both define a type and arrayLength == 0. */ if(value->arrayLength != oldValue->arrayLength) return true; if(value->type != oldValue->type) return true; + if(UA_Variant_isScalar(value) != UA_Variant_isScalar(oldValue)) + return true; + + /* Treat scalars as an array of length 1 and iterate */ size_t length = 1; if(!UA_Variant_isScalar(value)) length = value->arrayLength; + uintptr_t data = (uintptr_t)value->data; uintptr_t oldData = (uintptr_t)oldValue->data; UA_UInt32 memSize = value->type->memSize; @@ -103,6 +110,10 @@ detectValueChange(UA_Server *server, UA_MonitoredItem *mon, UA_assert(trigger == UA_DATACHANGETRIGGER_STATUSVALUE || trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP); + /* Can we compare values? */ + if(value->hasValue != mon->lastValue.hasValue) + return true; + /* Test absolute deadband */ if(dcf && dcf->deadbandType == UA_DEADBANDTYPE_ABSOLUTE && value->value.type != NULL && UA_DataType_isNumeric(value->value.type)) @@ -119,8 +130,6 @@ detectValueChange(UA_Server *server, UA_MonitoredItem *mon, } /* Has the value changed? */ - if(value->hasValue != mon->lastValue.hasValue) - return true; return (UA_order(&value->value, &mon->lastValue.value, &UA_TYPES[UA_TYPES_VARIANT]) != UA_ORDER_EQ); } diff --git a/tests/server/check_monitoreditem_filter.c b/tests/server/check_monitoreditem_filter.c index 3176a74c13a..f43babe5335 100644 --- a/tests/server/check_monitoreditem_filter.c +++ b/tests/server/check_monitoreditem_filter.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "client/ua_client_internal.h" @@ -915,6 +916,84 @@ START_TEST(Server_MonitoredItemsAbsoluteFilterSetOnCreate) { } END_TEST +static UA_StatusCode +setEmptyArray(UA_Client *thisClient, UA_NodeId node) { + UA_Variant variant; + UA_Variant_init (&variant); + UA_Variant_setArray(&variant, NULL, 0, &UA_TYPES[UA_TYPES_DOUBLE]); + return UA_Client_writeValueAttribute(thisClient, node, &variant); +} + +START_TEST(Server_MonitoredItemsAbsoluteFilterNULLValue) { + UA_DataValue_init(&lastValue); + /* define a monitored item with an absolute filter with deadbandvalue = 2.0 */ + UA_MonitoredItemCreateRequest item = UA_MonitoredItemCreateRequest_default(outNodeId); + UA_DataChangeFilter filter; + UA_DataChangeFilter_init(&filter); + filter.trigger = UA_DATACHANGETRIGGER_STATUSVALUE; + filter.deadbandType = UA_DEADBANDTYPE_ABSOLUTE; + filter.deadbandValue = 2.0; + item.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED; + item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGEFILTER]; + item.requestedParameters.filter.content.decoded.data = &filter; + UA_UInt32 newMonitoredItemIds[1]; + UA_Client_DataChangeNotificationCallback callbacks[1]; + callbacks[0] = dataChangeHandler; + UA_Client_DeleteMonitoredItemCallback deleteCallbacks[1] = {NULL}; + void *contexts[1]; + contexts[0] = NULL; + + /* Set empty array value so that the initial value data ptr for the monitored item is NULL */ + ck_assert_uint_eq(setEmptyArray(client, outNodeId), UA_STATUSCODE_GOOD); + + UA_CreateMonitoredItemsRequest createRequest; + UA_CreateMonitoredItemsRequest_init(&createRequest); + createRequest.subscriptionId = subId; + createRequest.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH; + createRequest.itemsToCreate = &item; + createRequest.itemsToCreateSize = 1; + UA_CreateMonitoredItemsResponse createResponse = + UA_Client_MonitoredItems_createDataChanges(client, createRequest, contexts, + callbacks, deleteCallbacks); + + ck_assert_uint_eq(createResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD); + ck_assert_uint_eq(createResponse.resultsSize, 1); + ck_assert_uint_eq(createResponse.results[0].statusCode, UA_STATUSCODE_GOOD); + newMonitoredItemIds[0] = createResponse.results[0].monitoredItemId; + UA_CreateMonitoredItemsResponse_clear(&createResponse); + + // Do we get initial value ? + notificationReceived = false; + countNotificationReceived = 0; + ck_assert_uint_eq(waitForNotification(1, 10), UA_STATUSCODE_GOOD); + ck_assert_uint_eq(notificationReceived, true); + ck_assert_uint_eq(countNotificationReceived, 1); + ck_assert(lastValue.value.data == NULL); + + notificationReceived = false; + ck_assert_uint_eq(setDouble(client, outNodeId, 42.0), UA_STATUSCODE_GOOD); + ck_assert_uint_eq(waitForNotification(1, 10), UA_STATUSCODE_GOOD); + ck_assert_uint_eq(notificationReceived, true); + ck_assert_uint_eq(countNotificationReceived, 2); + + // remove monitored item + UA_DeleteMonitoredItemsRequest deleteRequest; + UA_DeleteMonitoredItemsRequest_init(&deleteRequest); + deleteRequest.subscriptionId = subId; + deleteRequest.monitoredItemIds = newMonitoredItemIds; + deleteRequest.monitoredItemIdsSize = 1; + + UA_DeleteMonitoredItemsResponse deleteResponse = + UA_Client_MonitoredItems_delete(client, deleteRequest); + + ck_assert_uint_eq(deleteResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD); + ck_assert_uint_eq(deleteResponse.resultsSize, 1); + ck_assert_uint_eq(deleteResponse.results[0], UA_STATUSCODE_GOOD); + + UA_DeleteMonitoredItemsResponse_clear(&deleteResponse); +} +END_TEST + START_TEST(Server_MonitoredItemsPercentFilterSetOnCreateMissingEURange) { UA_DataValue_init(&lastValue); /* define a monitored item with an percent filter with deadbandvalue = 2.0 */ @@ -1130,11 +1209,16 @@ static Suite* testSuite_Client(void) { tcase_add_test(tc_server, Server_MonitoredItemsAbsoluteFilterSetOnCreateRemoveLater); tcase_add_test(tc_server, Server_MonitoredItemsPercentFilterSetOnCreateMissingEURange); tcase_add_test(tc_server, Server_MonitoredItemsPercentFilterSetLaterMissingEURange); + + + tcase_add_test(tc_server, Server_MonitoredItemsAbsoluteFilterNULLValue); + #ifdef UA_ENABLE_DA tcase_add_test(tc_server, Server_MonitoredItemsPercentFilterSetOnCreate); tcase_add_test(tc_server, Server_MonitoredItemsPercentFilterSetOnCreateDeadBandValueOutOfRange); #endif /* UA_ENABLE_DA */ #endif /* UA_ENABLE_SUBSCRIPTIONS */ + suite_add_tcase(s, tc_server); return s; From 41f4deef34a9d0f94fcb830e2c831a9eb6236ade Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 2 Feb 2026 21:06:41 +0100 Subject: [PATCH 83/98] refactor(build): Bump version to v1.3.17 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9f0b9ea5b1..cf4c4fd65ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 16) +set(OPEN62541_VER_PATCH 17) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From d6fb639f29b964fc68f2e443b461f60456424810 Mon Sep 17 00:00:00 2001 From: "aaghash.r" Date: Tue, 10 Mar 2026 03:11:12 +0530 Subject: [PATCH 84/98] fix(client): update status codes for error masking --- src/client/ua_client.c | 1 - tests/client/check_client_securechannel.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/client/ua_client.c b/src/client/ua_client.c index cfbadfa9e2a..73d291b9c11 100644 --- a/src/client/ua_client.c +++ b/src/client/ua_client.c @@ -437,7 +437,6 @@ receiveResponse(UA_Client *client, void *response, const UA_DataType *responseTy "Receiving the response failed with StatusCode %s", UA_StatusCode_name(retval)); closeSecureChannel(client); - retval = UA_STATUSCODE_BADCONNECTIONCLOSED; break; } now = UA_DateTime_nowMonotonic(); diff --git a/tests/client/check_client_securechannel.c b/tests/client/check_client_securechannel.c index a536912f507..f6bd96955e7 100644 --- a/tests/client/check_client_securechannel.c +++ b/tests/client/check_client_securechannel.c @@ -160,7 +160,7 @@ START_TEST(SecureChannel_networkfail) { UA_Variant_init(&val); UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); retval = UA_Client_readValueAttribute(client, nodeId, &val); - ck_assert(retval == UA_STATUSCODE_BADCONNECTIONCLOSED); + ck_assert(retval == UA_STATUSCODE_BADSECURECHANNELCLOSED); UA_Client_disconnect(client); UA_Client_delete(client); @@ -205,7 +205,7 @@ START_TEST(SecureChannel_cableunplugged) { client->connection.recv = UA_Client_recvTesting; /* Simulate network cable unplugged (no response from server) */ - UA_Client_recvTesting_result = UA_STATUSCODE_BADINTERNALERROR; + UA_Client_recvTesting_result = UA_STATUSCODE_BADCONNECTIONCLOSED; UA_Variant_init(&val); retval = UA_Client_readValueAttribute(client, nodeId, &val); From 20b9990c5ee88a654a508ee6337778ffbebca600 Mon Sep 17 00:00:00 2001 From: Niels Beier Date: Thu, 7 May 2026 15:42:56 +0200 Subject: [PATCH 85/98] fix(server): Apply allowBrowseNode access control in TranslateBrowsePathsToNodeIds The TranslateBrowsePathsToNodeIds service did not call the allowBrowseNode access-control callback when resolving path elements or terminal targets. A client denied direct Browse access to a node could still use that node as a waypoint or receive its NodeId as a path translation result, disclosing hidden nodes and their children. Add the same allowBrowseNode gate already applied in the Browse service to both walkBrowsePathElement (intermediate nodes) and Operation_TranslateBrowsePathToNodeIds (terminal nodes). Internal Vulnerability Advisory: open62541-SA-2026-0004 Co-authored-by: keyme --- src/server/ua_services_view.c | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/server/ua_services_view.c b/src/server/ua_services_view.c index 9b0436c2c51..002a46c09c7 100644 --- a/src/server/ua_services_view.c +++ b/src/server/ua_services_view.c @@ -999,6 +999,25 @@ walkBrowsePathElement(UA_Server *server, UA_Session *session, if(!node) continue; + /* Check whether the session is allowed to browse this node. + * Mirrors the access-control gate applied in browseWithContinuation(). + * Without this check, a client denied direct Browse on a node can + * still use it as a waypoint in TranslateBrowsePathsToNodeIds, + * disclosing hidden intermediate nodes and their children. */ + if(session != &server->adminSession) { + UA_UNLOCK(&server->serviceMutex); + UA_Boolean canBrowse = + server->config.accessControl.allowBrowseNode( + server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + ¤t->targets[i].nodeId, node->head.context); + UA_LOCK(&server->serviceMutex); + if(!canBrowse) { + UA_NODESTORE_RELEASE(server, node); + continue; + } + } + /* Test whether the node fits the class mask */ UA_Boolean skip = !matchClassMask(node, nodeClassMask); @@ -1149,6 +1168,25 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, const UA_Node *node = UA_NODESTORE_GET(server, &next->targets[k].nodeId); if(!node) continue; + + /* Check whether the session is allowed to browse the resolved target. + * Without this check, a client denied direct Browse on a terminal node + * can still have its NodeId disclosed as the result of path + * translation. */ + if(session != &server->adminSession) { + UA_UNLOCK(&server->serviceMutex); + UA_Boolean canBrowse = + server->config.accessControl.allowBrowseNode( + server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + &next->targets[k].nodeId, node->head.context); + UA_LOCK(&server->serviceMutex); + if(!canBrowse) { + UA_NODESTORE_RELEASE(server, node); + continue; + } + } + UA_Boolean match = UA_QualifiedName_equal(browseNameFilter, &node->head.browseName); UA_NODESTORE_RELEASE(server, node); if(!match) From 6f58e2cf84b6c76cda4bd9d4a503656cf8a0dd36 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 24 Jun 2026 18:34:11 +0200 Subject: [PATCH 86/98] fix(client): Return the precise statuscode when triggering a reconnect --- src/client/ua_client.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/client/ua_client.c b/src/client/ua_client.c index 73d291b9c11..cca789eaaa7 100644 --- a/src/client/ua_client.c +++ b/src/client/ua_client.c @@ -436,6 +436,13 @@ receiveResponse(UA_Client *client, void *response, const UA_DataType *responseTy UA_LOG_WARNING_CHANNEL(&client->config.logger, &client->channel, "Receiving the response failed with StatusCode %s", UA_StatusCode_name(retval)); + /* The receive itself can succeed while the channel was closed + * remotely (e.g. an ERR message during the handshake). Forward the + * detailed status code captured from the close so the reconnect is + * not silent. */ + if(retval == UA_STATUSCODE_GOOD) + retval = (client->connectStatus != UA_STATUSCODE_GOOD) ? + client->connectStatus : UA_STATUSCODE_BADCONNECTIONCLOSED; closeSecureChannel(client); break; } From bdc949736874afbf76009641e9b70151a6cf867f Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 24 Jun 2026 18:34:55 +0200 Subject: [PATCH 87/98] fix(tests): Fix an endless loop on CI runs --- tests/encryption/check_crl_validation.c | 46 +++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/encryption/check_crl_validation.c b/tests/encryption/check_crl_validation.c index 9c4c08d5e45..e3172e9c70b 100644 --- a/tests/encryption/check_crl_validation.c +++ b/tests/encryption/check_crl_validation.c @@ -300,9 +300,49 @@ START_TEST(encryption_connect_revoked) { UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); ck_assert(client != NULL); - /* Secure client connect */ + /* Secure client connect. The application certificate is revoked by the + * intermediate CA's CRL, so the server rejects the handshake. */ + UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); + ck_assert_uint_eq(retval, UA_STATUSCODE_BADSECURITYCHECKSFAILED); + + UA_Client_disconnect(client); + UA_Client_delete(client); +} +END_TEST + +START_TEST(encryption_connect_issuer_revoked) { + UA_ByteString certificate; + certificate.length = APPLICATION_CERT_DER_LENGTH; + certificate.data = APPLICATION_CERT_DER_DATA; + ck_assert_uint_ne(certificate.length, 0); + + UA_ByteString privateKey; + privateKey.length = APPLICATION_KEY_DER_LENGTH; + privateKey.data = APPLICATION_KEY_DER_DATA; + ck_assert_uint_ne(privateKey.length, 0); + + /* Load the trustlist */ + UA_ByteString *trustList = NULL; + size_t trustListSize = 0; + UA_ByteString *revocationList = NULL; + size_t revocationListSize = 0; + + /* Secure client initialization */ + UA_Client *client = UA_Client_new(); + UA_ClientConfig *cc = UA_Client_getConfig(client); + UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey, + trustList, trustListSize, + revocationList, revocationListSize); + cc->certificateVerification.clear(&cc->certificateVerification); + UA_CertificateVerification_AcceptAll(&cc->certificateVerification); + cc->securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); + ck_assert(client != NULL); + + /* Secure client connect. The intermediate CA certificate is revoked by the + * root CA's CRL, so the issuer of the application certificate is revoked. */ UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); - ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONCLOSED); + ck_assert_uint_eq(retval, UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED); UA_Client_disconnect(client); UA_Client_delete(client); @@ -320,7 +360,7 @@ static Suite* testSuite_encryption(void) { #ifdef UA_ENABLE_ENCRYPTION tcase_add_test(tc_encryption_valid, encryption_connect_valid); tcase_add_test(tc_encryption_revoked, encryption_connect_revoked); - tcase_add_test(tc_encryption_revoked2, encryption_connect_revoked); + tcase_add_test(tc_encryption_revoked2, encryption_connect_issuer_revoked); #endif /* UA_ENABLE_ENCRYPTION */ suite_add_tcase(s,tc_encryption_valid); suite_add_tcase(s,tc_encryption_revoked); From 683bb385dc33b1fc73f8bc5908a7a685a8266c34 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Wed, 24 Jun 2026 18:35:21 +0200 Subject: [PATCH 88/98] fix(build): Ensure the check library is found on MacOS --- tools/cmake/FindCheck.cmake | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/cmake/FindCheck.cmake b/tools/cmake/FindCheck.cmake index ed410c16b83..25c8bbf54c3 100644 --- a/tools/cmake/FindCheck.cmake +++ b/tools/cmake/FindCheck.cmake @@ -22,6 +22,19 @@ INCLUDE( FindPkgConfig ) # Take care about check.pc settings PKG_SEARCH_MODULE( CHECK check ) +# pkg-config exports the plural CHECK_INCLUDE_DIRS and a bare library name. +# Mirror them to the singular CHECK_INCLUDE_DIR and an absolute CHECK_LIBRARIES +# that this module documents and the build expects. +IF( CHECK_FOUND ) + IF( NOT CHECK_INCLUDE_DIR ) + SET( CHECK_INCLUDE_DIR ${CHECK_INCLUDE_DIRS} ) + ENDIF() + FIND_LIBRARY( CHECK_LIBRARY NAMES check PATHS ${CHECK_LIBRARY_DIRS} ) + IF( CHECK_LIBRARY ) + SET( CHECK_LIBRARIES ${CHECK_LIBRARY} ) + ENDIF() +ENDIF() + # Look for CHECK include dir and libraries IF( NOT CHECK_FOUND ) IF ( CHECK_INSTALL_DIR ) From 9e0d23838e0777f5244dd5e3638147cf49d168c6 Mon Sep 17 00:00:00 2001 From: Tomer Dricker Date: Wed, 11 Feb 2026 00:00:00 +0000 Subject: [PATCH 89/98] fix(core): Fix integer overflow in array decoding Rearrange the overflow check in Array_decodeBinary so that the multiplication `type->memSize * length` cannot overflow before the comparison. Instead of checking ctx->pos + (type->memSize * length) / 128 <= ctx->end which overflows when the product exceeds SIZE_MAX, rewrite it as length / 128 <= remaining / type->memSize where `remaining = ctx->end - ctx->pos`, keeping all operations in safe size_t range. Internal Vulnerability Advisory: open62541-SA-2026-0003 --- src/ua_types_encoding_binary.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ua_types_encoding_binary.c b/src/ua_types_encoding_binary.c index 65de4375803..c814f390e8e 100644 --- a/src/ua_types_encoding_binary.c +++ b/src/ua_types_encoding_binary.c @@ -497,7 +497,8 @@ Array_decodeBinary(void *UA_RESTRICT *UA_RESTRICT dst, size_t *out_length, * sizeof(UA_DataValue) == 80 and an empty DataValue is encoded with just * one byte. We use 128 as the smallest power of 2 larger than 80. */ size_t length = (size_t)signed_length; - UA_CHECK(ctx->pos + ((type->memSize * length) / 128) <= ctx->end, + size_t remaining = (size_t)(ctx->end - ctx->pos); + UA_CHECK(length / 128 <= remaining / type->memSize, return UA_STATUSCODE_BADDECODINGERROR); /* Allocate memory */ From 0eb7d97ada87eb1447356bd73832d22529681563 Mon Sep 17 00:00:00 2001 From: Niels Beier Date: Thu, 7 May 2026 15:27:17 +0200 Subject: [PATCH 90/98] fix(pubsub): Guard DataSetPayload JSON field count against UA_UInt16 overflow The JSON decoder for PubSub DataSetPayload casts the token count to UA_UInt16 without bounds checking. If a malicious or malformed message provides more than UA_UINT16_MAX/2 tokens, the cast silently truncates to a smaller value while the actual allocation uses the full (large) length. This can lead to heap buffer overflows and memory corruption. Add an explicit bounds check before the cast, rejecting messages with a field count that exceeds UA_UINT16_MAX. See: open62541-SA-2026-0001 --- src/pubsub/ua_pubsub_networkmessage_json.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pubsub/ua_pubsub_networkmessage_json.c b/src/pubsub/ua_pubsub_networkmessage_json.c index e73af226c75..45b696c0dc3 100644 --- a/src/pubsub/ua_pubsub_networkmessage_json.c +++ b/src/pubsub/ua_pubsub_networkmessage_json.c @@ -286,6 +286,8 @@ DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, } size_t length = (size_t)parseCtx->tokenArray[parseCtx->index].size; + if(length > UA_UINT16_MAX) + return UA_STATUSCODE_BADDECODINGERROR; UA_String *fieldNames = (UA_String*)UA_calloc(length, sizeof(UA_String)); dsm->data.keyFrameData.fieldNames = fieldNames; dsm->data.keyFrameData.fieldCount = (UA_UInt16)length; From 435ac16aae0df9ac0d80bd4733bae34d88c10325 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sat, 27 Jun 2026 09:48:53 +0200 Subject: [PATCH 91/98] fix(build): Fix FindCheck for cross-arch builds --- tools/cmake/FindCheck.cmake | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/cmake/FindCheck.cmake b/tools/cmake/FindCheck.cmake index 25c8bbf54c3..b02dc148369 100644 --- a/tools/cmake/FindCheck.cmake +++ b/tools/cmake/FindCheck.cmake @@ -22,16 +22,20 @@ INCLUDE( FindPkgConfig ) # Take care about check.pc settings PKG_SEARCH_MODULE( CHECK check ) -# pkg-config exports the plural CHECK_INCLUDE_DIRS and a bare library name. -# Mirror them to the singular CHECK_INCLUDE_DIR and an absolute CHECK_LIBRARIES -# that this module documents and the build expects. +# pkg-config exports the plural CHECK_INCLUDE_DIRS and linker flags with the +# architecture-specific library directory. Mirror them to the singular +# CHECK_INCLUDE_DIR and CHECK_LIBRARIES that this module documents and the build +# expects. Do not resolve the library again with find_library(), because that can +# pick a host-architecture library during multilib/cross builds. IF( CHECK_FOUND ) IF( NOT CHECK_INCLUDE_DIR ) SET( CHECK_INCLUDE_DIR ${CHECK_INCLUDE_DIRS} ) ENDIF() - FIND_LIBRARY( CHECK_LIBRARY NAMES check PATHS ${CHECK_LIBRARY_DIRS} ) - IF( CHECK_LIBRARY ) - SET( CHECK_LIBRARIES ${CHECK_LIBRARY} ) + IF( CHECK_LDFLAGS ) + SET( CHECK_LIBRARIES ${CHECK_LDFLAGS} ) + IF( CHECK_LDFLAGS_OTHER ) + LIST( APPEND CHECK_LIBRARIES ${CHECK_LDFLAGS_OTHER} ) + ENDIF() ENDIF() ENDIF() From db393f2c94374ee55d89ef46e5163686932222ee Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Sun, 28 Jun 2026 17:34:08 +0200 Subject: [PATCH 92/98] refactor(build): Bump version to v1.3.18 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf4c4fd65ee..d34a23b040a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 17) +set(OPEN62541_VER_PATCH 18) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit") From 7cf493ecca5a3cffef3191e65651f03694c3f7f5 Mon Sep 17 00:00:00 2001 From: lonelybones Date: Tue, 31 Mar 2026 08:55:30 -0400 Subject: [PATCH 93/98] fix(core): use correct size in memset after moving Variant array elements Variant_setRange uses sizeof(elem_size) instead of elem_size in the memset that zeros moved array elements. sizeof(elem_size) always evaluates to sizeof(size_t), which is 8 on 64-bit. For types with memSize > 8 (e.g. UA_String at 16 bytes), only half the struct is zeroed, leaving heap pointers dangling. This causes a double-free when both the source and the variant are cleared. --- src/ua_types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ua_types.c b/src/ua_types.c index 2fff32e18bb..f16bb0ec107 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -931,7 +931,7 @@ Variant_setRange(UA_Variant *v, void *array, size_t arraySize, /* If members were moved, initialize original array to prevent reuse */ if(!copy && !v->type->pointerFree) - memset(array, 0, sizeof(elem_size)*arraySize); + memset(array, 0, elem_size*arraySize); return retval; } From 9c1636a2325ef46a2cc463789b06b31e8da639f3 Mon Sep 17 00:00:00 2001 From: Niels Beier Date: Tue, 28 Apr 2026 10:24:00 +0200 Subject: [PATCH 94/98] fix(server): Cap default outstanding PublishRequest count per session The default server configuration zero-initialises maxPublishReqPerSession, which disables the per-session cap on outstanding PublishRequest entries. A remote client that is allowed to create a session and a subscription can therefore send an unbounded number of PublishRequest messages, each of which allocates a UA_PublishResponseEntry and appends it to the session's publish queue. The resulting monotonic heap growth causes process memory exhaustion and a denial of service. Set a safe finite default of 512 outstanding PublishRequests per session in setDefaultConfig() so that the cap is enforced out of the box, while still allowing deployers to override it. Internal Vulnerability Advisory: open62541-SA-2026-0010 Co-Authored-By: keyme --- plugins/ua_config_default.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ua_config_default.c b/plugins/ua_config_default.c index b1445975c63..01c21455919 100644 --- a/plugins/ua_config_default.c +++ b/plugins/ua_config_default.c @@ -211,6 +211,7 @@ setDefaultConfig(UA_ServerConfig *conf) { conf->maxNotificationsPerPublish = 1000; conf->enableRetransmissionQueue = true; conf->maxRetransmissionQueueSize = 0; /* unlimited */ + conf->maxPublishReqPerSession = 512; /* limit outstanding publish requests per session */ # ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS conf->maxEventsPerNode = 0; /* unlimited */ # endif From 8098907673099afe6b726de05675146066b24d9c Mon Sep 17 00:00:00 2001 From: Niels Beier Date: Mon, 11 May 2026 10:55:31 +0200 Subject: [PATCH 95/98] fix(core): reject overflowing arrayDimensions product in Variant en/decoding Multiplying attacker-controlled arrayDimensions values into a size_t accumulator without an overflow check allows the product to wrap and match a small arrayLength. Subsequent ranged read or write operations then access memory outside the allocated array bounds. Add checked multiplication at all sites where the dimension product is computed: Variant binary decode, Variant binary encode, checkAdjustRange, and computeStrides (as a defence-in-depth measure). Internal Vulnerability Advisory: open62541-SA-2026-0012 and open62541-SA-2026-0013 Co-authored-by: Asher Davila Co-authored-by: Malav Vyas --- src/ua_types.c | 10 +++++++++- src/ua_types_encoding_binary.c | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/ua_types.c b/src/ua_types.c index f16bb0ec107..9c1b76053f0 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -636,8 +636,11 @@ checkAdjustRange(const UA_Variant *v, UA_NumericRange *range) { /* Check that the number of elements in the variant matches the array * dimensions */ size_t elements = 1; - for(size_t i = 0; i < dims_count; ++i) + for(size_t i = 0; i < dims_count; ++i) { + if(dims[i] != 0 && elements > SIZE_MAX / dims[i]) + return UA_STATUSCODE_BADINTERNALERROR; elements *= dims[i]; + } if(elements != v->arrayLength) return UA_STATUSCODE_BADINTERNALERROR; @@ -700,6 +703,11 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range, *block = running_dimssize * dimrange; *stride = running_dimssize * dims[k]; } + /* Overflow in running_dimssize is only possible when the Variant has + * passed a corrupted state through checkAdjustRange. Guard here as a + * defence-in-depth measure. */ + if(running_dimssize != 0 && dims[k] > SIZE_MAX / running_dimssize) + break; *first += running_dimssize * range.dimensions[k].min; running_dimssize *= dims[k]; } diff --git a/src/ua_types_encoding_binary.c b/src/ua_types_encoding_binary.c index c814f390e8e..3f03c2966e6 100644 --- a/src/ua_types_encoding_binary.c +++ b/src/ua_types_encoding_binary.c @@ -1000,8 +1000,17 @@ ENCODE_BINARY(Variant) { const UA_Boolean hasDimensions = isArray && src->arrayDimensionsSize > 0; if(isArray) { encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_ARRAY; - if(hasDimensions) + if(hasDimensions) { encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS; + size_t totalRequiredSize = 1; + for(size_t i = 0; i < src->arrayDimensionsSize; ++i) { + if(src->arrayDimensions[i] != 0 && + totalRequiredSize > SIZE_MAX / src->arrayDimensions[i]) + return UA_STATUSCODE_BADENCODINGERROR; + totalRequiredSize *= src->arrayDimensions[i]; + } + if(totalRequiredSize != src->arrayLength) return UA_STATUSCODE_BADENCODINGERROR; + } } /* Encode the encoding byte */ @@ -1116,9 +1125,13 @@ DECODE_BINARY(Variant) { /* Validate array length against array dimensions */ size_t totalSize = 1; for(size_t i = 0; i < dst->arrayDimensionsSize; ++i) { - if(dst->arrayDimensions[i] == 0) - return UA_STATUSCODE_BADDECODINGERROR; - totalSize *= dst->arrayDimensions[i]; + if(dst->arrayDimensions[i] == 0) { + ret = UA_STATUSCODE_BADDECODINGERROR; + } else if(totalSize > SIZE_MAX / dst->arrayDimensions[i]) { + ret = UA_STATUSCODE_BADDECODINGERROR; + } else { + totalSize *= dst->arrayDimensions[i]; + } } UA_CHECK(totalSize == dst->arrayLength, ret = UA_STATUSCODE_BADDECODINGERROR); } From a1257feec0c539f191cb2d40f72f116a901d3322 Mon Sep 17 00:00:00 2001 From: Niels Beier Date: Mon, 11 May 2026 13:17:19 +0200 Subject: [PATCH 96/98] fix(pubsub): check message length before signature size subtraction Add bounds check in verifyAndDecrypt() to prevent unsigned integer underflow when buffer->length is smaller than the expected signature size. Without this check, the subtraction wraps around producing a large size_t that causes mbedtls to read unmapped memory. Internal Vulnerability Advisory: open62541-SA-2026-0014 Co-authored-by: Abhinav Agarwal --- src/pubsub/ua_pubsub_security.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pubsub/ua_pubsub_security.c b/src/pubsub/ua_pubsub_security.c index 42690177e56..25139f8be68 100644 --- a/src/pubsub/ua_pubsub_security.c +++ b/src/pubsub/ua_pubsub_security.c @@ -84,6 +84,11 @@ verifyAndDecrypt(const UA_Logger *logger, UA_ByteString *buffer, if(doValidate) { size_t sigSize = securityPolicy->symmetricModule.cryptoModule. signatureAlgorithm.getLocalSignatureSize(channelContext); + if(buffer->length < sigSize) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "PubSub receive. Message too short for signature"); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } UA_ByteString toBeVerified = {buffer->length - sigSize, buffer->data}; UA_ByteString signature = {sigSize, buffer->data + buffer->length - sigSize}; From 2da371bcdaadeb23051635a60e38f31039af9fd8 Mon Sep 17 00:00:00 2001 From: Niels Beier Date: Mon, 11 May 2026 13:21:15 +0200 Subject: [PATCH 97/98] fix(server): migrate samplingMonitoredItems in TransferSubscriptions Operation_TransferSubscription() copies the UA_Subscription struct with memcpy but only migrates monitoredItems, notificationQueue, and retransmissionQueue. The samplingMonitoredItems list was not re-initialized in the new subscription, leaving stale le_prev backpointers from items with samplingType==PUBLISH pointing into the freed old subscription struct. When UA_MonitoredItem_unregisterSampling() calls LIST_REMOVE, it writes to freed memory (heap-use-after-free). Add migration of samplingMonitoredItems to the new subscription after the point of no return, matching the pattern used for monitoredItems. Internal Vulnerability Advisory: open62541-SA-2026-0015 Co-authored-by: Abhinav Agarwal --- src/server/ua_services_subscription.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/server/ua_services_subscription.c b/src/server/ua_services_subscription.c index ecec4b151bc..9ec6b40523b 100644 --- a/src/server/ua_services_subscription.c +++ b/src/server/ua_services_subscription.c @@ -549,6 +549,15 @@ Operation_TransferSubscription(UA_Server *server, UA_Session *session, } sub->monitoredItemsSize = 0; + /* Move over the samplingMonitoredItems and adjust the backpointers */ + LIST_INIT(&newSub->samplingMonitoredItems); + UA_MonitoredItem *smon, *smon_tmp; + LIST_FOREACH_SAFE(smon, &sub->samplingMonitoredItems, sampling.samplingListEntry, smon_tmp) { + LIST_REMOVE(smon, sampling.samplingListEntry); + LIST_INSERT_HEAD(&newSub->samplingMonitoredItems, smon, + sampling.samplingListEntry); + } + /* Move over the notification queue */ TAILQ_INIT(&newSub->notificationQueue); UA_Notification *nn, *nn_tmp; From 00c485444eba6039f952a343dbd5cf4dd07800f5 Mon Sep 17 00:00:00 2001 From: Julius Pfrommer Date: Mon, 27 Jul 2026 13:14:35 +0200 Subject: [PATCH 98/98] refactor(build): Bump version to v1.3.19 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d34a23b040a..1e1acb3f0f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # overwritten with more detailed information if git is available. set(OPEN62541_VER_MAJOR 1) set(OPEN62541_VER_MINOR 3) -set(OPEN62541_VER_PATCH 18) +set(OPEN62541_VER_PATCH 19) set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty" set(OPEN62541_VER_COMMIT "unknown-commit")