├── .gitattributes ├── README.md └── draft-rundgren-jose-json-crypto-normalization.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable LF normalization for all files 2 | * -text -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Although working, this scheme has been superseded by [JSON Canonicalization](https://github.com/cyberphone/json-canonicalization#json-canonicalization). 2 | 3 | # json-crypto-normalization 4 | Internet-Draft describing the JSON processing rules used in Cleartext JWS and JWE as well as in some other schemes 5 | where "Crypto Safe" JSON is utilized. 6 | 7 | ## View draft in traditional RFC format: 8 | https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https%3A%2F%2Fraw.githubusercontent.com%2Fcyberphone%2Fjson-crypto-normalization%2Fmaster%2Fdraft-rundgren-jose-json-crypto-normalization.xml 9 | 10 | ## View draft in HTML markup: 11 | https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https%3A%2F%2Fraw.githubusercontent.com%2Fcyberphone%2Fjson-crypto-normalization%2Fmaster%2Fdraft-rundgren-jose-json-crypto-normalization.xml&modeAsFormat=html%2Fascii 12 | -------------------------------------------------------------------------------- /draft-rundgren-jose-json-crypto-normalization.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | JSON Crypto Normalization (JCN) 17 | 18 | 19 | 20 | Independent 21 |
22 | 23 | 24 | 25 | Montpellier 26 | France 27 | 28 | anders.rundgren.net@gmail.com 29 |
30 |
31 | 32 | 33 | 34 | Security 35 | 36 | JSON Object Signing and Encryption (JOSE) 37 | 38 | 39 | JOSE, JSON, ECMAScript, Signatures, Cryptography, Canonicalization 40 | 41 | 42 | 43 | 44 | Cryptographic operations like hashing and signing depend on that the 45 | target data does not change during serialization, transport, or parsing. 46 | By applying the JCN (JSON Crypto Normalization) scheme, data provided in the 47 | JSON format can be exchanged "as is", 48 | while still being suitable for cryptographic operations. 49 | JCN achieves this by exploiting the strict predictability 50 | offered by the JSON parsing and serialization methods defined in 51 | ECMAScript beginning with version 6 . 52 | 53 | 54 | The intended audience of this document is JSON tool vendors who 55 | may need updating their products in order to support schemes like 56 | Cleartext JSON Web Signature , 57 | building on ECMAScript JSON processing rules. 58 | The latter also have utility outside of cryptography. 59 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | Cryptographic operations like hashing and signing depend on that the 67 | target data does not change during serialization, transport, or parsing. 68 | A straightforward way of accomplishing this is converting the data into 69 | a format which has a simple and fixed representation like Base64Url 70 | which for example have been used in JWS . 71 | Another solution is creating a canonicalized version of the target data 72 | with XML Signature as a prime example. 73 | 74 | 75 | Although the mentioned approaches obviously work, the ability 76 | applying cryptographic operations on JSON data (without encoding it 77 | in Base64Url or having to rely on standalone canonicalizers) became 78 | fully realistic with the advent of ECMAScript (aka JavaScript) version 6 79 | from now on referred to as "ES6". 80 | 81 | 82 | Realistic in this context means "available" since ES6 83 | compatible JSON processing is already supported by most Web browsers, 84 | Node.js , 85 | as well as by third party libraries like Open Keystore . 86 | 87 | 88 | The JCN specification describes how JSON processing rules compliant 89 | with ES6, can be used for supporting "Crypto Safe" JSON. 90 | 91 |
92 | 93 |
94 | 95 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL 96 | NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", 97 | "MAY", and "OPTIONAL" in this document are to be interpreted as 98 | described in BCP 14 99 | when, and only when, they appear in all capitals, as shown here. 100 | 101 |
102 | 103 |
104 | 105 | This section elaborates on the different issues related to JCN and how they are addressed by ES6. 106 | 107 |
108 | 109 | When parsing JSON string data the following MUST be taken in account: 110 | 111 | 112 | 113 | 114 | The input data MUST conform to JSON as specified in . 115 | 116 | Note: ES6 requires that data encoded as UTF-8 , 117 | is converted to the internal ES6 string format (which is based on UTF-16), 118 | in order to make it processable 119 | by the ES6 JSON.parse() method. 120 | 121 | 122 | The property names within a JSON object MUST be unique. 123 | 124 | Note: this is currently not checked by ES6 compatible parsers. 125 | 126 | 127 | Whitespace MUST be removed which in practical terms means removal 128 | of all characters outside of quoted strings having a value of x09, 129 | x0a, x0d or x20. This is the de-facto standard for JSON parsers, 130 | indirectly derived from the JSON specification 131 | itself. 132 | 133 | 134 | All JSON escape sequences 135 | (\/ \" \\ \b \f \n \r \t \uhhhh) 136 | within quoted strings MUST be converted to their proper single 137 | character internal representation. 138 | ES6 defines this behavior in Section 11.8.4. 139 | 140 | 141 | 142 |
143 |
144 | 145 | It is common knowledge that the order of properties in JSON is insignificant. 146 | 147 | 148 | However, this is not equivalent with disrespecting the order in which properties 149 | are supplied in JSON objects during parsing or serialization. 150 | It is obvious that if you parse (or create) a JSON object like 151 | 152 | 153 |
154 | 161 |
162 |
163 | 164 | and it would serialize like 165 | 166 | 167 |
168 | 175 |
176 |
177 | 178 | the result would not only possibly surprise the developer; it would break a signature 179 | depending on an immutable representation of JSON data. 180 | 181 | 182 | ES6 does with a minor exception described in , 183 | maintain an internal "Creation Order" of properties, per 184 | Section 9.1.12 of ES6. 185 | This ordering applies to the following core operations that may 186 | be used for dealing with "Crypto Safe" JSON data: 187 | 188 | 189 | 190 | 191 | Creation of an empty JSON object: 192 | 193 | obj = {} 194 | 195 | 196 | 197 | Parsing of a JSON string into a JSON object: 198 | 199 | obj = JSON.parse('...') 200 | 201 | 202 | 203 | Serialization of a JSON object into JSON string: 204 | 205 | ... = JSON.stringify(obj) 206 | 207 | 208 | 209 | Shallow cloning (only the top level properties are copied) of a JSON object: 210 | 211 | ... = Object.assign({}, obj) 212 | 213 | 214 | 215 | Deep cloning of a JSON object: 216 | 217 | ... = JSON.parse(JSON.stringify(obj)) 218 | 219 | 220 | 221 | Deletion of a JSON property: 222 | 223 | delete obj.property 224 | 225 | 226 | 227 | Addition of a JSON property: 228 | 229 | obj.property = ... 230 | 231 | 232 | 233 | 234 | 235 | Although the above is specified in ES6 notation, a JSON tool kit 236 | for another platform MUST provide the same functionality 237 | in order to be compliant with this specification. 238 | 239 |
240 |
241 |
242 | 243 | Assume that you parse a JSON object like the following 244 | using the rules outlined in the previous sections: 245 | 246 | 247 |
248 | 252 |
253 |
254 | 255 | If you subsequently serialize the object created by the operation above, 256 | using an ES6 compliant serializer, 257 | the result would (with a line wrap between elements for display purposes only), 258 | be rather divergent with respect to data representation: 259 | 260 | 261 |
262 | 264 |
265 |
266 | Note: \u20ac denotes the Euro character, which not being ASCII, is currently not displayable in RFCs. 267 | 268 | The reason for the huge difference between the parsed data and its 269 | serialized counterpart, is due to a wider tolerance on input data than on output data. 270 | 271 | For serializing JSON data according to ES6 the following rules apply: 272 | 273 | 274 | The literals null, true, 275 | and false present no challenge since they already have a 276 | fixed definition in JSON . 277 | 278 | 279 | For data of the type String (which includes 280 | property names as well), each character MUST be serialized as 281 | described in Section 24.3.2.2 of ES6. 282 | 283 | If the Unicode value falls within the traditional ASCII control 284 | character range (0x0000-0x001f), it MUST 285 | be serialized using lowercase hexadecimal Unicode notation (\uhhhh) unless it is in the 286 | set of predefined JSON control characters 0x0008, 0x0009, 0x000a, 0x000c or 0x000d 287 | which MUST be serialized as \b, \t, \n, \f and \r respectively. 288 | 289 | If the Unicode value is outside of the ASCII control character range, it MUST 290 | be serialized "as is" unless it is equivalent to 291 | 0x005c (\) or 0x0022 (") which MUST be serialized as \\ and \" respectively. 292 | 293 | 294 | Data of the type Number, MUST be serialized according to 295 | Section 7.1.12.1 of ES6; for 296 | maximum interoperability preferably including the "Note 2" enhancement as well. 297 | The latter is implemented by for example Google's V8 . 298 | 299 | Due to the relative complexity of this part, it is not included in this specification. 300 | 301 | Note that ES6 builds on the IEEE-754 double precision 302 | standard for storing Number data. If the target 303 | JSON system uses another format it may be difficult achieving full 304 | interoperability with respect to numeric data. 305 | 306 | holds a set of test values. 307 | 308 | 309 | 310 |
311 |
312 | 313 | The final step is converting the textual output into an UTF-8 formatted array. 314 | Applied to the sample in this should yield the following bytes here shown in hexadecimal notation: 315 | 316 | 317 |
318 | 322 |
323 |
324 | 325 | This data is intended to be usable as 326 | interoperable input to cryptographic functions. 327 | 328 |
329 |
330 |
331 |
332 | 333 | For execution speed optimization reasons, ES6 internally rearranges 334 | the order of properties with names expressed as integers, making a 335 | parsed JSON string like 336 | 337 | 338 |
339 | 340 |
341 |
342 | 343 | actually serialize as 344 | 345 | 346 |
347 | 348 |
349 |
350 | 351 | which is in conflict with the requirements stated in . 352 | Due to this fact, signature creators MUST 353 | "emulate" this scheme since this behavior is not 354 | intended to be an additional requirement to support by JSON tools in 355 | general in order to use this specification. 356 | 357 | The easiest way accomplishing this is to programmatically make sure that possible 358 | numeric property names always are created first and added in ascending 359 | order. 360 | 361 |
362 | 363 |
364 | 365 | This document has no IANA actions. 366 | 367 |
368 | 369 |
370 | 371 | JSON parsers MUST check that input data conforms to the JSON 372 | specification. 373 | 374 |
375 | 376 |
377 | 378 | Building on ES6 number normalization was originally 379 | proposed by James Manger. This ultimately led to 380 | the adoption of the entire ES6 JSON processing model. 381 | 382 |
383 |
384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | ECMAScript 2015 Language Specification 394 | 395 | Ecma International 396 | 397 | 398 | 399 | 400 | 401 | 402 | IEEE Standard for Floating-Point Arithmetic 403 | 404 | IEEE 405 | 406 | 407 | 408 | 409 | 410 | 411 | The Unicode Standard, Version 10.0.0 412 | 413 | The Unicode Consortium 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | Chrome V8 Open Source JavaScript Engine 425 | 426 | Google LLC 427 | 428 | 429 | 430 | 431 | 432 | 433 | Work-In-Progress: Cleartext JSON Web Signature 434 | 435 | Erdtman, S., Rundgren, A. and M. Jones 436 | 437 | 438 | 439 | 440 | 441 | 442 | Node.js 443 | 444 | 445 | 446 | 447 | 448 | 449 | Open Keystore 450 | 451 | 452 | 453 | 454 | 455 | 456 | XML Signature Syntax and Processing Version 1.1 457 | 458 | W3C 459 | 460 | 461 | 462 | 463 | 464 | 465 |
466 | 467 | The following table holds a set of ES6 Number serializations including 468 | some edge cases. The field "ES6 Internal" refers to the internal 469 | ES6 representation of the Number data type which is based on the 470 | IEEE-754 standard using 64-bit (double precision) values, 471 | here expressed in hexadecimal. 472 | 473 | 474 |
475 | 518 |
519 |
520 |
521 |
522 |
523 | --------------------------------------------------------------------------------