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 @@
<Compile Include="src\asn1\DerUniversalString.cs" />
<Compile Include="src\asn1\DerVideotexString.cs" />
<Compile Include="src\asn1\DerVisibleString.cs" />
+ <Compile Include="src\asn1\DLSequence.cs" />
+ <Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs" />
<Compile Include="src\asn1\IAsn1Choice.cs" />
<Compile Include="src\asn1\IAsn1Convertible.cs" />
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 @@
<Compile Include="src\asn1\DerUniversalString.cs" />
<Compile Include="src\asn1\DerVideotexString.cs" />
<Compile Include="src\asn1\DerVisibleString.cs" />
+ <Compile Include="src\asn1\DLSequence.cs" />
+ <Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs" />
<Compile Include="src\asn1\IAsn1Choice.cs" />
<Compile Include="src\asn1\IAsn1Convertible.cs" />
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 @@
<Compile Include="src\asn1\DerUniversalString.cs" />
<Compile Include="src\asn1\DerVideotexString.cs" />
<Compile Include="src\asn1\DerVisibleString.cs" />
+ <Compile Include="src\asn1\DLSequence.cs" />
+ <Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs" />
<Compile Include="src\asn1\IAsn1Choice.cs" />
<Compile Include="src\asn1\IAsn1Convertible.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 0f90a842d..8c5f70e30 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -519,6 +519,16 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\asn1\DLSequence.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\asn1\DLSet.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\asn1\IAsn1ApplicationSpecificParser.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs
index a92a3adae..0a575c8c5 100644
--- a/crypto/src/asn1/ASN1StreamParser.cs
+++ b/crypto/src/asn1/ASN1StreamParser.cs
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Asn1
return v.Count == 1
? new DerTaggedObject(true, tag, v[0])
- : new DerTaggedObject(false, tag, DerSequence.FromVector(v));
+ : new DerTaggedObject(false, tag, DLSequence.FromVector(v));
}
public virtual IAsn1Convertible ReadObject()
@@ -122,7 +122,7 @@ namespace Org.BouncyCastle.Asn1
if (tag == -1)
return null;
- // turn of looking for "00" while we resolve the tag
+ // turn off looking for "00" while we resolve the tag
Set00Check(false);
//
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 14073e921..27c583338 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Asn1
case Asn1Tags.Set:
return CreateDLSet(defIn);
case Asn1Tags.External:
- return DerSequence.FromVector(ReadVector(defIn)).ToAsn1External();
+ return DLSequence.FromVector(ReadVector(defIn)).ToAsn1External();
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
@@ -145,12 +145,12 @@ namespace Org.BouncyCastle.Asn1
internal virtual Asn1Sequence CreateDLSequence(DefiniteLengthInputStream defIn)
{
- return DerSequence.FromVector(ReadVector(defIn));
+ return DLSequence.FromVector(ReadVector(defIn));
}
internal virtual Asn1Set CreateDLSet(DefiniteLengthInputStream defIn)
{
- return DerSet.FromVector(ReadVector(defIn), false);
+ return DLSet.FromVector(ReadVector(defIn));
}
public Asn1Object ReadObject()
diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs
index f1e9aec57..b0d4a18fa 100644
--- a/crypto/src/asn1/Asn1OutputStream.cs
+++ b/crypto/src/asn1/Asn1OutputStream.cs
@@ -57,6 +57,11 @@ namespace Org.BouncyCastle.Asn1
get { return true; }
}
+ internal virtual bool IsDer
+ {
+ get { return false; }
+ }
+
internal void WriteDL(int length)
{
if (length < 128)
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index e1d0fa675..8025492d2 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -10,9 +10,6 @@ namespace Org.BouncyCastle.Asn1
public abstract class Asn1Sequence
: Asn1Object, IEnumerable
{
- // NOTE: Only non-readonly to support LazyDerSequence
- internal Asn1Encodable[] elements;
-
/**
* return an Asn1Sequence from the given object.
*
@@ -57,49 +54,43 @@ namespace Org.BouncyCastle.Asn1
* dealing with implicitly tagged sequences you really <b>should</b>
* 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 <b>should</b>
* 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<Asn1Encodable>()
.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<byte[]>
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)
|