Skip to content

Commit

Permalink
misc: dissector: Add support for data tracer
Browse files Browse the repository at this point in the history
Signed-off-by: Siddharth Chandrasekaran <[email protected]>
  • Loading branch information
sidcha committed Feb 17, 2024
1 parent f362833 commit 571e384
Showing 1 changed file with 98 additions and 60 deletions.
158 changes: 98 additions & 60 deletions misc/osdp_dissector.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,43 @@
--
-- SPDX-License-Identifier: Apache-2.0

local malformed_error = ProtoExpert.new("Error.Malformed", "Malformed Packet", expert.group.MALFORMED, expert.severity.ERROR)

-- Header
local header = ProtoField.new("Header", "OSDP.Header", ftypes.BYTES)
local header = ProtoField.new("OSDP Header", "OSDP.Header", ftypes.BYTES)
local mark = ProtoField.uint8("OSDP.Mark", "Mark byte", base.HEX)
local som = ProtoField.uint8("OSDP.SOM", "Start of message", base.HEX)
local type = ProtoField.new("Message Type", "OSDP.MessageType", ftypes.UINT8,
{ [0] = "Command", [1] = "Reply" }, base.NONE, 0x80)
local address = ProtoField.uint8("OSDP.Address", "PD Address", base.DEC, nil, 0x7f)
local type = ProtoField.new("Message Type", "OSDP.MessageType", ftypes.UINT8, { [0] = "Command", [1] = "Reply" }, base.NONE, 0x80)
local address = ProtoField.new("PD Address", "OSDP.Address", ftypes.UINT8, nil, base.DEC, 0x7f)
local length = ProtoField.uint16("OSDP.Length", "Packet Length", base.DEC)
local control = ProtoField.uint16("OSDP.Control", "Packet Control", base.DEC)

local control = ProtoField.new("Packet Control", "OSDP.Control", ftypes.UINT8, nil, base.HEX)
local control_sequence = ProtoField.new("Sequence", "OSDP.Control.Sequence", ftypes.UINT8, nil, base.DEC, 0x03)
local control_check = ProtoField.new("Integrity Check", "OSDP.Control.IC", ftypes.UINT8, { [0] = "Checksum", [1] = "CRC-16" }, base.NONE, 0x04)
local control_scb = ProtoField.new("Secure Control Block", "OSDP.Control.SCB", ftypes.UINT8, { [0] = "Absent", [1] = "Present" }, base.NONE, 0x08)
local control_trace = ProtoField.new("Capture Type", "OSDP.Control.Trace", ftypes.UINT8, { [0] = "Original", [1] = "Mangled" }, base.NONE, 0x80)

-- Entire payload
local payload = ProtoField.new("Payload", "OSDP.Payload", ftypes.BYTES)
local payload = ProtoField.new("OSDP Payload", "Payload", ftypes.BYTES)

-- SC sub entries
local scb = ProtoField.new("Secure Channel Block", "OSDP.SCB", ftypes.BYTES)
local sc_data = ProtoField.new("Enctrypted Data Block", "OSDP.SC_DATA", ftypes.BYTES)
local sc_mac = ProtoField.new("Message Authentication Code", "OSDP.SC_MAC", ftypes.BYTES)
local scb = ProtoField.new("Secure Channel Block", "SCB", ftypes.BYTES)
local sc_data = ProtoField.new("Enctrypted Data Block", "SC_DATA", ftypes.BYTES)
local sc_mac = ProtoField.new("Message Authentication Code", "SC_MAC", ftypes.BYTES)

-- Plaintext sub entries
local plaintext_id = ProtoField.uint8("OSDP.PlainText.ID", "Command/Reply ID", base.HEX)
local plaintext_data = ProtoField.new("Command/Reply Data", "OSDP.PlainText.Data", ftypes.BYTES)
local plaintext_id = ProtoField.uint8("PlainText.ID", "Command/Reply ID", base.HEX)
local plaintext_data = ProtoField.new("Command/Reply Data", "PlainText.Data", ftypes.BYTES)

-- Checksum/CRC16
local packet_check = ProtoField.new("CheckSum", "OSDP.CheckSum", ftypes.BYTES)

-- Helper methods
function ControlString(control_byte)
local str = "SEQ: " .. tostring(bit32.band(control_byte, 0x3))
if bit32.band(control_byte, 0x4) == 0x4 then
str = str .. ", CRC16"
else
str = str .. ", CHECKSUM"
end
if bit32.band(control_byte, 0x8) == 0x8 then
str = str .. ", SCB"
end
return str
end
local packet_check = ProtoField.new("CheckSum", "CheckSum", ftypes.BYTES)

-- Protocol definition
local osdp_protocol = Proto("OSDP", "Open Supervised Device Protocol")
osdp_protocol.fields = {
header,
mark, som, type, address, length, control,
mark, som, type, address, length,
control, control_sequence, control_check, control_scb, control_trace,

payload,
scb, sc_data, sc_mac,
Expand All @@ -57,66 +50,109 @@ osdp_protocol.fields = {
-- Protocol disector
function osdp_protocol.dissector(buffer, pinfo, tree)
local packet_length = buffer:len()
if length == 0 then return end
if length == 0 then
tree:add_proto_expert_info(malformed_error)
return
end

local packet_header_len = 6
local packet_mac_len = 4
local packet_check_len = 1
local has_mark = false;
local first_byte = buffer(0, 1):uint()
if first_byte == 0xFF then
has_mark = true;
else
if first_byte ~= 0x53 then
tree:add_proto_expert_info(malformed_error)
return
end
end
local packet_header_len = 5
local pos = 0

if has_mark then
packet_header_len = 6
pos = 1
end

local control_byte = buffer(pos + 4, 1):uint()
local has_crc16 = bit32.band(control_byte, 0x04) == 0x04
local has_scb = bit32.band(control_byte, 0x08) == 0x08
local trace_mangled = bit32.band(control_byte, 0x80) == 0x80

if has_crc16 then
packet_check_len = 2
end
if trace_mangled then
packet_check_len = 0
end

local subtree = tree:add(osdp_protocol, buffer(0, packet_length), "OSDP Packet")

-- Packet header
local header_subtree = subtree:add(header, buffer(0, packet_header_len))
header_subtree:add(mark, buffer(0, 1))
header_subtree:add(som, buffer(1, 1))
header_subtree:add(type, buffer(2, 1))
header_subtree:add(address, buffer(2, 1))
header_subtree:add_le(length, buffer(3, 2))
local control_byte = buffer(5, 1):uint()
header_subtree:add(control, buffer(5, 1))
:append_text(" (" .. ControlString(control_byte) .. ")")

if bit32.band(control_byte, 0x04) == 0x04 then
packet_check_len = 2
if has_mark then
header_subtree:add(mark, buffer(0, 1))
end
header_subtree:add(som, buffer(pos + 0, 1))
header_subtree:add(type, buffer(pos + 1, 1))
header_subtree:add(address, buffer(pos + 1, 1))
header_subtree:add_le(length, buffer(pos + 2, 2))

local control_subtree = header_subtree:add(control, buffer(pos + 4, 1))
control_subtree:add(control_sequence, buffer(pos + 4, 1))
control_subtree:add(control_check, buffer(pos + 4, 1))
control_subtree:add(control_scb, buffer(pos + 4, 1))
control_subtree:add(control_trace, buffer(pos + 4, 1))

pinfo.cols.protocol = osdp_protocol.name
local pd_address = bit32.band(buffer(2, 1):uint(), 0x7f)
if bit32.band(buffer(2, 1):uint(), 0x80) == 0x80 then
pinfo.cols.src = "PD[" .. tostring(pd_address) .. "]"
pinfo.cols.dst = "CP"
else
local pd_address = bit32.band(buffer(pos + 1, 1):uint(), 0x7f)
local is_cmd = bit32.band(buffer(pos + 1, 1):uint(), 0x80) ~= 0x80
if is_cmd then
pinfo.cols.src = "CP"
pinfo.cols.dst = "PD[" .. tostring(pd_address) .. "]"
else
pinfo.cols.src = "PD[" .. tostring(pd_address) .. "]"
pinfo.cols.dst = "CP"
end

-- payload
local offset = packet_header_len
local payload_len = packet_length - packet_header_len - packet_check_len

local payload_subtree = subtree:add(payload, buffer(offset, payload_len))
if bit32.band(control_byte, 0x08) == 0x08 then
if has_scb then
-- Secure Control Block
local scb_len = buffer(offset, 1):uint()
local scb_type = buffer(offset + 1, 1):uint()
local scs_type_name = "SCS_" .. string.format("%x", scb_type)

payload_subtree:add(plaintext_id, buffer(offset + scb_len, 1))
local scb_subtree = payload_subtree:add(scb, buffer(offset, scb_len))
:append_text(" (SCS_" .. string.format("%x", scb_type) .. ")")

offset = offset + scb_len
payload_len = payload_len - scb_len
payload_subtree:add(plaintext_id, buffer(offset + scb_len, 1))

-- Secure Data Block
print("Secure Data Block: offset: " .. offset .. " payload_len: " .. payload_len)
if scb_type >= 0x15 then
if scb_type == 0x17 or scb_type == 0x18 then
-- +1 and -1 below are to skip the Command/Response ID
scb_subtree:add(sc_data, buffer(offset + 1, payload_len - 1))
-- +1 and -1 below are to skip the Command/Response ID
offset = offset + scb_len + 1
payload_len = payload_len - scb_len - 1
local info = "Seure Message"
if scb_type < 0x15 then
info = "SC Handshake"
end
if trace_mangled then
-- This message was mangled by data tracer to have SCB but no
-- encrypted data so we add them as is.
payload_subtree:add(plaintext_data, buffer(offset, payload_len))
info = "Decrypted " .. info
else
-- Secure Data Block
if scb_type >= 0x15 then
if scb_type == 0x17 or scb_type == 0x18 then
scb_subtree:add(sc_data, buffer(offset, payload_len))
info = info .. " with Data"
end
scb_subtree:add(sc_mac, buffer(offset + payload_len - packet_mac_len, packet_mac_len))
end
scb_subtree:add(sc_mac, buffer(offset + payload_len - packet_mac_len, packet_mac_len))
end
pinfo.cols.info = "Seure Message"
pinfo.cols.info = info .. " (" .. scs_type_name .. ")"
else
-- Plain text block
payload_subtree:add(plaintext_id, buffer(offset, 1))
Expand All @@ -126,5 +162,7 @@ function osdp_protocol.dissector(buffer, pinfo, tree)
end

-- Packet check
subtree:add(packet_check, buffer(packet_length - packet_check_len, packet_check_len))
if packet_check_len > 0 then
subtree:add(packet_check, buffer(packet_length - packet_check_len, packet_check_len))
end
end

0 comments on commit 571e384

Please sign in to comment.