summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2021-11-06 23:39:42 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2021-11-06 23:39:42 +0700
commitf6f0935f51e33f1ccd01fb4d167abc23a4c9b1d1 (patch)
treec1d42127be4455f042e895ac9d0b12d3d98d9460 /crypto/src/asn1
parentTrim the stack trace (diff)
downloadBouncyCastle.NET-ed25519-f6f0935f51e33f1ccd01fb4d167abc23a4c9b1d1.tar.xz
Rewrite DerExternal
Diffstat (limited to '')
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs8
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs18
-rw-r--r--crypto/src/asn1/BerSequence.cs14
-rw-r--r--crypto/src/asn1/DERExternal.cs319
-rw-r--r--crypto/src/asn1/DerSequence.cs10
5 files changed, 234 insertions, 135 deletions
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index 286b731f5..ecc773a1a 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -128,6 +128,11 @@ namespace Org.BouncyCastle.Asn1
             this.elements = Asn1EncodableVector.CloneElements(elements);
         }
 
+        internal Asn1Sequence(Asn1Encodable[] elements, bool clone)
+        {
+            this.elements = clone ? Asn1EncodableVector.CloneElements(elements) : elements;
+        }
+
         protected internal Asn1Sequence(Asn1EncodableVector elementVector)
         {
             if (null == elementVector)
@@ -248,5 +253,8 @@ namespace Org.BouncyCastle.Asn1
         {
             return CollectionUtilities.ToString(elements);
         }
+
+        // TODO[asn1] Preferably return an Asn1External (doesn't exist yet)
+        internal abstract DerExternal ToAsn1External();
     }
 }
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index 501f877ab..5eb0441ed 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -145,12 +145,26 @@ namespace Org.BouncyCastle.Asn1
             return obj.ToAsn1Object();
         }
 
-		/**
+        /**
+         * Needed for open types, until we have better type-guided parsing support. Use
+         * sparingly for other purposes, and prefer {@link #getExplicitBaseTagged()} or
+         * {@link #getBaseUniversal(boolean, int)} where possible. Before using, check
+         * for matching tag {@link #getTagClass() class} and {@link #getTagNo() number}.
+         */
+        public Asn1Object GetExplicitBaseObject()
+        {
+            if (!IsExplicit())
+                throw new InvalidOperationException("object implicit - explicit expected.");
+
+            return obj.ToAsn1Object();
+        }
+
+        /**
 		* Return the object held in this tagged object as a parser assuming it has
 		* the type of the passed in tag. If the object doesn't have a parser
 		* associated with it, the base object is returned.
 		*/
-		public IAsn1Convertible GetObjectParser(
+        public IAsn1Convertible GetObjectParser(
 			int		tag,
 			bool	isExplicit)
 		{
diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs
index 068f0a2a8..1795025f2 100644
--- a/crypto/src/asn1/BerSequence.cs
+++ b/crypto/src/asn1/BerSequence.cs
@@ -43,6 +43,11 @@ namespace Org.BouncyCastle.Asn1
 		{
 		}
 
+        internal BerSequence(Asn1Encodable[] elements, bool clone)
+            : base(elements, clone)
+        {
+        }
+
         internal override int EncodedLength(bool withID)
         {
             throw Platform.CreateNotImplementedException("BerSequence.EncodedLength");
@@ -59,5 +64,12 @@ namespace Org.BouncyCastle.Asn1
 				base.Encode(asn1Out, withID);
 			}
 		}
-	}
+
+        internal override DerExternal ToAsn1External()
+        {
+            // TODO There is currently no BerExternal class (or ToDLObject/ToDerObject)
+            //return ((Asn1Sequence)ToDLObject()).ToAsn1External();
+            return new DerSequence(elements, false).ToAsn1External();
+        }
+    }
 }
diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs
index f457917ca..faf64c266 100644
--- a/crypto/src/asn1/DERExternal.cs
+++ b/crypto/src/asn1/DERExternal.cs
@@ -11,54 +11,98 @@ namespace Org.BouncyCastle.Asn1
 	public class DerExternal
 		: Asn1Object
 	{
-		private DerObjectIdentifier	directReference;
-		private DerInteger			indirectReference;
-		private Asn1Object			dataValueDescriptor;
-		private int					encoding;
-		private Asn1Object			externalContent;
-
-		public DerExternal(
-			Asn1EncodableVector vector)
+        public static DerExternal GetInstance(object obj)
+        {
+            if (obj == null || obj is DerExternal)
+            {
+                return (DerExternal)obj;
+            }
+            if (obj is Asn1Encodable)
+            {
+                Asn1Object asn1 = ((Asn1Encodable)obj).ToAsn1Object();
+                if (asn1 is DerExternal)
+                    return (DerExternal)asn1;
+            }
+            if (obj is byte[])
+            {
+                try
+                {
+                    return GetInstance(FromByteArray((byte[])obj));
+                }
+                catch (Exception e)
+                {
+                    throw new ArgumentException("encoding error in GetInstance: " + e.ToString(), "obj");
+                }
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+        }
+
+        public static DerExternal GetInstance(Asn1TaggedObject taggedObject, bool isExplicit)
+        {
+            Asn1Object baseObject = taggedObject.GetObject();
+
+            if (isExplicit || baseObject is DerExternal)
+            {
+                return GetInstance(baseObject);
+            }
+
+            return Asn1Sequence.GetInstance(taggedObject, false).ToAsn1External();
+        }
+
+		private readonly DerObjectIdentifier directReference;
+		private readonly DerInteger indirectReference;
+        private readonly Asn1ObjectDescriptor dataValueDescriptor;
+		private readonly int encoding;
+		private readonly Asn1Object externalContent;
+
+        [Obsolete("Use constructor taking an Asn1Sequence instead.")]
+        public DerExternal(Asn1EncodableVector vector)
+            : this(new DerSequence(vector))
+        {
+        }
+
+        public DerExternal(DerSequence sequence)
 		{
 			int offset = 0;
-			Asn1Object enc = GetObjFromVector(vector, offset);
-			if (enc is DerObjectIdentifier)
+
+			Asn1Object asn1 = GetObjFromSequence(sequence, offset);
+			if (asn1 is DerObjectIdentifier)
 			{
-				directReference = (DerObjectIdentifier)enc;
-				offset++;
-				enc = GetObjFromVector(vector, offset);
+				directReference = (DerObjectIdentifier)asn1;
+                asn1 = GetObjFromSequence(sequence, ++offset);
 			}
-			if (enc is DerInteger)
+			if (asn1 is DerInteger)
 			{
-				indirectReference = (DerInteger) enc;
-				offset++;
-				enc = GetObjFromVector(vector, offset);
+				indirectReference = (DerInteger)asn1;
+                asn1 = GetObjFromSequence(sequence, ++offset);
 			}
-			if (!(enc is Asn1TaggedObject))
+			if (!(asn1 is Asn1TaggedObject))
 			{
-				dataValueDescriptor = enc;
-				offset++;
-				enc = GetObjFromVector(vector, offset);
+				dataValueDescriptor = (Asn1ObjectDescriptor)asn1;
+                asn1 = GetObjFromSequence(sequence, ++offset);
 			}
 
-            if (vector.Count != offset + 1)
-				throw new ArgumentException("input vector too large", "vector");
+            if (sequence.Count != offset + 1)
+				throw new ArgumentException("input sequence too large", "sequence");
 
-            if (!(enc is Asn1TaggedObject))
-				throw new ArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External", "vector");
+            if (!(asn1 is Asn1TaggedObject))
+				throw new ArgumentException(
+                    "No tagged object found in sequence. Structure doesn't seem to be of type External", "sequence");
 
-            Asn1TaggedObject obj = (Asn1TaggedObject)enc;
-
-			// Use property accessor to include check on value
-			Encoding = obj.TagNo;
-
-			if (encoding < 0 || encoding > 2)
-				throw new InvalidOperationException("invalid encoding value");
+            Asn1TaggedObject obj = (Asn1TaggedObject)asn1;
+			this.encoding = CheckEncoding(obj.TagNo);
+            this.externalContent = GetExternalContent(obj);
+		}
 
-			externalContent = obj.GetObject();
+        [Obsolete("Use constructor with dataValueDescriptor of type Asn1ObjectDescriptor")]
+        public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference,
+            Asn1Object dataValueDescriptor, DerTaggedObject externalData)
+			: this(directReference, indirectReference, CheckDataValueDescriptor(dataValueDescriptor), externalData)
+		{
 		}
 
-		/**
+        /**
 		* Creates a new instance of DerExternal
 		* See X.690 for more informations about the meaning of these parameters
 		* @param directReference The direct reference or <code>null</code> if not set.
@@ -66,12 +110,25 @@ namespace Org.BouncyCastle.Asn1
 		* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
 		* @param externalData The external data in its encoded form.
 		*/
-		public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, DerTaggedObject externalData)
-			: this(directReference, indirectReference, dataValueDescriptor, externalData.TagNo, externalData.ToAsn1Object())
+        public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference,
+            Asn1ObjectDescriptor dataValueDescriptor, DerTaggedObject externalData)
+        {
+            this.directReference = directReference;
+            this.indirectReference = indirectReference;
+            this.dataValueDescriptor = dataValueDescriptor;
+            this.encoding = CheckEncoding(externalData.TagNo);
+            this.externalContent = GetExternalContent(externalData);
+        }
+
+        [Obsolete("Use constructor with dataValueDescriptor of type Asn1ObjectDescriptor")]
+        public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference,
+            Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData)
+            : this(directReference, indirectReference, CheckDataValueDescriptor(dataValueDescriptor), encoding,
+                  externalData)
 		{
 		}
 
-		/**
+        /**
 		* Creates a new instance of DerExternal.
 		* See X.690 for more informations about the meaning of these parameters
 		* @param directReference The direct reference or <code>null</code> if not set.
@@ -80,96 +137,63 @@ namespace Org.BouncyCastle.Asn1
 		* @param encoding The encoding to be used for the external data
 		* @param externalData The external data
 		*/
-		public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData)
-		{
-			DirectReference = directReference;
-			IndirectReference = indirectReference;
-			DataValueDescriptor = dataValueDescriptor;
-			Encoding = encoding;
-			ExternalContent = externalData.ToAsn1Object();
-		}
-
-        internal override int EncodedLength(bool withID)
+        public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference,
+            Asn1ObjectDescriptor dataValueDescriptor, int encoding, Asn1Object externalData)
         {
-            int contentsLength = 0;
-            if (directReference != null)
-            {
-                contentsLength += directReference.EncodedLength(true);
-            }
-            if (indirectReference != null)
-            {
-                contentsLength += indirectReference.EncodedLength(true);
-            }
-            if (dataValueDescriptor != null)
-            {
-                // TODO[asn1]
-                //contentsLength += dataValueDescriptor.ToDerObject().EncodedLength(true);
-                contentsLength += dataValueDescriptor.GetDerEncoded().Length;
-            }
+            this.directReference = directReference;
+            this.indirectReference = indirectReference;
+            this.dataValueDescriptor = dataValueDescriptor;
+            this.encoding = CheckEncoding(encoding);
+            this.externalContent = CheckExternalContent(encoding, externalData);
+        }
 
-            // TODO[asn1]
-            //contentsLength += new DerTaggedObject(true, encoding, externalContent).EncodedLength(true);
-            contentsLength += new DerTaggedObject(Asn1Tags.External, externalContent).EncodedLength(true);
+        internal Asn1Sequence BuildSequence()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(4);
+            v.AddOptional(directReference, indirectReference, dataValueDescriptor);
+            v.Add(new DerTaggedObject(0 == encoding, encoding, externalContent));
+            return new DerSequence(v);
+        }
 
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
+        internal override int EncodedLength(bool withID)
+        {
+            return BuildSequence().EncodedLength(withID);
         }
 
         internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-		{
-			MemoryStream ms = new MemoryStream();
-			WriteEncodable(ms, directReference);
-			WriteEncodable(ms, indirectReference);
-			WriteEncodable(ms, dataValueDescriptor);
-			WriteEncodable(ms, new DerTaggedObject(Asn1Tags.External, externalContent));
-
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.External, ms.ToArray());
-		}
+        {
+            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.External);
+            BuildSequence().Encode(asn1Out, false);
+        }
 
-		protected override int Asn1GetHashCode()
+        protected override int Asn1GetHashCode()
 		{
-			int ret = externalContent.GetHashCode();
-			if (directReference != null)
-			{
-				ret ^= directReference.GetHashCode();
-			}
-			if (indirectReference != null)
-			{
-				ret ^= indirectReference.GetHashCode();
-			}
-			if (dataValueDescriptor != null)
-			{
-				ret ^= dataValueDescriptor.GetHashCode();
-			}
-			return ret;
+            return Platform.GetHashCode(this.directReference)
+                ^  Platform.GetHashCode(this.indirectReference)
+                ^  Platform.GetHashCode(this.dataValueDescriptor)
+                ^  this.encoding
+                ^  this.externalContent.GetHashCode();
 		}
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
+		protected override bool Asn1Equals(Asn1Object asn1Object)
 		{
-			if (this == asn1Object)
-				return true;
-
-			DerExternal other = asn1Object as DerExternal;
-
-			if (other == null)
-				return false;
-
-			return Platform.Equals(directReference, other.directReference)
-				&& Platform.Equals(indirectReference, other.indirectReference)
-				&& Platform.Equals(dataValueDescriptor, other.dataValueDescriptor)
-				&& externalContent.Equals(other.externalContent);
+			DerExternal that = asn1Object as DerExternal;
+            return null != that
+                && Platform.Equals(this.directReference, that.directReference)
+                && Platform.Equals(this.indirectReference, that.indirectReference)
+                && Platform.Equals(this.dataValueDescriptor, that.dataValueDescriptor)
+                && this.encoding == that.encoding
+				&& this.externalContent.Equals(that.externalContent);
 		}
 
-		public Asn1Object DataValueDescriptor
+		public Asn1ObjectDescriptor DataValueDescriptor
 		{
 			get { return dataValueDescriptor; }
-			set { this.dataValueDescriptor = value; }
 		}
 
 		public DerObjectIdentifier DirectReference
 		{
 			get { return directReference; }
-			set { this.directReference = value; }
 		}
 
 		/**
@@ -182,46 +206,77 @@ namespace Org.BouncyCastle.Asn1
 		*/
 		public int Encoding
 		{
-			get
-			{
-				return encoding;
-			}
-			set
-			{
-				if (encoding < 0 || encoding > 2)
-					throw new InvalidOperationException("invalid encoding value: " + encoding);
-
-				this.encoding = value;
-			}
+            get { return encoding; }
 		}
 
 		public Asn1Object ExternalContent
 		{
 			get { return externalContent; }
-			set { this.externalContent = value; }
 		}
 
 		public DerInteger IndirectReference
 		{
 			get { return indirectReference; }
-			set { this.indirectReference = value; }
 		}
 
-		private static Asn1Object GetObjFromVector(Asn1EncodableVector v, int index)
-		{
-			if (v.Count <= index)
-				throw new ArgumentException("too few objects in input vector", "v");
+        private static Asn1ObjectDescriptor CheckDataValueDescriptor(Asn1Object dataValueDescriptor)
+        {
+            if (dataValueDescriptor is Asn1ObjectDescriptor)
+                return (Asn1ObjectDescriptor)dataValueDescriptor;
+            if (dataValueDescriptor is DerGraphicString)
+                return new Asn1ObjectDescriptor((DerGraphicString)dataValueDescriptor);
 
-			return v[index].ToAsn1Object();
-		}
+            throw new ArgumentException("incompatible type for data-value-descriptor", "dataValueDescriptor");
+        }
 
-		private static void WriteEncodable(MemoryStream ms, Asn1Encodable e)
+        private static int CheckEncoding(int encoding)
+        {
+            if (encoding < 0 || encoding > 2)
+                throw new InvalidOperationException("invalid encoding value: " + encoding);
+
+            return encoding;
+        }
+
+        private static Asn1Object CheckExternalContent(int tagNo, Asn1Object externalContent)
+        {
+            switch (tagNo)
+            {
+            case 1:
+                //return ASN1OctetString.TYPE.checkedCast(externalContent);
+                return (Asn1OctetString)externalContent;
+            case 2:
+                //return ASN1BitString.TYPE.checkedCast(externalContent);
+                return (DerBitString)externalContent;
+            default:
+                return externalContent;
+            }
+        }
+
+        private static Asn1Object GetExternalContent(Asn1TaggedObject encoding)
+        {
+            int tagClass = encoding.TagClass, tagNo = encoding.TagNo;
+            if (Asn1Tags.ContextSpecific != tagClass)
+                throw new ArgumentException("invalid tag: " + Asn1Utilities.GetTagText(tagClass, tagNo), "encoding");
+
+            switch (tagNo)
+            {
+            case 0:
+                return encoding.GetExplicitBaseObject();
+            case 1:
+                return Asn1OctetString.GetInstance(encoding, false);
+            case 2:
+                return DerBitString.GetInstance(encoding, false);
+            default:
+                throw new ArgumentException("invalid tag: " + Asn1Utilities.GetTagText(tagClass, tagNo), "encoding");
+            }
+        }
+
+        private static Asn1Object GetObjFromSequence(Asn1Sequence sequence, int index)
 		{
-			if (e != null)
-			{
-				byte[] bs = e.GetDerEncoded();
-				ms.Write(bs, 0, bs.Length);
-			}
+			if (sequence.Count <= index)
+				throw new ArgumentException("too few objects in input sequence", "sequence");
+
+			return sequence[index].ToAsn1Object();
 		}
 	}
 }
diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs
index 6750b8a50..d703cd0f5 100644
--- a/crypto/src/asn1/DerSequence.cs
+++ b/crypto/src/asn1/DerSequence.cs
@@ -45,6 +45,11 @@ namespace Org.BouncyCastle.Asn1
 		{
 		}
 
+        internal DerSequence(Asn1Encodable[] elements, bool clone)
+            : base(elements, clone)
+        {
+        }
+
         internal override int EncodedLength(bool withID)
         {
             throw Platform.CreateNotImplementedException("DerSequence.EncodedLength");
@@ -84,5 +89,10 @@ namespace Org.BouncyCastle.Asn1
 
             Platform.Dispose(dOut);
         }
+
+        internal override DerExternal ToAsn1External()
+        {
+            return new DerExternal(this);
+        }
     }
 }