| /* |
| * Copyright (c) 2020 Siddharth Chandrasekaran <siddharth@embedjournal.com> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef _OSDP_COMMON_H_ |
| #define _OSDP_COMMON_H_ |
| |
| #include <mgmt/osdp.h> |
| #include <sys/__assert.h> |
| |
| #define OSDP_RESP_TOUT_MS (200) |
| |
| #define OSDP_CMD_SLAB_BUF_SIZE \ |
| (sizeof(struct osdp_cmd) * CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE) |
| |
| #define ISSET_FLAG(p, f) (((p)->flags & (f)) == (f)) |
| #define SET_FLAG(p, f) ((p)->flags |= (f)) |
| #define CLEAR_FLAG(p, f) ((p)->flags &= ~(f)) |
| |
| #define BYTE_0(x) (uint8_t)(((x) >> 0) & 0xFF) |
| #define BYTE_1(x) (uint8_t)(((x) >> 8) & 0xFF) |
| #define BYTE_2(x) (uint8_t)(((x) >> 16) & 0xFF) |
| #define BYTE_3(x) (uint8_t)(((x) >> 24) & 0xFF) |
| |
| /* casting helpers */ |
| #define TO_OSDP(p) ((struct osdp *)p) |
| #define TO_CP(p) (((struct osdp *)(p))->cp) |
| #define TO_PD(p, i) (((struct osdp *)(p))->pd + i) |
| #define TO_CTX(p) ((struct osdp *)p->__parent) |
| |
| #define GET_CURRENT_PD(p) (TO_CP(p)->current_pd) |
| #define SET_CURRENT_PD(p, i) \ |
| do { \ |
| TO_CP(p)->current_pd = TO_PD(p, i); \ |
| TO_CP(p)->pd_offset = i; \ |
| } while (0) |
| #define PD_MASK(ctx) \ |
| (uint32_t)((1 << (TO_CP(ctx)->num_pd)) - 1) |
| #define AES_PAD_LEN(x) ((x + 16 - 1) & (~(16 - 1))) |
| #define NUM_PD(ctx) (TO_CP(ctx)->num_pd) |
| #define OSDP_COMMAND_DATA_MAX_LEN sizeof(struct osdp_cmd) |
| |
| /** |
| * @brief OSDP reserved commands |
| */ |
| #define CMD_POLL 0x60 |
| #define CMD_ID 0x61 |
| #define CMD_CAP 0x62 |
| #define CMD_DIAG 0x63 |
| #define CMD_LSTAT 0x64 |
| #define CMD_ISTAT 0x65 |
| #define CMD_OSTAT 0x66 |
| #define CMD_RSTAT 0x67 |
| #define CMD_OUT 0x68 |
| #define CMD_LED 0x69 |
| #define CMD_BUZ 0x6A |
| #define CMD_TEXT 0x6B |
| #define CMD_RMODE 0x6C |
| #define CMD_TDSET 0x6D |
| #define CMD_COMSET 0x6E |
| #define CMD_DATA 0x6F |
| #define CMD_XMIT 0x70 |
| #define CMD_PROMPT 0x71 |
| #define CMD_SPE 0x72 |
| #define CMD_BIOREAD 0x73 |
| #define CMD_BIOMATCH 0x74 |
| #define CMD_KEYSET 0x75 |
| #define CMD_CHLNG 0x76 |
| #define CMD_SCRYPT 0x77 |
| #define CMD_CONT 0x79 |
| #define CMD_ABORT 0x7A |
| #define CMD_MAXREPLY 0x7B |
| #define CMD_MFG 0x80 |
| #define CMD_SCDONE 0xA0 |
| #define CMD_XWR 0xA1 |
| |
| /** |
| * @brief OSDP reserved responses |
| */ |
| #define REPLY_ACK 0x40 |
| #define REPLY_NAK 0x41 |
| #define REPLY_PDID 0x45 |
| #define REPLY_PDCAP 0x46 |
| #define REPLY_LSTATR 0x48 |
| #define REPLY_ISTATR 0x49 |
| #define REPLY_OSTATR 0x4A |
| #define REPLY_RSTATR 0x4B |
| #define REPLY_RAW 0x50 |
| #define REPLY_FMT 0x51 |
| #define REPLY_PRES 0x52 |
| #define REPLY_KEYPPAD 0x53 |
| #define REPLY_COM 0x54 |
| #define REPLY_SCREP 0x55 |
| #define REPLY_SPER 0x56 |
| #define REPLY_BIOREADR 0x57 |
| #define REPLY_BIOMATCHR 0x58 |
| #define REPLY_CCRYPT 0x76 |
| #define REPLY_RMAC_I 0x78 |
| #define REPLY_MFGREP 0x90 |
| #define REPLY_BUSY 0x79 |
| #define REPLY_XRD 0xB1 |
| |
| /** |
| * @brief secure block types |
| */ |
| #define SCS_11 0x11 /* CP -> PD -- CMD_CHLNG */ |
| #define SCS_12 0x12 /* PD -> CP -- REPLY_CCRYPT */ |
| #define SCS_13 0x13 /* CP -> PD -- CMD_SCRYPT */ |
| #define SCS_14 0x14 /* PD -> CP -- REPLY_RMAC_I */ |
| |
| #define SCS_15 0x15 /* CP -> PD -- packets w MAC w/o ENC */ |
| #define SCS_16 0x16 /* PD -> CP -- packets w MAC w/o ENC */ |
| #define SCS_17 0x17 /* CP -> PD -- packets w MAC w ENC*/ |
| #define SCS_18 0x18 /* PD -> CP -- packets w MAC w ENC*/ |
| |
| /* PD Flags */ |
| #define PD_FLAG_SC_CAPABLE 0x00000001 /* PD secure channel capable */ |
| #define PD_FLAG_TAMPER 0x00000002 /* local tamper status */ |
| #define PD_FLAG_POWER 0x00000004 /* local power status */ |
| #define PD_FLAG_R_TAMPER 0x00000008 /* remote tamper status */ |
| #define PD_FLAG_AWAIT_RESP 0x00000020 /* set after command is sent */ |
| #define PD_FLAG_SKIP_SEQ_CHECK 0x00000040 /* disable seq checks (debug) */ |
| #define PD_FLAG_SC_USE_SCBKD 0x00000080 /* in this SC attempt, use SCBKD */ |
| #define PD_FLAG_SC_ACTIVE 0x00000100 /* secure channel is active */ |
| #define PD_FLAG_SC_SCBKD_DONE 0x00000200 /* SCBKD check is done */ |
| #define PD_FLAG_INSTALL_MODE 0x40000000 /* PD is in install mode */ |
| #define PD_FLAG_PD_MODE 0x80000000 /* device is setup as PD */ |
| |
| enum osdp_pd_nak_code_e { |
| /** |
| * @brief Dummy |
| */ |
| OSDP_PD_NAK_NONE, |
| /** |
| * @brief Message check character(s) error (bad cksum/crc) |
| */ |
| OSDP_PD_NAK_MSG_CHK, |
| /** |
| * @brief Command length error |
| */ |
| OSDP_PD_NAK_CMD_LEN, |
| /** |
| * @brief Unknown Command Code – Command not implemented by PD |
| */ |
| OSDP_PD_NAK_CMD_UNKNOWN, |
| /** |
| * @brief Unexpected sequence number detected in the header |
| */ |
| OSDP_PD_NAK_SEQ_NUM, |
| /** |
| * @brief Unexpected sequence number detected in the header |
| */ |
| OSDP_PD_NAK_SC_UNSUP, |
| /** |
| * @brief unsupported security block or security conditions not met |
| */ |
| OSDP_PD_NAK_SC_COND, |
| /** |
| * @brief BIO_TYPE not supported |
| */ |
| OSDP_PD_NAK_BIO_TYPE, |
| /** |
| * @brief BIO_FORMAT not supported |
| */ |
| OSDP_PD_NAK_BIO_FMT, |
| /** |
| * @brief Unable to process command record |
| */ |
| OSDP_PD_NAK_RECORD, |
| /** |
| * @brief Dummy |
| */ |
| OSDP_PD_NAK_SENTINEL |
| }; |
| |
| enum osdp_pd_state_e { |
| OSDP_PD_STATE_IDLE, |
| OSDP_PD_STATE_SEND_REPLY, |
| OSDP_PD_STATE_ERR, |
| }; |
| |
| enum osdp_cp_phy_state_e { |
| OSDP_CP_PHY_STATE_IDLE, |
| OSDP_CP_PHY_STATE_SEND_CMD, |
| OSDP_CP_PHY_STATE_REPLY_WAIT, |
| OSDP_CP_PHY_STATE_WAIT, |
| OSDP_CP_PHY_STATE_ERR, |
| OSDP_CP_PHY_STATE_ERR_WAIT, |
| OSDP_CP_PHY_STATE_CLEANUP, |
| }; |
| |
| enum osdp_cp_state_e { |
| OSDP_CP_STATE_INIT, |
| OSDP_CP_STATE_IDREQ, |
| OSDP_CP_STATE_CAPDET, |
| OSDP_CP_STATE_SC_INIT, |
| OSDP_CP_STATE_SC_CHLNG, |
| OSDP_CP_STATE_SC_SCRYPT, |
| OSDP_CP_STATE_SET_SCBK, |
| OSDP_CP_STATE_ONLINE, |
| OSDP_CP_STATE_OFFLINE |
| }; |
| |
| enum osdp_pkt_errors_e { |
| OSDP_ERR_PKT_FMT = -1, |
| OSDP_ERR_PKT_WAIT = -2, |
| OSDP_ERR_PKT_SKIP = -3 |
| }; |
| |
| /** |
| * @brief Various PD capability function codes. |
| */ |
| enum osdp_pd_cap_function_code_e { |
| /** |
| * @brief Dummy. |
| */ |
| OSDP_PD_CAP_UNUSED, |
| |
| /** |
| * @brief This function indicates the ability to monitor the status of a |
| * switch using a two-wire electrical connection between the PD and the |
| * switch. The on/off position of the switch indicates the state of an |
| * external device. |
| * |
| * The PD may simply resolve all circuit states to an open/closed |
| * status, or it may implement supervision of the monitoring circuit. |
| * A supervised circuit is able to indicate circuit fault status in |
| * addition to open/closed status. |
| */ |
| OSDP_PD_CAP_CONTACT_STATUS_MONITORING, |
| |
| /** |
| * @brief This function provides a switched output, typically in the |
| * form of a relay. The Output has two states: active or inactive. The |
| * Control Panel (CP) can directly set the Output's state, or, if the PD |
| * supports timed operations, the CP can specify a time period for the |
| * activation of the Output. |
| */ |
| OSDP_PD_CAP_OUTPUT_CONTROL, |
| |
| /** |
| * @brief This capability indicates the form of the card data is |
| * presented to the Control Panel. |
| */ |
| OSDP_PD_CAP_CARD_DATA_FORMAT, |
| |
| /** |
| * @brief This capability indicates the presence of and type of LEDs. |
| */ |
| OSDP_PD_CAP_READER_LED_CONTROL, |
| |
| /** |
| * @brief This capability indicates the presence of and type of an |
| * Audible Annunciator (buzzer or similar tone generator) |
| */ |
| OSDP_PD_CAP_READER_AUDIBLE_OUTPUT, |
| |
| /** |
| * @brief This capability indicates that the PD supports a text display |
| * emulating character-based display terminals. |
| */ |
| OSDP_PD_CAP_READER_TEXT_OUTPUT, |
| |
| /** |
| * @brief This capability indicates that the type of date and time |
| * awareness or time keeping ability of the PD. |
| */ |
| OSDP_PD_CAP_TIME_KEEPING, |
| |
| /** |
| * @brief All PDs must be able to support the checksum mode. This |
| * capability indicates if the PD is capable of supporting CRC mode. |
| */ |
| OSDP_PD_CAP_CHECK_CHARACTER_SUPPORT, |
| |
| /** |
| * @brief This capability indicates the extent to which the PD supports |
| * communication security (Secure Channel Communication) |
| */ |
| OSDP_PD_CAP_COMMUNICATION_SECURITY, |
| |
| /** |
| * @brief This capability indicates the maximum size single message the |
| * PD can receive. |
| */ |
| OSDP_PD_CAP_RECEIVE_BUFFERSIZE, |
| |
| /** |
| * @brief This capability indicates the maximum size multi-part message |
| * which the PD can handle. |
| */ |
| OSDP_PD_CAP_LARGEST_COMBINED_MESSAGE_SIZE, |
| |
| /** |
| * @brief This capability indicates whether the PD supports the |
| * transparent mode used for communicating directly with a smart card. |
| */ |
| OSDP_PD_CAP_SMART_CARD_SUPPORT, |
| |
| /** |
| * @brief This capability indicates the number of credential reader |
| * devices present. Compliance levels are bit fields to be assigned as |
| * needed. |
| */ |
| OSDP_PD_CAP_READERS, |
| |
| /** |
| * @brief This capability indicates the ability of the reader to handle |
| * biometric input |
| */ |
| OSDP_PD_CAP_BIOMETRICS, |
| |
| /** |
| * @brief Capability Sentinel |
| */ |
| OSDP_PD_CAP_SENTINEL |
| }; |
| |
| /** |
| * @brief PD capability structure. Each PD capability has a 3 byte |
| * representation. |
| * |
| * @param function_code One of enum osdp_pd_cap_function_code_e. |
| * @param compliance_level A function_code dependent number that indicates what |
| * the PD can do with this capability. |
| * @param num_items Number of such capability entities in PD. |
| */ |
| struct osdp_pd_cap { |
| uint8_t function_code; |
| uint8_t compliance_level; |
| uint8_t num_items; |
| }; |
| |
| /** |
| * @brief PD ID information advertised by the PD. |
| * |
| * @param version 3-bytes IEEE assigned OUI |
| * @param model 1-byte Manufacturer's model number |
| * @param vendor_code 1-Byte Manufacturer's version number |
| * @param serial_number 4-byte serial number for the PD |
| * @param firmware_version 3-byte version (major, minor, build) |
| */ |
| struct osdp_pd_id { |
| int version; |
| int model; |
| uint32_t vendor_code; |
| uint32_t serial_number; |
| uint32_t firmware_version; |
| }; |
| |
| struct osdp_channel { |
| /** |
| * @brief pointer to a block of memory that will be passed to the |
| * send/receive method. This is optional and can be left empty. |
| */ |
| void *data; |
| |
| /** |
| * @brief pointer to function that copies received bytes into buffer |
| * @param data for use by underlying layers. channel_s::data is passed |
| * @param buf byte array copy incoming data |
| * @param len sizeof `buf`. Can copy utmost `len` bytes into `buf` |
| * |
| * @retval +ve: number of bytes copied on to `bug`. Must be <= `len` |
| * @retval -ve on errors |
| */ |
| int (*recv)(void *data, uint8_t *buf, int maxlen); |
| |
| /** |
| * @brief pointer to function that sends byte array into some channel |
| * @param data for use by underlying layers. channel_s::data is passed |
| * @param buf byte array to be sent |
| * @param len number of bytes in `buf` |
| * |
| * @retval +ve: number of bytes sent. must be <= `len` |
| * @retval -ve on errors |
| */ |
| int (*send)(void *data, uint8_t *buf, int len); |
| |
| /** |
| * @brief pointer to function that drops all bytes in TX/RX fifo |
| * @param data for use by underlying layers. channel_s::data is passed |
| */ |
| void (*flush)(void *data); |
| }; |
| |
| struct osdp_cmd_queue { |
| sys_slist_t queue; |
| struct k_mem_slab slab; |
| uint8_t slab_buf[OSDP_CMD_SLAB_BUF_SIZE]; |
| }; |
| |
| struct osdp_notifiers { |
| int (*keypress)(int address, uint8_t key); |
| int (*cardread)(int address, int format, uint8_t *data, int len); |
| }; |
| |
| #ifdef CONFIG_OSDP_SC_ENABLED |
| struct osdp_secure_channel { |
| uint8_t scbk[16]; |
| uint8_t s_enc[16]; |
| uint8_t s_mac1[16]; |
| uint8_t s_mac2[16]; |
| uint8_t r_mac[16]; |
| uint8_t c_mac[16]; |
| uint8_t cp_random[8]; |
| uint8_t pd_random[8]; |
| uint8_t pd_client_uid[8]; |
| uint8_t cp_cryptogram[16]; |
| uint8_t pd_cryptogram[16]; |
| }; |
| #endif |
| |
| struct osdp_pd { |
| void *__parent; |
| int offset; |
| uint32_t flags; |
| |
| /* OSDP specified data */ |
| int baud_rate; |
| int address; |
| int seq_number; |
| struct osdp_pd_cap cap[OSDP_PD_CAP_SENTINEL]; |
| struct osdp_pd_id id; |
| |
| /* PD state management */ |
| #ifdef CONFIG_OSDP_MODE_PD |
| enum osdp_pd_state_e state; |
| #else |
| enum osdp_cp_state_e state; |
| enum osdp_cp_phy_state_e phy_state; |
| int64_t phy_tstamp; |
| #endif |
| int64_t tstamp; |
| uint8_t rx_buf[CONFIG_OSDP_UART_BUFFER_LENGTH]; |
| int rx_buf_len; |
| |
| int cmd_id; |
| int reply_id; |
| uint8_t cmd_data[OSDP_COMMAND_DATA_MAX_LEN]; |
| |
| struct osdp_channel channel; |
| struct osdp_cmd_queue cmd; |
| #ifdef CONFIG_OSDP_SC_ENABLED |
| int64_t sc_tstamp; |
| struct osdp_secure_channel sc; |
| #endif |
| }; |
| |
| struct osdp_cp { |
| void *__parent; |
| uint32_t flags; |
| int num_pd; |
| struct osdp_pd *current_pd; /* current operational pd's pointer */ |
| int pd_offset; /* current pd's offset into ctx->pd */ |
| struct osdp_notifiers notifier; |
| }; |
| |
| struct osdp { |
| int magic; |
| uint32_t flags; |
| struct osdp_cp *cp; |
| struct osdp_pd *pd; |
| #ifdef CONFIG_OSDP_SC_ENABLED |
| uint8_t sc_master_key[16]; |
| #endif |
| }; |
| |
| /* from osdp_phy.c */ |
| int osdp_phy_packet_init(struct osdp_pd *p, uint8_t *buf, int max_len); |
| int osdp_phy_packet_finalize(struct osdp_pd *p, uint8_t *buf, |
| int len, int max_len); |
| int osdp_phy_decode_packet(struct osdp_pd *p, uint8_t *buf, int len); |
| 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); |
| struct osdp_cmd *osdp_cmd_alloc(struct osdp_pd *pd); |
| void osdp_cmd_free(struct osdp_pd *pd, struct osdp_cmd *cmd); |
| void osdp_cmd_enqueue(struct osdp_pd *pd, struct osdp_cmd *cmd); |
| int osdp_cmd_dequeue(struct osdp_pd *pd, struct osdp_cmd **cmd); |
| struct osdp_cmd *osdp_cmd_get_last(struct osdp_pd *pd); |
| |
| /* from osdp.c */ |
| struct osdp *osdp_get_ctx(); |
| |
| /* from osdp_cp.c */ |
| #ifdef CONFIG_OSDP_MODE_CP |
| int osdp_extract_address(int *address); |
| #endif |
| |
| #ifdef CONFIG_OSDP_SC_ENABLED |
| 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); |
| #endif |
| |
| /* from osdp_sc.c */ |
| void osdp_compute_scbk(struct osdp_pd *pd, uint8_t *scbk); |
| void osdp_compute_session_keys(struct osdp *ctx); |
| void osdp_compute_cp_cryptogram(struct osdp_pd *pd); |
| int osdp_verify_cp_cryptogram(struct osdp_pd *pd); |
| void osdp_compute_pd_cryptogram(struct osdp_pd *pd); |
| int osdp_verify_pd_cryptogram(struct osdp_pd *pd); |
| void osdp_compute_rmac_i(struct osdp_pd *pd); |
| int osdp_decrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int len); |
| 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_fill_random(uint8_t *buf, int len); |
| |
| /* must be implemented by CP or PD */ |
| int osdp_setup(struct osdp *ctx, uint8_t *key); |
| void osdp_update(struct osdp *ctx); |
| |
| #endif /* _OSDP_COMMON_H_ */ |