From 23c30f39bb54a52670e2f5f5e6e1c259cefdb62a Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Fri, 8 Nov 2024 11:35:55 -0500 Subject: [PATCH] Fix handling of empty SCS17/SCS18 messages Add a flag to allow for non-compliant messages for SCS17/SCS18 messages. Some OSDP implementations will send an SCS17/SCS18 message with no data when in secure mode. This is not correct according to the standard. If this message is received with libosdp, the current behavior is to drop the message and print an error. This patch adds a new flag, FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK to allow for non-standard behavior of an empty data block with SCS17/SCS18. This is only when libosdp is used as a PD. --- README.md | 3 +-- include/osdp.h | 11 +++++++++++ python/osdp/constants.py | 1 + python/osdp_sys/module.c | 1 + src/osdp_common.h | 12 ++++++++++++ src/osdp_phy.c | 2 +- src/osdp_sc.c | 4 ++++ 7 files changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ed867b0d..b6c3be50 100644 --- a/README.md +++ b/README.md @@ -162,8 +162,7 @@ is how you can run them: ```sh mkdir build && cd build cmake .. -make python_install -make check +make check-ut ``` To add new tests for the feature you are working one, see the other tests in diff --git a/include/osdp.h b/include/osdp.h index 3651b44e..9992ee9f 100644 --- a/include/osdp.h +++ b/include/osdp.h @@ -72,6 +72,17 @@ extern "C" { */ #define OSDP_FLAG_CAPTURE_PACKETS 0x00100000 +/** + * @brief Allow an empty encrypted data block(SCS_17 and SCS_18 packets). + * This is non-conforming to the standard. If there is no data to be + * transferred, the CP should instead use the SCS_15/SCS_16 messages. + * Some OSDP implementations are buggy and send a 0-length data block with + * the SCS_17 and SCS_18 messages, this flag accepts that buggy behavior. + * + * @note this is a PD mode only flag + */ +#define OSDP_FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK 0x00200000 + /** * @brief Various PD capability function codes. */ diff --git a/python/osdp/constants.py b/python/osdp/constants.py index 4d0c5837..556efd2e 100644 --- a/python/osdp/constants.py +++ b/python/osdp/constants.py @@ -12,6 +12,7 @@ class LibFlag: IgnoreUnsolicited = osdp_sys.FLAG_IGN_UNSOLICITED EnableNotification = osdp_sys.FLAG_ENABLE_NOTIFICATION CapturePackets = osdp_sys.FLAG_CAPTURE_PACKETS + AllowEmptySCS17_SCS18 = osdp_sys.FLAG_ALLOW_EMPTY_SCS17_SCS18 class LogLevel: Emergency = osdp_sys.LOG_EMERG diff --git a/python/osdp_sys/module.c b/python/osdp_sys/module.c index 7d935ed6..b5d365ef 100644 --- a/python/osdp_sys/module.c +++ b/python/osdp_sys/module.c @@ -24,6 +24,7 @@ void pyosdp_add_module_constants(PyObject *module) ADD_CONST("FLAG_IGN_UNSOLICITED", OSDP_FLAG_IGN_UNSOLICITED); ADD_CONST("FLAG_ENABLE_NOTIFICATION", OSDP_FLAG_ENABLE_NOTIFICATION); ADD_CONST("FLAG_CAPTURE_PACKETS", OSDP_FLAG_CAPTURE_PACKETS); + ADD_CONST("FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK", OSDP_FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK); ADD_CONST("LOG_EMERG", OSDP_LOG_EMERG); ADD_CONST("LOG_ALERT", OSDP_LOG_ALERT); diff --git a/src/osdp_common.h b/src/osdp_common.h index 2bd43cf4..f296f5f2 100644 --- a/src/osdp_common.h +++ b/src/osdp_common.h @@ -43,6 +43,14 @@ #define LOG_ERR(...) __logger_log(&pd->logger, LOG_ERR, __FILE__, __LINE__, __VA_ARGS__) #define LOG_INF(...) __logger_log(&pd->logger, LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) #define LOG_WRN(...) __logger_log(&pd->logger, LOG_WARNING,__FILE__, __LINE__, __VA_ARGS__) +#define LOG_WRN_ONCE(...) \ +do {\ + static int warned = 0; \ + if(!warned) { \ + __logger_log(&pd->logger, LOG_WARNING,__FILE__, __LINE__, __VA_ARGS__);\ + warned = 1;\ + }\ +}while(0) #define LOG_NOT(...) __logger_log(&pd->logger, LOG_NOTICE, __FILE__, __LINE__, __VA_ARGS__) #define LOG_DBG(...) __logger_log(&pd->logger, LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) @@ -581,4 +589,8 @@ static inline bool is_packet_trace_enabled(struct osdp_pd *pd) { IS_ENABLED(CONFIG_OSDP_PACKET_TRACE)); } +static inline bool sc_allow_empty_encrypted_data_block(struct osdp_pd *pd) { + return ISSET_FLAG(pd, OSDP_FLAG_ALLOW_EMPTY_ENCRYPTED_DATA_BLOCK); +} + #endif /* _OSDP_COMMON_H_ */ diff --git a/src/osdp_phy.c b/src/osdp_phy.c index 22745007..1d6bc047 100644 --- a/src/osdp_phy.c +++ b/src/osdp_phy.c @@ -664,7 +664,7 @@ int osdp_phy_decode_packet(struct osdp_pd *pd, uint8_t **pkt_start) * used SCS_15/SCS_16 but we will be tolerant * towards those faulty implementations. */ - LOG_INF("Received encrypted data block with 0 " + LOG_WRN_ONCE("Received encrypted data block with 0 " "length; tolerating non-conformance!"); } len += 1; /* put back cmd/reply ID */ diff --git a/src/osdp_sc.c b/src/osdp_sc.c index 35b448d5..1cc0f728 100644 --- a/src/osdp_sc.c +++ b/src/osdp_sc.c @@ -139,6 +139,10 @@ int osdp_decrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length) return -1; } + if (allow_scs17_scs18_empty(pd) && length == 0) { + return 0; + } + memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16); for (i = 0; i < 16; i++) { iv[i] = ~iv[i];