From 3c034ea8ac68da52b5ff128300b6780549d05bd1 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Tue, 9 Nov 2021 23:37:08 +0700 Subject: Add DLSequence, DLSet for internal use - improve sorting of sets --- crypto/BouncyCastle.Android.csproj | 2 + crypto/BouncyCastle.csproj | 2 + crypto/BouncyCastle.iOS.csproj | 2 + crypto/crypto.csproj | 10 +++ crypto/src/asn1/ASN1StreamParser.cs | 4 +- crypto/src/asn1/Asn1InputStream.cs | 6 +- crypto/src/asn1/Asn1OutputStream.cs | 5 ++ crypto/src/asn1/Asn1Sequence.cs | 49 ++++++------- crypto/src/asn1/Asn1Set.cs | 129 +++++++++++++++++++---------------- crypto/src/asn1/BerSequence.cs | 20 +++--- crypto/src/asn1/BerSet.cs | 25 ++++--- crypto/src/asn1/DERSequenceParser.cs | 16 +++-- crypto/src/asn1/DERSetParser.cs | 14 ++-- crypto/src/asn1/DLSequence.cs | 96 ++++++++++++++++++++++++++ crypto/src/asn1/DLSet.cs | 91 ++++++++++++++++++++++++ crypto/src/asn1/DerOutputStream.cs | 5 ++ crypto/src/asn1/DerSequence.cs | 8 ++- crypto/src/asn1/DerSet.cs | 43 +++++++----- crypto/src/asn1/LazyDLSequence.cs | 2 +- crypto/src/asn1/LazyDLSet.cs | 3 +- 20 files changed, 386 insertions(+), 146 deletions(-) create mode 100644 crypto/src/asn1/DLSequence.cs create mode 100644 crypto/src/asn1/DLSet.cs diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 567351082..8d7900444 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -132,6 +132,8 @@ + + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index aec91b946..495b55220 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -126,6 +126,8 @@ + + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 83d8c66a2..9333ba1e5 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -127,6 +127,8 @@ + + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 0f90a842d..8c5f70e30 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -518,6 +518,16 @@ SubType = "Code" BuildAction = "Compile" /> + + should * be using this method. * - * @param obj the tagged object. - * @param explicitly true if the object is meant to be explicitly tagged, + * @param taggedObject the tagged object. + * @param declaredExplicit true if the object is meant to be explicitly tagged, * false otherwise. * @exception ArgumentException if the tagged object cannot * be converted. */ - public static Asn1Sequence GetInstance( - Asn1TaggedObject obj, - bool explicitly) + public static Asn1Sequence GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) { - Asn1Object inner = obj.GetObject(); + Asn1Object baseObject = taggedObject.GetObject(); - if (explicitly) + if (declaredExplicit) { - if (!obj.IsExplicit()) + if (!taggedObject.IsExplicit()) throw new ArgumentException("object implicit - explicit expected."); - return (Asn1Sequence) inner; + return (Asn1Sequence)baseObject; } - // - // constructed object which appears to be explicitly tagged - // when it should be implicit means we have to add the - // surrounding sequence. - // - if (obj.IsExplicit()) + // If parsed as explicit though declared implicit, it should have been a sequence of one + if (taggedObject.IsExplicit()) { - if (obj is BerTaggedObject) - { - return new BerSequence(inner); - } + if (taggedObject is BerTaggedObject) + return new BerSequence(baseObject); - return new DerSequence(inner); + return new DLSequence(baseObject); } - if (inner is Asn1Sequence) - { - return (Asn1Sequence) inner; - } + if (baseObject is Asn1Sequence) + return (Asn1Sequence)baseObject; - throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj"); + throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(taggedObject), + "taggedObject"); } + // NOTE: Only non-readonly to support LazyDLSequence + internal Asn1Encodable[] elements; + protected internal Asn1Sequence() { this.elements = Asn1EncodableVector.EmptyElements; @@ -286,5 +277,7 @@ namespace Org.BouncyCastle.Asn1 internal abstract DerExternal ToAsn1External(); internal abstract Asn1OctetString ToAsn1OctetString(); + + internal abstract Asn1Set ToAsn1Set(); } } diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs index 453627b7c..b1439be47 100644 --- a/crypto/src/asn1/Asn1Set.cs +++ b/crypto/src/asn1/Asn1Set.cs @@ -13,12 +13,9 @@ using Org.BouncyCastle.Utilities.Collections; namespace Org.BouncyCastle.Asn1 { - abstract public class Asn1Set + public abstract class Asn1Set : Asn1Object, IEnumerable { - // NOTE: Only non-readonly to support LazyDerSet - internal Asn1Encodable[] elements; - /** * return an ASN1Set from the given object. * @@ -63,65 +60,52 @@ namespace Org.BouncyCastle.Asn1 * dealing with implicitly tagged sets you really should * be using this method. * - * @param obj the tagged object. - * @param explicitly true if the object is meant to be explicitly tagged + * @param taggedObject the tagged object. + * @param declaredExplicit true if the object is meant to be explicitly tagged * false otherwise. * @exception ArgumentException if the tagged object cannot * be converted. */ - public static Asn1Set GetInstance( - Asn1TaggedObject obj, - bool explicitly) + public static Asn1Set GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) { - Asn1Object inner = obj.GetObject(); + Asn1Object baseObject = taggedObject.GetObject(); - if (explicitly) + if (declaredExplicit) { - if (!obj.IsExplicit()) + if (!taggedObject.IsExplicit()) throw new ArgumentException("object implicit - explicit expected."); - return (Asn1Set) inner; + return (Asn1Set)baseObject; } - // - // constructed object which appears to be explicitly tagged - // and it's really implicit means we have to add the - // surrounding sequence. - // - if (obj.IsExplicit()) + // If parsed as explicit though declared implicit, it should have been a set of one + if (taggedObject.IsExplicit()) { - return new DerSet(inner); - } + if (taggedObject is BerTaggedObject) + return new BerSet(baseObject); - if (inner is Asn1Set) - { - return (Asn1Set) inner; + return new DLSet(baseObject); } - // - // in this case the parser returns a sequence, convert it - // into a set. - // - if (inner is Asn1Sequence) - { - Asn1EncodableVector v = new Asn1EncodableVector(); - Asn1Sequence s = (Asn1Sequence) inner; + if (baseObject is Asn1Set) + return (Asn1Set)baseObject; - foreach (Asn1Encodable ae in s) - { - v.Add(ae); - } - - // TODO Should be able to construct set directly from sequence? - return new DerSet(v, false); - } + // Parser assumes implicit constructed encodings are sequences + if (baseObject is Asn1Sequence) + return ((Asn1Sequence)baseObject).ToAsn1Set(); - throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj"); + throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(taggedObject), + "taggedObject"); } + // NOTE: Only non-readonly to support LazyDLSet + internal Asn1Encodable[] elements; + internal bool isSorted; + protected internal Asn1Set() { this.elements = Asn1EncodableVector.EmptyElements; + this.isSorted = true; } protected internal Asn1Set(Asn1Encodable element) @@ -130,22 +114,47 @@ namespace Org.BouncyCastle.Asn1 throw new ArgumentNullException("element"); this.elements = new Asn1Encodable[]{ element }; + this.isSorted = true; } - protected internal Asn1Set(params Asn1Encodable[] elements) + protected internal Asn1Set(Asn1Encodable[] elements, bool doSort) { if (Arrays.IsNullOrContainsNull(elements)) throw new NullReferenceException("'elements' cannot be null, or contain null"); - this.elements = Asn1EncodableVector.CloneElements(elements); + Asn1Encodable[] tmp = Asn1EncodableVector.CloneElements(elements); + if (doSort && tmp.Length >= 2) + { + tmp = Sort(tmp); + } + + this.elements = tmp; + this.isSorted = doSort || tmp.Length < 2; } - protected internal Asn1Set(Asn1EncodableVector elementVector) + protected internal Asn1Set(Asn1EncodableVector elementVector, bool doSort) { if (null == elementVector) throw new ArgumentNullException("elementVector"); - this.elements = elementVector.TakeElements(); + Asn1Encodable[] tmp; + if (doSort && elementVector.Count >= 2) + { + tmp = Sort(elementVector.CopyElements()); + } + else + { + tmp = elementVector.TakeElements(); + } + + this.elements = tmp; + this.isSorted = doSort || tmp.Length < 2; + } + + protected internal Asn1Set(bool isSorted, Asn1Encodable[] elements) + { + this.elements = elements; + this.isSorted = isSorted || elements.Length < 2; } public virtual IEnumerator GetEnumerator() @@ -257,15 +266,24 @@ namespace Org.BouncyCastle.Asn1 return true; } - protected internal void Sort() + internal override bool EncodeConstructed() { - // NOTE: Call Count here to 'force' a LazyDerSet - int count = Count; + return true; + } + + public override string ToString() + { + return CollectionUtilities.ToString(elements); + } + + private static Asn1Encodable[] Sort(Asn1Encodable[] elements) + { + int count = elements.Length; if (count < 2) - return; + return elements; #if PORTABLE - this.elements = elements + return elements .Cast() .Select(a => new { Item = a, Key = a.GetEncoded(Asn1Encodable.Der) }) .OrderBy(t => t.Key, new DerComparer()) @@ -278,19 +296,10 @@ namespace Org.BouncyCastle.Asn1 keys[i] = elements[i].GetEncoded(Der); } Array.Sort(keys, elements, new DerComparer()); + return elements; #endif } - internal override bool EncodeConstructed() - { - return true; - } - - public override string ToString() - { - return CollectionUtilities.ToString(elements); - } - #if PORTABLE private class DerComparer : IComparer diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs index e0525efa6..c8c5bbbbd 100644 --- a/crypto/src/asn1/BerSequence.cs +++ b/crypto/src/asn1/BerSequence.cs @@ -55,14 +55,13 @@ namespace Org.BouncyCastle.Asn1 internal override void Encode(Asn1OutputStream asn1Out, bool withID) { - if (asn1Out.IsBer) + if (!asn1Out.IsBer) { - asn1Out.WriteEncodingIL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, elements); - } - else - { - base.Encode(asn1Out, withID); - } + base.Encode(asn1Out, withID); + return; + } + + asn1Out.WriteEncodingIL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, elements); } internal override DerBitString ToAsn1BitString() @@ -74,12 +73,17 @@ namespace Org.BouncyCastle.Asn1 { // TODO There is currently no BerExternal class (or ToDLObject/ToDerObject) //return ((Asn1Sequence)ToDLObject()).ToAsn1External(); - return new DerSequence(elements, false).ToAsn1External(); + return new DLSequence(elements).ToAsn1External(); } internal override Asn1OctetString ToAsn1OctetString() { return new BerOctetString(GetConstructedOctetStrings()); } + + internal override Asn1Set ToAsn1Set() + { + return new BerSet(false, elements); + } } } diff --git a/crypto/src/asn1/BerSet.cs b/crypto/src/asn1/BerSet.cs index 5d61db6aa..2cfda2f09 100644 --- a/crypto/src/asn1/BerSet.cs +++ b/crypto/src/asn1/BerSet.cs @@ -14,13 +14,8 @@ namespace Org.BouncyCastle.Asn1 return elementVector.Count < 1 ? Empty : new BerSet(elementVector); } - internal static new BerSet FromVector(Asn1EncodableVector elementVector, bool needsSorting) - { - return elementVector.Count < 1 ? Empty : new BerSet(elementVector, needsSorting); - } - /** - * create an empty sequence + * create an empty set */ public BerSet() : base() @@ -35,6 +30,11 @@ namespace Org.BouncyCastle.Asn1 { } + public BerSet(params Asn1Encodable[] elements) + : base(elements, false) + { + } + /** * create a set containing a vector of objects. */ @@ -43,8 +43,8 @@ namespace Org.BouncyCastle.Asn1 { } - internal BerSet(Asn1EncodableVector elementVector, bool needsSorting) - : base(elementVector, needsSorting) + internal BerSet(bool isSorted, Asn1Encodable[] elements) + : base(isSorted, elements) { } @@ -55,14 +55,13 @@ namespace Org.BouncyCastle.Asn1 internal override void Encode(Asn1OutputStream asn1Out, bool withID) { - if (asn1Out.IsBer) - { - asn1Out.WriteEncodingIL(withID, Asn1Tags.Constructed | Asn1Tags.Set, elements); - } - else + if (!asn1Out.IsBer) { base.Encode(asn1Out, withID); + return; } + + asn1Out.WriteEncodingIL(withID, Asn1Tags.Constructed | Asn1Tags.Set, elements); } } } diff --git a/crypto/src/asn1/DERSequenceParser.cs b/crypto/src/asn1/DERSequenceParser.cs index 69c2b9b2d..a373fcf32 100644 --- a/crypto/src/asn1/DERSequenceParser.cs +++ b/crypto/src/asn1/DERSequenceParser.cs @@ -1,24 +1,26 @@ +using System; + namespace Org.BouncyCastle.Asn1 { - public class DerSequenceParser + // TODO[asn1] Should be renamed/replaced with DLSequenceParser + public class DerSequenceParser : Asn1SequenceParser { - private readonly Asn1StreamParser _parser; + private readonly Asn1StreamParser m_parser; - internal DerSequenceParser( - Asn1StreamParser parser) + internal DerSequenceParser(Asn1StreamParser parser) { - this._parser = parser; + this.m_parser = parser; } public IAsn1Convertible ReadObject() { - return _parser.ReadObject(); + return m_parser.ReadObject(); } public Asn1Object ToAsn1Object() { - return new DerSequence(_parser.ReadVector()); + return DLSequence.FromVector(m_parser.ReadVector()); } } } diff --git a/crypto/src/asn1/DERSetParser.cs b/crypto/src/asn1/DERSetParser.cs index d67f135be..344de3bc1 100644 --- a/crypto/src/asn1/DERSetParser.cs +++ b/crypto/src/asn1/DERSetParser.cs @@ -1,24 +1,26 @@ +using System; + namespace Org.BouncyCastle.Asn1 { + // TODO[asn1] Should be renamed/replaced with DLSetParser public class DerSetParser : Asn1SetParser { - private readonly Asn1StreamParser _parser; + private readonly Asn1StreamParser m_parser; - internal DerSetParser( - Asn1StreamParser parser) + internal DerSetParser(Asn1StreamParser parser) { - this._parser = parser; + this.m_parser = parser; } public IAsn1Convertible ReadObject() { - return _parser.ReadObject(); + return m_parser.ReadObject(); } public Asn1Object ToAsn1Object() { - return new DerSet(_parser.ReadVector(), false); + return DLSet.FromVector(m_parser.ReadVector()); } } } diff --git a/crypto/src/asn1/DLSequence.cs b/crypto/src/asn1/DLSequence.cs new file mode 100644 index 000000000..56a0e6932 --- /dev/null +++ b/crypto/src/asn1/DLSequence.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + internal class DLSequence + : DerSequence + { + internal static new readonly DLSequence Empty = new DLSequence(); + + internal static new DLSequence FromVector(Asn1EncodableVector elementVector) + { + return elementVector.Count < 1 ? Empty : new DLSequence(elementVector); + } + + /** + * create an empty sequence + */ + internal DLSequence() + : base() + { + } + + /** + * create a sequence containing one object + */ + internal DLSequence(Asn1Encodable element) + : base(element) + { + } + + internal DLSequence(params Asn1Encodable[] elements) + : base(elements) + { + } + + /** + * create a sequence containing a vector of objects. + */ + internal DLSequence(Asn1EncodableVector elementVector) + : base(elementVector) + { + } + + internal DLSequence(Asn1Encodable[] elements, bool clone) + : base(elements, clone) + { + } + + internal override int EncodedLength(bool withID) + { + throw Platform.CreateNotImplementedException("DLSequence.EncodedLength"); + } + + internal override void Encode(Asn1OutputStream asn1Out, bool withID) + { + if (asn1Out.IsDer) + { + base.Encode(asn1Out, withID); + return; + } + + if (Count < 1) + { + asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, Asn1OctetString.EmptyOctets); + return; + } + + // TODO Intermediate buffer could be avoided if we could calculate expected length + MemoryStream bOut = new MemoryStream(); + // TODO Once DLOutputStream exists, this should create one + Asn1OutputStream dOut = Asn1OutputStream.Create(bOut); + dOut.WriteElements(elements); + dOut.FlushInternal(); + +#if PORTABLE + byte[] bytes = bOut.ToArray(); + int length = bytes.Length; +#else + byte[] bytes = bOut.GetBuffer(); + int length = (int)bOut.Position; +#endif + + asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, bytes, 0, length); + + Platform.Dispose(dOut); + } + + internal override Asn1Set ToAsn1Set() + { + return new DLSet(false, elements); + } + } +} diff --git a/crypto/src/asn1/DLSet.cs b/crypto/src/asn1/DLSet.cs new file mode 100644 index 000000000..0605a0167 --- /dev/null +++ b/crypto/src/asn1/DLSet.cs @@ -0,0 +1,91 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + internal class DLSet + : DerSet + { + internal static new readonly DLSet Empty = new DLSet(); + + internal static new DLSet FromVector(Asn1EncodableVector elementVector) + { + return elementVector.Count < 1 ? Empty : new DLSet(elementVector); + } + + /** + * create an empty set + */ + internal DLSet() + : base() + { + } + + /** + * create a set containing one object + */ + internal DLSet(Asn1Encodable element) + : base(element) + { + } + + internal DLSet(params Asn1Encodable[] elements) + : base(elements, false) + { + } + + /** + * create a set containing a vector of objects. + */ + internal DLSet(Asn1EncodableVector elementVector) + : base(elementVector, false) + { + } + + internal DLSet(bool isSorted, Asn1Encodable[] elements) + : base(isSorted, elements) + { + } + + internal override int EncodedLength(bool withID) + { + throw Platform.CreateNotImplementedException("DLSet.EncodedLength"); + } + + internal override void Encode(Asn1OutputStream asn1Out, bool withID) + { + if (asn1Out.IsDer) + { + base.Encode(asn1Out, withID); + return; + } + + if (Count < 1) + { + asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, Asn1OctetString.EmptyOctets); + return; + } + + // TODO Intermediate buffer could be avoided if we could calculate expected length + MemoryStream bOut = new MemoryStream(); + // TODO Once DLOutputStream exists, this should create one + Asn1OutputStream dOut = Asn1OutputStream.Create(bOut); + dOut.WriteElements(elements); + dOut.FlushInternal(); + +#if PORTABLE + byte[] bytes = bOut.ToArray(); + int length = bytes.Length; +#else + byte[] bytes = bOut.GetBuffer(); + int length = (int)bOut.Position; +#endif + + asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, bytes, 0, length); + + Platform.Dispose(dOut); + } + } +} diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs index b8cbe9ee2..f384c20a8 100644 --- a/crypto/src/asn1/DerOutputStream.cs +++ b/crypto/src/asn1/DerOutputStream.cs @@ -39,6 +39,11 @@ namespace Org.BouncyCastle.Asn1 get { return false; } } + internal override bool IsDer + { + get { return true; } + } + internal override void WritePrimitive(Asn1Object primitive, bool withID) { Asn1Set asn1Set = primitive as Asn1Set; diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs index 5b315a909..157d99c93 100644 --- a/crypto/src/asn1/DerSequence.cs +++ b/crypto/src/asn1/DerSequence.cs @@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Asn1 MemoryStream bOut = new MemoryStream(); Asn1OutputStream dOut = Asn1OutputStream.Create(bOut, Der); dOut.WriteElements(elements); - dOut.Flush(); + dOut.FlushInternal(); #if PORTABLE byte[] bytes = bOut.ToArray(); @@ -103,5 +103,11 @@ namespace Org.BouncyCastle.Asn1 { return new DerOctetString(BerOctetString.FlattenOctetStrings(GetConstructedOctetStrings())); } + + internal override Asn1Set ToAsn1Set() + { + // NOTE: DLSet is intentional, we don't want sorting + return new DLSet(false, elements); + } } } diff --git a/crypto/src/asn1/DerSet.cs b/crypto/src/asn1/DerSet.cs index d401d3a36..030b0a38f 100644 --- a/crypto/src/asn1/DerSet.cs +++ b/crypto/src/asn1/DerSet.cs @@ -18,11 +18,6 @@ namespace Org.BouncyCastle.Asn1 return elementVector.Count < 1 ? Empty : new DerSet(elementVector); } - internal static DerSet FromVector(Asn1EncodableVector elementVector, bool needsSorting) - { - return elementVector.Count < 1 ? Empty : new DerSet(elementVector, needsSorting); - } - /** * create an empty set */ @@ -39,29 +34,34 @@ namespace Org.BouncyCastle.Asn1 { } - public DerSet(params Asn1Encodable[] elements) - : base(elements) + public DerSet(params Asn1Encodable[] elements) + : base(elements, true) + { + } + + internal DerSet(Asn1Encodable[] elements, bool doSort) + : base(elements, doSort) { - Sort(); } /** * @param v - a vector of objects making up the set. */ public DerSet(Asn1EncodableVector elementVector) - : this(elementVector, true) + : base(elementVector, true) { } - internal DerSet(Asn1EncodableVector elementVector, bool needsSorting) - : base(elementVector) + internal DerSet(Asn1EncodableVector elementVector, bool doSort) + : base(elementVector, doSort) { - if (needsSorting) - { - Sort(); - } } + internal DerSet(bool isSorted, Asn1Encodable[] elements) + : base(isSorted, elements) + { + } + internal override int EncodedLength(bool withID) { throw Platform.CreateNotImplementedException("DerSet.EncodedLength"); @@ -83,11 +83,22 @@ namespace Org.BouncyCastle.Asn1 return; } + if (!isSorted) + { + new DerSet(elements, true).ImplEncode(asn1Out, withID); + return; + } + + ImplEncode(asn1Out, withID); + } + + private void ImplEncode(Asn1OutputStream asn1Out, bool withID) + { // TODO Intermediate buffer could be avoided if we could calculate expected length MemoryStream bOut = new MemoryStream(); Asn1OutputStream dOut = Asn1OutputStream.Create(bOut, Der); dOut.WriteElements(elements); - dOut.Flush(); + dOut.FlushInternal(); #if PORTABLE byte[] bytes = bOut.ToArray(); diff --git a/crypto/src/asn1/LazyDLSequence.cs b/crypto/src/asn1/LazyDLSequence.cs index 63152e446..fe924365e 100644 --- a/crypto/src/asn1/LazyDLSequence.cs +++ b/crypto/src/asn1/LazyDLSequence.cs @@ -5,7 +5,7 @@ using System.IO; namespace Org.BouncyCastle.Asn1 { internal class LazyDLSequence - : DerSequence + : DLSequence { private byte[] encoded; diff --git a/crypto/src/asn1/LazyDLSet.cs b/crypto/src/asn1/LazyDLSet.cs index 0d4d84310..bdee0bc22 100644 --- a/crypto/src/asn1/LazyDLSet.cs +++ b/crypto/src/asn1/LazyDLSet.cs @@ -5,7 +5,7 @@ using System.IO; namespace Org.BouncyCastle.Asn1 { internal class LazyDLSet - : DerSet + : DLSet { private byte[] encoded; @@ -106,6 +106,7 @@ namespace Org.BouncyCastle.Asn1 Asn1EncodableVector v = input.ReadVector(); this.elements = v.TakeElements(); + this.isSorted = elements.Length < 2; this.encoded = null; } catch (IOException e) -- cgit 1.4.1