Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
774b566
Dissecto DIFFs
polybassa Feb 2, 2023
3d33033
update documentation
polybassa May 24, 2024
ec50fb1
use python scm way to generate versions
polybassa May 24, 2024
96df2d5
fix spellcheck
polybassa May 24, 2024
07e02c5
testing new versioning
polybassa May 24, 2024
b22ee42
Fix the newest codespell update (#4400)
polybassa May 31, 2024
5251582
fix spellcheck
polybassa May 24, 2024
2e9e136
Disable debug message
polybassa Jun 7, 2024
91cf7b8
fix flake
polybassa Jul 11, 2024
f4ffdd2
Remove log message
polybassa Jul 11, 2024
85253e9
Initial plan
Copilot Feb 9, 2026
4b31297
Implement CBOR parser following ASN.1 paradigm
Copilot Feb 9, 2026
9f76719
Address code review comments: improve error messages and implement pr…
Copilot Feb 9, 2026
46d1e1e
Add cbor2 interoperability tests (cbor2 used ONLY in tests)
Copilot Feb 11, 2026
9e2c381
Document cbor2 as test-only dependency in test file header
Copilot Feb 11, 2026
69931a6
Add CBOR documentation to advanced_usage.rst following ASN.1 pattern
Copilot Feb 11, 2026
fd1a504
Add cbor2 to tox.ini testenv deps for CBOR interoperability tests
Copilot Feb 11, 2026
3d77346
Add adapted tests from PR #4875 for CBOR encoding edge cases
Copilot Feb 11, 2026
46f4f04
Fix UTF-8 encoding test failures on Windows by specifying encoding in…
Copilot Feb 11, 2026
2289f71
Fix documentation warning: remove trailing whitespace before Automata…
Copilot Feb 11, 2026
e3b06eb
Add RandCBORObject for fuzzing and comprehensive unit tests
Copilot Feb 13, 2026
bee0119
Fix extremely slow CBOR fuzzing tests by optimizing recursive structu…
Copilot Feb 13, 2026
b57d9ea
Fix syntax errors in CBOR unit tests by adding blank lines before ass…
Copilot Feb 13, 2026
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
2 changes: 1 addition & 1 deletion .config/codespell_ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ iff
implementors
inout
interaktive
joinin
JoinIn
merchantibility
microsof
mitre
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ coverage.xml
__pycache__/
doc/scapy/_build
doc/scapy/api
.idea
78 changes: 78 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Change pip's cache directory to be inside the project directory since we can
# only cache local items.
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

# Pip's cache doesn't store the python packages
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
#
# If you want to also cache the installed packages, you have to install
# them in a virtualenv and cache it as well.
cache:
paths:
- .cache/pip
- venv/
- venv_pypy/

.default:
image: python:3.11
tags:
- docker-ipv6
before_script:
- pip install tox

health:
extends: .default
script:
- tox -e flake8
- tox -e spell
- tox -e twine

mypy:
extends: .default
script:
- tox -e mypy

py311:
image: dissecto/scapy-tests:latest
tags:
- docker-ipv6
script:
- ./.config/ci/test.sh 3.11 non_root

pypy3:
image: dissecto/scapy-tests-pypy:latest
tags:
- docker-ipv6
script:
- ./.config/ci/test.sh pypy3 non_root

.publish:
image: python:latest
needs:
- pypy3
- py311
- mypy
- health
tags:
- docker
script:
- pip install build twine
- python -m build
- TWINE_PASSWORD=${CI_JOB_TOKEN} TWINE_USERNAME=gitlab-ci-token python -m twine upload --verbose --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*

publish:
allow_failure: true
rules:
- if: $CI_COMMIT_BRANCH == "master"
when: always
- when: never
extends: .publish

publish_tags:
extends: .publish
only:
- tags
except:
- branches

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,4 @@ The documentation (everything unless marked otherwise in `doc/`, and except the

Want to contribute? Great! Please take a few minutes to
[read this](CONTRIBUTING.md)!

228 changes: 228 additions & 0 deletions doc/scapy/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,234 @@ It is even possible to graph it::
>>> conf.mib._make_graph()


CBOR
====

What is CBOR?
-------------

.. note::

This section provides a practical introduction to CBOR from Scapy's perspective. For the complete specification, see RFC 8949.

CBOR (Concise Binary Object Representation) is a data format whose goal is to provide a compact, self-describing binary data interchange format based on the JSON data model. It is defined in RFC 8949 and is designed to be small in code size, reasonably small in message size, and extensible without the need for version negotiation.

CBOR provides basic data types including:

* **Unsigned integers** (major type 0): Non-negative integers
* **Negative integers** (major type 1): Negative integers
* **Byte strings** (major type 2): Raw binary data
* **Text strings** (major type 3): UTF-8 encoded strings
* **Arrays** (major type 4): Ordered sequences of values
* **Maps** (major type 5): Unordered key-value pairs
* **Semantic tags** (major type 6): Tagged values with additional semantics
* **Simple values and floats** (major type 7): Booleans, null, undefined, and floating-point numbers

Each CBOR data item begins with an initial byte that encodes the major type (in the top 3 bits) and additional information (in the low 5 bits). This design allows for compact encoding while maintaining self-describing properties.

Scapy and CBOR
--------------

Scapy provides a complete CBOR encoder and decoder following the same architectural pattern as the ASN.1 implementation. The CBOR engine can encode Python objects to CBOR binary format and decode CBOR data back to Python objects. It has been designed to be RFC 8949 compliant and interoperable with other CBOR implementations.

CBOR engine
^^^^^^^^^^^

Scapy's CBOR engine provides classes to represent CBOR data items. The main components are:

* ``CBOR_MajorTypes``: Defines the 8 major types (0-7) used in CBOR encoding
* ``CBOR_Object``: Base class for all CBOR value objects
* ``CBOR_Codecs``: Registry for encoding/decoding rules

The ``CBOR_MajorTypes`` class defines tags for all major types::

class CBOR_MajorTypes:
name = "CBOR_MAJOR_TYPES"
UNSIGNED_INTEGER = 0
NEGATIVE_INTEGER = 1
BYTE_STRING = 2
TEXT_STRING = 3
ARRAY = 4
MAP = 5
TAG = 6
SIMPLE_AND_FLOAT = 7

All CBOR objects are represented by Python instances that wrap raw values. They inherit from ``CBOR_Object``::

class CBOR_UNSIGNED_INTEGER(CBOR_Object):
tag = CBOR_MajorTypes.UNSIGNED_INTEGER

class CBOR_TEXT_STRING(CBOR_Object):
tag = CBOR_MajorTypes.TEXT_STRING

class CBOR_ARRAY(CBOR_Object):
tag = CBOR_MajorTypes.ARRAY

Creating CBOR objects
^^^^^^^^^^^^^^^^^^^^^

CBOR objects can be easily created and composed::

>>> from scapy.cbor import *
>>> # Create basic types
>>> num = CBOR_UNSIGNED_INTEGER(42)
>>> text = CBOR_TEXT_STRING("Hello, CBOR!")
>>> data = CBOR_BYTE_STRING(b'\x01\x02\x03')
>>>
>>> # Create collections
>>> arr = CBOR_ARRAY([CBOR_UNSIGNED_INTEGER(1),
... CBOR_UNSIGNED_INTEGER(2),
... CBOR_TEXT_STRING("three")])
>>> arr
<CBOR_ARRAY[[<CBOR_UNSIGNED_INTEGER[1]>, <CBOR_UNSIGNED_INTEGER[2]>, <CBOR_TEXT_STRING['three']>]]>
>>>
>>> # Create maps
>>> from scapy.cbor.cborcodec import CBORcodec_MAP
>>> mapping = {"name": "Alice", "age": 30, "active": True}

Encoding and decoding
^^^^^^^^^^^^^^^^^^^^^

CBOR objects are encoded using their ``.enc()`` method. All codecs are referenced in the ``CBOR_Codecs`` object. The default codec is ``CBOR_Codecs.CBOR``::

>>> num = CBOR_UNSIGNED_INTEGER(42)
>>> encoded = bytes(num)
>>> encoded.hex()
'182a'
>>>
>>> # Decode back
>>> decoded, remainder = CBOR_Codecs.CBOR.dec(encoded)
>>> decoded.val
42
>>> isinstance(decoded, CBOR_UNSIGNED_INTEGER)
True

Encoding collections::

>>> from scapy.cbor.cborcodec import CBORcodec_ARRAY, CBORcodec_MAP
>>> # Encode an array
>>> encoded = CBORcodec_ARRAY.enc([1, 2, 3, 4, 5])
>>> encoded.hex()
'850102030405'
>>>
>>> # Decode the array
>>> decoded, _ = CBOR_Codecs.CBOR.dec(encoded)
>>> [item.val for item in decoded.val]
[1, 2, 3, 4, 5]
>>>
>>> # Encode a map
>>> encoded = CBORcodec_MAP.enc({"x": 100, "y": 200})
>>> decoded, _ = CBOR_Codecs.CBOR.dec(encoded)
>>> isinstance(decoded, CBOR_MAP)
True

Working with different types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

CBOR supports various data types::

>>> # Booleans
>>> true_val = CBOR_TRUE()
>>> false_val = CBOR_FALSE()
>>> bytes(true_val).hex()
'f5'
>>> bytes(false_val).hex()
'f4'
>>>
>>> # Null and undefined
>>> null_val = CBOR_NULL()
>>> undef_val = CBOR_UNDEFINED()
>>> bytes(null_val).hex()
'f6'
>>> bytes(undef_val).hex()
'f7'
>>>
>>> # Floating point
>>> float_val = CBOR_FLOAT(3.14159)
>>> bytes(float_val).hex()
'fb400921f9f01b866e'
>>>
>>> # Negative integers
>>> neg = CBOR_NEGATIVE_INTEGER(-100)
>>> bytes(neg).hex()
'3863'

Complex structures
^^^^^^^^^^^^^^^^^^

CBOR supports nested structures::

>>> # Nested arrays
>>> nested = CBORcodec_ARRAY.enc([1, [2, 3], [4, [5, 6]]])
>>> decoded, _ = CBOR_Codecs.CBOR.dec(nested)
>>> isinstance(decoded, CBOR_ARRAY)
True
>>>
>>> # Complex maps with mixed types
>>> data = {
... "name": "Bob",
... "age": 25,
... "active": True,
... "tags": ["user", "admin"]
... }
>>> encoded = CBORcodec_MAP.enc(data)
>>> decoded, _ = CBOR_Codecs.CBOR.dec(encoded)
>>> len(decoded.val)
4

Semantic tags
^^^^^^^^^^^^^

CBOR supports semantic tags (major type 6) for providing additional meaning to data items::

>>> # Tag 1 is for Unix epoch timestamps
>>> import time
>>> timestamp = int(time.time())
>>> tagged = CBOR_SEMANTIC_TAG((1, CBOR_UNSIGNED_INTEGER(timestamp)))
>>> encoded = bytes(tagged)
>>> decoded, _ = CBOR_Codecs.CBOR.dec(encoded)
>>> decoded.val[0] # Tag number
1

Interoperability
^^^^^^^^^^^^^^^^

Scapy's CBOR implementation is fully interoperable with other CBOR libraries. The implementation has been tested with the ``cbor2`` Python library to ensure RFC 8949 compliance::

>>> import cbor2
>>> # Encode with Scapy, decode with cbor2
>>> scapy_obj = CBOR_UNSIGNED_INTEGER(12345)
>>> scapy_encoded = bytes(scapy_obj)
>>> cbor2.loads(scapy_encoded)
12345
>>>
>>> # Encode with cbor2, decode with Scapy
>>> cbor2_encoded = cbor2.dumps([1, "test", True])
>>> scapy_decoded, _ = CBOR_Codecs.CBOR.dec(cbor2_encoded)
>>> isinstance(scapy_decoded, CBOR_ARRAY)
True

Error handling
^^^^^^^^^^^^^^

Scapy provides safe decoding with error handling::

>>> # Safe decoding returns error objects for invalid data
>>> invalid_data = b'\xff\xff\xff'
>>> obj, remainder = CBOR_Codecs.CBOR.safedec(invalid_data)
>>> isinstance(obj, CBOR_DECODING_ERROR)
True

Comparison with ASN.1
^^^^^^^^^^^^^^^^^^^^^

While both ASN.1 and CBOR are data serialization formats, they serve different purposes:

* **ASN.1** is designed for complex schemas with strict typing and multiple encoding rules (BER, DER, PER, etc.)
* **CBOR** is designed for simplicity and compactness, with a single self-describing encoding

Scapy implements both following the same architectural pattern, making it easy to work with either format. CBOR's simpler structure makes it ideal for IoT, embedded systems, and web APIs, while ASN.1 is prevalent in telecommunications and cryptographic standards.


Automata
========
Expand Down
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[build-system]
requires = [ "setuptools>=62.0.0" ]
requires = ["setuptools>=64.0", "setuptools-scm>=8.0"]
build-backend = "setuptools.build_meta"

[project]
name = "scapy"
dynamic = [ "version", "readme" ]
dynamic = [ "version"]
readme = "README.md"
authors = [
{ name="Philippe BIONDI" },
]
Expand Down Expand Up @@ -59,6 +60,7 @@ all = [
"matplotlib",
]
doc = [
"cryptography>=2.0",
"sphinx>=7.0.0",
"sphinx_rtd_theme>=1.3.0",
"tox>=3.0.0",
Expand All @@ -78,8 +80,7 @@ exclude = [
"doc*",
]

[tool.setuptools.dynamic]
version = { attr="scapy.VERSION" }
[tool.setuptools_scm]

# coverage

Expand Down
Loading
Loading