summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2021-11-11 14:06:03 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2021-11-11 14:06:03 +0700
commit46230a012af2824a5e742db8e6dc5b23c720d696 (patch)
tree9cd842e680b7a9e3eac925f05bde504bb8670859
parentHandle high tag numbers (diff)
downloadBouncyCastle.NET-ed25519-46230a012af2824a5e742db8e6dc5b23c720d696.tar.xz
ASN.1: Update encoding in line with bc-java
-rw-r--r--crypto/src/asn1/Asn1Object.cs4
-rw-r--r--crypto/src/asn1/Asn1ObjectDescriptor.cs6
-rw-r--r--crypto/src/asn1/Asn1OctetString.cs28
-rw-r--r--crypto/src/asn1/Asn1OutputStream.cs11
-rw-r--r--crypto/src/asn1/Asn1RelativeOid.cs4
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs19
-rw-r--r--crypto/src/asn1/Asn1Set.cs21
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs11
-rw-r--r--crypto/src/asn1/BERBitString.cs72
-rw-r--r--crypto/src/asn1/BerOctetString.cs72
-rw-r--r--crypto/src/asn1/BerSequence.cs19
-rw-r--r--crypto/src/asn1/BerSet.cs17
-rw-r--r--crypto/src/asn1/BerTaggedObject.cs107
-rw-r--r--crypto/src/asn1/DERExternal.cs8
-rw-r--r--crypto/src/asn1/DLSequence.cs78
-rw-r--r--crypto/src/asn1/DLSet.cs84
-rw-r--r--crypto/src/asn1/DerApplicationSpecific.cs6
-rw-r--r--crypto/src/asn1/DerBMPString.cs4
-rw-r--r--crypto/src/asn1/DerBitString.cs4
-rw-r--r--crypto/src/asn1/DerBoolean.cs13
-rw-r--r--crypto/src/asn1/DerEnumerated.cs4
-rw-r--r--crypto/src/asn1/DerGeneralString.cs4
-rw-r--r--crypto/src/asn1/DerGeneralizedTime.cs4
-rw-r--r--crypto/src/asn1/DerGraphicString.cs4
-rw-r--r--crypto/src/asn1/DerIA5String.cs4
-rw-r--r--crypto/src/asn1/DerInteger.cs4
-rw-r--r--crypto/src/asn1/DerNull.cs4
-rw-r--r--crypto/src/asn1/DerNumericString.cs4
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs4
-rw-r--r--crypto/src/asn1/DerOctetString.cs4
-rw-r--r--crypto/src/asn1/DerOutputStream.cs8
-rw-r--r--crypto/src/asn1/DerPrintableString.cs5
-rw-r--r--crypto/src/asn1/DerSequence.cs74
-rw-r--r--crypto/src/asn1/DerSet.cs88
-rw-r--r--crypto/src/asn1/DerT61String.cs4
-rw-r--r--crypto/src/asn1/DerTaggedObject.cs74
-rw-r--r--crypto/src/asn1/DerUTCTime.cs4
-rw-r--r--crypto/src/asn1/DerUTF8String.cs4
-rw-r--r--crypto/src/asn1/DerUniversalString.cs4
-rw-r--r--crypto/src/asn1/DerVideotexString.cs4
-rw-r--r--crypto/src/asn1/DerVisibleString.cs4
-rw-r--r--crypto/src/asn1/LazyDLSequence.cs18
-rw-r--r--crypto/src/asn1/LazyDLSet.cs18
43 files changed, 567 insertions, 370 deletions
diff --git a/crypto/src/asn1/Asn1Object.cs b/crypto/src/asn1/Asn1Object.cs
index 2f438c236..67c0f37c4 100644
--- a/crypto/src/asn1/Asn1Object.cs
+++ b/crypto/src/asn1/Asn1Object.cs
@@ -62,9 +62,9 @@ namespace Org.BouncyCastle.Asn1
             return this;
         }
 
-        internal abstract bool EncodeConstructed();
+        internal abstract bool EncodeConstructed(int encoding);
 
-        internal abstract int EncodedLength(bool withID);
+        internal abstract int EncodedLength(int encoding, bool withID);
 
         internal abstract void Encode(Asn1OutputStream asn1Out, bool withID);
 
diff --git a/crypto/src/asn1/Asn1ObjectDescriptor.cs b/crypto/src/asn1/Asn1ObjectDescriptor.cs
index e5cc42450..4d25da77b 100644
--- a/crypto/src/asn1/Asn1ObjectDescriptor.cs
+++ b/crypto/src/asn1/Asn1ObjectDescriptor.cs
@@ -78,14 +78,14 @@ namespace Org.BouncyCastle.Asn1
             get { return m_baseGraphicString; }
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            return m_baseGraphicString.EncodedLength(withID);
+            return m_baseGraphicString.EncodedLength(encoding, withID);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
diff --git a/crypto/src/asn1/Asn1OctetString.cs b/crypto/src/asn1/Asn1OctetString.cs
index d5766e299..66d6fb8d1 100644
--- a/crypto/src/asn1/Asn1OctetString.cs
+++ b/crypto/src/asn1/Asn1OctetString.cs
@@ -58,14 +58,36 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1OctetString GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
         {
+            if (declaredExplicit)
+            {
+                if (!taggedObject.IsExplicit())
+                    throw new ArgumentException("object implicit - explicit expected.");
+
+                return GetInstance(taggedObject.GetObject());
+            }
+
             Asn1Object baseObject = taggedObject.GetObject();
 
-            if (declaredExplicit || baseObject is Asn1OctetString)
+            // If parsed as explicit though declared implicit, it should have been a set of one
+            if (taggedObject.IsExplicit())
             {
-                return GetInstance(baseObject);
+                Asn1OctetString singleSegment = GetInstance(baseObject);
+
+                if (taggedObject is BerTaggedObject)
+                    return new BerOctetString(new Asn1OctetString[]{ singleSegment });
+
+                return singleSegment;
             }
 
-            return BerOctetString.FromSequence(Asn1Sequence.GetInstance(baseObject));
+            if (baseObject is Asn1OctetString)
+                return (Asn1OctetString)baseObject;
+
+            // Parser assumes implicit constructed encodings are sequences
+            if (baseObject is Asn1Sequence)
+                return ((Asn1Sequence)baseObject).ToAsn1OctetString();
+
+            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(taggedObject),
+                "taggedObject");
         }
 
         internal readonly byte[] contents;
diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs
index b0d4a18fa..79ab84b74 100644
--- a/crypto/src/asn1/Asn1OutputStream.cs
+++ b/crypto/src/asn1/Asn1OutputStream.cs
@@ -6,6 +6,9 @@ namespace Org.BouncyCastle.Asn1
     public class Asn1OutputStream
         : DerOutputStream
     {
+        internal const int EncodingBer = 1;
+        internal const int EncodingDer = 2;
+
         public static Asn1OutputStream Create(Stream output)
         {
             return new Asn1OutputStream(output);
@@ -52,14 +55,14 @@ namespace Org.BouncyCastle.Asn1
             // Placeholder to support future internal buffering
         }
 
-        internal virtual bool IsBer
+        internal virtual DerOutputStreamNew GetDerSubStream()
         {
-            get { return true; }
+            return new DerOutputStreamNew(s);
         }
 
-        internal virtual bool IsDer
+        internal virtual int Encoding
         {
-            get { return false; }
+            get { return EncodingBer; }
         }
 
         internal void WriteDL(int length)
diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs
index e1ee5309a..efa050413 100644
--- a/crypto/src/asn1/Asn1RelativeOid.cs
+++ b/crypto/src/asn1/Asn1RelativeOid.cs
@@ -110,12 +110,12 @@ namespace Org.BouncyCastle.Asn1
             return identifier.GetHashCode();
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length);
         }
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index 8025492d2..9ab41ffd3 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -62,16 +62,16 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1Sequence GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
         {
-            Asn1Object baseObject = taggedObject.GetObject();
-
             if (declaredExplicit)
             {
                 if (!taggedObject.IsExplicit())
                     throw new ArgumentException("object implicit - explicit expected.");
 
-                return (Asn1Sequence)baseObject;
+                return GetInstance(taggedObject.GetObject());
             }
 
+            Asn1Object baseObject = taggedObject.GetObject();
+
             // If parsed as explicit though declared implicit, it should have been a sequence of one
             if (taggedObject.IsExplicit())
             {
@@ -235,7 +235,7 @@ namespace Org.BouncyCastle.Asn1
             return true;
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return true;
         }
@@ -245,6 +245,17 @@ namespace Org.BouncyCastle.Asn1
             return CollectionUtilities.ToString(elements);
         }
 
+        internal int CalculateContentsLength(int encoding)
+        {
+            int contentsLength = 0;
+            for (int i = 0, count = elements.Length; i < count; ++i)
+            {
+                Asn1Object asn1Object = elements[i].ToAsn1Object();
+                contentsLength += asn1Object.EncodedLength(encoding, true);
+            }
+            return contentsLength;
+        }
+
         // TODO[asn1] Preferably return an Asn1BitString[] (doesn't exist yet)
         internal DerBitString[] GetConstructedBitStrings()
         {
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index b1439be47..6193e8178 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -68,16 +68,16 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1Set GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
         {
-            Asn1Object baseObject = taggedObject.GetObject();
-
             if (declaredExplicit)
             {
                 if (!taggedObject.IsExplicit())
                     throw new ArgumentException("object implicit - explicit expected.");
 
-                return (Asn1Set)baseObject;
+                return GetInstance(taggedObject.GetObject());
             }
 
+            Asn1Object baseObject = taggedObject.GetObject();
+
             // If parsed as explicit though declared implicit, it should have been a set of one
             if (taggedObject.IsExplicit())
             {
@@ -266,7 +266,7 @@ namespace Org.BouncyCastle.Asn1
             return true;
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return true;
         }
@@ -276,7 +276,18 @@ namespace Org.BouncyCastle.Asn1
             return CollectionUtilities.ToString(elements);
         }
 
-        private static Asn1Encodable[] Sort(Asn1Encodable[] elements)
+        internal int CalculateContentsLength(int encoding)
+        {
+            int contentsLength = 0;
+            for (int i = 0, count = elements.Length; i < count; ++i)
+            {
+                Asn1Object asn1Object = elements[i].ToAsn1Object();
+                contentsLength += asn1Object.EncodedLength(encoding, true);
+            }
+            return contentsLength;
+        }
+
+        internal static Asn1Encodable[] Sort(Asn1Encodable[] elements)
         {
             int count = elements.Length;
             if (count < 2)
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index 87a66ffe0..9f7eab576 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -198,17 +198,6 @@ namespace Org.BouncyCastle.Asn1
         }
 
         /**
-         * Return true if the object is marked as constructed, false otherwise.
-         *
-         * @return true if constructed, otherwise false.
-         */
-        // TODO Need this public if/when DerApplicationSpecific extends Asn1TaggedObject
-        internal bool IsConstructed()
-        {
-            return EncodeConstructed();
-        }
-
-        /**
          * return whatever was following the tag.
          * <p>
          * Note: tagged objects are generally context dependent if you're
diff --git a/crypto/src/asn1/BERBitString.cs b/crypto/src/asn1/BERBitString.cs
index 156ea2d1f..a012d2a7c 100644
--- a/crypto/src/asn1/BERBitString.cs
+++ b/crypto/src/asn1/BERBitString.cs
@@ -1,8 +1,6 @@
 using System;
 using System.Diagnostics;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1
 {
     public class BerBitString
@@ -113,54 +111,56 @@ namespace Org.BouncyCastle.Asn1
             this.segmentLimit = DefaultSegmentLimit;
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
-            // NOTE: Assumes BER encoding
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodeConstructed(encoding);
+
             return null != elements || contents.Length > segmentLimit;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("BerBitString.EncodedLength");
-
-            // TODO This depends on knowing it's not DER
-            //if (!EncodeConstructed())
-            //    return EncodedLength(withID, contents.Length);
-
-            //int totalLength = withID ? 4 : 3;
-
-            //if (null != elements)
-            //{
-            //    for (int i = 0; i < elements.Length; ++i)
-            //    {
-            //        totalLength += elements[i].EncodedLength(true);
-            //    }
-            //}
-            //else if (contents.Length < 2)
-            //{
-            //    // No bits
-            //}
-            //else
-            //{
-            //    int extraSegments = (contents.Length - 2) / (segmentLimit - 1);
-            //    totalLength += extraSegments * EncodedLength(true, segmentLimit);
-
-            //    int lastSegmentLength = contents.Length - (extraSegments * (segmentLimit - 1));
-            //    totalLength += EncodedLength(true, lastSegmentLength);
-            //}
-
-            //return totalLength;
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodedLength(encoding, withID);
+
+            if (!EncodeConstructed(encoding))
+                return EncodedLength(withID, contents.Length);
+
+            int totalLength = withID ? 4 : 3;
+
+            if (null != elements)
+            {
+                for (int i = 0; i < elements.Length; ++i)
+                {
+                    totalLength += elements[i].EncodedLength(encoding, true);
+                }
+            }
+            else if (contents.Length < 2)
+            {
+                // No bits
+            }
+            else
+            {
+                int extraSegments = (contents.Length - 2) / (segmentLimit - 1);
+                totalLength += extraSegments * EncodedLength(true, segmentLimit);
+
+                int lastSegmentLength = contents.Length - (extraSegments * (segmentLimit - 1));
+                totalLength += EncodedLength(true, lastSegmentLength);
+            }
+
+            return totalLength;
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (!asn1Out.IsBer)
+            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
             {
                 base.Encode(asn1Out, withID);
                 return;
             }
 
-            if (!EncodeConstructed())
+            if (!EncodeConstructed(asn1Out.Encoding))
             {
                 Encode(asn1Out, withID, contents, 0, contents.Length);
                 return;
diff --git a/crypto/src/asn1/BerOctetString.cs b/crypto/src/asn1/BerOctetString.cs
index 0dab617b9..52ddd51c3 100644
--- a/crypto/src/asn1/BerOctetString.cs
+++ b/crypto/src/asn1/BerOctetString.cs
@@ -120,52 +120,60 @@ namespace Org.BouncyCastle.Asn1
 			return GetEnumerator();
 		}
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
-            // NOTE: Assumes BER encoding
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodeConstructed(encoding);
+
             return null != elements || contents.Length > segmentLimit;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("BerOctetString.EncodedLength");
-
-            // TODO This depends on knowing it's not DER
-            //if (!EncodeConstructed())
-            //    return EncodedLength(withID, contents.Length);
-
-            //int totalLength = withID ? 4 : 3;
-
-            //if (null != elements)
-            //{
-            //    for (int i = 0; i < elements.Length; ++i)
-            //    {
-            //        totalLength += elements[i].EncodedLength(true);
-            //    }
-            //}
-            //else
-            //{
-            //    int fullSegments = contents.Length / segmentLimit;
-            //    totalLength += fullSegments * EncodedLength(true, segmentLimit);
-
-            //    int lastSegmentLength = contents.Length - (fullSegments * segmentLimit);
-            //    if (lastSegmentLength > 0)
-            //    {
-            //        totalLength += EncodedLength(true, lastSegmentLength);
-            //    }
-            //}
-
-            //return totalLength;
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodedLength(encoding, withID);
+
+            if (!EncodeConstructed(encoding))
+                return EncodedLength(withID, contents.Length);
+
+            int totalLength = withID ? 4 : 3;
+
+            if (null != elements)
+            {
+                for (int i = 0; i < elements.Length; ++i)
+                {
+                    totalLength += elements[i].EncodedLength(encoding, true);
+                }
+            }
+            else
+            {
+                int fullSegments = contents.Length / segmentLimit;
+                totalLength += fullSegments * EncodedLength(true, segmentLimit);
+
+                int lastSegmentLength = contents.Length - (fullSegments * segmentLimit);
+                if (lastSegmentLength > 0)
+                {
+                    totalLength += EncodedLength(true, lastSegmentLength);
+                }
+            }
+
+            return totalLength;
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (!asn1Out.IsBer || !EncodeConstructed())
+            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
             {
                 base.Encode(asn1Out, withID);
                 return;
             }
 
+            if (!EncodeConstructed(asn1Out.Encoding))
+            {
+                Encode(asn1Out, withID, contents, 0, contents.Length);
+                return;
+            }
+
             asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.OctetString);
             asn1Out.WriteByte(0x80);
 
diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs
index c8c5bbbbd..a92b70f98 100644
--- a/crypto/src/asn1/BerSequence.cs
+++ b/crypto/src/asn1/BerSequence.cs
@@ -1,7 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1
 {
 	public class BerSequence
@@ -48,14 +46,25 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("BerSequence.EncodedLength");
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodedLength(encoding, withID);
+
+            int totalLength = withID ? 4 : 3;
+
+            for (int i = 0, count = elements.Length; i < count; ++i)
+            {
+                Asn1Object asn1Object = elements[i].ToAsn1Object();
+                totalLength += asn1Object.EncodedLength(encoding, true);
+            }
+
+            return totalLength;
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
 		{
-			if (!asn1Out.IsBer)
+            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
             {
                 base.Encode(asn1Out, withID);
                 return;
diff --git a/crypto/src/asn1/BerSet.cs b/crypto/src/asn1/BerSet.cs
index 2cfda2f09..c0d00537c 100644
--- a/crypto/src/asn1/BerSet.cs
+++ b/crypto/src/asn1/BerSet.cs
@@ -48,14 +48,25 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("BerSet.EncodedLength");
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodedLength(encoding, withID);
+
+            int totalLength = withID ? 4 : 3;
+
+            for (int i = 0, count = elements.Length; i < count; ++i)
+            {
+                Asn1Object asn1Object = elements[i].ToAsn1Object();
+                totalLength += asn1Object.EncodedLength(encoding, true);
+            }
+
+            return totalLength;
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (!asn1Out.IsBer)
+            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
             {
                 base.Encode(asn1Out, withID);
                 return;
diff --git a/crypto/src/asn1/BerTaggedObject.cs b/crypto/src/asn1/BerTaggedObject.cs
index 4bf27e12f..fc4d1835a 100644
--- a/crypto/src/asn1/BerTaggedObject.cs
+++ b/crypto/src/asn1/BerTaggedObject.cs
@@ -1,7 +1,4 @@
 using System;
-using System.Collections;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
@@ -52,75 +49,67 @@ namespace Org.BouncyCastle.Asn1
             get { return Ber; }
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
-            throw Platform.CreateNotImplementedException("BerTaggedObject.EncodeConstructed");
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodeConstructed(encoding);
 
-            // TODO This depends on knowing it's not DER
-            //return IsExplicit() || obj.ToAsn1Object().EncodeConstructed();
+            return IsExplicit() || GetBaseObject().ToAsn1Object().EncodeConstructed(encoding);
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("BerTaggedObject.EncodedLength");
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.EncodedLength(encoding, withID);
+
+            Asn1Object baseObject = GetBaseObject().ToAsn1Object();
+            bool withBaseID = IsExplicit();
+
+            int length = baseObject.EncodedLength(encoding, withBaseID);
+
+            if (withBaseID)
+            {
+                length += 3;
+            }
+
+            length += withID ? Asn1OutputStream.GetLengthOfIdentifier(TagNo) : 0;
+
+            return length;
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
 		{
-			if (asn1Out.IsBer)
-			{
-                if (withID)
+            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
+            {
+                base.Encode(asn1Out, withID);
+                return;
+            }
+
+            Asn1Object baseObject = GetBaseObject().ToAsn1Object();
+            bool withBaseID = IsExplicit();
+
+            if (withID)
+            {
+                int flags = TagClass;
+                if (withBaseID || baseObject.EncodeConstructed(asn1Out.Encoding))
                 {
-                    asn1Out.WriteIdentifier(true, Asn1Tags.Constructed | TagClass, TagNo);
+                    flags |= Asn1Tags.Constructed;
                 }
 
-                asn1Out.WriteByte(0x80);
+                asn1Out.WriteIdentifier(true, flags, TagNo);
+            }
 
-				if (!explicitly)
-				{
-					IEnumerable eObj;
-					if (obj is Asn1OctetString)
-					{
-						if (obj is BerOctetString)
-						{
-							eObj = (BerOctetString) obj;
-						}
-						else
-						{
-							Asn1OctetString octs = (Asn1OctetString)obj;
-							eObj = new BerOctetString(octs.GetOctets());
-						}
-					}
-					else if (obj is Asn1Sequence)
-					{
-						eObj = (Asn1Sequence) obj;
-					}
-					else if (obj is Asn1Set)
-					{
-						eObj = (Asn1Set) obj;
-					}
-					else
-					{
-						throw Platform.CreateNotImplementedException(Platform.GetTypeName(obj));
-					}
-
-					foreach (Asn1Encodable o in eObj)
-					{
-						asn1Out.WritePrimitive(o.ToAsn1Object(), true);
-					}
-				}
-				else
-				{
-					asn1Out.WritePrimitive(obj.ToAsn1Object(), true);
-				}
-
-				asn1Out.WriteByte(0x00);
-				asn1Out.WriteByte(0x00);
-			}
-			else
-			{
-				base.Encode(asn1Out, withID);
-			}
+            if (withBaseID)
+            {
+                asn1Out.WriteByte(0x80);
+                baseObject.Encode(asn1Out, true);
+                asn1Out.WriteByte(0x00);
+                asn1Out.WriteByte(0x00);
+            }
+            else
+            {
+                baseObject.Encode(asn1Out, false);
+            }
 		}
 
         internal override Asn1Sequence RebuildConstructed(Asn1Object asn1Object)
diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs
index ae707a2f5..32fc8d6d8 100644
--- a/crypto/src/asn1/DERExternal.cs
+++ b/crypto/src/asn1/DERExternal.cs
@@ -155,15 +155,15 @@ namespace Org.BouncyCastle.Asn1
             return new DerSequence(v);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
-            //return BuildSequence().EncodeConstructed();
+            //return BuildSequence().EncodeConstructed(encoding);
             return true;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            return BuildSequence().EncodedLength(withID);
+            return BuildSequence().EncodedLength(encoding, withID);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
diff --git a/crypto/src/asn1/DLSequence.cs b/crypto/src/asn1/DLSequence.cs
index 56a0e6932..0fede574a 100644
--- a/crypto/src/asn1/DLSequence.cs
+++ b/crypto/src/asn1/DLSequence.cs
@@ -1,7 +1,4 @@
 using System;
-using System.IO;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
@@ -15,6 +12,8 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DLSequence(elementVector);
         }
 
+        private int m_contentsLengthDL = -1;
+
         /**
 		 * create an empty sequence
 		 */
@@ -49,48 +48,73 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("DLSequence.EncodedLength");
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return base.EncodedLength(encoding, withID);
+
+            return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContentsLengthDL());
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (asn1Out.IsDer)
+            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding)
             {
                 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();
+            // TODO[asn1] Use DL encoding when supported
+            //asn1Out = asn1Out.GetDLSubStream();
 
-#if PORTABLE
-            byte[] bytes = bOut.ToArray();
-            int length = bytes.Length;
-#else
-            byte[] bytes = bOut.GetBuffer();
-            int length = (int)bOut.Position;
-#endif
+            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Sequence);
 
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, bytes, 0, length);
+            int count = elements.Length;
+            if (m_contentsLengthDL >= 0 || count > 16)
+            {
+                asn1Out.WriteDL(GetContentsLengthDL());
 
-            Platform.Dispose(dOut);
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Object.Encode(asn1Out, true);
+                }
+            }
+            else
+            {
+                int contentsLength = 0;
+
+                Asn1Object[] asn1Objects = new Asn1Object[count];
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Objects[i] = asn1Object;
+                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
+                }
+
+                this.m_contentsLengthDL = contentsLength;
+                asn1Out.WriteDL(contentsLength);
+
+                for (int i = 0; i < count; ++i)
+                {
+                    asn1Objects[i].Encode(asn1Out, true);
+                }
+            }
         }
 
         internal override Asn1Set ToAsn1Set()
         {
             return new DLSet(false, elements);
         }
+
+        private int GetContentsLengthDL()
+        {
+            if (m_contentsLengthDL < 0)
+            {
+                // TODO[asn1] Use DL encoding when supported
+                m_contentsLengthDL = CalculateContentsLength(Asn1OutputStream.EncodingBer);
+            }
+            return m_contentsLengthDL;
+        }
     }
 }
diff --git a/crypto/src/asn1/DLSet.cs b/crypto/src/asn1/DLSet.cs
index 0605a0167..7dcac25c2 100644
--- a/crypto/src/asn1/DLSet.cs
+++ b/crypto/src/asn1/DLSet.cs
@@ -1,7 +1,4 @@
 using System;
-using System.IO;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
@@ -15,6 +12,8 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DLSet(elementVector);
         }
 
+        private int m_contentsLengthDL = -1;
+
         /**
          * create an empty set
          */
@@ -49,43 +48,80 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("DLSet.EncodedLength");
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return base.EncodedLength(encoding, withID);
+
+            // TODO[asn1] Force DL encoding when supported
+            //encoding = Asn1OutputStream.EncodingDL;
+
+            int count = elements.Length;
+            int contentsLength = 0;
+
+            for (int i = 0; i < count; ++i)
+            {
+                Asn1Object asn1Object = elements[i].ToAsn1Object();
+                contentsLength += asn1Object.EncodedLength(encoding, true);
+            }
+
+            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (asn1Out.IsDer)
+            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding)
             {
                 base.Encode(asn1Out, withID);
                 return;
             }
 
-            if (Count < 1)
+            // TODO[asn1] Force DL encoding when supported
+            //asn1Out = asn1Out.GetDLSubStream();
+
+            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Set);
+
+            int count = elements.Length;
+            if (m_contentsLengthDL >= 0 || count > 16)
             {
-                asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, Asn1OctetString.EmptyOctets);
-                return;
+                asn1Out.WriteDL(GetContentsLengthDL());
+
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Object.Encode(asn1Out, true);
+                }
             }
+            else
+            {
+                int contentsLength = 0;
 
-            // 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();
+                Asn1Object[] asn1Objects = new Asn1Object[count];
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Objects[i] = asn1Object;
+                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
+                }
 
-#if PORTABLE
-            byte[] bytes = bOut.ToArray();
-            int length = bytes.Length;
-#else
-            byte[] bytes = bOut.GetBuffer();
-            int length = (int)bOut.Position;
-#endif
+                this.m_contentsLengthDL = contentsLength;
+                asn1Out.WriteDL(contentsLength);
 
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, bytes, 0, length);
+                for (int i = 0; i < count; ++i)
+                {
+                    asn1Objects[i].Encode(asn1Out, true);
+                }
+            }
+        }
 
-            Platform.Dispose(dOut);
+        private int GetContentsLengthDL()
+        {
+            if (m_contentsLengthDL < 0)
+            {
+                // TODO[asn1] Use DL encoding when supported
+                m_contentsLengthDL = CalculateContentsLength(Asn1OutputStream.EncodingBer);
+            }
+            return m_contentsLengthDL;
         }
     }
 }
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index a71526876..bc48d24e5 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -163,12 +163,12 @@ namespace Org.BouncyCastle.Asn1
 			return FromByteArray(tmp);
 		}
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
-            throw Platform.CreateNotImplementedException("DerApplicationSpecific.EncodeConstructed");
+            return isConstructed;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, tag, octets.Length);
         }
diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs
index f3fe6aa42..d3c7b3b46 100644
--- a/crypto/src/asn1/DerBMPString.cs
+++ b/crypto/src/asn1/DerBMPString.cs
@@ -111,12 +111,12 @@ namespace Org.BouncyCastle.Asn1
 			return this.str.Equals(other.str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length * 2);
         }
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
index 9cf84db1e..2814b9677 100644
--- a/crypto/src/asn1/DerBitString.cs
+++ b/crypto/src/asn1/DerBitString.cs
@@ -216,12 +216,12 @@ namespace Org.BouncyCastle.Asn1
             }
 		}
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, contents.Length);
         }
diff --git a/crypto/src/asn1/DerBoolean.cs b/crypto/src/asn1/DerBoolean.cs
index e2cd145a1..a6f972629 100644
--- a/crypto/src/asn1/DerBoolean.cs
+++ b/crypto/src/asn1/DerBoolean.cs
@@ -81,20 +81,25 @@ namespace Org.BouncyCastle.Asn1
             get { return value != 0; }
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, 1);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            // TODO Should we make sure the byte value is one of '0' or '0xff' here?
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Boolean, value);
+            byte contents = value;
+            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding && IsTrue)
+            {
+                contents = 0xFF;
+            }
+
+            asn1Out.WriteEncodingDL(withID, Asn1Tags.Boolean, contents);
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index 03d85fbfd..af9e6330a 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -119,12 +119,12 @@ namespace Org.BouncyCastle.Asn1
             }
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, bytes.Length);
         }
diff --git a/crypto/src/asn1/DerGeneralString.cs b/crypto/src/asn1/DerGeneralString.cs
index 9724870b1..f5575650b 100644
--- a/crypto/src/asn1/DerGeneralString.cs
+++ b/crypto/src/asn1/DerGeneralString.cs
@@ -61,12 +61,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
         }
diff --git a/crypto/src/asn1/DerGeneralizedTime.cs b/crypto/src/asn1/DerGeneralizedTime.cs
index c17fcbdce..e70a481dc 100644
--- a/crypto/src/asn1/DerGeneralizedTime.cs
+++ b/crypto/src/asn1/DerGeneralizedTime.cs
@@ -295,12 +295,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(time);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, time.Length);
         }
diff --git a/crypto/src/asn1/DerGraphicString.cs b/crypto/src/asn1/DerGraphicString.cs
index f037c648b..4a864ea8c 100644
--- a/crypto/src/asn1/DerGraphicString.cs
+++ b/crypto/src/asn1/DerGraphicString.cs
@@ -83,12 +83,12 @@ namespace Org.BouncyCastle.Asn1
             return Arrays.Clone(m_contents);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, m_contents.Length);
         }
diff --git a/crypto/src/asn1/DerIA5String.cs b/crypto/src/asn1/DerIA5String.cs
index 47c1395cf..97a9222c2 100644
--- a/crypto/src/asn1/DerIA5String.cs
+++ b/crypto/src/asn1/DerIA5String.cs
@@ -100,12 +100,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
         }
diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs
index 791b6e7e3..36fd58870 100644
--- a/crypto/src/asn1/DerInteger.cs
+++ b/crypto/src/asn1/DerInteger.cs
@@ -169,12 +169,12 @@ namespace Org.BouncyCastle.Asn1
             }
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, bytes.Length);
         }
diff --git a/crypto/src/asn1/DerNull.cs b/crypto/src/asn1/DerNull.cs
index 5ca8ba771..947acaf0b 100644
--- a/crypto/src/asn1/DerNull.cs
+++ b/crypto/src/asn1/DerNull.cs
@@ -16,12 +16,12 @@ namespace Org.BouncyCastle.Asn1
 		{
 		}
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, 0);
         }
diff --git a/crypto/src/asn1/DerNumericString.cs b/crypto/src/asn1/DerNumericString.cs
index cb73817be..4412f973e 100644
--- a/crypto/src/asn1/DerNumericString.cs
+++ b/crypto/src/asn1/DerNumericString.cs
@@ -100,12 +100,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
         }
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index 08451b82f..f24bbf984 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -128,12 +128,12 @@ namespace Org.BouncyCastle.Asn1
             return identifier.GetHashCode();
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length);
         }
diff --git a/crypto/src/asn1/DerOctetString.cs b/crypto/src/asn1/DerOctetString.cs
index 55c099360..d49393641 100644
--- a/crypto/src/asn1/DerOctetString.cs
+++ b/crypto/src/asn1/DerOctetString.cs
@@ -21,12 +21,12 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, contents.Length);
         }
diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs
index f384c20a8..47b945635 100644
--- a/crypto/src/asn1/DerOutputStream.cs
+++ b/crypto/src/asn1/DerOutputStream.cs
@@ -34,14 +34,14 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override bool IsBer
+        internal override DerOutputStreamNew GetDerSubStream()
         {
-            get { return false; }
+            return this;
         }
 
-        internal override bool IsDer
+        internal override int Encoding
         {
-            get { return true; }
+            get { return EncodingDer; }
         }
 
         internal override void WritePrimitive(Asn1Object primitive, bool withID)
diff --git a/crypto/src/asn1/DerPrintableString.cs b/crypto/src/asn1/DerPrintableString.cs
index e930e2845..3d911a6ac 100644
--- a/crypto/src/asn1/DerPrintableString.cs
+++ b/crypto/src/asn1/DerPrintableString.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Text;
 
 using Org.BouncyCastle.Utilities;
 
@@ -100,12 +99,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
         }
diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs
index 157d99c93..e60796091 100644
--- a/crypto/src/asn1/DerSequence.cs
+++ b/crypto/src/asn1/DerSequence.cs
@@ -1,7 +1,4 @@
 using System;
-using System.IO;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
@@ -15,10 +12,12 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DerSequence(elementVector);
 		}
 
-		/**
+        private int m_contentsLengthDer = -1;
+
+        /**
 		 * create an empty sequence
 		 */
-		public DerSequence()
+        public DerSequence()
 			: base()
 		{
 		}
@@ -49,9 +48,9 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("DerSequence.EncodedLength");
+            return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContentsLengthDer());
         }
 
         /*
@@ -64,29 +63,41 @@ namespace Org.BouncyCastle.Asn1
 		 */
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            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();
-            Asn1OutputStream dOut = Asn1OutputStream.Create(bOut, Der);
-            dOut.WriteElements(elements);
-            dOut.FlushInternal();
+            asn1Out = asn1Out.GetDerSubStream();
 
-#if PORTABLE
-            byte[] bytes = bOut.ToArray();
-            int length = bytes.Length;
-#else
-            byte[] bytes = bOut.GetBuffer();
-            int length = (int)bOut.Position;
-#endif
+            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Sequence);
 
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, bytes, 0, length);
+            int count = elements.Length;
+            if (m_contentsLengthDer >= 0 || count > 16)
+            {
+                asn1Out.WriteDL(GetContentsLengthDer());
 
-            Platform.Dispose(dOut);
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Object.Encode(asn1Out, true);
+                }
+            }
+            else
+            {
+                int contentsLength = 0;
+
+                Asn1Object[] asn1Objects = new Asn1Object[count];
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Objects[i] = asn1Object;
+                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
+                }
+
+                this.m_contentsLengthDer = contentsLength;
+                asn1Out.WriteDL(contentsLength);
+
+                for (int i = 0; i < count; ++i)
+                {
+                    asn1Objects[i].Encode(asn1Out, true);
+                }
+            }
         }
 
         internal override DerBitString ToAsn1BitString()
@@ -109,5 +120,14 @@ namespace Org.BouncyCastle.Asn1
             // NOTE: DLSet is intentional, we don't want sorting
             return new DLSet(false, elements);
         }
+
+        private int GetContentsLengthDer()
+        {
+            if (m_contentsLengthDer < 0)
+            {
+                m_contentsLengthDer = CalculateContentsLength(Asn1OutputStream.EncodingDer);
+            }
+            return m_contentsLengthDer;
+        }
     }
 }
diff --git a/crypto/src/asn1/DerSet.cs b/crypto/src/asn1/DerSet.cs
index 030b0a38f..d89285d9e 100644
--- a/crypto/src/asn1/DerSet.cs
+++ b/crypto/src/asn1/DerSet.cs
@@ -1,7 +1,4 @@
 using System;
-using System.IO;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
@@ -18,10 +15,12 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DerSet(elementVector);
 		}
 
-		/**
+        private int m_contentsLengthDer = -1;
+
+        /**
 		 * create an empty set
 		 */
-		public DerSet()
+        public DerSet()
 			: base()
 		{
 		}
@@ -62,9 +61,20 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("DerSet.EncodedLength");
+            encoding = Asn1OutputStream.EncodingDer;
+
+            int count = elements.Length;
+            int contentsLength = 0;
+
+            for (int i = 0; i < count; ++i)
+            {
+                Asn1Object asn1Object = elements[i].ToAsn1Object();
+                contentsLength += asn1Object.EncodedLength(encoding, true);
+            }
+
+            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
         }
 
         /*
@@ -83,34 +93,56 @@ namespace Org.BouncyCastle.Asn1
                 return;
             }
 
+            Asn1Encodable[] elements = this.elements;
             if (!isSorted)
             {
-                new DerSet(elements, true).ImplEncode(asn1Out, withID);
-                return;
+                elements = Sort((Asn1Encodable[])elements.Clone());
             }
 
-            ImplEncode(asn1Out, withID);
+            asn1Out = asn1Out.GetDerSubStream();
+
+            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Set);
+
+            int count = elements.Length;
+            if (m_contentsLengthDer >= 0 || count > 16)
+            {
+                asn1Out.WriteDL(GetContentsLengthDer());
+
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Object.Encode(asn1Out, true);
+                }
+            }
+            else
+            {
+                int contentsLength = 0;
+
+                Asn1Object[] asn1Objects = new Asn1Object[count];
+                for (int i = 0; i < count; ++i)
+                {
+                    Asn1Object asn1Object = elements[i].ToAsn1Object();
+                    asn1Objects[i] = asn1Object;
+                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
+                }
+
+                this.m_contentsLengthDer = contentsLength;
+                asn1Out.WriteDL(contentsLength);
+
+                for (int i = 0; i < count; ++i)
+                {
+                    asn1Objects[i].Encode(asn1Out, true);
+                }
+            }
         }
 
-        private void ImplEncode(Asn1OutputStream asn1Out, bool withID)
+        private int GetContentsLengthDer()
         {
-            // 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.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);
+            if (m_contentsLengthDer < 0)
+            {
+                m_contentsLengthDer = CalculateContentsLength(Asn1OutputStream.EncodingDer);
+            }
+            return m_contentsLengthDer;
         }
     }
 }
diff --git a/crypto/src/asn1/DerT61String.cs b/crypto/src/asn1/DerT61String.cs
index cf2123131..79a7ef8e4 100644
--- a/crypto/src/asn1/DerT61String.cs
+++ b/crypto/src/asn1/DerT61String.cs
@@ -77,12 +77,12 @@ namespace Org.BouncyCastle.Asn1
             return str;
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
         }
diff --git a/crypto/src/asn1/DerTaggedObject.cs b/crypto/src/asn1/DerTaggedObject.cs
index b75e0879d..e58590c8d 100644
--- a/crypto/src/asn1/DerTaggedObject.cs
+++ b/crypto/src/asn1/DerTaggedObject.cs
@@ -1,7 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1
 {
 	/**
@@ -12,11 +10,13 @@ namespace Org.BouncyCastle.Asn1
 	public class DerTaggedObject
 		: Asn1TaggedObject
 	{
-		/**
+        private int m_contentsLengthDer = -1;
+
+        /**
 		 * @param tagNo the tag number for this object.
 		 * @param obj the tagged object.
 		 */
-		public DerTaggedObject(
+        public DerTaggedObject(
 			int				tagNo,
 			Asn1Encodable	obj)
 			: base(tagNo, obj)
@@ -51,50 +51,70 @@ namespace Org.BouncyCastle.Asn1
             get { return Der; }
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
-            throw Platform.CreateNotImplementedException("DerTaggedObject.EncodeConstructed");
+            encoding = Asn1OutputStream.EncodingDer;
 
-            //return IsExplicit() || obj.ToAsn1Object().ToDerObject().EncodeConstructed();
+            return IsExplicit() || GetBaseObject().ToAsn1Object().EncodeConstructed(encoding);
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            throw Platform.CreateNotImplementedException("DerTaggedObject.EncodedLength");
+            encoding = Asn1OutputStream.EncodingDer;
+
+            Asn1Object baseObject = GetBaseObject().ToAsn1Object();
+            bool withBaseID = IsExplicit();
+
+            int length = GetContentsLengthDer(baseObject, withBaseID);
+
+            if (withBaseID)
+            {
+                length += Asn1OutputStream.GetLengthOfDL(length);
+            }
+
+            length += withID ? Asn1OutputStream.GetLengthOfIdentifier(TagNo) : 0;
+
+            return length;
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            byte[] bytes = obj.GetDerEncoded();
+            asn1Out = asn1Out.GetDerSubStream();
 
-            if (explicitly)
-            {
-                asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | TagClass, TagNo, bytes);
-            }
-            else
+            Asn1Object baseObject = GetBaseObject().ToAsn1Object();
+            bool withBaseID = IsExplicit();
+
+            if (withID)
             {
-                int tagHdr = bytes[0], tagLen = 1;
-                if ((tagHdr & 0x1F) == 0x1F)
+                int flags = TagClass;
+                if (withBaseID || baseObject.EncodeConstructed(asn1Out.Encoding))
                 {
-                    while ((bytes[tagLen++] & 0x80) != 0)
-                    {
-                    }
+                    flags |= Asn1Tags.Constructed;
                 }
 
-                if (withID)
-                {
-                    int flags = (tagHdr & Asn1Tags.Constructed) | TagClass;
-
-                    asn1Out.WriteIdentifier(true, flags, TagNo);
-                }
+                asn1Out.WriteIdentifier(true, flags, TagNo);
+            }
 
-                asn1Out.Write(bytes, tagLen, bytes.Length - tagLen);
+            if (withBaseID)
+            {
+                asn1Out.WriteDL(GetContentsLengthDer(baseObject, true));
             }
+
+            baseObject.Encode(asn1Out, withBaseID);
         }
 
         internal override Asn1Sequence RebuildConstructed(Asn1Object asn1Object)
         {
             return new DerSequence(asn1Object);
         }
+
+        private int GetContentsLengthDer(Asn1Object baseObject, bool withBaseID)
+        {
+            if (m_contentsLengthDer < 0)
+            {
+                m_contentsLengthDer = baseObject.EncodedLength(Asn1OutputStream.EncodingDer, withBaseID);
+            }
+            return m_contentsLengthDer;
+        }
     }
 }
diff --git a/crypto/src/asn1/DerUTCTime.cs b/crypto/src/asn1/DerUTCTime.cs
index 5124af12f..17d02df19 100644
--- a/crypto/src/asn1/DerUTCTime.cs
+++ b/crypto/src/asn1/DerUTCTime.cs
@@ -237,12 +237,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(time);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, time.Length);
         }
diff --git a/crypto/src/asn1/DerUTF8String.cs b/crypto/src/asn1/DerUTF8String.cs
index 0406f4a71..7bc9ff524 100644
--- a/crypto/src/asn1/DerUTF8String.cs
+++ b/crypto/src/asn1/DerUTF8String.cs
@@ -89,12 +89,12 @@ namespace Org.BouncyCastle.Asn1
 			return this.str.Equals(other.str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, Encoding.UTF8.GetByteCount(str));
         }
diff --git a/crypto/src/asn1/DerUniversalString.cs b/crypto/src/asn1/DerUniversalString.cs
index e9188b202..ab89a0e12 100644
--- a/crypto/src/asn1/DerUniversalString.cs
+++ b/crypto/src/asn1/DerUniversalString.cs
@@ -86,12 +86,12 @@ namespace Org.BouncyCastle.Asn1
             return (byte[]) str.Clone();
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, this.str.Length);
         }
diff --git a/crypto/src/asn1/DerVideotexString.cs b/crypto/src/asn1/DerVideotexString.cs
index 377cd060a..5b9ad09f9 100644
--- a/crypto/src/asn1/DerVideotexString.cs
+++ b/crypto/src/asn1/DerVideotexString.cs
@@ -79,12 +79,12 @@ namespace Org.BouncyCastle.Asn1
             return Arrays.Clone(mString);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, mString.Length);
         }
diff --git a/crypto/src/asn1/DerVisibleString.cs b/crypto/src/asn1/DerVisibleString.cs
index ae2aaeec2..9e34ef65e 100644
--- a/crypto/src/asn1/DerVisibleString.cs
+++ b/crypto/src/asn1/DerVisibleString.cs
@@ -86,12 +86,12 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed()
+        internal override bool EncodeConstructed(int encoding)
         {
             return false;
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
             return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
         }
diff --git a/crypto/src/asn1/LazyDLSequence.cs b/crypto/src/asn1/LazyDLSequence.cs
index fe924365e..bf9fc0800 100644
--- a/crypto/src/asn1/LazyDLSequence.cs
+++ b/crypto/src/asn1/LazyDLSequence.cs
@@ -63,21 +63,25 @@ namespace Org.BouncyCastle.Asn1
             return base.ToString();
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            // TODO This depends on knowing it's BER
-            byte[] encoded = GetContents();
-            if (encoded != null)
+            if (Asn1OutputStream.EncodingBer == encoding)
             {
-                return Asn1OutputStream.GetLengthOfEncodingDL(withID, encoded.Length);
+                byte[] encoded = GetContents();
+                if (null != encoded)
+                    return Asn1OutputStream.GetLengthOfEncodingDL(withID, encoded.Length);
+            }
+            else
+            {
+                Force();
             }
 
-            return base.EncodedLength(withID);
+            return base.EncodedLength(encoding, withID);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (asn1Out.IsBer)
+            if (Asn1OutputStream.EncodingBer == asn1Out.Encoding)
             {
                 byte[] encoded = GetContents();
                 if (encoded != null)
diff --git a/crypto/src/asn1/LazyDLSet.cs b/crypto/src/asn1/LazyDLSet.cs
index bdee0bc22..a426bb4cb 100644
--- a/crypto/src/asn1/LazyDLSet.cs
+++ b/crypto/src/asn1/LazyDLSet.cs
@@ -63,21 +63,25 @@ namespace Org.BouncyCastle.Asn1
             return base.ToString();
         }
 
-        internal override int EncodedLength(bool withID)
+        internal override int EncodedLength(int encoding, bool withID)
         {
-            // TODO This depends on knowing it's BER
-            byte[] encoded = GetContents();
-            if (encoded != null)
+            if (Asn1OutputStream.EncodingBer == encoding)
             {
-                return Asn1OutputStream.GetLengthOfEncodingDL(withID, encoded.Length);
+                byte[] encoded = GetContents();
+                if (null != encoded)
+                    return Asn1OutputStream.GetLengthOfEncodingDL(withID, encoded.Length);
+            }
+            else
+            {
+                Force();
             }
 
-            return base.EncodedLength(withID);
+            return base.EncodedLength(encoding, withID);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
         {
-            if (asn1Out.IsBer)
+            if (Asn1OutputStream.EncodingBer == asn1Out.Encoding)
             {
                 byte[] encoded = GetContents();
                 if (encoded != null)