diff --git a/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs index 096b47622b..87bef93068 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs @@ -49,9 +49,13 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expressions); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { - Expressions = ((JArray)json["expressions"]).Select(p => FromJson((JObject)p)).ToArray(); + if (maxNestDepth <= 0) throw new FormatException(); + JArray expressions = (JArray)json["expressions"]; + if (expressions.Count > MaxSubitems) throw new FormatException(); + Expressions = expressions.Select(p => FromJson((JObject)p, maxNestDepth - 1)).ToArray(); + if (Expressions.Length == 0) throw new FormatException(); } public override JObject ToJson() diff --git a/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs index ad6a914dd1..8fee03cf07 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs @@ -8,12 +8,13 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; +using System.IO; using Neo.IO; using Neo.Json; using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; -using System.IO; namespace Neo.Network.P2P.Payloads.Conditions { @@ -42,7 +43,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expression); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Expression = json["expression"].GetBoolean(); } @@ -56,7 +57,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Expression); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs index 82f24c7676..0c2a98b86c 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs @@ -13,6 +13,7 @@ using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; namespace Neo.Network.P2P.Payloads.Conditions @@ -42,7 +43,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Hash); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Hash = UInt160.Parse(json["hash"].GetString()); } @@ -56,7 +57,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Hash.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs index 4e5455af57..7e309f4e29 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs @@ -9,6 +9,7 @@ // modifications are permitted. using Neo.IO; +using Neo.Json; using Neo.SmartContract; using System.IO; @@ -18,10 +19,6 @@ public class CalledByEntryCondition : WitnessCondition { public override WitnessConditionType Type => WitnessConditionType.CalledByEntry; - protected override void DeserializeWithoutType(ref MemoryReader reader, int maxNestDepth) - { - } - public override bool Match(ApplicationEngine engine) { var state = engine.CurrentContext.GetState(); @@ -30,8 +27,10 @@ public override bool Match(ApplicationEngine engine) return state.CallingContext is null; } - protected override void SerializeWithoutType(BinaryWriter writer) - { - } + protected override void DeserializeWithoutType(ref MemoryReader reader, int maxNestDepth) { } + + protected override void SerializeWithoutType(BinaryWriter writer) { } + + private protected override void ParseJson(JObject json, int maxNestDepth) { } } } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs index d542d031db..5c91c8bebd 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs @@ -15,6 +15,7 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; using System.Linq; @@ -47,7 +48,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Group); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Group = ECPoint.Parse(json["group"].GetString(), ECCurve.Secp256r1); } @@ -61,7 +62,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Group.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs index 1acd19f190..44299a751c 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs @@ -15,6 +15,7 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; using System.Linq; @@ -47,7 +48,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Group); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Group = ECPoint.Parse(json["group"].GetString(), ECCurve.Secp256r1); } @@ -61,7 +62,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Group.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs index 667a66770c..6bb2c2c9de 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs @@ -47,9 +47,10 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expression); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { - Expression = FromJson((JObject)json["expression"]); + if (maxNestDepth <= 0) throw new FormatException(); + Expression = FromJson((JObject)json["expression"], maxNestDepth - 1); } public override JObject ToJson() diff --git a/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs index c66becde2a..99fb0490cf 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs @@ -49,9 +49,13 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expressions); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { - Expressions = ((JArray)json["expressions"]).Select(p => FromJson((JObject)p)).ToArray(); + if (maxNestDepth <= 0) throw new FormatException(); + JArray expressions = (JArray)json["expressions"]; + if (expressions.Count > MaxSubitems) throw new FormatException(); + Expressions = expressions.Select(p => FromJson((JObject)p, maxNestDepth - 1)).ToArray(); + if (Expressions.Length == 0) throw new FormatException(); } public override JObject ToJson() diff --git a/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs index 315c1fde02..84109b6a99 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs @@ -13,6 +13,7 @@ using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; namespace Neo.Network.P2P.Payloads.Conditions @@ -42,7 +43,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Hash); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Hash = UInt160.Parse(json["hash"].GetString()); } @@ -56,7 +57,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Hash.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs index ed9f55b941..eaed8ff02f 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs @@ -21,7 +21,7 @@ namespace Neo.Network.P2P.Payloads.Conditions { public abstract class WitnessCondition : IInteroperable, ISerializable { - private const int MaxSubitems = 16; + internal const int MaxSubitems = 16; internal const int MaxNestingDepth = 2; /// @@ -92,21 +92,20 @@ void ISerializable.Serialize(BinaryWriter writer) /// The for writing data. protected abstract void SerializeWithoutType(BinaryWriter writer); - private protected virtual void ParseJson(JObject json) - { - } + private protected abstract void ParseJson(JObject json, int maxNestDepth); /// /// Converts the from a JSON object. /// /// The represented by a JSON object. + /// The maximum nesting depth allowed during deserialization. /// The converted . - public static WitnessCondition FromJson(JObject json) + public static WitnessCondition FromJson(JObject json, int maxNestDepth) { WitnessConditionType type = Enum.Parse(json["type"].GetString()); if (ReflectionCache.CreateInstance(type) is not WitnessCondition condition) throw new FormatException("Invalid WitnessConditionType."); - condition.ParseJson(json); + condition.ParseJson(json, maxNestDepth); return condition; } diff --git a/src/Neo/Network/P2P/Payloads/WitnessRule.cs b/src/Neo/Network/P2P/Payloads/WitnessRule.cs index a020191e79..15152776c2 100644 --- a/src/Neo/Network/P2P/Payloads/WitnessRule.cs +++ b/src/Neo/Network/P2P/Payloads/WitnessRule.cs @@ -57,10 +57,15 @@ void ISerializable.Serialize(BinaryWriter writer) /// The converted . public static WitnessRule FromJson(JObject json) { + WitnessRuleAction action = Enum.Parse(json["action"].GetString()); + + if (action != WitnessRuleAction.Allow && action != WitnessRuleAction.Deny) + throw new FormatException(); + return new() { - Action = Enum.Parse(json["action"].GetString()), - Condition = WitnessCondition.FromJson((JObject)json["condition"]) + Action = action, + Condition = WitnessCondition.FromJson((JObject)json["condition"], WitnessCondition.MaxNestingDepth) }; } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs index 97a7ede352..21260c39b2 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs @@ -22,7 +22,7 @@ public void TestFromJson1() } }; var json = condition.ToJson(); - var new_condi = WitnessCondition.FromJson(json); + var new_condi = WitnessCondition.FromJson(json, 2); Assert.IsTrue(new_condi is OrCondition); var or_condi = (OrCondition)new_condi; Assert.AreEqual(2, or_condi.Expressions.Length); @@ -42,7 +42,7 @@ public void TestFromJson2() var hash2 = UInt160.Parse("0xd2a4cff31913016155e38e474a2c06d08be276cf"); var jstr = "{\"type\":\"Or\",\"expressions\":[{\"type\":\"And\",\"expressions\":[{\"type\":\"CalledByContract\",\"hash\":\"0x0000000000000000000000000000000000000000\"},{\"type\":\"ScriptHash\",\"hash\":\"0xd2a4cff31913016155e38e474a2c06d08be276cf\"}]},{\"type\":\"Or\",\"expressions\":[{\"type\":\"CalledByGroup\",\"group\":\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"},{\"type\":\"Boolean\",\"expression\":true}]}]}"; var json = (JObject)JToken.Parse(jstr); - var condi = WitnessCondition.FromJson(json); + var condi = WitnessCondition.FromJson(json, 2); var or_condi = (OrCondition)condi; Assert.AreEqual(2, or_condi.Expressions.Length); var and_condi = (AndCondition)or_condi.Expressions[0];