idnits 2.17.1 draft-rundgren-json-canonicalization-scheme-02.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The abstract seems to contain references ([RFC7493], [RFC8259], [ES6]), which it shouldn't. Please replace those with straight textual mentions of the documents in question. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (December 19, 2018) is 1926 days in the past. Is this intentional? Checking references for intended status: Informational ---------------------------------------------------------------------------- == Missing Reference: 'RFC4648' is mentioned on line 407, but not defined == Missing Reference: 'RFC7515' is mentioned on line 411, but not defined == Missing Reference: 'XMLDSIG' is mentioned on line 422, but not defined == Missing Reference: 'NODEJS' is mentioned on line 403, but not defined == Missing Reference: 'RFC7638' is mentioned on line 415, but not defined == Missing Reference: 'KEYBASE' is mentioned on line 400, but not defined -- Looks like a reference, but probably isn't: '1' on line 427 == Missing Reference: 'V8' is mentioned on line 419, but not defined == Missing Reference: 'OPENAPI' is mentioned on line 657, but not defined -- Looks like a reference, but probably isn't: '2' on line 715 -- Looks like a reference, but probably isn't: '3' on line 717 -- Looks like a reference, but probably isn't: '4' on line 720 -- Looks like a reference, but probably isn't: '5' on line 723 -- Looks like a reference, but probably isn't: '6' on line 731 -- Looks like a reference, but probably isn't: '7' on line 733 -- Looks like a reference, but probably isn't: '8' on line 735 -- Looks like a reference, but probably isn't: '9' on line 740 Summary: 1 error (**), 0 flaws (~~), 9 warnings (==), 10 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Network Working Group A. Rundgren 3 Internet-Draft Independent 4 Intended status: Informational December 19, 2018 5 Expires: June 22, 2019 7 JSON Canonicalization Scheme (JCS) 8 draft-rundgren-json-canonicalization-scheme-02 10 Abstract 12 Cryptographic operations like hashing and signing depend on that the 13 target data does not change during serialization, transport, or 14 parsing. By applying the rules defined by JCS (JSON Canonicalization 15 Scheme), data provided in the JSON [RFC8259] format can be exchanged 16 "as is", while still being subject to secure cryptographic 17 operations. JCS achieves this by building on the serialization 18 formats for JSON primitives as defined by ECMAScript [ES6], 19 constraining JSON data to the I-JSON [RFC7493] subset, and through a 20 platform independent property sorting scheme. 22 The intended audiences of this document are JSON tool vendors, as 23 well as designers of JSON based cryptographic solutions. 25 Status of This Memo 27 This Internet-Draft is submitted in full conformance with the 28 provisions of BCP 78 and BCP 79. 30 Internet-Drafts are working documents of the Internet Engineering 31 Task Force (IETF). Note that other groups may also distribute 32 working documents as Internet-Drafts. The list of current Internet- 33 Drafts is at https://datatracker.ietf.org/drafts/current/. 35 Internet-Drafts are draft documents valid for a maximum of six months 36 and may be updated, replaced, or obsoleted by other documents at any 37 time. It is inappropriate to use Internet-Drafts as reference 38 material or to cite them other than as "work in progress." 40 This Internet-Draft will expire on June 22, 2019. 42 Copyright Notice 44 Copyright (c) 2018 IETF Trust and the persons identified as the 45 document authors. All rights reserved. 47 This document is subject to BCP 78 and the IETF Trust's Legal 48 Provisions Relating to IETF Documents 49 (https://trustee.ietf.org/license-info) in effect on the date of 50 publication of this document. Please review these documents 51 carefully, as they describe your rights and restrictions with respect 52 to this document. Code Components extracted from this document must 53 include Simplified BSD License text as described in Section 4.e of 54 the Trust Legal Provisions and are provided without warranty as 55 described in the Simplified BSD License. 57 Table of Contents 59 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 60 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 3 61 3. Detailed Operation . . . . . . . . . . . . . . . . . . . . . 3 62 3.1. Creation of JSON Data . . . . . . . . . . . . . . . . . . 3 63 3.2. Canonicalization of JSON Data . . . . . . . . . . . . . . 4 64 3.2.1. Whitespace Handling . . . . . . . . . . . . . . . . . 4 65 3.2.2. Serialization of Primitive Data Types . . . . . . . . 4 66 3.2.2.1. Serialization of Literals . . . . . . . . . . . . 5 67 3.2.2.2. Serialization of Strings . . . . . . . . . . . . 5 68 3.2.2.3. Serialization of Numbers . . . . . . . . . . . . 6 69 3.2.3. Sorting of Object Properties . . . . . . . . . . . . 6 70 3.2.4. UTF-8 Generation . . . . . . . . . . . . . . . . . . 7 71 4. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8 72 5. Security Considerations . . . . . . . . . . . . . . . . . . . 8 73 6. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 8 74 7. References . . . . . . . . . . . . . . . . . . . . . . . . . 8 75 7.1. Normative References . . . . . . . . . . . . . . . . . . 8 76 7.2. Informal References . . . . . . . . . . . . . . . . . . . 9 77 7.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 9 78 Appendix A. ES6 Sample Canonicalizer . . . . . . . . . . . . . . 10 79 Appendix B. Number Serialization Samples . . . . . . . . . . . . 11 80 Appendix C. Canonicalized JSON as "Wire Format" . . . . . . . . 13 81 Appendix D. Dealing with Big Numbers . . . . . . . . . . . . . . 14 82 Appendix E. Implementation Guidelines . . . . . . . . . . . . . 15 83 Appendix F. Open Source Implementations . . . . . . . . . . . . 16 84 Appendix G. Other JSON Canonicalization Efforts . . . . . . . . 16 85 Appendix H. Development Portal . . . . . . . . . . . . . . . . . 16 86 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 16 88 1. Introduction 90 Cryptographic operations like hashing and signing depend on that the 91 target data does not change during serialization, transport, or 92 parsing. A straightforward way of accomplishing this is converting 93 the data into a format having a simple and fixed representation like 94 Base64Url [RFC4648], used in JWS [RFC7515]. Another solution is 95 creating a canonicalized version of the target data with XML 96 Signature [XMLDSIG] as a prime example. 98 Since the objective was keeping the data "as is", the 99 canonicalization method was selected. For avoiding "reinventing the 100 wheel", JCS relies on serialization of JSON primitives compatible 101 with ECMAScript (aka JavaScript) beginning with version 6 [ES6], from 102 now on simply referred to as "ES6". 104 Seasoned XML developers recalling difficulties getting signatures to 105 validate (usually due to different interpretations of the quite 106 intricate XML canonicalization rules as well as of the equally 107 extensive Web Services security standards), may rightfully wonder why 108 JCS would not suffer from similar issues. The reasons are twofold: 110 o The absence of a namespace concept and default values, as well as 111 constraining data to I-JSON eliminate the need for specific 112 parsing schemes for canonicalized data. 114 o JCS compatible serialization of JSON primitives is already 115 supported by most Web browsers and Node.js [NODEJS], while the 116 full JCS specification is supported by multiple Open Source 117 implementations (see Appendix F), giving the proposed 118 canonicalization scheme a head start. Also see Appendix E. 120 The JCS specification describes how serialization of JSON primitives 121 compliant with ES6, combined with an elementary property sorting 122 scheme, can be used for supporting "Crypto Safe" JSON. 124 JCS is compatible with some existing systems relying on JSON 125 canonicalization such as JWK Thumbprint [RFC7638] and Keybase 126 [KEYBASE]. 128 2. Terminology 130 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 131 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 132 "OPTIONAL" in this document are to be interpreted as described in BCP 133 14 [RFC2119] [RFC8174] when, and only when, they appear in all 134 capitals, as shown here. 136 3. Detailed Operation 138 This section describes the different issues related to JSON 139 canonicalization, and how they are addressed by JCS. 141 3.1. Creation of JSON Data 143 In order to canonicalize JSON data, an internal representation of the 144 JSON data is needed. This can be achieved by: 146 o Parsing externally supplied JSON data. 148 o Programmatic creation of JSON data. 150 Irrespective of method used, the JSON data MUST be compatible both 151 with ES6 and I-JSON [RFC7493], which implies the following: 153 o There MUST NOT be any duplicate property names within an "Object". 155 o Data of the type "String" MUST be expressible as Unicode [UNICODE] 156 strings. Also see Section 3.2.2.2. 158 o Data of the type "Number" MUST be expressible as IEEE-754 159 [IEEE754] double precision values. Also see Section 3.2.2.3. 161 3.2. Canonicalization of JSON Data 163 The following sub sections describe the steps required for creating a 164 canonicalized version of internal JSON data elaborated on in the 165 previous section. 167 Appendix A shows sample code for an ES6 based canonicalizer, matching 168 the JCS specification. 170 3.2.1. Whitespace Handling 172 Whitespace between JSON elements MUST NOT be emitted. 174 3.2.2. Serialization of Primitive Data Types 176 Assume that you parse a JSON object like the following: 178 { 179 "numbers": [333333333.33333329, 1E30, 4.50, 180 2e-3, 0.000000000000000000000000001], 181 "string": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/", 182 "literals": [null, true, false] 183 } 185 If you subsequently serialize the object created by the operation 186 above using an serializer compliant with ES6's "JSON.stringify()", 187 the result would (with a line wrap added for display purposes only), 188 be rather divergent with respect to representation of data: 190 {"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string": 191 "\u20ac$\u000f\nA'B\"\\\\\"/","literals":[null,true,false]} 193 Note: \u20ac denotes the Euro character, which not 194 being ASCII, is currently not displayable in RFCs. 196 The reason for the difference between the parsed data and its 197 serialized counterpart, is due to a wide tolerance on input data (as 198 defined by JSON [RFC8259]), while output data (as defined by ES6), 199 has a fixed representation. As can be seen by the example, numbers 200 are subject to rounding as well. 202 The following sub sections describe serialization of primitive JSON 203 data types according to JCS. This part is identical to that of ES6. 205 3.2.2.1. Serialization of Literals 207 The JSON literals "null", "true", and "false" present no challenge 208 since they already have a fixed definition in JSON [RFC8259]. 210 3.2.2.2. Serialization of Strings 212 For JSON data of the type "String" (which includes "Object" property 213 names as well), each character MUST be serialized as described below 214 (also matching section 24.3.2.2 of ES6): 216 o If the Unicode value falls within the traditional ASCII control 217 character range (U+0000 through U+001F), it MUST be serialized 218 using lowercase hexadecimal Unicode notation (\uhhhh) unless it is 219 in the set of predefined JSON control characters U+0008, U+0009, 220 U+000A, U+000C or U+000D which MUST be serialized as \b, \t, \n, 221 \f and \r respectively. 223 o If the Unicode value is outside of the ASCII control character 224 range, it MUST be serialized "as is" unless it is equivalent to 225 U+005C (\) or U+0022 (") which MUST be serialized as \\ and \" 226 respectively. 228 Finally, the serialized string value MUST be enclosed in double 229 quotes ("). 231 Note: some JSON systems permit the use of invalid Unicode data like 232 "lone surrogates" (e.g. U+DEAD), which also is dealt with in a 233 platform specific way. Since this leads to interoperability issues 234 including broken signatures, such usages MUST be avoided. 236 Note: although the Unicode standard offers a possibility combining 237 certain characters into one, referred to as "Unicode Normalization" 238 (https://www.unicode.org/reports/tr15/ [1]), such functionality MUST 239 be delegated to the application layer which already is the case for 240 most other uses of JSON. 242 3.2.2.3. Serialization of Numbers 244 JSON data of the type "Number" MUST be serialized according to 245 section 7.1.12.1 of ES6; for maximum interoperability preferably 246 including the "Note 2" enhancement as well. The latter is 247 implemented by for example Google's V8 [V8]. 249 Due to the relative complexity of this part, it is not included in 250 this specification. 252 Note: ES6 builds on the IEEE-754 [IEEE754] double precision standard 253 for storing "Number" data. Appendix B holds a set of IEEE-754 sample 254 values and their corresponding JSON serialization. 256 Occasionally applications need higher precision or longer integers 257 than offered by the current implementation of JSON "Number" in ES6. 258 Appendix D outlines how this can be achieved in a portable and 259 extensible way. 261 3.2.3. Sorting of Object Properties 263 Although the previous step indeed normalized the representation of 264 primitive JSON data types, the result would not qualify as canonical 265 since JSON "Object" properties are not in lexicographic 266 (alphabetical) order. 268 Applied to the sample in Section 3.2.2, a properly canonicalized 269 version should (with a line wrap added for display purposes only), 270 read as: 272 {"literals":[null,true,false],"numbers":[333333333.3333333, 273 1e+30,4.5,0.002,1e-27],"string":"\u20ac$\u000f\nA'B\"\\\\\"/"} 275 Note: \u20ac denotes the Euro character, which not 276 being ASCII, is currently not displayable in RFCs. 278 The rules for lexicographic sorting of JSON "Object" properties 279 according to JCS are as follows: 281 o JSON "Object" properties MUST be sorted in a recursive manner 282 which means that a found JSON child "Object" type MUST be subject 283 to sorting as well. 285 o JSON "Array" data MUST also be scanned for presence of sortable 286 JSON "Object" elements, but array element order MUST NOT be 287 changed. 289 When a JSON "Object" is about to have its properties sorted, the 290 following measures MUST be adhered to: 292 o The sorting process is applied to the internal representation of 293 property strings. That is, their state before serialization. 295 o Property strings to be sorted depend on that such strings are 296 formatted as arrays of UTF-16 [UNICODE] code units. The sorting 297 is based on pure value comparisons, where code units are treated 298 as unsigned integers, independent of locale settings. 300 o Property strings either have different values at some index that 301 is a valid index for both strings, or their lengths are different, 302 or both. If they have different values at one or more index 303 positions, let k be the smallest such index; then the string whose 304 value at position k has the smaller value, as determined by using 305 the < operator, lexicographically precedes the other string. If 306 there is no index position at which they differ, then the shorter 307 string lexicographically precedes the longer string. 309 The rationale for basing the sort algorithm on UTF-16 code units is 310 that it maps directly to the string type in ECMAScript, Java and 311 .NET. Systems using another internal representation of string data 312 will need to convert JSON property strings into arrays of UTF-16 code 313 units before sorting. 315 Note: for the purpose obtaining a deterministic property order, 316 sorting on UTF-8 or UTF-32 encoded data would also work, but the 317 result would differ (and thus be incompatible with this 318 specification). 320 3.2.4. UTF-8 Generation 322 Finally, in order to create a platform independent representation, 323 the resulting JSON string data MUST be encoded in UTF-8. 325 Applied to the sample in Section 3.2.3 this should yield the 326 following bytes here shown in hexadecimal notation: 328 7b 22 6c 69 74 65 72 61 6c 73 22 3a 5b 6e 75 6c 6c 2c 74 72 329 75 65 2c 66 61 6c 73 65 5d 2c 22 6e 75 6d 62 65 72 73 22 3a 330 5b 33 33 33 33 33 33 33 33 33 2e 33 33 33 33 33 33 33 2c 31 331 65 2b 33 30 2c 34 2e 35 2c 30 2e 30 30 32 2c 31 65 2d 32 37 332 5d 2c 22 73 74 72 69 6e 67 22 3a 22 e2 82 ac 24 5c 75 30 30 333 30 66 5c 6e 41 27 42 5c 22 5c 5c 5c 5c 5c 22 2f 22 7d 335 This data is intended to be usable as input to cryptographic methods 336 as well as for value comparisons of JSON objects. 338 For other uses see Appendix C. 340 4. IANA Considerations 342 This document has no IANA actions. 344 5. Security Considerations 346 It is vital performing "sanity" checks on input data to avoid 347 overflowing buffers and similar things that could affect the 348 integrity of the system. By doing that an incorrectly implemented 349 JCS algorithm or improperly canonicalized data should not introduce a 350 security problem, but rather make the associated application 351 (preferably gracefully) fail due to a broken signature, hash or 352 comparison. 354 6. Acknowledgements 356 Building on ES6 "Number" normalization was originally proposed by 357 James Manger. This ultimately led to the adoption of the entire ES6 358 serialization scheme for JSON primitives. 360 Other people who have contributed with valuable input to this 361 specification include John-Mark Gurney, Mike Jones, Mike Miller, Mike 362 Samuel, Michal Wadas, Richard Gibson, Robert Tupelo-Schneck and Scott 363 Ananian. 365 7. References 367 7.1. Normative References 369 [ES6] Ecma International, "ECMAScript 2015 Language 370 Specification", . 373 [IEEE754] IEEE, "IEEE Standard for Floating-Point Arithmetic", 374 August 2008, . 376 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 377 Requirement Levels", BCP 14, RFC 2119, 378 DOI 10.17487/RFC2119, March 1997, 379 . 381 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 382 DOI 10.17487/RFC7493, March 2015, 383 . 385 [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 386 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 387 May 2017, . 389 [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 390 Interchange Format", STD 90, RFC 8259, 391 DOI 10.17487/RFC8259, December 2017, 392 . 394 [UNICODE] The Unicode Consortium, "The Unicode Standard, Version 395 10.0.0", 396 . 398 7.2. Informal References 400 [KEYBASE] "Keybase", 401 . 403 [NODEJS] "Node.js", . 405 [OPENAPI] "The OpenAPI Initiative", . 407 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data 408 Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, 409 . 411 [RFC7515] Jones, M., Bradley, J., and N. Sakimura, "JSON Web 412 Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May 413 2015, . 415 [RFC7638] Jones, M. and N. Sakimura, "JSON Web Key (JWK) 416 Thumbprint", RFC 7638, DOI 10.17487/RFC7638, September 417 2015, . 419 [V8] Google LLC, "Chrome V8 Open Source JavaScript Engine", 420 . 422 [XMLDSIG] W3C, "XML Signature Syntax and Processing Version 1.1", 423 . 425 7.3. URIs 427 [1] https://www.unicode.org/reports/tr15/ 429 [2] https://www.npmjs.com/package/canonicalize 431 [3] https://github.com/erdtman/java-json-canonicalization 433 [4] https://github.com/cyberphone/json-canonicalization/tree/master/ 434 dotnet 436 [5] https://github.com/cyberphone/json-canonicalization/tree/master/ 437 python3 439 [6] https://tools.ietf.org/html/draft-staykov-hu-json-canonical- 440 form-00 442 [7] https://gibson042.github.io/canonicaljson-spec/ 444 [8] http://wiki.laptop.org/go/Canonical_JSON 446 [9] https://github.com/cyberphone/json-canonicalization 448 Appendix A. ES6 Sample Canonicalizer 450 Below is a functionally complete example of a JCS compliant 451 canonicalizer for usage with ES6 based systems. 453 Note: the primary purpose of this code is highlighting the 454 canonicalization algorithm. Using the full power of ES6 would reduce 455 the code size considerably but would also be more difficult to follow 456 by non-experts. 458 var canonicalize = function(object) { 460 var buffer = ''; 461 serialize(object); 462 return buffer; 464 function serialize(object) { 465 if (object === null || typeof object !== 'object') { 466 ///////////////////////////////////////////////// 467 // Primitive data type - Use ES6/JSON // 468 ///////////////////////////////////////////////// 469 buffer += JSON.stringify(object); 471 } else if (Array.isArray(object)) { 472 ///////////////////////////////////////////////// 473 // Array - Maintain element order // 474 ///////////////////////////////////////////////// 475 buffer += '['; 476 let next = false; 477 object.forEach((element) => { 478 if (next) { 479 buffer += ','; 480 } 481 next = true; 482 ///////////////////////////////////////// 483 // Array element - Recursive expansion // 484 ///////////////////////////////////////// 485 serialize(element); 486 }); 487 buffer += ']'; 489 } else { 490 ///////////////////////////////////////////////// 491 // Object - Sort properties before serializing // 492 ///////////////////////////////////////////////// 493 buffer += '{'; 494 let next = false; 495 Object.keys(object).sort().forEach((property) => { 496 if (next) { 497 buffer += ','; 498 } 499 next = true; 500 /////////////////////////////////////////////// 501 // Property names are strings - Use ES6/JSON // 502 /////////////////////////////////////////////// 503 buffer += JSON.stringify(property); 504 buffer += ':'; 505 ////////////////////////////////////////// 506 // Property value - Recursive expansion // 507 ////////////////////////////////////////// 508 serialize(object[property]); 509 }); 510 buffer += '}'; 511 } 512 } 513 }; 515 Appendix B. Number Serialization Samples 517 The following table holds a set of ES6 "Number" serialization 518 samples, including some edge cases. The column "IEEE-754" refers to 519 the internal ES6 representation of the "Number" data type which is 520 based on the IEEE-754 [IEEE754] standard using 64-bit (double 521 precision) values, here expressed in hexadecimal. 523 |===================================================================| 524 | IEEE-754 | JSON Representation | Comment | 525 |===================================================================| 526 | 0000000000000000 | 0 | Zero | 527 |-------------------------------------------------------------------| 528 | 8000000000000000 | 0 | Minus zero | 529 |-------------------------------------------------------------------| 530 | 0000000000000001 | 5e-324 | Smallest pos number | 531 |-------------------------------------------------------------------| 532 | 8000000000000001 | -5e-324 | Smallest neg number | 533 |-------------------------------------------------------------------| 534 | 7fefffffffffffff | 1.7976931348623157e+308 | Largest pos number | 535 |-------------------------------------------------------------------| 536 | ffefffffffffffff | -1.7976931348623157e+308 | Largest neg number | 537 |-------------------------------------------------------------------| 538 | 4340000000000000 | 9007199254740992 | Largest pos integer | 539 |-------------------------------------------------------------------| 540 | c340000000000000 | -9007199254740992 | Largest neg integer | 541 |-------------------------------------------------------------------| 542 | 7fffffffffffffff | | Error (NaN) | 543 |-------------------------------------------------------------------| 544 | 7ff0000000000000 | | Error (Infinity) | 545 |-------------------------------------------------------------------| 546 | 44b52d02c7e14af5 | 9.999999999999997e+22 | | 547 |-------------------------------------------------------------------| 548 | 44b52d02c7e14af6 | 1e+23 | | 549 |-------------------------------------------------------------------| 550 | 44b52d02c7e14af7 | 1.0000000000000001e+23 | | 551 |-------------------------------------------------------------------| 552 | 444b1ae4d6e2ef4e | 999999999999999700000 | | 553 |-------------------------------------------------------------------| 554 | 444b1ae4d6e2ef4f | 999999999999999900000 | | 555 |-------------------------------------------------------------------| 556 | 444b1ae4d6e2ef50 | 1e+21 | | 557 |-------------------------------------------------------------------| 558 | 444b1ae4d6e2ef51 | 1.0000000000000001e+21 | | 559 |-------------------------------------------------------------------| 560 | 41b3de4355555553 | 333333333.3333332 | | 561 |-------------------------------------------------------------------| 562 | 41b3de4355555554 | 333333333.33333325 | | 563 |-------------------------------------------------------------------| 564 | 41b3de4355555555 | 333333333.3333333 | | 565 |-------------------------------------------------------------------| 566 | 41b3de4355555556 | 333333333.3333334 | | 567 |-------------------------------------------------------------------| 568 | 41b3de4355555557 | 333333333.33333343 | | 569 |-------------------------------------------------------------------| 570 Note: for maximum compliance with ECMAScript's JSON object, values 571 that are to be interpreted as true integers, SHOULD be in the range 572 -9007199254740991 to 9007199254740991. 574 Note: although a set of specific integers like 2**68 575 (4430000000000000 in IEEE-754 format) could be regarded as having 576 extended precision, the JCS/ES6 number serialization algorithm does 577 not take this in consideration. 579 Appendix C. Canonicalized JSON as "Wire Format" 581 Since the result from the canonicalization process (see 582 Section 3.2.4), is fully valid JSON, it can also be used as 583 "Wire Format". However, this is just an option since cryptographic 584 schemes based on JCS, in most cases would not depend on that 585 externally supplied JSON data already is canonicalized. 587 In fact, the ES6 standard way of serializing objects using 588 "JSON.stringify()" produces a more "logical" format, where properties 589 are kept in the order they were created or received. The example 590 below shows an address record which could benefit from ES6 standard 591 serialization: 593 { 594 "name": "John Doe", 595 "address": "2000 Sunset Boulevard", 596 "city": "Los Angeles", 597 "zip": "90001", 598 "state": "CA" 599 } 601 Using canonicalization the properties above would be output in the 602 order "address", "city", "name", "state" and "zip", which adds 603 fuzziness to the data from a human (developer or technical support), 604 perspective. 606 That is, for many applications, canonicalization would only be used 607 internally for creating a "hashable" representation of the data 608 needed for cryptographic operations. 610 Note: if message size is not a concern, you may even send 611 "Pretty Printed" JSON data on the wire (since whitespace always is 612 ignored by the canonicalization process). 614 Appendix D. Dealing with Big Numbers 616 There are two major issues associated with the JSON "Number" type, 617 here illustrated by the following sample object: 619 { 620 "giantNumber": 1.4e+9999, 621 "payMeThis": 26000.33, 622 "int64Max": 9223372036854775807 623 } 625 Although the sample above conforms to JSON (according to [RFC8259]), 626 there are some practical hurdles to consider: 628 o Standard JSON parsers rarely process "giantNumber" in a meaningful 629 way. 64-bit integers like "int64Max" normally pass through 630 parsers, but in systems like ES6, at the expense of lost 631 precision. 633 o Another issue is that parsers typically would use different 634 schemes for handling "giantNumber" and "int64Max". In addition, 635 monetary data like "payMeThis" would presumably not rely on a 636 floating point system due to rounding issues with respect to 637 decimal arithmetic. 639 The (to the author NB), only known way handling this kind of 640 "overloading" of the "Number" type (at least in an extensible 641 manner), is through mapping mechanisms, instructing parsers what 642 to do with different properties based on their name. However, 643 this greatly limits the value of using the "Number" type outside 644 of its original somewhat constrained, JavaScript context. 646 For usage with JCS (and in fact for any usage of JSON by multiple 647 parties potentially using independently developed software), numbers 648 that do not have a natural place in the current JSON ecosystem MUST 649 be wrapped using the JSON "String" type. This is close to a de-facto 650 standard for open systems. 652 Aided by a mapping system; be it programmatic like 654 var obj = JSON.parse('{"giantNumber": "1.4e+9999"}'); 655 var biggie = new BigNumber(obj.giantNumber); 657 or declarative schemes like OpenAPI [OPENAPI], there are no real 658 limits, not even when using ES6. 660 Appendix E. Implementation Guidelines 662 The optimal solution is integrating support for JCS directly in JSON 663 serializers (parsers need no changes). That is, canonicalization 664 would just be an additional "mode" for a JSON serializer. However, 665 this is currently not the case. Fortunately JCS support can be 666 performed through externally supplied canonicalizer software, 667 enabling signature creation schemes like the following: 669 1. Create the data to be signed. 671 2. Serialize the data using existing JSON tools. 673 3. Let the external canonicalizer process the serialized data and 674 return canonicalized result data. 676 4. Sign the canonicalized data. 678 5. Add the resulting signature value to the original JSON data 679 through a designated signature property. 681 6. Serialize the completed (now signed) JSON object using existing 682 JSON tools. 684 A compatible signature verification scheme would then be as follows: 686 1. Parse the signed JSON data using existing JSON tools. 688 2. Read and save the signature value from the designated signature 689 property. 691 3. Remove the signature property from the parsed JSON object. 693 4. Serialize the remaining JSON data using existing JSON tools. 695 5. Let the external canonicalizer process the serialized data and 696 return canonicalized result data. 698 6. Verify that the canonicalized data matches the saved signature 699 value using the algorithm and key used for creating the 700 signature. 702 A canonicalizer like above is effectively only a "filter", 703 potentially usable with a multitude of quite different cryptographic 704 schemes. 706 Using a JSON serializer with integrated JCS support, the 707 serialization performed before the canonicalization step could be 708 eliminated for both processes. 710 Appendix F. Open Source Implementations 712 The following Open Source implementations have been verified to be 713 compatible with JCS: 715 o JavaScript: https://www.npmjs.com/package/canonicalize [2] 717 o Java: https://github.com/erdtman/java-json-canonicalization [3] 719 o .NET/C#: https://github.com/cyberphone/json- 720 canonicalization/tree/master/dotnet [4] 722 o Python: https://github.com/cyberphone/json- 723 canonicalization/tree/master/python3 [5] 725 Appendix G. Other JSON Canonicalization Efforts 727 There are (and have been) other efforts creating "Canonical JSON". 728 Below is a list of URLs to some of them: 730 o https://tools.ietf.org/html/draft-staykov-hu-json-canonical- 731 form-00 [6] 733 o https://gibson042.github.io/canonicaljson-spec/ [7] 735 o http://wiki.laptop.org/go/Canonical_JSON [8] 737 Appendix H. Development Portal 739 The JSC specification is currently developed at 740 https://github.com/cyberphone/json-canonicalization [9]. 742 The portal also provides software for on-line testing as well as test 743 data for implementers. 745 Author's Address 747 Anders Rundgren 748 Independent 749 Montpellier 750 France 752 Email: anders.rundgren.net@gmail.com 753 URI: https://www.linkedin.com/in/andersrundgren/