Internet-Draft | U-CBOR | March 2025 |
Rundgren | Expires 4 September 2025 | [Page] |
This document defines Universal CBOR (U-CBOR), a strict subset of CBOR (RFC 8949) intended to serve as a viable replacement for JSON. To foster interoperability, deterministic encoding is mandated. Furthermore, the document outlines how deterministic encoding combined with enhanced CBOR tools, enables the support of cryptographic constructs that operate on "raw" (non-wrapped) CBOR data. This document mainly targets CBOR tool developers.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 4 September 2025.¶
Copyright (c) 2025 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
The Universal CBOR (U-CBOR) specification is based on CBOR [RFC8949]. While there are different ways you can encode certain CBOR objects, this is non-trivial to support in general purpose platform-based tools, not to mention the limited utility of such measures. To cope with this, U-CBOR defines a specific (non-variant) encoding scheme, aka "Deterministic Encoding". The selected encoding scheme is believed to be compatible with most existing systems using CBOR. See also Appendix C.¶
U-CBOR is intended to be agnostic with respect to programming languages.¶
By combining the compact binary representation and the rich set of data types offered by CBOR, with a deterministic encoding scheme, U-CBOR could for new designs, serve as viable alternative to JSON [RFC8259]. Although the mandated encoding scheme has proved to be deployable in constrained environments, the primary target is rather mainstream platforms like mobile phones and Web servers.¶
However, for unleashing the full power of deterministic encoding, the ability to perform cryptographic operations on "raw" (non-wrapped) CBOR data, compliant U-CBOR tools need additional functionality. See also Appendix B.¶
Section 2 contains the actual specification.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
This section describes the three pillars that U-CBOR relies on.¶
The following table shows the CBOR subset supported by U-CBOR:¶
CDDL | Note |
---|---|
int
|
Integer |
bigint
|
Big integer |
float
|
16-, 32-, and 64-bit [IEEE754] numbers |
tstr
|
Text string encoded as UTF-8 [RFC3629] |
bstr
|
Byte string |
bool
|
Boolean true and false
|
null
|
Represents a null object |
[]
|
Array |
{}
|
Map |
#6.nnn(type)
|
Tagged data |
Conforming implementations (of course) only have to implement the U-CBOR types required by the targeted application(s).¶
Although extensions are imaginable (like supporting all
"simple" types), extensions will most likely cause
interoperability issues and are thus NOT RECOMMENDED. In addition,
the mandated CBOR subset is compatible with most computer languages and platforms.
Compared to the current state-of-the-art, JSON [RFC8259],
the availability of bigint
, bstr
, and "tagged data"
represent major improvements.¶
However, nothing prevents developers from at the application (API) level, through mapping concepts, support additional, "virtual" data types, analogous to how you map an application's data model to the set of data types available, be it a data interchange format, a database, or a programming language.¶
The U-CBOR encoding scheme adheres to section 4.2 of [RFC8949], but adds a few constraints (denoted by RFC+), where the RFC offers choices. The deterministic encoding rules are as follows:¶
RFC: Integers, represented by the int
and
bigint
types, MUST use the int
type if the value is between -264
and 264-1
,
otherwise the bigint
type MUST be used.
Appendix A.1
features a list of compliant integer sample values.¶
RFC+: Floating point numbers MUST always use the shortest [IEEE754] variant that preserves the precision of the original value. Appendix A.2 features a list of compliant floating point sample values.¶
Note that NaN
"signaling" (like f97e01
),
MUST be rejected.¶
RFC: Map keys MUST be sorted in the bytewise lexicographic order of their deterministic encoding. Duplicate keys MUST be rejected. Somewhat surprisingly the following represents a properly sorted map:¶
{ "a": ... , "b": ... , "aa": ... }¶
0.0
and
-0.0
, and the integer number 0
represent the distinct keys
f90000
, f98000
, and 00
respectively.¶
The primary feature that deterministic encoding brings to the table is
that wrapping CBOR data to be signed in bstr
objects, like
specified by COSE [RFC9052] (Section 2), no longer is a prerequisite.
That is, cryptographic operations can optionally be performed
on "raw" CBOR data.
Turn to Appendix B for
an example of an application depending on such features.¶
However, to make this a reality, the following functionality MUST be provided by CBOR tools compliant with this specification:¶
map
and array
objects, of
received and decoded CBOR data. Note: CBOR primitives MUST remain immutable.¶
It is RECOMMENDED separating CBOR data and application / platform-level data, since the latter may not always reserialize as expected, like in this Chrome browser console example:¶
> let date = new Date('2025-03-02T13:08:55.0001Z'); > date.toISOString() '2025-03-02T13:08:55.000Z'¶
How this separation actually is accomplished is out of scope for this specification. However, encapsulation of CBOR data in high-level, and self-rendering objects, represents a usable method. Similar approaches are used by most ASN.1 tools. The code in Appendix B.5 shows an example that updates and reserializes decoded CBOR data.¶
This memo includes no request to IANA.¶
All is good 😸¶
This normative section holds a selection of CBOR integer values, with an emphasize on edge cases.¶
Value | CBOR Encoding | Note |
---|---|---|
0
|
00
|
Smallest positive implicit int
|
-1
|
20
|
Smallest negative implicit int
|
23
|
17
|
Largest positive implicit int
|
-24
|
37
|
Largest negative implicit int
|
24
|
1818
|
Smallest positive one-byte int
|
-25
|
3818
|
Smallest negative one-byte int
|
255
|
18ff
|
Largest positive one-byte int
|
-256
|
38ff
|
Largest negative one-byte int
|
256
|
190100
|
Smallest positive two-byte int
|
-257
|
390100
|
Smallest negative two-byte int
|
65535
|
19ffff
|
Largest positive two-byte int
|
-65536
|
39ffff
|
Largest negative two-byte int
|
65536
|
1a00010000
|
Smallest positive four-byte int
|
-65537
|
3a00010000
|
Smallest negative four-byte int
|
4294967295
|
1affffffff
|
Largest positive four-byte int
|
-4294967296
|
3affffffff
|
Largest negative four-byte int
|
4294967296
|
1b0000000100000000
|
Smallest positive eight-byte int
|
-4294967297
|
3b0000000100000000
|
Smallest negative eight-byte int
|
18446744073709551615
|
1bffffffffffffffff
|
Largest positive eight-byte int
|
-18446744073709551616
|
3bffffffffffffffff
|
Largest negative eight-byte int
|
18446744073709551616
|
c249010000000000000000
|
Smallest positive bigint
|
-18446744073709551617
|
c349010000000000000000
|
Smallest negative bigint
|
This normative section holds a selection of [IEEE754] 16, 32, and 64-bit values, with an emphasize on edge cases.¶
The textual representation of the values is based on
the serialization method for the Number
data type,
defined by [ECMASCRIPT] with one change:
to comply with diagnostic notation
(section 8 of [RFC8949]), all values are
expressed as floating point numbers.
The rationale for using [ECMASCRIPT] serialization is
because it supposed to generate the shortest and most
correct representation of [IEEE754] numbers.¶
Value | CBOR Encoding | Note |
---|---|---|
0.0
|
f90000
|
Zero |
-0.0
|
f98000
|
Negative zero |
Infinity
|
f97c00
|
Infinity |
-Infinity
|
f9fc00
|
-Infinity |
NaN
|
f97e00
|
NaN |
5.960464477539063e-8
|
f90001
|
Smallest positive subnormal 16-bit float
|
0.00006097555160522461
|
f903ff
|
Largest positive subnormal 16-bit float
|
0.00006103515625
|
f90400
|
Smallest positive 16-bit float
|
65504.0
|
f97bff
|
Largest positive 16-bit float
|
1.401298464324817e-45
|
fa00000001
|
Smallest positive subnormal 32-bit float
|
1.1754942106924411e-38
|
fa007fffff
|
Largest positive subnormal 32-bit float
|
1.1754943508222875e-38
|
fa00800000
|
Smallest positive 32-bit float
|
3.4028234663852886e+38
|
fa7f7fffff
|
Largest positive 32-bit float
|
5.0e-324
|
fb0000000000000001
|
Smallest positive subnormal 64-bit float
|
2.225073858507201e-308
|
fb000fffffffffffff
|
Largest positive subnormal 64-bit float
|
2.2250738585072014e-308
|
fb0010000000000000
|
Smallest positive 64-bit float
|
1.7976931348623157e+308
|
fb7fefffffffffffff
|
Largest positive 64-bit float
|
-0.0000033333333333333333
|
fbbecbf647612f3696
|
Randomly selected number |
295147905179352830000.0
|
fa61800000
|
~268
|
2.0
|
f94000
|
Number without a fractional part |
-5.960464477539063e-8
|
f98001
|
Smallest negative subnormal 16-bit float
|
-5.960464477539062e-8
|
fbbe6fffffffffffff
|
Close to smallest negative subnormal 16-bit float
|
-5.960464477539064e-8
|
fbbe70000000000001
|
"" |
-5.960465188081798e-8
|
fab3800001
|
"" |
0.0000609755516052246
|
fb3f0ff7ffffffffff
|
Close to largest subnormal 16-bit float
|
0.000060975551605224616
|
fb3f0ff80000000001
|
"" |
0.000060975555243203416
|
fa387fc001
|
"" |
0.00006103515624999999
|
fb3f0fffffffffffff
|
Close to smallest 16-bit float
|
0.00006103515625000001
|
fb3f10000000000001
|
"" |
0.00006103516352595761
|
fa38800001
|
"" |
65503.99999999999
|
fb40effbffffffffff
|
Close to largest 16-bit float
|
65504.00000000001
|
fb40effc0000000001
|
"" |
65504.00390625
|
fa477fe001
|
"" |
1.4012984643248169e-45
|
fb369fffffffffffff
|
Close to smallest subnormal 32-bit float
|
1.4012984643248174e-45
|
fb36a0000000000001
|
"" |
1.175494210692441e-38
|
fb380fffffbfffffff
|
Close to largest subnormal 32-bit float
|
1.1754942106924412e-38
|
fb380fffffc0000001
|
"" |
1.1754943508222874e-38
|
fb380fffffffffffff
|
Close to smallest 32-bit float
|
1.1754943508222878e-38
|
fb3810000000000001
|
"" |
3.4028234663852882e+38
|
fb47efffffdfffffff
|
Close to largest 32-bit float
|
3.402823466385289e+38
|
fb47efffffe0000001
|
"" |
The following table holds a selection of valid CBOR objects, not permitted by U-CBOR.¶
CBOR Encoding | Diagnostic Notation | Note |
---|---|---|
a2616200616101
|
{"b":0,"a":1}
|
Improper map key ordering [1] |
1900ff
|
255
|
Number with leading zero bytes [1] |
c34a00010000000000000000
|
-18446744073709551617
|
Number with leading zero bytes [1] |
Fa41280000
|
10.5
|
Not in shortest encoding [1] |
fa7fc00000
|
NaN
|
Not in shortest encoding [1] |
c243010000
|
65536
|
Incorrect value for bigint [1] |
f97e01
|
NaN
|
NaN with payload [1] |
f7
|
undefined
|
Unsupported simple type |
f0
|
simple(16)
|
Unsupported simple type |
5f4101420203ff
|
(_ h'01', h'0203')
|
Unsupported indefinite length object |
This is a non-normative appendix showing how U-CBOR can be used for supporting enveloped signatures.¶
The primary advantages with enveloped signatures compared to the approach used by COSE [RFC9052] include:¶
Enveloped signatures are for example featured in Verified Credentials [CREDENTIALS]. A drawback with designs based on JSON [RFC8259] is that they rely on canonicalization schemes like JCS [RFC8785], that require specialized encoders and decoders, whereas U-CBOR works "straight out of the box".¶
Although this specification is not "married" to any particular signature schema, the example uses the CBOR Signature Format [CSF]. For the sake of simplicity, the example uses an HMAC (see Appendix B.4) as signature algorithm.¶
Imagine you have a CBOR map object like the following that you want to sign:¶
{ 1: "data", 2: "more data" }¶
Then continue to the next section (Appendix B.2)...¶
This section describes the steps required for adding an enveloped signature to the CBOR map object in Appendix B.1.¶
Generate a signature by invoking a (hypothetical) signature method with the following arguments:¶
The result after the final step (using the parameters from Appendix B.4), should match the following CBOR object:¶
{ 1: "data", 2: "more data", -1: { 1: 5, 6: h'4853d7730cc1340682b1748dc346cf627a5e91ce62c67fff15c40257ed2a37a1' } }¶
Note that the signature covers the entire CBOR object except for the CSF signature value and label (6).¶
In order to validate the enveloped signature created in the Appendix B.2, the following steps are performed:¶
Fetch a reference to the CSF container using the application-defined label (-1). Next perform the following operations using the reference:¶
Now we should have exactly the same CBOR object as we had before step #4 in Appendix B.2. That is:¶
{ 1: "data", 2: "more data", -1: { 1: 5 } }¶
Validate the signature data by invoking a (hypothetical) signature validation method with the following arguments:¶
Note: this is a "bare-bones" validation process, lacking the ruggedness of a real-world implementation.¶
The signature and validation processes depend on the COSE [RFC9053] algorithm "HMAC 256/256" and an associated 256-bit key, here provided in hex code:¶
7fdd851a3b9d2dafc5f0d00030e22b9343900cd42ede4948568a4a2ee655291a¶
Using the JavaScript implementation mentioned in Appendix E, basic signature validation of the signed CBOR object created in Appendix B.2, could be performed by the following code:¶
// The variable cborBinary is supposed to contain CBOR let object = CBOR.decode(cborBinary); // Decode let csf = object.get(CBOR.Int(-1)); // Get CSF container let alg = csf.get(CBOR.Int(1)).getInt(); // Read algorithm let sig = csf.remove(CBOR.Int(6)).getBytes(); // Read and remove signature value let key = CBOR.fromHex('7fdd851a3b9d2dafc5f0d00030e22b9343900cd42ede4948568a4a2ee655291a'); // Hypothetical HMAC validation method: hmacValidate(alg, sig, key, object.encode()); // Note that object.encode() // reserializes all but sig. // Validated object, access the "payload": let param = object.get(CBOR.Int(1)).getString(); // param should now contain "data"¶
Note that this code depends heavily on the CBOR tool features outlined in Section 2.3.¶
It is assumed that most systems using CBOR are able to process an (application specific), selection of CBOR data items that are encoded in compliance with [RFC8949]. Since the deterministic encoding scheme mandated by U-CBOR, also is compliant with [RFC8949], there should be no major interoperability issues. That is, if the previous assumption actually is correct 😏¶
However, in the other direction (U-CBOR tools processing data from Systems using "legacy" CBOR encoding schemes), the situation is likely to be considerably more challenging since deterministic encoding "by design" is strict. Due to this potential obstacle, implementers of U-CBOR tools, are RECOMMENDED to offer decoder options that permit "relaxing" the rigidness of deterministic encoding with respect to:¶
Note that regardless of the format of received CBOR data, a compliant U-CBOR implementation MUST maintain deterministic encoding. See also Appendix A.3.¶
For testing and learning about U-CBOR, there are currently a number of compatible online tools (subject to availability...).¶
For using U-CBOR in applications, there are currently a number of compatible ibraries.¶
This work was inspired by a CBOR based project known as [GordianEnvelope], pioneered by Wolf McNally and Christopher Allen. This project also exploits the ability to hash "raw" (non-wrapped) CBOR data, enabled by the use of a deterministic encoding scheme.¶