osdp

package
v0.577.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2026 License: AGPL-3.0 Imports: 3 Imported by: 0

Documentation

Overview

Package osdp decodes OSDP (Open Supervised Device Protocol) packets — the SIA / IEC 60839-11-5 serial protocol that modern physical-access- control readers speak to their controllers (the secure successor to Wiegand). An OSDP bus dump is a sequence of these packets; dissecting them shows the poll/reply traffic, the card-read replies, the secure-channel handshake and any integrity failures — the staple of an access-control pentest / bus tap.

Wrap-vs-native judgement

Native. The OSDP packet is a fixed little-endian frame — optional
0xFF driver mark, 0x53 start-of-message, address byte (bit 7 =
reply direction, low 7 = PD address), 16-bit length, a control
byte (2-bit sequence number, CRC-vs-checksum flag, security-block
flag), an optional security control block, the command/reply code,
the data, and a trailer that is either a CRC-16/AUG-CCITT
(poly 0x1021, init 0x1D0F) or a 1-byte two's-complement checksum.
All of that is pure byte-field extraction plus one standard CRC,
so it is reimplemented here from the libosdp reference rather than
wrapped — no new dependency, no shell-out.

What this covers

  • The full packet frame: mark / SOM / address (+ direction + PD address) / length / control (sequence number, CRC-or-checksum mode, secure-channel-block presence).
  • The security control block (length + type + type meaning) when present — the secure-channel handshake markers SCS_11..SCS_18.
  • The command (CP->PD) and reply (PD->CP) code with its name.
  • NAK replies: the error code with its meaning.
  • Trailer integrity: the CRC-16/AUG-CCITT or checksum is recomputed and reported as valid / invalid.
  • Typed reply payloads for the codes with a well-defined plaintext layout: osdp_RAW (card-read reader / format / bit-count / card data — the actual badge), osdp_PDID (vendor / model / version / serial / firmware device fingerprint), osdp_COM (address + baud rate), osdp_KEYPAD (PIN key presses) and osdp_LSTATR (tamper + power). Their wire layouts are ported from the libosdp reference reply builder; see payload.go.

Deliberately deferred

Command (CP->PD) payload field decode (osdp_LED / BUZ / OUT / TEXT
parameters) is not broken out — the data is surfaced as hex and the
code name identifies it. Secure-channel-encrypted payloads
(SCS_17/18) cannot be decrypted without the session keys and are
surfaced as ciphertext.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CardRead added in v0.535.0

type CardRead struct {
	ReaderNo    int    `json:"reader_no"`
	Format      int    `json:"format"`
	FormatName  string `json:"format_name"`
	BitCount    int    `json:"bit_count"`
	CardDataHex string `json:"card_data_hex,omitempty"`
}

CardRead is the osdp_RAW (0x50) card-read reply payload.

type ComConfig added in v0.535.0

type ComConfig struct {
	Address  int    `json:"address"`
	BaudRate uint32 `json:"baud_rate"`
}

ComConfig is the osdp_COM (0x54) communication-configuration reply.

type DeviceID added in v0.535.0

type DeviceID struct {
	VendorCode      string `json:"vendor_code"` // 24-bit OUI
	Model           int    `json:"model"`
	Version         int    `json:"version"`
	SerialNumber    uint32 `json:"serial_number"`
	FirmwareVersion string `json:"firmware_version"`
}

DeviceID is the osdp_PDID (0x45) device-identification reply payload.

type Keypad added in v0.535.0

type Keypad struct {
	ReaderNo  int    `json:"reader_no"`
	Length    int    `json:"length"`
	KeysHex   string `json:"keys_hex,omitempty"`
	KeysASCII string `json:"keys_ascii,omitempty"`
}

Keypad is the osdp_KEYPAD (0x53) key-press reply payload.

type LocalStatus added in v0.535.0

type LocalStatus struct {
	Tamper int `json:"tamper"`
	Power  int `json:"power"`
}

LocalStatus is the osdp_LSTATR (0x48) local-status reply payload.

type Result

type Result struct {
	HasMark        bool   `json:"has_mark"`
	AddressByte    string `json:"address_byte"`
	PDAddress      int    `json:"pd_address"`
	Broadcast      bool   `json:"broadcast"`
	Direction      string `json:"direction"` // "command (CP->PD)" / "reply (PD->CP)"
	Length         int    `json:"length"`
	SequenceNumber int    `json:"sequence_number"`
	CheckMode      string `json:"check_mode"` // "crc" / "checksum"

	SecureBlock *SecureBlock `json:"secure_block,omitempty"`

	Code     string `json:"code"`
	CodeName string `json:"code_name"`
	DataHex  string `json:"data_hex,omitempty"`

	NAKError     *int   `json:"nak_error_code,omitempty"`
	NAKErrorName string `json:"nak_error_name,omitempty"`

	// Decoded reply payloads (PD->CP), when the code has a well-defined
	// plaintext layout (ported from the libosdp reference; see payload.go).
	CardRead    *CardRead    `json:"card_read,omitempty"`
	DeviceID    *DeviceID    `json:"device_id,omitempty"`
	ComConfig   *ComConfig   `json:"com_config,omitempty"`
	Keypad      *Keypad      `json:"keypad,omitempty"`
	LocalStatus *LocalStatus `json:"local_status,omitempty"`

	TrailerHex      string `json:"trailer_hex"`
	TrailerComputed string `json:"trailer_computed"`
	TrailerValid    bool   `json:"trailer_valid"`

	Notes []string `json:"notes,omitempty"`
}

Result is the decoded view of one OSDP packet.

func Decode

func Decode(hexStr string) (*Result, error)

Decode parses one OSDP packet from hex. Accepts an optional leading 0xFF driver mark and ':'/'-'/'_'/whitespace separators.

type SecureBlock

type SecureBlock struct {
	Length   int    `json:"length"`
	Type     string `json:"type"`
	TypeName string `json:"type_name"`
	DataHex  string `json:"data_hex,omitempty"`
}

SecureBlock is the decoded security control block.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL