summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2024-06-06 20:20:28 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2024-06-06 20:20:28 +0700
commit2de510c0d1e7969eee14473ba71b161bf5d01e15 (patch)
tree524bd77b97f17d6c2656fc3de2d21684971fb982 /crypto
parentRefactoring in Asn1.Cms.Ecc (diff)
downloadBouncyCastle.NET-ed25519-2de510c0d1e7969eee14473ba71b161bf5d01e15.tar.xz
Refactoring in Asn1.Ess
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/asn1/ess/ContentHints.cs99
-rw-r--r--crypto/src/asn1/ess/ContentIdentifier.cs66
-rw-r--r--crypto/src/asn1/ess/ESSCertID.cs98
-rw-r--r--crypto/src/asn1/ess/ESSCertIDv2.cs100
-rw-r--r--crypto/src/asn1/ess/SigningCertificate.cs88
-rw-r--r--crypto/src/asn1/ess/SigningCertificateV2.cs82
-rw-r--r--crypto/src/asn1/x509/IssuerSerial.cs15
7 files changed, 225 insertions, 323 deletions
diff --git a/crypto/src/asn1/ess/ContentHints.cs b/crypto/src/asn1/ess/ContentHints.cs
index f61bf0df8..29e3c3c89 100644
--- a/crypto/src/asn1/ess/ContentHints.cs
+++ b/crypto/src/asn1/ess/ContentHints.cs
@@ -1,74 +1,54 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.Ess
 {
-	public class ContentHints
+    public class ContentHints
 		: Asn1Encodable
 	{
-		private readonly DerUtf8String contentDescription;
-		private readonly DerObjectIdentifier contentType;
+        public static ContentHints GetInstance(object o)
+        {
+            if (o == null)
+                return null;
+            if (o is ContentHints contentHints)
+                return contentHints;
+            return new ContentHints(Asn1Sequence.GetInstance(o));
+        }
 
-		public static ContentHints GetInstance(
-			object o)
-		{
-			if (o == null || o is ContentHints)
-			{
-				return (ContentHints)o;
-			}
+        public static ContentHints GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new ContentHints(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
 
-			if (o is Asn1Sequence)
-			{
-				return new ContentHints((Asn1Sequence)o);
-			}
+        private readonly DerUtf8String m_contentDescription;
+        private readonly DerObjectIdentifier m_contentType;
 
-			throw new ArgumentException("unknown object in 'ContentHints' factory : "
-                + Platform.GetTypeName(o) + ".");
-		}
+        private ContentHints(Asn1Sequence seq)
+        {
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-		/**
-		 * constructor
-		 */
-		private ContentHints(
-			Asn1Sequence seq)
-		{
-			IAsn1Convertible field = seq[0];
-			if (field.ToAsn1Object() is DerUtf8String)
-			{
-				contentDescription = DerUtf8String.GetInstance(field);
-				contentType = DerObjectIdentifier.GetInstance(seq[1]);
-			}
-			else
-			{
-				contentType = DerObjectIdentifier.GetInstance(seq[0]);
-			}
-		}
+            m_contentDescription = Asn1Utilities.ReadOptional(seq, ref pos, DerUtf8String.GetOptional);
+            m_contentType = DerObjectIdentifier.GetInstance(seq[pos++]);
 
-		public ContentHints(
-			DerObjectIdentifier contentType)
-		{
-			this.contentType = contentType;
-			this.contentDescription = null;
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
-		public ContentHints(
-			DerObjectIdentifier	contentType,
-			DerUtf8String		contentDescription)
-		{
-			this.contentType = contentType;
-			this.contentDescription = contentDescription;
-		}
+        public ContentHints(DerObjectIdentifier contentType)
+            : this(contentType, null)
+        {
+        }
 
-		public DerObjectIdentifier ContentType
-		{
-			get { return contentType; }
-		}
+        public ContentHints(DerObjectIdentifier contentType, DerUtf8String contentDescription)
+        {
+            m_contentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
+            m_contentDescription = contentDescription;
+        }
 
-		public DerUtf8String ContentDescription
-		{
-			get { return contentDescription; }
-		}
+        public DerObjectIdentifier ContentType => m_contentType;
+
+		public DerUtf8String ContentDescription => m_contentDescription;
 
 		/**
 		 * <pre>
@@ -79,10 +59,9 @@ namespace Org.BouncyCastle.Asn1.Ess
 		 */
 		public override Asn1Object ToAsn1Object()
 		{
-			Asn1EncodableVector v = new Asn1EncodableVector(2);
-            v.AddOptional(contentDescription);
-			v.Add(contentType);
-			return new DerSequence(v);
+			return m_contentDescription == null
+				?  new DerSequence(m_contentType)
+                :  new DerSequence(m_contentDescription, m_contentType);
 		}
 	}
 }
diff --git a/crypto/src/asn1/ess/ContentIdentifier.cs b/crypto/src/asn1/ess/ContentIdentifier.cs
index 430185e11..0520653f3 100644
--- a/crypto/src/asn1/ess/ContentIdentifier.cs
+++ b/crypto/src/asn1/ess/ContentIdentifier.cs
@@ -1,54 +1,43 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.Ess
 {
-	public class ContentIdentifier
+    public class ContentIdentifier
 		: Asn1Encodable
 	{
-		private Asn1OctetString value;
-
-		public static ContentIdentifier GetInstance(
-			object o)
-		{
-			if (o == null || o is ContentIdentifier)
-			{
-				return (ContentIdentifier) o;
-			}
-
-			if (o is Asn1OctetString)
-			{
-				return new ContentIdentifier((Asn1OctetString) o);
-			}
-
-			throw new ArgumentException(
-				"unknown object in 'ContentIdentifier' factory : "
-                + Platform.GetTypeName(o) + ".");
-		}
-
-		/**
+        public static ContentIdentifier GetInstance(object o)
+        {
+            if (o == null)
+                return null;
+            if (o is ContentIdentifier contentIdentifier)
+                return contentIdentifier;
+            return new ContentIdentifier(Asn1OctetString.GetInstance(o));
+        }
+
+        public static ContentIdentifier GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new ContentIdentifier(Asn1OctetString.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly Asn1OctetString m_value;
+
+        /**
 		 * Create from OCTET STRING whose octets represent the identifier.
 		 */
-		public ContentIdentifier(
-			Asn1OctetString value)
-		{
-			this.value = value;
-		}
+        public ContentIdentifier(Asn1OctetString value)
+        {
+            m_value = value ?? throw new ArgumentNullException(nameof(value));
+        }
 
-		/**
+        /**
 		 * Create from byte array representing the identifier.
 		 */
-		public ContentIdentifier(
-			byte[] value)
+        public ContentIdentifier(byte[] value)
 			: this(new DerOctetString(value))
 		{
 		}
 
-		public Asn1OctetString Value
-		{
-			get { return value; }
-		}
+		public Asn1OctetString Value => m_value;
 
 		/**
 		 * The definition of ContentIdentifier is
@@ -59,9 +48,6 @@ namespace Org.BouncyCastle.Asn1.Ess
 		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
 		 *  smime(16) id-aa(2) 7 }
 		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			return value;
-		}
+		public override Asn1Object ToAsn1Object() => m_value;
 	}
 }
diff --git a/crypto/src/asn1/ess/ESSCertID.cs b/crypto/src/asn1/ess/ESSCertID.cs
index 7e5fe4c1e..d8a09e22e 100644
--- a/crypto/src/asn1/ess/ESSCertID.cs
+++ b/crypto/src/asn1/ess/ESSCertID.cs
@@ -5,72 +5,58 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Ess
 {
-	public class EssCertID
+    public class EssCertID
 		: Asn1Encodable
 	{
-		private Asn1OctetString certHash;
-		private IssuerSerial issuerSerial;
+        public static EssCertID GetInstance(object o)
+        {
+            if (o == null)
+                return null;
+            if (o is EssCertID essCertID)
+                return essCertID;
+#pragma warning disable CS0618 // Type or member is obsolete
+            return new EssCertID(Asn1Sequence.GetInstance(o));
+#pragma warning restore CS0618 // Type or member is obsolete
+        }
 
-		public static EssCertID GetInstance(
-			object o)
-		{
-			if (o == null || o is EssCertID)
-			{
-				return (EssCertID) o;
-			}
-
-			if (o is Asn1Sequence)
-			{
-				return new EssCertID((Asn1Sequence) o);
-			}
+        public static EssCertID GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+#pragma warning disable CS0618 // Type or member is obsolete
+            return new EssCertID(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+#pragma warning restore CS0618 // Type or member is obsolete
+        }
 
-			throw new ArgumentException(
-				"unknown object in 'EssCertID' factory : "
-                + Platform.GetTypeName(o) + ".");
-		}
+        private readonly Asn1OctetString m_certHash;
+        private readonly IssuerSerial m_issuerSerial;
 
-		/**
-		 * constructor
-		 */
-		public EssCertID(
-			Asn1Sequence seq)
+        [Obsolete("Use 'GetInstance' instead")]
+        public EssCertID(Asn1Sequence seq)
 		{
-			if (seq.Count < 1 || seq.Count > 2)
-			{
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
-			}
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			this.certHash = Asn1OctetString.GetInstance(seq[0]);
+            m_certHash = Asn1OctetString.GetInstance(seq[pos++]);
+            m_issuerSerial = Asn1Utilities.ReadOptional(seq, ref pos, IssuerSerial.GetOptional);
 
-			if (seq.Count > 1)
-			{
-				issuerSerial = IssuerSerial.GetInstance(seq[1]);
-			}
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
-		public EssCertID(
-			byte[] hash)
-		{
-			certHash = new DerOctetString(hash);
-		}
+        public EssCertID(byte[] hash)
+            : this(hash, null)
+        {
+        }
 
-		public EssCertID(
-			byte[]			hash,
-			IssuerSerial	issuerSerial)
-		{
-			this.certHash = new DerOctetString(hash);
-			this.issuerSerial = issuerSerial;
-		}
+        public EssCertID(byte[] hash, IssuerSerial issuerSerial)
+        {
+            m_certHash = new DerOctetString(hash);
+            m_issuerSerial = issuerSerial;
+        }
 
-		public byte[] GetCertHash()
-		{
-			return certHash.GetOctets();
-		}
+        public byte[] GetCertHash() => Arrays.Clone(m_certHash.GetOctets());
 
-		public IssuerSerial IssuerSerial
-		{
-			get { return issuerSerial; }
-		}
+        public IssuerSerial IssuerSerial => m_issuerSerial;
 
 		/**
 		 * <pre>
@@ -81,9 +67,9 @@ namespace Org.BouncyCastle.Asn1.Ess
 		 */
 		public override Asn1Object ToAsn1Object()
 		{
-			Asn1EncodableVector v = new Asn1EncodableVector(certHash);
-            v.AddOptional(issuerSerial);
-			return new DerSequence(v);
+			return m_issuerSerial == null
+				?  new DerSequence(m_certHash)
+				:  new DerSequence(m_certHash, m_issuerSerial);
 		}
 	}
 }
diff --git a/crypto/src/asn1/ess/ESSCertIDv2.cs b/crypto/src/asn1/ess/ESSCertIDv2.cs
index b3d49ceb5..c1a37675a 100644
--- a/crypto/src/asn1/ess/ESSCertIDv2.cs
+++ b/crypto/src/asn1/ess/ESSCertIDv2.cs
@@ -9,10 +9,6 @@ namespace Org.BouncyCastle.Asn1.Ess
     public class EssCertIDv2
         : Asn1Encodable
     {
-        private readonly AlgorithmIdentifier hashAlgorithm;
-        private readonly byte[]              certHash;
-        private readonly IssuerSerial        issuerSerial;
-
         private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier(
             NistObjectIdentifiers.IdSha256);
 
@@ -20,37 +16,33 @@ namespace Org.BouncyCastle.Asn1.Ess
         {
             if (obj == null)
                 return null;
-            EssCertIDv2 existing = obj as EssCertIDv2;
-            if (existing != null)
-                return existing;
+            if (obj is EssCertIDv2 essCertIDv2)
+                return essCertIDv2;
             return new EssCertIDv2(Asn1Sequence.GetInstance(obj));
         }
 
-        private EssCertIDv2(
-            Asn1Sequence seq)
+        public static EssCertIDv2 GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
         {
-            if (seq.Count > 3)
-                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+            return new EssCertIDv2(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
 
-            int count = 0;
+        private readonly AlgorithmIdentifier m_hashAlgorithm;
+        private readonly Asn1OctetString m_certHash;
+        private readonly IssuerSerial m_issuerSerial;
 
-            if (seq[0] is Asn1OctetString)
-            {
-                // Default value
-                this.hashAlgorithm = DefaultAlgID;
-            }
-            else
-            {
-                this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object());
-            }
+        private EssCertIDv2(Asn1Sequence seq)
+        {
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets();
+            m_hashAlgorithm = Asn1Utilities.ReadOptional(seq, ref pos, AlgorithmIdentifier.GetOptional)
+                ?? DefaultAlgID;
+            m_certHash = Asn1OctetString.GetInstance(seq[pos++]);
+            m_issuerSerial = Asn1Utilities.ReadOptional(seq, ref pos, IssuerSerial.GetOptional);
 
-            if (seq.Count > count)
-            {
-                this.issuerSerial = IssuerSerial.GetInstance(
-                    Asn1Sequence.GetInstance(seq[count].ToAsn1Object()));
-            }
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
         }
 
         public EssCertIDv2(byte[] certHash)
@@ -58,53 +50,28 @@ namespace Org.BouncyCastle.Asn1.Ess
         {
         }
 
-        public EssCertIDv2(
-            AlgorithmIdentifier	algId,
-            byte[]				certHash)
+        public EssCertIDv2(AlgorithmIdentifier algId, byte[] certHash)
             : this(algId, certHash, null)
         {
         }
 
-        public EssCertIDv2(
-            byte[]              certHash,
-            IssuerSerial        issuerSerial)
+        public EssCertIDv2(byte[] certHash, IssuerSerial issuerSerial)
             : this(null, certHash, issuerSerial)
         {
         }
 
-        public EssCertIDv2(
-            AlgorithmIdentifier	algId,
-            byte[]				certHash,
-            IssuerSerial		issuerSerial)
+        public EssCertIDv2(AlgorithmIdentifier algId, byte[] certHash, IssuerSerial issuerSerial)
         {
-            if (algId == null)
-            {
-                // Default value
-                this.hashAlgorithm = DefaultAlgID;
-            }
-            else
-            {
-                this.hashAlgorithm = algId;
-            }
-
-            this.certHash = certHash;
-            this.issuerSerial = issuerSerial;
+            m_hashAlgorithm = algId ?? DefaultAlgID;
+            m_certHash = new DerOctetString(certHash);
+            m_issuerSerial = issuerSerial;
         }
 
-        public AlgorithmIdentifier HashAlgorithm
-        {
-            get { return this.hashAlgorithm; }
-        }
+        public AlgorithmIdentifier HashAlgorithm => m_hashAlgorithm;
 
-        public byte[] GetCertHash()
-        {
-            return Arrays.Clone(certHash);
-        }
+        public byte[] GetCertHash() => Arrays.Clone(m_certHash.GetOctets());
 
-        public IssuerSerial IssuerSerial
-        {
-            get { return issuerSerial; }
-        }
+        public IssuerSerial IssuerSerial => m_issuerSerial;
 
         /**
          * <pre>
@@ -126,16 +93,13 @@ namespace Org.BouncyCastle.Asn1.Ess
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(3);
-
-            if (!hashAlgorithm.Equals(DefaultAlgID))
+            if (!DefaultAlgID.Equals(m_hashAlgorithm))
             {
-                v.Add(hashAlgorithm);
+                v.Add(m_hashAlgorithm);
             }
-
-            v.Add(new DerOctetString(certHash).ToAsn1Object());
-            v.AddOptional(issuerSerial);
+            v.Add(m_certHash);
+            v.AddOptional(m_issuerSerial);
             return new DerSequence(v);
         }
-
     }
 }
diff --git a/crypto/src/asn1/ess/SigningCertificate.cs b/crypto/src/asn1/ess/SigningCertificate.cs
index ae263428e..1d7fb1d67 100644
--- a/crypto/src/asn1/ess/SigningCertificate.cs
+++ b/crypto/src/asn1/ess/SigningCertificate.cs
@@ -1,67 +1,55 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Ess
 {
-	public class SigningCertificate
+    public class SigningCertificate
 		: Asn1Encodable
 	{
-		private Asn1Sequence certs, policies;
-
-		public static SigningCertificate GetInstance(
-			object o)
-		{
-			if (o == null || o is SigningCertificate)
-			{
-				return (SigningCertificate) o;
-			}
+        public static SigningCertificate GetInstance(object o)
+        {
+            if (o == null)
+                return null;
+            if (o is SigningCertificate signingCertificate)
+                return signingCertificate;
+#pragma warning disable CS0618 // Type or member is obsolete
+            return new SigningCertificate(Asn1Sequence.GetInstance(o));
+#pragma warning restore CS0618 // Type or member is obsolete
+        }
 
-			if (o is Asn1Sequence)
-			{
-				return new SigningCertificate((Asn1Sequence) o);
-			}
+        public static SigningCertificate GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+#pragma warning disable CS0618 // Type or member is obsolete
+            return new SigningCertificate(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+#pragma warning restore CS0618 // Type or member is obsolete
+        }
 
-			throw new ArgumentException(
-				"unknown object in 'SigningCertificate' factory : "
-                + Platform.GetTypeName(o) + ".");
-		}
+        private readonly Asn1Sequence m_certs;
+        private readonly Asn1Sequence m_policies;
 
-		/**
-		 * constructors
-		 */
-		public SigningCertificate(
-			Asn1Sequence seq)
+        [Obsolete("Use 'GetInstance' instead")]
+        public SigningCertificate(Asn1Sequence seq)
 		{
-			if (seq.Count < 1 || seq.Count > 2)
-			{
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
-			}
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			this.certs = Asn1Sequence.GetInstance(seq[0]);
+            m_certs = Asn1Sequence.GetInstance(seq[pos++]);
+            m_policies = Asn1Utilities.ReadOptional(seq, ref pos, Asn1Sequence.GetOptional);
 
-			if (seq.Count > 1)
-			{
-				this.policies = Asn1Sequence.GetInstance(seq[1]);
-			}
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
-		public SigningCertificate(
-			EssCertID essCertID)
+		public SigningCertificate(EssCertID essCertID)
 		{
-			certs = new DerSequence(essCertID);
+			m_certs = new DerSequence(essCertID);
 		}
 
-        public EssCertID[] GetCerts()
-        {
-            return certs.MapElements(EssCertID.GetInstance);
-        }
+        public EssCertID[] GetCerts() => m_certs.MapElements(EssCertID.GetInstance);
 
-        public PolicyInformation[] GetPolicies()
-        {
-            return policies?.MapElements(PolicyInformation.GetInstance);
-        }
+        public PolicyInformation[] GetPolicies() => m_policies?.MapElements(PolicyInformation.GetInstance);
 
         /**
 		 * The definition of SigningCertificate is
@@ -76,10 +64,10 @@ namespace Org.BouncyCastle.Asn1.Ess
 		 *  smime(16) id-aa(2) 12 }
 		 */
         public override Asn1Object ToAsn1Object()
-		{
-			Asn1EncodableVector v = new Asn1EncodableVector(certs);
-            v.AddOptional(policies);
-			return new DerSequence(v);
-		}
-	}
+        {
+            return m_policies == null
+                ?  new DerSequence(m_certs)
+                :  new DerSequence(m_certs, m_policies);
+        }
+    }
 }
diff --git a/crypto/src/asn1/ess/SigningCertificateV2.cs b/crypto/src/asn1/ess/SigningCertificateV2.cs
index 557bede9c..c53a7c990 100644
--- a/crypto/src/asn1/ess/SigningCertificateV2.cs
+++ b/crypto/src/asn1/ess/SigningCertificateV2.cs
@@ -1,77 +1,61 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Ess
 {
     public class SigningCertificateV2
         : Asn1Encodable
     {
-        private readonly Asn1Sequence certs;
-        private readonly Asn1Sequence policies;
-
-        public static SigningCertificateV2 GetInstance(
-            object o)
+        public static SigningCertificateV2 GetInstance(object o)
         {
-            if (o == null || o is SigningCertificateV2)
-                return (SigningCertificateV2) o;
-
-            if (o is Asn1Sequence)
-                return new SigningCertificateV2((Asn1Sequence) o);
+            if (o == null)
+                return null;
+            if (o is SigningCertificateV2 signingCertificateV2)
+                return signingCertificateV2;
+            return new SigningCertificateV2(Asn1Sequence.GetInstance(o));
+        }
 
-            throw new ArgumentException(
-                "unknown object in 'SigningCertificateV2' factory : "
-                + Platform.GetTypeName(o) + ".");
+        public static SigningCertificateV2 GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new SigningCertificateV2(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
         }
 
-        private SigningCertificateV2(
-            Asn1Sequence seq)
+        private readonly Asn1Sequence m_certs;
+        private readonly Asn1Sequence m_policies;
+
+        private SigningCertificateV2(Asn1Sequence seq)
         {
-            if (seq.Count < 1 || seq.Count > 2)
-                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+            m_certs = Asn1Sequence.GetInstance(seq[pos++]);
+            m_policies = Asn1Utilities.ReadOptional(seq, ref pos, Asn1Sequence.GetOptional);
 
-            if (seq.Count > 1)
-            {
-                this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
-            }
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
         }
 
-        public SigningCertificateV2(
-            EssCertIDv2 cert)
+        public SigningCertificateV2(EssCertIDv2 cert)
         {
-            this.certs = new DerSequence(cert);
+            m_certs = new DerSequence(cert);
         }
 
-        public SigningCertificateV2(
-            EssCertIDv2[] certs)
+        public SigningCertificateV2(EssCertIDv2[] certs)
         {
-            this.certs = new DerSequence(certs);
+            m_certs = DerSequence.FromElements(certs);
         }
 
-        public SigningCertificateV2(
-            EssCertIDv2[]		certs,
-            PolicyInformation[]	policies)
+        public SigningCertificateV2(EssCertIDv2[] certs, PolicyInformation[] policies)
         {
-            this.certs = new DerSequence(certs);
-
-            if (policies != null)
-            {
-                this.policies = new DerSequence(policies);
-            }
+            m_certs = new DerSequence(certs);
+            m_policies = policies == null ? null : DerSequence.FromElements(policies);
         }
 
-        public EssCertIDv2[] GetCerts()
-        {
-            return certs.MapElements(EssCertIDv2.GetInstance);
-        }
+        public EssCertIDv2[] GetCerts() => m_certs.MapElements(EssCertIDv2.GetInstance);
 
-        public PolicyInformation[] GetPolicies()
-        {
-            return policies?.MapElements(PolicyInformation.GetInstance);
-        }
+        public PolicyInformation[] GetPolicies() => m_policies?.MapElements(PolicyInformation.GetInstance);
 
         /**
          * The definition of SigningCertificateV2 is
@@ -87,9 +71,9 @@ namespace Org.BouncyCastle.Asn1.Ess
          */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(certs);
-            v.AddOptional(policies);
-            return new DerSequence(v);
+            return m_policies == null
+                ?  new DerSequence(m_certs)
+                :  new DerSequence(m_certs, m_policies);
         }
     }
 }
diff --git a/crypto/src/asn1/x509/IssuerSerial.cs b/crypto/src/asn1/x509/IssuerSerial.cs
index 09b6dae18..8e7ba1fa6 100644
--- a/crypto/src/asn1/x509/IssuerSerial.cs
+++ b/crypto/src/asn1/x509/IssuerSerial.cs
@@ -19,6 +19,21 @@ namespace Org.BouncyCastle.Asn1.X509
             return new IssuerSerial(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
+        public static IssuerSerial GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is IssuerSerial issuerSerial)
+                return issuerSerial;
+
+            Asn1Sequence asn1Sequence = Asn1Sequence.GetOptional(element);
+            if (asn1Sequence != null)
+                return new IssuerSerial(asn1Sequence);
+
+            return null;
+        }
+
         private readonly GeneralNames issuer;
         private readonly DerInteger serial;
         private readonly DerBitString issuerUid;