CBOR library in Go - Small. Fast. Reliable. No crashes on malicious data. API is encoding/json + 'toarray' and 'keyasint' struct tags. fxamacker/cbor v1.3


(Faye Amacker) #1

What does this do? fxamacker/cbor encodes and decodes CBOR, like encoding/json does for JSON.

What is CBOR? CBOR (RFC 7049) is a binary data format inspired by JSON and MessagePack. CBOR is used in IETF Internet Standards such as COSE (RFC 8152) and CWT (RFC 8392 CBOR Web Token). WebAuthn also uses CBOR.

Why was this created when others exist? I needed to use CBOR (in Go) without bloat and without worrying about a tiny malicious CBOR message being able to bring down the entire system.

:point_right: I found a github project replaced a 1000+ star library with this one because an external security audit found tiny malicious CBOR messages being able to exhaust system resources with the other one.

Why should projects choose this CBOR library? It doesn’t crash and it has well-balanced qualities: small, fast, reliable and easy.

  • :atom_symbol: Small and self-contained. It compiles to under 0.5 MB, has no external dependencies, and no code gen. Compiled program size difference vs another library can be as extreme as 8+ MB (see chart.)

  • :rocket: Fast (esp. since v1.3). It soley uses safe optimizations. Faster libraries will always exist, but speed is only one factor. Choose this library if you value your time, program size, and system reliability.

  • :lock: Reliable and safe. It prevents crashes on malicious CBOR data by using extensive tests, coverage-guided fuzzing, data validation, and avoiding Go’s unsafe package.

  • :hourglass_flowing_sand: Easy and saves time. It has the same API as Go’s encoding/json. Existing structs don’t require changes. Go struct tags like `cbor:"name,omitempty"` and `json:"name,omitempty"` work as expected. Extra struct tags like keyasint and toarray make CBOR, COSE, CWT, and SenML very easy to use.

Install with go get github.com/fxamacker/cbor and use it like Go’s encoding/json.

Example: CBOR Web Token (CWT)

The keyasint and toarray struct tags simplify decoding Signed CWT to an easy-to-use Go struct. These tags make decoding simple: err := cbor.Unmarshal(b, &v).

cbor_cwt_snippet

Comparisons

Doing your own comparisons is recommended. Use your most common message sizes and data types.

Additional comparisons may be added from time to time (esp. speed comparisons!)

Current Status

Version 1.x has:

  • Stable API – won’t make breaking API changes.
  • Stable requirements – will always support Go v1.12.
  • Passed fuzzing – v1.3 passed 2+ billion execs in 72+ hours of coverage-guided fuzzing.

Recent Activity

  • Release v1.2 – add RawMessage type, Marshaler and Unmarshaler interfaces.
  • Release v1.3 – faster encoding and decoding.
  • Release v1.3 – add struct to/from CBOR array (toarray struct tag) for more compact data.
  • Release v1.3 – add struct to/from CBOR map with int keys (keyasint struct tag). Simplifies using CBOR and esp. COSE, CWT, SenML, etc.
  • Milestone v1.4:balloon: (maybe) Add support for CBOR tags (major type 6.) Please let me know if this feature matters to you!

(Jakob Borg) #2

I’ve used this and was happy to see a well tested high quality implementation! :+1:


(Faye Amacker) #3

Your kind words prompted me to include this in my project’s How to Contribute. :smiley:

When I announced v1.2 on Go Forum, Jakob Borg (calmh) responded with a thumbs up and encouragement. Another project of equal priority needed my time and Jakob’s kind words tipped the scale for me to work on this one (speedups for milestone v1.3.) So words of appreciation or encouragement is nice way to contribute to open source projects.


(Faye Amacker) #4

Release v1.3 is done! It passed 2+ billion execs in 72 hrs of coverage-guided fuzzing.

Changes include:

  • faster speed (many safe optimizations)
  • toarray struct tag
  • keyasint struct tag
  • refactor to use best practices for naming and grouping internal functions

Example code using CBOR Web Token (CWT) shows how these tags make decoding Signed CWT to easy-to-use Go struct simple: err := cbor.Unmarshal(b, &v).