pax_global_header00006660000000000000000000000064147164570620014526gustar00rootroot0000000000000052 comment=d703796cbb0a4045e04d63089317859428080a59 golang-webpki-org-jsoncanonicalizer-1.0.1/000077500000000000000000000000001471645706200205515ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/.gitignore000066400000000000000000000007711471645706200225460ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out coverageout coverage.html goreportcard.db # Dependency directories (remove the comment below to include it) # vendor/ # vscode */.vscode *.code-workspace # sublime text *.sublime-workspace *.sublime-project # Mac files .DS_Store golang-webpki-org-jsoncanonicalizer-1.0.1/LICENSE000066400000000000000000000261361471645706200215660ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-webpki-org-jsoncanonicalizer-1.0.1/README.md000066400000000000000000000066621471645706200220420ustar00rootroot00000000000000![JCS](https://cyberphone.github.io/doc/security/jcs.svg) # JSON Canonicalization [![Go Report Card](https://goreportcard.com/badge/github.com/gowebpki/jcs)](https://goreportcard.com/report/github.com/gowebpki/jcs) [![godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://pkg.go.dev/github.com/gowebpki/jcs) [![GitHub license](https://img.shields.io/github/license/gowebpki/jcs.svg?style=flat)](https://github.com/gowebpki/jcs/blob/master/LICENSE) [![GitHub go.mod Go version of a Go module](https://img.shields.io/github/go-mod/go-version/gowebpki/jcs.svg?style=flat)](https://github.com/gowebpki/jcs) Cryptographic operations like hashing and signing depend on that the target data does not change during serialization, transport, or parsing. By applying the rules defined by JCS (JSON Canonicalization Scheme), data provided in the JSON [[RFC8259](https://tools.ietf.org/html/rfc8259)] format can be exchanged "as is", while still being subject to secure cryptographic operations. JCS achieves this by building on the serialization formats for JSON primitives as defined by ECMAScript [[ES](https://ecma-international.org/ecma-262/)], constraining JSON data to the I-JSON [[RFC7493](https://tools.ietf.org/html//rfc7493)] subset, and through a platform independent property sorting scheme. Public RFC: https://tools.ietf.org/html/rfc8785 The JSON Canonicalization Scheme concept in a nutshell: - Serialization of primitive JSON data types using methods compatible with ECMAScript's `JSON.stringify()` - Lexicographic sorting of JSON `Object` properties in a *recursive* process - JSON `Array` data is also subject to canonicalization, *but element order remains untouched* ### Original Work This code was originally created by Anders Rundgren aka cyberphone and can be found here: https://github.com/cyberphone/json-canonicalization. This fork and work is done with Anders' permission and is an attempt to clean up the Golang version. ### Sample Input ```code { "numbers": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001], "string": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/", "literals": [null, true, false] } ``` ### Expected Output ```code {"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"} ``` Note: for platform interoperable canonicalization, the output must be converted to UTF-8 as well, here shown in hexadecimal notation: ```code 7b 22 6c 69 74 65 72 61 6c 73 22 3a 5b 6e 75 6c 6c 2c 74 72 75 65 2c 66 61 6c 73 65 5d 2c 22 6e 75 6d 62 65 72 73 22 3a 5b 33 33 33 33 33 33 33 33 33 2e 33 33 33 33 33 33 33 2c 31 65 2b 33 30 2c 34 2e 35 2c 30 2e 30 30 32 2c 31 65 2d 32 37 5d 2c 22 73 74 72 69 6e 67 22 3a 22 e2 82 ac 24 5c 75 30 30 30 66 5c 6e 41 27 42 5c 22 5c 5c 5c 5c 5c 22 2f 22 7d ``` ### Combining JCS and JWS (RFC7515) [JWS-JCS](https://github.com/cyberphone/jws-jcs#combining-detached-jws-with-jcs-json-canonicalization-scheme) ### On-line Browser JCS Test https://cyberphone.github.io/doc/security/browser-json-canonicalization.html ### ECMAScript Proposal: JSON.canonify() [JSON.canonify()](https://github.com/cyberphone/json-canonicalization/blob/master/JSON.canonify.md) ### Other Canonicalization Efforts https://tools.ietf.org/html/draft-staykov-hu-json-canonical-form-00 http://wiki.laptop.org/go/Canonical_JSON https://gibson042.github.io/canonicaljson-spec/ https://gist.github.com/mikesamuel/20710f94a53e440691f04bf79bc3d756 golang-webpki-org-jsoncanonicalizer-1.0.1/es6numfmt.go000066400000000000000000000032211471645706200230220ustar00rootroot00000000000000// Copyright 2021 Bret Jordan & Benedikt Thoma, All rights reserved. // Copyright 2006-2019 WebPKI.org (http://webpki.org). // // Use of this source code is governed by an Apache 2.0 license that can be // found in the LICENSE file in the root of the source tree. package jcs import ( "errors" "math" "strconv" "strings" ) const invalidPattern uint64 = 0x7ff0000000000000 // NumberToJSON converts numbers in IEEE-754 double precision into the // format specified for JSON in EcmaScript Version 6 and forward. // The core application for this is canonicalization per RFC 8785: func NumberToJSON(ieeeF64 float64) (res string, err error) { ieeeU64 := math.Float64bits(ieeeF64) // Special case: NaN and Infinity are invalid in JSON if (ieeeU64 & invalidPattern) == invalidPattern { return "null", errors.New("Invalid JSON number: " + strconv.FormatUint(ieeeU64, 16)) } // Special case: eliminate "-0" as mandated by the ES6-JSON/JCS specifications if ieeeF64 == 0 { // Right, this line takes both -0 and 0 return "0", nil } // Deal with the sign separately var sign string = "" if ieeeF64 < 0 { ieeeF64 = -ieeeF64 sign = "-" } // ES6 has a unique "g" format var format byte = 'e' if ieeeF64 < 1e+21 && ieeeF64 >= 1e-6 { format = 'f' } // The following should (in "theory") do the trick: es6Formatted := strconv.FormatFloat(ieeeF64, format, -1, 64) // Ryu version exponent := strings.IndexByte(es6Formatted, 'e') if exponent > 0 { // Go outputs "1e+09" which must be rewritten as "1e+9" if es6Formatted[exponent+2] == '0' { es6Formatted = es6Formatted[:exponent+2] + es6Formatted[exponent+3:] } } return sign + es6Formatted, nil } golang-webpki-org-jsoncanonicalizer-1.0.1/es6numfmt_test.go000066400000000000000000000056571471645706200241000ustar00rootroot00000000000000// Copyright 2021 Bret Jordan & Benedikt Thoma, All rights reserved. // Copyright 2006-2019 WebPKI.org (http://webpki.org). // // Use of this source code is governed by an Apache 2.0 license that can be // found in the LICENSE file in the root of the source tree. package jcs import ( "bufio" "math" "os" "strconv" "strings" "testing" "github.com/stretchr/testify/require" ) const testFile = "/home/test/es6testfile100m.txt" const invalidNumber = "null" type numberParsingTestCase struct { desc string ieeeHex string expected string } func TestNumberToJSON(t *testing.T) { r := require.New(t) testCases := []numberParsingTestCase{ { ieeeHex: "4340000000000001", expected: "9007199254740994", }, { ieeeHex: "4340000000000002", expected: "9007199254740996", }, { ieeeHex: "444b1ae4d6e2ef50", expected: "1e+21", }, { ieeeHex: "3eb0c6f7a0b5ed8d", expected: "0.000001", }, { ieeeHex: "3eb0c6f7a0b5ed8c", expected: "9.999999999999997e-7", }, { ieeeHex: "8000000000000000", expected: "0", }, { ieeeHex: "7fffffffffffffff", expected: invalidNumber, }, { ieeeHex: "7ff0000000000000", expected: invalidNumber, }, { ieeeHex: "fff0000000000000", expected: invalidNumber, }, } if _, err := os.Stat(testFile); err == nil { file, err := os.Open(testFile) r.NoErrorf(err, "Failed at reading test sample file: %s\n", err) scanner := bufio.NewScanner(file) var lineCount int for scanner.Scan() { lineCount++ line := scanner.Text() lineSl := strings.Split(line, ",") r.Equalf(len(lineSl), 2, "Failed because a comma is missing in line %v\n", lineCount) hex := lineSl[0] expected := lineSl[1] t.Run(expected, func(t *testing.T) { testNumberParsing(t, r, numberParsingTestCase{ desc: expected, ieeeHex: hex, expected: expected, }) }) } r.NoErrorf(err, "Failed at scanning test file: %s\n", err) file.Close() } else if os.IsNotExist(err) { } else { r.NoErrorf(err, "Failed at testing if numbers test file exists: %s\n", err) } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { testNumberParsing(t, r, tC) }) } } func testNumberParsing(t *testing.T, r *require.Assertions, tC numberParsingTestCase) { for len(tC.ieeeHex) < 16 { tC.ieeeHex = "0" + tC.ieeeHex } ieeeU64, err := strconv.ParseUint(tC.ieeeHex, 16, 64) r.NoErrorf(err, "Failed at parsing tC.ieeeHex [%s]: %s\n", tC.ieeeHex, err) ieeeF64 := math.Float64frombits(ieeeU64) es6Created, err := NumberToJSON(ieeeF64) if tC.expected == invalidNumber { r.Errorf(err, "Failed because parsing number to json did not return an error even though the expected JSON is null\n") } else { r.NoErrorf(err, "Failed at converting float to json: %s\n", err) } r.Equalf(tC.expected, es6Created, "Failed because converted number [%s] (tC.ieeeHex [%s]) does not match tC.expected [%s]\n", es6Created, tC.ieeeHex, tC.expected) } golang-webpki-org-jsoncanonicalizer-1.0.1/go.mod000066400000000000000000000001241471645706200216540ustar00rootroot00000000000000module github.com/gowebpki/jcs go 1.15 require github.com/stretchr/testify v1.7.0 golang-webpki-org-jsoncanonicalizer-1.0.1/go.sum000066400000000000000000000020001471645706200216740ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= golang-webpki-org-jsoncanonicalizer-1.0.1/jcs.go000066400000000000000000000243211471645706200216610ustar00rootroot00000000000000// Copyright 2021 Bret Jordan & Benedikt Thoma, All rights reserved. // Copyright 2006-2019 WebPKI.org (http://webpki.org). // // Use of this source code is governed by an Apache 2.0 license that can be // found in the LICENSE file in the root of the source tree. // Package jcs transforms UTF-8 JSON data into a canonicalized version according RFC 8785 package jcs import ( "container/list" "errors" "fmt" "strconv" "strings" "unicode/utf16" ) type nameValueType struct { name string sortKey []uint16 value string } type jcsData struct { // JSON data MUST be UTF-8 encoded jsonData []byte // Current pointer in jsonData index int } // JSON standard escapes (modulo \u) var ( asciiEscapes = []byte{'\\', '"', 'b', 'f', 'n', 'r', 't'} binaryEscapes = []byte{'\\', '"', '\b', '\f', '\n', '\r', '\t'} ) // JSON literals var literals = []string{"true", "false", "null"} // Transform converts raw JSON data from a []byte array into a canonicalized version according RFC 8785 func Transform(jsonData []byte) ([]byte, error) { if jsonData == nil { return nil, errors.New("No JSON data provided") } // Create a JCS Data struct to store the JSON Data and the index. var jd jcsData jd.jsonData = jsonData j := &jd transformed, err := j.parseEntry() if err != nil { return nil, err } for j.index < len(j.jsonData) { if !j.isWhiteSpace(j.jsonData[j.index]) { return nil, errors.New("Improperly terminated JSON object") } j.index++ } return []byte(transformed), err } func (j *jcsData) isWhiteSpace(c byte) bool { return c == 0x20 || c == 0x0a || c == 0x0d || c == 0x09 } func (j *jcsData) nextChar() (byte, error) { if j.index < len(j.jsonData) { c := j.jsonData[j.index] if c > 0x7f { return 0, errors.New("Unexpected non-ASCII character") } j.index++ return c, nil } return 0, errors.New("Unexpected EOF reached") } // scan advances index on jsonData to the first non whitespace character and returns it. func (j *jcsData) scan() (byte, error) { for { c, err := j.nextChar() if err != nil { return 0, err } if j.isWhiteSpace(c) { continue } return c, nil } } func (j *jcsData) scanFor(expected byte) error { c, err := j.scan() if err != nil { return err } if c != expected { return fmt.Errorf("Expected %s but got %s", string(expected), string(c)) } return nil } func (j *jcsData) getUEscape() (rune, error) { start := j.index for i := 0; i < 4; i++ { _, err := j.nextChar() if err != nil { return 0, err } } u16, err := strconv.ParseUint(string(j.jsonData[start:j.index]), 16, 64) if err != nil { return 0, err } return rune(u16), nil } func (j *jcsData) decorateString(rawUTF8 string) string { var quotedString strings.Builder quotedString.WriteByte('"') CoreLoop: for _, c := range []byte(rawUTF8) { // Is this within the JSON standard escapes? for i, esc := range binaryEscapes { if esc == c { quotedString.WriteByte('\\') quotedString.WriteByte(asciiEscapes[i]) continue CoreLoop } } if c < 0x20 { // Other ASCII control characters must be escaped with \uhhhh quotedString.WriteString(fmt.Sprintf("\\u%04x", c)) } else { quotedString.WriteByte(c) } } quotedString.WriteByte('"') return quotedString.String() } // parseEntry is the entrypoint into the parsing control flow func (j *jcsData) parseEntry() (string, error) { c, err := j.scan() if err != nil { return "", err } j.index-- switch c { case '{', '"', '[': return j.parseElement() default: value, err := parseLiteral(string(j.jsonData)) if err != nil { return "", err } j.index = len(j.jsonData) return value, nil } } func (j *jcsData) parseQuotedString() (string, error) { var rawString strings.Builder CoreLoop: for { var c byte if j.index < len(j.jsonData) { c = j.jsonData[j.index] j.index++ } else { return "", errors.New("Unexpected EOF reached") } if c == '"' { break } if c < ' ' { return "", errors.New("Unterminated string literal") } else if c == '\\' { // Escape sequence c, err := j.nextChar() if err != nil { return "", err } if c == 'u' { // The \u escape firstUTF16, err := j.getUEscape() if err != nil { return "", err } if utf16.IsSurrogate(firstUTF16) { // If the first UTF-16 code unit has a certain value there must be // another succeeding UTF-16 code unit as well backslash, err := j.nextChar() if err != nil { return "", err } u, err := j.nextChar() if err != nil { return "", err } if backslash != '\\' || u != 'u' { return "", errors.New("Missing surrogate") } // Output the UTF-32 code point as UTF-8 uEscape, err := j.getUEscape() if err != nil { return "", err } rawString.WriteRune(utf16.DecodeRune(firstUTF16, uEscape)) } else { // Single UTF-16 code identical to UTF-32. Output as UTF-8 rawString.WriteRune(firstUTF16) } } else if c == '/' { // Benign but useless escape rawString.WriteByte('/') } else { // The JSON standard escapes for i, esc := range asciiEscapes { if esc == c { rawString.WriteByte(binaryEscapes[i]) continue CoreLoop } } return "", fmt.Errorf("Unexpected escape: \\%s", string(c)) } } else { // Just an ordinary ASCII character alternatively a UTF-8 byte // outside of ASCII. // Note that properly formatted UTF-8 never clashes with ASCII // making byte per byte search for ASCII break characters work // as expected. rawString.WriteByte(c) } } return rawString.String(), nil } func (j *jcsData) parseSimpleType() (string, error) { var token strings.Builder j.index-- // no condition is needed here. // if the buffer reaches EOF scan returns an error, or we terminate because the // json simple type terminates for { c, err := j.scan() if err != nil { return "", err } if c == ',' || c == ']' || c == '}' { j.index-- break } token.WriteByte(c) } if token.Len() == 0 { return "", errors.New("Missing argument") } return parseLiteral(token.String()) } func parseLiteral(value string) (string, error) { // Is it a JSON literal? for _, literal := range literals { if literal == value { return literal, nil } } // Apparently not so we assume that it is a I-JSON number ieeeF64, err := strconv.ParseFloat(value, 64) if err != nil { return "", err } value, err = NumberToJSON(ieeeF64) if err != nil { return "", err } return value, nil } func (j *jcsData) parseElement() (string, error) { c, err := j.scan() if err != nil { return "", err } switch c { case '{': return j.parseObject() case '"': str, err := j.parseQuotedString() if err != nil { return "", err } return j.decorateString(str), nil case '[': return j.parseArray() default: return j.parseSimpleType() } } func (j *jcsData) peek() (byte, error) { c, err := j.scan() if err != nil { return 0, err } j.index-- return c, nil } func (j *jcsData) parseArray() (string, error) { var arrayData strings.Builder var next bool arrayData.WriteByte('[') for { c, err := j.peek() if err != nil { return "", err } if c == ']' { j.index++ break } if next { err = j.scanFor(',') if err != nil { return "", err } arrayData.WriteByte(',') } else { next = true } element, err := j.parseElement() if err != nil { return "", err } arrayData.WriteString(element) } arrayData.WriteByte(']') return arrayData.String(), nil } func (j *jcsData) lexicographicallyPrecedes(sortKey []uint16, e *list.Element) (bool, error) { // Find the minimum length of the sortKeys oldSortKey := e.Value.(nameValueType).sortKey minLength := len(oldSortKey) if minLength > len(sortKey) { minLength = len(sortKey) } for q := 0; q < minLength; q++ { diff := int(sortKey[q]) - int(oldSortKey[q]) if diff < 0 { // Smaller => Precedes return true, nil } else if diff > 0 { // Bigger => No match return false, nil } // Still equal => Continue } // The sortKeys compared equal up to minLength if len(sortKey) < len(oldSortKey) { // Shorter => Precedes return true, nil } if len(sortKey) == len(oldSortKey) { return false, fmt.Errorf("Duplicate key: %s", e.Value.(nameValueType).name) } // Longer => No match return false, nil } func (j *jcsData) parseObject() (string, error) { nameValueList := list.New() var next bool = false CoreLoop: for { c, err := j.peek() if err != nil { return "", err } if c == '}' { // advance index because of peeked '}' j.index++ break } if next { err = j.scanFor(',') if err != nil { return "", err } } next = true err = j.scanFor('"') if err != nil { return "", err } rawUTF8, err := j.parseQuotedString() if err != nil { break } // Sort keys on UTF-16 code units // Since UTF-8 doesn't have endianess this is just a value transformation // In the Go case the transformation is UTF-8 => UTF-32 => UTF-16 sortKey := utf16.Encode([]rune(rawUTF8)) err = j.scanFor(':') if err != nil { return "", err } element, err := j.parseElement() if err != nil { return "", err } nameValue := nameValueType{rawUTF8, sortKey, element} for e := nameValueList.Front(); e != nil; e = e.Next() { // Check if the key is smaller than a previous key if precedes, err := j.lexicographicallyPrecedes(sortKey, e); err != nil { return "", err } else if precedes { // Precedes => Insert before and exit sorting nameValueList.InsertBefore(nameValue, e) continue CoreLoop } // Continue searching for a possibly succeeding sortKey // (which is straightforward since the list is ordered) } // The sortKey is either the first or is succeeding all previous sortKeys nameValueList.PushBack(nameValue) } // Now everything is sorted so we can properly serialize the object var objectData strings.Builder objectData.WriteByte('{') next = false for e := nameValueList.Front(); e != nil; e = e.Next() { if next { objectData.WriteByte(',') } next = true nameValue := e.Value.(nameValueType) objectData.WriteString(j.decorateString(nameValue.name)) objectData.WriteByte(':') objectData.WriteString(nameValue.value) } objectData.WriteByte('}') return objectData.String(), nil } golang-webpki-org-jsoncanonicalizer-1.0.1/jcs_test.go000066400000000000000000000054261471645706200227250ustar00rootroot00000000000000// Copyright 2021 Bret Jordan & Benedikt Thoma, All rights reserved. // Copyright 2006-2019 WebPKI.org (http://webpki.org). // // Use of this source code is governed by an Apache 2.0 license that can be // found in the LICENSE file in the root of the source tree. package jcs import ( "bytes" "fmt" "os" "path/filepath" "testing" "github.com/stretchr/testify/require" ) const ( pathTestData = "./testdata" pathInputRelativeToTestData = "/input" pathOutputRelativeToTestData = "/output" ) func failedBecause(errormsg string) string { return fmt.Sprintf("Failed because %s", errormsg) } func errorOccurred(activity string, err error) string { return failedBecause(fmt.Sprintf("an error occurred while %s: %s\n", activity, err)) } func doesNotMatchExpected(expectedField, expectedValue, actualField, actualValue string) string { return failedBecause( fmt.Sprintf( "%s [%s] does not match expected %s [%s]\n", actualField, actualValue, expectedField, expectedValue, ), ) } func TestTransform(t *testing.T) { testCases := []struct { desc string filename string }{ { desc: "Null", filename: "null.json", }, { desc: "True", filename: "true.json", }, { desc: "False", filename: "false.json", }, { desc: "Arrays", filename: "arrays.json", }, { desc: "French", filename: "french.json", }, { desc: "SimpleString", filename: "simpleString.json", }, { desc: "Structures", filename: "structures.json", }, { desc: "Unicode", filename: "unicode.json", }, { desc: "Values", filename: "values.json", }, { desc: "Weird", filename: "weird.json", }, } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { tC := tC t.Parallel() r := require.New(t) input, err := os.ReadFile(filepath.Join(pathTestData, pathInputRelativeToTestData, tC.filename)) r.NoError(err, errorOccurred("reading test input json", err)) output, err := os.ReadFile(filepath.Join(pathTestData, pathOutputRelativeToTestData, tC.filename)) r.NoError(err, errorOccurred("reading expected transformed output sample", err)) transformed, err := Transform(input) r.NoError(err, errorOccurred("transforming test input", err)) twiceTransformed, err := Transform(input) r.NoError(err, errorOccurred("transforming transformed input", err)) r.True( bytes.Equal(transformed, output), doesNotMatchExpected( "JSON", string(output), "transformed JSON", string(transformed), ), ) r.True( bytes.Equal(twiceTransformed, transformed), doesNotMatchExpected( "transformed JSON", string(transformed), "twice transformed JSON", string(twiceTransformed), ), ) }) } } golang-webpki-org-jsoncanonicalizer-1.0.1/test/000077500000000000000000000000001471645706200215305ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/test/verify-canonicalization/000077500000000000000000000000001471645706200263575ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/test/verify-canonicalization/verify-canonicalization.go000066400000000000000000000042371471645706200335430ustar00rootroot00000000000000// // Copyright 2006-2019 WebPKI.org (http://webpki.org). // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This program verifies the JSON canonicalizer using a test suite // containing sample data and expected output package main import ( "bytes" "fmt" "io/ioutil" "path/filepath" "runtime" "github.com/gowebpki/jcs" ) func check(e error) { if e != nil { panic(e) } } var testdata string var failures = 0 func read(fileName string, directory string) []byte { data, err := ioutil.ReadFile(filepath.Join(filepath.Join(testdata, directory), fileName)) check(err) return data } func verify(fileName string) { actual, err := jcs.Transform(read(fileName, "input")) check(err) recycled, err2 := jcs.Transform(actual) check(err2) expected := read(fileName, "output") utf8InHex := "\nFile: " + fileName byteCount := 0 next := false for _, b := range actual { if byteCount%32 == 0 { utf8InHex = utf8InHex + "\n" next = false } byteCount++ if next { utf8InHex = utf8InHex + " " } next = true utf8InHex = utf8InHex + fmt.Sprintf("%02x", b) } fmt.Println(utf8InHex + "\n") if !bytes.Equal(actual, expected) || !bytes.Equal(actual, recycled) { failures++ fmt.Println("THE TEST ABOVE FAILED!") } } func main() { _, executable, _, _ := runtime.Caller(0) testdata = filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(executable))), "jcs/testdata") fmt.Println(testdata) files, err := ioutil.ReadDir(filepath.Join(testdata, "input")) check(err) for _, file := range files { verify(file.Name()) } if failures == 0 { fmt.Println("All tests succeeded!") } else { fmt.Printf("\n****** ERRORS: %d *******\n", failures) } } golang-webpki-org-jsoncanonicalizer-1.0.1/test/verify-numbers/000077500000000000000000000000001471645706200245055ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/test/verify-numbers/verify-numbers.go000066400000000000000000000052541471645706200300170ustar00rootroot00000000000000// // Copyright 2006-2019 WebPKI.org (http://webpki.org). // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This program tests the JSON number serializer using both a few discrete // values as well as the 100 million value test suite package main import ( "bufio" "fmt" "math" "os" "strconv" "strings" "github.com/gowebpki/jcs" ) func check(e error) { if e != nil { panic(e) } } // Change the file name to suit your environment const testFile = "c:\\es6\\numbers\\es6testfile100m.txt" const invalidNumber = "null" var conversionErrors int = 0 func verify(ieeeHex string, expected string) { for len(ieeeHex) < 16 { ieeeHex = "0" + ieeeHex } ieeeU64, err := strconv.ParseUint(ieeeHex, 16, 64) check(err) ieeeF64 := math.Float64frombits(ieeeU64) es6Created, err := jcs.NumberToJSON(ieeeF64) if expected == invalidNumber { if err == nil { panic("Missing error") } return } check(err) if es6Created != expected { conversionErrors++ fmt.Println("\n" + ieeeHex) fmt.Println(es6Created) fmt.Println(expected) } esParsed, err := strconv.ParseFloat(expected, 64) check(err) if esParsed != ieeeF64 { panic("Parsing error ieeeHex: " + ieeeHex + " expected: " + expected) } } func main() { verify("4340000000000001", "9007199254740994") verify("4340000000000002", "9007199254740996") verify("444b1ae4d6e2ef50", "1e+21") verify("3eb0c6f7a0b5ed8d", "0.000001") verify("3eb0c6f7a0b5ed8c", "9.999999999999997e-7") verify("8000000000000000", "0") verify("7fffffffffffffff", invalidNumber) verify("7ff0000000000000", invalidNumber) verify("fff0000000000000", invalidNumber) file, err := os.Open(testFile) check(err) defer file.Close() scanner := bufio.NewScanner(file) var lineCount int = 0 for scanner.Scan() { lineCount++ if lineCount%1000000 == 0 { fmt.Printf("line: %d\n", lineCount) } line := scanner.Text() comma := strings.IndexByte(line, ',') if comma <= 0 { panic("Missing comma!") } verify(line[:comma], line[comma+1:]) } check(scanner.Err()) if conversionErrors == 0 { fmt.Printf("\nSuccessful Operation. Lines read: %d\n", lineCount) } else { fmt.Printf("\n****** ERRORS: %d *******\n", conversionErrors) } } golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/000077500000000000000000000000001471645706200223625ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/README.md000066400000000000000000000017161471645706200236460ustar00rootroot00000000000000## Test Data The [input](input) directory contains files with non-canonicalized data which is supposed be transformed as specified by the corresponding file in the [output](output) directory. In the [outhex](outhex) directory the expected output is expressed in hexadecimal byte notation. ## ES6 Numbers For testing ES6 number serialization there is a ZIP file on https://1drv.ms/u/s!AmhUDQ0Od0GTiXeAjaBJFLJlxyg0?e=HFG4Ao containing about a 100 million of random and edge-case values. The test file consists of lines ```code hex-ieee,expected\n ``` where `hex-ieee` holds 1-16 ASCII hexadecimal characters representing an IEEE-754 double precision value while `expected` holds the expected serialized value. Each line is terminated by a single new-line character. Sample lines: ```code 4340000000000001,9007199254740994 4340000000000002,9007199254740996 444b1ae4d6e2ef50,1e+21 3eb0c6f7a0b5ed8d,0.000001 3eb0c6f7a0b5ed8c,9.999999999999997e-7 8000000000000000,0 0,0 ``` golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/000077500000000000000000000000001471645706200235215ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/arrays.json000066400000000000000000000000761471645706200257200ustar00rootroot00000000000000[ 56, { "d": true, "10": null, "1": [ ] } ] golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/false.json000066400000000000000000000000051471645706200255010ustar00rootroot00000000000000falsegolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/french.json000066400000000000000000000002261471645706200256610ustar00rootroot00000000000000{ "peach": "This sorting order", "péché": "is wrong according to French", "pêche": "but canonicalization MUST", "sin": "ignore locale" } golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/null.json000066400000000000000000000000041471645706200253600ustar00rootroot00000000000000nullgolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/simpleString.json000066400000000000000000000000401471645706200270660ustar00rootroot00000000000000 "this is a test string 1235"golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/structures.json000066400000000000000000000002121471645706200266320ustar00rootroot00000000000000{ "1": {"f": {"f": "hi","F": 5} ,"\n": 56.0}, "10": { }, "": "empty", "a": { }, "111": [ {"e": "yes","E": "no" } ], "A": { } }golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/true.json000066400000000000000000000000041471645706200253650ustar00rootroot00000000000000truegolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/unicode.json000066400000000000000000000000471471645706200260430ustar00rootroot00000000000000{ "Unnormalized Unicode":"A\u030a" } golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/values.json000066400000000000000000000002661471645706200257170ustar00rootroot00000000000000{ "numbers": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001], "string": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/", "literals": [null, true, false] }golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/input/weird.json000066400000000000000000000004331471645706200255260ustar00rootroot00000000000000{ "\u20ac": "Euro Sign", "\r": "Carriage Return", "\u000a": "Newline", "1": "One", "\u0080": "Control\u007f", "\ud83d\ude02": "Smiley", "\u00f6": "Latin Small Letter O With Diaeresis", "\ufb33": "Hebrew Letter Dalet With Dagesh", "": "Browser Challenge" } golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/000077500000000000000000000000001471645706200236765ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/arrays.txt000066400000000000000000000001401471645706200257330ustar00rootroot000000000000005b 35 36 2c 7b 22 31 22 3a 5b 5d 2c 22 31 30 22 3a 6e 75 6c 6c 2c 22 64 22 3a 74 72 75 65 7d 5d golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/false.txt000066400000000000000000000000161471645706200255260ustar00rootroot0000000000000066 61 6C 73 65golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/french.txt000066400000000000000000000006061471645706200257060ustar00rootroot000000000000007b 22 70 65 61 63 68 22 3a 22 54 68 69 73 20 73 6f 72 74 69 6e 67 20 6f 72 64 65 72 22 2c 22 70 c3 a9 63 68 c3 a9 22 3a 22 69 73 20 77 72 6f 6e 67 20 61 63 63 6f 72 64 69 6e 67 20 74 6f 20 46 72 65 6e 63 68 22 2c 22 70 c3 aa 63 68 65 22 3a 22 62 75 74 20 63 61 6e 6f 6e 69 63 61 6c 69 7a 61 74 69 6f 6e 20 4d 55 53 54 22 2c 22 73 69 6e 22 3a 22 69 67 6e 6f 72 65 20 6c 6f 63 61 6c 65 22 7d golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/null.txt000066400000000000000000000000131471645706200254030ustar00rootroot000000000000006E 75 6C 6Cgolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/structures.txt000066400000000000000000000004461471645706200266660ustar00rootroot000000000000007b 22 22 3a 22 65 6d 70 74 79 22 2c 22 31 22 3a 7b 22 5c 6e 22 3a 35 36 2c 22 66 22 3a 7b 22 46 22 3a 35 2c 22 66 22 3a 22 68 69 22 7d 7d 2c 22 31 30 22 3a 7b 7d 2c 22 31 31 31 22 3a 5b 7b 22 45 22 3a 22 6e 6f 22 2c 22 65 22 3a 22 79 65 73 22 7d 5d 2c 22 41 22 3a 7b 7d 2c 22 61 22 3a 7b 7d 7d golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/true.txt000066400000000000000000000000131471645706200254100ustar00rootroot0000000000000074 72 75 65golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/unicode.txt000066400000000000000000000001321471645706200260610ustar00rootroot000000000000007b 22 55 6e 6e 6f 72 6d 61 6c 69 7a 65 64 20 55 6e 69 63 6f 64 65 22 3a 22 41 cc 8a 22 7d golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/values.txt000066400000000000000000000005421471645706200257370ustar00rootroot000000000000007b 22 6c 69 74 65 72 61 6c 73 22 3a 5b 6e 75 6c 6c 2c 74 72 75 65 2c 66 61 6c 73 65 5d 2c 22 6e 75 6d 62 65 72 73 22 3a 5b 33 33 33 33 33 33 33 33 33 2e 33 33 33 33 33 33 33 2c 31 65 2b 33 30 2c 34 2e 35 2c 30 2e 30 30 32 2c 31 65 2d 32 37 5d 2c 22 73 74 72 69 6e 67 22 3a 22 e2 82 ac 24 5c 75 30 30 30 66 5c 6e 41 27 42 5c 22 5c 5c 5c 5c 5c 22 2f 22 7d golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/outhex/weird.txt000066400000000000000000000012021471645706200255440ustar00rootroot000000000000007b 22 5c 6e 22 3a 22 4e 65 77 6c 69 6e 65 22 2c 22 5c 72 22 3a 22 43 61 72 72 69 61 67 65 20 52 65 74 75 72 6e 22 2c 22 31 22 3a 22 4f 6e 65 22 2c 22 3c 2f 73 63 72 69 70 74 3e 22 3a 22 42 72 6f 77 73 65 72 20 43 68 61 6c 6c 65 6e 67 65 22 2c 22 c2 80 22 3a 22 43 6f 6e 74 72 6f 6c 7f 22 2c 22 c3 b6 22 3a 22 4c 61 74 69 6e 20 53 6d 61 6c 6c 20 4c 65 74 74 65 72 20 4f 20 57 69 74 68 20 44 69 61 65 72 65 73 69 73 22 2c 22 e2 82 ac 22 3a 22 45 75 72 6f 20 53 69 67 6e 22 2c 22 f0 9f 98 82 22 3a 22 53 6d 69 6c 65 79 22 2c 22 ef ac b3 22 3a 22 48 65 62 72 65 77 20 4c 65 74 74 65 72 20 44 61 6c 65 74 20 57 69 74 68 20 44 61 67 65 73 68 22 7d golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/000077500000000000000000000000001471645706200237225ustar00rootroot00000000000000golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/arrays.json000066400000000000000000000000401471645706200261100ustar00rootroot00000000000000[56,{"1":[],"10":null,"d":true}]golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/false.json000066400000000000000000000000051471645706200257020ustar00rootroot00000000000000falsegolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/french.json000066400000000000000000000002021471645706200260540ustar00rootroot00000000000000{"peach":"This sorting order","péché":"is wrong according to French","pêche":"but canonicalization MUST","sin":"ignore locale"}golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/null.json000066400000000000000000000000041471645706200255610ustar00rootroot00000000000000nullgolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/simpleString.json000066400000000000000000000000341471645706200272720ustar00rootroot00000000000000"this is a test string 1235"golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/structures.json000066400000000000000000000001421471645706200270350ustar00rootroot00000000000000{"":"empty","1":{"\n":56,"f":{"F":5,"f":"hi"}},"10":{},"111":[{"E":"no","e":"yes"}],"A":{},"a":{}}golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/true.json000066400000000000000000000000041471645706200255660ustar00rootroot00000000000000truegolang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/unicode.json000066400000000000000000000000361471645706200262420ustar00rootroot00000000000000{"Unnormalized Unicode":"Å"}golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/values.json000066400000000000000000000001661471645706200261170ustar00rootroot00000000000000{"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}golang-webpki-org-jsoncanonicalizer-1.0.1/testdata/output/weird.json000066400000000000000000000003261471645706200257300ustar00rootroot00000000000000{"\n":"Newline","\r":"Carriage Return","1":"One","":"Browser Challenge","€":"Control","ö":"Latin Small Letter O With Diaeresis","€":"Euro Sign","😂":"Smiley","דּ":"Hebrew Letter Dalet With Dagesh"}