This is an automated email from the ASF dual-hosted git repository. vipulrahane pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push: new 980cf44 net/osdp: update osdp library to upstream master @ aaba129 new 9332d6a Merge pull request #2516 from vikrant-proxy/osdp-sync 980cf44 is described below commit 980cf4486259c36853eabdec51b955f616cd16aa Author: Vikrant More <vikr...@proxy.com> AuthorDate: Thu Mar 4 08:41:34 2021 -0800 net/osdp: update osdp library to upstream master @ aaba129 --- net/osdp/include/osdp/osdp_common.h | 36 ++++++++++--------- net/osdp/src/osdp_cp.c | 48 ++++++++++++++++---------- net/osdp/src/osdp_pd.c | 2 +- net/osdp/src/osdp_phy.c | 69 ++++++++++++++++++++++++------------- net/osdp/src/osdp_sc.c | 12 ++++--- net/osdp/syscfg.yml | 4 +++ 6 files changed, 107 insertions(+), 64 deletions(-) diff --git a/net/osdp/include/osdp/osdp_common.h b/net/osdp/include/osdp/osdp_common.h index cd2ed13..ab50375 100644 --- a/net/osdp/include/osdp/osdp_common.h +++ b/net/osdp/include/osdp/osdp_common.h @@ -222,6 +222,13 @@ enum osdp_state_e { }; enum osdp_pkt_errors_e { + /* Define the busy error to a +ve value to indicate no error. Also set it + * to 2 which is the value of OSDP_CP_ERR_RETRY_CMD which is the error + * code returned by cp_decode_response() after decoding the busy reply + * packet. This thus allows a busy reply packet to be detected and + * handled without needing the usual additional decoding step. */ + OSDP_ERR_PKT_BUSY = 2, + OSDP_ERR_PKT_NONE = 0, OSDP_ERR_PKT_FMT = -1, OSDP_ERR_PKT_WAIT = -2, @@ -285,6 +292,7 @@ struct osdp_pd { /* PD state management */ int state; int phy_state; + uint32_t wait_ms; int64_t tstamp; int64_t sc_tstamp; @@ -345,25 +353,9 @@ void osdp_phy_state_reset(struct osdp_pd *pd); int osdp_phy_packet_get_data_offset(struct osdp_pd *p, const uint8_t *buf); uint8_t *osdp_phy_packet_get_smb(struct osdp_pd *p, const uint8_t *buf); -/* from osdp_common.c */ -int64_t osdp_millis_now(void); -int64_t osdp_millis_since(int64_t last); -/* void osdp_dump(const char *head, uint8_t *buf, int len); */ -uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len); -int osdp_device_lock(struct os_mutex *lock); -void osdp_device_unlock(struct os_mutex *lock); - /* from osdp.c */ struct osdp *osdp_get_ctx(); -/* from osdp_cp.c */ -#if MYNEWT_VAL(OSDP_MODE_CP) -int osdp_extract_address(int *address); -#endif - -void osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len); -void osdp_decrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len); - /* from osdp_sc.c */ void osdp_compute_scbk(struct osdp_pd *pd, uint8_t *master_key, uint8_t *scbk); void osdp_compute_session_keys(struct osdp *ctx); @@ -377,7 +369,17 @@ int osdp_encrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int len); int osdp_compute_mac(struct osdp_pd *pd, int is_cmd, const uint8_t *data, int len); void osdp_sc_init(struct osdp_pd *pd); -void osdp_get_rand(uint8_t *buf, int len); + +/* from osdp_common.c */ +__attribute__((weak)) int64_t osdp_millis_now(void); +int64_t osdp_millis_since(int64_t last); +/* void osdp_dump(const char *head, uint8_t *buf, int len); */ +uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len); +__attribute__((weak)) void osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len); +__attribute__((weak)) void osdp_decrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len); +__attribute__((weak)) void osdp_get_rand(uint8_t *buf, int len); +int osdp_device_lock(struct os_mutex *lock); +void osdp_device_unlock(struct os_mutex *lock); /** * @brief This method is used to setup a device in PD mode. Application must diff --git a/net/osdp/src/osdp_cp.c b/net/osdp/src/osdp_cp.c index 4776960..0d48748 100644 --- a/net/osdp/src/osdp_cp.c +++ b/net/osdp/src/osdp_cp.c @@ -17,10 +17,8 @@ #define OSDP_PD_POLL_TIMEOUT_MS (1000 / MYNEWT_VAL(OSDP_PD_POLL_RATE)) #define OSDP_CMD_RETRY_WAIT_MS (MYNEWT_VAL(OSDP_CMD_RETRY_WAIT_SEC) * 1000) - -#if MYNEWT_VAL(OSDP_SC_ENABLED) #define OSDP_PD_SC_RETRY_MS (MYNEWT_VAL(OSDP_SC_RETRY_WAIT_SEC) * 1000) -#endif +#define OSDP_ONLINE_RETRY_WAIT_MAX_MS (MYNEWT_VAL(OSDP_ONLINE_RETRY_WAIT_MAX_SEC) * 1000) #define CMD_POLL_LEN 1 #define CMD_LSTAT_LEN 1 @@ -424,7 +422,6 @@ cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) if (smb == NULL) { break; } - osdp_get_rand(pd->sc.cp_random, 8); smb[0] = 3; /* length */ smb[1] = SCS_11; /* type */ smb[2] = ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD) ? 0 : 1; @@ -739,7 +736,7 @@ cp_send_command(struct osdp_pd *pd) if (MYNEWT_VAL(OSDP_PACKET_TRACE)) { if (pd->cmd_id != CMD_POLL) { - osdp_dump(pd->rx_buf, pd->rx_buf_len, + osdp_dump(pd->rx_buf, len, "OSDP: PD[%d]: Sent\n", pd->offset); } } @@ -794,18 +791,33 @@ cp_process_reply(struct osdp_pd *pd) } static inline void -cp_set_offline(struct osdp_pd *pd) +cp_set_state(struct osdp_pd *pd, enum osdp_state_e state) { - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - pd->state = OSDP_CP_STATE_OFFLINE; - pd->tstamp = osdp_millis_now(); + pd->state = state; + CLEAR_FLAG(pd, PD_FLAG_AWAIT_RESP); } static inline void -cp_set_state(struct osdp_pd *pd, enum osdp_state_e state) +cp_set_online(struct osdp_pd *pd) { - pd->state = state; - CLEAR_FLAG(pd, PD_FLAG_AWAIT_RESP); + cp_set_state(pd, OSDP_CP_STATE_ONLINE); + pd->wait_ms = 0; +} + +static inline void +cp_set_offline(struct osdp_pd *pd) +{ + CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); + pd->state = OSDP_CP_STATE_OFFLINE; + pd->tstamp = osdp_millis_now(); + if (pd->wait_ms == 0) { + pd->wait_ms = 1000; /* retry after 1 second initially */ + } else { + pd->wait_ms <<= 1; + if (pd->wait_ms > OSDP_ONLINE_RETRY_WAIT_MAX_MS) { + pd->wait_ms = OSDP_ONLINE_RETRY_WAIT_MAX_MS; + } + } } static int @@ -957,7 +969,7 @@ state_update(struct osdp_pd *pd) } break; case OSDP_CP_STATE_OFFLINE: - if (osdp_millis_since(pd->tstamp) > OSDP_CMD_RETRY_WAIT_MS) { + if (osdp_millis_since(pd->tstamp) > pd->wait_ms) { cp_set_state(pd, OSDP_CP_STATE_INIT); osdp_phy_state_reset(pd); } @@ -999,7 +1011,7 @@ state_update(struct osdp_pd *pd) "to ENFORCE_SECURE\n"); cp_set_offline(pd); } else { - cp_set_state(pd, OSDP_CP_STATE_ONLINE); + cp_set_online(pd); } break; case OSDP_CP_STATE_SC_INIT: @@ -1020,7 +1032,7 @@ state_update(struct osdp_pd *pd) if (ISSET_FLAG(pd, PD_FLAG_SC_SCBKD_DONE)) { OSDP_LOG_INFO("SC Failed. Online without SC\n"); pd->sc_tstamp = osdp_millis_now(); - cp_set_state(pd, OSDP_CP_STATE_ONLINE); + cp_set_online(pd); break; } SET_FLAG(pd, PD_FLAG_SC_USE_SCBKD); @@ -1039,7 +1051,7 @@ state_update(struct osdp_pd *pd) OSDP_LOG_ERROR("CHLNG failed. Online without SC\n"); pd->sc_tstamp = osdp_millis_now(); osdp_phy_state_reset(pd); - cp_set_state(pd, OSDP_CP_STATE_ONLINE); + cp_set_online(pd); } break; } @@ -1058,7 +1070,7 @@ state_update(struct osdp_pd *pd) OSDP_LOG_ERROR("SCRYPT failed. Online without SC\n"); osdp_phy_state_reset(pd); pd->sc_tstamp = osdp_millis_now(); - cp_set_state(pd, OSDP_CP_STATE_ONLINE); + cp_set_online(pd); } break; } @@ -1069,7 +1081,7 @@ state_update(struct osdp_pd *pd) } OSDP_LOG_INFO("SC Active\n"); pd->sc_tstamp = osdp_millis_now(); - cp_set_state(pd, OSDP_CP_STATE_ONLINE); + cp_set_online(pd); break; case OSDP_CP_STATE_SET_SCBK: if (cp_cmd_dispatcher(pd, CMD_KEYSET) != 0) { diff --git a/net/osdp/src/osdp_pd.c b/net/osdp/src/osdp_pd.c index 28aec6b..6efe78d 100644 --- a/net/osdp/src/osdp_pd.c +++ b/net/osdp/src/osdp_pd.c @@ -699,7 +699,7 @@ pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) case REPLY_PDCAP: ASSERT_BUF_LEN(REPLY_PDCAP_LEN); buf[len++] = pd->reply_id; - for (i = 0; i < OSDP_PD_CAP_SENTINEL; i++) { + for (i = 1; i < OSDP_PD_CAP_SENTINEL; i++) { if (pd->cap[i].function_code != i) { continue; } diff --git a/net/osdp/src/osdp_phy.c b/net/osdp/src/osdp_phy.c index ee041fd..00e1fc6 100644 --- a/net/osdp/src/osdp_phy.c +++ b/net/osdp/src/osdp_phy.c @@ -104,7 +104,7 @@ osdp_phy_packet_init(struct osdp_pd *pd, uint8_t *buf, int max_len) pd_mode = ISSET_FLAG(pd, PD_FLAG_PD_MODE); exp_len = sizeof(struct osdp_packet_header) + 64; /* 64 is estimated */ if (max_len < exp_len) { - OSDP_LOG_ERROR("packet_init: out of space! CMD: %02x", pd->cmd_id); + OSDP_LOG_ERROR("packet_init: out of space! CMD: %02x\n", pd->cmd_id); return OSDP_ERR_PKT_FMT; } @@ -160,13 +160,13 @@ osdp_phy_packet_finalize(struct osdp_pd *pd, uint8_t *buf, /* Do a sanity check only; we expect expect header to be prefilled */ if ((unsigned long)len <= sizeof(struct osdp_packet_header)) { - OSDP_LOG_ERROR("PKT_F: Invalid header"); + OSDP_LOG_ERROR("PKT_F: Invalid header\n"); return OSDP_ERR_PKT_FMT; } if (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) { if (buf[0] != OSDP_PKT_MARK) { - OSDP_LOG_ERROR("PKT_F: MARK validation failed! ID: 0x%02x", + OSDP_LOG_ERROR("PKT_F: MARK validation failed! ID: 0x%02x\n", is_cmd ? pd->cmd_id : pd->reply_id); return OSDP_ERR_PKT_FMT; } @@ -177,7 +177,7 @@ osdp_phy_packet_finalize(struct osdp_pd *pd, uint8_t *buf, } pkt = (struct osdp_packet_header *)buf; if (pkt->som != OSDP_PKT_SOM) { - OSDP_LOG_ERROR("PKT_F: header SOM validation failed! ID: 0x%02x", + OSDP_LOG_ERROR("PKT_F: header SOM validation failed! ID: 0x%02x\n", is_cmd ? pd->cmd_id : pd->reply_id); return OSDP_ERR_PKT_FMT; } @@ -247,7 +247,7 @@ osdp_phy_packet_finalize(struct osdp_pd *pd, uint8_t *buf, return len; out_of_space_error: - OSDP_LOG_ERROR("PKT_F: Out of buffer space! CMD(%02x)", pd->cmd_id); + OSDP_LOG_ERROR("PKT_F: Out of buffer space! CMD(%02x)\n", pd->cmd_id); return OSDP_ERR_PKT_FMT; } @@ -276,13 +276,13 @@ osdp_phy_check_packet(struct osdp_pd *pd, uint8_t *buf, int len, /* validate packet header */ if (pkt->som != OSDP_PKT_SOM) { - OSDP_LOG_ERROR("Invalid SOM 0x%02x", pkt->som); + OSDP_LOG_ERROR("Invalid SOM 0x%02x\n", pkt->som); return OSDP_ERR_PKT_FMT; } if (!ISSET_FLAG(pd, PD_FLAG_PD_MODE) && !(pkt->pd_address & 0x80)) { - OSDP_LOG_ERROR("Reply without address MSB set!", pkt->pd_address); + OSDP_LOG_ERROR("Reply without address MSB set!\n", pkt->pd_address); return OSDP_ERR_PKT_FMT; } @@ -297,19 +297,21 @@ osdp_phy_check_packet(struct osdp_pd *pd, uint8_t *buf, int len, /* validate CRC/checksum */ if (pkt->control & PKT_CONTROL_CRC) { - cur = (buf[pkt_len - 1] << 8) | buf[pkt_len - 2]; - comp = osdp_compute_crc16(buf, pkt_len - 2); + pkt_len -= 2; /* consume CRC */ + cur = (buf[pkt_len + 1] << 8) | buf[pkt_len]; + comp = osdp_compute_crc16(buf, pkt_len); if (comp != cur) { - OSDP_LOG_ERROR("Invalid crc 0x%04x/0x%04x", comp, cur); + OSDP_LOG_ERROR("Invalid crc 0x%04x/0x%04x\n", comp, cur); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_MSG_CHK; return OSDP_ERR_PKT_CHECK; } } else { - cur = buf[pkt_len - 1]; - comp = osdp_compute_checksum(buf, pkt_len - 1); + pkt_len -= 1; /* consume checksum */ + cur = buf[pkt_len]; + comp = osdp_compute_checksum(buf, pkt_len); if (comp != cur) { - OSDP_LOG_ERROR("Invalid checksum %02x/%02x", comp, cur); + OSDP_LOG_ERROR("Invalid checksum %02x/%02x\n", comp, cur); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_MSG_CHK; return OSDP_ERR_PKT_CHECK; @@ -321,7 +323,7 @@ osdp_phy_check_packet(struct osdp_pd *pd, uint8_t *buf, int len, if (pd_addr != pd->address && pd_addr != 0x7F) { /* not addressed to us and was not broadcasted */ if (!ISSET_FLAG(pd, PD_FLAG_PD_MODE)) { - OSDP_LOG_ERROR("Invalid pd address %d", pd_addr); + OSDP_LOG_ERROR("Invalid pd address %d\n", pd_addr); return OSDP_ERR_PKT_FMT; } return OSDP_ERR_PKT_SKIP; @@ -347,15 +349,27 @@ osdp_phy_check_packet(struct osdp_pd *pd, uint8_t *buf, int len, * TODO: PD must resend the last response if CP send the * same sequence number again. */ - OSDP_LOG_ERROR("seq-repeat/reply-resend not supported!"); + OSDP_LOG_ERROR("seq-repeat/reply-resend not supported!\n"); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SEQ_NUM; return OSDP_ERR_PKT_FMT; } + } else { + if (comp == 0) { + /** + * Check for receiving a busy reply from the PD which would + * have a sequence number of 0, come in an unsecured packet + * of minimum length, and have the reply ID REPLY_BUSY. + */ + if ((pkt_len == 6) && (pkt->data[0] == REPLY_BUSY)) { + pd->seq_number -= 1; + return OSDP_ERR_PKT_BUSY; + } + } } cur = osdp_phy_get_seq_number(pd, ISSET_FLAG(pd, PD_FLAG_PD_MODE)); if (cur != comp && !ISSET_FLAG(pd, PD_FLAG_SKIP_SEQ_CHECK)) { - OSDP_LOG_ERROR("packet seq mismatch %d/%d", cur, comp); + OSDP_LOG_ERROR("packet seq mismatch %d/%d\n", cur, comp); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SEQ_NUM; return OSDP_ERR_PKT_FMT; @@ -387,13 +401,13 @@ osdp_phy_decode_packet(struct osdp_pd *pd, uint8_t *buf, int len, if (pkt->control & PKT_CONTROL_SCB) { if (ISSET_FLAG(pd, PD_FLAG_PD_MODE) && !ISSET_FLAG(pd, PD_FLAG_SC_CAPABLE)) { - OSDP_LOG_ERROR("PD is not SC capable"); + OSDP_LOG_ERROR("PD is not SC capable\n"); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SC_UNSUP; return OSDP_ERR_PKT_FMT; } if (pkt->data[1] < SCS_11 || pkt->data[1] > SCS_18) { - OSDP_LOG_ERROR("Invalid SB Type"); + OSDP_LOG_ERROR("Invalid SB Type\n"); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; return OSDP_ERR_PKT_FMT; @@ -415,7 +429,7 @@ osdp_phy_decode_packet(struct osdp_pd *pd, uint8_t *buf, int len, len -= pkt->data[0]; /* consume security block */ } else { if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - OSDP_LOG_ERROR("Received plain-text message in SC"); + OSDP_LOG_ERROR("Received plain-text message in SC\n"); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; return OSDP_ERR_PKT_FMT; @@ -430,7 +444,7 @@ osdp_phy_decode_packet(struct osdp_pd *pd, uint8_t *buf, int len, osdp_compute_mac(pd, is_cmd, buf, mac_offset); mac = is_cmd ? pd->sc.c_mac : pd->sc.r_mac; if (memcmp(buf + mac_offset, mac, 4) != 0) { - OSDP_LOG_ERROR("Invalid MAC; discarding SC"); + OSDP_LOG_ERROR("Invalid MAC; discarding SC\n"); CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; @@ -444,20 +458,29 @@ osdp_phy_decode_packet(struct osdp_pd *pd, uint8_t *buf, int len, * Only the data portion of message (after id byte) * is encrypted. While (en/de)crypting, we must skip * header (6), security block (2) and cmd/reply id (1) - * bytes if cmd/reply has no data, use SCS_15/SCS_16. + * bytes. * * At this point, the header and security block is * already consumed. So we can just skip the cmd/reply * ID (data[0]) when calling osdp_decrypt_data(). */ len = osdp_decrypt_data(pd, is_cmd, data + 1, len - 1); - if (len <= 0) { - OSDP_LOG_ERROR("Failed at decrypt; discarding SC"); + if (len < 0) { + OSDP_LOG_ERROR("Failed at decrypt; discarding SC\n"); CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); pd->reply_id = REPLY_NAK; pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; return OSDP_ERR_PKT_FMT; } + if (len == 0) { + /** + * If cmd/reply has no data, PD "should" have + * used SCS_15/SCS_16 but we will be tolerant + * towards those faulty implementations. + */ + OSDP_LOG_INFO("Received encrypted data block with 0 " + "length; tolerating non-conformance!\n"); + } len += 1; /* put back cmd/reply ID */ } } diff --git a/net/osdp/src/osdp_sc.c b/net/osdp/src/osdp_sc.c index 4328548..e98ff17 100644 --- a/net/osdp/src/osdp_sc.c +++ b/net/osdp/src/osdp_sc.c @@ -10,7 +10,6 @@ #include "osdp/osdp_common.h" #define TAG "SC: " - #define OSDP_SC_EOM_MARKER 0x80 /* End of Message Marker */ /* Default key as specified in OSDP specification */ @@ -167,15 +166,16 @@ osdp_decrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length) osdp_decrypt(pd->sc.s_enc, iv, data, length); - while (data[length - 1] == 0x00) { + length--; + while (length && data[length] == 0x00) { length--; } - if (data[length - 1] != OSDP_SC_EOM_MARKER) { + if (data[length] != OSDP_SC_EOM_MARKER) { return -1; } - data[length - 1] = 0; + data[length] = 0; - return length - 1; + return length; } int @@ -256,5 +256,7 @@ osdp_sc_init(struct osdp_pd *pd) pd->sc.pd_client_uid[5] = BYTE_1(pd->id.serial_number); pd->sc.pd_client_uid[6] = BYTE_2(pd->id.serial_number); pd->sc.pd_client_uid[7] = BYTE_3(pd->id.serial_number); + } else { + osdp_get_rand(pd->sc.cp_random, 8); } } diff --git a/net/osdp/syscfg.yml b/net/osdp/syscfg.yml index 3cb8853..004ae3f 100644 --- a/net/osdp/syscfg.yml +++ b/net/osdp/syscfg.yml @@ -44,6 +44,10 @@ syscfg.defs: description: 'Time in seconds to wait after a secure channel failure, and before retrying to establish it.' + OSDP_ONLINE_RETRY_WAIT_MAX_SEC: + value: 300 + description: 'Upper limit in seconds for the CP to wait and retry communication.' + OSDP_RESP_TOUT_MS: value: 200 description: 'Response timeout in milliseconds.'