Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ option(OPT_OSDP_STATIC "Build without dynamic memory allocation" OFF)
option(OPT_OSDP_LIB_ONLY "Only build the library" OFF)
option(OPT_BUILD_BARE_METAL "Build library for bare metal targets" OFF)
option(OPT_USE_32BIT_TICK_T "Use uint32_t tick_t on bare-metal targets" OFF)
option(OPT_BUILD_OSDP_TRS "Enabled Transparent Reader Support" OFF)
set(OPT_OSDP_CRYPTO_BACKEND "auto" CACHE STRING
"Crypto backend selection: auto, openssl, mbedtls, or tinyaes")
set_property(CACHE OPT_OSDP_CRYPTO_BACKEND PROPERTY STRINGS
Expand Down
11 changes: 11 additions & 0 deletions configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ usage() {
--lib-only Only build the library
--bare-metal Enable bare-metal build paths
--use-32bit-tick-t Use uint32_t tick_t (requires --bare-metal)
--enable-trs Enable support for Transparent Reader Support
--cross-compile PREFIX Use to pass a compiler prefix
--prefix PATH Install path prefix (default: /usr)
--build-dir Build output directory (default: ./build)
Expand Down Expand Up @@ -57,6 +58,7 @@ while [ $# -gt 0 ]; do
--lib-only) LIB_ONLY=1;;
--bare-metal) BARE_METAL=1;;
--use-32bit-tick-t) USE_32BIT_TICK_T=1;;
--enable-trs) ENABLE_TRS=1;;
--build-dir) BUILD_DIR=$2; shift;;
-d|--debug) DEBUG=1;;
-f|--force) FORCE=1;;
Expand Down Expand Up @@ -133,6 +135,10 @@ if [[ ! -z "${USE_32BIT_TICK_T}" ]]; then
CCFLAGS+=" -DUSE_32BIT_TICK_T"
fi

if [[ ! -z "${ENABLE_TRS}" ]]; then
CCFLAGS+=" -DOPT_BUILD_OSDP_TRS"
fi

## Repo meta data
echo "Extracting source code meta information"
PROJECT_VERSION=$(perl -ne 'print if s/^project\(libosdp VERSION ([0-9.]+)\)$/\1/' CMakeLists.txt)
Expand Down Expand Up @@ -214,6 +220,10 @@ fi

TARGETS="cp_app pd_app"

if [[ ! -z "${ENABLE_TRS}" ]]; then
LIBOSDP_SOURCES+=" src/osdp_trs.c"
fi

TEST_SOURCES="tests/unit-tests/test.c"
TEST_SOURCES+=" tests/unit-tests/test-cp-phy.c"
TEST_SOURCES+=" tests/unit-tests/test-pd-phy.c"
Expand All @@ -227,6 +237,7 @@ TEST_SOURCES+=" tests/unit-tests/test-sc.c"
TEST_SOURCES+=" tests/unit-tests/test-sc-sia-vectors.c"
TEST_SOURCES+=" tests/unit-tests/test-notifications.c"
TEST_SOURCES+=" tests/unit-tests/test-codec-fuzz.c"
TEST_SOURCES+=" tests/unit-tests/test-trs.c"
TEST_SOURCES+=" ${LIBOSDP_SOURCES} ${UTILS_SOURCES}"

if [[ ! -z "${LIB_ONLY}" ]]; then
Expand Down
192 changes: 192 additions & 0 deletions include/osdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -831,9 +831,183 @@ enum osdp_cmd_e {
OSDP_CMD_STATUS, /**< Status report command */
OSDP_CMD_COMSET_DONE, /**< Comset completed; Alias for OSDP_CMD_COMSET */
OSDP_CMD_NOTIFICATION,/**< LibOSDP notification (PD mode, synthesized) */
OSDP_CMD_XWR, /**< Transparent mode command */
OSDP_CMD_SENTINEL /**< Max command value */
};

/**
* @brief Transparent Reader Support (TRS) commands a CP application can issue to
* a smart card in the reader. Set in @c struct osdp_trs_cmd::command and
* submitted as an @c OSDP_CMD_XWR command.
*
* The library owns the transparent-mode session lifecycle (mode negotiation and
* teardown), so those protocol-internal steps are deliberately not exposed here.
*/
enum osdp_trs_cmd_e {
OSDP_TRS_CMD_SEND_APDU = 1, /**< Send a C-APDU to the card */
OSDP_TRS_CMD_ENTER_PIN, /**< EMV PIN entry */
OSDP_TRS_CMD_CARD_SCAN, /**< Scan for a card in the field */
};

/** @brief Max APDU length carried in a TRS command or reply */
#define OSDP_TRS_APDU_MAX_LEN 64
/** @brief Max CSN length carried in a TRS card-info reply */
#define OSDP_TRS_CSN_MAX_LEN 32
/** @brief Max protocol-data length carried in a TRS card-info reply */
#define OSDP_TRS_PROTOCOL_DATA_MAX_LEN 64

struct osdp_trs_apdu {
int length; /**< APDU length in bytes */
uint8_t data[OSDP_TRS_APDU_MAX_LEN]; /**< APDU bytes */
};

/** @brief Encoding of the PIN digits the reader inserts into the C-APDU */
enum osdp_trs_pin_format_e {
OSDP_TRS_PIN_FORMAT_BINARY = 1, /**< PIN digits as binary values */
OSDP_TRS_PIN_FORMAT_BCD, /**< PIN digits as packed BCD */
OSDP_TRS_PIN_FORMAT_ASCII, /**< PIN digits as ASCII characters */
};

/**
* @brief Conditions that end PIN entry; OR them into
* @c osdp_trs_pin_entry::complete_on.
*/
enum osdp_trs_pin_complete_e {
OSDP_TRS_PIN_COMPLETE_ON_MAX_DIGITS = 1 << 0, /**< max_digits entered */
OSDP_TRS_PIN_COMPLETE_ON_KEY = 1 << 1, /**< Validation (enter) key pressed */
OSDP_TRS_PIN_COMPLETE_ON_TIMEOUT = 1 << 2, /**< Entry timed out */
};

/**
* @brief TRS secure PIN entry request: the reader prompts the user for their
* PIN, inserts it into @a apdu as described by the layout fields below, and
* sends the result to the card.
*
* APDU positions are expressed in bits from the start of the APDU payload.
* Not every position is expressible on the wire: it must be byte-aligned (up
* to 120 bits) or fall within the first 15 bits; anything else fails the
* command submission.
*/
struct osdp_trs_pin_entry {
int timeout_initial; /**< First-digit timeout in seconds (0 = reader default) */
int timeout_digit; /**< Per-digit timeout in seconds after the first key */

/**
* The PIN block: the region of the C-APDU where the reader formats
* and inserts the entered PIN.
*/
struct {
enum osdp_trs_pin_format_e format; /**< PIN digit encoding */
bool right_justify; /**< Right-justify the PIN within the block
* (default: left-justified) */
int offset_bits; /**< Block position in the APDU payload, in bits */
int size_bytes; /**< Block size in bytes, after justification
* and formatting, as defined by the card
* scheme (8 for EMV/ISO 9564 PIN blocks) */
} pin_block;

/*
* Optional slot in the C-APDU where the reader records how many PIN
* digits the user entered; the app cannot pre-fill it because only
* the reader knows the entered length.
*/
struct {
int size_bits; /**< Slot size in bits (0 = APDU has no such slot) */
int offset_bits; /**< Slot position in the APDU payload, in bits */
} pin_length_field;

int min_digits; /**< Minimum PIN length, in digits */
int max_digits; /**< Maximum PIN length, in digits */
uint32_t complete_on; /**< When PIN entry ends: OR of
* enum osdp_trs_pin_complete_e conditions */

int num_messages; /**< Number of display messages */
int language_id; /**< Display language identifier */
int msg_index; /**< Index of the message to display */
uint8_t teo_prologue[3]; /**< T=1 protocol prologue */
struct osdp_trs_apdu apdu; /**< C-APDU to send after PIN entry */
};

struct osdp_trs_cmd {
enum osdp_trs_cmd_e command; /**< Which TRS command; selects the union */
union {
struct osdp_trs_apdu apdu; /**< For OSDP_TRS_CMD_SEND_APDU */
struct osdp_trs_pin_entry pin_entry;
};
};

/** @brief Smart-card communication protocol reported in a TRS card-info reply */
enum osdp_trs_card_protocol_e {
OSDP_TRS_CARD_PROTOCOL_CONTACT = 1, /**< ISO 7816 contact (T=0/T=1) */
OSDP_TRS_CARD_PROTOCOL_CONTACTLESS, /**< ISO 14443 A/B contactless */
};

struct osdp_trs_card_info {
int reader; /**< Reader number (0 = first, 1 = second) */
enum osdp_trs_card_protocol_e protocol; /**< Card communication protocol */
int csn_len; /**< Length of @a csn in bytes */
uint8_t csn[OSDP_TRS_CSN_MAX_LEN]; /**< Card serial number */
int protocol_data_len; /**< Length of @a protocol_data in bytes */
uint8_t protocol_data[OSDP_TRS_PROTOCOL_DATA_MAX_LEN]; /** ATR or ATS/ATQB */
};

/** @brief Smart-card presence (and interface) reported in a TRS card-present reply */
enum osdp_trs_card_status_e {
OSDP_TRS_CARD_NOT_PRESENT = 1, /**< No card detected */
OSDP_TRS_CARD_PRESENT, /**< Card present; interface not specified */
OSDP_TRS_CARD_PRESENT_CONTACTLESS, /**< Card present on the contactless (ISO 14443) interface */
OSDP_TRS_CARD_PRESENT_CONTACT, /**< Card present on the contact (ISO 7816) interface */
};

struct osdp_trs_card_present {
int reader; /**< Reader number (0 = first, 1 = second) */
enum osdp_trs_card_status_e status; /**< Smart-card presence status */
};

struct osdp_trs_card_data {
int reader; /**< Reader number (0 = first, 1 = second) */
int status; /**< Result of the APDU exchange as reported by the reader
* (reader-defined; not standardized by OSDP) */
struct osdp_trs_apdu apdu; /**< R-APDU returned by the card */
};

struct osdp_trs_pin_complete {
int reader; /**< Reader number (0 = first, 1 = second) */
int status; /**< Result of the secure PIN entry sequence as reported by the
* reader (reader-defined; not standardized by OSDP) */
int tries; /**< Number of PIN-entry attempts */
};

struct osdp_trs_error {
int code; /**< Error/NAK condition from the reader or card
* (reader-defined; not standardized by OSDP) */
};

/**
* @brief Transparent Reader Support (TRS) replies delivered to a CP application
* as an @c OSDP_EVENT_TRS event, or submitted by a PD application (via
* @c osdp_pd_submit_event) in answer to a TRS command. The @a reply field
* selects the active union member.
*/
enum osdp_trs_reply_e {
OSDP_TRS_REPLY_CARD_INFO = 1, /**< A card entered the field (CSN, protocol) */
OSDP_TRS_REPLY_CARD_PRESENT, /**< Card-present status for a reader */
OSDP_TRS_REPLY_CARD_DATA, /**< R-APDU returned by the card */
OSDP_TRS_REPLY_PIN_COMPLETE, /**< PIN entry completed */
OSDP_TRS_REPLY_ERROR, /**< Transparent-mode error / NAK from reader */
};

struct osdp_trs_reply {
enum osdp_trs_reply_e reply; /**< Which TRS reply; selects the union */
union {
struct osdp_trs_card_info card_info;
struct osdp_trs_card_present card_present;
struct osdp_trs_card_data card_data;
struct osdp_trs_pin_complete pin_complete;
struct osdp_trs_error error;
};
};

/**
* @brief When set (`struct osdp_cmd::flags`), the command is sent out with the
* OSDP packet broadcast flag to the PD.
Expand Down Expand Up @@ -875,6 +1049,7 @@ struct osdp_cmd {
struct osdp_cmd_file_tx file_tx; /**< File transfer command structure */
struct osdp_status_report status; /**< Status report command structure */
struct osdp_notification notif; /**< LibOSDP notification (PD mode) */
struct osdp_trs_cmd trs; /**< Transparent mode command structure */
};
};

Expand Down Expand Up @@ -978,6 +1153,7 @@ enum osdp_event_type {
OSDP_EVENT_MFGREP, /**< Manufacturer specific reply event */
OSDP_EVENT_STATUS, /**< Status event */
OSDP_EVENT_NOTIFICATION, /**< LibOSDP notification event */
OSDP_EVENT_TRS, /**< Transparent mode response event */
OSDP_EVENT_SENTINEL /**< Max event value */
};

Expand All @@ -995,6 +1171,7 @@ struct osdp_event {
struct osdp_event_mfgrep mfgrep; /**< Manufacturer specific response event struture */
struct osdp_status_report status; /**< Status report event structure */
struct osdp_notification notif; /**< LibOSDP notification (CP mode) */
struct osdp_trs_reply trs; /**< Transparent mode reply event structure */
};
};

Expand Down Expand Up @@ -1253,6 +1430,21 @@ int osdp_cp_send_command(osdp_t *ctx, int pd, const struct osdp_cmd *cmd);
OSDP_EXPORT
int osdp_cp_submit_command(osdp_t *ctx, int pd, const struct osdp_cmd *cmd);

/**
* @brief Request an orderly stop of an active TRS (Transparent Reader) session
* on a PD. The library terminates the card connection and restores the PD to
* transparent-mode-off before returning it to the ONLINE state.
*
* @param ctx OSDP context
* @param pd PD offset (0-indexed) of this PD in `osdp_pd_info_t *` passed to
* osdp_cp_setup()
*
* @retval 0 on success
* @retval -1 on failure (e.g. TRS support not built in)
*/
OSDP_EXPORT
int osdp_cp_trs_stop(osdp_t *ctx, int pd);

/**
* @brief Deletes all commands queued for a give PD
*
Expand Down
1 change: 1 addition & 0 deletions library.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"srcFilter": [
"+<**/*.c>",
"-<osdp_diag.c>",
"-<osdp_trs.c>",
"-<crypto/mbedtls.c>",
"-<crypto/openssl.c>",
"+<../utils/src/disjoint_set.c>",
Expand Down
11 changes: 11 additions & 0 deletions python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def try_vendor_sources(src_dir, src_files, vendor_dir):
"src/osdp_common.h",
"src/osdp_file.h",
"src/osdp_metrics.h",
"src/osdp_trs.h",
"src/crypto/tinyaes_src.h",
]

Expand All @@ -168,6 +169,9 @@ def try_vendor_sources(src_dir, src_files, vendor_dir):
"src/osdp_diag.h",
"utils/include/utils/pcap_gen.h",
"utils/src/pcap_gen.c",

# Optional when TRS is enabled
"src/osdp_trs.c",
]

# LICENSE lives at the repo root; vendor a copy so wheel/sdist builds
Expand All @@ -176,6 +180,8 @@ def try_vendor_sources(src_dir, src_files, vendor_dir):

definitions = [
"OPT_OSDP_PACKET_TRACE",
# osdp_sys exposes no TRS bindings yet; keep TRS out of the extension.
# "OPT_BUILD_OSDP_TRS",
# "OPT_OSDP_DATA_TRACE",
# "OPT_OSDP_SKIP_MARK_BYTE",
]
Expand All @@ -195,6 +201,11 @@ def try_vendor_sources(src_dir, src_files, vendor_dir):
"utils/src/pcap_gen.c",
]

if "OPT_BUILD_OSDP_TRS" in definitions:
source_files += [
"src/osdp_trs.c",
]

source_files = add_prefix_to_path(source_files, "vendor")

include_dirs = [
Expand Down
10 changes: 10 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ if (OPT_OSDP_STATIC)
list(APPEND LIB_OSDP_DEFINITIONS "-DOPT_OSDP_STATIC=1")
endif()

if (OPT_BUILD_OSDP_TRS)
list(APPEND LIB_OSDP_DEFINITIONS "-DOPT_BUILD_OSDP_TRS")
endif()

# Crypto backend selection driven by OPT_OSDP_CRYPTO_BACKEND:
# auto - probe openssl, then mbedtls, else fall back to bundled tinyaes
# openssl - require OpenSSL (hard-fail if missing)
Expand Down Expand Up @@ -93,6 +97,12 @@ if (OPT_OSDP_PACKET_TRACE OR OPT_OSDP_DATA_TRACE)
)
endif()

if (OPT_BUILD_OSDP_TRS)
list(APPEND LIB_OSDP_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/osdp_trs.c
)
endif()

list(APPEND LIB_OSDP_INCLUDE_DIRS
${PROJECT_BINARY_DIR}/include
)
Expand Down
Loading