diff --git a/CHANGELOG b/CHANGELOG index cf2264d0..09b503f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,11 +17,13 @@ Other changes: - Ethernet(Linux): Set to promisc mode by default - removed legacy defines for report reasons (#449) +- removed legacy compatibility functions for SV subscriner ("SVClientaSDU_") Fixed bugs and vulnerabilities: -- fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513) -- ACSE: fixed out-of-bounds read in parseAarqPdu function (LIB61850-441)(#512) +- Vulnerability: fixed potential stack buffer overflow in MMS client identity service and other services (LIB61850-447) +- Vulnerability: fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513) +- Vulnerability: ACSE: fixed out-of-bounds read in parseAarqPdu function (LIB61850-441)(#512) - GOOSE receiver: added additional length and plausibility checks to fix #509 - MmsValue_decodeMmsData: add support for empty visible-string, mms-string, and octet-string values (#506) - MMS client: fixed - getNameList task can get stuck in while loop when message cannot be sent (LIB61850-347) @@ -32,7 +34,7 @@ Fixed bugs and vulnerabilities: - MMS server: fixed - server is sending data set response larger than negotiated MMS PDU size (LIB61850-435) - fixed - potential race condition when using IedConnection_installReportHandler and IedConnection_uninstallReportHandler - fixed - IEC 61580 server: dataset is not released when RCB.Datset is set to empty string by client (LIB61850-425) -- MMS client: fixed - parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469) +- Vulnerability: MMS client: fixed - parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7499c8c2..99f636fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,8 @@ option(CONFIG_IEC61850_SERVICE_TRACKING "Build with support for IEC 61850 servic option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON) option(CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL "Allow user provided callback to control read access" ON) option(CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT "allow only configured clients (when pre-configured by ClientLN)" OFF) +option(CONFIG_IEC61850_L2_GOOSE "Build with support for L2 GOOSE (winpcap required on windows)" ON) +option(CONFIG_IEC61850_L2_SMV "Build with support for L2 SMV (winpcap required on windows)" ON) option(CONFIG_IEC61850_R_GOOSE "Build with support for R-GOOSE (mbedtls required)" ON) option(CONFIG_IEC61850_R_SMV "Build with support for R-SMV (mbedtls required)" ON) option(CONFIG_IEC61850_SNTP_CLIENT "Build with SNTP client code" ON) @@ -142,12 +144,17 @@ set(FOUND_SQLITE3_SOURCE 1) message("Found sqlite3 source in third_party folder -> can compile with log service support") endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h) +if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0) +set(WITH_MBEDTLS3 1) +set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0/include") +else() if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28) set(WITH_MBEDTLS 1) set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include") endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28) +endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0) -if(WITH_MBEDTLS) +if(WITH_MBEDTLS OR WITH_MBEDTLS3) add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1) @@ -163,7 +170,12 @@ if (CONFIG_IEC61850_SNTP_CLIENT) set(BUILD_SNTP_CLIENT_EXAMPLES 1) endif (CONFIG_IEC61850_SNTP_CLIENT) -endif(WITH_MBEDTLS) +else(WITH_MBEDTLS OR WITH_MBEDTLS3) + +set(CONFIG_IEC61850_R_GOOSE 0) +set(CONFIG_IEC61850_R_SMV 0) + +endif(WITH_MBEDTLS OR WITH_MBEDTLS3) include(CheckCCompilerFlag) diff --git a/Makefile b/Makefile index ef530346..a7fef22a 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,7 @@ LIB_INCLUDE_DIRS += src/sampled_values LIB_INCLUDE_DIRS += src/iec61850/inc LIB_INCLUDE_DIRS += src/iec61850/inc_private LIB_INCLUDE_DIRS += src/logging +LIB_INCLUDE_DIRS += src/r_session LIB_INCLUDE_DIRS += src/tls ifeq ($(HAL_IMPL), WIN32) LIB_INCLUDE_DIRS += third_party/winpcap/Include @@ -84,6 +85,8 @@ LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.28/include LIB_INCLUDE_DIRS += hal/tls/mbedtls CFLAGS += -D'MBEDTLS_CONFIG_FILE="mbedtls_config.h"' CFLAGS += -D'CONFIG_MMS_SUPPORT_TLS=1' +CFLAGS += -D'CONFIG_IEC61850_R_GOOSE=1' +CFLAGS += -D'CONFIG_IEC61850_R_SMV=1' endif LIB_INCLUDES = $(addprefix -I,$(LIB_INCLUDE_DIRS)) @@ -120,6 +123,7 @@ LIB_API_HEADER_FILES += src/goose/goose_publisher.h LIB_API_HEADER_FILES += src/sampled_values/sv_subscriber.h LIB_API_HEADER_FILES += src/sampled_values/sv_publisher.h LIB_API_HEADER_FILES += src/logging/logging_api.h +LIB_API_HEADER_FILES += src/r_session/r_session.h get_sources_from_directory = $(wildcard $1/*.c) get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir))) @@ -137,13 +141,13 @@ ifneq ($(HAL_IMPL), WIN32) CFLAGS += -Wuninitialized endif -CFLAGS += -Wsign-compare CFLAGS += -Wpointer-arith CFLAGS += -Wnested-externs CFLAGS += -Wmissing-declarations CFLAGS += -Wshadow CFLAGS += -Wall CFLAGS += -Wextra +CFLAGS += -Wno-sign-compare CFLAGS += -Wno-format #CFLAGS += -Wconditional-uninitialized #CFLAGS += -Werror diff --git a/README.md b/README.md index d8024cff..c8086bfa 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ The library support the following IEC 61850 protocol features: * Setting group handling * Support for service tracking * GOOSE and SV control block handling -* Support for R-session protocol/R-GOOSE/R-SMV -* Simple SNTP client code +* Support for R-session protocol/R-GOOSE/R-SMV (BETA) +* Simple SNTP client code (BETA) * TLS support * C and C#/.NET API diff --git a/config/stack_config.h b/config/stack_config.h index 37e663e3..00ac2bcc 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -68,36 +68,20 @@ /* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */ #define CONFIG_COTP_MAX_TPDU_SIZE 8192 -/* Ethernet interface ID for GOOSE and SV */ +/* Ethernet interface ID for L2 GOOSE and SV */ #define CONFIG_ETHERNET_INTERFACE_ID "eth0" /* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */ /* #define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. */ -/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */ +/* Set to 1 to include generic GOOSE support in the build. Otherwise set to 0 */ #define CONFIG_INCLUDE_GOOSE_SUPPORT 1 -/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */ +/* Set to 1 to include generic Sampled Values support in the build. Otherwise set to 0 */ #define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1 /* Set to 1 to compile for edition 1 server - default is 0 to compile for edition 2 */ #define CONFIG_IEC61850_EDITION_1 0 -#ifdef _WIN32 - -/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */ -#ifdef EXCLUDE_ETHERNET_WINDOWS -#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT -#undef CONFIG_INCLUDE_GOOSE_SUPPORT -#endif -#define CONFIG_INCLUDE_GOOSE_SUPPORT 0 -#define CONFIG_INCUDE_ETHERNET_WINDOWS 0 -#else -#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1 -#undef CONFIG_ETHERNET_INTERFACE_ID -#define CONFIG_ETHERNET_INTERFACE_ID "0" -#endif -#endif - /* The GOOSE retransmission interval in ms for the stable condition - i.e. no monitored value changed */ #define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000 @@ -179,9 +163,36 @@ /* compile with support for R-SMV (mbedtls required) */ #define CONFIG_IEC61850_R_SMV 0 +/* compile with support for L2 GOOSE */ +#define CONFIG_IEC61850_L2_GOOSE 0 + +/* compile with support for L2 SMV */ +#define CONFIG_IEC61850_L2_SMV 0 + /* compile SNTP client code */ #define CONFIG_IEC61850_SNTP_CLIENT 0 + +#ifdef _WIN32 + +/* L2 GOOSE/SMV will be disabled for Windows if ethernet support (winpcap) is not available */ +#ifdef EXCLUDE_ETHERNET_WINDOWS +#ifdef CONFIG_IEC61850_L2_GOOSE +#undef CONFIG_IEC61850_L2_GOOSE +#endif +#ifdef CONFIG_IEC61850_L2_SMV +#undef CONFIG_IEC61850_L2_SMV +#endif +#define CONFIG_IEC61850_L2_GOOSE 0 +#define CONFIG_IEC61850_L2_SMV 0 +#define CONFIG_INCUDE_ETHERNET_WINDOWS 0 +#else +#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1 +#undef CONFIG_ETHERNET_INTERFACE_ID +#define CONFIG_ETHERNET_INTERFACE_ID "0" +#endif +#endif + /* overwrite default results for MMS identify service */ /* #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" */ /* #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" */ diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake index 28521f25..271bcb9c 100644 --- a/config/stack_config.h.cmake +++ b/config/stack_config.h.cmake @@ -68,10 +68,10 @@ /* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */ /* #define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. */ -/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */ +/* Set to 1 to include generic GOOSE support in the build. Otherwise set to 0 */ #cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT -/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */ +/* Set to 1 to include generic Sampled Values support in the build. Otherwise set to 0 */ #define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1 /* compile with support for R-GOOSE (mbedtls requried) */ @@ -80,6 +80,12 @@ /* compile with support for R-SMV (mbedtls required) */ #cmakedefine01 CONFIG_IEC61850_R_SMV +/* compile with support for L2 GOOSE */ +#cmakedefine01 CONFIG_IEC61850_L2_GOOSE + +/* compile with support for L2 SMV */ +#cmakedefine01 CONFIG_IEC61850_L2_SMV + /* compile SNTP client code */ #cmakedefine01 CONFIG_IEC61850_SNTP_CLIENT @@ -88,12 +94,16 @@ #ifdef _WIN32 -/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */ +/* L2 GOOSE/SMV will be disabled for Windows if ethernet support (winpcap) is not available */ #ifdef EXCLUDE_ETHERNET_WINDOWS -#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT -#undef CONFIG_INCLUDE_GOOSE_SUPPORT +#ifdef CONFIG_IEC61850_L2_GOOSE +#undef CONFIG_IEC61850_L2_GOOSE +#endif +#ifdef CONFIG_IEC61850_L2_SMV +#undef CONFIG_IEC61850_L2_SMV #endif -#define CONFIG_INCLUDE_GOOSE_SUPPORT 0 +#define CONFIG_IEC61850_L2_GOOSE 0 +#define CONFIG_IEC61850_L2_SMV 0 #define CONFIG_INCUDE_ETHERNET_WINDOWS 0 #else #define CONFIG_INCLUDE_ETHERNET_WINDOWS 1 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f551ec6e..8074ac6a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -55,10 +55,10 @@ else() set(BUILD_SV_GOOSE_EXAMPLES ON) endif() -if(WITH_MBEDTLS) +if(WITH_MBEDTLS OR WITH_MBEDTLS3) add_subdirectory(tls_client_example) add_subdirectory(tls_server_example) -endif(WITH_MBEDTLS) +endif(WITH_MBEDTLS OR WITH_MBEDTLS3) if(${BUILD_SV_GOOSE_EXAMPLES}) add_subdirectory(server_example_goose) diff --git a/examples/mms_utility/mms_utility.c b/examples/mms_utility/mms_utility.c index 24c909c9..3cedd8ab 100644 --- a/examples/mms_utility/mms_utility.c +++ b/examples/mms_utility/mms_utility.c @@ -129,7 +129,8 @@ int main(int argc, char** argv) int c; - while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1) { + while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1) + { switch (c) { case 'm': printRawMmsMessages = 1; @@ -212,7 +213,8 @@ int main(int argc, char** argv) if (printRawMmsMessages) MmsConnection_setRawMessageHandler(con, (MmsRawMessageHandler) printRawMmsMessage, NULL); - if (!MmsConnection_connect(con, &error, hostname, tcpPort)) { + if (!MmsConnection_connect(con, &error, hostname, tcpPort)) + { printf("MMS connect failed!\n"); if (error != MMS_ERROR_NONE) @@ -223,14 +225,16 @@ int main(int argc, char** argv) else printf("MMS connected.\n"); - if (identifyDevice) { + if (identifyDevice) + { MmsServerIdentity* identity = MmsConnection_identify(con, &error); if (error != MMS_ERROR_NONE) returnCode = error; - if (identity != NULL) { + if (identity != NULL) + { printf("\nServer identity:\n----------------\n"); printf(" vendor:\t%s\n", identity->vendorName); printf(" model:\t%s\n", identity->modelName); @@ -240,32 +244,37 @@ int main(int argc, char** argv) printf("Reading server identity failed!\n"); } - if (readDeviceList) { + if (readDeviceList) + { printf("\nDomains present on server:\n--------------------------\n"); LinkedList nameList = MmsConnection_getDomainNames(con, &error); if (error != MMS_ERROR_NONE) returnCode = error; - if (nameList) { + if (nameList) + { LinkedList_printStringList(nameList); LinkedList_destroy(nameList); } } - if (getDeviceDirectory) { + if (getDeviceDirectory) + { LinkedList variableList = MmsConnection_getDomainVariableNames(con, &error, domainName); if (error != MMS_ERROR_NONE) returnCode = error; - if (variableList) { + if (variableList) + { LinkedList element = LinkedList_getNext(variableList); printf("\nMMS domain variables for domain %s\n", domainName); - while (element != NULL) { + while (element != NULL) + { char* name = (char*) element->data; printf(" %s\n", name); @@ -284,8 +293,8 @@ int main(int argc, char** argv) if (error != MMS_ERROR_NONE) returnCode = error; - if (variableList) { - + if (variableList) + { LinkedList element = variableList; printf("\nMMS journals for domain %s\n", domainName); @@ -301,18 +310,17 @@ int main(int argc, char** argv) else { printf("\nFailed to read domain journals (error=%d)\n", error); } - } - if (readJournal) { - + if (readJournal) + { printf(" read journal %s...\n", journalName); char* logDomain = journalName; char* logName = strchr(journalName, '/'); - if (logName != NULL) { - + if (logName != NULL) + { logName[0] = 0; logName++; @@ -335,11 +343,12 @@ int main(int argc, char** argv) MmsValue_delete(startTime); MmsValue_delete(endTime); - if (journalEntries != NULL) { - + if (journalEntries != NULL) + { bool readNext; - do { + do + { readNext = false; LinkedList lastEntry = LinkedList_getLastElement(journalEntries); @@ -353,7 +362,8 @@ int main(int argc, char** argv) LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy); - if (moreFollows) { + if (moreFollows) + { char buf[100]; MmsValue_printToBuffer(nextEntryId, buf, 100); @@ -374,12 +384,14 @@ int main(int argc, char** argv) printf(" Invalid log name!\n"); } - if (readVariable) { - if (readWriteHasDomain) { - + if (readVariable) + { + if (readWriteHasDomain) + { MmsValue* result; - if (componentName == NULL) { + if (componentName == NULL) + { if (arrayIndex == -1) { result = MmsConnection_readVariable(con, &error, domainName, variableName); } @@ -396,15 +408,18 @@ int main(int argc, char** argv) } } - if (error != MMS_ERROR_NONE) { + if (error != MMS_ERROR_NONE) + { printf("Reading variable failed: (ERROR %i)\n", error); returnCode = error; } - else { + else + { printf("Read SUCCESS\n"); - if (result != NULL) { + if (result != NULL) + { char outbuf[1024]; MmsValue_printToBuffer(result, outbuf, 1024); @@ -416,22 +431,27 @@ int main(int argc, char** argv) else printf("result: NULL\n"); } - } else + { printf("Reading VMD scope variable not yet supported!\n"); + } } - if (readVariableList) { - if (readWriteHasDomain) { + if (readVariableList) + { + if (readWriteHasDomain) + { MmsValue* variables = MmsConnection_readNamedVariableListValues(con, &error, domainName, variableName, true); - if (error != MMS_ERROR_NONE) { + if (error != MMS_ERROR_NONE) + { printf("Reading variable failed: (ERROR %i)\n", error); returnCode = error; } - else { + else + { printf("Read SUCCESS\n"); } } @@ -439,24 +459,28 @@ int main(int argc, char** argv) printf("Reading VMD scope variable list not yet supported!\n"); } - if (readDataSetDirectory) { - if (readWriteHasDomain) { - + if (readDataSetDirectory) + { + if (readWriteHasDomain) + { bool deletable = false; LinkedList varListDir = MmsConnection_readNamedVariableListDirectory(con, &error, domainName, variableName, &deletable); - if (error != MMS_ERROR_NONE) { + if (error != MMS_ERROR_NONE) + { printf("Reading variable list directory failed: (ERROR %i)\n", error); returnCode = error; } - else { + else + { LinkedList varListElem = LinkedList_getNext(varListDir); int listIdx = 0; - while (varListElem) { + while (varListElem) + { MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(varListElem); if (varAccessSpec->arrayIndex) @@ -476,14 +500,15 @@ int main(int argc, char** argv) printf("Reading VMD scope variable list not yet supported!\n"); } - if (showFileList) { + if (showFileList) + { char lastName[300]; lastName[0] = 0; char* continueAfter = NULL; - while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName)) { - + while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName)) + { if (error != MMS_ERROR_NONE) returnCode = error; @@ -491,21 +516,25 @@ int main(int argc, char** argv) } } - if (getFileAttributes) { + if (getFileAttributes) + { MmsConnection_getFileDirectory(con, &error, filename, NULL, mmsGetFileAttributeHandler, NULL); if (error != MMS_ERROR_NONE) returnCode = error; } - if (deleteFile) { + if (deleteFile) + { MmsConnection_fileDelete(con, &error, filename); - if (error != MMS_ERROR_NONE) { + if (error != MMS_ERROR_NONE) + { printf("Delete file failed: (ERROR %i)\n", error); returnCode = error; } - else { + else + { printf("File deleted\n"); } } @@ -521,4 +550,3 @@ exit: return returnCode; } - diff --git a/examples/rsv_publisher_example/r_sv_publisher_example.c b/examples/rsv_publisher_example/r_sv_publisher_example.c index e4dad561..30c74dd7 100644 --- a/examples/rsv_publisher_example/r_sv_publisher_example.c +++ b/examples/rsv_publisher_example/r_sv_publisher_example.c @@ -21,8 +21,8 @@ main(int argc, char** argv) { RSession rSession = RSession_create(); - if (rSession) { - + if (rSession) + { /* Call RSession_setLocalAddress to use a particular interface to send the R-GOOSE messages */ //RSession_setLocalAddress(rSession, "169.254.110.126", -1); RSession_setRemoteAddress(rSession, "230.0.10.10", 102); @@ -32,8 +32,8 @@ main(int argc, char** argv) uint32_t activeKeyId = 1; uint64_t nextKeyChangeTime = Hal_getTimeInMs() + 5000; - if (svPublisher) { - + if (svPublisher) + { signal(SIGINT, sigint_handler); char* key1 = "0123456789ABCDEF"; @@ -63,7 +63,8 @@ main(int argc, char** argv) RSession_start(rSession); - while (running) { + while (running) + { Timestamp ts; Timestamp_clearFlags(&ts); Timestamp_setTimeInMilliseconds(&ts, Hal_getTimeInMs()); @@ -84,7 +85,8 @@ main(int argc, char** argv) SVPublisher_publish(svPublisher); - if (Hal_getTimeInMs() >= nextKeyChangeTime) { + if (Hal_getTimeInMs() >= nextKeyChangeTime) + { /* change key */ if (activeKeyId == 1) @@ -101,14 +103,15 @@ main(int argc, char** argv) SVPublisher_destroy(svPublisher); } - else { + else + { printf("Failed to create SV publisher\n"); } RSession_destroy(rSession); } - else { + else + { printf("Failed to create remote session instance\n"); } - } diff --git a/examples/rsv_subscriber_example/r_sv_subscriber_example.c b/examples/rsv_subscriber_example/r_sv_subscriber_example.c index 7fdc591c..920a301d 100644 --- a/examples/rsv_subscriber_example/r_sv_subscriber_example.c +++ b/examples/rsv_subscriber_example/r_sv_subscriber_example.c @@ -50,8 +50,8 @@ main(int argc, char** argv) { RSession rSession = RSession_create(); - if (rSession) { - + if (rSession) + { RSession_setLocalAddress(rSession, "0.0.0.0", 102); RSession_addMulticastGroup(rSession, "230.0.10.10"); @@ -64,7 +64,8 @@ main(int argc, char** argv) SVReceiver receiver = SVReceiver_createRemote(rSession); - if (receiver) { + if (receiver) + { /* Create a subscriber listening to SV messages with APPID 4000h */ SVSubscriber subscriber = SVSubscriber_create(NULL, 0x4000); @@ -77,7 +78,8 @@ main(int argc, char** argv) /* Start listening to SV messages - starts a new receiver background thread */ SVReceiver_start(receiver); - if (SVReceiver_isRunning(receiver)) { + if (SVReceiver_isRunning(receiver)) + { signal(SIGINT, sigint_handler); while (running) @@ -86,21 +88,23 @@ main(int argc, char** argv) /* Stop listening to SV messages */ SVReceiver_stop(receiver); } - else { + else + { printf("Failed to start SV subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n"); } /* Cleanup and free resources */ SVReceiver_destroy(receiver); } - else { + else + { printf("Failed to create SV receiver\n"); } RSession_destroy(rSession); } - else { + else + { printf("Failed to create remote session protocol\n"); } - } diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt index 9b421f6b..7b9f2db9 100644 --- a/hal/CMakeLists.txt +++ b/hal/CMakeLists.txt @@ -10,7 +10,7 @@ endif() project(hal) set(LIBHAL_VERSION_MAJOR "2") -set(LIBHAL_VERSION_MINOR "1") +set(LIBHAL_VERSION_MINOR "2") set(LIBHAL_VERSION_PATCH "0") # feature checks @@ -28,7 +28,7 @@ message("Found winpcap -> compile ethernet HAL layer (required for GOOSE/SV supp set(WITH_WPCAP 1) include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Include") else() -message("winpcap not found -> skip ethernet HAL layer (no GOOSE/SV support)") +message("winpcap not found -> skip ethernet HAL layer (no L2 GOOSE/SV support)") endif() endif(WIN32) @@ -116,10 +116,15 @@ ENDIF(WIN32) #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" ) if(WITH_MBEDTLS) -message("Found mbedtls -> can compile HAL with TLS support") +message("Found mbedtls 2.28 -> can compile HAL with TLS 1.2 support") set(WITH_MBEDTLS 1) endif(WITH_MBEDTLS) +if (WITH_MBEDTLS3) +message("Found mbedtls 3.6 -> can compile HAL with TLS 1.3 support") +set(WITH_MBEDTLS3 1) +endif(WITH_MBEDTLS3) + if(WITH_MBEDTLS) include_directories( ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls @@ -147,6 +152,32 @@ list (APPEND libhal_SRCS ${tls_SRCS}) endif(WITH_MBEDTLS) +if(WITH_MBEDTLS3) +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3 + ${MBEDTLS_INCLUDE_DIR} +) + +if(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) +link_directories(${CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH}) +else() +file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/library/*.c) +endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) + +add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h") + +set (libhal_SRCS ${libhal_SRCS} + ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3/tls_mbedtls.c +) + +IF(MSVC) +set_source_files_properties(${libhal_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF() + +list (APPEND libhal_SRCS ${tls_SRCS}) +endif(WITH_MBEDTLS3) + add_library (hal STATIC ${libhal_SRCS}) add_library (hal-shared STATIC ${libhal_SRCS}) @@ -178,6 +209,11 @@ IF(MINGW) target_link_libraries(hal ws2_32 iphlpapi) ENDIF(MINGW) +IF (MSVC) + target_link_libraries(hal bcrypt) + target_link_libraries(hal-shared bcrypt) +ENDIF() + iF(WITH_WPCAP) target_link_libraries(hal ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib diff --git a/hal/serial/linux/serial_port_linux.c b/hal/serial/linux/serial_port_linux.c index f976e724..3bf4c974 100644 --- a/hal/serial/linux/serial_port_linux.c +++ b/hal/serial/linux/serial_port_linux.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "hal_serial.h" #include "hal_time.h" @@ -29,11 +30,10 @@ struct sSerialPort { char parity; uint8_t stopBits; uint64_t lastSentTime; - struct timeval timeout; + int timeout; SerialPortError lastError; }; - SerialPort SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, char parity, uint8_t stopBits) { @@ -46,8 +46,7 @@ SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, cha self->stopBits = stopBits; self->parity = parity; self->lastSentTime = 0; - self->timeout.tv_sec = 0; - self->timeout.tv_usec = 100000; /* 100 ms */ + self->timeout = 100; /* 100 ms */ strncpy(self->interfaceName, interfaceName, 99); self->lastError = SERIAL_PORT_ERROR_NONE; } @@ -212,8 +211,7 @@ SerialPort_discardInBuffer(SerialPort self) void SerialPort_setTimeout(SerialPort self, int timeout) { - self->timeout.tv_sec = timeout / 1000; - self->timeout.tv_usec = (timeout % 1000) * 1000; + self->timeout = timeout; } SerialPortError @@ -226,14 +224,14 @@ int SerialPort_readByte(SerialPort self) { uint8_t buf[1]; - fd_set set; + struct pollfd fds[1]; self->lastError = SERIAL_PORT_ERROR_NONE; - FD_ZERO(&set); - FD_SET(self->fd, &set); + fds[0].fd = self->fd; + fds[0].events = POLLIN; - int ret = select(self->fd + 1, &set, NULL, NULL, &(self->timeout)); + int ret = poll(fds, 1, self->timeout); if (ret == -1) { self->lastError = SERIAL_PORT_ERROR_UNKNOWN; diff --git a/hal/socket/linux/socket_linux.c b/hal/socket/linux/socket_linux.c index 44b4cbef..dc168c94 100644 --- a/hal/socket/linux/socket_linux.c +++ b/hal/socket/linux/socket_linux.c @@ -479,10 +479,6 @@ Socket_connectAsync(Socket self, const char* address, int port) if (!prepareAddress(address, port, &serverAddress)) return false; - fd_set fdSet; - FD_ZERO(&fdSet); - FD_SET(self->fd, &fdSet); - activateTcpNoDelay(self); fcntl(self->fd, F_SETFL, O_NONBLOCK); @@ -506,17 +502,14 @@ Socket_connectAsync(Socket self, const char* address, int port) SocketState Socket_checkAsyncConnectState(Socket self) { - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; + struct pollfd fds[1]; - fd_set fdSet; - FD_ZERO(&fdSet); - FD_SET(self->fd, &fdSet); + fds[0].fd = self->fd; + fds[0].events = POLLOUT; - int selectVal = select(self->fd + 1, NULL, &fdSet , NULL, &timeout); + int result = poll(fds, 1, 0); - if (selectVal == 1) { + if (result == 1) { /* Check if connection is established */ @@ -531,7 +524,7 @@ Socket_checkAsyncConnectState(Socket self) return SOCKET_STATE_FAILED; } - else if (selectVal == 0) { + else if (result == 0) { return SOCKET_STATE_CONNECTING; } else { @@ -545,15 +538,14 @@ Socket_connect(Socket self, const char* address, int port) if (Socket_connectAsync(self, address, port) == false) return false; - struct timeval timeout; - timeout.tv_sec = self->connectTimeout / 1000; - timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + struct pollfd fds[1]; + + fds[0].fd = self->fd; + fds[0].events = POLLOUT; - fd_set fdSet; - FD_ZERO(&fdSet); - FD_SET(self->fd, &fdSet); + int result = poll(fds, 1, self->connectTimeout); - if (select(self->fd + 1, NULL, &fdSet , NULL, &timeout) == 1) { + if (result == 1) { /* Check if connection is established */ diff --git a/hal/tls/mbedtls/tls_mbedtls.c b/hal/tls/mbedtls/tls_mbedtls.c index 7470e3d2..89b4dbd9 100644 --- a/hal/tls/mbedtls/tls_mbedtls.c +++ b/hal/tls/mbedtls/tls_mbedtls.c @@ -72,7 +72,7 @@ struct sTLSConfiguration { /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_0) */ TLSConfigVersion minVersion; - /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */ + /* TLS maximum version allowed (default: TLS_VERSION_TLS_1_2) */ TLSConfigVersion maxVersion; TLSConfiguration_EventHandler eventHandler; @@ -308,7 +308,7 @@ TLSConfiguration_create() { TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration)); - if (self != NULL) + if (self) { mbedtls_ssl_config_init( &(self->conf) ); mbedtls_x509_crt_init( &(self->ownCertificate) ); diff --git a/hal/tls/mbedtls3/mbedtls_config.h b/hal/tls/mbedtls3/mbedtls_config.h new file mode 100644 index 00000000..bfef80d2 --- /dev/null +++ b/hal/tls/mbedtls3/mbedtls_config.h @@ -0,0 +1,73 @@ +// https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#introduce-a-level-of-indirection-and-versioning-in-the-config-files +// #ifndef MBEDTLS_CONFIG_H +// #define MBEDTLS_CONFIG_H + +/* System support */ +#define MBEDTLS_HAVE_ASM +#define MBEDTLS_HAVE_TIME +#define MBEDTLS_HAVE_TIME_DATE +#define MBEDTLS_NO_UDBL_DIVISION +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_DEBUG_C + +/* mbed TLS feature support */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_PROTO_TLS1_3 +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-support-for-tls-10-11-and-dtls-10 +// #define MBEDTLS_SSL_PROTO_TLS1_1 +// #define MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_RENEGOTIATION + +#error "MBEDTLS" + +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES + +/* mbed TLS modules */ +#define MBEDTLS_GCM_C +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +/* #define MBEDTLS_DES_C */ +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_NET_C +#define MBEDTLS_OID_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CRL_PARSE_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_SSL_CACHE_C + +/* For test certificates */ +#define MBEDTLS_BASE64_C +#define MBEDTLS_CERTS_C +#define MBEDTLS_PEM_PARSE_C + +#define MBEDTLS_PKCS12_C +#define MBEDTLS_PKCS5_C + +/* For testing with compat.sh */ +#define MBEDTLS_FS_IO + +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-mbedtls_x509_check__key_usage-options-from-mbedtls_configh +// #define MBEDTLS_X509_CHECK_KEY_USAGE +// #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#introduce-a-level-of-indirection-and-versioning-in-the-config-files +// #include "mbedtls/check_config.h" + +// #endif /* MBEDTLS_CONFIG_H */ diff --git a/hal/tls/mbedtls3/tls_mbedtls.c b/hal/tls/mbedtls3/tls_mbedtls.c new file mode 100644 index 00000000..4f49ddc9 --- /dev/null +++ b/hal/tls/mbedtls3/tls_mbedtls.c @@ -0,0 +1,1273 @@ +/* + * tls_mbedtls.c + * + * TLS API for TCP/IP protocol stacks + * + * Copyright 2017-2024 Michael Zillgith + * + * Implementation of the TLS abstraction layer for mbedtls + * + */ + +#include + +#include "tls_socket.h" +#include "hal_thread.h" +#include "lib_memory.h" +#include "hal_time.h" +#include "linked_list.h" + +#include "mbedtls/platform.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-the-certs-module-from-the-library +// #include "mbedtls/certs.h" (MIGRATE 2.28->3.x.x) +#include "mbedtls/x509.h" +#include "mbedtls/ssl.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" +#include "mbedtls/ssl_cache.h" + +#define SEC_EVENT_ALARM 2 +#define SEC_EVENT_WARNING 1 +#define SEC_EVENT_INFO 0 + +#ifndef CONFIG_DEBUG_TLS +#define CONFIG_DEBUG_TLS 1 +#endif + +#if (CONFIG_DEBUG_TLS == 1) +#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__) +#else +#define DEBUG_PRINT(fmt, ...) do {} while(0) +#endif + +static int psaInitCounter = 0; + +struct sTLSConfiguration { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_x509_crt ownCertificate; + mbedtls_pk_context ownKey; + + mbedtls_x509_crt cacerts; + + mbedtls_x509_crl crl; + + mbedtls_ssl_config conf; + LinkedList /* */ allowedCertificates; + + /* session cache for server */ + mbedtls_ssl_cache_context cache; + + /* client side cached session */ + mbedtls_ssl_session* savedSession; + uint64_t savedSessionTime; + + bool chainValidation; + bool allowOnlyKnownCertificates; + + /* TLS session renegotiation interval in milliseconds */ + int renegotiationTimeInMs; + + // MIGRATE 2.28->3.x.x: Changed min version to 1.2 to reflect the removal of 1.1 and 1.0 + /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */ + TLSConfigVersion minVersion; + + // MIGRATE 2.28->3.x.x: Kept the max version but changed documentation + /* TLS maximum version allowed (default: TLS_VERSION_NOT_SELECTED) */ + TLSConfigVersion maxVersion; + + TLSConfiguration_EventHandler eventHandler; + void* eventHandlerParameter; + + /* time of the last CRL update */ + uint64_t crlUpdated; + + bool setupComplete; + + bool useSessionResumption; + int sessionResumptionInterval; /* session resumption interval in seconds */ + + int* ciphersuites; + int maxCiphersuites; +}; + +struct sTLSSocket { + mbedtls_ssl_context ssl; + Socket socket; + mbedtls_ssl_config conf; + TLSConfiguration tlsConfig; + bool storePeerCert; + uint8_t* peerCert; + int peerCertLength; + + /* time of last session renegotiation (used to calculate next renegotiation time) */ + uint64_t lastRenegotiationTime; + + /* time of the last CRL update */ + uint64_t crlUpdated; +}; + +static void +raiseSecurityEvent(TLSConfiguration config, TLSEventLevel eventCategory, int eventCode, const char* message, TLSSocket socket) +{ + if (config->eventHandler) { + config->eventHandler(config->eventHandlerParameter, eventCategory, eventCode, message, (TLSConnection)socket); + } +} + +static bool +compareCertificates(mbedtls_x509_crt *crt1, mbedtls_x509_crt *crt2) +{ + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private + if (crt1 != NULL && crt2 != NULL && + crt1->raw.len == crt2->raw.len && + memcmp(crt1->raw.p, crt2->raw.p, crt1->raw.len) == 0) { + return true; + } + + return false; +} + +static int +verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags) +{ + TLSSocket self = (TLSSocket) parameter; + + DEBUG_PRINT("TLS", "Verify cert: depth %i\n", certificate_depth); + + DEBUG_PRINT("TLS", " flags: %08x\n", *flags); + + char buffer[1024]; + + mbedtls_x509_crt_info(buffer, 1023, " ", crt); + + DEBUG_PRINT("TLS", "%s\n", buffer); + + if (self->tlsConfig->chainValidation == false) + { + if (certificate_depth != 0) + *flags = 0; + } + + if (certificate_depth == 0) + { + if (self->tlsConfig->allowOnlyKnownCertificates) + { + DEBUG_PRINT("TLS", "Check against list of allowed certs\n"); + + bool certMatches = false; + + LinkedList certList = LinkedList_getNext(self->tlsConfig->allowedCertificates); + + while (certList) + { + mbedtls_x509_crt* allowedCert = (mbedtls_x509_crt*) LinkedList_getData(certList); + + DEBUG_PRINT("TLS", "Compare With:\n"); + mbedtls_x509_crt_info(buffer, 1023, " ", allowedCert); + DEBUG_PRINT("TLS", "%s\n", buffer); + + if (compareCertificates(allowedCert, crt)) + { + certMatches = true; + break; + } + + certList = LinkedList_getNext(certList); + } + + if (certMatches) + *flags = 0; + else + { + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: certificate validation: trusted individual certificate not available", self); + + *flags |= MBEDTLS_X509_BADCERT_OTHER; + return 1; + } + } + + if (self->storePeerCert) + { + if (*flags == 0) + { + self->peerCertLength = 0; + self->peerCert = (uint8_t*) GLOBAL_MALLOC(crt->raw.len); + + if (self->peerCert) + { + self->peerCertLength = (int)crt->raw.len; + memcpy(self->peerCert, crt->raw.p, self->peerCertLength); + } + } + } + } + + return 0; +} + +/* + * Finish configuration when used the first time. + */ +static bool +TLSConfiguration_setupComplete(TLSConfiguration self) +{ + if (self->setupComplete == false) + { + mbedtls_ssl_conf_ca_chain( &(self->conf), &(self->cacerts), &(self->crl) ); + + if (self->ownCertificate.version > 0) + { + int ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(self->ownCertificate), &(self->ownKey)); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned -0x%x\n", -ret); + return false; + } + } + + if (self->useSessionResumption) + { + if (mbedtls_ssl_conf_get_endpoint(&(self->conf)) == MBEDTLS_SSL_IS_CLIENT) { + + } + else + { + mbedtls_ssl_cache_init( &(self->cache) ); + + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private + mbedtls_ssl_cache_set_timeout(&(self->cache), self->sessionResumptionInterval); + + mbedtls_ssl_conf_session_cache( &(self->conf), &(self->cache), + mbedtls_ssl_cache_get, + mbedtls_ssl_cache_set ); + } + } + + mbedtls_ssl_conf_ciphersuites(&(self->conf), self->ciphersuites); + + self->setupComplete = true; + } + + return true; +} + +void +TLSConfiguration_addCipherSuite(TLSConfiguration self, int ciphersuite) +{ + /* search last index */ + int nextIndex = 0; + int i; + + for (i = 0; i < self->maxCiphersuites; i++) + { + if (self->ciphersuites[i] == 0) + { + nextIndex = i; + break; + } + } + + if (nextIndex == self->maxCiphersuites) + { + /* reallocate space for ciphersuites list */ + int newMaxCiphersuites = self->maxCiphersuites + 10; + + int* newCiphersuites = (int*)GLOBAL_CALLOC(newMaxCiphersuites, sizeof(int)); + + if (newCiphersuites) + { + for (i = 0; i < self->maxCiphersuites; i++) + { + newCiphersuites[i] = self->ciphersuites[i]; + } + + GLOBAL_FREEMEM(self->ciphersuites); + self->ciphersuites = newCiphersuites; + self->maxCiphersuites = newMaxCiphersuites; + + TLSConfiguration_addCipherSuite(self, ciphersuite); + } + } + else + { + self->ciphersuites[nextIndex] = ciphersuite; + self->ciphersuites[nextIndex + 1] = 0; + } +} + +void +TLSConfiguration_clearCipherSuiteList(TLSConfiguration self) +{ + self->ciphersuites[0] = 0; +} + +TLSConfiguration +TLSConfiguration_create() +{ + TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration)); + + if (self) + { + /* call to psa_crypto_init required -> see https://github.com/Mbed-TLS/mbedtls/issues/9223 */ + psa_status_t psaStatus = psa_crypto_init(); + + psaInitCounter++; + + mbedtls_ssl_config_init( &(self->conf) ); + mbedtls_x509_crt_init( &(self->ownCertificate) ); + mbedtls_x509_crt_init( &(self->cacerts) ); + mbedtls_x509_crl_init( &(self->crl) ); + mbedtls_pk_init( &(self->ownKey) ); + mbedtls_entropy_init( &(self->entropy) ); + mbedtls_ctr_drbg_init( &(self->ctr_drbg) ); + + /* WARINING is fixed to server! */ + mbedtls_ssl_config_defaults( &(self->conf), + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT ); + + mbedtls_ctr_drbg_seed( &(self->ctr_drbg), mbedtls_entropy_func, &(self->entropy), NULL, 0); + mbedtls_ssl_conf_rng( &(self->conf), mbedtls_ctr_drbg_random, &(self->ctr_drbg) ); + + mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED); + + mbedtls_ssl_conf_renegotiation(&(self->conf), MBEDTLS_SSL_RENEGOTIATION_ENABLED); + + self->minVersion = TLS_VERSION_TLS_1_2; + self->maxVersion = TLS_VERSION_NOT_SELECTED; + + self->renegotiationTimeInMs = -1; /* no automatic renegotiation */ + + self->allowedCertificates = LinkedList_create(); + + /* default behavior is to allow all certificates that are signed by the CA */ + self->chainValidation = true; + self->allowOnlyKnownCertificates = false; + self->setupComplete = false; + + self->eventHandler = NULL; + self->eventHandlerParameter = NULL; + + self->useSessionResumption = true; + self->sessionResumptionInterval = 21600; /* default value: 6h */ + self->savedSession = NULL; + self->savedSessionTime = 0; + + self->ciphersuites = (int*)GLOBAL_CALLOC(20, sizeof(int)); + + if (self->ciphersuites) + { + self->maxCiphersuites = 20; + + /* mandatory cipher suites by IEC 62351-4:2018 */ + self->ciphersuites[0] = MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256; + /* self->ciphersuites[1] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_GCM_SHA256; */ /* weak - not supported? */ + self->ciphersuites[1] = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; + self->ciphersuites[2] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + + /* recommended cipher suites by IEC 62351-4:2018 */ + + /* self->ciphersuites[1] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_CBC_SHA256; */ /* weak - not supported?*/ + /* self->ciphersuites[1] = MBEDTLS_TLS_DH_RSA_WITH_AES_256_GCM_SHA384; */ /* not supported?*/ + self->ciphersuites[3] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + self->ciphersuites[4] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; + self->ciphersuites[5] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + + /* additional ciphersuites */ + self->ciphersuites[6] = MBEDTLS_TLS_RSA_WITH_NULL_SHA256; + self->ciphersuites[7] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + } + } + + return self; +} + +void +TLSConfiguration_setClientMode(TLSConfiguration self) +{ + mbedtls_ssl_conf_endpoint(&(self->conf), MBEDTLS_SSL_IS_CLIENT); +} + +void +TLSConfiguration_enableSessionResumption(TLSConfiguration self, bool enable) +{ + self->useSessionResumption = enable; +} + +void +TLSConfiguration_setSessionResumptionInterval(TLSConfiguration self, int intervalInSeconds) +{ + self->sessionResumptionInterval = intervalInSeconds; +} + +void +TLSConfiguration_setEventHandler(TLSConfiguration self, TLSConfiguration_EventHandler handler, void* parameter) +{ + self->eventHandler = handler; + self->eventHandlerParameter = parameter; +} + +void +TLSConfiguration_setMinTlsVersion(TLSConfiguration self, TLSConfigVersion version) +{ + self->minVersion = version; +} + +void +TLSConfiguration_setMaxTlsVersion(TLSConfiguration self, TLSConfigVersion version) +{ + self->maxVersion = version; +} + +void +TLSConfiguration_setChainValidation(TLSConfiguration self, bool value) +{ + self->chainValidation = value; +} + +void +TLSConfiguration_setAllowOnlyKnownCertificates(TLSConfiguration self, bool value) +{ + self->allowOnlyKnownCertificates = value; +} + +bool +TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, int certLen) +{ + int ret = mbedtls_x509_crt_parse(&(self->ownCertificate), certificate, certLen); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crt_parse_file(&(self->ownCertificate), filename); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse_file returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword) +{ + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#some-functions-gained-an-rng-parameter + // MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create + int ret = mbedtls_pk_parse_key(&(self->ownKey), key, keyLen, (const uint8_t*) keyPassword, (keyPassword == NULL) ? 0 : strlen(keyPassword), mbedtls_ctr_drbg_random, &(self->ctr_drbg)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_pk_parse_key returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword) +{ + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#some-functions-gained-an-rng-parameter + // MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create + int ret = mbedtls_pk_parse_keyfile(&(self->ownKey), filename, keyPassword, mbedtls_ctr_drbg_random, &(self->ctr_drbg)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_pk_parse_keyfile returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certificate, int certLen) +{ + mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt)); + + int ret = mbedtls_x509_crt_parse(cert, certificate, certLen); + + if (ret == 0) + { + LinkedList_add(self->allowedCertificates, cert); + return true; + } + else + { + GLOBAL_FREEMEM(cert); + return false; + } +} + +bool +TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename) +{ + mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt)); + + int ret = mbedtls_x509_crt_parse_file(cert, filename); + + if (ret == 0) + { + LinkedList_add(self->allowedCertificates, cert); + return true; + } + else + { + GLOBAL_FREEMEM(cert); + return false; + } +} + +bool +TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, int certLen) +{ + int ret = mbedtls_x509_crt_parse(&(self->cacerts), certificate, certLen); + + if (ret != 0) + { + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret); + return false; + } + + return (ret == 0); +} + +bool +TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crt_parse_file(&(self->cacerts), filename); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret); + + return (ret == 0); +} + +static void +udpatedCRL(TLSConfiguration self) +{ + self->crlUpdated = Hal_getTimeInMs(); + + /* We need to clean-up resumption cache (if enabled) to make sure we renegotiate as CRL may have changed data */ + if (self->useSessionResumption == false) + return; + + if (mbedtls_ssl_conf_get_endpoint(&(self->conf)) == MBEDTLS_SSL_IS_SERVER) + { + mbedtls_ssl_cache_free(&(self->cache)); + } +} + +bool +TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen) +{ + int ret = mbedtls_x509_crl_parse(&(self->crl), crl, crlLen); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse returned -0x%x\n", -ret); + } + else { + udpatedCRL(self); + } + + return (ret == 0); +} + +bool +TLSConfiguration_addCRLFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crl_parse_file(&(self->crl), filename); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse_file returned %d\n", ret); + } + else { + udpatedCRL(self); + } + + return (ret == 0); +} + +void +TLSConfiguration_resetCRL(TLSConfiguration self) +{ + mbedtls_x509_crl_free(&(self->crl)); + mbedtls_x509_crl_init(&(self->crl)); + self->crlUpdated = Hal_getTimeInMs(); +} + +void +TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs) +{ + self->renegotiationTimeInMs = timeInMs; +} + +void +TLSConfiguration_destroy(TLSConfiguration self) +{ + if (self->useSessionResumption) + { + if (mbedtls_ssl_conf_get_endpoint(&(self->conf)) == MBEDTLS_SSL_IS_CLIENT) + { + if (self->savedSession) + { + mbedtls_ssl_session_free(self->savedSession); + GLOBAL_FREEMEM(self->savedSession); + } + } + else + { + mbedtls_ssl_cache_free(&(self->cache)); + } + } + + mbedtls_x509_crt_free(&(self->ownCertificate)); + mbedtls_x509_crt_free(&(self->cacerts)); + mbedtls_x509_crl_free(&(self->crl)); + mbedtls_pk_free(&(self->ownKey)); + mbedtls_ssl_config_free(&(self->conf)); + mbedtls_ctr_drbg_free(&(self->ctr_drbg)); + mbedtls_entropy_free(&(self->entropy)); + + LinkedList certElem = LinkedList_getNext(self->allowedCertificates); + + while (certElem) + { + mbedtls_x509_crt* cert = (mbedtls_x509_crt*) LinkedList_getData(certElem); + + mbedtls_x509_crt_free(cert); + + certElem = LinkedList_getNext(certElem); + } + + LinkedList_destroy(self->allowedCertificates); + + psaInitCounter--; + + if (psaInitCounter < 1) + mbedtls_psa_crypto_free(); + + GLOBAL_FREEMEM(self); +} + +static void +createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket socket) +{ + if (config->eventHandler == NULL) + return; + + switch (ret) { + case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG: + raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: Algorithm not supported", socket); + break; + + // MIGRATE 2.28->3.x.x:https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#changes-in-the-ssl-error-code-space + // case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: no matching TLS ciphers", socket); + // break; + + // case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Algorithm not supported", socket); + // break; + + + case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE: + raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Handshake failure", socket); + break; + + // case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Alarm: Unsecure communication", socket); + // break; + + case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_UNAVAILABLE, "Alarm: certificate unavailable", socket); + break; + + // case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Alarm: Bad certificate", socket); + // break; + + case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_SIZE_EXCEEDED, "Alarm: TLS certificate size exceeded", socket); + break; + + // MIGRATE 2.28->3.x.x: the removal of this is undocumented TODO: Verify migration path + // case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm: certificate validation: certificate signature could not be validated", socket); + // break; + + // MIGRATE 2.28->3.x.x: the removal of this is undocumented. The docs say migrating users are affected but don't provide a migration path TODO: Verify migration path (MIGRATE 2.28->3.x.x) + // case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED: + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Alarm: Certificate required", socket); + // break; + + case MBEDTLS_ERR_SSL_DECODE_ERROR: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Decode error", socket); + break; + + case MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Illegal parameter", socket); + break; + + case MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Bad protocol version", socket); + break; + + case MBEDTLS_ERR_SSL_BAD_CERTIFICATE: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Bad certificate", socket); + break; + + case MBEDTLS_ERR_SSL_UNRECOGNIZED_NAME: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unrecognized name", socket); + break; + + case MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unsupported extension", socket); + break; + + case MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: No application protocol", socket); + break; + + case MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unexpected message", socket); + break; + + case MBEDTLS_ERR_SSL_INTERNAL_ERROR: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Internal error", socket); + break; + + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + { + if (flags & MBEDTLS_X509_BADCERT_EXPIRED) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_EXPIRED, "Alarm: expired certificate", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_REVOKED) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED, "Alarm: revoked certificate", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED, "Alarm: Certificate validation: CA certificate not available", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_OTHER) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: Certificate not configured", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_BAD_KEY) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: Insufficient key length", socket); + } + + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm: Certificate verification failed", socket); + } + break; + + default: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: handshake failed for unknown reason", socket); + break; + } +} + +static int +readFunction(void* ctx, unsigned char* buf, size_t len) +{ + int ret = Socket_read((Socket) ctx, buf, (int)len); + + if ((ret == 0) && (len > 0)) + { + return MBEDTLS_ERR_SSL_WANT_READ; + } + + return ret; +} + +static int +writeFunction(void* ctx, unsigned char* buf, size_t len) +{ + int ret = Socket_write((Socket)ctx, buf, (int)len); + + if ((ret == 0) && (len > 0)) + { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + + return ret; +} + +static TLSConfigVersion +getTLSVersion(int majorVersion, int minorVersion) +{ + if (majorVersion != 3) { + return TLS_VERSION_NOT_SELECTED; + } + else + { + switch (minorVersion) { + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case 0: + return TLS_VERSION_SSL_3_0; + case 1: + return TLS_VERSION_TLS_1_0; + case 2: + return TLS_VERSION_TLS_1_1; + /* Up until here (MIGRATE 2.28->3.x.x) */ + case 3: + return TLS_VERSION_TLS_1_2; + case 4: + return TLS_VERSION_TLS_1_3; + default: + return TLS_VERSION_NOT_SELECTED; + } + } +} + +static int +getMajorVersion(TLSConfigVersion version) +{ + switch(version) { + case TLS_VERSION_NOT_SELECTED: + return 0; + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_SSL_3_0: + case TLS_VERSION_TLS_1_0: + case TLS_VERSION_TLS_1_1: + /* Up until here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_TLS_1_2: + case TLS_VERSION_TLS_1_3: + return 3; + default: + return 0; + } +} + +static int +getMinorVersion(TLSConfigVersion version) +{ + switch(version) { + case TLS_VERSION_NOT_SELECTED: + return 0; + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_SSL_3_0: + return 0; + case TLS_VERSION_TLS_1_0: + return 1; + case TLS_VERSION_TLS_1_1: + return 2; + /* Up until here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_TLS_1_2: + return 3; + case TLS_VERSION_TLS_1_3: + return 4; + default: + return 0; + } +} + +TLSSocket +TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClientCert) +{ + TLSSocket self = (TLSSocket) GLOBAL_CALLOC(1, sizeof(struct sTLSSocket)); + + if (self) + { + self->socket = socket; + self->tlsConfig = configuration; + self->storePeerCert = storeClientCert; + self->peerCert = NULL; + self->peerCertLength = 0; + + TLSConfiguration_setupComplete(configuration); + + memcpy(&(self->conf), &(configuration->conf), sizeof(mbedtls_ssl_config)); + + mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*) self); + + int ret; + + mbedtls_ssl_conf_ca_chain( &(self->conf), &(configuration->cacerts), &(configuration->crl) ); + + self->crlUpdated = configuration->crlUpdated; + + if (configuration->minVersion != TLS_VERSION_NOT_SELECTED) + { + /* set minimum TLS version */ + + int majorVer = getMajorVersion(configuration->minVersion); + int minorVer = getMinorVersion(configuration->minVersion); + + mbedtls_ssl_conf_min_version( &(self->conf), majorVer, minorVer); + } + + if (configuration->maxVersion != TLS_VERSION_NOT_SELECTED) + { + /* set maximum TLS version */ + + int majorVer = getMajorVersion(configuration->maxVersion); + int minorVer = getMinorVersion(configuration->maxVersion); + + mbedtls_ssl_conf_max_version( &(self->conf), majorVer, minorVer); + } + + if (configuration->ownCertificate.version > 0) + { + ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(configuration->ownCertificate), &(configuration->ownKey)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); + } + + ret = mbedtls_ssl_setup( &(self->ssl), &(self->conf) ); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret); + + mbedtls_ssl_set_bio(&(self->ssl), socket, (mbedtls_ssl_send_t*) writeFunction, + (mbedtls_ssl_recv_t*) readFunction, NULL); + + if (configuration->useSessionResumption) + { + if (mbedtls_ssl_conf_get_endpoint(&(configuration->conf)) == MBEDTLS_SSL_IS_CLIENT) + { + if (configuration->savedSession && configuration->savedSessionTime > 0) + { + if (Hal_getTimeInMs() < (configuration->savedSessionTime + configuration->sessionResumptionInterval * 1000)) + { + ret = mbedtls_ssl_set_session(&(self->ssl), configuration->savedSession); + + if (ret != 0) + { + DEBUG_PRINT("TLS", "mbedtls_ssl_set_session returned %d\n", ret); + configuration->savedSessionTime = 0; + } + else + { + DEBUG_PRINT("TLS", "resume TLS session\n"); + } + } + else + { + configuration->savedSessionTime = 0; + DEBUG_PRINT("TLS", "cached session expired\n"); + } + } + } + } + + while( (ret = mbedtls_ssl_handshake(&(self->ssl)) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + DEBUG_PRINT("TLS", "handshake failed - mbedtls_ssl_handshake returned -0x%x\n", -ret ); + + uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); + + createSecurityEvents(configuration, ret, flags, self); + + mbedtls_ssl_free(&(self->ssl)); + + if (self->peerCert) { + GLOBAL_FREEMEM(self->peerCert); + } + + GLOBAL_FREEMEM(self); + + return NULL; + } + } + + if (configuration->useSessionResumption) + { + if (mbedtls_ssl_conf_get_endpoint(&(configuration->conf)) == MBEDTLS_SSL_IS_CLIENT) + { + if (configuration->savedSession == NULL) + { + configuration->savedSession = (mbedtls_ssl_session*)GLOBAL_CALLOC(1, sizeof(mbedtls_ssl_session)); + } + + if (configuration->savedSession) + { + if (configuration->savedSessionTime == 0) + { + ret = mbedtls_ssl_get_session(&(self->ssl), configuration->savedSession); + + if (ret != 0) + { + DEBUG_PRINT("TLS", "mbedtls_ssl_get_session returned %d\n", ret); + } + else + { + configuration->savedSessionTime = Hal_getTimeInMs(); + } + } + } + } + } + + self->lastRenegotiationTime = Hal_getTimeInMs(); + + // MIGRATE 2.28->3.x.x: impossible since mbedtls 3.x.x doesn't support insecure TLS versions + // if (getTLSVersion(self->ssl.major_ver, self->ssl.minor_ver) < TLS_VERSION_TLS_1_2) { + // raiseSecurityEvent(configuration, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self); + // } + + /* create event that TLS session is established */ + { + char msg[256]; + + const char* cipherSuite = mbedtls_ssl_get_ciphersuite(&(self->ssl)); + + snprintf(msg, 255, "Info: Session established with cipher suite %s", cipherSuite); + + raiseSecurityEvent(configuration, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_ESTABLISHED, msg, self); + } + } + + return self; +} + +uint8_t* +TLSSocket_getPeerCertificate(TLSSocket self, int* certSize) +{ + if (certSize) + *certSize = self->peerCertLength; + + return self->peerCert; +} + +bool +TLSSocket_performHandshake(TLSSocket self) +{ + int ret = mbedtls_ssl_renegotiate(&(self->ssl)); + + if (ret == 0 || ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE || + ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS || ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) + { + // MIGRATE 2.28->3.x.x: impossible since mbedtls 3.x.x doesn't support insecure TLS versions + // if (getTLSVersion(self->ssl.major_ver, self->ssl.minor_ver) < TLS_VERSION_TLS_1_2) { + // raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self); + // } + + return true; + } + else { + DEBUG_PRINT("TLS", "TLSSocket_performHandshake failed -> ret=%i\n", ret); + + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Alarm: Renegotiation failed", self); + + /* mbedtls_ssl_renegotiate mandates to reset the ssl session in case of errors */ + ret = mbedtls_ssl_session_reset(&(self->ssl)); + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -> ret: -0x%X\n", -ret); + } + + return false; + } +} + +static void +checkForCRLUpdate(TLSSocket self) +{ + if (self->crlUpdated == self->tlsConfig->crlUpdated) + return; + + DEBUG_PRINT("TLS", "CRL updated -> refresh CA chain\n"); + + mbedtls_ssl_conf_ca_chain( &(self->conf), &( self->tlsConfig->cacerts), &( self->tlsConfig->crl) ); + + self->crlUpdated = self->tlsConfig->crlUpdated; + + /* IEC TS 62351-100-3 Conformance test 6.2.6 requires that upon CRL update a TLS renegotiation should occur */ + self->lastRenegotiationTime = 0; +} + +/* true = renegotiation is not needed or it is successfull, false = Failed */ +static bool +startRenegotiationIfRequired(TLSSocket self) +{ + if (self->tlsConfig->renegotiationTimeInMs <= 0) + return true; + + if (Hal_getTimeInMs() <= self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs) + return true; + + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Info: session renegotiation started", self); + + if (TLSSocket_performHandshake(self) == false) + { + DEBUG_PRINT("TLS", " renegotiation failed\n"); + return false; + } + + DEBUG_PRINT("TLS", " started renegotiation\n"); + self->lastRenegotiationTime = Hal_getTimeInMs(); + + return true; +} + +int +TLSSocket_read(TLSSocket self, uint8_t* buf, int size) +{ + checkForCRLUpdate(self); + + if (startRenegotiationIfRequired(self) == false) { + return -1; + } + + int ret = mbedtls_ssl_read(&(self->ssl), buf, size); + + if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE)) + return 0; + + if (ret < 0) { + + switch (ret) + { + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + DEBUG_PRINT("TLS", " connection was closed gracefully\n"); + return -1; + + case MBEDTLS_ERR_NET_CONN_RESET: + DEBUG_PRINT("TLS", " connection was reset by peer\n"); + return -1; + + default: + DEBUG_PRINT("TLS", " mbedtls_ssl_read returned -0x%x\n", -ret); + + { + uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); + + createSecurityEvents(self->tlsConfig, ret, flags, self); + } + + return -1; + } + } + + return ret; +} + +int +TLSSocket_write(TLSSocket self, uint8_t* buf, int size) +{ + int len = 0; + + checkForCRLUpdate(self); + + if (startRenegotiationIfRequired(self) == false) { + return -1; + } + + while (len < size) + { + int ret = mbedtls_ssl_write(&(self->ssl), (buf + len), (size -len)); + if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE) || + (ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) || (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)) { + continue; + } + + if (ret < 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_write returned -0x%X\n", -ret); + + if (0 != (ret = mbedtls_ssl_session_reset(&(self->ssl)))) { + DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -0x%X\n", -ret); + } + + return -1; + } + + len += ret; + } + + return len; +} + +void +TLSSocket_close(TLSSocket self) +{ + int ret; + + /* TODO add timeout? */ + + while ((ret = mbedtls_ssl_close_notify(&(self->ssl))) < 0) + { + if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) + { + DEBUG_PRINT("TLS", "mbedtls_ssl_close_notify returned -0x%x\n", -ret); + break; + } + } + + Thread_sleep(10); + + mbedtls_ssl_free(&(self->ssl)); + + if (self->peerCert) + GLOBAL_FREEMEM(self->peerCert); + + GLOBAL_FREEMEM(self); +} + +char* +TLSConnection_getPeerAddress(TLSConnection self, char* peerAddrBuf) +{ + TLSSocket socket = (TLSSocket)self; + + if (peerAddrBuf == NULL) { + peerAddrBuf = (char*)GLOBAL_MALLOC(61); + } + + if (peerAddrBuf) + return Socket_getPeerAddressStatic(socket->socket, peerAddrBuf); + else + return NULL; +} + +uint8_t* +TLSConnection_getPeerCertificate(TLSConnection self, int* certSize) +{ + TLSSocket socket = (TLSSocket)self; + + return TLSSocket_getPeerCertificate(socket, certSize); +} + +TLSConfigVersion +TLSConnection_getTLSVersion(TLSConnection self) +{ + TLSSocket socket = (TLSSocket)self; + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private + mbedtls_ssl_protocol_version version = mbedtls_ssl_get_version_number(&(socket->ssl)); + + switch(version) { + case MBEDTLS_SSL_VERSION_TLS1_2: + return TLS_VERSION_TLS_1_2; + case MBEDTLS_SSL_VERSION_TLS1_3: + return TLS_VERSION_TLS_1_3; + case MBEDTLS_SSL_VERSION_UNKNOWN: + default: + return TLS_VERSION_NOT_SELECTED; + } +} + +const char* +TLSConfigVersion_toString(TLSConfigVersion version) +{ + switch (version) + { + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_SSL_3_0: + return "SSL 3.0"; + case TLS_VERSION_TLS_1_0: + return "TLS 1.0"; + case TLS_VERSION_TLS_1_1: + return "TLS 1.1"; + /* Up until here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_TLS_1_2: + return "TLS 1.2"; + case TLS_VERSION_TLS_1_3: + return "TLS 1.3"; + default: + return "unknown TLS version"; + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 50e6d4c5..98f647e7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,16 @@ +if(WITH_MBEDTLS3) +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3 + ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/include +) +else() if(WITH_MBEDTLS) include_directories( ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-2.28/include ) endif(WITH_MBEDTLS) +endif(WITH_MBEDTLS3) set (lib_common_SRCS ./common/string_map.c @@ -189,7 +196,7 @@ set (lib_sv_SRCS ./sampled_values/sv_publisher.c ) -if(WITH_MBEDTLS AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)) +if((WITH_MBEDTLS OR WITH_MBEDTLS3) AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)) set (lib_rsession_SRCS ./r_session/r_session.c ./r_session/r_session_crypto_mbedtls.c @@ -220,7 +227,7 @@ set (lib_bsd_SRCS IF(WIN32) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib") -message("Found winpcap -> can compile with GOOSE support") +message("Found winpcap -> can compile with L2 GOOSE/SMV support") set(WITH_WPCAP 1) endif() @@ -232,16 +239,13 @@ set_source_files_properties(${lib_common_SRCS} ${lib_windows_SRCS} PROPERTIES LANGUAGE CXX) set_source_files_properties(${lib_rsession_SRCS} PROPERTIES LANGUAGE CXX) -ENDIF() - -IF(WITH_WPCAP) -IF(MSVC) set_source_files_properties(${lib_goose_SRCS} PROPERTIES LANGUAGE CXX) set_source_files_properties(${lib_sv_SRCS} PROPERTIES LANGUAGE CXX) - ENDIF() + +IF(WITH_WPCAP) ELSE() add_definitions(-DEXCLUDE_ETHERNET_WINDOWS) ENDIF() @@ -250,7 +254,7 @@ include_directories( ../third_party/winpcap/include ) -IF(WITH_WPCAP) +IF(WITH_WPCAP OR CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV) set (library_SRCS ${lib_common_SRCS} ${lib_asn1c_SRCS} @@ -266,11 +270,10 @@ set (library_SRCS ${lib_common_SRCS} ${lib_asn1c_SRCS} ${lib_windows_SRCS} - ${lib_rsession_SRCS} ${lib_sntp_SRCS} ) -ENDIF(WITH_WPCAP) +ENDIF(WITH_WPCAP OR CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV) ELSEIF(UNIX) IF(APPLE) diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c index 094881a5..fa276ec1 100644 --- a/src/goose/goose_publisher.c +++ b/src/goose/goose_publisher.c @@ -40,7 +40,8 @@ static bool prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID, bool useVlanTags); -struct sGoosePublisher { +struct sGoosePublisher +{ uint8_t* buffer; #if (CONFIG_IEC61850_R_GOOSE == 1) @@ -49,8 +50,10 @@ struct sGoosePublisher { uint16_t appId; #endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ +#if (CONFIG_IEC61850_L2_GOOSE == 1) /* only for Ethernet based GOOSE */ EthernetSocket ethernetSocket; +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ int lengthField; int payloadStart; @@ -99,6 +102,7 @@ GoosePublisher_createRemote(RSession session, uint16_t appId) } #endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ +#if (CONFIG_IEC61850_L2_GOOSE == 1) GoosePublisher GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, bool useVlanTag) { @@ -127,15 +131,18 @@ GoosePublisher_create(CommParameters* parameters, const char* interfaceID) { return GoosePublisher_createEx(parameters, interfaceID, true); } +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ void GoosePublisher_destroy(GoosePublisher self) { if (self) { +#if (CONFIG_IEC61850_L2_GOOSE == 1) if (self->ethernetSocket) { Ethernet_destroySocket(self->ethernetSocket); } +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ MmsValue_delete(self->timestamp); @@ -242,6 +249,7 @@ GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToL self->timeAllowedToLive = timeAllowedToLive; } +#if (CONFIG_IEC61850_L2_GOOSE == 1) static bool prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID, bool useVlanTags) { @@ -342,6 +350,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* return false; } } +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ static int32_t createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffer, size_t maxPayloadSize) @@ -460,7 +469,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe { MmsValue* dataSetEntry = (MmsValue*) element->data; - if (dataSetEntry) { + if (dataSetEntry) + { bufPos = MmsValue_encodeMmsData(dataSetEntry, buffer, bufPos, true); } else { @@ -490,7 +500,9 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet) if (self->sqNum == 0) self->sqNum = 1; - if (self->ethernetSocket) { +#if (CONFIG_IEC61850_L2_GOOSE == 1) + if (self->ethernetSocket) + { int lengthIndex = self->lengthField; size_t gooseLength = self->payloadLength + 8; @@ -503,9 +515,11 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet) if (DEBUG_GOOSE_PUBLISHER) printf("GOOSE_PUBLISHER: send GOOSE message\n"); } -#if (CONFIG_IEC61850_R_GOOSE == 1) - else if (self->remoteSession) { +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ +#if (CONFIG_IEC61850_R_GOOSE == 1) + if (self->remoteSession) + { RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_GOOSE, self->simulation, self->appId, buffer, self->payloadLength); if (DEBUG_GOOSE_PUBLISHER) diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c index 6109eee9..fd94d9c5 100644 --- a/src/goose/goose_receiver.c +++ b/src/goose/goose_receiver.c @@ -73,7 +73,7 @@ GooseReceiver_createEx(uint8_t* buffer) { GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver)); - if (self != NULL) + if (self) { self->running = false; self->stop = false; @@ -94,7 +94,8 @@ GooseReceiver_create() { GooseReceiver self = GooseReceiver_createEx(NULL); - if (self) { + if (self) + { self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH); } @@ -107,7 +108,8 @@ GooseReceiver_createRemote(RSession session) { GooseReceiver self = GooseReceiver_create(); - if (self) { + if (self) + { self->session = session; } @@ -1116,7 +1118,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes) if (subscriberFound) parseGoosePayload(self, buffer + bufPos, apduLength); - else { + else + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: GOOSE message ignored due to unknown DST-MAC or APPID value\n"); } @@ -1128,6 +1131,7 @@ gooseReceiverLoop(void *threadParameter) { GooseReceiver self = (GooseReceiver) threadParameter; +#if (CONFIG_IEC61850_L2_GOOSE == 1) if (self->ethSocket) { EthernetHandleSet handleSet = EthernetHandleSet_new(); @@ -1159,8 +1163,10 @@ gooseReceiverLoop(void *threadParameter) EthernetHandleSet_destroy(handleSet); } -#if (CONFIG_IEC61850_R_GOOSE == 0) - else if (self->session) +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ + +#if (CONFIG_IEC61850_R_GOOSE == 1) + if (self->session) { HandleSet handleSet = Handleset_new(); @@ -1207,29 +1213,38 @@ GooseReceiver_start(GooseReceiver self) { self->thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, false); - if (self->thread != NULL) { - - if (self->ethSocket) { + if (self->thread) + { +#if (CONFIG_IEC61850_L2_GOOSE == 1) + if (self->ethSocket) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: GOOSE receiver started for interface %s\n", self->interfaceId); Thread_start(self->thread); + + return; } +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ + + #if (CONFIG_IEC61850_R_GOOSE == 1) - else if (self->session) { + if (self->session) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: R-GOOSE receiver started\n"); Thread_start(self->thread); + + return; } #endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ - else { - if (DEBUG_GOOSE_SUBSCRIBER) - printf("GOOSE_SUBSCRIBER: ERROR - No link/transport layer specified -> cannot start!\n"); - Thread_destroy(self->thread); - self->thread = NULL; - } + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: ERROR - No link/transport layer specified -> cannot start!\n"); + + Thread_destroy(self->thread); + self->thread = NULL; } else { if (DEBUG_GOOSE_SUBSCRIBER) @@ -1287,7 +1302,8 @@ EthernetSocket GooseReceiver_startThreadless(GooseReceiver self) { #if (CONFIG_IEC61850_R_GOOSE == 1) - if (self->session) { + if (self->session) + { if (RSession_start(self->session) == R_SESSION_ERROR_OK) { self->running = true; @@ -1304,6 +1320,7 @@ GooseReceiver_startThreadless(GooseReceiver self) else { #endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ +#if (CONFIG_IEC61850_L2_GOOSE == 1) if (self->interfaceId == NULL) self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); else @@ -1340,6 +1357,7 @@ GooseReceiver_startThreadless(GooseReceiver self) else { self->running = false; } +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ #if (CONFIG_IEC61850_R_GOOSE == 1) } @@ -1351,20 +1369,24 @@ GooseReceiver_startThreadless(GooseReceiver self) void GooseReceiver_stopThreadless(GooseReceiver self) { +#if (CONFIG_IEC61850_L2_GOOSE == 1) if (self->ethSocket) Ethernet_destroySocket(self->ethSocket); +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ self->running = false; } +#if (CONFIG_IEC61850_R_GOOSE == 1) static void handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadData, int payloadSize) { + (void)appId; GooseReceiver self = (GooseReceiver) parameter; parseGoosePayload(self, payloadData, payloadSize); } - +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ /* call after reception of ethernet frame */ bool @@ -1381,6 +1403,8 @@ GooseReceiver_tick(GooseReceiver self) else { #endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ + +#if (CONFIG_IEC61850_L2_GOOSE == 1) int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); if (packetSize > 0) @@ -1390,6 +1414,7 @@ GooseReceiver_tick(GooseReceiver self) } else return false; +#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */ #if (CONFIG_IEC61850_R_GOOSE == 1) } diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index d6227ec7..3000224c 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3380,8 +3380,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom if (listType == MMS_GETNAMELIST_DATASETS) { - if (self->listObjectsAccessHandler) { - + if (self->listObjectsAccessHandler) + { char str[65]; char* ldName = MmsDomain_getName(domain); @@ -3414,7 +3414,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom } else if (listType == MMS_GETNAMELIST_JOURNALS) { - if (self->listObjectsAccessHandler) { + if (self->listObjectsAccessHandler) + { char str[65]; char* ldName = MmsDomain_getName(domain); @@ -3457,7 +3458,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom { FunctionalConstraint fc = IEC61850_FC_NONE; - if (separator) { + if (separator) + { fc = FunctionalConstraint_fromString(separator + 1); if (fc == IEC61850_FC_BR || fc == IEC61850_FC_US || @@ -3473,17 +3475,20 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom LogicalNode* ln = LogicalDevice_getLogicalNode(ld, str); - if (ln) { + if (ln) + { char* doStart = strchr(separator + 1, '$'); - if (doStart != NULL) { - + if (doStart != NULL) + { char* doEnd = strchr(doStart + 1, '$'); - if (doEnd == NULL) { + if (doEnd == NULL) + { StringUtils_copyStringToBuffer(doStart + 1, str); } - else { + else + { doEnd--; StringUtils_createStringFromBufferInBufferMax(str, (uint8_t*) (doStart + 1), doEnd - doStart, sizeof(str)); @@ -3521,7 +3526,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom break; } - if (self->listObjectsAccessHandler) { + if (self->listObjectsAccessHandler) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, acsiClass, ld, ln, str, subObjectName, fc); @@ -3543,14 +3549,16 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom { char* doStart = strchr(separator + 1, '$'); - if (doStart != NULL) { - + if (doStart != NULL) + { char* doEnd = strchr(doStart + 1, '$'); - if (doEnd == NULL) { + if (doEnd == NULL) + { StringUtils_copyStringToBuffer(doStart + 1, str); } - else { + else + { doEnd--; StringUtils_createStringFromBufferInBufferMax(str, (uint8_t*) (doStart + 1), doEnd - doStart, sizeof(str)); @@ -3558,8 +3566,10 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom subObjectName = StringUtils_copyStringToBufferAndReplace(doEnd + 2, subObjectBuf, '$', '.'); } - if (fc == IEC61850_FC_SP) { - if (!strcmp(str, "SGCB")) { + if (fc == IEC61850_FC_SP) + { + if (!strcmp(str, "SGCB")) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); @@ -3572,41 +3582,47 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom ModelNode* dobj = ModelNode_getChild((ModelNode*) ln, str); - if (dobj != NULL) { - - if (dobj->modelType == DataObjectModelType) { - + if (dobj != NULL) + { + if (dobj->modelType == DataObjectModelType) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - if (self->listObjectsAccessHandler) { + if (self->listObjectsAccessHandler) + { allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, dobj->name, subObjectName, fc); } } } } - else { + else + { /* no data object but with FC specified */ ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - if (self->listObjectsAccessHandler) { + if (self->listObjectsAccessHandler) + { allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, NULL, NULL, fc); } } } } } - else { + else + { LogicalNode* ln = LogicalDevice_getLogicalNode(ld, variableId); - if (ln) { + if (ln) + { /* only LN, no FC specified */ ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - if (self->listObjectsAccessHandler) { + if (self->listObjectsAccessHandler) + { allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, NULL, NULL, fc); } } @@ -3778,21 +3794,24 @@ checkDataSetAccess(MmsMapping* self, MmsServerConnection connection, MmsVariable { bool accessGranted = true; - if (self->dataSetAccessHandler) { - + if (self->dataSetAccessHandler) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); char dataSetRef[130]; dataSetRef[0] = 0; - if (listType == MMS_ASSOCIATION_SPECIFIC) { + if (listType == MMS_ASSOCIATION_SPECIFIC) + { dataSetRef[0] = '@'; StringUtils_copyStringToBuffer(dataSetRef + 1, listName); } - else if (listType == MMS_VMD_SPECIFIC) { + else if (listType == MMS_VMD_SPECIFIC) + { StringUtils_copyStringToBuffer(dataSetRef, listName); } - else if (listType == MMS_DOMAIN_SPECIFIC) { + else if (listType == MMS_DOMAIN_SPECIFIC) + { StringUtils_appendString(dataSetRef, 129, domain->domainName); StringUtils_appendString(dataSetRef, 129, "/"); StringUtils_appendString(dataSetRef, 129, listName); @@ -3841,11 +3860,12 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType printf("specific (name=%s)\n", listName); #endif /* (DEBUG_IED_SERVER == 1) */ - if (accessType == MMS_VARLIST_CREATE) { - - if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_CREATE)) { - - if (listType == MMS_DOMAIN_SPECIFIC) { + if (accessType == MMS_VARLIST_CREATE) + { + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_CREATE)) + { + if (listType == MMS_DOMAIN_SPECIFIC) + { /* check if LN exists - otherwise reject request (to fulfill test case sDsN1c) */ allow = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; @@ -3854,13 +3874,14 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType LogicalDevice* ld = IedModel_getDevice(model, domain->domainName); - if (ld != NULL) { - + if (ld != NULL) + { char lnName[129]; char* separator = strchr(listName, '$'); - if (separator != NULL) { + if (separator != NULL) + { int lnNameLen = separator - listName; memcpy(lnName, listName, lnNameLen); @@ -3869,7 +3890,6 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType if (LogicalDevice_getLogicalNode(ld, lnName) != NULL) allow = MMS_ERROR_NONE; } - } } } @@ -3877,46 +3897,58 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; } } - else if (accessType == MMS_VARLIST_DELETE) { - - if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_DELETE)) { + else if (accessType == MMS_VARLIST_DELETE) + { + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_DELETE)) + { /* Check if data set is referenced in a report */ LinkedList rcElement = self->reportControls; - while ((rcElement = LinkedList_getNext(rcElement)) != NULL) { + while ((rcElement = LinkedList_getNext(rcElement)) != NULL) + { ReportControl* rc = (ReportControl*) rcElement->data; - if (rc->isDynamicDataSet) { - if (rc->dataSet != NULL) { - - if (listType == MMS_DOMAIN_SPECIFIC) { - if (rc->dataSet->logicalDeviceName != NULL) { - if (strcmp(rc->dataSet->name, listName) == 0) { - if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { + if (rc->isDynamicDataSet) + { + if (rc->dataSet != NULL) + { + if (listType == MMS_DOMAIN_SPECIFIC) + { + if (rc->dataSet->logicalDeviceName != NULL) + { + if (strcmp(rc->dataSet->name, listName) == 0) + { + if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) + { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; break; } } } } - else if (listType == MMS_VMD_SPECIFIC) { - if (rc->dataSet->logicalDeviceName == NULL) { - if (strcmp(rc->dataSet->name, listName) == 0) { + else if (listType == MMS_VMD_SPECIFIC) + { + if (rc->dataSet->logicalDeviceName == NULL) + { + if (strcmp(rc->dataSet->name, listName) == 0) + { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + break; } } } - else if (listType == MMS_ASSOCIATION_SPECIFIC) { - if (rc->dataSet->logicalDeviceName == NULL) { - if (strcmp(rc->dataSet->name, listName) == 0) { + else if (listType == MMS_ASSOCIATION_SPECIFIC) + { + if (rc->dataSet->logicalDeviceName == NULL) + { + if (strcmp(rc->dataSet->name, listName) == 0) + { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; break; } } } - } } } @@ -3925,31 +3957,39 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType /* check if data set is referenced in a log control block*/ LinkedList logElement = self->logControls; - while ((logElement = LinkedList_getNext(logElement)) != NULL) { + while ((logElement = LinkedList_getNext(logElement)) != NULL) + { LogControl* lc = (LogControl*) logElement->data; - if (lc->isDynamicDataSet) { - if (lc->dataSet != NULL) { - - if (listType == MMS_DOMAIN_SPECIFIC) { - if (lc->dataSet->logicalDeviceName != NULL) { - if (strcmp(lc->dataSet->name, listName) == 0) { - if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { + if (lc->isDynamicDataSet) + { + if (lc->dataSet != NULL) + { + if (listType == MMS_DOMAIN_SPECIFIC) + { + if (lc->dataSet->logicalDeviceName != NULL) + { + if (strcmp(lc->dataSet->name, listName) == 0) + { + if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) + { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; break; } } } } - else if (listType == MMS_VMD_SPECIFIC) { - if (lc->dataSet->logicalDeviceName == NULL) { - if (strcmp(lc->dataSet->name, listName) == 0) { + else if (listType == MMS_VMD_SPECIFIC) + { + if (lc->dataSet->logicalDeviceName == NULL) + { + if (strcmp(lc->dataSet->name, listName) == 0) + { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + break; } } } - } } } @@ -3990,7 +4030,8 @@ mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, M MmsMapping* self = (MmsMapping*)parameter; - if (self->controlBlockAccessHandler) { + if (self->controlBlockAccessHandler) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName); @@ -4005,7 +4046,8 @@ mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, M char* separator = strchr(str, '$'); - if (separator) { + if (separator) + { name = separator + 1; *separator = 0; @@ -4049,15 +4091,18 @@ isMemberValueRecursive(MmsValue* container, MmsValue* value) if (container == value) isMemberValue = true; - else { + else + { if ((MmsValue_getType(container) == MMS_STRUCTURE) || (MmsValue_getType(container) == MMS_ARRAY)) { int compCount = MmsValue_getArraySize(container); int i; - for (i = 0; i < compCount; i++) { - if (isMemberValueRecursive(MmsValue_getElement(container, i), value)) { + for (i = 0; i < compCount; i++) + { + if (isMemberValueRecursive(MmsValue_getElement(container, i), value)) + { isMemberValue = true; break; } @@ -4077,12 +4122,15 @@ DataSet_isMemberValue(DataSet* dataSet, MmsValue* value, int* index) DataSetEntry* dataSetEntry = dataSet->fcdas; - while (dataSetEntry != NULL) { - + while (dataSetEntry != NULL) + { MmsValue* dataSetValue = dataSetEntry->value; - if (dataSetValue != NULL) { /* prevent invalid data set members */ - if (isMemberValueRecursive(dataSetValue, value)) { + if (dataSetValue != NULL) + { + /* prevent invalid data set members */ + if (isMemberValueRecursive(dataSetValue, value)) + { if (index != NULL) *index = i; @@ -4108,12 +4156,15 @@ DataSet_isMemberValueWithRef(DataSet* dataSet, MmsValue* value, char* dataRef, c DataSetEntry* dataSetEntry = dataSet->fcdas; - while (dataSetEntry != NULL) { - + while (dataSetEntry != NULL) + { MmsValue *dataSetValue = dataSetEntry->value; - if (dataSetValue != NULL) { /* prevent invalid data set members */ - if (isMemberValueRecursive(dataSetValue, value)) { + if (dataSetValue != NULL) + { + /* prevent invalid data set members */ + if (isMemberValueRecursive(dataSetValue, value)) + { if (dataRef != NULL) sprintf(dataRef, "%s%s/%s", iedName, dataSetEntry->logicalDeviceName, dataSetEntry->variableName); @@ -4137,11 +4188,12 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl { LinkedList element = self->logControls; - while ((element = LinkedList_getNext(element)) != NULL) { + while ((element = LinkedList_getNext(element)) != NULL) + { LogControl* lc = (LogControl*) element->data; - if ((lc->enabled) && (lc->dataSet != NULL)) { - + if ((lc->enabled) && (lc->dataSet != NULL)) + { uint8_t reasonCode; switch (flag) { @@ -4179,15 +4231,16 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl int dsEntryIdx = 0; - if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef, self->model->name, &dsEntryIdx)) { - - if (lc->logInstance != NULL) { - - if (lc->dataSet) { - + if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef, self->model->name, &dsEntryIdx)) + { + if (lc->logInstance != NULL) + { + if (lc->dataSet) + { DataSetEntry* dsEntry = lc->dataSet->fcdas; - while (dsEntry && (dsEntryIdx > 0)) { + while (dsEntry && (dsEntryIdx > 0)) + { dsEntry = dsEntry->sibling; if (dsEntry == NULL) @@ -4196,21 +4249,20 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl dsEntryIdx--; } - if (dsEntry) { + if (dsEntry) + { MmsValue* dsValue = dsEntry->value; LogInstance_logSingleData(lc->logInstance, dataRef, dsValue, reasonCode); } - } - } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: No log instance available!\n"); } } - } } } @@ -4278,20 +4330,24 @@ MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value) { LinkedList element = self->gseControls; - while ((element = LinkedList_getNext(element)) != NULL) { + while ((element = LinkedList_getNext(element)) != NULL) + { MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; - if (MmsGooseControlBlock_isEnabled(gcb)) { + if (MmsGooseControlBlock_isEnabled(gcb)) + { DataSet* dataSet = MmsGooseControlBlock_getDataSet(gcb); - if (DataSet_isMemberValue(dataSet, value, NULL)) { + if (DataSet_isMemberValue(dataSet, value, NULL)) + { MmsGooseControlBlock_setStateChangePending(gcb); #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->isModelLockedMutex); #endif - if (self->isModelLocked == false) { + if (self->isModelLocked == false) + { MmsGooseControlBlock_publishNewState(gcb); } @@ -4308,10 +4364,12 @@ MmsMapping_enableGoosePublishing(MmsMapping* self) { LinkedList element = LinkedList_getNext(self->gseControls); - while (element) { + while (element) + { MmsGooseControlBlock gcb = (MmsGooseControlBlock) LinkedList_getData(element); - if (MmsGooseControlBlock_enable(gcb, self) == false) { + if (MmsGooseControlBlock_enable(gcb, self) == false) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: failed to enable GoCB %s\n", MmsGooseControlBlock_getName(gcb)); } @@ -4325,14 +4383,18 @@ MmsMapping_useGooseVlanTag(MmsMapping* self, LogicalNode* ln, const char* gcbNam { LinkedList element = self->gseControls; - while ((element = LinkedList_getNext(element)) != NULL) { + while ((element = LinkedList_getNext(element)) != NULL) + { MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; - if (ln == NULL) { + if (ln == NULL) + { MmsGooseControlBlock_useGooseVlanTag(gcb, useVlanTag); } - else { - if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) { + else + { + if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) + { MmsGooseControlBlock_useGooseVlanTag(gcb, useVlanTag); } } @@ -4344,14 +4406,18 @@ MmsMapping_setGooseInterfaceId(MmsMapping* self, LogicalNode* ln, const char* g { LinkedList element = self->gseControls; - while ((element = LinkedList_getNext(element)) != NULL) { + while ((element = LinkedList_getNext(element)) != NULL) + { MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; - if (ln == NULL) { + if (ln == NULL) + { MmsGooseControlBlock_setGooseInterfaceId(gcb, interfaceId); } - else { - if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) { + else + { + if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) + { MmsGooseControlBlock_setGooseInterfaceId(gcb, interfaceId); } } @@ -4363,7 +4429,8 @@ MmsMapping_disableGoosePublishing(MmsMapping* self) { LinkedList element = self->gseControls; - while ((element = LinkedList_getNext(element)) != NULL) { + while ((element = LinkedList_getNext(element)) != NULL) + { MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; MmsGooseControlBlock_disable(gcb, self); @@ -4393,10 +4460,12 @@ GOOSE_processGooseEvents(MmsMapping* self, uint64_t currentTimeInMs) { LinkedList element = LinkedList_getNext(self->gseControls); - while (element != NULL) { + while (element != NULL) + { MmsGooseControlBlock mmsGCB = (MmsGooseControlBlock) element->data; - if (MmsGooseControlBlock_isEnabled(mmsGCB)) { + if (MmsGooseControlBlock_isEnabled(mmsGCB)) + { MmsGooseControlBlock_checkAndPublish(mmsGCB, currentTimeInMs, self); } @@ -4449,8 +4518,8 @@ eventWorkerThread(MmsMapping* self) { bool running = true; - while (running) { - + while (running) + { processPeriodicTasks(self); Thread_sleep(1); /* hand-over control to other threads */ @@ -4477,11 +4546,12 @@ MmsMapping_startEventWorkerThread(MmsMapping* self) void MmsMapping_stopEventWorkerThread(MmsMapping* self) { - if (self->reportThreadRunning) { - + if (self->reportThreadRunning) + { self->reportThreadRunning = false; - if (self->reportWorkerThread) { + if (self->reportWorkerThread) + { Thread_destroy(self->reportWorkerThread); self->reportWorkerThread = NULL; } @@ -4494,15 +4564,18 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi { DataSet* dataSet = (DataSet*) GLOBAL_CALLOC(1, sizeof(DataSet)); - if (dataSet) { - - if (variableList->domain != NULL) { + if (dataSet) + { + if (variableList->domain != NULL) + { LogicalDevice* ld = IedModel_getDevice(self->model, MmsDomain_getName(variableList->domain)); - if (ld) { + if (ld) + { dataSet->logicalDeviceName = ld->name; } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: LD lookup error!"); } @@ -4517,17 +4590,18 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi DataSetEntry* lastDataSetEntry = NULL; - while (element != NULL) { + while (element != NULL) + { MmsAccessSpecifier* listEntry = (MmsAccessSpecifier*) element->data; LogicalDevice* entryLd = IedModel_getDevice(self->model, MmsDomain_getName(listEntry->domain)); - if (entryLd) { - + if (entryLd) + { DataSetEntry* dataSetEntry = (DataSetEntry*) GLOBAL_MALLOC(sizeof(DataSetEntry)); - if (dataSetEntry) { - + if (dataSetEntry) + { /* use variable name part of domain name as logicalDeviceName */ dataSetEntry->logicalDeviceName = entryLd->name; dataSetEntry->variableName = listEntry->variableName; @@ -4545,42 +4619,51 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi MmsValue* dataSetEntryValue = MmsServer_getValueFromCacheEx(self->mmsServer, listEntry->domain, listEntry->variableName, &dataSetEntryVarSpec); - if (dataSetEntryValue) { - if (dataSetEntry->index != -1) { - if (dataSetEntryVarSpec->type == MMS_ARRAY) { + if (dataSetEntryValue) + { + if (dataSetEntry->index != -1) + { + if (dataSetEntryVarSpec->type == MMS_ARRAY) + { MmsValue* elementValue = MmsValue_getElement(dataSetEntryValue, dataSetEntry->index); - if (elementValue) { - - if (dataSetEntry->componentName) { + if (elementValue) + { + if (dataSetEntry->componentName) + { MmsVariableSpecification* elementType = dataSetEntryVarSpec->typeSpec.array.elementTypeSpec; MmsValue* subElementValue = MmsVariableSpecification_getChildValue(elementType, elementValue, dataSetEntry->componentName); - if (subElementValue) { + if (subElementValue) + { dataSetEntry->value = subElementValue; } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: ERROR - component %s of array element not found\n", dataSetEntry->componentName); } - } - else { + else + { dataSetEntry->value = elementValue; } } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: ERROR - array element %i not found\n", dataSetEntry->index); } } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: ERROR - variable %s/%s is not an array\n", dataSetEntry->logicalDeviceName, dataSetEntry->variableName); } } - else { + else + { dataSetEntry->value = dataSetEntryValue; } } @@ -4588,7 +4671,8 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi lastDataSetEntry = dataSetEntry; } } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: LD lookup error!\n"); } @@ -4644,7 +4728,8 @@ MmsMapping_freeDynamicallyCreatedDataSet(DataSet* dataSet) { DataSetEntry* dataSetEntry = dataSet->fcdas; - while (dataSetEntry != NULL) { + while (dataSetEntry) + { DataSetEntry* nextEntry = dataSetEntry->sibling; GLOBAL_FREEMEM (dataSetEntry); diff --git a/src/mms/asn1/ber_encoder.c b/src/mms/asn1/ber_encoder.c index 53a5d178..86e6a02c 100644 --- a/src/mms/asn1/ber_encoder.c +++ b/src/mms/asn1/ber_encoder.c @@ -1,7 +1,7 @@ /* * ber_encoder.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * diff --git a/src/mms/inc/mms_value.h b/src/mms/inc/mms_value.h index 206345c4..05c40ec3 100644 --- a/src/mms/inc/mms_value.h +++ b/src/mms/inc/mms_value.h @@ -1018,6 +1018,20 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize); LIB61850_API MmsValue* MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos); +/** + * \brief create a new MmsValue instance from a BER encoded MMS Data element (deserialize) with a defined maximum recursion depth + * + * \param buffer the buffer to read from + * \param bufPos the start position of the mms value data in the buffer + * \param bufferLength the length of the buffer + * \param endBufPos the position in the buffer after the read MMS data element (NULL if not required) + * \param maxDepth the maximum recursion depth + * + * \return the MmsValue instance created from the buffer + */ +LIB61850_API MmsValue* +MmsValue_decodeMmsDataMaxRecursion(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos, int maxDepth); + /** * \brief Serialize the MmsValue instance as BER encoded MMS Data element * diff --git a/src/mms/inc_private/ber_encoder.h b/src/mms/inc_private/ber_encoder.h index 48cd2bc6..4668e0cc 100644 --- a/src/mms/inc_private/ber_encoder.h +++ b/src/mms/inc_private/ber_encoder.h @@ -1,7 +1,7 @@ /* * ber_encoder.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -75,6 +75,9 @@ BerEncoder_encodeFloat(uint8_t* floatValue, uint8_t formatWidth, uint8_t exponen LIB61850_INTERNAL int BerEncoder_UInt32determineEncodedSize(uint32_t value); +LIB61850_INTERNAL int +BerEncoder_Int32determineEncodedSize(int32_t value); + LIB61850_INTERNAL int BerEncoder_determineLengthSize(uint32_t length); diff --git a/src/mms/iso_cotp/cotp.c b/src/mms/iso_cotp/cotp.c index 2b4e43e6..e8f5f50e 100644 --- a/src/mms/iso_cotp/cotp.c +++ b/src/mms/iso_cotp/cotp.c @@ -67,8 +67,8 @@ writeOptions(CotpConnection* self) uint8_t* buffer = self->writeBuffer->buffer; int bufPos = self->writeBuffer->size; - if (self->options.tpduSize != 0) { - + if (self->options.tpduSize != 0) + { if (DEBUG_COTP) printf("COTP: send TPDU size: %i\n", CotpConnection_getTpduSize(self)); @@ -77,7 +77,8 @@ writeOptions(CotpConnection* self) buffer[bufPos++] = self->options.tpduSize; } - if (self->options.tSelDst.size != 0) { + if (self->options.tSelDst.size != 0) + { buffer[bufPos++] = 0xc2; buffer[bufPos++] = (uint8_t) self->options.tSelDst.size; @@ -86,7 +87,8 @@ writeOptions(CotpConnection* self) buffer[bufPos++] = (uint8_t) self->options.tSelDst.value[i]; } - if (self->options.tSelSrc.size != 0) { + if (self->options.tSelSrc.size != 0) + { buffer[bufPos++] = 0xc1; buffer[bufPos++] = (uint8_t) self->options.tSelSrc.size; @@ -177,28 +179,32 @@ writeToSocket(CotpConnection* self, uint8_t* buf, int size) static bool flushBuffer(CotpConnection* self) { - if (self->socketExtensionBufferFill > 0) { - + if (self->socketExtensionBufferFill > 0) + { int sentBytes = writeToSocket(self, self->socketExtensionBuffer, self->socketExtensionBufferFill); - if (sentBytes > 0) { - - if (sentBytes != self->socketExtensionBufferFill) { + if (sentBytes > 0) + { + if (sentBytes != self->socketExtensionBufferFill) + { int target = 0; int i; uint8_t* buf = self->socketExtensionBuffer; - for (i = sentBytes; i < self->socketExtensionBufferFill; i++) { + for (i = sentBytes; i < self->socketExtensionBufferFill; i++) + { buf[target++] = buf[i]; } self->socketExtensionBufferFill = self->socketExtensionBufferFill - sentBytes; } - else { + else + { self->socketExtensionBufferFill = 0; } } - else if (sentBytes == -1) { + else if (sentBytes == -1) + { return false; } } @@ -214,35 +220,40 @@ sendBuffer(CotpConnection* self) bool retVal = false; - if (flushBuffer(self) == false) { + if (flushBuffer(self) == false) + { goto exit_function; } int sentBytes = 0; - if (self->socketExtensionBufferFill == 0) { + if (self->socketExtensionBufferFill == 0) + { sentBytes = writeToSocket(self, buffer, remainingSize); } if (sentBytes == -1) goto exit_function; - if (sentBytes != remainingSize) { - + if (sentBytes != remainingSize) + { /* write additional data to extension buffer */ - if (self->socketExtensionBuffer) { + if (self->socketExtensionBuffer) + { uint8_t* extBuf = self->socketExtensionBuffer; int extCurrentPos = self->socketExtensionBufferFill; int bytesNotSent = remainingSize - sentBytes; int i; - for (i = 0; i < bytesNotSent; i++) { + for (i = 0; i < bytesNotSent; i++) + { extBuf[i + extCurrentPos] = buffer[sentBytes + i]; } self->socketExtensionBufferFill = extCurrentPos + bytesNotSent; } - else { + else + { goto exit_function; } } @@ -264,7 +275,9 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) int fragmentPayloadSize = CotpConnection_getTpduSize(self) - COTP_DATA_HEADER_SIZE; - if (payload->length > fragmentPayloadSize) { /* Check if segmentation is required? */ + if (payload->length > fragmentPayloadSize) + { + /* Check if segmentation is required? */ fragments = payload->length / fragmentPayloadSize; if ((payload->length % fragmentPayloadSize) != 0) @@ -275,15 +288,18 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) int totalSize = (fragments * (COTP_DATA_HEADER_SIZE + 4)) + payload->length; /* try to flush extension buffer */ - if (flushBuffer(self) == false) { + if (flushBuffer(self) == false) + { return COTP_ERROR; } /* check if totalSize will fit in extension buffer */ - if (self->socketExtensionBuffer) { + if (self->socketExtensionBuffer) + { int freeExtBufSize = self->socketExtensionBufferSize - self->socketExtensionBufferFill; - if (freeExtBufSize < totalSize) { + if (freeExtBufSize < totalSize) + { return COTP_ERROR; } } @@ -300,12 +316,15 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) uint8_t* buffer = self->writeBuffer->buffer; - while (fragments > 0) { - if (fragments > 1) { + while (fragments > 0) + { + if (fragments > 1) + { currentLimit = currentBufPos + fragmentPayloadSize; lastUnit = 0; } - else { + else + { currentLimit = payload->length; lastUnit = 1; } @@ -317,9 +336,10 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) int bufPos = 7; int i; - for (i = currentBufPos; i < currentLimit; i++) { - - if (currentChainIndex >= currentChain->partLength) { + for (i = currentBufPos; i < currentLimit; i++) + { + if (currentChainIndex >= currentChain->partLength) + { currentChain = currentChain->nextPart; if (DEBUG_COTP) printf("COTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength); @@ -338,7 +358,8 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) if (DEBUG_COTP) printf("COTP: Send COTP fragment %i bufpos: %i\n", fragments, currentBufPos); - if (!sendBuffer(self)) { + if (!sendBuffer(self)) + { retValue = COTP_ERROR; if (DEBUG_COTP) @@ -438,11 +459,13 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen) { int bufPos = 0; - while (bufPos < bufLen) { + while (bufPos < bufLen) + { uint8_t optionType = buffer[bufPos++]; uint8_t optionLen = buffer[bufPos++]; - if (optionLen > (bufLen - bufPos)) { + if (optionLen > (bufLen - bufPos)) + { if (DEBUG_COTP) printf("COTP: option to long optionLen:%i bufPos:%i bufLen:%i\n", optionLen, bufPos, bufLen); goto cpo_error; @@ -453,7 +476,8 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen) switch (optionType) { case 0xc0: - if (optionLen == 1) { + if (optionLen == 1) + { int requestedTpduSize = (1 << buffer[bufPos++]); CotpConnection_setTpduSize(self, requestedTpduSize); @@ -466,7 +490,8 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen) break; case 0xc1: /* remote T-selector */ - if (optionLen < 5) { + if (optionLen < 5) + { self->options.tSelSrc.size = optionLen; int i; @@ -478,7 +503,8 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen) break; case 0xc2: /* local T-selector */ - if (optionLen < 5) { + if (optionLen < 5) + { self->options.tSelDst.size = optionLen; int i; @@ -650,7 +676,8 @@ parseDataTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) static bool addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength) { - if (payloadLength < 1) { + if (payloadLength < 1) + { if (DEBUG_COTP) printf("COTP: missing payload\n"); @@ -681,7 +708,8 @@ parseCotpMessage(CotpConnection* self) len = buffer[0]; - if (len > tpduLength) { + if (len > tpduLength) + { if (DEBUG_COTP) printf("COTP: parseCotpMessage: len=%d tpduLength=%d\n", len, tpduLength); @@ -702,8 +730,8 @@ parseCotpMessage(CotpConnection* self) else return COTP_ERROR; case 0xf0: - if (parseDataTpdu(self, buffer + 2, len)) { - + if (parseDataTpdu(self, buffer + 2, len)) + { if (addPayloadToBuffer(self, buffer + 3, tpduLength - 3) != 1) return COTP_ERROR; @@ -743,7 +771,8 @@ readFromSocket(CotpConnection* self, uint8_t* buf, int size) #if (CONFIG_MMS_SUPPORT_TLS == 1) if (self->tlsSocket) return TLSSocket_read(self->tlsSocket, buf, size); - else { + else + { switch (Handleset_waitReady(self->handleSet, 10)) { case -1: @@ -787,7 +816,8 @@ CotpConnection_readToTpktBuffer(CotpConnection* self) assert (bufferSize > 4); - if (self->socketExtensionBufferFill > 0) { + if (self->socketExtensionBufferFill > 0) + { if (flushBuffer(self) == false) goto exit_error; @@ -797,33 +827,38 @@ CotpConnection_readToTpktBuffer(CotpConnection* self) int readBytes; - if (bufPos < 4) { - + if (bufPos < 4) + { readBytes = readFromSocket(self, buffer + bufPos, 4 - bufPos); if (readBytes < 0) goto exit_closed; - if (DEBUG_COTP) { + if (DEBUG_COTP) + { if (readBytes > 0) printf("TPKT: read %i bytes from socket\n", readBytes); } bufPos += readBytes; - if (bufPos == 4) { - if ((buffer[0] == 3) && (buffer[1] == 0)) { + if (bufPos == 4) + { + if ((buffer[0] == 3) && (buffer[1] == 0)) + { self->packetSize = (buffer[2] * 0x100) + buffer[3]; if (DEBUG_COTP) printf("TPKT: header complete (msg size = %i)\n", self->packetSize); - if (self->packetSize > bufferSize) { + if (self->packetSize > bufferSize) + { if (DEBUG_COTP) printf("TPKT: packet too large\n"); goto exit_error; } } - else { + else + { if (DEBUG_COTP) printf("TPKT: failed to decode TPKT header.\n"); goto exit_error; } @@ -869,4 +904,3 @@ exit_waiting: self->readBuffer->size = bufPos; return TPKT_WAITING; } - diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index e92f8046..3522fda0 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -3579,6 +3579,7 @@ MmsJournalEntry_destroy(MmsJournalEntry self) MmsValue_delete(self->occurenceTime); LinkedList_destroyDeep(self->journalVariables, (LinkedListValueDeleteFunction) MmsJournalVariable_destroy); + GLOBAL_FREEMEM(self); } } diff --git a/src/mms/iso_mms/client/mms_client_journals.c b/src/mms/iso_mms/client/mms_client_journals.c index 6ae36782..affbca57 100644 --- a/src/mms/iso_mms/client/mms_client_journals.c +++ b/src/mms/iso_mms/client/mms_client_journals.c @@ -1,7 +1,7 @@ /* * mms_client_journals.c * - * Copyright 2016 Michael Zillgith + * Copyright 2016-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -38,15 +38,16 @@ parseJournalVariable(uint8_t* buffer, int bufPos, int maxLength, MmsJournalVaria { int maxBufPos = bufPos + maxLength; - while (bufPos < maxBufPos) { - + while (bufPos < maxBufPos) + { uint8_t tag = buffer[bufPos++]; int length; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); @@ -56,17 +57,23 @@ parseJournalVariable(uint8_t* buffer, int bufPos, int maxLength, MmsJournalVaria switch (tag) { case 0x80: /* variableTag */ - if (journalVariable->tag == NULL) { + if (journalVariable->tag == NULL) + { journalVariable->tag = (char*) GLOBAL_MALLOC(length + 1); - memcpy(journalVariable->tag, buffer + bufPos, length); - journalVariable->tag[length] = 0; + + if (journalVariable->tag) + { + memcpy(journalVariable->tag, buffer + bufPos, length); + journalVariable->tag[length] = 0; + } } break; case 0xa1: /* valueSpec */ - if (journalVariable->value == NULL) { + if (journalVariable->value == NULL) + { journalVariable->value = MmsValue_decodeMmsData(buffer, bufPos, bufPos + length, NULL); } @@ -91,30 +98,52 @@ parseJournalVariables(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntr { int maxBufPos = bufPos + maxLength; - while (bufPos < maxBufPos) { - + while (bufPos < maxBufPos) + { int length; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); return false; } - MmsJournalVariable journalVariable; - switch (tag) { case 0x30: /* journalVariable */ - journalVariable = (MmsJournalVariable) + MmsJournalVariable journalVariable = (MmsJournalVariable) GLOBAL_CALLOC(1, sizeof(struct sMmsJournalVariable)); - parseJournalVariable(buffer, bufPos, length, journalVariable); + if (journalVariable) + { + if (parseJournalVariable(buffer, bufPos, length, journalVariable)) + { + LinkedList_add(journalEntry->journalVariables, (void*) journalVariable); + } + else + { + if (journalVariable->tag) + GLOBAL_FREEMEM(journalVariable->tag); - LinkedList_add(journalEntry->journalVariables, (void*) journalVariable); + if (journalVariable->value) + MmsValue_delete(journalVariable->value); + + GLOBAL_FREEMEM(journalVariable); + + return false; + } + } + else + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: out of memory\n"); + + return false; + } break; @@ -136,13 +165,14 @@ parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEnt { int maxBufPos = bufPos + maxLength; - while (bufPos < maxBufPos) { - + while (bufPos < maxBufPos) + { int length; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); @@ -151,10 +181,29 @@ parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEnt switch (tag) { case 0xa1: /* journalVariables */ + if (journalEntry->journalVariables) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: duplicate journalVariables\n"); - journalEntry->journalVariables = LinkedList_create(); - - parseJournalVariables(buffer, bufPos, length, journalEntry); + return false; + } + else + { + journalEntry->journalVariables = LinkedList_create(); + + if (journalEntry->journalVariables == NULL) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: out of memory\n"); + + return false; + } + else + { + parseJournalVariables(buffer, bufPos, length, journalEntry); + } + } break; @@ -163,7 +212,6 @@ parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEnt default: break; - } bufPos += length; @@ -177,29 +225,41 @@ parseEntryContent(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry jo { int maxBufPos = bufPos + maxLength; - while (bufPos < maxBufPos) { + while (bufPos < maxBufPos) + { + int length; + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); - int length; - uint8_t tag = buffer[bufPos++]; - bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); - if (bufPos < 0) { - if (DEBUG_MMS_CLIENT) - printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); + return false; + } - return false; - } + switch (tag) { + case 0x80: /* occurenceTime */ - switch (tag) { - case 0x80: /* occurenceTime */ - if (length == 6) - journalEntry->occurenceTime = MmsValue_newBinaryTime(false); - else if (length == 4) - journalEntry->occurenceTime = MmsValue_newBinaryTime(true); - else - break; + if (journalEntry->occurenceTime) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: duplicate occurenceTime\n"); - memcpy(journalEntry->occurenceTime->value.binaryTime.buf, buffer + bufPos, length); + return false; + } + else + { + if (length == 6) + journalEntry->occurenceTime = MmsValue_newBinaryTime(false); + else if (length == 4) + journalEntry->occurenceTime = MmsValue_newBinaryTime(true); + else + break; + + memcpy(journalEntry->occurenceTime->value.binaryTime.buf, buffer + bufPos, length); + } break; @@ -230,26 +290,46 @@ parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journal int maxBufPos = bufPos + maxLength; MmsJournalEntry journalEntry = (MmsJournalEntry) GLOBAL_CALLOC(1, sizeof(struct sMmsJournalEntry)); - LinkedList_add(journalEntries, (void*) journalEntry); - while (bufPos < maxBufPos) { + if (journalEntry == NULL) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: out of memory\n"); + + return false; + } + while (bufPos < maxBufPos) + { int length; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); - return false; + goto exit_error; } - switch (tag) { - + switch (tag) + { case 0x80: /* entryID */ - journalEntry->entryID = MmsValue_newOctetString(length, length); - MmsValue_setOctetString(journalEntry->entryID, buffer + bufPos, length); + if (journalEntry->entryID) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: parseReadJournalResponse: duplicate entryID\n"); + + goto exit_error; + } + else + { + journalEntry->entryID = MmsValue_newOctetString(length, length); + + if (journalEntry->entryID) + MmsValue_setOctetString(journalEntry->entryID, buffer + bufPos, length); + } break; case 0xa1: /* originatingApplication */ @@ -258,7 +338,7 @@ parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journal case 0xa2: /* entryContent */ if (parseEntryContent(buffer, bufPos, length, journalEntry) == false) - return false; + goto exit_error; break; @@ -269,13 +349,21 @@ parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journal if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: parseReadJournalResponse: unknown tag %02x\n", tag); - return false; + goto exit_error; } bufPos += length; } + LinkedList_add(journalEntries, (void*) journalEntry); + return true; + +exit_error: + + MmsJournalEntry_destroy(journalEntry); + + return false; } static bool @@ -283,14 +371,14 @@ parseListOfJournalEntries(uint8_t* buffer, int bufPos, int maxLength, LinkedList { int maxBufPos = bufPos + maxLength; - - while (bufPos < maxBufPos) { - + while (bufPos < maxBufPos) + { int length; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n"); @@ -322,8 +410,6 @@ parseListOfJournalEntries(uint8_t* buffer, int bufPos, int maxLength, LinkedList bool mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* moreFollows, LinkedList* result) { - - uint8_t* buffer = ByteBuffer_getBuffer(response); int maxBufPos = ByteBuffer_getSize(response); int bufPos = respBufPos; @@ -331,7 +417,8 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m uint8_t tag = buffer[bufPos++]; - if (tag != 0xbf) { + if (tag != 0xbf) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: unknown tag %02x\n", tag); return false; @@ -342,7 +429,8 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m if (moreFollows) *moreFollows = false; - if (tag != 0x41) { + if (tag != 0x41) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: unknown tag %02x\n", tag); return false; @@ -355,17 +443,43 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m LinkedList journalEntries = NULL; - while (bufPos < endPos) { + while (bufPos < endPos) + { tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); if (bufPos < 0) return false; switch (tag) { case 0xa0: /* listOfJournalEntry */ - journalEntries = LinkedList_create(); - if (!parseListOfJournalEntries(buffer, bufPos, length, journalEntries)) + if (journalEntries) + { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: duplicate listOfJournalEntry\n"); + + LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy); + return false; + } + else + { + journalEntries = LinkedList_create(); + + if (journalEntries) + { + if (!parseListOfJournalEntries(buffer, bufPos, length, journalEntries)) + { + LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy); + + return false; + } + } + else + { + return false; + } + } + break; case 0x81: /* moreFollows */ @@ -380,6 +494,8 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: message contains unknown tag %02x!\n", tag); + LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy); + return false; } @@ -524,4 +640,3 @@ mmsClient_createReadJournalRequestStartAfter(uint32_t invokeId, ByteBuffer* requ request->size = bufPos; } - diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c index bf0bc018..5e0443d4 100644 --- a/src/mms/iso_mms/client/mms_client_read.c +++ b/src/mms/iso_mms/client/mms_client_read.c @@ -1,7 +1,7 @@ /* * mms_client_read.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -45,17 +45,19 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi int i = 0; - for (i = 0; i < elementCount; i++) { - + for (i = 0; i < elementCount; i++) + { value = NULL; AccessResult_PR presentType = accessResultList[i]->present; - if (presentType == AccessResult_PR_failure) { + if (presentType == AccessResult_PR_failure) + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: received access error!\n"); - if (accessResultList[i]->choice.failure.size > 0) { + if (accessResultList[i]->choice.failure.size > 0) + { int errorCode = (int) accessResultList[i]->choice.failure.buf[0]; MmsDataAccessError dataAccessError = DATA_ACCESS_ERROR_UNKNOWN; @@ -68,26 +70,29 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi else value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); } - else if (presentType == AccessResult_PR_array) { - + else if (presentType == AccessResult_PR_array) + { int arrayElementCount = accessResultList[i]->choice.array.list.count; - if (arrayElementCount > 0) { + if (arrayElementCount > 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_ARRAY; value->value.structure.size = arrayElementCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); - if (value->value.structure.components) { + if (value->value.structure.components) + { int j; - for (j = 0; j < arrayElementCount; j++) { + for (j = 0; j < arrayElementCount; j++) + { value->value.structure.components[j] = mmsMsg_parseDataElement( accessResultList[i]->choice.array.list.array[j]); - if (value->value.structure.components[j] == NULL) { - + if (value->value.structure.components[j] == NULL) + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: failed to parse array element %i\n", j); @@ -98,33 +103,37 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi } } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid array size)!\n"); } - } - else if (presentType == AccessResult_PR_structure) { - + else if (presentType == AccessResult_PR_structure) + { int componentCount = accessResultList[i]->choice.structure.list.count; - if (componentCount > 0) { + if (componentCount > 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_STRUCTURE; value->value.structure.size = componentCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); - if (value->value.structure.components) { + if (value->value.structure.components) + { int j; - for (j = 0; j < componentCount; j++) { + for (j = 0; j < componentCount; j++) + { value->value.structure.components[j] = mmsMsg_parseDataElement( accessResultList[i]->choice.structure.list.array[j]); - if (value->value.structure.components[j] == NULL) { - + if (value->value.structure.components[j] == NULL) + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: failed to parse struct element %i\n", j); @@ -136,213 +145,257 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi } } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid structure size)!\n"); } - } - else if (presentType == AccessResult_PR_bitstring) { - + else if (presentType == AccessResult_PR_bitstring) + { int size = accessResultList[i]->choice.bitstring.size; - if (size > 0) { - + if (size > 0) + { int maxSize = (size * 8); int bitSize = maxSize - accessResultList[i]->choice.bitstring.bits_unused; - if ((bitSize > 0) && (maxSize >= bitSize)) { - + if ((bitSize > 0) && (maxSize >= bitSize)) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_BIT_STRING; + if (value) + { + value->type = MMS_BIT_STRING; - value->value.bitString.size = (size * 8) - - accessResultList[i]->choice.bitstring.bits_unused; + value->value.bitString.size = (size * 8) + - accessResultList[i]->choice.bitstring.bits_unused; - value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.bitString.buf, - accessResultList[i]->choice.bitstring.buf, size); + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + accessResultList[i]->choice.bitstring.buf, size); + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (bit string padding problem)!\n"); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (bit string size 0 or negative)!\n"); } - } - else if (presentType == AccessResult_PR_integer) { - + else if (presentType == AccessResult_PR_integer) + { int size = accessResultList[i]->choice.integer.size; - if (size > 0) { + if (size > 0) + { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, size); value = MmsValue_newIntegerFromBerInteger(berInteger); } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid integer size)!\n"); } } - else if (presentType == AccessResult_PR_unsigned) { - + else if (presentType == AccessResult_PR_unsigned) + { int size = accessResultList[i]->choice.Unsigned.size; - if (size > 0) { + if (size > 0) + { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, accessResultList[i]->choice.Unsigned.size); value = MmsValue_newUnsignedFromBerInteger(berInteger); } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid unsigned size)!\n"); } - } - else if (presentType == AccessResult_PR_floatingpoint) { - + else if (presentType == AccessResult_PR_floatingpoint) + { int size = accessResultList[i]->choice.floatingpoint.size; - if (size == 5) { /* FLOAT32 */ - + if (size == 5) /* FLOAT32 */ + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_FLOAT; - value->value.floatingPoint.formatWidth = 32; - value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; + if (value) + { + value->type = MMS_FLOAT; + + value->value.floatingPoint.formatWidth = 32; + value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; - uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); + uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); #if (ORDER_LITTLE_ENDIAN == 1) - memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); #else - memcpy(value->value.floatingPoint.buf, floatBuf, 4); + memcpy(value->value.floatingPoint.buf, floatBuf, 4); #endif - + } } - else if (size == 9) { /* FLOAT64 */ - + else if (size == 9) /* FLOAT64 */ + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_FLOAT; - value->value.floatingPoint.formatWidth = 64; - value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; + if (value) + { + value->type = MMS_FLOAT; - uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); + value->value.floatingPoint.formatWidth = 64; + value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; + + uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); #if (ORDER_LITTLE_ENDIAN == 1) - memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); #else - memcpy(value->value.floatingPoint.buf, floatBuf, 8); + memcpy(value->value.floatingPoint.buf, floatBuf, 8); #endif + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing float (size must be 5 or 9, is %i)\n", size); } - } - else if (presentType == AccessResult_PR_visiblestring) { - + else if (presentType == AccessResult_PR_visiblestring) + { int strSize = accessResultList[i]->choice.visiblestring.size; - if (strSize >= 0) { + if (strSize >= 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_VISIBLE_STRING; - value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); - value->value.visibleString.size = strSize; + if (value) + { + value->type = MMS_VISIBLE_STRING; + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; - memcpy(value->value.visibleString.buf, - accessResultList[i]->choice.visiblestring.buf, - strSize); + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.visiblestring.buf, + strSize); - value->value.visibleString.buf[strSize] = 0; + value->value.visibleString.buf[strSize] = 0; + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid visible-string size)\n"); } - } - else if (presentType == AccessResult_PR_mMSString) { - + else if (presentType == AccessResult_PR_mMSString) + { int strSize = accessResultList[i]->choice.mMSString.size; - if (strSize >= 0) { + if (strSize >= 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_STRING; - value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); - value->value.visibleString.size = strSize; + if (value) + { + value->type = MMS_STRING; + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; - memcpy(value->value.visibleString.buf, - accessResultList[i]->choice.mMSString.buf, strSize); + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.mMSString.buf, strSize); - value->value.visibleString.buf[strSize] = 0; + value->value.visibleString.buf[strSize] = 0; + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid mms-string size)\n"); } } - else if (presentType == AccessResult_PR_utctime) { - + else if (presentType == AccessResult_PR_utctime) + { int size = accessResultList[i]->choice.utctime.size; - if (size == 8) { + if (size == 8) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_UTC_TIME; - memcpy(value->value.utcTime, accessResultList[i]->choice.utctime.buf, 8); + if (value) + { + value->type = MMS_UTC_TIME; + memcpy(value->value.utcTime, accessResultList[i]->choice.utctime.buf, 8); + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size); } } - else if (presentType == AccessResult_PR_boolean) { + else if (presentType == AccessResult_PR_boolean) + { value = MmsValue_newBoolean(accessResultList[i]->choice.boolean); } - else if (presentType == AccessResult_PR_binarytime) { + else if (presentType == AccessResult_PR_binarytime) + { int size = accessResultList[i]->choice.binarytime.size; - if ((size == 4) || (size == 6)) { + if ((size == 4) || (size == 6)) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_BINARY_TIME; - value->value.binaryTime.size = size; - memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); + + if (value) + { + value->type = MMS_BINARY_TIME; + value->value.binaryTime.size = size; + memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size); } } - else if (presentType == AccessResult_PR_octetstring) { + else if (presentType == AccessResult_PR_octetstring) + { int size = accessResultList[i]->choice.octetstring.size; - if (size >= 0) { + if (size >= 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_OCTET_STRING; - value->value.octetString.maxSize = -size; - value->value.octetString.size = size; - value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + + if (value) + { + value->type = MMS_OCTET_STRING; + value->value.octetString.maxSize = -size; + value->value.octetString.size = size; + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing access result (invalid octet-string size)\n"); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: unknown type %i in access result\n", presentType); value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID); diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c index 76657334..a52d8e07 100644 --- a/src/mms/iso_mms/common/mms_common_msg.c +++ b/src/mms/iso_mms/common/mms_common_msg.c @@ -185,25 +185,29 @@ mmsMsg_parseDataElement(Data_t* dataElement) { MmsValue* value = NULL; - if (dataElement->present == Data_PR_array) { - + if (dataElement->present == Data_PR_array) + { int componentCount = dataElement->choice.array->list.count; - if (componentCount > 0) { + if (componentCount > 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_ARRAY; value->value.structure.size = componentCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; - for (i = 0; i < componentCount; i++) { + for (i = 0; i < componentCount; i++) + { value->value.structure.components[i] = mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); - if (value->value.structure.components[i] == NULL) { + if (value->value.structure.components[i] == NULL) + { MmsValue_delete(value); value = NULL; break; @@ -211,31 +215,35 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing data element (invalid array size)!\n"); } - } - else if (dataElement->present == Data_PR_structure) { - + else if (dataElement->present == Data_PR_structure) + { int componentCount = dataElement->choice.structure->list.count; - if (componentCount > 0) { + if (componentCount > 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_STRUCTURE; value->value.structure.size = componentCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; - for (i = 0; i < componentCount; i++) { + for (i = 0; i < componentCount; i++) + { value->value.structure.components[i] = mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); - if (value->value.structure.components[i] == NULL) { + if (value->value.structure.components[i] == NULL) + { MmsValue_delete(value); value = NULL; break; @@ -243,112 +251,128 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing data element (invalid structure size)!\n"); } } - else { - if (dataElement->present == Data_PR_integer) { - - if (dataElement->choice.integer.size > 0) { + else + { + if (dataElement->present == Data_PR_integer) + { + if (dataElement->choice.integer.size > 0) + { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( dataElement->choice.integer.buf, dataElement->choice.integer.size); if (berInteger) value = MmsValue_newIntegerFromBerInteger(berInteger); } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing data element (invalid integer size)!\n"); } } - else if (dataElement->present == Data_PR_unsigned) { - - if (dataElement->choice.Unsigned.size > 0) { + else if (dataElement->present == Data_PR_unsigned) + { + if (dataElement->choice.Unsigned.size > 0) + { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); if (berInteger) value = MmsValue_newUnsignedFromBerInteger(berInteger); } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing data element (invalid unsigned size)!\n"); } } - else if (dataElement->present == Data_PR_visiblestring) { - - if (dataElement->choice.visiblestring.size >= 0) { + else if (dataElement->present == Data_PR_visiblestring) + { + if (dataElement->choice.visiblestring.size >= 0) + { value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, dataElement->choice.visiblestring.size); } } - else if (dataElement->present == Data_PR_mMSString) { - - if ( dataElement->choice.mMSString.size >= 0) { + else if (dataElement->present == Data_PR_mMSString) + { + if ( dataElement->choice.mMSString.size >= 0) + { value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, dataElement->choice.mMSString.size); } } - else if (dataElement->present == Data_PR_bitstring) { - + else if (dataElement->present == Data_PR_bitstring) + { int size = dataElement->choice.bitstring.size; - if (size >= 0) { - + if (size >= 0) + { int maxSize = (size * 8); int bitSize = maxSize - dataElement->choice.bitstring.bits_unused; - if ((bitSize > 0) && (maxSize >= bitSize)) { + if ((bitSize > 0) && (maxSize >= bitSize)) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { - + if (value) + { value->type = MMS_BIT_STRING; value->value.bitString.size = bitSize; value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); - if (value->value.bitString.buf) { + if (value->value.bitString.buf) + { memcpy(value->value.bitString.buf, dataElement->choice.bitstring.buf, size); } - else { + else + { GLOBAL_FREEMEM(value); value = 0; } } } - else if (bitSize == 0) { + else if (bitSize == 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_BIT_STRING; value->value.bitString.size = 0; value->value.bitString.buf = NULL; } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing data element (bit string padding problem)!\n"); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing data element (bit string size 0 or negative)!\n"); } } - else if (dataElement->present == Data_PR_floatingpoint) { - + else if (dataElement->present == Data_PR_floatingpoint) + { int size = dataElement->choice.floatingpoint.size; - if (size == 5) { /* FLOAT32 */ - + if (size == 5) /* FLOAT32 */ + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_FLOAT; value->value.floatingPoint.formatWidth = 32; @@ -364,11 +388,12 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } - if (size == 9) { /* FLOAT64 */ - + if (size == 9) /* FLOAT64 */ + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_FLOAT; value->value.floatingPoint.formatWidth = 64; @@ -384,29 +409,34 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } } - else if (dataElement->present == Data_PR_utctime) { - + else if (dataElement->present == Data_PR_utctime) + { int size = dataElement->choice.utctime.size; - if (size == 8) { + if (size == 8) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_UTC_TIME; memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size); } } - else if (dataElement->present == Data_PR_octetstring) { - - if (dataElement->choice.octetstring.size >= 0) { + else if (dataElement->present == Data_PR_octetstring) + { + if (dataElement->choice.octetstring.size >= 0) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_OCTET_STRING; int size = dataElement->choice.octetstring.size; @@ -419,44 +449,51 @@ mmsMsg_parseDataElement(Data_t* dataElement) value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(abs(value->value.octetString.maxSize)); - if (value->value.octetString.buf) { + if (value->value.octetString.buf) + { memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); } - else { + else + { GLOBAL_FREEMEM(value); value = NULL; } } } - } - else if (dataElement->present == Data_PR_binarytime) { + else if (dataElement->present == Data_PR_binarytime) + { int size = dataElement->choice.binarytime.size; - if ((size == 4) || (size == 6)) { + if ((size == 4) || (size == 6)) + { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (value) { + if (value) + { value->type = MMS_BINARY_TIME; value->value.binaryTime.size = size; memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size); } } - else if (dataElement->present == Data_PR_boolean) { + else if (dataElement->present == Data_PR_boolean) + { value = MmsValue_newBoolean(dataElement->choice.boolean); } - else if (dataElement->present == Data_PR_booleanArray) { - + else if (dataElement->present == Data_PR_booleanArray) + { + /* not supported */ } - } - if (DEBUG_MMS_CLIENT) { + if (DEBUG_MMS_CLIENT) + { if (value == NULL) printf("MMS CLIENT: error parsing data element\n"); } @@ -472,16 +509,16 @@ mmsMsg_createStringFromAsnIdentifier(Identifier_t identifier) return str; } - void mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, int bufSize) { - if (identifier.size < bufSize) { + if (identifier.size < bufSize) + { memcpy(buffer, identifier.buf, identifier.size); buffer[identifier.size] = 0; } - else { - + else + { if (DEBUG_MMS_SERVER || DEBUG_MMS_CLIENT) printf("MMS_COMMON: mms_common_msg.c: ASN1 identifier to long!\n"); @@ -492,12 +529,12 @@ mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, i char* mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, char* componentNameBuf, int nameBufPos) { - if (alternateAccess->list.count == 1) { - - if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) { - - if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) { - + if (alternateAccess->list.count == 1) + { + if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) + { + if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) + { if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component) { @@ -507,26 +544,30 @@ mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, c AlternateAccess_t* nextAlternateAccess = alternateAccess->list.array[0]->choice.unnamed-> choice.selectAlternateAccess.alternateAccess; - if (nextAlternateAccess) { - if (nameBufPos + componentIdentifier.size + 1 < 65) { + if (nextAlternateAccess) + { + if (nameBufPos + componentIdentifier.size + 1 < 65) + { memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size); nameBufPos += componentIdentifier.size; componentNameBuf[nameBufPos++] = '$'; return mmsMsg_getComponentNameFromAlternateAccess(nextAlternateAccess, componentNameBuf, nameBufPos); } - else { + else + { if (DEBUG_MMS_SERVER) printf("MMS_SERVER: component identifier name too long!\n"); } } - else { + else + { if (DEBUG_MMS_SERVER) printf("MMS_SERVER: next alternate access specification is missing!\n"); } } } - else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) { - + else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) + { /* final component part */ if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == @@ -535,21 +576,21 @@ mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, c Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed-> choice.selectAccess.choice.component; - if (nameBufPos + componentIdentifier.size + 1 < 65) { + if (nameBufPos + componentIdentifier.size + 1 < 65) + { memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size); nameBufPos += componentIdentifier.size; componentNameBuf[nameBufPos++] = 0; return componentNameBuf; } - else { + else + { if (DEBUG_MMS_SERVER) printf("MMS_SERVER: component identifier name too long!\n"); } } } - } - } if (DEBUG_MMS_SERVER) @@ -610,23 +651,26 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos uint8_t tag = buffer[(*bufPos)++]; - if (tag != 0x19) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - return false; + if (tag != 0x19) + { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return false; } int length; *bufPos = BerDecoder_decodeLength(buffer, &length, *bufPos, maxBufPos); - if (*bufPos < 0) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - return false; + if (*bufPos < 0) + { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return false; } - if (length > 255) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); - return false; + if (length > 255) + { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return false; } memcpy(filename, buffer + *bufPos, length); @@ -637,7 +681,8 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos * TODO this may be platform dependent. Also depending of the platform there might be other evil * characters. */ - if (strstr(filename, "..") != NULL) { + if (strstr(filename, "..") != NULL) + { mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT); return false; } @@ -646,4 +691,3 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos } #endif /* (MMS_FILE_SERVICE == 1) */ - diff --git a/src/mms/iso_mms/server/mms_access_result.c b/src/mms/iso_mms/server/mms_access_result.c index 95dcef8a..188719e7 100644 --- a/src/mms/iso_mms/server/mms_access_result.c +++ b/src/mms/iso_mms/server/mms_access_result.c @@ -152,9 +152,14 @@ exit_with_error: return -1; } -MmsValue* -MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos) +static MmsValue* +MmsValue_decodeMmsDataRecursive(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos, int depth, int maxDepth) { + depth++; + + if (depth > maxDepth) + return NULL; + MmsValue* value = NULL; int dataEndBufPos = bufferLength; @@ -206,7 +211,7 @@ MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBu int elementBufLength = newBufPos - bufPos + elementLength; - MmsValue* elementValue = MmsValue_decodeMmsData(buffer, bufPos, bufPos + elementBufLength, NULL); + MmsValue* elementValue = MmsValue_decodeMmsDataRecursive(buffer, bufPos, bufPos + elementBufLength, NULL, depth, maxDepth); if (elementValue == NULL) goto exit_with_error; @@ -338,6 +343,18 @@ exit_with_error: return NULL; } +MmsValue* +MmsValue_decodeMmsDataMaxRecursion(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos, int maxDepth) +{ + return MmsValue_decodeMmsDataRecursive(buffer, bufPos, bufferLength, endBufPos, 0, maxDepth); +} + +MmsValue* +MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos) +{ + return MmsValue_decodeMmsDataMaxRecursion(buffer, bufPos, bufferLength, endBufPos, 25); +} + static int MmsValue_getMaxStructSize(MmsValue* self) { diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 2f6f2b27..1e860f3a 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -1,7 +1,7 @@ /* * mms_server.c * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -34,7 +34,8 @@ createValueCaches(MmsDevice* device) Map valueCaches = Map_create(); int i; - for (i = 0; i < device->domainCount; i++) { + for (i = 0; i < device->domainCount; i++) + { MmsValueCache valueCache = MmsValueCache_create(device->domains[i]); Map_addEntry(valueCaches, device->domains[i], valueCache); } @@ -52,7 +53,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration) { MmsServer self = (MmsServer) GLOBAL_CALLOC(1, sizeof(struct sMmsServer)); - if (self) { + if (self) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) self->openConnectionsLock = Semaphore_create(1); @@ -75,7 +77,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration) if (self->isoServerList == NULL) goto exit_error; - if (tlsConfiguration) { + if (tlsConfiguration) + { IsoServer isoServer = IsoServer_create(tlsConfiguration); if (isoServer == NULL) @@ -115,7 +118,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration) { int i; - for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) { + for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) + { self->fileUploadTasks[i].state = 0; #if (CONFIG_MMS_THREADLESS_STACK != 1) @@ -140,8 +144,8 @@ MmsServer_addAP(MmsServer self, const char* ipAddr, int tcpPort, TLSConfiguratio { IsoServer isoServer = IsoServer_create(tlsConfiguration); - if (isoServer) { - + if (isoServer) + { IsoServer_setLocalIpAddress(isoServer, ipAddr); if (tcpPort != -1) @@ -161,13 +165,15 @@ MmsServer_addAP(MmsServer self, const char* ipAddr, int tcpPort, TLSConfiguratio void MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress) { - if (LinkedList_size(self->isoServerList) == 0) { + if (LinkedList_size(self->isoServerList) == 0) + { MmsServer_addAP(self, NULL, -1, NULL); } LinkedList elem = LinkedList_get(self->isoServerList, 0); - if (elem) { + if (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_setLocalIpAddress(isoServer, localIpAddress); @@ -179,7 +185,8 @@ MmsServer_isRunning(MmsServer self) { LinkedList elem = LinkedList_get(self->isoServerList, 0); - if (elem) { + if (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); if (IsoServer_getState(isoServer) == ISO_SVR_STATE_RUNNING) @@ -193,12 +200,13 @@ void MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) - if (self->filestoreBasepath != NULL) { + if (self->filestoreBasepath) + { GLOBAL_FREEMEM(self->filestoreBasepath); self->filestoreBasepath = NULL; } - if (basepath != NULL) + if (basepath) self->filestoreBasepath = StringUtils_copyString(basepath); #endif /* (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) */ } @@ -208,15 +216,17 @@ MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath) void MmsServer_setMaxConnections(MmsServer self, int maxConnections) { - if (self->isoServerList) { - - if (LinkedList_size(self->isoServerList) == 0) { + if (self->isoServerList) + { + if (LinkedList_size(self->isoServerList) == 0) + { MmsServer_addAP(self, NULL, -1, NULL); } LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_setMaxConnections(isoServer, maxConnections); @@ -307,13 +317,14 @@ MmsServer_getObtainFileTask(MmsServer self) { int i; - for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) { - + for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->fileUploadTasks[i].taskLock); #endif - if (self->fileUploadTasks[i].state == 0) { + if (self->fileUploadTasks[i].state == 0) + { self->fileUploadTasks[i].state = 1; return &(self->fileUploadTasks[i]); @@ -322,7 +333,6 @@ MmsServer_getObtainFileTask(MmsServer self) #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->fileUploadTasks[i].taskLock); #endif - } return NULL; @@ -392,11 +402,12 @@ MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator self->authenticator = authenticator; self->authenticatorParameter = authenticatorParameter; - if (self->isoServerList) { - + if (self->isoServerList) + { LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_setAuthenticator(isoServer, authenticator, authenticatorParameter); @@ -448,7 +459,8 @@ deleteSingleCache(MmsValueCache cache) void MmsServer_destroy(MmsServer self) { - if (self) { + if (self) + { LinkedList_destroyDeep(self->isoServerList, (LinkedListValueDeleteFunction) IsoServer_destroy); Map_deleteDeep(self->openConnections, false, closeConnection); @@ -476,7 +488,8 @@ MmsServer_destroy(MmsServer self) #if (MMS_OBTAIN_FILE_SERVICE == 1) #if (CONFIG_MMS_THREADLESS_STACK != 1) int i; - for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) { + for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) + { if (self->fileUploadTasks[i].taskLock) Semaphore_destroy(self->fileUploadTasks[i].taskLock); } @@ -492,10 +505,10 @@ MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, const char* itemI { MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); - if (cache != NULL) + if (cache) return MmsValueCache_lookupValue(cache, itemId, NULL); - return NULL ; + return NULL; } MmsValue* @@ -503,10 +516,10 @@ MmsServer_getValueFromCacheEx(MmsServer self, MmsDomain* domain, const char* ite { MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); - if (cache != NULL) + if (cache) return MmsValueCache_lookupValue(cache, itemId, typeSpec); - return NULL ; + return NULL; } MmsValue* @@ -514,10 +527,10 @@ MmsServer_getValueFromCacheEx2(MmsServer self, MmsDomain* domain, const char* it { MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); - if (cache != NULL) + if (cache) return MmsValueCache_lookupValueEx(cache, itemId, idx, componentId, NULL); - return NULL ; + return NULL; } void @@ -525,9 +538,8 @@ MmsServer_insertIntoCache(MmsServer self, MmsDomain* domain, char* itemId, MmsVa { MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); - if (cache != NULL) { + if (cache) MmsValueCache_insertValue(cache, itemId, value); - } } MmsDataAccessError @@ -541,7 +553,8 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va indication = self->writeHandler(self->writeHandlerParameter, domain, itemId, -1, NULL, value, connection); } - else { + else + { MmsValue* cachedValue; if (domain == NULL) @@ -549,10 +562,12 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va cachedValue = MmsServer_getValueFromCache(self, domain, itemId); - if (cachedValue) { + if (cachedValue) + { MmsValue_update(cachedValue, value); indication = DATA_ACCESS_ERROR_SUCCESS; - } else + } + else indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } @@ -570,7 +585,8 @@ mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* indication = self->writeHandler(self->writeHandlerParameter, domain, itemId, arrayIdx, componentId, value, connection); } - else { + else + { MmsValue* cachedValue = NULL; if (domain == NULL) @@ -578,10 +594,12 @@ mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* cachedValue = MmsServer_getValueFromCacheEx2(self, domain, itemId, arrayIdx, componentId); - if (cachedValue) { + if (cachedValue) + { MmsValue_update(cachedValue, value); indication = DATA_ACCESS_ERROR_SUCCESS; - } else + } + else indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } @@ -593,12 +611,14 @@ mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerCon { MmsValue* value = NULL; - if (self->readAccessHandler != NULL) { + if (self->readAccessHandler != NULL) + { MmsDataAccessError accessError = self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain, itemId, connection, isDirectAccess); - if (accessError != DATA_ACCESS_ERROR_SUCCESS) { + if (accessError != DATA_ACCESS_ERROR_SUCCESS) + { value = MmsValue_newDataAccessError(accessError); MmsValue_setDeletable(value); goto exit_function; @@ -616,26 +636,13 @@ exit_function: return value; } -MmsDataAccessError -mmsServer_checkReadAccess(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess) -{ - MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS; - - if (self->readAccessHandler) { - accessError = - self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain, - itemId, connection, isDirectAccess); - } - - return accessError; -} - bool mmsServer_checkListAccess(MmsServer self, MmsGetNameListType listType, MmsDomain* domain, char* itemId, MmsServerConnection connection) { bool allowAccess = true; - if (self->listAccessHandler) { + if (self->listAccessHandler) + { allowAccess = self->listAccessHandler(self->listAccessHandlerParameter, listType, domain, itemId, connection); } @@ -654,7 +661,8 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication, { MmsServer self = (MmsServer) parameter; - if (indication == ISO_CONNECTION_OPENED) { + if (indication == ISO_CONNECTION_OPENED) + { MmsServerConnection mmsCon = MmsServerConnection_init(0, self, connection); #if (CONFIG_MMS_THREADLESS_STACK != 1) @@ -671,8 +679,8 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication, self->connectionHandler(self->connectionHandlerParameter, mmsCon, MMS_SERVER_NEW_CONNECTION); } - else if (indication == ISO_CONNECTION_CLOSED) { - + else if (indication == ISO_CONNECTION_CLOSED) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->openConnectionsLock); #endif @@ -697,15 +705,17 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication, void MmsServer_startListening(MmsServer self, int tcpPort) { - if (self->isoServerList) { - - if (LinkedList_size(self->isoServerList) == 0) { + if (self->isoServerList) + { + if (LinkedList_size(self->isoServerList) == 0) + { MmsServer_addAP(self, NULL, -1, NULL); } LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_setConnectionHandler(isoServer, isoConnectionIndicationHandler, (void*) self); @@ -723,10 +733,12 @@ MmsServer_startListening(MmsServer self, int tcpPort) void MmsServer_stopListening(MmsServer self) { - if (self->isoServerList) { + if (self->isoServerList) + { LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_stopListening(isoServer); @@ -740,15 +752,17 @@ MmsServer_stopListening(MmsServer self) void MmsServer_startListeningThreadless(MmsServer self, int tcpPort) { - if (self->isoServerList) { - - if (LinkedList_size(self->isoServerList) == 0) { + if (self->isoServerList) + { + if (LinkedList_size(self->isoServerList) == 0) + { MmsServer_addAP(self, NULL, -1, NULL); } LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_setConnectionHandler(isoServer, isoConnectionIndicationHandler, (void*) self); @@ -768,21 +782,25 @@ MmsServer_waitReady(MmsServer self, unsigned int timeoutMs) { int result = 0; - if (self->isoServerList) { + if (self->isoServerList) + { bool isFirst = true; LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); int serverResult; - if (isFirst) { + if (isFirst) + { serverResult = IsoServer_waitReady(isoServer, timeoutMs); isFirst = false; } - else { + else + { serverResult = IsoServer_waitReady(isoServer, 0); } @@ -799,10 +817,12 @@ MmsServer_waitReady(MmsServer self, unsigned int timeoutMs) void MmsServer_handleIncomingMessages(MmsServer self) { - if (self->isoServerList) { + if (self->isoServerList) + { LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_processIncomingMessages(isoServer); @@ -844,10 +864,12 @@ MmsServer_getConnectionCounter(MmsServer self) { int count = 0; - if (self->isoServerList) { + if (self->isoServerList) + { LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); count += IsoServer_getConnectionCounter(isoServer); @@ -862,7 +884,8 @@ MmsServer_getConnectionCounter(MmsServer self) void MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection) { - if (self->connectionHandler) { + if (self->connectionHandler) + { self->connectionHandler(self->connectionHandlerParameter, connection, MMS_SERVER_CONNECTION_TICK); } } @@ -870,10 +893,12 @@ MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection) void MmsServer_stopListeningThreadless(MmsServer self) { - if (self->isoServerList) { + if (self->isoServerList) + { LinkedList elem = LinkedList_getNext(self->isoServerList); - while (elem) { + while (elem) + { IsoServer isoServer = (IsoServer) LinkedList_getData(elem); IsoServer_stopListeningThreadless(isoServer); diff --git a/src/r_session/r_session.h b/src/r_session/r_session.h index 662e8846..f856df81 100644 --- a/src/r_session/r_session.h +++ b/src/r_session/r_session.h @@ -81,7 +81,7 @@ struct sRSessionPayloadElement * \return new RSession instance */ LIB61850_API RSession -RSession_create(); +RSession_create(void); /** * \brief Set the maximum buffer size for session messages (range: 128 - 65535) diff --git a/src/r_session/r_session_crypto_mbedtls.c b/src/r_session/r_session_crypto_mbedtls.c index eb3aa23d..db592b42 100644 --- a/src/r_session/r_session_crypto_mbedtls.c +++ b/src/r_session/r_session_crypto_mbedtls.c @@ -3,7 +3,7 @@ * * Implementation of RSessionCrypto interface using mbedtls * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -25,7 +25,6 @@ #include "mbedtls/cipher.h" #include "mbedtls/md.h" -#include "mbedtls/md_internal.h" #include "mbedtls/platform_util.h" #include "mbedtls/gcm.h" #include "mbedtls/entropy.h" @@ -42,7 +41,7 @@ bool RSessionCrypto_createHMAC(uint8_t* buffer, int bufSize, uint8_t* key, int keySize, uint8_t* hmac, int hmacMaxSize) { - const mbedtls_md_info_t* md_info = &mbedtls_sha256_info; + const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); mbedtls_md_context_t md_ctx; diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index f69b90cd..90179cf6 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -1,7 +1,7 @@ /* * sv_publisher.c * - * Copyright 2016-2022 Michael Zillgith + * Copyright 2016-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -76,8 +76,10 @@ struct sSVPublisher { uint16_t appId; bool simulation; +#if (CONFIG_IEC61850_L2_SMV == 1) /* only for Ethernet based SV */ EthernetSocket ethernetSocket; +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ #if (CONFIG_IEC61850_R_SMV == 1) /* only for R-SV */ @@ -93,7 +95,7 @@ struct sSVPublisher { SVPublisher_ASDU asduList; }; - +#if (CONFIG_IEC61850_L2_SMV == 1) static bool preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* interfaceId, bool useVlanTags) { @@ -194,7 +196,7 @@ preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* in return true; } - +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ static int encodeUInt16FixedSize(uint16_t value, uint8_t* buffer, int bufPos) @@ -303,6 +305,7 @@ SVPublisher_createRemote(RSession session, uint16_t appId) } #endif /* (CONFIG_IEC61850_R_SMV == 1) */ +#if (CONFIG_IEC61850_L2_SMV == 1) SVPublisher SVPublisher_createEx(CommParameters* parameters, const char* interfaceId, bool useVlanTag) { @@ -329,6 +332,7 @@ SVPublisher_create(CommParameters* parameters, const char* interfaceId) { return SVPublisher_createEx(parameters, interfaceId, true); } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ SVPublisher_ASDU SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev) @@ -527,21 +531,25 @@ SVPublisher_setupComplete(SVPublisher self) void SVPublisher_publish(SVPublisher self) { - if (DEBUG_SV_PUBLISHER) - printf("SV_PUBLISHER: send SV message\n"); +#if (CONFIG_IEC61850_L2_SMV == 1) + if (self->ethernetSocket) + { + if (DEBUG_SV_PUBLISHER) + printf("SV_PUBLISHER: send L2 SV message\n"); - if (self->ethernetSocket) { Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + self->payloadLength); } +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ + #if (CONFIG_IEC61850_R_SMV == 1) - else if (self->remoteSession) { + if (self->remoteSession) + { + if (DEBUG_SV_PUBLISHER) + printf("SV_PUBLISHER: send R-SV message\n"); + RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_SV, self->simulation, self->appId, self->buffer, self->payloadLength); } #endif /* (CONFIG_IEC61850_R_SMV == 1) */ - else { - if (DEBUG_SV_PUBLISHER) - printf("SV_PUBLISHER: no network layer!\n"); - } } void @@ -549,8 +557,10 @@ SVPublisher_destroy(SVPublisher self) { if (self) { +#if (CONFIG_IEC61850_L2_SMV == 1) if (self->ethernetSocket) Ethernet_destroySocket(self->ethernetSocket); +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ if (self->buffer) GLOBAL_FREEMEM(self->buffer); @@ -808,139 +818,3 @@ SVPublisher_ASDU_setSmpSynch(SVPublisher_ASDU self, uint16_t smpSynch) self->smpSynch = smpSynch; *(self->smpSynchBuf) = self->smpSynch; } - -/******************************************************************* - * Wrapper functions to support old API (remove in future versions) - *******************************************************************/ - -SVPublisher -SampledValuesPublisher_create(CommParameters* parameters, const char* interfaceId) -{ - return SVPublisher_create(parameters, interfaceId); -} - -SVPublisher_ASDU -SampledValuesPublisher_addASDU(SVPublisher self, char* svID, char* datset, uint32_t confRev) -{ - return SVPublisher_addASDU(self, svID, datset, confRev); -} - -void -SampledValuesPublisher_setupComplete(SVPublisher self) -{ - SVPublisher_setupComplete(self); -} - -void -SampledValuesPublisher_publish(SVPublisher self) -{ - SVPublisher_publish(self); -} - -void -SampledValuesPublisher_destroy(SVPublisher self) -{ - SVPublisher_destroy(self); -} - -void -SV_ASDU_resetBuffer(SVPublisher_ASDU self) -{ - SVPublisher_ASDU_resetBuffer(self); -} - -int -SV_ASDU_addINT8(SVPublisher_ASDU self) -{ - return SVPublisher_ASDU_addINT8(self); -} - -void -SV_ASDU_setINT8(SVPublisher_ASDU self, int index, int8_t value) -{ - SVPublisher_ASDU_setINT8(self, index, value); -} - -int -SV_ASDU_addINT32(SVPublisher_ASDU self) -{ - return SVPublisher_ASDU_addINT32(self); -} - -void -SV_ASDU_setINT32(SVPublisher_ASDU self, int index, int32_t value) -{ - SVPublisher_ASDU_setINT32(self, index, value); -} - -int -SV_ASDU_addINT64(SVPublisher_ASDU self) -{ - return SVPublisher_ASDU_addINT64(self); -} - -void -SV_ASDU_setINT64(SVPublisher_ASDU self, int index, int64_t value) -{ - SVPublisher_ASDU_setINT64(self, index, value); -} - -int -SV_ASDU_addFLOAT(SVPublisher_ASDU self) -{ - return SVPublisher_ASDU_addFLOAT(self); -} - -void -SV_ASDU_setFLOAT(SVPublisher_ASDU self, int index, float value) -{ - SVPublisher_ASDU_setFLOAT(self, index, value); -} - -int -SV_ASDU_addFLOAT64(SVPublisher_ASDU self) -{ - return SVPublisher_ASDU_addFLOAT64(self); -} - -void -SV_ASDU_setFLOAT64(SVPublisher_ASDU self, int index, double value) -{ - SVPublisher_ASDU_setFLOAT64(self, index, value); -} - -void -SV_ASDU_setSmpCnt(SVPublisher_ASDU self, uint16_t value) -{ - SVPublisher_ASDU_setSmpCnt(self, value); -} - -uint16_t -SV_ASDU_getSmpCnt(SVPublisher_ASDU self) -{ - return SVPublisher_ASDU_getSmpCnt(self); -} - -void -SV_ASDU_increaseSmpCnt(SVPublisher_ASDU self) -{ - SVPublisher_ASDU_increaseSmpCnt(self); -} - -void -SV_ASDU_setRefrTm(SVPublisher_ASDU self, uint64_t refrTm) -{ - SVPublisher_ASDU_setRefrTm(self, refrTm); -} - -void -SV_ASDU_setSmpMod(SVPublisher_ASDU self, uint8_t smpMod) -{ - SVPublisher_ASDU_setSmpMod(self, smpMod); -} - -void -SV_ASDU_setSmpRate(SVPublisher_ASDU self, uint16_t smpRate) -{ - SVPublisher_ASDU_setSmpRate(self, smpRate); -} diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index 48d8bfc8..221eb1a8 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -1,7 +1,7 @@ /* * sv_receiver.c * - * Copyright 2015-2022 Michael Zillgith + * Copyright 2015-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -67,7 +67,6 @@ struct sSVReceiver Semaphore subscriberListLock; Thread thread; #endif - }; struct sSVSubscriber @@ -101,7 +100,8 @@ SVReceiver_create(void) { SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver)); - if (self != NULL) { + if (self) + { self->subscriberList = LinkedList_create(); self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH); @@ -122,7 +122,8 @@ SVReceiver_createRemote(RSession session) { SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver)); - if (self != NULL) { + if (self != NULL) + { self->subscriberList = LinkedList_create(); self->buffer = NULL; @@ -193,6 +194,7 @@ svReceiverLoop(void* threadParameter) { SVReceiver self = (SVReceiver) threadParameter; +#if (CONFIG_IEC61850_L2_SMV == 1) if (self->ethSocket) { EthernetHandleSet handleSet = EthernetHandleSet_new(); @@ -217,8 +219,10 @@ svReceiverLoop(void* threadParameter) EthernetHandleSet_destroy(handleSet); } +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ + #if (CONFIG_IEC61850_R_SMV == 1) - else if (self->session) + if (self->session) { self->stopped = false; @@ -349,14 +353,12 @@ SVReceiver_startThreadless(SVReceiver self) return true; } - else - { - return false; - } } else { #endif /* (CONFIG_IEC61850_R_SMV == 1) */ + +#if (CONFIG_IEC61850_L2_SMV == 1) if (self->interfaceId == NULL) self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); else @@ -367,22 +369,25 @@ SVReceiver_startThreadless(SVReceiver self) Ethernet_setProtocolFilter(self->ethSocket, ETH_P_SV); self->running = true; - } - if (self->ethSocket) return true; - else - return false; + } +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ + #if (CONFIG_IEC61850_R_SMV == 1) } #endif /* (CONFIG_IEC61850_R_SMV == 1) */ + + return false; } void SVReceiver_stopThreadless(SVReceiver self) { +#if (CONFIG_IEC61850_L2_SMV == 1) if (self->ethSocket) Ethernet_destroySocket(self->ethSocket); +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ #if (CONFIG_IEC61850_R_SMV == 1) if (self->session) { @@ -611,35 +616,37 @@ handleSVApdu(SVReceiver self, uint16_t appId, uint8_t* apdu, int apduLength, uin bool subscriberFound = false; - while (element != NULL) { + while (element) + { subscriber = (SVSubscriber) LinkedList_getData(element); - if (subscriber->appId == appId) { - - - if (self->checkDestAddr) { - - if (self->ethSocket) { - if (memcmp(dstAddr, subscriber->ethAddr, 6) == 0) { + if (subscriber->appId == appId) + { + if (self->checkDestAddr) + { + if (self->ethSocket) + { + if (memcmp(dstAddr, subscriber->ethAddr, 6) == 0) + { subscriberFound = true; break; } else + { if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Checking ethernet dest address failed!\n"); + } } - else { + else + { //TODO check destination IP address for R-SV - } - } - else { + else + { subscriberFound = true; break; } - - } element = LinkedList_getNext(element); @@ -650,8 +657,11 @@ handleSVApdu(SVReceiver self, uint16_t appId, uint8_t* apdu, int apduLength, uin #endif if (subscriberFound) + { parseSVPayload(self, subscriber, apdu, apduLength); - else { + } + else + { if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: SV message ignored due to unknown APPID value or dest address mismatch\n"); } @@ -710,17 +720,21 @@ parseSVMessage(SVReceiver self, int numbytes) handleSVApdu(self, appId, buffer + bufPos, apduLength, dstAddr); } +#if (CONFIG_IEC61850_R_SMV == 1) static void handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadData, int payloadSize) { + (void)appId; SVReceiver self = (SVReceiver) parameter; handleSVApdu(self, appId, payloadData, payloadSize, NULL); } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ bool SVReceiver_tick(SVReceiver self) { +#if (CONFIG_IEC61850_L2_SMV == 1) if (self->ethSocket) { int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); @@ -731,8 +745,10 @@ SVReceiver_tick(SVReceiver self) return true; } } +#endif /* (CONFIG_IEC61850_L2_SMV == 1) */ + #if (CONFIG_IEC61850_R_SMV == 1) - else if (self->session) + if (self->session) { if (RSession_receiveMessage(self->session, handleSessionPayloadElement, (void*) self) == R_SESSION_ERROR_OK) return true; @@ -747,7 +763,7 @@ SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID) { SVSubscriber self = (SVSubscriber) GLOBAL_CALLOC(1, sizeof(struct sSVSubscriber)); - if (self != NULL) + if (self) { self->appId = appID; @@ -761,7 +777,7 @@ SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID) void SVSubscriber_destroy(SVSubscriber self) { - if (self != NULL) + if (self) GLOBAL_FREEMEM(self); } @@ -816,7 +832,7 @@ decodeUtcTimeToNsTime(uint8_t* buffer, uint8_t* timeQuality) nsVal = nsVal * 1000000000UL; nsVal = nsVal >> 24; - if (timeQuality != NULL) + if (timeQuality) *timeQuality = buffer[7]; uint64_t timeval64 = (uint64_t) timeval32 * 1000000000ULL + nsVal; @@ -829,7 +845,7 @@ SVSubscriber_ASDU_getRefrTmAsMs(SVSubscriber_ASDU self) { msSinceEpoch msTime = 0; - if (self->refrTm != NULL) + if (self->refrTm) msTime = decodeUtcTimeToNsTime(self->refrTm, NULL); return (msTime / 1000000ULL); @@ -840,7 +856,7 @@ SVSubscriber_ASDU_getRefrTmAsNs(SVSubscriber_ASDU self) { nsSinceEpoch nsTime = 0; - if (self->refrTm != NULL) + if (self->refrTm) nsTime = decodeUtcTimeToNsTime(self->refrTm, NULL); return nsTime; @@ -1083,99 +1099,3 @@ SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self) { return self->dataBufferLength; } - -uint16_t -SVClientASDU_getSmpCnt(SVSubscriber_ASDU self) -{ - return SVSubscriber_ASDU_getSmpCnt(self); -} - -const char* -SVClientASDU_getSvId(SVSubscriber_ASDU self) -{ - return SVSubscriber_ASDU_getSvId(self); -} - -uint32_t -SVClientASDU_getConfRev(SVSubscriber_ASDU self) -{ - return SVSubscriber_ASDU_getConfRev(self); -} - -bool -SVClientASDU_hasRefrTm(SVSubscriber_ASDU self) -{ - return SVSubscriber_ASDU_hasRefrTm(self); -} - -uint64_t -SVClientASDU_getRefrTmAsMs(SVSubscriber_ASDU self) -{ - return SVSubscriber_ASDU_getRefrTmAsMs(self); -} - -int8_t -SVClientASDU_getINT8(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT8(self, index); -} - -int16_t -SVClientASDU_getINT16(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT16(self, index); -} - -int32_t -SVClientASDU_getINT32(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT32(self, index); -} - -int64_t -SVClientASDU_getINT64(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT64(self, index); -} - -uint8_t -SVClientASDU_getINT8U(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT8U(self, index); -} - -uint16_t -SVClientASDU_getINT16U(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT16U(self, index); -} - -uint32_t -SVClientASDU_getINT32U(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT32U(self, index); -} - -uint64_t -SVClientASDU_getINT64U(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getINT64U(self, index); -} - -float -SVClientASDU_getFLOAT32(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getFLOAT32(self, index); -} - -double -SVClientASDU_getFLOAT64(SVSubscriber_ASDU self, int index) -{ - return SVSubscriber_ASDU_getFLOAT64(self, index); -} - -int -SVClientASDU_getDataSize(SVSubscriber_ASDU self) -{ - return SVSubscriber_ASDU_getDataSize(self); -} diff --git a/src/sampled_values/sv_subscriber.h b/src/sampled_values/sv_subscriber.h index 0ec4d5ef..c33228a8 100644 --- a/src/sampled_values/sv_subscriber.h +++ b/src/sampled_values/sv_subscriber.h @@ -560,72 +560,7 @@ SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self); uint8_t SVSubscriber_ASDU_getSmpSynch(SVSubscriber_ASDU self); -#ifndef DEPRECATED -#if defined(__GNUC__) || defined(__clang__) - #define DEPRECATED __attribute__((deprecated)) -#else - #define DEPRECATED -#endif -#endif - -/** - * \addtogroup sv_subscriber_deprecated_api_group Deprecated API - * \ingroup sv_subscriber_api_group IEC 61850 Sampled Values (SV) publisher API - * \deprecated - * @{ - */ - -typedef struct sSVSubscriberASDU* SVClientASDU; - -LIB61850_API DEPRECATED uint16_t -SVClientASDU_getSmpCnt(SVSubscriber_ASDU self); - -LIB61850_API DEPRECATED const char* -SVClientASDU_getSvId(SVSubscriber_ASDU self); - -LIB61850_API DEPRECATED uint32_t -SVClientASDU_getConfRev(SVSubscriber_ASDU self); - -LIB61850_API DEPRECATED bool -SVClientASDU_hasRefrTm(SVSubscriber_ASDU self); - -LIB61850_API DEPRECATED uint64_t -SVClientASDU_getRefrTmAsMs(SVSubscriber_ASDU self); - -LIB61850_API DEPRECATED int8_t -SVClientASDU_getINT8(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED int16_t -SVClientASDU_getINT16(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED int32_t -SVClientASDU_getINT32(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED int64_t -SVClientASDU_getINT64(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED uint8_t -SVClientASDU_getINT8U(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED uint16_t -SVClientASDU_getINT16U(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED uint32_t -SVClientASDU_getINT32U(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED uint64_t -SVClientASDU_getINT64U(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED float -SVClientASDU_getFLOAT32(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED double -SVClientASDU_getFLOAT64(SVSubscriber_ASDU self, int index); - -LIB61850_API DEPRECATED int -SVClientASDU_getDataSize(SVSubscriber_ASDU self); - -/**@} @}*/ +/** @}*/ #ifdef __cplusplus } diff --git a/src/sntp/sntp_client.c b/src/sntp/sntp_client.c index 27e9d09c..1935b7e9 100644 --- a/src/sntp/sntp_client.c +++ b/src/sntp/sntp_client.c @@ -37,8 +37,8 @@ typedef struct sSNTPClient* SNTPClient; /* new time types */ - -typedef struct { +typedef struct +{ uint32_t coarse; uint32_t fine; } NtpTime; @@ -164,7 +164,8 @@ parseResponseMessage(SNTPClient self, uint8_t* buffer, int bufSize) int li = (header & 0xc0)>> 6; /* check for "clock-not-synchronized" */ - if (li == 3) { + if (li == 3) + { /* ignore time message */ if (SNTP_DEBUG) printf("WARNING: received clock-not-synchronized from server\n"); @@ -223,7 +224,8 @@ parseResponseMessage(SNTPClient self, uint8_t* buffer, int bufSize) uint64_t trnsTime = ntpTimeToNsTime(coarse, fine); /* set system time */ - if (Hal_setTimeInNs(trnsTime) == false) { + if (Hal_setTimeInNs(trnsTime) == false) + { if (SNTP_DEBUG) printf("SNTP: failed to set system clock!\n"); } @@ -231,11 +233,13 @@ parseResponseMessage(SNTPClient self, uint8_t* buffer, int bufSize) self->clockSynced = true; self->outStandingRequest = false; - if (self->userCallback) { + if (self->userCallback) + { self->userCallback(self->userCallbackParameter, true); } - if (SNTP_DEBUG) { + if (SNTP_DEBUG) + { printf("SNTP: reference time: %u.%.6u\n", nsTimeToSeconds(refTime), getUsPartFromNsTime(refTime)); printf("SNTP: original time: %u.%.9u\n", nsTimeToSeconds(origTime), getUsPartFromNsTime(origTime)); printf("SNTP: receive time: %u.%.6u\n", nsTimeToSeconds(recvTime), getUsPartFromNsTime(recvTime)); @@ -310,14 +314,17 @@ SNTPClient_create() { SNTPClient self = (SNTPClient) GLOBAL_CALLOC(1, sizeof(struct sSNTPClient)); - if (self) { + if (self) + { self->socket = UdpSocket_create(); - if (self->socket == NULL) { + if (self->socket == NULL) + { GLOBAL_FREEMEM(self); self = NULL; } - else { + else + { self->handleSet = Handleset_new(); Handleset_addSocket(self->handleSet, (Socket) self->socket); self->pollInterval = 30000000000UL; /* 30 s */ @@ -351,7 +358,8 @@ SNTPClient_isSynchronized(SNTPClient self) void SNTPClient_setUserCallback(SNTPClient self, SNTPClient_UserCallback callback, void* parameter) { - if (self) { + if (self) + { self->userCallback = callback; self->userCallbackParameter = parameter; } @@ -375,23 +383,28 @@ SNTPClient_tick(SNTPClient self) if (self->lastRequestTimestamp > now) self->lastRequestTimestamp = now; - if (self->lastRequestTimestamp > 0) { + if (self->lastRequestTimestamp > 0) + { /* check for timeout */ - if ((now - self->lastReceivedMessage) > 300000000000UL) { - - if (self->clockSynced) { + if ((now - self->lastReceivedMessage) > 300000000000UL) + { + if (self->clockSynced) + { self->clockSynced = false; printf("SNTP: request timeout\n"); - //TODO when to call user handler? - if (self->userCallback) { + + if (self->userCallback) + { self->userCallback(self->userCallbackParameter, false); } } } } - if (self->serverAddr) { - if ((now - self->lastRequestTimestamp) > self->pollInterval) { + if (self->serverAddr) + { + if ((now - self->lastRequestTimestamp) > self->pollInterval) + { sendRequestMessage(self, self->serverAddr, self->serverPort); } } @@ -405,17 +418,19 @@ SNTPClient_handleIncomingMessage(SNTPClient self) uint8_t buffer[200]; int rcvdBytes = UdpSocket_receiveFrom(self->socket, ipAddress, 200, buffer, sizeof(buffer)); - if (rcvdBytes > 0) { - + if (rcvdBytes > 0) + { if (SNTP_DEBUG) printf("SNTP: received response from %s\n", ipAddress); parseResponseMessage(self, buffer, rcvdBytes); } - else if (rcvdBytes == -1) { + else if (rcvdBytes == -1) + { printf("UDP socket error\n"); } - else { + else + { printf("No data!\n"); } } @@ -442,10 +457,12 @@ handleThread(void* parameter) void SNTPClient_start(SNTPClient self) { - if (self) { + if (self) + { int sntpPoirt = SNTP_DEFAULT_PORT; - if (UdpSocket_bind(self->socket, "0.0.0.0", SNTP_DEFAULT_PORT)) { + if (UdpSocket_bind(self->socket, "0.0.0.0", SNTP_DEFAULT_PORT)) + { printf("Start NTP thread\n"); self->thread = Thread_create(handleThread, self, false); @@ -453,7 +470,8 @@ SNTPClient_start(SNTPClient self) if (self->thread) Thread_start(self->thread); } - else { + else + { if (SNTP_DEBUG) printf("SNTP: Failed to bind to port %i\n", sntpPoirt); } @@ -463,7 +481,8 @@ SNTPClient_start(SNTPClient self) void SNTPClient_stop(SNTPClient self) { - if (self->thread) { + if (self->thread) + { self->running = false; Thread_destroy(self->thread); self->thread = NULL; @@ -473,16 +492,15 @@ SNTPClient_stop(SNTPClient self) void SNTPClient_destroy(SNTPClient self) { - if (self) { - + if (self) + { SNTPClient_stop(self); if (self->serverAddr) GLOBAL_FREEMEM(self->serverAddr); - if (self->socket) { + if (self->socket) Socket_destroy((Socket) self->socket); - } GLOBAL_FREEMEM(self); } diff --git a/third_party/mbedtls/README b/third_party/mbedtls/README index b6171f07..7d886014 100644 --- a/third_party/mbedtls/README +++ b/third_party/mbedtls/README @@ -1,9 +1,33 @@ README ------ -For TLS support with mbedtls download the source tarball of version 2.28.x and extract here in the subfolder +At the moment libiec61850 provides support for two versions of mbedtls (2.28 and 3.6). + +mbedtls version 2.28 support different TLS versions up to TLS 1.2. + +mbedtls version 3.6 only support TLS 1.2 and TLS 1.3. Older versions are not supported. + +It is recommended that you use version 3.6 unless you need support for older versions of TLS. mbedtls-2.28 +------------ + +Download the latest source tarball from version 2.27.x and extract it here in the subfolder mbedtls-2.28 After extracting of the archive you may have to rename the folder to match the exact name "mbedtls-2.28". Otherwise the build system will not find the library. + wget https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/v2.28.8.tar.gz + + tar xzf v2.28.8.tar.gz + + mv mbedtls-2.28.8 mbedtls-2.28 + +mbedtls-3.6.0 +------------- + +You just have to download the archive and extract it in this folder. + + wget https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/v3.6.0.tar.gz + + tar xzf v3.6.0.tar.gz +