What is CBOR?
CBOR (Concise Binary Object Representation) is defined in RFC 8949. It's a binary data format that models data similar to JSON but encodes it more efficiently. CBOR was designed for constrained environments like IoT devices.
Compact Size
Binary encoding is 30-50% smaller than equivalent JSON, reducing bandwidth and storage.
No Base64 Needed
Binary data (signatures, keys) can be stored directly without Base64 encoding overhead.
Fast Parsing
Self-describing format allows streaming and efficient parsing on constrained devices.
Schema-less
Like JSON, CBOR doesn't require predefined schemas, enabling flexible data structures.
CBOR Data Types
CBOR defines 8 major types, each identified by the first 3 bits of the initial byte. This allows the decoder to immediately know what type of data follows.
| Type | Major | Example | Notes |
|---|---|---|---|
| Unsigned Integer | 0 | 25 → 0x18 0x19 | Values 0-23 fit in one byte |
| Negative Integer | 1 | -1 → 0x20 | Encoded as -1 - n |
| Byte String | 2 | h'01020304' | Raw binary data |
| Text String | 3 | "hello" → 0x65 0x68656C6C6F | UTF-8 encoded |
| Array | 4 | [1, 2, 3] | Ordered collection |
| Map | 5 | {1: "a", 2: "b"} | Key-value pairs |
| Tagged Value | 6 | tag(0) datetime | Semantic tagging |
| Simple/Float | 7 | true, false, null | Booleans, null, floats |
Encoding Format
Each CBOR data item starts with an initial byte where the high 3 bits indicate the major type and the low 5 bits provide additional information.
Initial Byte Structure
Example: Encoding the number 25
Major type 0 (unsigned int) = 000 binary
25 requires additional byte (values 0-23 fit in additional info, 24-255 need extra byte)
Additional info = 24 (indicates 1-byte follow) = 11000 binary
Result: 0x18 0x19 (2 bytes vs "25" = 2 bytes in JSON)
Example: Encoding a map
// JSON: {"a": 1, "b": 2}
// CBOR diagnostic: {"a": 1, "b": 2}
// CBOR hex: A2 61 61 01 61 62 02
//
// A2 = Major type 5 (map), 2 items
// 61 = Major type 3 (text), 1 byte follows
// 61 = "a" (ASCII 0x61)
// 01 = Major type 0 (uint), value 1
// 61 = text, 1 byte
// 62 = "b"
// 02 = uint, value 2COSE Signatures
COSE (CBOR Object Signing and Encryption) is to CBOR what JOSE is to JSON. mDOC uses COSE_Sign1 (single signer) for the MSO signature.
COSE_Sign1 = [
/ protected / h'a10126', -- {1: -7} = {alg: ES256}
/ unprotected / {4: h'...'}, -- {kid: ...}
/ payload / h'...', -- The signed data
/ signature / h'...' -- ECDSA signature
]
Protected Header (decoded):
{
1: -7 // alg: ES256 (ECDSA with P-256)
}
Common COSE Algorithms:
-7 = ES256 (ECDSA P-256)
-35 = ES384 (ECDSA P-384)
-36 = ES512 (ECDSA P-521)
-8 = EdDSAProtected Header
CBOR-encoded map wrapped in a byte string. Contains parameters that are included in the signature calculation (alg, content type).
Unprotected Header
CBOR map with parameters not covered by signature (kid, x5chain for certificate chain).