Coverage Report

Created: 2026-09-04 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/S2OPC/src/ClientServer/configuration/sopc_toolkit_config.c
Line
Count
Source
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include <inttypes.h>
21
#include <stdio.h>
22
#include <string.h>
23
24
#include "opcua_identifiers.h"
25
#include "sopc_assert.h"
26
#include "sopc_common.h"
27
#include "sopc_date_time.h"
28
#include "sopc_encodeabletype.h"
29
#include "sopc_enum_types.h"
30
#include "sopc_event_timer_manager.h"
31
#include "sopc_filesystem.h"
32
#include "sopc_helper_endianness_cfg.h"
33
#include "sopc_internal_app_dispatcher.h"
34
#include "sopc_logger.h"
35
#include "sopc_macros.h"
36
#include "sopc_mem_alloc.h"
37
#include "sopc_mutexes.h"
38
#include "sopc_secure_channels_api.h"
39
#include "sopc_services_api.h"
40
#include "sopc_singly_linked_list.h"
41
#include "sopc_sockets_api.h"
42
#include "sopc_toolkit_build_info.h"
43
#include "sopc_toolkit_config.h"
44
#include "sopc_toolkit_config_internal.h"
45
#include "sopc_user_app_itf.h"
46
47
#include "address_space_impl.h"
48
#include "util_b2c.h"
49
50
/* Check IEEE-754 compliance */
51
#include "sopc_ieee_check.h"
52
53
static struct
54
{
55
    uint8_t initDone;
56
    SOPC_Condition serverConfigCond;
57
    uint8_t serverConfigLocked;
58
    uint8_t serverConfigUsedCounter;
59
60
    SOPC_Mutex mut;
61
    /* Specific client */
62
    SOPC_SecureChannel_Config* scConfigs[SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + 1];
63
    const char* reverseEpConfigs[SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS + 1]; // index 0 reserved
64
    SOPC_SecureChannelConfigIdx scConfigIdxMax;
65
    SOPC_ReverseEndpointConfigIdx reverseEpConfigIdxMax;
66
    /* Specific server */
67
    SOPC_SecureChannel_Config* serverScConfigs[SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + 1];
68
    SOPC_Endpoint_Config* epConfigs[SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS + 1]; // index 0 reserved
69
    SOPC_SecureChannelConfigIdx serverScLastConfigIdx;
70
    SOPC_EndpointConfigIdx epConfigIdxMax;
71
72
    SOPC_AddressSpaceNotif_Fct* appAddSpaceNotifCb;
73
74
} // Any change in values below shall be also done in SOPC_Toolkit_Clear
75
tConfig = {.initDone = false,
76
           .serverConfigLocked = false,
77
           .serverConfigUsedCounter = 0,
78
           .scConfigIdxMax = 0,
79
           .reverseEpConfigIdxMax = 0,
80
           .serverScLastConfigIdx = 0,
81
           .epConfigIdxMax = 0,
82
           .appAddSpaceNotifCb = NULL};
83
84
// Total number of layers using locked server configuration (SecureChannels + Services)
85
0
#define SOPC_NB_LAYERS_USING_SERVER_CONFIG 2
86
0
#define SOPC_CHANGE_CONFIG_LOCK_STATE_TIMEOUT_MS 1000
87
88
typedef struct
89
{
90
    bool enabled;
91
    int priority;
92
    int cpuAffinity;
93
} SOPC_Toolkit_ThreadPropertiesStorage;
94
95
static SOPC_Toolkit_ThreadPropertiesStorage toolkitThreadProperties[SOPC_TOOLKIT_THREAD_COMPONENT_COUNT] = {{0}};
96
97
void SOPC_ToolkitInternal_ClearThreadConfiguration(void)
98
0
{
99
0
    memset(toolkitThreadProperties, 0, sizeof(toolkitThreadProperties));
100
0
}
101
102
void SOPC_ToolkitInternal_SetThreadProperties(SOPC_Toolkit_ThreadComponent threadComponent,
103
                                              int priority,
104
                                              int cpuAffinity)
105
0
{
106
0
    if (threadComponent < 0 || threadComponent >= SOPC_TOOLKIT_THREAD_COMPONENT_COUNT)
107
0
    {
108
0
        return;
109
0
    }
110
111
0
    toolkitThreadProperties[threadComponent].enabled = true;
112
0
    toolkitThreadProperties[threadComponent].priority = priority;
113
0
    toolkitThreadProperties[threadComponent].cpuAffinity = cpuAffinity;
114
0
}
115
116
void SOPC_ToolkitInternal_GetThreadProperties(SOPC_Toolkit_ThreadComponent threadComponent,
117
                                              int* priority,
118
                                              int* cpuAffinity)
119
0
{
120
0
    if (NULL != priority)
121
0
    {
122
0
        *priority = 0;
123
0
    }
124
0
    if (NULL != cpuAffinity)
125
0
    {
126
0
        *cpuAffinity = -1;
127
0
    }
128
129
0
    if (NULL == priority || NULL == cpuAffinity || threadComponent < 0 ||
130
0
        threadComponent >= SOPC_TOOLKIT_THREAD_COMPONENT_COUNT || !toolkitThreadProperties[threadComponent].enabled)
131
0
    {
132
0
        return;
133
0
    }
134
135
0
    *priority = toolkitThreadProperties[threadComponent].priority;
136
0
    *cpuAffinity = toolkitThreadProperties[threadComponent].cpuAffinity;
137
0
}
138
139
SOPC_ReturnStatus SOPC_Toolkit_Initialize(SOPC_ComEvent_Fct* pAppFct)
140
0
{
141
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
142
0
    int timerPriority = 0;
143
0
    int timerCpuAffinity = -1;
144
145
0
    if (NULL == pAppFct)
146
0
    {
147
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
148
0
    }
149
150
0
    bool bRet = SOPC_Common_IsInitialized();
151
0
    if (SOPC_STATUS_OK == status && !bRet)
152
0
    {
153
        /* Initialize with default log configuration */
154
0
        SOPC_Log_Configuration defaultLogConfiguration = SOPC_Common_GetDefaultLogConfiguration();
155
0
        status = SOPC_Common_Initialize(&defaultLogConfiguration, NULL);
156
0
    }
157
158
0
    if (SOPC_STATUS_OK == status)
159
0
    {
160
0
        if (tConfig.initDone)
161
0
        {
162
0
            status = SOPC_STATUS_INVALID_STATE;
163
0
        }
164
0
        else
165
0
        {
166
0
            SOPC_Mutex_Initialization(&tConfig.mut);
167
0
            SOPC_Condition_Init(&tConfig.serverConfigCond);
168
0
            SOPC_Mutex_Lock(&tConfig.mut);
169
            // Note: check again the flag to avoid possible concurrency issue detection by static analysis.
170
            //       Nevertheless this function shall never be called concurrently since the mutex is created during
171
            //       call
172
0
            if (!tConfig.initDone)
173
0
            {
174
0
                tConfig.initDone = true;
175
176
0
                sopc_appEventCallback = pAppFct;
177
178
                // Ensure constants cannot be modified later
179
                // Return value is not check as the encoding config could be already set.
180
0
                SOPC_Common_EncodingConstants defEncConst = SOPC_Common_GetDefaultEncodingConstants();
181
0
                bRet = SOPC_Common_SetEncodingConstants(defEncConst);
182
0
                SOPC_Helper_Endianness_Check();
183
184
0
                if (SOPC_STATUS_OK == status)
185
0
                {
186
0
                    memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs));
187
0
                    memset((void*) tConfig.reverseEpConfigs, 0, sizeof(tConfig.reverseEpConfigs));
188
0
                    memset(tConfig.serverScConfigs, 0, sizeof(tConfig.serverScConfigs));
189
0
                    memset(tConfig.epConfigs, 0, sizeof(tConfig.epConfigs));
190
0
                    SOPC_App_Initialize();
191
0
                    SOPC_ToolkitInternal_GetThreadProperties(SOPC_TOOLKIT_THREAD_EVENT_TIMER, &timerPriority,
192
0
                                                             &timerCpuAffinity);
193
0
                    SOPC_EventTimer_InitializeWithThreadProperties(timerPriority, timerCpuAffinity);
194
0
                    SOPC_Sockets_Initialize();
195
0
                    SOPC_SecureChannels_Initialize(SOPC_Sockets_SetEventHandler);
196
0
                    SOPC_Services_Initialize(SOPC_SecureChannels_SetEventHandler);
197
198
0
                    SOPC_Toolkit_Build_Info toolkitBuildInfo = SOPC_ToolkitConfig_GetBuildInfo();
199
200
                    /* set log level to INFO for version logging, then restore it */
201
0
                    SOPC_Log_Level level = SOPC_Logger_GetTraceLogLevel();
202
0
                    SOPC_Logger_SetTraceLogLevel(SOPC_LOG_LEVEL_INFO);
203
0
                    SOPC_Logger_TraceInfo(SOPC_LOG_MODULE_CLIENTSERVER,
204
0
                                          "Common library DATE='%s' VERSION='%s' SIGNATURE='%s' DOCKER='%s'",
205
0
                                          toolkitBuildInfo.commonBuildInfo.buildBuildDate,
206
0
                                          toolkitBuildInfo.commonBuildInfo.buildVersion,
207
0
                                          toolkitBuildInfo.commonBuildInfo.buildSrcCommit,
208
0
                                          toolkitBuildInfo.commonBuildInfo.buildDockerId);
209
0
                    SOPC_Logger_TraceInfo(
210
0
                        SOPC_LOG_MODULE_CLIENTSERVER,
211
0
                        "Client/Server toolkit library DATE='%s' VERSION='%s' SIGNATURE='%s' DOCKER='%s'",
212
0
                        toolkitBuildInfo.clientServerBuildInfo.buildBuildDate,
213
0
                        toolkitBuildInfo.clientServerBuildInfo.buildVersion,
214
0
                        toolkitBuildInfo.clientServerBuildInfo.buildSrcCommit,
215
0
                        toolkitBuildInfo.clientServerBuildInfo.buildDockerId);
216
0
                    SOPC_Logger_SetTraceLogLevel(level);
217
0
                }
218
0
            }
219
0
            SOPC_Mutex_Unlock(&tConfig.mut);
220
0
        }
221
0
    }
222
223
0
    return status;
224
0
}
225
226
static SOPC_ReturnStatus SOPC_SecurityCheck_UserCredentialsEncrypted(const SOPC_SecurityPolicy* pSecurityPolicy,
227
                                                                     const OpcUa_UserTokenPolicy* pUserTokenPolicies)
228
0
{
229
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
230
0
    SOPC_String securityPolicyNoneURI;
231
0
    SOPC_String_Initialize(&securityPolicyNoneURI);
232
0
    status = SOPC_String_AttachFromCstring(&securityPolicyNoneURI, SOPC_SecurityPolicy_None_URI);
233
0
    if (SOPC_STATUS_OK != status)
234
0
    {
235
0
        return SOPC_STATUS_NOK;
236
0
    }
237
238
    // Check if SecurityPolicy "security mode" is "None" AND if "UserToken security policy" is "empty" (default)
239
0
    if (0 != (pSecurityPolicy->securityModes & SOPC_SECURITY_MODE_NONE_MASK) &&
240
0
        pUserTokenPolicies->SecurityPolicyUri.Length <= 0)
241
0
    {
242
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
243
0
                               "Security Check UserCredentials: Failed. Combination not allowed : SecurityPolicy "
244
0
                               "security mode is None and UserToken security policy is empty.\n");
245
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
246
0
    }
247
248
    // Check if SecurityPolicy "security mode" is "None or Sign" AND if "UserToken security policy" is "None"
249
0
    else if (0 != (pSecurityPolicy->securityModes & (SOPC_SECURITY_MODE_SIGN_MASK | SOPC_SECURITY_MODE_NONE_MASK)) &&
250
0
             true == SOPC_String_Equal(&pUserTokenPolicies->SecurityPolicyUri, &securityPolicyNoneURI))
251
0
    {
252
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
253
0
                               "Security Check UserCredentials: Failed. Combination not allowed : SecurityPolicy "
254
0
                               "security mode is None or Sign and UserToken security policy is None.\n");
255
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
256
0
    }
257
0
    return status;
258
0
}
259
260
SOPC_ReturnStatus SOPC_ToolkitServer_SecurityCheck(void)
261
0
{
262
0
    SOPC_Endpoint_Config* pEpConfig;
263
0
    SOPC_SecurityPolicy* pSecurityPolicy;
264
0
    OpcUa_UserTokenPolicy* pUserTokenPolicies;
265
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
266
0
    SOPC_ReturnStatus statusSecurityCheck = SOPC_STATUS_OK;
267
0
    SOPC_String securityPolicyNoneURI;
268
269
0
    SOPC_String_Initialize(&securityPolicyNoneURI);
270
0
    status = SOPC_String_AttachFromCstring(&securityPolicyNoneURI, SOPC_SecurityPolicy_None_URI);
271
0
    if (SOPC_STATUS_OK != status)
272
0
    {
273
0
        return SOPC_STATUS_NOK;
274
0
    }
275
276
0
    for (uint32_t nbEpConfigIndex = 1; nbEpConfigIndex <= tConfig.epConfigIdxMax; nbEpConfigIndex++)
277
0
    {
278
0
        pEpConfig = tConfig.epConfigs[nbEpConfigIndex];
279
280
0
        for (uint8_t nbSecuIndex = 0; nbSecuIndex < pEpConfig->nbSecuConfigs; nbSecuIndex++)
281
0
        {
282
0
            pSecurityPolicy = &pEpConfig->secuConfigurations[nbSecuIndex];
283
284
0
            for (uint8_t nbTokenIndex = 0; nbTokenIndex < pSecurityPolicy->nbOfUserTokenPolicies; nbTokenIndex++)
285
0
            {
286
0
                pUserTokenPolicies = &pSecurityPolicy->userTokenPolicies[nbTokenIndex];
287
288
0
                if (OpcUa_UserTokenType_Anonymous != pUserTokenPolicies->TokenType)
289
0
                {
290
0
                    status = SOPC_SecurityCheck_UserCredentialsEncrypted(pSecurityPolicy, pUserTokenPolicies);
291
0
                    if (SOPC_STATUS_OK != status)
292
0
                    {
293
0
                        statusSecurityCheck = status;
294
0
                    }
295
0
                }
296
0
            }
297
298
            /* Check if SecurityPolicy "security policy URI" is different from "None" AND if SecurityPolicy "security
299
            mode" is "None" */
300
0
            if (false == SOPC_String_Equal(&pSecurityPolicy->securityPolicy, &securityPolicyNoneURI) &&
301
0
                0 != (pSecurityPolicy->securityModes & SOPC_SECURITY_MODE_NONE_MASK))
302
0
            {
303
0
                SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
304
0
                                       "Security Check: Failed. Combination not allowed : SecurityPolicy security "
305
0
                                       "policy URI is different from None and SecurityPolicy security mode is None.\n");
306
0
                statusSecurityCheck = SOPC_STATUS_INVALID_PARAMETERS;
307
0
            }
308
0
        }
309
0
    }
310
0
    return statusSecurityCheck;
311
0
}
312
313
SOPC_ReturnStatus SOPC_ToolkitServer_Configured(void)
314
0
{
315
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_STATE;
316
0
    if (tConfig.initDone)
317
0
    {
318
0
        SOPC_ReturnStatus mutStatus = SOPC_Mutex_Lock(&tConfig.mut);
319
0
        SOPC_ASSERT(SOPC_STATUS_OK == mutStatus);
320
0
        if (!tConfig.serverConfigLocked)
321
0
        {
322
            // Check an address space is defined in case a endpoint configuration exists
323
0
            if (tConfig.epConfigIdxMax > 0 && SOPC_AddressSpace_Check_Configured())
324
0
            {
325
0
                tConfig.serverConfigLocked = true;
326
0
                status = SOPC_ToolkitServer_SecurityCheck();
327
0
            }
328
0
            else
329
0
            {
330
                // No address space defined whereas a server configuration exists
331
0
                status = SOPC_STATUS_INVALID_PARAMETERS;
332
0
            }
333
0
        }
334
        // Notify services layer that server configuration is configured and locked
335
0
        if (SOPC_STATUS_OK == status)
336
0
        {
337
0
            SOPC_Services_EnqueueEvent(APP_TO_SE_SERVER_CONFIGURED, 0, (uintptr_t) true, 0);
338
0
        }
339
        // Wait configured is set in all layers before returning
340
0
        while (SOPC_STATUS_OK == mutStatus && tConfig.serverConfigUsedCounter < SOPC_NB_LAYERS_USING_SERVER_CONFIG)
341
0
        {
342
0
            mutStatus = SOPC_Mutex_UnlockAndTimedWaitCond(&tConfig.serverConfigCond, &tConfig.mut,
343
0
                                                          SOPC_CHANGE_CONFIG_LOCK_STATE_TIMEOUT_MS);
344
0
        }
345
0
        status = mutStatus;
346
0
        mutStatus = SOPC_Mutex_Unlock(&tConfig.mut);
347
0
        SOPC_ASSERT(SOPC_STATUS_OK == mutStatus);
348
0
    }
349
0
    return status;
350
0
}
351
352
bool SOPC_ToolkitServer_IsConfigured(void)
353
0
{
354
0
    bool res = false;
355
0
    if (tConfig.initDone)
356
0
    {
357
0
        SOPC_Mutex_Lock(&tConfig.mut);
358
0
        res = tConfig.serverConfigLocked;
359
0
        SOPC_Mutex_Unlock(&tConfig.mut);
360
0
    }
361
0
    return res;
362
0
}
363
364
static void SOPC_ToolkitServer_ClearScConfig_WithoutLock(uint32_t serverScConfigIdxWithoutOffset)
365
0
{
366
0
    SOPC_SecureChannel_Config* scConfig = tConfig.serverScConfigs[serverScConfigIdxWithoutOffset];
367
0
    if (scConfig != NULL)
368
0
    {
369
0
        SOPC_ASSERT(!scConfig->isClientSc);
370
        // In case of server it is an internally created config
371
        // => only client certificate / client info was specifically allocated
372
        // Exceptional case: configuration added internally and shall be freed on clear call
373
0
        SOPC_KeyCertPair_Delete(&scConfig->peerAppCert);
374
0
        SOPC_Free(scConfig->clientPeerInfo);
375
0
        SOPC_Free(scConfig->clientAuditInfo);
376
0
        SOPC_Free(scConfig);
377
0
        tConfig.serverScConfigs[serverScConfigIdxWithoutOffset] = NULL;
378
0
    }
379
0
}
380
381
// Deallocate fields allocated on server side only and free all the SC configs
382
static void SOPC_Toolkit_ClearServerScConfigs_WithoutLock(void)
383
0
{
384
    // Index 0 reserved for indet, index = MAX valid
385
0
    for (uint32_t i = 1; i <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED; i++)
386
0
    {
387
0
        SOPC_ToolkitServer_ClearScConfig_WithoutLock(i);
388
0
    }
389
0
}
390
391
void SOPC_Toolkit_Clear(void)
392
0
{
393
0
    if (tConfig.initDone)
394
0
    {
395
        // Services are in charge to gracefully close all connections.
396
        // It must be done before stopping the services
397
0
        SOPC_Services_CloseAllSCs(false);
398
399
        // Ensure no new events are triggered by timers
400
0
        SOPC_EventTimer_PreClear();
401
402
0
        SOPC_Sockets_Clear();
403
0
        SOPC_SecureChannels_Clear();
404
0
        SOPC_Services_Clear();
405
0
        SOPC_App_Clear();
406
0
        SOPC_EventTimer_Clear();
407
408
0
        SOPC_Mutex_Lock(&tConfig.mut);
409
        // Note: check again the flag to avoid possible concurrency issue detection by static analysis.
410
        //       Nevertheless this function shall never be called concurrently since the mutex is destroyed after call.
411
0
        if (tConfig.initDone)
412
0
        {
413
0
            SOPC_Toolkit_ClearServerScConfigs_WithoutLock();
414
0
            tConfig.appAddSpaceNotifCb = NULL;
415
0
            sopc_appEventCallback = NULL;
416
            // Reset values to init value
417
0
            tConfig.initDone = false;
418
0
            tConfig.serverConfigLocked = false;
419
0
            tConfig.scConfigIdxMax = 0;
420
0
            tConfig.reverseEpConfigIdxMax = 0;
421
0
            tConfig.serverScLastConfigIdx = 0;
422
0
            tConfig.epConfigIdxMax = 0;
423
            // Note: done by APP_TO_SE_UNINITIALIZE_SERVICES event/ io_dispatch_mgr__UNINITIALISATION operation
424
            // address_space_bs__nodes = NULL;
425
0
        }
426
0
        SOPC_Mutex_Unlock(&tConfig.mut);
427
0
        SOPC_Condition_Clear(&tConfig.serverConfigCond);
428
0
        SOPC_Mutex_Clear(&tConfig.mut);
429
0
    }
430
0
    SOPC_ToolkitInternal_ClearThreadConfiguration();
431
0
    SOPC_Common_Clear();
432
0
}
433
434
static bool SOPC_Internal_CheckClientSecureChannelConfig(const SOPC_SecureChannel_Config* scConfig)
435
0
{
436
0
    bool result = true;
437
0
    if (!scConfig->isClientSc)
438
0
    {
439
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: isClientSc flag not set");
440
0
        result = false;
441
0
    }
442
0
    if (NULL == scConfig->url)
443
0
    {
444
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
445
0
                               "AddSecureChannelConfig check: server endpoint URL not set");
446
0
        result = false;
447
0
    }
448
0
    if (NULL == scConfig->reqSecuPolicyUri)
449
0
    {
450
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
451
0
                               "AddSecureChannelConfig check: Security Policy URI not set");
452
0
        result = false;
453
0
    }
454
0
    if (scConfig->msgSecurityMode <= OpcUa_MessageSecurityMode_Invalid ||
455
0
        scConfig->msgSecurityMode >= OpcUa_MessageSecurityMode_SizeOf)
456
0
    {
457
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: Security Mode not set");
458
0
        result = false;
459
0
    }
460
0
    if (scConfig->requestedLifetime < SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME)
461
0
    {
462
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
463
0
                               "AddSecureChannelConfig check: requested lifetime is less than minimum defined: %" PRIu32
464
0
                               " < %" PRIu32,
465
0
                               scConfig->requestedLifetime, (uint32_t) SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME);
466
0
        result = false;
467
0
    }
468
0
    if (NULL == scConfig->clientConfigPtr)
469
0
    {
470
0
        SOPC_Logger_TraceError(
471
0
            SOPC_LOG_MODULE_CLIENTSERVER,
472
0
            "AddSecureChannelConfig check: client application configuration (clientConfigPtr) is not defined.");
473
0
        result = false;
474
0
    }
475
0
    else if ((NULL != scConfig->reqSecuPolicyUri &&
476
0
              (0 != strcmp(scConfig->reqSecuPolicyUri, SOPC_SecurityPolicy_None_URI))) ||
477
0
             scConfig->msgSecurityMode != OpcUa_MessageSecurityMode_None)
478
0
    {
479
0
        if (NULL == scConfig->clientConfigPtr->clientPKI)
480
0
        {
481
0
            SOPC_Logger_TraceError(
482
0
                SOPC_LOG_MODULE_CLIENTSERVER,
483
0
                "AddSecureChannelConfig check: PKI is not defined but is required due to Security policy / mode");
484
0
            result = false;
485
0
        }
486
0
        if (NULL == scConfig->clientConfigPtr->clientKeyCertPair)
487
0
        {
488
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
489
0
                                   "AddSecureChannelConfig check: Client certificate / key pair is not defined but is "
490
0
                                   "required due to Security policy / mode");
491
0
            result = false;
492
0
        }
493
0
        if (NULL == scConfig->peerAppCert)
494
0
        {
495
0
            SOPC_Logger_TraceError(
496
0
                SOPC_LOG_MODULE_CLIENTSERVER,
497
0
                "AddSecureChannelConfig check: Server certificate (peerAppCert) is not defined but is required "
498
0
                "due to Security policy / mode");
499
0
            result = false;
500
0
        }
501
0
    }
502
0
    return result;
503
0
}
504
505
SOPC_SecureChannelConfigIdx SOPC_ToolkitClient_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig)
506
0
{
507
0
    SOPC_ASSERT(NULL != scConfig);
508
0
    SOPC_SecureChannelConfigIdx result = 0;
509
510
0
    if (tConfig.initDone && SOPC_Internal_CheckClientSecureChannelConfig(scConfig))
511
0
    {
512
0
        SOPC_Mutex_Lock(&tConfig.mut);
513
0
        if (tConfig.scConfigIdxMax < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
514
0
        {
515
0
            tConfig.scConfigIdxMax++; // Minimum used == 1 && Maximum used == MAX + 1
516
0
            SOPC_ASSERT(NULL == tConfig.scConfigs[tConfig.scConfigIdxMax]);
517
0
            tConfig.scConfigs[tConfig.scConfigIdxMax] = scConfig;
518
0
            result = tConfig.scConfigIdxMax;
519
0
        }
520
0
        SOPC_Mutex_Unlock(&tConfig.mut);
521
0
    }
522
0
    return result;
523
0
}
524
525
SOPC_SecureChannel_Config* SOPC_ToolkitClient_GetSecureChannelConfig(uint32_t scConfigIdx)
526
0
{
527
0
    SOPC_SecureChannel_Config* res = NULL;
528
0
    if (scConfigIdx > 0 && scConfigIdx <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
529
0
    {
530
0
        if (tConfig.initDone)
531
0
        {
532
0
            SOPC_Mutex_Lock(&tConfig.mut);
533
0
            res = tConfig.scConfigs[scConfigIdx];
534
0
            SOPC_Mutex_Unlock(&tConfig.mut);
535
0
        }
536
0
    }
537
0
    return res;
538
0
}
539
540
const char* SOPC_ToolkitClient_GetReverseEndpointURL(SOPC_ReverseEndpointConfigIdx reverseEpCfgIdx)
541
0
{
542
0
    const char* res = NULL;
543
0
    if (SOPC_IS_VALID_REVERSE_EP_CONFIGURATION(reverseEpCfgIdx))
544
0
    {
545
0
        if (tConfig.initDone)
546
0
        {
547
0
            SOPC_Mutex_Lock(&tConfig.mut);
548
0
            res = tConfig.reverseEpConfigs[reverseEpCfgIdx - SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS];
549
0
            SOPC_Mutex_Unlock(&tConfig.mut);
550
0
        }
551
0
    }
552
0
    return res;
553
0
}
554
555
SOPC_SecureChannelConfigIdx SOPC_ToolkitServer_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig)
556
0
{
557
0
    SOPC_ASSERT(NULL != scConfig);
558
559
0
    SOPC_SecureChannelConfigIdx lastScIdx = 0;
560
0
    SOPC_SecureChannelConfigIdx idxWithServerOffset = 0;
561
562
    // TODO: check all parameters of scConfig (requested lifetime >= MIN, etc)
563
0
    if (tConfig.initDone)
564
0
    {
565
0
        SOPC_Mutex_Lock(&tConfig.mut);
566
0
        lastScIdx = tConfig.serverScLastConfigIdx;
567
0
        do
568
0
        {
569
0
            if (lastScIdx < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
570
0
            {
571
0
                lastScIdx++; // Minimum used == 1 && Maximum used == MAX + 1
572
0
                if (NULL == tConfig.serverScConfigs[lastScIdx])
573
0
                {
574
0
                    tConfig.serverScLastConfigIdx = lastScIdx;
575
0
                    tConfig.serverScConfigs[lastScIdx] = scConfig;
576
0
                    idxWithServerOffset = SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED +
577
0
                                          lastScIdx; // disjoint with SC config indexes for client
578
0
                }
579
0
            }
580
0
            else
581
0
            {
582
0
                lastScIdx = 0; // lastScIdx++ <=> lastScIdx = 1 will be tested next time
583
0
            }
584
0
        } while (0 == idxWithServerOffset && lastScIdx != tConfig.serverScLastConfigIdx);
585
0
        SOPC_Mutex_Unlock(&tConfig.mut);
586
0
    }
587
0
    return idxWithServerOffset;
588
0
}
589
590
static uint32_t SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(uint32_t serverScConfigIdx)
591
3
{
592
3
    uint32_t res = 0;
593
3
    if (serverScConfigIdx > SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED &&
594
0
        serverScConfigIdx <=
595
0
            2 * SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) // disjoint with SC config indexes for client
596
0
    {
597
0
        res = serverScConfigIdx - SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED;
598
0
    }
599
3
    return res;
600
3
}
601
602
SOPC_SecureChannel_Config* SOPC_ToolkitServer_GetSecureChannelConfig(uint32_t serverScConfigIdx)
603
3
{
604
3
    SOPC_SecureChannel_Config* res = NULL;
605
3
    uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx);
606
3
    if (idxWithoutOffset != 0 && tConfig.initDone)
607
0
    {
608
0
        SOPC_Mutex_Lock(&tConfig.mut);
609
0
        if (tConfig.serverConfigLocked)
610
0
        {
611
0
            res = tConfig.serverScConfigs[idxWithoutOffset];
612
0
        }
613
0
        SOPC_Mutex_Unlock(&tConfig.mut);
614
0
    }
615
3
    return res;
616
3
}
617
618
bool SOPC_ToolkitServer_RemoveSecureChannelConfig(uint32_t serverScConfigIdx)
619
0
{
620
0
    bool res = false;
621
0
    uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx);
622
0
    if (idxWithoutOffset != 0 && tConfig.initDone)
623
0
    {
624
0
        SOPC_Mutex_Lock(&tConfig.mut);
625
0
        if (tConfig.serverConfigLocked)
626
0
        {
627
0
            if (tConfig.serverScConfigs[idxWithoutOffset] != NULL)
628
0
            {
629
0
                res = true;
630
0
                SOPC_ToolkitServer_ClearScConfig_WithoutLock(idxWithoutOffset);
631
0
            }
632
0
        }
633
0
        SOPC_Mutex_Unlock(&tConfig.mut);
634
0
    }
635
0
    return res;
636
0
}
637
638
static bool SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(SOPC_Endpoint_Config* epConfig)
639
0
{
640
0
    SOPC_ASSERT(epConfig->nbSecuConfigs <= SOPC_MAX_SECU_POLICIES_CFG);
641
0
    int res = 0;
642
0
    bool hasNoneSecurityConfig = false;
643
0
    for (uint8_t i = 0; i < epConfig->nbSecuConfigs && !hasNoneSecurityConfig; i++)
644
0
    {
645
0
        res = strcmp(SOPC_SecurityPolicy_None_URI,
646
0
                     SOPC_String_GetRawCString(&epConfig->secuConfigurations[i].securityPolicy));
647
0
        hasNoneSecurityConfig = (0 == res);
648
0
    }
649
650
0
    if (!hasNoneSecurityConfig)
651
0
    {
652
0
        if (epConfig->nbSecuConfigs < SOPC_MAX_SECU_POLICIES_CFG)
653
0
        {
654
0
            SOPC_SecurityPolicy* secuPolicy = &epConfig->secuConfigurations[epConfig->nbSecuConfigs];
655
            // No user token policy defined to forbid any session to be activated on discovery endpoint only
656
0
            secuPolicy->nbOfUserTokenPolicies = 0;
657
0
            secuPolicy->securityModes = SOPC_SECURITY_MODE_NONE_MASK;
658
0
            SOPC_String_Initialize(&secuPolicy->securityPolicy);
659
0
            SOPC_ReturnStatus status =
660
0
                SOPC_String_AttachFromCstring(&secuPolicy->securityPolicy, SOPC_SecurityPolicy_None_URI);
661
0
            if (SOPC_STATUS_OK == status)
662
0
            {
663
                // Implicit discovery endpoint added
664
0
                epConfig->nbSecuConfigs++;
665
0
                hasNoneSecurityConfig = true;
666
0
            }
667
0
        } // else: no remaining config to add a discovery endpoint configuration
668
0
    }
669
670
0
    return hasNoneSecurityConfig;
671
0
}
672
673
SOPC_EndpointConfigIdx SOPC_ToolkitServer_AddEndpointConfig(SOPC_Endpoint_Config* epConfig)
674
0
{
675
0
    SOPC_EndpointConfigIdx result = 0;
676
0
    SOPC_ASSERT(NULL != epConfig);
677
0
    SOPC_ASSERT(NULL != epConfig->serverConfigPtr);
678
679
0
    if (epConfig->nbSecuConfigs > SOPC_MAX_SECU_POLICIES_CFG)
680
0
    {
681
0
        return result;
682
0
    }
683
684
0
    if (epConfig->hasDiscoveryEndpoint && !SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(epConfig))
685
0
    {
686
0
        return result;
687
0
    }
688
689
    // TODO: check all parameters of epConfig: certificate presence w.r.t. secu policy, app desc (Uris are valid
690
    // w.r.t. part 6), etc.
691
0
    if (tConfig.initDone)
692
0
    {
693
0
        SOPC_Mutex_Lock(&tConfig.mut);
694
0
        if (!tConfig.serverConfigLocked)
695
0
        {
696
0
            if (tConfig.epConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS)
697
0
            {
698
0
                tConfig.epConfigIdxMax++;
699
0
                SOPC_ASSERT(NULL == tConfig.epConfigs[tConfig.epConfigIdxMax]);
700
0
                tConfig.epConfigs[tConfig.epConfigIdxMax] = epConfig;
701
0
                result = tConfig.epConfigIdxMax;
702
0
            }
703
0
        }
704
0
        SOPC_Mutex_Unlock(&tConfig.mut);
705
0
    }
706
0
    return result;
707
0
}
708
709
SOPC_ReverseEndpointConfigIdx SOPC_ToolkitClient_AddReverseEndpointConfig(const char* reverseEndpointURL)
710
0
{
711
0
    SOPC_ReverseEndpointConfigIdx result = 0;
712
0
    SOPC_ASSERT(NULL != reverseEndpointURL);
713
714
0
    if (tConfig.initDone)
715
0
    {
716
0
        SOPC_Mutex_Lock(&tConfig.mut);
717
0
        if (tConfig.reverseEpConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS)
718
0
        {
719
0
            tConfig.reverseEpConfigIdxMax++;
720
0
            SOPC_ASSERT(NULL == tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax]);
721
0
            tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax] = reverseEndpointURL;
722
0
            result = tConfig.reverseEpConfigIdxMax;
723
0
        }
724
0
        SOPC_Mutex_Unlock(&tConfig.mut);
725
0
    }
726
0
    if (0 != result)
727
0
    {
728
        // Make server endpoint and client reverse endpoint configuration indexes disjoint
729
0
        result += SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS;
730
0
    }
731
0
    return result;
732
0
}
733
734
SOPC_Endpoint_Config* SOPC_ToolkitServer_GetEndpointConfig(uint32_t epConfigIdx)
735
2
{
736
2
    SOPC_Endpoint_Config* res = NULL;
737
2
    if (tConfig.initDone)
738
0
    {
739
0
        SOPC_Mutex_Lock(&tConfig.mut);
740
0
        if (tConfig.serverConfigLocked)
741
0
        {
742
0
            res = tConfig.epConfigs[epConfigIdx];
743
0
        }
744
0
        SOPC_Mutex_Unlock(&tConfig.mut);
745
0
    }
746
2
    return res;
747
2
}
748
749
SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace)
750
0
{
751
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
752
0
    if (addressSpace != NULL)
753
0
    {
754
0
        status = SOPC_STATUS_INVALID_STATE;
755
0
        if (tConfig.initDone)
756
0
        {
757
0
            SOPC_Mutex_Lock(&tConfig.mut);
758
0
            if (!tConfig.serverConfigLocked && !SOPC_AddressSpace_Check_Configured())
759
0
            {
760
0
                status = SOPC_STATUS_OK;
761
0
                SOPC_AddressSpace_SetConfigured(addressSpace);
762
0
            }
763
0
            SOPC_Mutex_Unlock(&tConfig.mut);
764
0
        }
765
0
    }
766
0
    return status;
767
0
}
768
769
SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceNotifCb(SOPC_AddressSpaceNotif_Fct* pAddSpaceNotifFct)
770
0
{
771
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
772
0
    if (pAddSpaceNotifFct != NULL)
773
0
    {
774
0
        status = SOPC_STATUS_INVALID_STATE;
775
0
        if (tConfig.initDone)
776
0
        {
777
0
            SOPC_Mutex_Lock(&tConfig.mut);
778
0
            if (!tConfig.serverConfigLocked && tConfig.appAddSpaceNotifCb == NULL)
779
0
            {
780
0
                status = SOPC_STATUS_OK;
781
0
                tConfig.appAddSpaceNotifCb = pAddSpaceNotifFct;
782
0
            }
783
0
            SOPC_Mutex_Unlock(&tConfig.mut);
784
0
        }
785
0
    }
786
0
    return status;
787
0
}
788
789
SOPC_Toolkit_Build_Info SOPC_ToolkitConfig_GetBuildInfo(void)
790
0
{
791
0
    return (SOPC_Toolkit_Build_Info){SOPC_Common_GetBuildInfo(), SOPC_ClientServer_GetBuildInfo()};
792
0
}
793
794
void SOPC_ToolkitClient_ClearAllSCs(void)
795
0
{
796
0
    if (!tConfig.initDone)
797
0
    {
798
0
        return;
799
0
    }
800
    // TODO: close all sessions !
801
0
    SOPC_Services_CloseAllSCs(true);
802
0
    SOPC_Mutex_Lock(&tConfig.mut);
803
0
    memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs));
804
0
    tConfig.scConfigIdxMax = 0;
805
0
    SOPC_Mutex_Unlock(&tConfig.mut);
806
0
}
807
808
SOPC_ReturnStatus SOPC_ToolkitServer_UsingLockedConfig(bool activate)
809
0
{
810
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_STATE;
811
0
    if (tConfig.initDone)
812
0
    {
813
0
        SOPC_ReturnStatus mutStatus = SOPC_Mutex_Lock(&tConfig.mut);
814
0
        SOPC_ASSERT(SOPC_STATUS_OK == mutStatus);
815
0
        if (tConfig.serverConfigLocked)
816
0
        {
817
0
            if (activate)
818
0
            {
819
0
                tConfig.serverConfigUsedCounter++;
820
0
                status = SOPC_STATUS_OK;
821
0
            }
822
0
            else if (tConfig.serverConfigUsedCounter > 0)
823
0
            {
824
0
                tConfig.serverConfigUsedCounter--;
825
0
                status = SOPC_STATUS_OK;
826
0
            }
827
            // Signal to waiting threads that condition criteria has changed
828
0
            mutStatus = SOPC_Condition_SignalAll(&tConfig.serverConfigCond);
829
0
            SOPC_ASSERT(SOPC_STATUS_OK == mutStatus);
830
0
        }
831
0
        mutStatus = SOPC_Mutex_Unlock(&tConfig.mut);
832
0
        SOPC_ASSERT(SOPC_STATUS_OK == mutStatus);
833
0
    }
834
0
    return status;
835
0
}
836
837
SOPC_ReturnStatus SOPC_ToolkitServer_UnConfigure(void)
838
0
{
839
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_STATE;
840
0
    if (tConfig.initDone)
841
0
    {
842
0
        SOPC_ReturnStatus mutStatus = SOPC_Mutex_Lock(&tConfig.mut);
843
0
        if (tConfig.serverConfigLocked)
844
0
        {
845
            // Notify services layer that server configuration will become unlocked
846
0
            SOPC_Services_EnqueueEvent(APP_TO_SE_SERVER_CONFIGURED, 0, (uintptr_t) false, 0);
847
848
            // Wait for services layer and secure channels to "release" the server configuration
849
0
            while (SOPC_STATUS_OK == mutStatus && tConfig.serverConfigUsedCounter > 0)
850
0
            {
851
0
                mutStatus = SOPC_Mutex_UnlockAndTimedWaitCond(&tConfig.serverConfigCond, &tConfig.mut,
852
0
                                                              SOPC_CHANGE_CONFIG_LOCK_STATE_TIMEOUT_MS);
853
0
            }
854
0
            if (SOPC_STATUS_TIMEOUT == mutStatus)
855
0
            {
856
                // Timeout reached, cannot unconfigure
857
0
                status = SOPC_STATUS_WOULD_BLOCK;
858
0
            }
859
0
            else
860
0
            {
861
                // Clear the server configuration
862
0
                tConfig.appAddSpaceNotifCb = NULL;
863
0
                tConfig.serverConfigLocked = false;
864
0
                status = SOPC_STATUS_OK;
865
                // Note: done by clear_server_configuration_context operation
866
                // address_space_bs__nodes = NULL;
867
0
            }
868
0
        }
869
0
        mutStatus = SOPC_Mutex_Unlock(&tConfig.mut);
870
0
        SOPC_ASSERT(SOPC_STATUS_OK == mutStatus);
871
0
    }
872
0
    return status;
873
0
}
874
875
SOPC_ReturnStatus SOPC_ToolkitServer_RemoveAllEndpointsConfig(void)
876
0
{
877
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_STATE;
878
0
    if (tConfig.initDone)
879
0
    {
880
0
        SOPC_Mutex_Lock(&tConfig.mut);
881
0
        if (!tConfig.serverConfigLocked)
882
0
        {
883
0
            tConfig.epConfigIdxMax = 0;
884
0
            memset(tConfig.epConfigs, 0, sizeof(tConfig.epConfigs));
885
0
            status = SOPC_STATUS_OK;
886
0
        }
887
0
        SOPC_Mutex_Unlock(&tConfig.mut);
888
0
    }
889
0
    return status;
890
0
}
891
892
SOPC_AddressSpaceNotif_Fct* SOPC_ToolkitServer_GetAddSpaceNotifCb(void)
893
0
{
894
0
    SOPC_AddressSpaceNotif_Fct* result = NULL;
895
0
    if (tConfig.initDone)
896
0
    {
897
0
        SOPC_Mutex_Lock(&tConfig.mut);
898
0
        result = tConfig.appAddSpaceNotifCb;
899
0
        SOPC_Mutex_Unlock(&tConfig.mut);
900
0
    }
901
0
    return result;
902
0
}