/src/S2OPC/src/ClientServer/configuration/sopc_toolkit_config.c
Line | Count | Source (jump to first uncovered line) |
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 | | uint8_t serverConfigLocked; |
57 | | SOPC_Mutex mut; |
58 | | /* Specific client */ |
59 | | SOPC_SecureChannel_Config* scConfigs[SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + 1]; |
60 | | const char* reverseEpConfigs[SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS + 1]; // index 0 reserved |
61 | | SOPC_SecureChannelConfigIdx scConfigIdxMax; |
62 | | SOPC_ReverseEndpointConfigIdx reverseEpConfigIdxMax; |
63 | | /* Specific server */ |
64 | | SOPC_SecureChannel_Config* serverScConfigs[SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + 1]; |
65 | | SOPC_Endpoint_Config* epConfigs[SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS + 1]; // index 0 reserved |
66 | | SOPC_SecureChannelConfigIdx serverScLastConfigIdx; |
67 | | SOPC_EndpointConfigIdx epConfigIdxMax; |
68 | | } // Any change in values below shall be also done in SOPC_Toolkit_Clear |
69 | | tConfig = {.initDone = false, |
70 | | .serverConfigLocked = false, |
71 | | .scConfigIdxMax = 0, |
72 | | .reverseEpConfigIdxMax = 0, |
73 | | .serverScLastConfigIdx = 0, |
74 | | .epConfigIdxMax = 0}; |
75 | | |
76 | | SOPC_ReturnStatus SOPC_Toolkit_Initialize(SOPC_ComEvent_Fct* pAppFct) |
77 | 0 | { |
78 | 0 | SOPC_ReturnStatus status = SOPC_STATUS_OK; |
79 | |
|
80 | 0 | if (NULL == pAppFct) |
81 | 0 | { |
82 | 0 | status = SOPC_STATUS_INVALID_PARAMETERS; |
83 | 0 | } |
84 | |
|
85 | 0 | bool bRet = SOPC_Common_IsInitialized(); |
86 | 0 | if (SOPC_STATUS_OK == status && !bRet) |
87 | 0 | { |
88 | | /* Initialize with default log configuration */ |
89 | 0 | SOPC_Log_Configuration defaultLogConfiguration = SOPC_Common_GetDefaultLogConfiguration(); |
90 | 0 | status = SOPC_Common_Initialize(defaultLogConfiguration); |
91 | 0 | } |
92 | |
|
93 | 0 | if (SOPC_STATUS_OK == status) |
94 | 0 | { |
95 | 0 | if (tConfig.initDone) |
96 | 0 | { |
97 | 0 | status = SOPC_STATUS_INVALID_STATE; |
98 | 0 | } |
99 | 0 | else |
100 | 0 | { |
101 | 0 | SOPC_Mutex_Initialization(&tConfig.mut); |
102 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
103 | | // Note: check again the flag to avoid possible concurrency issue detection by static analysis. |
104 | | // Nevertheless this function shall never be called concurrently since the mutex is created during |
105 | | // call |
106 | 0 | if (!tConfig.initDone) |
107 | 0 | { |
108 | 0 | tConfig.initDone = true; |
109 | |
|
110 | 0 | sopc_appEventCallback = pAppFct; |
111 | | |
112 | | // Ensure constants cannot be modified later |
113 | | // Return value is not check as the encoding config could be already set. |
114 | 0 | SOPC_Common_EncodingConstants defEncConst = SOPC_Common_GetDefaultEncodingConstants(); |
115 | 0 | bRet = SOPC_Common_SetEncodingConstants(defEncConst); |
116 | 0 | SOPC_Helper_Endianness_Check(); |
117 | |
|
118 | 0 | if (SOPC_STATUS_OK == status) |
119 | 0 | { |
120 | 0 | memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs)); |
121 | 0 | memset((void*) tConfig.reverseEpConfigs, 0, sizeof(tConfig.reverseEpConfigs)); |
122 | 0 | memset(tConfig.serverScConfigs, 0, sizeof(tConfig.serverScConfigs)); |
123 | 0 | memset(tConfig.epConfigs, 0, sizeof(tConfig.epConfigs)); |
124 | 0 | SOPC_App_Initialize(); |
125 | 0 | SOPC_EventTimer_Initialize(); |
126 | 0 | SOPC_Sockets_Initialize(); |
127 | 0 | SOPC_SecureChannels_Initialize(SOPC_Sockets_SetEventHandler); |
128 | 0 | SOPC_Services_Initialize(SOPC_SecureChannels_SetEventHandler); |
129 | |
|
130 | 0 | SOPC_Toolkit_Build_Info toolkitBuildInfo = SOPC_ToolkitConfig_GetBuildInfo(); |
131 | | |
132 | | /* set log level to INFO for version logging, then restore it */ |
133 | 0 | SOPC_Log_Level level = SOPC_Logger_GetTraceLogLevel(); |
134 | 0 | SOPC_Logger_SetTraceLogLevel(SOPC_LOG_LEVEL_INFO); |
135 | 0 | SOPC_Logger_TraceInfo(SOPC_LOG_MODULE_CLIENTSERVER, |
136 | 0 | "Common library DATE='%s' VERSION='%s' SIGNATURE='%s' DOCKER='%s'", |
137 | 0 | toolkitBuildInfo.commonBuildInfo.buildBuildDate, |
138 | 0 | toolkitBuildInfo.commonBuildInfo.buildVersion, |
139 | 0 | toolkitBuildInfo.commonBuildInfo.buildSrcCommit, |
140 | 0 | toolkitBuildInfo.commonBuildInfo.buildDockerId); |
141 | 0 | SOPC_Logger_TraceInfo( |
142 | 0 | SOPC_LOG_MODULE_CLIENTSERVER, |
143 | 0 | "Client/Server toolkit library DATE='%s' VERSION='%s' SIGNATURE='%s' DOCKER='%s'", |
144 | 0 | toolkitBuildInfo.clientServerBuildInfo.buildBuildDate, |
145 | 0 | toolkitBuildInfo.clientServerBuildInfo.buildVersion, |
146 | 0 | toolkitBuildInfo.clientServerBuildInfo.buildSrcCommit, |
147 | 0 | toolkitBuildInfo.clientServerBuildInfo.buildDockerId); |
148 | 0 | SOPC_Logger_SetTraceLogLevel(level); |
149 | 0 | } |
150 | 0 | } |
151 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
152 | 0 | } |
153 | 0 | } |
154 | |
|
155 | 0 | return status; |
156 | 0 | } |
157 | | |
158 | | static SOPC_ReturnStatus SOPC_SecurityCheck_UserCredentialsEncrypted(const SOPC_SecurityPolicy* pSecurityPolicy, |
159 | | const OpcUa_UserTokenPolicy* pUserTokenPolicies) |
160 | 0 | { |
161 | 0 | SOPC_ReturnStatus status = SOPC_STATUS_OK; |
162 | 0 | SOPC_String securityPolicyNoneURI; |
163 | 0 | SOPC_String_Initialize(&securityPolicyNoneURI); |
164 | 0 | status = SOPC_String_AttachFromCstring(&securityPolicyNoneURI, SOPC_SecurityPolicy_None_URI); |
165 | 0 | if (SOPC_STATUS_OK != status) |
166 | 0 | { |
167 | 0 | return SOPC_STATUS_NOK; |
168 | 0 | } |
169 | | |
170 | | // Check if SecurityPolicy "security mode" is "None" AND if "UserToken security policy" is "empty" (default) |
171 | 0 | if (0 != (pSecurityPolicy->securityModes & SOPC_SECURITY_MODE_NONE_MASK) && |
172 | 0 | pUserTokenPolicies->SecurityPolicyUri.Length <= 0) |
173 | 0 | { |
174 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
175 | 0 | "Security Check UserCredentials: Failed. Combination not allowed : SecurityPolicy " |
176 | 0 | "security mode is None and UserToken security policy is empty.\n"); |
177 | 0 | status = SOPC_STATUS_INVALID_PARAMETERS; |
178 | 0 | } |
179 | | |
180 | | // Check if SecurityPolicy "security mode" is "None or Sign" AND if "UserToken security policy" is "None" |
181 | 0 | else if (0 != (pSecurityPolicy->securityModes & (SOPC_SECURITY_MODE_SIGN_MASK | SOPC_SECURITY_MODE_NONE_MASK)) && |
182 | 0 | true == SOPC_String_Equal(&pUserTokenPolicies->SecurityPolicyUri, &securityPolicyNoneURI)) |
183 | 0 | { |
184 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
185 | 0 | "Security Check UserCredentials: Failed. Combination not allowed : SecurityPolicy " |
186 | 0 | "security mode is None or Sign and UserToken security policy is None.\n"); |
187 | 0 | status = SOPC_STATUS_INVALID_PARAMETERS; |
188 | 0 | } |
189 | 0 | return status; |
190 | 0 | } |
191 | | |
192 | | static SOPC_ReturnStatus SOPC_ToolkitServer_SecurityCheck(void) |
193 | 0 | { |
194 | 0 | SOPC_Endpoint_Config* pEpConfig; |
195 | 0 | SOPC_SecurityPolicy* pSecurityPolicy; |
196 | 0 | OpcUa_UserTokenPolicy* pUserTokenPolicies; |
197 | 0 | SOPC_ReturnStatus status = SOPC_STATUS_OK; |
198 | 0 | SOPC_ReturnStatus statusSecurityCheck = SOPC_STATUS_OK; |
199 | 0 | SOPC_String securityPolicyNoneURI; |
200 | |
|
201 | 0 | SOPC_String_Initialize(&securityPolicyNoneURI); |
202 | 0 | status = SOPC_String_AttachFromCstring(&securityPolicyNoneURI, SOPC_SecurityPolicy_None_URI); |
203 | 0 | if (SOPC_STATUS_OK != status) |
204 | 0 | { |
205 | 0 | return SOPC_STATUS_NOK; |
206 | 0 | } |
207 | | |
208 | 0 | for (uint32_t nbEpConfigIndex = 1; nbEpConfigIndex <= tConfig.epConfigIdxMax; nbEpConfigIndex++) |
209 | 0 | { |
210 | 0 | pEpConfig = tConfig.epConfigs[nbEpConfigIndex]; |
211 | |
|
212 | 0 | for (uint8_t nbSecuIndex = 0; nbSecuIndex < pEpConfig->nbSecuConfigs; nbSecuIndex++) |
213 | 0 | { |
214 | 0 | pSecurityPolicy = &pEpConfig->secuConfigurations[nbSecuIndex]; |
215 | |
|
216 | 0 | for (uint8_t nbTokenIndex = 0; nbTokenIndex < pSecurityPolicy->nbOfUserTokenPolicies; nbTokenIndex++) |
217 | 0 | { |
218 | 0 | pUserTokenPolicies = &pSecurityPolicy->userTokenPolicies[nbTokenIndex]; |
219 | |
|
220 | 0 | if (OpcUa_UserTokenType_Anonymous != pUserTokenPolicies->TokenType) |
221 | 0 | { |
222 | 0 | status = SOPC_SecurityCheck_UserCredentialsEncrypted(pSecurityPolicy, pUserTokenPolicies); |
223 | 0 | if (SOPC_STATUS_OK != status) |
224 | 0 | { |
225 | 0 | statusSecurityCheck = status; |
226 | 0 | } |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | /* Check if SecurityPolicy "security policy URI" is different from "None" AND if SecurityPolicy "security |
231 | | mode" is "None" */ |
232 | 0 | if (false == SOPC_String_Equal(&pSecurityPolicy->securityPolicy, &securityPolicyNoneURI) && |
233 | 0 | 0 != (pSecurityPolicy->securityModes & SOPC_SECURITY_MODE_NONE_MASK)) |
234 | 0 | { |
235 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
236 | 0 | "Security Check: Failed. Combination not allowed : SecurityPolicy security " |
237 | 0 | "policy URI is different from None and SecurityPolicy security mode is None.\n"); |
238 | 0 | statusSecurityCheck = SOPC_STATUS_INVALID_PARAMETERS; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | } |
242 | 0 | return statusSecurityCheck; |
243 | 0 | } |
244 | | |
245 | | SOPC_ReturnStatus SOPC_ToolkitServer_Configured(void) |
246 | 0 | { |
247 | 0 | SOPC_ReturnStatus status = SOPC_STATUS_INVALID_STATE; |
248 | 0 | if (tConfig.initDone) |
249 | 0 | { |
250 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
251 | 0 | if (!tConfig.serverConfigLocked) |
252 | 0 | { |
253 | | // Check an address space is defined in case a endpoint configuration exists |
254 | 0 | if (tConfig.epConfigIdxMax > 0 && sopc_addressSpace_configured) |
255 | 0 | { |
256 | 0 | tConfig.serverConfigLocked = true; |
257 | 0 | SOPC_AddressSpace_Check_Configured(); |
258 | 0 | status = SOPC_ToolkitServer_SecurityCheck(); |
259 | 0 | } |
260 | 0 | else |
261 | 0 | { |
262 | | // No address space defined whereas a server configuration exists |
263 | 0 | status = SOPC_STATUS_INVALID_PARAMETERS; |
264 | 0 | } |
265 | 0 | } |
266 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
267 | 0 | } |
268 | 0 | return status; |
269 | 0 | } |
270 | | |
271 | | static void SOPC_ToolkitServer_ClearScConfig_WithoutLock(uint32_t serverScConfigIdxWithoutOffset) |
272 | 0 | { |
273 | 0 | SOPC_SecureChannel_Config* scConfig = tConfig.serverScConfigs[serverScConfigIdxWithoutOffset]; |
274 | 0 | if (scConfig != NULL) |
275 | 0 | { |
276 | 0 | SOPC_ASSERT(!scConfig->isClientSc); |
277 | | // In case of server it is an internally created config |
278 | | // => only client certificate was specifically allocated |
279 | | // Exceptional case: configuration added internally and shall be freed on clear call |
280 | 0 | SOPC_KeyCertPair_Delete(&scConfig->peerAppCert); |
281 | 0 | SOPC_Free(scConfig); |
282 | 0 | tConfig.serverScConfigs[serverScConfigIdxWithoutOffset] = NULL; |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | // Deallocate fields allocated on server side only and free all the SC configs |
287 | | static void SOPC_Toolkit_ClearServerScConfigs_WithoutLock(void) |
288 | 0 | { |
289 | | // Index 0 reserved for indet, index = MAX valid |
290 | 0 | for (uint32_t i = 1; i <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED; i++) |
291 | 0 | { |
292 | 0 | SOPC_ToolkitServer_ClearScConfig_WithoutLock(i); |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | | void SOPC_Toolkit_Clear(void) |
297 | 0 | { |
298 | 0 | if (tConfig.initDone) |
299 | 0 | { |
300 | | // Services are in charge to gracefully close all connections. |
301 | | // It must be done before stopping the services |
302 | 0 | SOPC_Services_CloseAllSCs(false); |
303 | | |
304 | | // Ensure no new events are triggered by timers |
305 | 0 | SOPC_EventTimer_PreClear(); |
306 | |
|
307 | 0 | SOPC_Sockets_Clear(); |
308 | 0 | SOPC_SecureChannels_Clear(); |
309 | 0 | SOPC_Services_Clear(); |
310 | 0 | SOPC_App_Clear(); |
311 | 0 | SOPC_EventTimer_Clear(); |
312 | |
|
313 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
314 | | // Note: check again the flag to avoid possible concurrency issue detection by static analysis. |
315 | | // Nevertheless this function shall never be called concurrently since the mutex is destroyed after call. |
316 | 0 | if (tConfig.initDone) |
317 | 0 | { |
318 | 0 | SOPC_Toolkit_ClearServerScConfigs_WithoutLock(); |
319 | 0 | sopc_appEventCallback = NULL; |
320 | 0 | sopc_appAddressSpaceNotificationCallback = NULL; |
321 | 0 | address_space_bs__nodes = NULL; |
322 | 0 | sopc_addressSpace_configured = false; |
323 | | // Reset values to init value |
324 | 0 | tConfig.initDone = false; |
325 | 0 | tConfig.serverConfigLocked = false; |
326 | 0 | tConfig.scConfigIdxMax = 0; |
327 | 0 | tConfig.reverseEpConfigIdxMax = 0; |
328 | 0 | tConfig.serverScLastConfigIdx = 0; |
329 | 0 | tConfig.epConfigIdxMax = 0; |
330 | 0 | } |
331 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
332 | 0 | SOPC_Mutex_Clear(&tConfig.mut); |
333 | 0 | } |
334 | 0 | SOPC_Common_Clear(); |
335 | 0 | } |
336 | | |
337 | | static bool SOPC_Internal_CheckClientSecureChannelConfig(const SOPC_SecureChannel_Config* scConfig) |
338 | 0 | { |
339 | 0 | bool result = true; |
340 | 0 | if (!scConfig->isClientSc) |
341 | 0 | { |
342 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: isClientSc flag not set"); |
343 | 0 | result = false; |
344 | 0 | } |
345 | 0 | if (NULL == scConfig->url) |
346 | 0 | { |
347 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
348 | 0 | "AddSecureChannelConfig check: server endpoint URL not set"); |
349 | 0 | result = false; |
350 | 0 | } |
351 | 0 | if (NULL == scConfig->reqSecuPolicyUri) |
352 | 0 | { |
353 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
354 | 0 | "AddSecureChannelConfig check: Security Policy URI not set"); |
355 | 0 | result = false; |
356 | 0 | } |
357 | 0 | if (scConfig->msgSecurityMode <= OpcUa_MessageSecurityMode_Invalid || |
358 | 0 | scConfig->msgSecurityMode >= OpcUa_MessageSecurityMode_SizeOf) |
359 | 0 | { |
360 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: Security Mode not set"); |
361 | 0 | result = false; |
362 | 0 | } |
363 | 0 | if (scConfig->requestedLifetime < SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME) |
364 | 0 | { |
365 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
366 | 0 | "AddSecureChannelConfig check: requested lifetime is less than minimum defined: %" PRIu32 |
367 | 0 | " < %" PRIu32, |
368 | 0 | scConfig->requestedLifetime, (uint32_t) SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME); |
369 | 0 | result = false; |
370 | 0 | } |
371 | 0 | if (NULL == scConfig->clientConfigPtr) |
372 | 0 | { |
373 | 0 | SOPC_Logger_TraceError( |
374 | 0 | SOPC_LOG_MODULE_CLIENTSERVER, |
375 | 0 | "AddSecureChannelConfig check: client application configuration (clientConfigPtr) is not defined."); |
376 | 0 | result = false; |
377 | 0 | } |
378 | 0 | else if ((NULL != scConfig->reqSecuPolicyUri && |
379 | 0 | (0 != strcmp(scConfig->reqSecuPolicyUri, SOPC_SecurityPolicy_None_URI))) || |
380 | 0 | scConfig->msgSecurityMode != OpcUa_MessageSecurityMode_None) |
381 | 0 | { |
382 | 0 | if (NULL == scConfig->clientConfigPtr->clientPKI) |
383 | 0 | { |
384 | 0 | SOPC_Logger_TraceError( |
385 | 0 | SOPC_LOG_MODULE_CLIENTSERVER, |
386 | 0 | "AddSecureChannelConfig check: PKI is not defined but is required due to Security policy / mode"); |
387 | 0 | result = false; |
388 | 0 | } |
389 | 0 | if (NULL == scConfig->clientConfigPtr->clientKeyCertPair) |
390 | 0 | { |
391 | 0 | SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, |
392 | 0 | "AddSecureChannelConfig check: Client certificate / key pair is not defined but is " |
393 | 0 | "required due to Security policy / mode"); |
394 | 0 | result = false; |
395 | 0 | } |
396 | 0 | if (NULL == scConfig->peerAppCert) |
397 | 0 | { |
398 | 0 | SOPC_Logger_TraceError( |
399 | 0 | SOPC_LOG_MODULE_CLIENTSERVER, |
400 | 0 | "AddSecureChannelConfig check: Server certificate (peerAppCert) is not defined but is required " |
401 | 0 | "due to Security policy / mode"); |
402 | 0 | result = false; |
403 | 0 | } |
404 | 0 | } |
405 | 0 | return result; |
406 | 0 | } |
407 | | |
408 | | SOPC_SecureChannelConfigIdx SOPC_ToolkitClient_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig) |
409 | 0 | { |
410 | 0 | SOPC_ASSERT(NULL != scConfig); |
411 | 0 | SOPC_SecureChannelConfigIdx result = 0; |
412 | |
|
413 | 0 | if (tConfig.initDone && SOPC_Internal_CheckClientSecureChannelConfig(scConfig)) |
414 | 0 | { |
415 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
416 | 0 | if (tConfig.scConfigIdxMax < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) |
417 | 0 | { |
418 | 0 | tConfig.scConfigIdxMax++; // Minimum used == 1 && Maximum used == MAX + 1 |
419 | 0 | SOPC_ASSERT(NULL == tConfig.scConfigs[tConfig.scConfigIdxMax]); |
420 | 0 | tConfig.scConfigs[tConfig.scConfigIdxMax] = scConfig; |
421 | 0 | result = tConfig.scConfigIdxMax; |
422 | 0 | } |
423 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
424 | 0 | } |
425 | 0 | return result; |
426 | 0 | } |
427 | | |
428 | | SOPC_SecureChannel_Config* SOPC_ToolkitClient_GetSecureChannelConfig(uint32_t scConfigIdx) |
429 | 0 | { |
430 | 0 | SOPC_SecureChannel_Config* res = NULL; |
431 | 0 | if (scConfigIdx > 0 && scConfigIdx <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) |
432 | 0 | { |
433 | 0 | if (tConfig.initDone) |
434 | 0 | { |
435 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
436 | 0 | res = tConfig.scConfigs[scConfigIdx]; |
437 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
438 | 0 | } |
439 | 0 | } |
440 | 0 | return res; |
441 | 0 | } |
442 | | |
443 | | const char* SOPC_ToolkitClient_GetReverseEndpointURL(SOPC_ReverseEndpointConfigIdx reverseEpCfgIdx) |
444 | 0 | { |
445 | 0 | const char* res = NULL; |
446 | 0 | if (SOPC_IS_VALID_REVERSE_EP_CONFIGURATION(reverseEpCfgIdx)) |
447 | 0 | { |
448 | 0 | if (tConfig.initDone) |
449 | 0 | { |
450 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
451 | 0 | res = tConfig.reverseEpConfigs[reverseEpCfgIdx - SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS]; |
452 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
453 | 0 | } |
454 | 0 | } |
455 | 0 | return res; |
456 | 0 | } |
457 | | |
458 | | SOPC_SecureChannelConfigIdx SOPC_ToolkitServer_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig) |
459 | 0 | { |
460 | 0 | SOPC_ASSERT(NULL != scConfig); |
461 | | |
462 | 0 | SOPC_SecureChannelConfigIdx lastScIdx = 0; |
463 | 0 | SOPC_SecureChannelConfigIdx idxWithServerOffset = 0; |
464 | | |
465 | | // TODO: check all parameters of scConfig (requested lifetime >= MIN, etc) |
466 | 0 | if (tConfig.initDone) |
467 | 0 | { |
468 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
469 | 0 | lastScIdx = tConfig.serverScLastConfigIdx; |
470 | 0 | do |
471 | 0 | { |
472 | 0 | if (lastScIdx < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) |
473 | 0 | { |
474 | 0 | lastScIdx++; // Minimum used == 1 && Maximum used == MAX + 1 |
475 | 0 | if (NULL == tConfig.serverScConfigs[lastScIdx]) |
476 | 0 | { |
477 | 0 | tConfig.serverScLastConfigIdx = lastScIdx; |
478 | 0 | tConfig.serverScConfigs[lastScIdx] = scConfig; |
479 | 0 | idxWithServerOffset = SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + |
480 | 0 | lastScIdx; // disjoint with SC config indexes for client |
481 | 0 | } |
482 | 0 | } |
483 | 0 | else |
484 | 0 | { |
485 | 0 | lastScIdx = 0; // lastScIdx++ <=> lastScIdx = 1 will be tested next time |
486 | 0 | } |
487 | 0 | } while (0 == idxWithServerOffset && lastScIdx != tConfig.serverScLastConfigIdx); |
488 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
489 | 0 | } |
490 | 0 | return idxWithServerOffset; |
491 | 0 | } |
492 | | |
493 | | static uint32_t SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(uint32_t serverScConfigIdx) |
494 | 2 | { |
495 | 2 | uint32_t res = 0; |
496 | 2 | if (serverScConfigIdx > SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED && |
497 | 2 | serverScConfigIdx <= |
498 | 0 | 2 * SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) // disjoint with SC config indexes for client |
499 | 0 | { |
500 | 0 | res = serverScConfigIdx - SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED; |
501 | 0 | } |
502 | 2 | return res; |
503 | 2 | } |
504 | | |
505 | | SOPC_SecureChannel_Config* SOPC_ToolkitServer_GetSecureChannelConfig(uint32_t serverScConfigIdx) |
506 | 2 | { |
507 | 2 | SOPC_SecureChannel_Config* res = NULL; |
508 | 2 | uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx); |
509 | 2 | if (idxWithoutOffset != 0 && tConfig.initDone) |
510 | 0 | { |
511 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
512 | 0 | if (tConfig.serverConfigLocked) |
513 | 0 | { |
514 | 0 | res = tConfig.serverScConfigs[idxWithoutOffset]; |
515 | 0 | } |
516 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
517 | 0 | } |
518 | 2 | return res; |
519 | 2 | } |
520 | | |
521 | | bool SOPC_ToolkitServer_RemoveSecureChannelConfig(uint32_t serverScConfigIdx) |
522 | 0 | { |
523 | 0 | bool res = false; |
524 | 0 | uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx); |
525 | 0 | if (idxWithoutOffset != 0 && tConfig.initDone) |
526 | 0 | { |
527 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
528 | 0 | if (tConfig.serverConfigLocked) |
529 | 0 | { |
530 | 0 | if (tConfig.serverScConfigs[idxWithoutOffset] != NULL) |
531 | 0 | { |
532 | 0 | res = true; |
533 | 0 | SOPC_ToolkitServer_ClearScConfig_WithoutLock(idxWithoutOffset); |
534 | 0 | } |
535 | 0 | } |
536 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
537 | 0 | } |
538 | 0 | return res; |
539 | 0 | } |
540 | | |
541 | | static bool SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(SOPC_Endpoint_Config* epConfig) |
542 | 0 | { |
543 | 0 | SOPC_ASSERT(epConfig->nbSecuConfigs <= SOPC_MAX_SECU_POLICIES_CFG); |
544 | 0 | int res = 0; |
545 | 0 | bool hasNoneSecurityConfig = false; |
546 | 0 | for (uint8_t i = 0; i < epConfig->nbSecuConfigs && !hasNoneSecurityConfig; i++) |
547 | 0 | { |
548 | 0 | res = strcmp(SOPC_SecurityPolicy_None_URI, |
549 | 0 | SOPC_String_GetRawCString(&epConfig->secuConfigurations[i].securityPolicy)); |
550 | 0 | hasNoneSecurityConfig = (0 == res); |
551 | 0 | } |
552 | |
|
553 | 0 | if (!hasNoneSecurityConfig) |
554 | 0 | { |
555 | 0 | if (epConfig->nbSecuConfigs < SOPC_MAX_SECU_POLICIES_CFG) |
556 | 0 | { |
557 | 0 | SOPC_SecurityPolicy* secuPolicy = &epConfig->secuConfigurations[epConfig->nbSecuConfigs]; |
558 | | // No user token policy defined to forbid any session to be activated on discovery endpoint only |
559 | 0 | secuPolicy->nbOfUserTokenPolicies = 0; |
560 | 0 | secuPolicy->securityModes = SOPC_SECURITY_MODE_NONE_MASK; |
561 | 0 | SOPC_String_Initialize(&secuPolicy->securityPolicy); |
562 | 0 | SOPC_ReturnStatus status = |
563 | 0 | SOPC_String_AttachFromCstring(&secuPolicy->securityPolicy, SOPC_SecurityPolicy_None_URI); |
564 | 0 | if (SOPC_STATUS_OK == status) |
565 | 0 | { |
566 | | // Implicit discovery endpoint added |
567 | 0 | epConfig->nbSecuConfigs++; |
568 | 0 | hasNoneSecurityConfig = true; |
569 | 0 | } |
570 | 0 | } // else: no remaining config to add a discovery endpoint configuration |
571 | 0 | } |
572 | |
|
573 | 0 | return hasNoneSecurityConfig; |
574 | 0 | } |
575 | | |
576 | | SOPC_EndpointConfigIdx SOPC_ToolkitServer_AddEndpointConfig(SOPC_Endpoint_Config* epConfig) |
577 | 0 | { |
578 | 0 | SOPC_EndpointConfigIdx result = 0; |
579 | 0 | SOPC_ASSERT(NULL != epConfig); |
580 | 0 | SOPC_ASSERT(NULL != epConfig->serverConfigPtr); |
581 | | |
582 | 0 | if (epConfig->nbSecuConfigs > SOPC_MAX_SECU_POLICIES_CFG) |
583 | 0 | { |
584 | 0 | return result; |
585 | 0 | } |
586 | | |
587 | 0 | if (epConfig->hasDiscoveryEndpoint && !SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(epConfig)) |
588 | 0 | { |
589 | 0 | return result; |
590 | 0 | } |
591 | | |
592 | | // TODO: check all parameters of epConfig: certificate presence w.r.t. secu policy, app desc (Uris are valid |
593 | | // w.r.t. part 6), etc. |
594 | 0 | if (tConfig.initDone) |
595 | 0 | { |
596 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
597 | 0 | if (!tConfig.serverConfigLocked) |
598 | 0 | { |
599 | 0 | if (tConfig.epConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS) |
600 | 0 | { |
601 | 0 | tConfig.epConfigIdxMax++; |
602 | 0 | SOPC_ASSERT(NULL == tConfig.epConfigs[tConfig.epConfigIdxMax]); |
603 | 0 | tConfig.epConfigs[tConfig.epConfigIdxMax] = epConfig; |
604 | 0 | result = tConfig.epConfigIdxMax; |
605 | 0 | } |
606 | 0 | } |
607 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
608 | 0 | } |
609 | 0 | return result; |
610 | 0 | } |
611 | | |
612 | | SOPC_ReverseEndpointConfigIdx SOPC_ToolkitClient_AddReverseEndpointConfig(const char* reverseEndpointURL) |
613 | 0 | { |
614 | 0 | SOPC_ReverseEndpointConfigIdx result = 0; |
615 | 0 | SOPC_ASSERT(NULL != reverseEndpointURL); |
616 | | |
617 | 0 | if (tConfig.initDone) |
618 | 0 | { |
619 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
620 | 0 | if (tConfig.reverseEpConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS) |
621 | 0 | { |
622 | 0 | tConfig.reverseEpConfigIdxMax++; |
623 | 0 | SOPC_ASSERT(NULL == tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax]); |
624 | 0 | tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax] = reverseEndpointURL; |
625 | 0 | result = tConfig.reverseEpConfigIdxMax; |
626 | 0 | } |
627 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
628 | 0 | } |
629 | 0 | if (0 != result) |
630 | 0 | { |
631 | | // Make server endpoint and client reverse endpoint configuration indexes disjoint |
632 | 0 | result += SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS; |
633 | 0 | } |
634 | 0 | return result; |
635 | 0 | } |
636 | | |
637 | | SOPC_Endpoint_Config* SOPC_ToolkitServer_GetEndpointConfig(uint32_t epConfigIdx) |
638 | 7 | { |
639 | 7 | SOPC_Endpoint_Config* res = NULL; |
640 | 7 | if (tConfig.initDone) |
641 | 0 | { |
642 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
643 | 0 | if (tConfig.serverConfigLocked) |
644 | 0 | { |
645 | 0 | res = tConfig.epConfigs[epConfigIdx]; |
646 | 0 | } |
647 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
648 | 0 | } |
649 | 7 | return res; |
650 | 7 | } |
651 | | |
652 | | static void SOPC_Internal_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace) |
653 | 0 | { |
654 | 0 | SOPC_ASSERT(NULL != addressSpace); |
655 | 0 | address_space_bs__nodes = addressSpace; |
656 | 0 | sopc_addressSpace_configured = true; |
657 | 0 | } |
658 | | |
659 | | SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace) |
660 | 0 | { |
661 | 0 | SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS; |
662 | 0 | if (addressSpace != NULL) |
663 | 0 | { |
664 | 0 | status = SOPC_STATUS_INVALID_STATE; |
665 | 0 | if (tConfig.initDone) |
666 | 0 | { |
667 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
668 | 0 | if (!tConfig.serverConfigLocked && !sopc_addressSpace_configured) |
669 | 0 | { |
670 | 0 | status = SOPC_STATUS_OK; |
671 | 0 | SOPC_Internal_ToolkitServer_SetAddressSpaceConfig(addressSpace); |
672 | 0 | } |
673 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
674 | 0 | } |
675 | 0 | } |
676 | 0 | return status; |
677 | 0 | } |
678 | | |
679 | | SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceNotifCb(SOPC_AddressSpaceNotif_Fct* pAddSpaceNotifFct) |
680 | 0 | { |
681 | 0 | SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS; |
682 | 0 | if (pAddSpaceNotifFct != NULL) |
683 | 0 | { |
684 | 0 | status = SOPC_STATUS_INVALID_STATE; |
685 | 0 | if (tConfig.initDone) |
686 | 0 | { |
687 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
688 | 0 | if (!tConfig.serverConfigLocked && sopc_appAddressSpaceNotificationCallback == NULL) |
689 | 0 | { |
690 | 0 | status = SOPC_STATUS_OK; |
691 | 0 | sopc_appAddressSpaceNotificationCallback = pAddSpaceNotifFct; |
692 | 0 | } |
693 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
694 | 0 | } |
695 | 0 | } |
696 | 0 | return status; |
697 | 0 | } |
698 | | |
699 | | SOPC_Toolkit_Build_Info SOPC_ToolkitConfig_GetBuildInfo(void) |
700 | 0 | { |
701 | 0 | return (SOPC_Toolkit_Build_Info){SOPC_Common_GetBuildInfo(), SOPC_ClientServer_GetBuildInfo()}; |
702 | 0 | } |
703 | | |
704 | | void SOPC_ToolkitClient_ClearAllSCs(void) |
705 | 0 | { |
706 | 0 | if (!tConfig.initDone) |
707 | 0 | { |
708 | 0 | return; |
709 | 0 | } |
710 | | // TODO: close all sessions ! |
711 | 0 | SOPC_Services_CloseAllSCs(true); |
712 | 0 | SOPC_Mutex_Lock(&tConfig.mut); |
713 | 0 | memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs)); |
714 | 0 | tConfig.scConfigIdxMax = 0; |
715 | 0 | SOPC_Mutex_Unlock(&tConfig.mut); |
716 | 0 | } |