Giter Club home page Giter Club logo

libosdp's Introduction

LibOSDP - Open Supervised Device Protocol Library

Latest Release Build CI PyPI Version

This is a cross-platform open source implementation of IEC 60839-11-5 Open Supervised Device Protocol (OSDP). The protocol is intended to improve interoperability among access control and security products. It supports Secure Channel (SC) for encrypted and authenticated communication between configured devices.

OSDP describes the communication protocol for interfacing one or more Peripheral Devices (PD) to a Control Panel (CP) over a two-wire RS-485 multi-drop serial communication channel. Nevertheless, this protocol can be used to transfer secure data over any stream based physical channel. Read more about OSDP here.

This protocol is developed and maintained by Security Industry Association (SIA).

Salient Features of LibOSDP

  • Supports secure channel communication (AES-128) by default and provides a custom init-time flag to enforce a higher level of security not mandated by the specification
  • Can be used to setup a PD or CP mode of operation
  • Exposes a well defined contract though a single header file
  • Cross-platform; runs on bare-metal, Linux, Mac, and even Windows
  • No run-time memory allocation. All memory is allocated at init-time
  • No external dependencies (for ease of cross compilation)
  • Fully non-blocking, asynchronous design
  • Provides Rust, Python3, and C++ bindings for the C library for faster integration into various development phases.
  • Includes dozens of integration and unit tests which are incorporated in CI to ensure higher quality of releases.
  • Built-in, sophisticated, debugging infrastructure and tools (see).

Usage Overview

A device complying with OSDP can either be a CP or a PD. There can be only one CP on a bus which can talk to multiple PDs. LibOSDP allows your application to work either as a CP or a PD so depending on what you want to do you have to do some things differently.

LibOSDP creates the following constructs which allow interactions between devices on the OSDP bus. These should not be confused with the protocol specified terminologies that may use the same names. They are:

  • Channel - Something that allows two OSDP devices to talk to each other
  • Commands - A call for action from a CP to one of its PDs
  • Events - A call for action from a PD to its CP

You start by implementing the osdp_channel interface; this allows LibOSDP to communicate with other osdp devices on the bus. Then you describe the PD you are

  • talking to on the bus (in case of CP mode of operation) or,
  • going to behave as on the bus (in case of PD mode of operation) by using the osdp_pd_info_t struct.

You can use osdp_pd_info_t struct (or an array of it in case of CP) to create a osdp_t context. Then your app needs to call the osdp_cp/pd_refresh() as frequently as possible. To meet the OSDP specified timing requirements, your app must call this method at least once every 50ms.

After this point, the CP context can,

  • send commands to any one of the PDs (to control LEDs, Buzzers, etc.,)
  • register a callback for events that are sent from a PD

and the PD context can,

  • notify it's controlling CP about an event (card read, key press, etc.,)
  • register a callback for commands issued by the CP

Language Support

C/C++ API

LibOSDP core is written in C. It exposes a minimal set of API to setup and manage the lifecycle of OSDP devices. See include/osdp.h or include/osdp.hpp for more details.

Rust API

LibOSDP is available via crates.io. See rust/README.md for more info and usage examples.

Python API

LibOSDP is available as a python package. See python/README.md for more info and usage examples.

Supported Commands and Replies

OSDP has certain command and reply IDs pre-registered. This implementation of the protocol support only the most common among them. You can see a list of commands and replies and their support status in LibOSDP here.

Dependencies

  • goToMain/C-Utils (host, submodule)
  • cmake3 (host)
  • python3 (host, optional)
  • python3-pip (host, optional)
  • doxygen (host, optional; for building the html docs as seen here)
  • OpenSSL (host and target, optional - recommended)
  • MbedTLS (host and target, optional)
  • pytest (host, optional; for running the integrated test suite)
  • python3-venv (host, optional; for running integration test suite)

For ubuntu

sudo apt install cmake python3 python3-pip python3-dev python3-venv libssl-dev

Compile LibOSDP

LibOSDP provides a lean-build that only builds the core library and nothing else. This is useful if you are cross compiling as it doesn't have any other dependencies but a C compiler. Here is an example of how you can cross compile LibOSDP to arm-none-eabi-gcc.

export CROSS_COMPILE=arm-none-eabi-
export CCFLAGS=--specs=nosys.specs
./configure.sh
make

To build libosdp and all its components you must have cmake-3.0 (or above) and a C compiler installed. This repository produces a libosdp.so and libosdpstatic.a; so depending on on your needs you can link these with -losdp or -losdpstatic, respectively.

Have a look at examples/* for a quick lookup on how to consume this library and structure your application.

You can also read the API documentation for a comprehensive list of APIs that are exposed by libosdp.

git clone https://github.com/goToMain/libosdp --recurse-submodules
# git submodule update --init (if you missed doing --recurse-submodules earlier)
cd libosdp
mkdir build && cd build
cmake ..
make

Refer to this document for more information on build and cross compilation.

Run the test suite

LibOSDP uses the pytest python framework to test changes made to ensure we aren't breaking existing functionalities while adding newer ones. You can install pytest in your development machine with,

python3 -m pip install pytest

Running the tests locally before creating a pull request is recommended to make sure that your changes aren't breaking any of the existing functionalities. Here is how you can run them:

mkdir build && cd build
cmake ..
make python_install
make check

To add new tests for the feature you are working one, see the other tests in pytest directory.

Build HTML docs

This sections is for those who want to build the HTML documentation for this project locally. The latest version of the doc can always be found at libosdp.sidcha.dev.

Install the dependencies (one time) with,

sudo apt install doxygen
pip3 install -r doc/requirements.txt

Build the docs by doing the following:

mkdir build && cd build
cmake ..
make html_docs # output in ./docs/sphinx/

Contributions, Issues and Bugs

The Github issue tracker doubles up as TODO list for this project. Have a look at the open items, PRs in those directions are welcome.

If you have a idea, find bugs, or other issues, please open a new issue in the github page of this project https://github.com/goTomain/libosdp.

You can read more on this here.

License

This software is distributed under the terms of Apache-2.0 license. If you don't know what that means/implies, you can consider it is as "free as in beer".

OSDP protocol is also open for consumption into any product. There is no need to,

  • obtain permission from SIA
  • pay royalty to SIA
  • become SIA member

The OSDP specification can be obtained from SIA for a cost. Read more at our FAQ page.

Support the development

Since this is no longer a hobby project, it takes time and effort to develop and maintain this project. If you are a user and are happy with it, consider supporting the development by donations though my GitHub sponsors page. Your support will ensure sustained development of LibOSDP.

libosdp's People

Contributors

badevos avatar bjyoungblood avatar bojankoce avatar dmercer-google avatar dvucich avatar ejverat avatar jlanger avatar jr-oss avatar kaiamelung avatar mehmoodmalik avatar nathan-simpson avatar niklasva avatar pakesson-truesec avatar patrick-compass avatar schmida2 avatar sebastianjonasson avatar sidcha avatar stuckya avatar sympatron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libosdp's Issues

Add support for sequence repeat (CP) and reply resend (PD) features

According to the OSDP protocol
the SQN which defines in message control byte, I think if CP receives PD response SQN error or No response from PD,the CP should repeat the command packet,the repeat command packet should be same with the last time command package.

PD assumes incoming data is equal to packet size

When running multiple PDs a PD have to be able to receive multiple packets without breaking.
Today all incoming data is put into pd->rx_buf and osdp_phy_decode_packet assumes that only one command is put into this buffer.

When running multiple PDs a PD might receive multiple commands at a high rate. For example if there is PD A and PD B, PD A receives a command and replies to it instantly. if PD B, did not try and decode the first command before if got the reply it will get stuck waiting for more data(due to "if (pkt_len != len)" in osdp_phy.c).
(With multi drop each PD will receive the replies from other PDs, which will be discarded.)

The phy should only wait for more data if it needs it (pkt_len > len) and equally important is that it should not discard any additional bytes.
easiest implementation would be to separate rx_buf from the data delivery. so at the end of osdp_phy_decode_packet() the data is copied into a separate data buffer and any additional bytes in rx_buffer should be moved to the front of the buffer.

Question on secure mode and library usage

First off, great work! I have some questions on the usage of this library, hope you can clarify:

  • There is a setup flag to enable install mode on a PD. But say the PD is operational, how to get it into install mode? From the code, it doesn't look like it honors this flag during runtime, but only during initial setup. Is this expected to be handled by the application? Or should the init happen again?
  • Second question is somewhat related to the first point. Before entering install mode, or maybe in some other situation, how can a PD reset communication with the CP so as to restart secure channel handshake? I saw this note from the the author on one of the GH issues saying one of the ways to handle from the CP, can you point me to the point in the CP implementation where this happens -

On a side note, if you are developing the CP internally, you can force the sequence number to 0 in a message that tries to restart communication to force the PD to discard the current SC session. LibOSDP's CP implementation does this and it has worked very well for me.

  • Currently the PD setup sets the SC_CAPABLE flag to enable secure channel during init and also sets the implicit capability. This doesn't seem to be configurable from the application since the implicit capability overrides the capabilities sent from the application in the osdp_pd_setup function. Is there a way/API with which an application can set this flag during initialization to work in non-secure mode? It could potentially be trivially done by adding an arg in the setup function, but I was wondering if there is an existing way.
  • In the python binding sample app, if I enable the keyset command and send it to the PD with some 16byte data, the PD still receives the same SCBK made before with the the master key and the info parameters. This is possibly a gap in my understanding , but can you confirm this is the expected behavior?

Unit test produces segmentation fault

Below is the terminal output:

chayandashora@linux-ggds:~/Downloads/libosdp_master_sid/build> make && make check
[100%] Built target osdp
[100%] Built target osdpctl
[100%] Built target osdp
[100%] Built target osdp-test
------------------------------------------
OSDP - Unit Tests
------------------------------------------
Testing cp_build_packet(CMD_POLL) -- success!
Testing cp_build_packet(CMD_ID) -- success!
Testing phy_decode_packet(REPLY_ACK) -- success!
Testing cp_queue_command() -- success!

Starting CP fsm state tests
-- executing test_cp_phy_fsm()
make[3]: *** [CMakeFiles/check.dir/build.make:57: CMakeFiles/check] Segmentation fault (core dumped)
make[2]: *** [CMakeFiles/Makefile2:68: CMakeFiles/check.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:75: CMakeFiles/check.dir/rule] Error 2
make: *** [Makefile:164: check] Error 2

Upon further analysis, I found out that in test/test-cp-phy-fsm.c, line 126,
while (result) {
if the result value is 1, then segmentation fault appears.

Wrong SCS code sent by osdp_pd?

I'm using OSDP.Net library to check your library and I had problems with Secure Channel.
Changing osdp_pd.c with:

diff --git a/src/osdp_pd.c b/src/osdp_pd.c
index 5e5b997..02c63d7 100644
--- a/src/osdp_pd.c
+++ b/src/osdp_pd.c
@@ -330,7 +330,7 @@ int pd_build_reply(struct osdp_pd *p, struct osdp_data *reply, uint8_t * pkt)
 
 	if (smb && (smb[1] > SCS_14) && isset_flag(p, PD_FLAG_SC_ACTIVE)) {
 		smb[0] = 2;
-		smb[1] = (len > 1) ? SCS_17 : SCS_15;
+		smb[1] = (len > 1) ? SCS_18 : SCS_16;
 	}
 
 	if (len == 0) {

it works.
Is it correct?

Cannot import osdp library from python3.9

Describe the bug
After successfully building and installing the python library, error was encountered when trying to import the osdp library.

Expected behavior
The osdp library should be imported without error.

Observed behavior
When importing the osdp library via import osdp, below error is encountered:

➜  build git:(15) ✗ python3.9
Python 3.9.5 (default, May  4 2021, 03:36:27)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import osdp
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dlopen(/Users/dexinqi/Library/Python/3.9/lib/python/site-packages/osdp-1.5.0-py3.9-macosx-11-x86_64.egg/osdp.cpython-39-darwin.so, 2): Symbol not found: _hash32_djb2
  Referenced from: /Users/dexinqi/Library/Python/3.9/lib/python/site-packages/osdp-1.5.0-py3.9-macosx-11-x86_64.egg/osdp.cpython-39-darwin.so
  Expected in: flat namespace
 in /Users/dexinqi/Library/Python/3.9/lib/python/site-packages/osdp-1.5.0-py3.9-macosx-11-x86_64.egg/osdp.cpython-39-darwin.so

Additional context
I'm on macOS 11.4
This issues is encountered in version 771eae5, the current master.
This issues does not exist in release v1.4.0

ENFORCE_SECURE has no effect for PDs

When the enforce secure flag is set for PDs it has no real effect.
If a CP does not setup an encryption it will remain unencrypted.
a reasonable approach would be to only allow some unencrypted messages to be processes by the PD.
The ID, Capability and the encryption initialization messages would probably suffice.

Support install mode lock down for the CP

The install mode works well for the PD end today, however the CP will always switch to SCBK-D if SCBK do not work.
I think it would be good to have some sort of lock down flag to disallow both unencrypted and SCBK-D.

For application design it could be good enough to just pass that flag to osdp_cp_setup()

Resolve PD address / offset inconsistencies globally

Some places the PD is referred to with pd_info_t structure offsets. In others (when pd replies) pd address is sent as pd identifier.

For an application, the PD must always be identifiable with one integer.

Communication error when CP doesn't send 0xFF as the first character

I don't know if the 0xFF as first character is mandatory but the access control I'm using as CP sends it only after it has received it from the DP. I've resolved the problem adding it at the beginning of the buffer when the length of received buffer is 0 and the first character is not 0xFF.
I've done this also in an old library release.

Initiating Secure Channel in CP Mode

First off, thanks for the help to @patrick-compass with porting to FreeRTOS on a Cortex M4 on Issue 40. We are able to talk to multiple readers on a channel and move readers to a new PD address and 115,200 as well as detect cards and key presses.

Now we are trying to get a secure channel established -- first with the default SCBK after which we can then issue a osdp_KEYSET command with a new SCBK. I am working off of the current master -- cdf4627.

Unfortunately, the library returns an error: "CP: Failed to verify PD cryptogram".

I have a Veridt reader in its default state which a Veridt engineer assures me I should be able to use the SCBK-D to initiate a secure channel. It is my understanding from working with Veridt, that the reader needs be informed to use the SCBK-D via the osdp_CHLNG command.

I am hoping that this is a usage error on my part.

Describe the bug
I initiate a CP session and I set the OSDP_FLAG_ENFORCE_SECURE, OSDP_FLAG_INSTALL_MODE, and PD_FLAG_SC_USE_SCBKD flags in the PD info structure. I also set the pd_info->scbk to the SCBK-D, otherwise the session will fail and NULL is returned by osdp_cp_setup(). My call to osdp_cp_setup() gives NULL for the master_key as that is being deprecated by the spec.

Communication with the reader starts successfully with CMD_ID and CMD_CAP commands, but verification of the PD cryptogram fails.

Expected behavior
Secure Channel is established

Observed behavior
OSDP: ERROR: PD[0]: CP : Failed to verify PD cryptogram

Additional context

There is an issue with printf in the code handling the color coding, I apologize, but here is a debug output log:

.[32mOSDP: INFO : CP : CP setup complete
cmd> OSDP: PD[0]: Sent [zu] =>
    0000  0a 53 01 09 00 04 61 00  60 23                    |.S....a.`#      |
OSDP: PD[0]: Received [zu] =>
    0000  15 53 81 14 00 04 45 00  11 12 4d 42 30 31 31 30  |.S....E...MB0110|
    000zu  02 02 25 e5 21                                    |..%.!           |
.[0mOSDP: DEBUG: PD[0]: CP : CMD(61) REPLY(45)
.[0mOSDP: PD[0]: Sent [zu] =>
    0000  0a 53 01 09 00 05 62 00  03 41                    |.S....b..A      |
OSDP: PD[0]: Received [zu] =>
    0000  1c 53 81 38 00 05 46 01  01 02 03 03 00 04 04 01  |.S.8..F.........|
    000zu  04 02 06 05 01 01 06 01  00 07 02 00              |............    |
OSDP: PD[0]: Received [zu] =>
    0000  39 53 81 38 00 05 46 01  01 02 03 03 00 04 04 01  |.S.8..F.........|
    000zu  04 02 06 05 01 01 06 01  00 07 02 00 08 01 00 09  |................|
    000zu  11 00 0a 00 10 0b 00 10  0c 01 00 0d 01 01 0e 00  |................|
    000zu  00 0f 01 01 10 01 01 a7  f7                       |.........       |
.[0mOSDP: DEBUG: PD[0]: CP : CMD(62) REPLY(46)
.[0mOSDP: PD[0]: Sent [zu] =>
    0000  14 53 01 13 00 0e 03 11  01 76 00 b0 81 97 8e 60  |.S.......v.....`|
    000zu  41 35 ad ed                                       |A5..            |
OSDP: PD[0]: Received [zu] =>
    0000  23 53 81 2b 00 0e 03 12  01 76 00 11 12 4d 42 31  |.S.+.....v...MB1|
    000zu  31 30 95 9f 9a 98 99 99  99 99 26 0e 49 39 9a 02  |10........&.I9..|
    000zu  ca f4 14                                          |...             |
OSDP: PD[0]: Received [zu] =>
    0000  2c 53 81 2b 00 0e 03 12  01 76 00 11 12 4d 42 31  |.S.+.....v...MB1|
    000zu  31 30 95 9f 9a 98 99 99  99 99 26 0e 49 39 9a 02  |10........&.I9..|
    000zu  ca f4 14 7e cf 37 6b a1  a6 96 a6 c3              |...~.7k.....    |
.[31mOSDP: ERROR: PD[0]: CP : Failed to verify PD cryptogram
.[0m.[32mOSDP: INFO : PD[0]: CP : SC Failed. Set PD offline due to ENFORCE_SECURE

In debugging this, I've found that in the OSDP_CP_STATE_CAPDET, PD_FLAG_SC_USE_SCBKD is cleared and I'm not sure why. Because when the response arrives, osdp_compute_session_keys() doesn't use the SCBK-D, but generates the SCBK with osdp_compute_scbk(pd, ctx->sc_master_key, pd->sc.scbk);. However, If I force the used of SCBK-D in osdp_compute_session_keys(), I get the same result with failing to verify PD cryptogram.

However, if I comment out lines 928 and 929 of osdp_cp.c which clears the PD_FLAG_SC_USE_SCBKD, the reader responds with a NAK, even if I also force a 0 in writing to the SMB[2] byte in cp_build_command():

.[0mOSDP: PD[0]: Sent [zu] =>
    0000  14 53 01 13 00 0e 03 11  00 76 87 fe 43 1e 56 12  |.S.......v..C.V.|
    000zu  b9 f8 e8 e1                                       |....            |
OSDP: PD[0]: Received [zu] =>
    0000  0d 53 81 0c 00 0e 03 12  00 41 06 19 50           |.S.......A..P   |
.[33mOSDP: WARN : PD[0]: CP : PD replied with NAK(6) for CMD(76)
.[0m.[0mOSDP: DEBUG: PD[0]: CP : CMD(76) REPLY(41)
.[0m.[31mOSDP: ERROR: PD[0]: CP : CHLNG failed. Set PD offline due to ENFORCE_SECURE

From issue 40:

Implement SC methods osdp_encrypt(), osdp_decrypt() and osdp_get_rand() using some crypto library available in FreeRTOS.

Obviously, OpenSSL is not defined or used, so libOSDP is using hand written implementation of the above functions and I'm able to step through them.

Any help would be appreciated!

add mbedTLS support

I see the libosdp is already flexible in what crypto support functions it uses (OpenSSL, tiny-AES).
Actually our project evolves in the direction that we would have mbedTLS crypto library instead of OpenSSL in the (Linux) system.

It would be perfect to have mbedTLS as a third option for crypto functionality required by libosdp (AES, CMAC).

  • add option to use mbedTLS shared library (similar to the "find_package(OpenSSL)" cmake option)
  • fallback to integrated tiny-AES implementation if mbedTLS and OpenSSL is not available

osdpctl compile error

Unable to compile on master
Running into osdpctl build error on master. Please advise.

Steps followed from README,

git clone https://github.com/goToMain/libosdp --recurse-submodules
# git submodule update --init (if you missed doing --recurse-submodules earlier)
cd libosdp
mkdir build && cd build
cmake ..
make

Expected behavior
Clean build

Observed behavior
Running into the following error -

[ 70%] Building C object osdpctl/CMakeFiles/osdpctl.dir/cmd_start.c.o
/Users/libosdp/osdpctl/cmd_start.c:290:9: error: no member named 'scbk' in 'osdp_pd_info_t'
                info->scbk = NULL;
                ~~~~  ^
/Users/libosdp/osdpctl/cmd_start.c:307:13: error: no member named 'scbk' in 'osdp_pd_info_t'
                info_arr->scbk = scbk;
                ~~~~~~~~  ^
/Users/libosdp/osdpctl/cmd_start.c:308:37: error: too few arguments to function call, expected 2, have 1
                c->pd_ctx = osdp_pd_setup(info_arr);
                            ~~~~~~~~~~~~~         ^
/usr/local/include/osdp.h:642:1: note: 'osdp_pd_setup' declared here
osdp_t *osdp_pd_setup(osdp_pd_info_t * info, uint8_t *scbk);
^
3 errors generated.
make[2]: *** [osdpctl/CMakeFiles/osdpctl.dir/cmd_start.c.o] Error 1
make[1]: *** [osdpctl/CMakeFiles/osdpctl.dir/all] Error 2
make: *** [all] Error 2

Raw card data not accepted after a few minutes in secure mode

My peripheral device emulates a card reader and is connected to an access control system. If I connect them using the secure channel it works and the access control read the 'cards'. After some minutes while the communication is still working the access control doesn't read the 'cards'. I'm sure the PD is sending the 'card'. This problem doesn't happen with not encrypted mode.
It could be a problem of the access control but what do you think about it?
In the standard documentation they tell that if there is an error the keys are destroyed but how the secure channel is restored?

OSDP CP init should make sure that the SCBKs are different and non-zero.

Now the application can setup a CP with different SCBKs for each PD without passing a master key. But an ignorant programmer can pass the same SCBK buffer to all the PDs or worse, pass all zeros.

LibOSDP should do some preliminary checks on SCBK we receive from the user.

This issue was revealed from PR: #56

Porting libosdp to FreeRTOS

Would it be possible to port this library for using with FreeRTOS running on ARM MCU's?
Some embedded solutions which are looking to start implementing OSDP today are running task schedulers like FreeRTOS on small ARM Cortex-M0/M3/M4 cores.
I think it would be a nice feature to include an option/fork for building the library for these devices as well, especially the PD's which are most likely to run on cheaper MCU's.

REPLY_COM structure has address missing

According specification it should be:
case REPLY_COM:
buf[len++] = reply->id;
buf[len++] = p->address;
buf[len++] = byte_0(p->baud_rate);
buf[len++] = byte_1(p->baud_rate);
buf[len++] = byte_2(p->baud_rate);
buf[len++] = byte_3(p->baud_rate);
break;

OSDP_PD_SC_TIMEOUT_MS Value?

Describe the bug
Programmed 2 OSDP readers on OSDP Port 1.

Readers assigned addresses 0 and 2.
Reader address 0 is not connected.
Reader address 2 is PD based on libosdp.

The CP is sending CMD_POLL messages every 50-70ms to address 2 and then the CP sends a CMD_ID to address 0. The timing of CMD_POLL messages when the CMD_ID message is sent is > OSDP_PD_SC_TIMEOUT_MS (400ms).

Expected behavior
The CMD_POLL restarts at approximately 480ms so connection should not drop.

Observed behavior
Since the delay (480ms) is more than the OSDP_PD_SC_TIMEOUT_MS we call sc_deactivate().

https://pastebin.com/mCn2gNe7

A Comprehensive Log file

Added some timestamps when we update sc_tstamp to gather data. Extended OSDP_PD_SC_TIMEOUT_MS to 1000ms for the test:

https://pastebin.com/DL4qxgtU

Where does the value of OSDP_PD_SC_TIMEOUT_MS come from? I have OSDP Spec v2.1.6 and I don't see this number.

This is probably a CP issue in that the CMD_POLL messages shouldn't stop, but can we extend the OSDP_PD_SC_TIMEOUT_MS value and not violate the spec?

Tyco iSTAR Edge G2 with firmware 6.8.5.22814

Support multi-drop on same channel

OSDP is a multi-drop protocol designed for RS-485 where multiple PD can be connected to the same two wires.
The CP part of libosdp does not support running multiple PDs over the same interface since the channel is unique for each PD.
I don't know how this library is and will be used but I'm guessing most people will have 1 CP and 1 PD. If they have multiple PD they will likely use the same interface.

I see two solutions to supporting multiple PDs on the same channel.

  1. Change so only one channel is supported. This simplifies the code but it might be harder to emulate multiple PDs using message queues and similar.
  2. Add a channel ID so that libosdp knows if two PDs share the same communication channel.

For both these solution an ownership token have to be used to determine which PD that owns the communication channel.
This can be implemented in cp_phy_state_update() where OSDP_CP_ERR_INPROG can be returned if the channel is busy and if it is not and osdp_cmd_dequeue returns a command to send out it should take the ownership of the channel. The channel ownership is dropped when a reply is received or when an error occurs.

Because of the design of osdp_cp_refresh() each PD will get equal "air time". So no channel scheduling had to be done.

the link is broken

the link to protocol design documents in the intro is broken. can it be restored?

Add support for C++

LibOSDP must provide classes for CP and PD mode suitable for use in CPP projects.

OSM-1000-BRD as PD gets packet seq mismatch

PACKET: FF 53 80 14 00 04 45 CA 44 6C 01 00 C7 92 02 00 01 07 0F C4 42
PACKET: FF 53 80 23 00 05 46 01 01 02 02 01 01 03 01 00 04 02 01 08 01 00 09 01 01 0A 00 02 0D 00 01 10 01 00 D9 08
PACKET: FF 53 80 09 00 06 41 06 A0 BA
OSDP: ERROR: PD[0]: PD replied with NAK(6) for command 76
OSDP: ERROR: PD[0]: CHLNG failed. Online without SC

PACKET: FF 53 80 09 00 06 41 06 A0 BA
OSDP: ERROR: PD[0]: PHY: packet seq mismatch 3/2

Adding pd->seq_number = -1; to the referenced section below fixes this for me, however I am looking for a proper fix.

libosdp/src/osdp_cp.c

Lines 937 to 941 in 569e4c7

} else {
LOG_ERR("CHLNG failed. Online without SC");
pd->sc_tstamp = osdp_millis_now();
cp_set_state(pd, OSDP_CP_STATE_ONLINE);
}

Multiple PD’s in a single piece of code

The basic issue is that I am wanting to write some code that interfaces to an alarm system with an OSDP bus, and have my code implement four PD’s. As far as I can tell, all the code assumes a single PD per instance.

Running multiple instances of the code, or using multiple instances of the library could work I guess but I am assuming this would involve ‘connections’ to the serial port which depending on platform would be exclusive to a single connection.

Assuming this is an enhancement, I am not sure what the cleanest way to implement this would be. Thanks.

Bump OSDP specification supported version to IEC Edition 1.0

LibOSDP release v1.5.0 (inclusive) is based on v2.1.6 of the OSDP Specification. A later version of OSDP (v2.1.7 or IEC Edition 1.0) was released and this is a tracking issue for all changes that were introduced in that version.

  • Add support for additional baud rates
  • Allow CP app to send SCBK directly for each PD during cp_setup()
  • Add support for file transfer command #24

Add a in-library post command callback mechanism to perform success/failure actions

A lot of times, we need to perform some actions based on whether a command succeeded or failed. Since there are 2 level state machines (very messy) in osdp_cp.c, we have no way of performing some post success/failure operations for commands that got queued from the applications.

Note that this is not the same as command_complete_callback that exists today (which is for notifying the application). This issue is to track a in-library notifier. One prominent user case for this handler is when the application wants to set SCBK directly without a master_key; if that succeeds, LibOSDP must set the PD_FLAG_HAD_SCBK on the PD so this key can survive secure channel resets.

SC Failed from Install - Release 1.5.0

Describe the bug
Another test with 2 instances of OSDPCTL talking to each other over RS-485.

My configuration had an SCBK from running 1.4.0 and everything worked fine. If I start from INSTALL_MODE it fails with timeouts (CP) and invalid SOM errors (PD).

Expected behavior
Negotiate SCBK without constant failures and retries.

Observed behavior
CP Log:
OSDP: INFO : CP : CP setup complete
OSDP: ERROR: PD[0]: CP : Failed to verify PD cryptogram
OSDP: WARN : PD[0]: CP : SC Failed. Retry with SCBK-D
OSDP: WARN : PD[0]: CP : SC ACtive with SCBK-D. Set SCBK
OSDP: ERROR: PD[0]: CP : Response timeout for CMD(75)
OSDP: ERROR: PD[0]: CP : Failed to verify PD cryptogram
OSDP: WARN : PD[0]: CP : SC Failed. Retry with SCBK-D
OSDP: WARN : PD[0]: CP : SC ACtive with SCBK-D. Set SCBK
OSDP: ERROR: PD[0]: CP : Response timeout for CMD(75)
OSDP: ERROR: PD[0]: CP : Failed to verify PD cryptogram
OSDP: WARN : PD[0]: CP : SC Failed. Retry with SCBK-D
OSDP: WARN : PD[0]: CP : SC ACtive with SCBK-D. Set SCBK
OSDP: ERROR: PD[0]: CP : Response timeout for CMD(75)

PD Log:
OSDP: WARN : PD[0]: PD : SCBK not provided. PD is in INSTALL_MODE
OSDP: INFO : PD[0]: PD : PD setup complete
OSDP: DEBUG: PD[0]: PD : CMD: 61 REPLY: 45
OSDP: DEBUG: PD[0]: PD : CMD: 62 REPLY: 46
OSDP: DEBUG: PD[0]: PD : CMD: 76 REPLY: 76
OSDP: DEBUG: PD[0]: PD : CMD: 76 REPLY: 76
OSDP: DEBUG: PD[0]: PD : CMD: 77 REPLY: 78
OSDP: WARN : PD[0]: PD : SC Active with SCBK-D
OSDP: ERROR: PD[0]: PHY: Invalid SOM 0xb6
OSDP: ERROR: PD[0]: PD : CMD receive error/timeout - err:-1
OSDP: DEBUG: PD[0]: PD : CMD: 61 REPLY: 45
OSDP: DEBUG: PD[0]: PD : CMD: 62 REPLY: 46
OSDP: DEBUG: PD[0]: PD : CMD: 76 REPLY: 76
OSDP: DEBUG: PD[0]: PD : CMD: 76 REPLY: 76
OSDP: DEBUG: PD[0]: PD : CMD: 77 REPLY: 78
OSDP: WARN : PD[0]: PD : SC Active with SCBK-D
OSDP: ERROR: PD[0]: PHY: Invalid SOM 0x70
OSDP: ERROR: PD[0]: PD : CMD receive error/timeout - err:-1
OSDP: DEBUG: PD[0]: PD : CMD: 61 REPLY: 45
OSDP: DEBUG: PD[0]: PD : CMD: 62 REPLY: 46
OSDP: DEBUG: PD[0]: PD : CMD: 76 REPLY: 76
OSDP: DEBUG: PD[0]: PD : CMD: 76 REPLY: 76
OSDP: DEBUG: PD[0]: PD : CMD: 77 REPLY: 78
OSDP: WARN : PD[0]: PD : SC Active with SCBK-D
OSDP: ERROR: PD[0]: PHY: Invalid SOM 0xa3
OSDP: ERROR: PD[0]: PD : CMD receive error/timeout - err:-1

Attached traces of 1.4.0 and 1.5.0 from INSTALL_MODE.

Additional context
Stock 1.5.0 build with 369f3e8 picked up for the Command slab allocation failed issue.

Tried master, but it doesn't currently build ... want to stick with a release.
OSDP Trace.pdf

OSDP: ERROR: PD[0]: PHY: Invalid MAC; discarding SC

Describe the bug
Enabled SC with a commercial CP. Negotiates channel properly then fails and loops forever in failure mode.

Expected behavior
Not sure what isn't working to be honest.

Observed behavior
libosdp-1.5.0 [master (7190302+)]
OSDP: WARN : PD[0]: PD: SCBK not provided. PD is in INSTALL_MODE
OSDP: PD: Setup complete - libosdp-1.5.0 master (7190302+)
OSDP: DEBUG: PD[0]: PD: CMD: ID(61) REPLY: PDID(45)
OSDP: DEBUG: PD[0]: PD: CMD: CAP(62) REPLY: PDCAP(46)
OSDP: DEBUG: PD[0]: PD: CMD: CHLNG(76) REPLY: CCRYPT(76)
OSDP: DEBUG: PD[0]: PD: CMD: CHLNG(76) REPLY: CCRYPT(76)
OSDP: DEBUG: PD[0]: PD: CMD: CHLNG(76) REPLY: CCRYPT(76)
OSDP: DEBUG: PD[0]: PD: CMD: SCRYPT(77) REPLY: RMAC_I(78)
OSDP: WARN : PD[0]: PD: SC Active with SCBK-D
CP: CMD_ID: 5 OSDP: DEBUG: PD[0]: PD: CMD: KEYSET(75) REPLY: ACK(40)

OSDP: DEBUG: PD[0]: PD: CMD: ID(61) REPLY: PDID(45)
OSDP: DEBUG: PD[0]: PD: CMD: CAP(62) REPLY: PDCAP(46)
OSDP: DEBUG: PD[0]: PD: CMD: CHLNG(76) REPLY: CCRYPT(76)
OSDP: DEBUG: PD[0]: PD: CMD: SCRYPT(77) REPLY: RMAC_I(78)
OSDP: INFO : PD[0]: PD: SC Active
OSDP: DEBUG: PD[0]: PD: CMD: LSTAT(64) REPLY: LSTATR(48)
OSDP: INFO : PD[0]: PD: PD is not capable of handling CMD: BUZ(6a); Reply with NAK_CMD_UNKNOWN
OSDP: DEBUG: PD[0]: PD: CMD: BUZ(6a) REPLY: NAK(41)
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: Invalid MAC; discarding SC
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!

OSDP: DEBUG: PD[0]: PD: CMD: ID(61) REPLY: PDID(45)
OSDP: DEBUG: PD[0]: PD: CMD: CAP(62) REPLY: PDCAP(46)
OSDP: DEBUG: PD[0]: PD: CMD: CHLNG(76) REPLY: CCRYPT(76)
OSDP: DEBUG: PD[0]: PD: CMD: SCRYPT(77) REPLY: RMAC_I(78)
OSDP: INFO : PD[0]: PD: SC Active
OSDP: DEBUG: PD[0]: PD: CMD: LSTAT(64) REPLY: LSTATR(48)
OSDP: INFO : PD[0]: PD: PD is not capable of handling CMD: BUZ(6a); Reply with NAK_CMD_UNKNOWN
OSDP: DEBUG: PD[0]: PD: CMD: BUZ(6a) REPLY: NAK(41)
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: Invalid MAC; discarding SC
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[0]: PHY: seq-repeat/reply-resend not supported!

pastebin with all debug turned on: https://pastebin.com/cVz5pf4x

Additional context
OPENSSL_ROOT_DIR=/usr/local/opt/openssl cmake -DCONFIG_OSDP_PACKET_TRACE=ON -DCONFIG_OSDP_DATA_TRACE=ON ..
Definitely building master, only disabled python in CMakeLists.txt

osdp_phy_check_packet return value for incorrect PD

Return value of osdp_phy_check_packet in case a PD receives command poll command that is not intended it for i.e. meant for a different PD, shouldn't the following code block check for ISSET_FLAG(pd, PD_FLAG_PD_MODE) instead of !ISSET_FLAG(pd, PD_FLAG_PD_MODE) ?

  /* validate PD address */
  pd_addr = pkt->pd_address & 0x7F;
  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);
      return OSDP_ERR_PKT_FMT;
    }
    return OSDP_ERR_PKT_SKIP;
  }

Self adapting to mark or not mark

To manage mark or not mark condition (I've both on the same connection) and without change too much your software I've modified osdp_cp.c (v1.3.0) in this way:

  • if (was_empty && rec_bytes > 0) {
    /* Start of message */
    pd->tstamp = osdp_millis_now();
    }

    if (was_empty && (buf[0] != 0xFF)) {
    memmove(&buf[1], &buf[0], rec_bytes);
    buf[0] = 0xFF;
    rec_bytes++;
    }

    pd->rx_buf_len += rec_bytes;

    if (IS_ENABLED(CONFIG_OSDP_PACKET_TRACE)) {

I think you could do better.
I cannot use the CONFIG_OSDP_SKIP_MARK_BYTE switch because I've both the conditions.

OSDPCTL PD Mode - Command slab allocation failed

Describe the bug
Upgraded from Release 1.4.0 to Release 1.5.0 and ran a simple test with 2 instances of OSDPCTL talking to each other over RS-485.

After initial exchange the CP side will always fail with Command slab allocation failed.

Expected behavior
CP Mode should not have Command slab allocation failed.

Observed behavior

OSDP: INFO : CP : CP setup complete
OSDP: PD[0]: Sent [10] =>
0000 ff 53 00 09 00 04 61 00 c0 66 |.S....a..f |
OSDP: PD[0]: Received [21] =>
0000 ff 53 80 14 00 04 45 99 00 00 01 01 d2 04 00 00 |.S....E.........|
0016 00 00 10 00 57 |....W |
OSDP: PD[0]: Sent [10] =>
0000 ff 53 00 09 00 05 62 00 a3 04 |.S....b... |
OSDP: PD[0]: Received [1] =>
0000 ff |. |
OSDP: PD[0]: Received [9] =>
0000 ff 53 80 08 00 05 46 ae ff |.S....F.. |
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
OSDP: ERROR: PD[0]: CP : Command slab allocation failed
.
.

Additional context
Modified the PD side (osdp_pd.c) to not have any implicit capabilities (don't report we support secure channel) but otherwise the code is fresh build of Release 1.5.0.

Also tried building with the latest code and the same CP Mode Command slab allocation failed happens.

PD does not reset connection when CP sends sequence number 0

This is a placeholder for issue reported by Jonathan (by email).

OSDP: ERROR: PHY: packet seq mismatch 3/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet length mismatch 10/8
OSDP: ERROR: PHY: packet seq mismatch 1/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet length mismatch 10/9
OSDP: ERROR: PHY: packet seq mismatch 2/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet seq mismatch 3/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet length mismatch 10/0
OSDP: ERROR: PHY: packet seq mismatch 1/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet length mismatch 10/1
OSDP: ERROR: PHY: packet seq mismatch 2/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet seq mismatch 3/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet length mismatch 10/5
OSDP: ERROR: PHY: packet seq mismatch 1/0
OSDP: ERROR: PD: failed to decode packet
OSDP: ERROR: PHY: packet seq mismatch 2/0
OSDP: ERROR: PD: failed to decode packet

AES-128 padding for packet length % 16 == 0

In OSDP V2 1_6_2014 - Appendix D.4.5 Padding is specified that
padding is necessary also if the data block is multiple of 16.
At the moment in the library there is no padding if length % 16 == 0.

Python import error, undefined symbol: EVP_DecryptFinal_ex

Greetings.

I'm having some problems with getting the python module to work.

It builds and installs with no problem, but when i try to run following in python:

python3 -c "import osdp; print(\"pyosdp\", \"Version:\", osdp.get_version());"

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: /usr/local/lib/python3.6/dist-packages/osdp-1.3.0-py3.6-linux-x86_64.egg/osdp.cpython-36m-x86_64-linux-gnu.so: undefined symbol: EVP_DecryptFinal_ex

Any clue to what might cause this error?

This is on a fresh ubuntu 18.04 install, with the following done to make it build:
sudo apt-get install cmake
sudo apt-get install build-essential
sudo apt-get install libssl-dev
sudo apt-get install python3-sphinx
sudo apt-get install python3.6-dev
sudo apt-get install python3-pip
pip3 install setuptools

Issues trying to use OSDP with an InnerRange Inception

I am attempting to use LibOSDP with an InnerRange Exception alarm system. I have compiled the library, with some changes onto the STM32 using the Arduino ecosystem.

The exact code I am running lives in the following repositories:
* https://github.com/vk2tds/libosdp_pd
* https://github.com/vk2tds/libosdp_arduino

The PD is configured in Install Mode (PD is in INSTALL_MODE)

The PD that I am creating has the ID number of 1. There is an existing device that has the ID number of 0. The full debug log can be found at the following link: (https://pastebin.com/6FgGWAar). Looking at the appropriate lines, it appears that a SC session is created, and then things stop working. Alas, I am not familiar enough with the internal workings of the protocol to know what should be going on.

OSDP: DEBUG: PD[1]: PD: CMD: CHLNG(76) REPLY: CCRYPT(76)
OSDP: DEBUG: PD[1]: PD: CMD: SCRYPT(77) REPLY: RMAC_I(78)
OSDP: WARN : PD[1]: PD: SC Active with SCBK-D
OSDP: DEBUG: PD[1]: PD: CMD: ID(61) REPLY: PDID(45)
OSDP: INFO : PD[1]: PD: PD SC session timeout!
OSDP: ERROR: PD[1]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[1]: PHY: seq-repeat/reply-resend not supported!
OSDP: ERROR: PD[1]: PD: CMD receive error/timeout - err:-1

The pastebin was created using the following PD_CAP

      .function_code = OSDP_PD_CAP_COMMUNICATION_SECURITY,
      .compliance_level = 0, // Try 1 later
      // more doc/libosdp/secure-channel.rst
      .num_items = 0
    },

NOTE: I also tried with compliance_level=1. The capture can be found at https://pastebin.com/0guBD9zy

Any hints in getting this working would be appreciated. Thanks.

integrating into yocto.

Hello,
I'm trying to integrate the library into a yocto cmake project as it's instructed in user manual. the problem is that I'm able to compile the same project in ubuntu and manually cross compile it for the target. but when it comes to yocto bitbake, it fails because it's compiling the libosdp for the host, not for target.
does anyone have any idea about it?

PD behaviour in secure mode for commands with no defined command structure

Describe the bug
The secure session gets discarded due to "failed" decryption upon receiving commands that have no command structure defined in the spec. Such commands are LSTAT, OSTAT, RSTAT, ISTAT. These simply instruct the PD to reply based on the command code.

Expected behavior
Secure mode should not be discarded

Observed behavior
It is observed that secure session gets discarded when PD receives CMD_LSTAT in secure mode, due to decrypt function osdp_decrypt_data returning 0.

Additional context
Looking at the spec, the commands LSTAT, OSTAT, RSTAT, ISTAT have no command structure (i.e. no data to go along with the command), and could potentially have no decrypted data to work with. I think this is why returned length from osdp_decrypt_data is 0. Because the caller in osdp_phy_decode_packet considers 0 return value to be a failure scenario, this causes a secure session reset.

To be more specific, the decrypted data block for LSTAT looks like 80000000000000000000000000000000 which indicates that there is no data available, just the padding 0x80 to indicate end of message. So I don't think it is necessary to fail here.

I propose either removing the equality condition for all, or making an exception for just those four commands.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.