JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.73k stars 3.25k forks source link

Support for Canonicalization (Sorting) #1688

Open cyberphone opened 6 years ago

cyberphone commented 6 years ago

Using canonicalization, it becomes very simple adding a digital signature to a JSON object: https://github.com/cyberphone/json-canonicalization/tree/master/dotnet/json.net.sign

I have skimmed the code and it "seems" that the least intrusive change would be to add one field to Netwonsoft.Json.Formatting.

The suggested change would introduce the following algorithm: https://cyberphone.github.io/doc/security/draft-rundgren-json-canonicalization-scheme.html#json.sorting.properties

It would be sufficient calling this formatting mode Sorted since there are other things needed for full-blown I-JSON compatible signature support.

cyberphone commented 6 years ago

You may wonder what the purpose is, right?

Current standard for signed JSON: https://openid.net/specs/openid-financial-api-part-2.html#request

eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ew0KICJpc3MiOiA
(... abbreviated for brevity ...)
zCYIb_NMXvtTIVc1jpspnTSD7xMbpL-2QgwUsAlMGzw

JSON clear text signature alternatives depend on canonicalization:

{
  "id": "johndoe",
  "counter": 3,
  "list": [
    "yes",
    "no"
  ],
  "signature": {
    "alg": "HS256",
    "kid": "mykey",
    "val": "rlKLoCBExrwB7NaChPtQ3cAxr83eGdpLA7txrg49slw"
  }
}

End of Base64 tyranny 😂!!!

dbc2 commented 6 years ago

It's easy enough to do already during serialization, see e.g. OrderedContractResolver from Order of serialized fields using JSON.NET when serializing a type using reflection.

Some additional effort would be required for dictionaries or dynamic objects though.

cyberphone commented 6 years ago

@dbc2 Yes, I took an updated version the stackoverflow sample (added StringComparer which is compatible with the sorting algorithm)

    public class Canonicalizer : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            return base.CreateProperties(type, memberSerialization)
                .OrderBy(p => p.PropertyName, StringComparer.Ordinal).ToList();
        }
    }

for a scheme using declared objects but it failed for dynamic objects since the supplied contract resolver is never called (which may be logical since there is no contract).

Anyway, sorting alone does not enable signatures like above; serialization of JSON primitives must also conform to a standard and the only available such is specified in ECMAScript. Here is a 2000 line port achieving that: https://github.com/cyberphone/json-canonicalization/tree/master/dotnet/es6numberserialization

radu-matei commented 5 years ago

Hi, everyone! First of all, thanks for opening this issue, @cyberphone (and for the linked library).

I do believe adding a canonical formatter would be extremely helpful, specifically when trying to sign JSON files, and I agree that @cyberphone's suggestion of adding a new formatter in the enum.

@JamesNK - is this something we want to add in a future release? However, if that is not the case, what would be the best way to pass a custom formatter when serializing? (not a contract resolver).

yufeih commented 5 years ago

This is a very useful formatting option for us to achieve deterministic output. Cloud Native App Bundle is also using Canonical JSON.

drauch commented 4 years ago

Is there any .NET library (Newtonsoft.Json or not) which supports Canonical JSON output? We're in desperate need of one :-)

cyberphone commented 4 years ago

Hi @drauch, here you have source for a variant of Canonical JSON: https://github.com/cyberphone/json-canonicalization/tree/master/dotnet The referenced specification is currently in the RFC publication queue.

drauch commented 4 years ago

Thank you for the recommendation.