RFC 9682 | CDDL grammar updates | November 2024 |
Bormann | Standards Track | [Page] |
The Concise Data Definition Language (CDDL), as defined inRFCs 8610 and 9165,provides an easy and unambiguous way to express structures forprotocol messages and data formats that are represented in Concise Binary Object Representation (CBOR) orJSON.¶
This document updates RFC 8610 by addressing related errata reports and makingother small fixes for the ABNF grammar defined for CDDL.¶
This is an Internet Standards Track document.¶
This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 7841.¶
Information about the current status of this document, any errata, and how to provide feedback on it may be obtained athttps://www.rfc-editor.org/info/rfc9682.¶
Copyright (c) 2024 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 Concise Data Definition Language (CDDL), as defined in[RFC8610] and[RFC9165],provides an easy and unambiguous way to express structures forprotocol messages and data formats that are represented in CBOR orJSON.¶
This document updates[RFC8610] by addressing errata reports and makingother small fixes for the ABNF grammar defined for CDDL.The body of this document explains and shows motivation for the updates; theupdated collected ABNF syntax inFigure 11 inAppendix A replaces the collected ABNF syntax inAppendix B of [RFC8610].¶
A number of errata reports have been made regarding some details of textstring and byte string literal syntax: for example,[Err6527] and[Err6543].These are being addressed in this section, updating details of theABNF for these literal syntaxes.Also, the changes described in[Err6526] need to be applied (backslashes have been lost during the RFC publication process ofAppendix G.2 of [RFC8610], garbling the text explaining backslash escaping).¶
These changes are intended to mirror the way existing implementationshave dealt with the errata reports. This document also uses the opportunity presentedby the necessary cleanup of the grammar of string literals for abackward-compatible addition to the syntax for hexadecimal escapes.The latter change is not automatically forward compatible (i.e., CDDLspecifications that make use of this syntax do not necessarily workwith existing implementations until these are updated, which is recommended by thisspecification).¶
The ABNF used in[RFC8610] for the content of text string literals is rather permissive:¶
; ABNF from RFC 8610:text = %x22 *SCHAR %x22SCHAR = %x20-21 / %x23-5B / %x5D-7E / %x80-10FFFD / SESCSESC = "\" (%x20-7E / %x80-10FFFD)
This allows almost any non-C0 character to be escaped by a backslash,but critically misses out on the\uXXXX
and\uHHHH\uLLLL
formsthat JSON allows to specify characters in hex(which shouldapply here according to item 6 ofSection 3.1 of [RFC8610]).(Note that CDDL imports from JSON the unwieldy\uHHHH\uLLLL
syntax,which represents Unicode code points beyond U+FFFF by making them looklike UTF-16 surrogate pairs; CDDL text strings do not use UTF-16 or surrogates.)¶
Both can be solved by updating the SESC rule.This document uses the opportunity to add a popular form of directly specifyingcharacters in strings using hexadecimal escape sequences of the form\u{hex}
, wherehex
is the hexadecimal representation of theUnicode scalar value.The result is the new set of rules defining SESC inFigure 2.¶
; new rules collectively defining SESC:SESC = "\" ( %x22 / "/" / "\" / ; \" \/ \\ %x62 / %x66 / %x6E / %x72 / %x74 / ; \b \f \n \r \t (%x75 hexchar) ) ; \uXXXXhexchar = "{" (1*"0" [ hexscalar ] / hexscalar) "}" / non-surrogate / (high-surrogate "\" %x75 low-surrogate)non-surrogate = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG) / ("D" %x30-37 2HEXDIG )high-surrogate = "D" ("8"/"9"/"A"/"B") 2HEXDIGlow-surrogate = "D" ("C"/"D"/"E"/"F") 2HEXDIGhexscalar = "10" 4HEXDIG / HEXDIG1 4HEXDIG / non-surrogate / 1*3HEXDIGHEXDIG1 = DIGIT1 / "A" / "B" / "C" / "D" / "E" / "F"
Notes:In ABNF, strings such as"A"
,"B"
, etc., are case insensitive, as isintended here.The rules above could have also used%s"b"
, etc., instead of%x62
, but didn't, in order to maximize compatibility with ABNF tools.¶
Now that SESC is more restrictively formulated, anupdate to the BCHAR rule used in the ABNF syntax for byte stringliterals is also required:¶
; ABNF from RFC 8610:bytes = [bsqual] %x27 *BCHAR %x27BCHAR = %x20-26 / %x28-5B / %x5D-10FFFD / SESC / CRLFbsqual = "h" / "b64"
With the SESC updated as above,\'
is no longer allowed in BCHAR and now needs to be explicitly included there; seeFigure 4.¶
Updating BCHAR also provides an opportunity to address[Err6278],which points to an inconsistency in treating U+007F (DEL) between SCHAR andBCHAR.As U+007F is not printable, including it in a byte string literal isas confusing as for a text string literal; therefore, it should beexcluded from BCHAR as it is from SCHAR.The same reasoning also applies to the C1 control characters,so the updated ABNF actually excludes the entire range from U+007F to U+009F.The same reasoning also applies to text in comments (PCHAR). For completeness, all these rules should also explicitly exclude the codepoints that have been set aside for UTF-16 surrogates.¶
; new rules for SCHAR, BCHAR, and PCHAR:SCHAR = %x20-21 / %x23-5B / %x5D-7E / NONASCII / SESCBCHAR = %x20-26 / %x28-5B / %x5D-7E / NONASCII / SESC / "\'" / CRLFPCHAR = %x20-7E / NONASCIINONASCII = %xA0-D7FF / %xE000-10FFFD
(Note that, apart from addressing the inconsistencies, there is noattempt to further exclude non-printable characters from the ABNF;doing this properly would draw in complexity from the ongoingevolution of the Unicode standard[UNICODE] that is not needed here.)¶
The above changes also cover[Err6543] (a proposal to split offqualified byte string literals from UTF-8 byte string literals) and[Err6526] (lost backslashes); seeAppendix B for details.¶
The CDDL example inFigure 5 demonstrates various escapingtechniques now available for (byte and text) strings in CDDL.Obviously, in the literals fora
andx
, there is no need to escapethe second character, ano
, as\u{6f}
; this is just for demonstration.Similarly, as shown inc
andz
, there also is no need to escape the"🁳" (DOMINO TILE VERTICAL-02-02, U+1F073) or"⌘" (PLACE OF INTEREST SIGN, U+2318); however, escaping them may be convenient in order to limit the characterrepertoire of a CDDL file itself to ASCII[STD80].¶
start = [a, b, c, x, y, z]; "🁳", DOMINO TILE VERTICAL-02-02, and; "⌘", PLACE OF INTEREST SIGN, in a text string:a = "D\u{6f}mino's \u{1F073} + \u{2318}" ; \u{}-escape 3 charsb = "Domino's \uD83C\uDC73 + \u2318" ; escape JSON-likec = "Domino's 🁳 + ⌘" ; unescaped; in a byte string given as text, the ' needs to be escaped:x = 'D\u{6f}mino\u{27}s \u{1F073} + \u{2318}' ; \u{}-escape 4 charsy = 'Domino\'s \uD83C\uDC73 + \u2318' ; escape JSON-likez = 'Domino\'s 🁳 + ⌘' ; escape ' only
In this example, the rules a to c and x to z all produce strings withbyte-wise identical content: a to c are text strings and x to zare byte strings.Figure 6 illustrates this by showing the output generated fromthestart
rule inFigure 5, using pretty-printed hexadecimal.¶
86 # array(6) 73 # text(19) 446f6d696e6f277320f09f81b3202b20e28c98 # "Domino's 🁳 + ⌘" 73 # text(19) 446f6d696e6f277320f09f81b3202b20e28c98 # "Domino's 🁳 + ⌘" 73 # text(19) 446f6d696e6f277320f09f81b3202b20e28c98 # "Domino's 🁳 + ⌘" 53 # bytes(19) 446f6d696e6f277320f09f81b3202b20e28c98 # "Domino's 🁳 + ⌘" 53 # bytes(19) 446f6d696e6f277320f09f81b3202b20e28c98 # "Domino's 🁳 + ⌘" 53 # bytes(19) 446f6d696e6f277320f09f81b3202b20e28c98 # "Domino's 🁳 + ⌘"
Each subsection that follows specifies a small change to thegrammar that is intended to enable certain kinds of specifications.These changes are backward compatible (i.e., CDDL files thatcomply with[RFC8610] continue to match the updated grammar) but notnecessarily forward compatible (i.e., CDDL specifications that makeuse of these changes cannot necessarily be processed by existing implementations of[RFC8610]).¶
[RFC8610] requires a CDDL file to have at least one rule.¶
; ABNF from RFC 8610:cddl = S 1*(rule S)
cddl
This makes sense when the file has to stand alone, as a CDDL datamodel needs to have at least one rule to provide an entry point (i.e., a startrule).¶
With CDDL modules[CDDL-MODULES], CDDL files can also include directives,and these might be the source of all the rules thatultimately make up the module created by the file.Any other rule content in the file has to be available for directiveprocessing, making the requirement for at least one rule cumbersome.¶
Therefore, the present update extends the grammar as inFigure 8and turns the existence of at least one rule into a semantic constraint, tobe fulfilled after processing of all directives.¶
; new top-level rule:cddl = S *(rule S)
The existing ABNF syntax for expressing tags in CDDL is as follows:¶
; extracted from the ABNF in RFC 8610:type2 =/ "#" "6" ["." uint] "(" S type S ")"
This means tag numbers can only be given as literal numbers (uints).Some specifications operate on ranges of tag numbers; for example,[RFC9277]has a range of tag numbers 1668546817 (0x63740101) to 1668612095(0x6374FFFF) to tag specific content formats.This cannot currently be expressed in CDDL.Similar considerations apply to simple values (#7.
xx).¶
This update extends the syntax to the following:¶
; new rules collectively defining the tagged case:type2 =/ "#" "6" ["." head-number] "(" S type S ")" / "#" "7" ["." head-number]head-number = uint / ("<" type ">")
For#6
, thehead-number
stands for the tag number.For#7
, thehead-number
stands for the simple value if it is inthe ranges 0..23 or 32..255 (as per Section3.3 of RFC 8949[STD94],the simple values 24..31 are not used).For 24..31, thehead-number
stands for the "additionalinformation", e.g.,#7.25
or#7.<25>
is a float16, etc.(All ranges mentioned here are inclusive.)¶
So the above range can be expressed in a CDDL fragment such as:¶
ct-tag<content> = #6.<ct-tag-number>(content)ct-tag-number = 1668546817..1668612095; or use 0x63740101..0x6374FFFF¶
Notes:¶
This syntax reuses the angle bracket syntax for generics;this reuse is innocuous because a generic parameter or argument only everoccurs after a rule name (id
), while it occurs after the ".
" (dot) character here.(Whether there is potential for human confusion can be debated; theabove example deliberately uses generics as well.)¶
The updated ABNF grammar makes it a bit more explicit that the number given after the optional dot is the value of the argument: for tags and simple values, it is not giving the CBOR "additional information”, as it is with other uses of#
in CDDL.(Adding this observation toSection 2.2.3 of [RFC8610] is the subjectof[Err6575]; it is correctly noted inSection 3.6 of [RFC8610].)In hindsight, maybe a different character than the dot should havebeen chosen for this special case; however, changing the grammarin the current document would have been too disruptive.¶
The grammar fixes and updates in this document are not believed tocreate additional security considerations.The security considerations inSection 5 of [RFC8610] apply.Specifically, the potential for confusion is increased in anenvironment that uses a combination of CDDL tools, some of which havebeen updated and some of which have not, in particular based onSection 2.¶
Attackers may want to exploit such potential confusion by craftingCDDL models that are interpreted differently by different parts of asystem.There will be a period of transition from the details that the grammar in[RFC8610] handled in a less well-defined way, to the updatedgrammar defined in the present document. This transition might offer one (but not the only) type of opportunity for the kind of attack that relies on differences between implementations.Implementations that make use of CDDL models operationally alreadyneed to ascertain the provenance (and thus authenticity and integrity)and applicability of models they employ.At the time of writing, it is expected that the models will generallybe processed by a software developer, within a software developmentenvironment.Therefore, developers are advised to treat CDDL models withthe same care as any other source code.¶
This document has no IANA actions.¶
This appendix is normative.¶
It provides the full ABNF from[RFC8610] as updated by the present document.¶
cddl = S *(rule S)rule = typename [genericparm] S assignt S type / groupname [genericparm] S assigng S grpenttypename = idgroupname = idassignt = "=" / "/="assigng = "=" / "//="genericparm = "<" S id S *("," S id S ) ">"genericarg = "<" S type1 S *("," S type1 S ) ">"type = type1 *(S "/" S type1)type1 = type2 [S (rangeop / ctlop) S type2]; space may be needed before the operator if type2 ends in a nametype2 = value / typename [genericarg] / "(" S type S ")" / "{" S group S "}" / "[" S group S "]" / "~" S typename [genericarg] / "&" S "(" S group S ")" / "&" S groupname [genericarg] / "#" "6" ["." head-number] "(" S type S ")" / "#" "7" ["." head-number] / "#" DIGIT ["." uint] ; major/ai / "#" ; anyhead-number = uint / ("<" type ">")rangeop = "..." / ".."ctlop = "." idgroup = grpchoice *(S "//" S grpchoice)grpchoice = *(grpent optcom)grpent = [occur S] [memberkey S] type / [occur S] groupname [genericarg] ; preempted by above / [occur S] "(" S group S ")"memberkey = type1 S ["^" S] "=>" / bareword S ":" / value S ":"bareword = idoptcom = S ["," S]occur = [uint] "*" [uint] / "+" / "?"uint = DIGIT1 *DIGIT / "0x" 1*HEXDIG / "0b" 1*BINDIG / "0"value = number / text / bytesint = ["-"] uint; This is a float if it has fraction or exponent; int otherwisenumber = hexfloat / (int ["." fraction] ["e" exponent ])hexfloat = ["-"] "0x" 1*HEXDIG ["." 1*HEXDIG] "p" exponentfraction = 1*DIGITexponent = ["+"/"-"] 1*DIGITtext = %x22 *SCHAR %x22SCHAR = %x20-21 / %x23-5B / %x5D-7E / NONASCII / SESCSESC = "\" ( %x22 / "/" / "\" / ; \" \/ \\ %x62 / %x66 / %x6E / %x72 / %x74 / ; \b \f \n \r \t (%x75 hexchar) ) ; \uXXXXhexchar = "{" (1*"0" [ hexscalar ] / hexscalar) "}" / non-surrogate / (high-surrogate "\" %x75 low-surrogate)non-surrogate = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG) / ("D" %x30-37 2HEXDIG )high-surrogate = "D" ("8"/"9"/"A"/"B") 2HEXDIGlow-surrogate = "D" ("C"/"D"/"E"/"F") 2HEXDIGhexscalar = "10" 4HEXDIG / HEXDIG1 4HEXDIG / non-surrogate / 1*3HEXDIGbytes = [bsqual] %x27 *BCHAR %x27BCHAR = %x20-26 / %x28-5B / %x5D-7E / NONASCII / SESC / "\'" / CRLFbsqual = "h" / "b64"id = EALPHA *(*("-" / ".") (EALPHA / DIGIT))ALPHA = %x41-5A / %x61-7AEALPHA = ALPHA / "@" / "_" / "$"DIGIT = %x30-39DIGIT1 = %x31-39HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"HEXDIG1 = DIGIT1 / "A" / "B" / "C" / "D" / "E" / "F"BINDIG = %x30-31S = *WSWS = SP / NLSP = %x20NL = COMMENT / CRLFCOMMENT = ";" *PCHAR CRLFPCHAR = %x20-7E / NONASCIINONASCII = %xA0-D7FF / %xE000-10FFFDCRLF = %x0A / %x0D.0A
This appendix is informative.¶
[Err6543] notes thatthe ABNF used in[RFC8610] for the content of byte string literalslumps together byte strings notated as text with byte strings notated in base16 (hex) or base64 (but see also updated BCHAR rule inFigure 4):¶
; ABNF from RFC 8610:bytes = [bsqual] %x27 *BCHAR %x27BCHAR = %x20-26 / %x28-5B / %x5D-10FFFD / SESC / CRLF
Erratum ID 6543 proposes handling the two cases in separateABNF rules (where, with an updated SESC, BCHAR obviously needs to beupdated as above):¶
; Proposal from Erratum ID 6543:bytes = %x27 *BCHAR %x27 / bsqual %x27 *QCHAR %x27BCHAR = %x20-26 / %x28-5B / %x5D-10FFFD / SESC / CRLFQCHAR = DIGIT / ALPHA / "+" / "/" / "-" / "_" / "=" / WS
This potentially causes a subtle change, which is hidden in the WS rule:¶
; ABNF from RFC 8610:WS = SP / NLSP = %x20NL = COMMENT / CRLFCOMMENT = ";" *PCHAR CRLFPCHAR = %x20-7E / %x80-10FFFDCRLF = %x0A / %x0D.0A
This allows any non-C0 character in a comment, so this fragmentbecomes possible:¶
foo = h' 43424F52 ; 'CBOR' 0A ; LF, but don't use CR!'¶
The current text is not unambiguously saying whether the three apostrophesneed to be escaped with a\
or not, as in:¶
foo = h' 43424F52 ; \'CBOR\' 0A ; LF, but don\'t use CR!'¶
... which would be supported by the existing ABNF in[RFC8610].¶
This document takes the simpler approach of leaving the processing ofthe content of the byte string literal to a semantic step afterprocessing the syntax of thebytes
andBCHAR
rules, as updated byFigures2 and4 inSection 2.1 (updates prompted by the combinationof[Err6527] and[Err6278]).¶
Therefore, the rules inFigure 14 (as updated byFigure 4) are applied to the result of thisprocessing wherebsqual
is given ash
orb64
.¶
Note that this approach also works well with the use of byte stringsinSection 3 of [RFC9165].It does require some care when copying-and-pasting into CDDL models from ABNFthat contains single quotes (which may also hide as apostrophesin comments); these need to be escaped or possibly replaced by%x27
.¶
Finally, the approach taken lends support to extendingbsqual
in CDDLsimilar to the way this is done for CBOR diagnostic notation in[EDN-LITERALS].(Note that, at the time of writing, the processing of string literals is quite similar for bothCDDL and Extended Diagnostic Notation (EDN), except that CDDL has end-of-line comments that are ";
" based and EDN hastwo comment syntaxes: one in-line "/
" based and one end-of-line "#
" based.)¶
Many thanks go to the submitters of the errata reports addressed inthis document.In one of the ensuing discussions,Doug Ewell proposed defining anABNF rule "NONASCII", of which we have included the essence.Special thanks to the reviewersMarco Tiloca,Christian Amsüss (Shepherd Review and further guidance),Orie Steele (ADReview and further guidance), andÉric Vyncke(detailed IESG review).¶