summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/asn1/isismtt/ocsp/CertHash.cs83
-rw-r--r--crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs99
-rw-r--r--crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs54
-rw-r--r--crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs87
-rw-r--r--crypto/src/asn1/isismtt/x509/Admissions.cs125
-rw-r--r--crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs163
-rw-r--r--crypto/src/asn1/isismtt/x509/MonetaryLimit.cs87
-rw-r--r--crypto/src/asn1/isismtt/x509/NamingAuthority.cs153
-rw-r--r--crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs174
-rw-r--r--crypto/src/asn1/isismtt/x509/ProfessionInfo.cs304
-rw-r--r--crypto/src/asn1/isismtt/x509/Restriction.cs47
-rw-r--r--crypto/src/asn1/x500/DirectoryString.cs54
-rw-r--r--crypto/src/asn1/x509/GeneralName.cs63
-rw-r--r--crypto/src/asn1/x509/SubjectPublicKeyInfo.cs5
-rw-r--r--crypto/src/asn1/x509/Target.cs6
-rw-r--r--crypto/src/asn1/x509/X509CertificateStructure.cs128
16 files changed, 697 insertions, 935 deletions
diff --git a/crypto/src/asn1/isismtt/ocsp/CertHash.cs b/crypto/src/asn1/isismtt/ocsp/CertHash.cs
index be9fbd608..c5d223c15 100644
--- a/crypto/src/asn1/isismtt/ocsp/CertHash.cs
+++ b/crypto/src/asn1/isismtt/ocsp/CertHash.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 {
-	/**
+    /**
 	* ISIS-MTT PROFILE: The responder may include this extension in a response to
 	* send the hash of the requested certificate to the responder. This hash is
 	* cryptographically bound to the certificate and serves as evidence that the
@@ -25,29 +25,28 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 	*     }
 	* </pre>
 	*/
-	public class CertHash
+    public class CertHash
 		: Asn1Encodable
 	{
-		private readonly AlgorithmIdentifier	hashAlgorithm;
-		private readonly byte[]					certificateHash;
+        public static CertHash GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is CertHash certHash)
+                return certHash;
+            return new CertHash(Asn1Sequence.GetInstance(obj));
+        }
 
-		public static CertHash GetInstance(
-			object obj)
-		{
-			if (obj == null || obj is CertHash)
-			{
-				return (CertHash) obj;
-			}
+        public static CertHash GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new CertHash(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-			if (obj is Asn1Sequence)
-			{
-				return new CertHash((Asn1Sequence) obj);
-			}
+        public static CertHash GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new CertHash(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly AlgorithmIdentifier m_hashAlgorithm;
+        private readonly Asn1OctetString m_certificateHash;
 
-		/**
+        /**
 		* Constructor from Asn1Sequence.
 		* <p/>
 		* The sequence is of type CertHash:
@@ -61,44 +60,31 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 		*
 		* @param seq The ASN.1 sequence.
 		*/
-		private CertHash(
-			Asn1Sequence seq)
-		{
-			if (seq.Count != 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
+        private CertHash(Asn1Sequence seq)
+        {
+            int count = seq.Count;
+            if (count != 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
-			this.certificateHash = Asn1OctetString.GetInstance(seq[1]).GetOctets();
-		}
+            m_hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            m_certificateHash = Asn1OctetString.GetInstance(seq[1]);
+        }
 
-		/**
+        /**
 		* Constructor from a given details.
 		*
 		* @param hashAlgorithm   The hash algorithm identifier.
 		* @param certificateHash The hash of the whole DER encoding of the certificate.
 		*/
-		public CertHash(
-			AlgorithmIdentifier	hashAlgorithm,
-			byte[]				certificateHash)
-		{
-			if (hashAlgorithm == null)
-				throw new ArgumentNullException("hashAlgorithm");
-			if (certificateHash == null)
-				throw new ArgumentNullException("certificateHash");
-
-			this.hashAlgorithm = hashAlgorithm;
-			this.certificateHash = (byte[]) certificateHash.Clone();
+        public CertHash(AlgorithmIdentifier hashAlgorithm, byte[] certificateHash)
+        {
+			m_hashAlgorithm = hashAlgorithm ?? throw new ArgumentNullException(nameof(hashAlgorithm));
+			m_certificateHash = new DerOctetString(certificateHash);
 		}
 
-		public AlgorithmIdentifier HashAlgorithm
-		{
-			get { return hashAlgorithm; }
-		}
+		public AlgorithmIdentifier HashAlgorithm => m_hashAlgorithm;
 
-		public byte[] CertificateHash
-		{
-			get { return (byte[]) certificateHash.Clone(); }
-		}
+		public byte[] CertificateHash => Arrays.Clone(m_certificateHash.GetOctets());
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -114,9 +100,6 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 		*
 		* @return an Asn1Object
 		*/
-		public override Asn1Object ToAsn1Object()
-		{
-			return new DerSequence(hashAlgorithm, new DerOctetString(certificateHash));
-		}
+		public override Asn1Object ToAsn1Object() => new DerSequence(m_hashAlgorithm, m_certificateHash);
 	}
 }
diff --git a/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs b/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
index 7aaa9601c..98ac6c64d 100644
--- a/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
+++ b/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
@@ -2,11 +2,10 @@ using System;
 using System.IO;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 {
-	/**
+    /**
 	* ISIS-MTT-Optional: The certificate requested by the client by inserting the
 	* RetrieveIfAllowed extension in the request, will be returned in this
 	* extension.
@@ -39,7 +38,7 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 	*            }
 	* </pre>
 	*/
-	public class RequestedCertificate
+    public class RequestedCertificate
 		: Asn1Encodable, IAsn1Choice
 	{
 		public enum Choice
@@ -49,10 +48,6 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 			AttributeCertificate = 1
 		}
 
-		private readonly X509CertificateStructure	cert;
-		private readonly byte[]						publicKeyCert;
-		private readonly byte[]						attributeCert;
-
 		public static RequestedCertificate GetInstance(object obj)
 		{
 			if (obj == null)
@@ -61,13 +56,14 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 			if (obj is RequestedCertificate requestedCertificate)
 				return requestedCertificate;
 
-			if (obj is Asn1Sequence)
-				return new RequestedCertificate(X509CertificateStructure.GetInstance(obj));
-
-            if (obj is Asn1TaggedObject taggedObject)
-                return new RequestedCertificate(taggedObject);
+            if (obj is Asn1Encodable element)
+            {
+				var cert = X509CertificateStructure.GetOptional(element);
+				if (cert != null)
+					return new RequestedCertificate(cert);
+            }
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+            return new RequestedCertificate(Asn1TaggedObject.GetInstance(obj, Asn1Tags.ContextSpecific));
 		}
 
 		public static RequestedCertificate GetInstance(Asn1TaggedObject obj, bool isExplicit) =>
@@ -76,50 +72,50 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
         public static RequestedCertificate GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
             Asn1Utilities.GetTaggedChoice(taggedObject, declaredExplicit, GetInstance);
 
-		private RequestedCertificate(
-			Asn1TaggedObject tagged)
+        private readonly X509CertificateStructure m_cert;
+        private readonly Asn1OctetString m_publicKeyCert;
+        private readonly Asn1OctetString m_attributeCert;
+
+        private RequestedCertificate(Asn1TaggedObject tagged)
 		{
-			switch ((Choice) tagged.TagNo)
+			switch (tagged.TagNo)
 			{
-				case Choice.AttributeCertificate:
-					this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
-					break;
-				case Choice.PublicKeyCertificate:
-					this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
-					break;
-				default:
-					throw new ArgumentException("unknown tag number: " + tagged.TagNo);
+			case (int)Choice.AttributeCertificate:
+				m_attributeCert = Asn1OctetString.GetInstance(tagged, true);
+				break;
+			case (int)Choice.PublicKeyCertificate:
+				m_publicKeyCert = Asn1OctetString.GetInstance(tagged, true);
+				break;
+			default:
+				throw new ArgumentException("unknown tag number: " + tagged.TagNo);
 			}
 		}
 
-		/**
+        /**
 		* Constructor from a given details.
 		* <p/>
 		* Only one parameter can be given. All other must be <code>null</code>.
 		*
 		* @param certificate Given as Certificate
 		*/
-		public RequestedCertificate(
-			X509CertificateStructure certificate)
-		{
-			this.cert = certificate;
-		}
+        public RequestedCertificate(X509CertificateStructure certificate)
+        {
+            m_cert = certificate;
+        }
 
-		public RequestedCertificate(
-			Choice	type,
-			byte[]	certificateOctets)
-			: this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets)))
-		{
-		}
+        public RequestedCertificate(Choice type, byte[] certificateOctets)
+            : this(new DerTaggedObject((int)type, new DerOctetString(certificateOctets)))
+        {
+        }
 
-		public Choice Type
+        public Choice Type
 		{
 			get
 			{
-				if (cert != null)
+				if (m_cert != null)
 					return Choice.Certificate;
 
-				if (publicKeyCert != null)
+				if (m_publicKeyCert != null)
 					return Choice.PublicKeyCertificate;
 
 				return Choice.AttributeCertificate;
@@ -128,11 +124,11 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 
 		public byte[] GetCertificateBytes()
 		{
-			if (cert != null)
+			if (m_cert != null)
 			{
 				try
 				{
-					return cert.GetEncoded();
+					return m_cert.GetEncoded();
 				}
 				catch (IOException e)
 				{
@@ -140,12 +136,11 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 				}
 			}
 
-			if (publicKeyCert != null)
-				return publicKeyCert;
+			if (m_publicKeyCert != null)
+				return m_publicKeyCert.GetOctets();
 
-			return attributeCert;
+			return m_attributeCert.GetOctets();
 		}
-    
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -164,17 +159,13 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
 		*/
 		public override Asn1Object ToAsn1Object()
 		{
-			if (publicKeyCert != null)
-			{
-				return new DerTaggedObject(0, new DerOctetString(publicKeyCert));
-			}
+			if (m_publicKeyCert != null)
+				return new DerTaggedObject(0, m_publicKeyCert);
 
-			if (attributeCert != null)
-			{
-				return new DerTaggedObject(1, new DerOctetString(attributeCert));
-			}
+			if (m_attributeCert != null)
+				return new DerTaggedObject(1, m_attributeCert);
 
-			return cert.ToAsn1Object();
+			return m_cert.ToAsn1Object();
 		}
 	}
 }
diff --git a/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs b/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
index 53a8e98a7..84ee87f3b 100644
--- a/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
+++ b/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
@@ -1,11 +1,8 @@
-using System;
-
 using Org.BouncyCastle.Asn1.X500;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* Some other information of non-restrictive nature regarding the usage of this
 	* certificate.
 	* 
@@ -13,44 +10,44 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	*    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
 	* </pre>
 	*/
-	public class AdditionalInformationSyntax
+    public class AdditionalInformationSyntax
 		: Asn1Encodable
 	{
-		private readonly DirectoryString information;
+        public static AdditionalInformationSyntax GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is AdditionalInformationSyntax additionalInformationSyntax)
+                return additionalInformationSyntax;
+            return new AdditionalInformationSyntax(DirectoryString.GetInstance(obj));
+        }
 
-		public static AdditionalInformationSyntax GetInstance(
-			object obj)
-		{
-			if (obj is AdditionalInformationSyntax)
-				return (AdditionalInformationSyntax) obj;
+        public static AdditionalInformationSyntax GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new AdditionalInformationSyntax(DirectoryString.GetInstance(taggedObject, declaredExplicit));
 
-			if (obj is IAsn1String)
-				return new AdditionalInformationSyntax(DirectoryString.GetInstance(obj));
+        public static AdditionalInformationSyntax GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new AdditionalInformationSyntax(DirectoryString.GetTagged(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly DirectoryString m_information;
 
-		private AdditionalInformationSyntax(
-			DirectoryString information)
+        private AdditionalInformationSyntax(DirectoryString information)
 		{
-			this.information = information;
+            // TODO Length constraint?
+            m_information = information;
 		}
 
 		/**
 		* Constructor from a given details.
 		*
-		* @param information The describtion of the information.
+		* @param information The description of the information.
 		*/
-		public AdditionalInformationSyntax(
-			string information)
+		public AdditionalInformationSyntax(string information)
 		{
-			this.information = new DirectoryString(information);
+            // TODO Length constraint?
+            m_information = new DirectoryString(information);
 		}
 
-		public virtual DirectoryString Information
-		{
-			get { return information; }
-		}
+		public virtual DirectoryString Information => m_information;
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -63,9 +60,6 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @return an Asn1Object
 		*/
-		public override Asn1Object ToAsn1Object()
-		{
-			return information.ToAsn1Object();
-		}
+		public override Asn1Object ToAsn1Object() => m_information.ToAsn1Object();
 	}
 }
diff --git a/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs b/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
index d7f4779d6..5df8e27c6 100644
--- a/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
+++ b/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
@@ -115,24 +114,23 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
     public class AdmissionSyntax
         : Asn1Encodable
     {
-        private readonly GeneralName admissionAuthority;
-        private readonly Asn1Sequence contentsOfAdmissions;
-
-        public static AdmissionSyntax GetInstance(
-            object obj)
+        public static AdmissionSyntax GetInstance(object obj)
         {
-            if (obj == null || obj is AdmissionSyntax)
-            {
-                return (AdmissionSyntax)obj;
-            }
+            if (obj == null)
+                return null;
+            if (obj is AdmissionSyntax admissionSyntax)
+                return admissionSyntax;
+            return new AdmissionSyntax(Asn1Sequence.GetInstance(obj));
+        }
 
-            if (obj is Asn1Sequence)
-            {
-                return new AdmissionSyntax((Asn1Sequence)obj);
-            }
+        public static AdmissionSyntax GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new AdmissionSyntax(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-        }
+        public static AdmissionSyntax GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new AdmissionSyntax(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
+
+        private readonly GeneralName m_admissionAuthority;
+        private readonly Asn1Sequence m_contentsOfAdmissions;
 
         /**
         * Constructor from Asn1Sequence.
@@ -174,18 +172,15 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
         */
         private AdmissionSyntax(Asn1Sequence seq)
         {
-            switch (seq.Count)
-            {
-            case 1:
-                this.contentsOfAdmissions = Asn1Sequence.GetInstance(seq[0]);
-                break;
-            case 2:
-                admissionAuthority = GeneralName.GetInstance(seq[0]);
-                contentsOfAdmissions = Asn1Sequence.GetInstance(seq[1]);
-                break;
-            default:
-                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));
+
+            m_admissionAuthority = Asn1Utilities.ReadOptional(seq, ref pos, GeneralName.GetOptional);
+            m_contentsOfAdmissions = Asn1Sequence.GetInstance(seq[pos++]);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
         }
 
         /**
@@ -194,14 +189,17 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
         * @param admissionAuthority   The admission authority.
         * @param contentsOfAdmissions The admissions.
         */
-        public AdmissionSyntax(
-            GeneralName admissionAuthority,
-            Asn1Sequence contentsOfAdmissions)
+        public AdmissionSyntax(GeneralName admissionAuthority, Asn1Sequence contentsOfAdmissions)
         {
-            this.admissionAuthority = admissionAuthority;
-            this.contentsOfAdmissions = contentsOfAdmissions;
+            m_admissionAuthority = admissionAuthority;
+            m_contentsOfAdmissions = contentsOfAdmissions ?? throw new ArgumentNullException(nameof(contentsOfAdmissions));
         }
 
+        public virtual GeneralName AdmissionAuthority => m_admissionAuthority;
+
+        public virtual Admissions[] GetContentsOfAdmissions() =>
+            m_contentsOfAdmissions.MapElements(Admissions.GetInstance);
+
         /**
         * Produce an object suitable for an Asn1OutputStream.
         * <p/>
@@ -242,26 +240,9 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
         */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(2);
-            v.AddOptional(admissionAuthority);
-            v.Add(contentsOfAdmissions);
-            return new DerSequence(v);
-        }
-
-        /**
-        * @return Returns the admissionAuthority if present, null otherwise.
-        */
-        public virtual GeneralName AdmissionAuthority
-        {
-            get { return admissionAuthority; }
-        }
-
-        /**
-        * @return Returns the contentsOfAdmissions.
-        */
-        public virtual Admissions[] GetContentsOfAdmissions()
-        {
-            return contentsOfAdmissions.MapElements(Admissions.GetInstance);
+            return m_admissionAuthority == null
+                ?  new DerSequence(m_contentsOfAdmissions)
+                :  new DerSequence(m_admissionAuthority, m_contentsOfAdmissions);
         }
     }
 }
diff --git a/crypto/src/asn1/isismtt/x509/Admissions.cs b/crypto/src/asn1/isismtt/x509/Admissions.cs
index 57c5a6183..0ea209a35 100644
--- a/crypto/src/asn1/isismtt/x509/Admissions.cs
+++ b/crypto/src/asn1/isismtt/x509/Admissions.cs
@@ -1,11 +1,10 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* An Admissions structure.
 	* <p/>
 	* <pre>
@@ -22,25 +21,29 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
 	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
 	*/
-	public class Admissions
+    public class Admissions
 		: Asn1Encodable
 	{
-		private readonly GeneralName		admissionAuthority;
-		private readonly NamingAuthority	namingAuthority;
-		private readonly Asn1Sequence		professionInfos;
-
 		public static Admissions GetInstance(object obj)
 		{
-			if (obj == null || obj is Admissions)
-				return (Admissions)obj;
+			if (obj == null)
+				return null;
+			if (obj is Admissions admissions)
+				return admissions;
+			return new Admissions(Asn1Sequence.GetInstance(obj));
+		}
 
-			if (obj is Asn1Sequence seq)
-				return new Admissions(seq);
+        public static Admissions GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Admissions(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        public static Admissions GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Admissions(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-		/**
+        private readonly GeneralName m_admissionAuthority;
+        private readonly NamingAuthority m_namingAuthority;
+        private readonly Asn1Sequence m_professionInfos;
+
+        /**
 		* Constructor from Asn1Sequence.
 		* <p/>
 		* The sequence is of type ProcurationSyntax:
@@ -56,52 +59,21 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @param seq The ASN.1 sequence.
 		*/
-		private Admissions(Asn1Sequence seq)
+        private Admissions(Asn1Sequence seq)
 		{
-			if (seq.Count > 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			var e = seq.GetEnumerator();
+			m_admissionAuthority = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, true, GeneralName.GetTagged);
+            m_namingAuthority = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 1, true, NamingAuthority.GetTagged);
+			m_professionInfos = Asn1Sequence.GetInstance(seq[pos++]);
 
-			e.MoveNext();
-			Asn1Encodable o = e.Current;
-			if (o is Asn1TaggedObject tagged1)
-			{
-				switch (tagged1.TagNo)
-				{
-				case 0:
-					admissionAuthority = GeneralName.GetInstance(tagged1, true);
-					break;
-				case 1:
-					namingAuthority = NamingAuthority.GetInstance(tagged1, true);
-					break;
-				default:
-					throw new ArgumentException("Bad tag number: " + tagged1.TagNo);
-				}
-				e.MoveNext();
-				o = e.Current;
-			}
-			if (o is Asn1TaggedObject tagged2)
-			{
-				switch (tagged2.TagNo)
-				{
-				case 1:
-					namingAuthority = NamingAuthority.GetInstance(tagged2, true);
-					break;
-				default:
-					throw new ArgumentException("Bad tag number: " + tagged2.TagNo);
-				}
-				e.MoveNext();
-				o = e.Current;
-			}
-			professionInfos = Asn1Sequence.GetInstance(o);
-			if (e.MoveNext())
-			{
-                throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(e.Current));
-			}
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
-		/**
+        /**
 		* Constructor from a given details.
 		* <p/>
 		* Parameter <code>professionInfos</code> is mandatory.
@@ -110,36 +82,19 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		* @param namingAuthority    The naming authority.
 		* @param professionInfos    The profession infos.
 		*/
-		public Admissions(
-			GeneralName			admissionAuthority,
-			NamingAuthority		namingAuthority,
-			ProfessionInfo[]	professionInfos)
-		{
-			this.admissionAuthority = admissionAuthority;
-			this.namingAuthority = namingAuthority;
-			this.professionInfos = new DerSequence(professionInfos);
-		}
+        public Admissions(GeneralName admissionAuthority, NamingAuthority namingAuthority,
+			ProfessionInfo[] professionInfos)
+        {
+            m_admissionAuthority = admissionAuthority;
+            m_namingAuthority = namingAuthority;
+            m_professionInfos = DerSequence.FromElements(professionInfos);
+        }
 
-		public virtual GeneralName AdmissionAuthority
-		{
-			get { return admissionAuthority; }
-		}
+		public virtual GeneralName AdmissionAuthority => m_admissionAuthority;
 
-		public virtual NamingAuthority NamingAuthority
-		{
-			get { return namingAuthority; }
-		}
+		public virtual NamingAuthority NamingAuthority => m_namingAuthority;
 
-		public ProfessionInfo[] GetProfessionInfos()
-		{
-			ProfessionInfo[] infos = new ProfessionInfo[professionInfos.Count];
-			int count = 0;
-			foreach (Asn1Encodable ae in professionInfos)
-			{
-				infos[count++] = ProfessionInfo.GetInstance(ae);
-			}
-			return infos;
-		}
+		public ProfessionInfo[] GetProfessionInfos() => m_professionInfos.MapElements(ProfessionInfo.GetInstance);
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -161,9 +116,9 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		public override Asn1Object ToAsn1Object()
 		{
 			Asn1EncodableVector v = new Asn1EncodableVector(3);
-            v.AddOptionalTagged(true, 0, admissionAuthority);
-            v.AddOptionalTagged(true, 1, namingAuthority);
-			v.Add(professionInfos);
+            v.AddOptionalTagged(true, 0, m_admissionAuthority);
+            v.AddOptionalTagged(true, 1, m_namingAuthority);
+			v.Add(m_professionInfos);
 			return new DerSequence(v);
 		}
 	}
diff --git a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
index 645d9bd28..5db3df9e7 100644
--- a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
+++ b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
@@ -4,7 +4,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* A declaration of majority.
 	* <p/>
 	* <pre>
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	* fullAgeAtCountry indicates the majority of the owner with respect to the laws
 	* of a specific country.
 	*/
-	public class DeclarationOfMajority
+    public class DeclarationOfMajority
 		: Asn1Encodable, IAsn1Choice
 	{
 		public enum Choice
@@ -33,16 +33,81 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 			DateOfBirth = 2
 		};
 
-		private readonly Asn1TaggedObject m_declaration;
+        public static DeclarationOfMajority GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
 
-		public DeclarationOfMajority(int notYoungerThan)
+            if (obj is Asn1Encodable element)
+            {
+                var result = GetOptional(element);
+                if (result != null)
+                    return result;
+            }
+
+            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), nameof(obj));
+        }
+
+        public static DeclarationOfMajority GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            Asn1Utilities.GetInstanceChoice(taggedObject, declaredExplicit, GetInstance);
+
+        public static DeclarationOfMajority GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DeclarationOfMajority declarationOfMajority)
+                return declarationOfMajority;
+
+            if (element is Asn1TaggedObject taggedObject)
+            {
+                Asn1Encodable baseObject = GetOptionalBaseObject(taggedObject);
+                if (baseObject != null)
+                    return new DeclarationOfMajority(taggedObject.TagNo, baseObject);
+            }
+
+            return null;
+        }
+
+        public static DeclarationOfMajority GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            Asn1Utilities.GetTaggedChoice(taggedObject, declaredExplicit, GetInstance);
+
+        private static Asn1Encodable GetOptionalBaseObject(Asn1TaggedObject taggedObject)
+        {
+			if (taggedObject.HasContextTag())
+			{
+				switch (taggedObject.TagNo)
+				{
+				case (int)Choice.NotYoungerThan:
+                    return DerInteger.GetInstance(taggedObject, false);
+				case (int)Choice.FullAgeAtCountry:
+					return Asn1Sequence.GetInstance(taggedObject, false);
+				case (int)Choice.DateOfBirth:
+					return Asn1GeneralizedTime.GetInstance(taggedObject, false);
+				}
+            }
+
+            return null;
+        }
+
+        private readonly int m_tag;
+        private readonly Asn1Encodable m_baseObject;
+
+        private DeclarationOfMajority(int tag, Asn1Encodable baseObject)
+        {
+            m_tag = tag;
+            m_baseObject = baseObject;
+        }
+
+        public DeclarationOfMajority(int notYoungerThan)
 		{
-			m_declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan));
+			m_tag = (int)Choice.NotYoungerThan;
+			m_baseObject = new DerInteger(notYoungerThan);
 		}
 
 		public DeclarationOfMajority(bool fullAge, string country)
 		{
-			if (country.Length > 2)
+			if (country.Length != 2)
 				throw new ArgumentException("country can only be 2 characters", nameof(country));
 
 			DerPrintableString countryString = new DerPrintableString(country, true);
@@ -57,65 +122,17 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				seq = new DerSequence(DerBoolean.False, countryString);
 			}
 
-			m_declaration = new DerTaggedObject(false, 1, seq);
+			m_tag = (int)Choice.FullAgeAtCountry;
+			m_baseObject = seq;
 		}
 
 		public DeclarationOfMajority(Asn1GeneralizedTime dateOfBirth)
 		{
-			m_declaration = new DerTaggedObject(false, 2, dateOfBirth);
-		}
-
-		public static DeclarationOfMajority GetInstance(object obj)
-		{
-			if (obj == null)
-				return null;
-
-			if (obj is DeclarationOfMajority declarationOfMajority)
-				return declarationOfMajority;
-
-			if (obj is Asn1TaggedObject taggedObject)
-				return new DeclarationOfMajority(Asn1Utilities.CheckContextTagClass(taggedObject));
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), nameof(obj));
+			m_tag = (int)Choice.DateOfBirth;
+			m_baseObject = dateOfBirth ?? throw new ArgumentNullException(nameof(dateOfBirth));
 		}
 
-		private DeclarationOfMajority(Asn1TaggedObject o)
-		{
-			if (o.TagNo > 2)
-				throw new ArgumentException("Bad tag number: " + o.TagNo);
-
-			m_declaration = o;
-		}
-
-		/**
-		* Produce an object suitable for an Asn1OutputStream.
-		* <p/>
-		* Returns:
-		* <p/>
-		* <pre>
-		*           DeclarationOfMajoritySyntax ::= CHOICE
-		*           {
-		*             notYoungerThan [0] IMPLICIT INTEGER,
-		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
-		*             {
-		*               fullAge BOOLEAN DEFAULT TRUE,
-		*               country PrintableString (SIZE(2))
-		*             }
-		*             dateOfBirth [2] IMPLICIT GeneralizedTime
-		*           }
-		* </pre>
-		*
-		* @return an Asn1Object
-		*/
-		public override Asn1Object ToAsn1Object()
-		{
-			return m_declaration;
-		}
-
-		public Choice Type
-		{
-			get { return (Choice)m_declaration.TagNo; }
-		}
+		public Choice Type => (Choice)m_tag;
 
 		/**
 		* @return notYoungerThan if that's what we are, -1 otherwise
@@ -127,7 +144,7 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				switch (Type)
 				{
 				case Choice.NotYoungerThan:
-                    return DerInteger.GetInstance(m_declaration, false).IntValueExact;
+                    return DerInteger.GetInstance(m_baseObject).IntValueExact;
 				default:
 					return -1;
 				}
@@ -141,7 +158,7 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				switch (Type)
 				{
 				case Choice.FullAgeAtCountry:
-					return Asn1Sequence.GetInstance(m_declaration, false);
+					return Asn1Sequence.GetInstance(m_baseObject);
 				default:
 					return null;
 				}
@@ -155,11 +172,33 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				switch (Type)
 				{
 				case Choice.DateOfBirth:
-					return Asn1GeneralizedTime.GetInstance(m_declaration, false);
+					return Asn1GeneralizedTime.GetInstance(m_baseObject);
 				default:
 					return null;
 				}
 			}
 		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*           DeclarationOfMajoritySyntax ::= CHOICE
+		*           {
+		*             notYoungerThan [0] IMPLICIT INTEGER,
+		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+		*             {
+		*               fullAge BOOLEAN DEFAULT TRUE,
+		*               country PrintableString (SIZE(2))
+		*             }
+		*             dateOfBirth [2] IMPLICIT GeneralizedTime
+		*           }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object() => new DerTaggedObject(false, m_tag, m_baseObject);
 	}
 }
diff --git a/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs b/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
index b792fffda..42a4a3164 100644
--- a/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
+++ b/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
@@ -1,11 +1,10 @@
 using System;
 
 using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST be
 	* used in new certificates in place of the extension/attribute MonetaryLimit
 	* since January 1, 2004. For the sake of backward compatibility with
@@ -29,41 +28,40 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	* <p/>
 	* value = amount�10*exponent
 	*/
-	public class MonetaryLimit
+    public class MonetaryLimit
 		: Asn1Encodable
 	{
-		private readonly DerPrintableString	currency;
-		private readonly DerInteger			amount;
-		private readonly DerInteger			exponent;
+        public static MonetaryLimit GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is MonetaryLimit monetaryLimit)
+                return monetaryLimit;
+            return new MonetaryLimit(Asn1Sequence.GetInstance(obj));
+        }
 
-		public static MonetaryLimit GetInstance(
-			object obj)
-		{
-			if (obj == null || obj is MonetaryLimit)
-			{
-				return (MonetaryLimit) obj;
-			}
+        public static MonetaryLimit GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new MonetaryLimit(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-			if (obj is Asn1Sequence)
-			{
-				return new MonetaryLimit(Asn1Sequence.GetInstance(obj));
-			}
+        public static MonetaryLimit GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new MonetaryLimit(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly DerPrintableString m_currency;
+        private readonly DerInteger m_amount;
+        private readonly DerInteger m_exponent;
 
-		private MonetaryLimit(
-			Asn1Sequence seq)
+        private MonetaryLimit(Asn1Sequence seq)
 		{
-			if (seq.Count != 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
+            int count = seq.Count;
+            if (count != 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			currency = DerPrintableString.GetInstance(seq[0]);
-			amount = DerInteger.GetInstance(seq[1]);
-			exponent = DerInteger.GetInstance(seq[2]);
+			m_currency = DerPrintableString.GetInstance(seq[0]);
+			m_amount = DerInteger.GetInstance(seq[1]);
+			m_exponent = DerInteger.GetInstance(seq[2]);
 		}
 
-		/**
+        /**
 		* Constructor from a given details.
 		* <p/>
 		* <p/>
@@ -73,30 +71,18 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		* @param amount   The amount
 		* @param exponent The exponent
 		*/
-		public MonetaryLimit(
-			string	currency,
-			int		amount,
-			int		exponent)
-		{
-			this.currency = new DerPrintableString(currency, true);
-			this.amount = new DerInteger(amount);
-			this.exponent = new DerInteger(exponent);
-		}
+        public MonetaryLimit(string currency, int amount, int exponent)
+        {
+            m_currency = new DerPrintableString(currency, true);
+            m_amount = new DerInteger(amount);
+            m_exponent = new DerInteger(exponent);
+        }
 
-		public virtual string Currency
-		{
-			get { return currency.GetString(); }
-		}
+		public virtual string Currency => m_currency.GetString();
 
-		public virtual BigInteger Amount
-		{
-			get { return amount.Value; }
-		}
+		public virtual BigInteger Amount => m_amount.Value;
 
-		public virtual BigInteger Exponent
-		{
-			get { return exponent.Value; }
-		}
+		public virtual BigInteger Exponent => m_exponent.Value;
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -114,9 +100,6 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @return an Asn1Object
 		*/
-		public override Asn1Object ToAsn1Object()
-		{
-			return new DerSequence(currency, amount, exponent);
-		}
+		public override Asn1Object ToAsn1Object() => new DerSequence(m_currency, m_amount, m_exponent);
 	}
 }
diff --git a/crypto/src/asn1/isismtt/x509/NamingAuthority.cs b/crypto/src/asn1/isismtt/x509/NamingAuthority.cs
index 3c3f0a5f5..d247c1188 100644
--- a/crypto/src/asn1/isismtt/x509/NamingAuthority.cs
+++ b/crypto/src/asn1/isismtt/x509/NamingAuthority.cs
@@ -1,11 +1,10 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X500;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* Names of authorities which are responsible for the administration of title
 	* registers.
 	* 
@@ -20,7 +19,7 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
 	* 
 	*/
-	public class NamingAuthority
+    public class NamingAuthority
 		: Asn1Encodable
 	{
 		/**
@@ -29,30 +28,29 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		* �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the
 		* first naming authority under the OID id-isismtt-at-namingAuthorities.
 		*/
-		public static readonly DerObjectIdentifier IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern
-			= new DerObjectIdentifier(IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities + ".1");
-
-		private readonly DerObjectIdentifier	namingAuthorityID;
-		private readonly string					namingAuthorityUrl;
-		private readonly DirectoryString		namingAuthorityText;
+		public static readonly DerObjectIdentifier IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern =
+			IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities.Branch("1");
 
 		public static NamingAuthority GetInstance(object obj)
 		{
-			if (obj == null || obj is NamingAuthority)
-				return (NamingAuthority) obj;
+            if (obj == null)
+                return null;
+            if (obj is NamingAuthority namingAuthority)
+                return namingAuthority;
+            return new NamingAuthority(Asn1Sequence.GetInstance(obj));
+		}
 
-			if (obj is Asn1Sequence seq)
-				return new NamingAuthority(seq);
+		public static NamingAuthority GetInstance(Asn1TaggedObject obj, bool isExplicit) =>
+			new NamingAuthority(Asn1Sequence.GetInstance(obj, isExplicit));
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        public static NamingAuthority GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new NamingAuthority(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-		public static NamingAuthority GetInstance(Asn1TaggedObject obj, bool isExplicit)
-		{
-			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
-		}
+        private readonly DerObjectIdentifier m_namingAuthorityID;
+        private readonly DerIA5String m_namingAuthorityUrl;
+        private readonly DirectoryString m_namingAuthorityText;
 
-		/**
+        /**
 		* Constructor from Asn1Sequence.
 		* <p/>
 		* <p/>
@@ -67,90 +65,38 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @param seq The ASN.1 sequence.
 		*/
-		private NamingAuthority(Asn1Sequence seq)
+        private NamingAuthority(Asn1Sequence seq)
 		{
-			if (seq.Count > 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
+            int count = seq.Count, pos = 0;
+            if (count < 0 || count > 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			var e = seq.GetEnumerator();
+			m_namingAuthorityID = Asn1Utilities.ReadOptional(seq, ref pos, DerObjectIdentifier.GetOptional);
+            m_namingAuthorityUrl = Asn1Utilities.ReadOptional(seq, ref pos, DerIA5String.GetOptional);
+            m_namingAuthorityText = Asn1Utilities.ReadOptional(seq, ref pos, DirectoryString.GetOptional);
 
-			if (e.MoveNext())
-			{
-				Asn1Encodable o = e.Current;
-				if (o is DerObjectIdentifier oid)
-				{
-					namingAuthorityID = oid;
-				}
-				else if (o is DerIA5String ia5)
-				{
-					namingAuthorityUrl = ia5.GetString();
-				}
-				else if (o is IAsn1String)
-				{
-					namingAuthorityText = DirectoryString.GetInstance(o);
-				}
-				else
-				{
-                    throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
-				}
-			}
-
-			if (e.MoveNext())
-			{
-				Asn1Encodable o = e.Current;
-				if (o is DerIA5String ia5)
-				{
-					namingAuthorityUrl = ia5.GetString();
-				}
-				else if (o is IAsn1String)
-				{
-					namingAuthorityText = DirectoryString.GetInstance(o);
-				}
-				else
-				{
-                    throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
-				}
-			}
-
-			if (e.MoveNext())
-			{
-				Asn1Encodable o = e.Current;
-				if (o is IAsn1String)
-				{
-					namingAuthorityText = DirectoryString.GetInstance(o);
-				}
-				else
-				{
-                    throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
-				}
-			}
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
 		/**
 		* @return Returns the namingAuthorityID.
 		*/
-		public virtual DerObjectIdentifier NamingAuthorityID
-		{
-			get { return namingAuthorityID; }
-		}
+		public virtual DerObjectIdentifier NamingAuthorityID => m_namingAuthorityID;
 
 		/**
 		* @return Returns the namingAuthorityText.
 		*/
-		public virtual DirectoryString NamingAuthorityText
-		{
-			get { return namingAuthorityText; }
-		}
+		public virtual DirectoryString NamingAuthorityText => m_namingAuthorityText;
 
 		/**
 		* @return Returns the namingAuthorityUrl.
 		*/
-		public virtual string NamingAuthorityUrl
-		{
-			get { return namingAuthorityUrl; }
-		}
+		public virtual string NamingAuthorityUrl => m_namingAuthorityUrl?.GetString();
 
-		/**
+        public virtual DerIA5String NamingAuthorityUrlData => m_namingAuthorityUrl;
+
+        /**
 		* Constructor from given details.
 		* <p/>
 		* All parameters can be combined.
@@ -159,17 +105,15 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		* @param namingAuthorityUrl  URL for naming authority.
 		* @param namingAuthorityText Textual representation of naming authority.
 		*/
-		public NamingAuthority(
-			DerObjectIdentifier	namingAuthorityID,
-			string				namingAuthorityUrl,
-			DirectoryString		namingAuthorityText)
-		{
-			this.namingAuthorityID = namingAuthorityID;
-			this.namingAuthorityUrl = namingAuthorityUrl;
-			this.namingAuthorityText = namingAuthorityText;
-		}
-
-		/**
+        public NamingAuthority(DerObjectIdentifier namingAuthorityID, string namingAuthorityUrl,
+			DirectoryString namingAuthorityText)
+        {
+            m_namingAuthorityID = namingAuthorityID;
+            m_namingAuthorityUrl = namingAuthorityUrl == null ? null : new DerIA5String(namingAuthorityUrl, true);
+            m_namingAuthorityText = namingAuthorityText;
+        }
+
+        /**
 		* Produce an object suitable for an Asn1OutputStream.
 		* <p/>
 		* Returns:
@@ -185,17 +129,12 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @return an Asn1Object
 		*/
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
 		{
 			Asn1EncodableVector v = new Asn1EncodableVector(3);
-            v.AddOptional(namingAuthorityID);
-
-			if (namingAuthorityUrl != null)
-			{
-				v.Add(new DerIA5String(namingAuthorityUrl, true));
-			}
-
-            v.AddOptional(namingAuthorityText);
+            v.AddOptional(m_namingAuthorityID);
+            v.AddOptional(m_namingAuthorityUrl);
+            v.AddOptional(m_namingAuthorityText);
 			return new DerSequence(v);
 		}
 	}
diff --git a/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs b/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
index 96047f9bd..4b5a4693a 100644
--- a/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
+++ b/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 
 using Org.BouncyCastle.Asn1.X500;
 using Org.BouncyCastle.Asn1.X509;
@@ -6,7 +7,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* Attribute to indicate that the certificate holder may sign in the name of a
 	* third person.
 	* <p>
@@ -40,26 +41,29 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	* </pre>
 	* 
 	*/
-	public class ProcurationSyntax
+    public class ProcurationSyntax
 		: Asn1Encodable
 	{
-		private readonly string				country;
-		private readonly DirectoryString	typeOfSubstitution;
-		private readonly GeneralName		thirdPerson;
-		private readonly IssuerSerial		certRef;
-
-		public static ProcurationSyntax GetInstance(object obj)
-		{
-			if (obj == null || obj is ProcurationSyntax)
-				return (ProcurationSyntax) obj;
-
-			if (obj is Asn1Sequence seq)
-				return new ProcurationSyntax(seq);
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
-
-		/**
+        public static ProcurationSyntax GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is ProcurationSyntax procurationSyntax)
+                return procurationSyntax;
+            return new ProcurationSyntax(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static ProcurationSyntax GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ProcurationSyntax(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static ProcurationSyntax GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ProcurationSyntax(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
+
+        private readonly DerPrintableString m_country;
+        private readonly DirectoryString m_typeOfSubstitution;
+		private readonly Asn1Encodable m_signingFor;
+
+        /**
 		* Constructor from Asn1Sequence.
 		* <p/>
 		* The sequence is of type ProcurationSyntax:
@@ -80,40 +84,21 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @param seq The ASN.1 sequence.
 		*/
-		private ProcurationSyntax(Asn1Sequence seq)
+        private ProcurationSyntax(Asn1Sequence seq)
 		{
-			if (seq.Count < 1 || seq.Count > 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
-
-			foreach (var element in seq)
-			{
-				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(element, Asn1Tags.ContextSpecific);
-				switch (o.TagNo)
-				{
-				case 1:
-					country = DerPrintableString.GetInstance(o, true).GetString();
-					break;
-				case 2:
-					typeOfSubstitution = DirectoryString.GetInstance(o, true);
-					break;
-				case 3:
-					Asn1Encodable signingFor = o.GetExplicitBaseObject();
-					if (signingFor is Asn1TaggedObject)
-					{
-						thirdPerson = GeneralName.GetInstance(signingFor);
-					}
-					else
-					{
-						certRef = IssuerSerial.GetInstance(signingFor);
-					}
-					break;
-				default:
-					throw new ArgumentException("Bad tag number: " + o.TagNo);
-				}
-			}
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+			m_country = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 1, true, DerPrintableString.GetTagged);
+            m_typeOfSubstitution = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 2, true, DirectoryString.GetTagged);
+            m_signingFor = Asn1Utilities.ReadContextTagged(seq, ref pos, 3, true, GetTaggedSigningFor);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
-		/**
+        /**
 		* Constructor from a given details.
 		* <p/>
 		* <p/>
@@ -124,18 +109,14 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		* @param typeOfSubstitution The type of procuration.
 		* @param certRef            Reference to certificate of the person who is represented.
 		*/
-		public ProcurationSyntax(
-			string			country,
-			DirectoryString	typeOfSubstitution,
-			IssuerSerial	certRef)
-		{
-			this.country = country;
-			this.typeOfSubstitution = typeOfSubstitution;
-			this.thirdPerson = null;
-			this.certRef = certRef;
+        public ProcurationSyntax(string country, DirectoryString typeOfSubstitution, IssuerSerial certRef)
+        {
+            m_country = country == null ? null : new DerPrintableString(country, true);
+			m_typeOfSubstitution = typeOfSubstitution;
+			m_signingFor = certRef ?? throw new ArgumentNullException(nameof(certRef));
 		}
 
-		/**
+        /**
 		 * Constructor from a given details.
 		 * <p/>
 		 * <p/>
@@ -146,36 +127,20 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		 * @param typeOfSubstitution The type of procuration.
 		 * @param thirdPerson        The GeneralName of the person who is represented.
 		 */
-		public ProcurationSyntax(
-			string			country,
-			DirectoryString	typeOfSubstitution,
-			GeneralName		thirdPerson)
-		{
-			this.country = country;
-			this.typeOfSubstitution = typeOfSubstitution;
-			this.thirdPerson = thirdPerson;
-			this.certRef = null;
+        public ProcurationSyntax(string country, DirectoryString typeOfSubstitution, GeneralName thirdPerson)
+        {
+            m_country = country == null ? null : new DerPrintableString(country, true);
+            m_typeOfSubstitution = typeOfSubstitution;
+            m_signingFor = thirdPerson ?? throw new ArgumentNullException(nameof(thirdPerson));
 		}
 
-		public virtual string Country
-		{
-			get { return country; }
-		}
+		public virtual string Country => m_country?.GetString();
 
-		public virtual DirectoryString TypeOfSubstitution
-		{
-			get { return typeOfSubstitution; }
-		}
+		public virtual DirectoryString TypeOfSubstitution => m_typeOfSubstitution;
 
-		public virtual GeneralName ThirdPerson
-		{
-			get { return thirdPerson; }
-		}
+		public virtual GeneralName ThirdPerson => m_signingFor as GeneralName;
 
-		public virtual IssuerSerial CertRef
-		{
-			get { return certRef; }
-		}
+		public virtual IssuerSerial CertRef => m_signingFor as IssuerSerial;
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -201,24 +166,31 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		public override Asn1Object ToAsn1Object()
 		{
             Asn1EncodableVector v = new Asn1EncodableVector(3);
+			v.AddOptionalTagged(true, 1, m_country);
+            v.AddOptionalTagged(true, 2, m_typeOfSubstitution);
+			v.Add(new DerTaggedObject(true, 3, m_signingFor));
+            return new DerSequence(v);
+		}
 
-            if (country != null)
-            {
-                v.Add(new DerTaggedObject(true, 1, new DerPrintableString(country, true)));
-            }
+        private static Asn1Encodable GetInstanceSigningFor(Asn1Encodable obj)
+        {
+			var generalName = GeneralName.GetOptional(obj);
+			if (generalName != null)
+				return generalName;
 
-            v.AddOptionalTagged(true, 2, typeOfSubstitution);
+			var issuerSerial = IssuerSerial.GetOptional(obj);
+			if (issuerSerial != null)
+				return issuerSerial;
 
-            if (thirdPerson != null)
-            {
-                v.Add(new DerTaggedObject(true, 3, thirdPerson));
-            }
-            else
-            {
-                v.Add(new DerTaggedObject(true, 3, certRef));
-            }
+            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), nameof(obj));
+        }
 
-            return new DerSequence(v);
-		}
-	}
+		private static Asn1Encodable GetTaggedSigningFor(Asn1TaggedObject taggedObject, bool declaredExplicit)
+		{
+			Debug.Assert(taggedObject != null);
+			Debug.Assert(declaredExplicit);
+
+            return GetInstanceSigningFor(taggedObject.GetExplicitBaseObject());
+        }
+    }
 }
diff --git a/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs b/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
index 87e2aaa4f..c504b5d49 100644
--- a/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
+++ b/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
@@ -1,11 +1,10 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X500;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* Professions, specializations, disciplines, fields of activity, etc.
 	* 
 	* <pre>
@@ -21,141 +20,145 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 	* 
 	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
 	*/
-	public class ProfessionInfo
+    public class ProfessionInfo
 		: Asn1Encodable
 	{
 		/**
 		* Rechtsanw�ltin
 		*/
-		public static readonly DerObjectIdentifier Rechtsanwltin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".1");
+		public static readonly DerObjectIdentifier Rechtsanwltin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("1");
 
 		/**
 		* Rechtsanwalt
 		*/
-		public static readonly DerObjectIdentifier Rechtsanwalt = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".2");
+		public static readonly DerObjectIdentifier Rechtsanwalt =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("2");
 
 		/**
 		* Rechtsbeistand
 		*/
-		public static readonly DerObjectIdentifier Rechtsbeistand = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".3");
+		public static readonly DerObjectIdentifier Rechtsbeistand =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("3");
 
 		/**
 		* Steuerberaterin
 		*/
-		public static readonly DerObjectIdentifier Steuerberaterin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".4");
+		public static readonly DerObjectIdentifier Steuerberaterin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("4");
 
 		/**
 		* Steuerberater
 		*/
-		public static readonly DerObjectIdentifier Steuerberater = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".5");
+		public static readonly DerObjectIdentifier Steuerberater =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("5");
 
 		/**
 		* Steuerbevollm�chtigte
 		*/
-		public static readonly DerObjectIdentifier Steuerbevollmchtigte = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".6");
+		public static readonly DerObjectIdentifier Steuerbevollmchtigte =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("6");
 
 		/**
 		* Steuerbevollm�chtigter
 		*/
-		public static readonly DerObjectIdentifier Steuerbevollmchtigter = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".7");
+		public static readonly DerObjectIdentifier Steuerbevollmchtigter =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("7");
 
 		/**
 		* Notarin
 		*/
-		public static readonly DerObjectIdentifier Notarin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".8");
+		public static readonly DerObjectIdentifier Notarin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("8");
 
 		/**
 		* Notar
 		*/
-		public static readonly DerObjectIdentifier Notar = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".9");
+		public static readonly DerObjectIdentifier Notar =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("9");
 
 		/**
 		* Notarvertreterin
 		*/
-		public static readonly DerObjectIdentifier Notarvertreterin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".10");
+		public static readonly DerObjectIdentifier Notarvertreterin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("10");
 
 		/**
 		* Notarvertreter
 		*/
-		public static readonly DerObjectIdentifier Notarvertreter = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".11");
+		public static readonly DerObjectIdentifier Notarvertreter =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("11");
 
 		/**
 		* Notariatsverwalterin
 		*/
-		public static readonly DerObjectIdentifier Notariatsverwalterin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".12");
+		public static readonly DerObjectIdentifier Notariatsverwalterin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("12");
 
 		/**
 		* Notariatsverwalter
 		*/
-		public static readonly DerObjectIdentifier Notariatsverwalter = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".13");
+		public static readonly DerObjectIdentifier Notariatsverwalter =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("13");
 
 		/**
 		* Wirtschaftspr�ferin
 		*/
-		public static readonly DerObjectIdentifier Wirtschaftsprferin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".14");
+		public static readonly DerObjectIdentifier Wirtschaftsprferin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("14");
 
 		/**
 		* Wirtschaftspr�fer
 		*/
-		public static readonly DerObjectIdentifier Wirtschaftsprfer = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".15");
+		public static readonly DerObjectIdentifier Wirtschaftsprfer =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("15");
 
 		/**
 		* Vereidigte Buchpr�ferin
 		*/
-		public static readonly DerObjectIdentifier VereidigteBuchprferin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".16");
+		public static readonly DerObjectIdentifier VereidigteBuchprferin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("16");
 
 		/**
 		* Vereidigter Buchpr�fer
 		*/
-		public static readonly DerObjectIdentifier VereidigterBuchprfer = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".17");
+		public static readonly DerObjectIdentifier VereidigterBuchprfer =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("17");
 
 		/**
 		* Patentanw�ltin
 		*/
-		public static readonly DerObjectIdentifier Patentanwltin = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".18");
+		public static readonly DerObjectIdentifier Patentanwltin =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("18");
 
 		/**
 		* Patentanwalt
 		*/
-		public static readonly DerObjectIdentifier Patentanwalt = new DerObjectIdentifier(
-			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".19");
+		public static readonly DerObjectIdentifier Patentanwalt =
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern.Branch("19");
 
-		private readonly NamingAuthority	namingAuthority;
-		private readonly Asn1Sequence		professionItems;
-		private readonly Asn1Sequence		professionOids;
-		private readonly string				registrationNumber;
-		private readonly Asn1OctetString	addProfessionInfo;
+        public static ProfessionInfo GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is ProfessionInfo professionInfo)
+                return professionInfo;
+            return new ProfessionInfo(Asn1Sequence.GetInstance(obj));
+        }
 
-		public static ProfessionInfo GetInstance(object obj)
-		{
-			if (obj == null || obj is ProfessionInfo)
-				return (ProfessionInfo) obj;
+        public static ProfessionInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ProfessionInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-			if (obj is Asn1Sequence seq)
-				return new ProfessionInfo(seq);
+        public static ProfessionInfo GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ProfessionInfo(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly NamingAuthority m_namingAuthority;
+        private readonly Asn1Sequence m_professionItems;
+        private readonly Asn1Sequence m_professionOids;
+        private readonly DerPrintableString m_registrationNumber;
+        private readonly Asn1OctetString m_addProfessionInfo;
 
-		/**
+        /**
 		* Constructor from Asn1Sequence.
 		* <p/>
 		* <p/>
@@ -172,81 +175,23 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @param seq The ASN.1 sequence.
 		*/
-		private ProfessionInfo(Asn1Sequence seq)
+        private ProfessionInfo(Asn1Sequence seq)
 		{
-			if (seq.Count > 5)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
-
-			var e = seq.GetEnumerator();
-
-			e.MoveNext();
-			Asn1Encodable o = e.Current;
-
-			if (o is Asn1TaggedObject ato)
-			{
-				if (ato.TagNo != 0)
-					throw new ArgumentException("Bad tag number: " + ato.TagNo);
-
-				namingAuthority = NamingAuthority.GetInstance(ato, true);
-				e.MoveNext();
-				o = e.Current;
-			}
-
-			professionItems = Asn1Sequence.GetInstance(o);
-
-			if (e.MoveNext())
-			{
-				o = e.Current;
-				if (o is Asn1Sequence sequence)
-				{
-					professionOids = sequence;
-				}
-				else if (o is DerPrintableString printable)
-				{
-					registrationNumber = printable.GetString();
-				}
-				else if (o is Asn1OctetString octets)
-				{
-					addProfessionInfo = octets;
-				}
-				else
-				{
-                    throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
-				}
-			}
-
-			if (e.MoveNext())
-			{
-				o = e.Current;
-				if (o is DerPrintableString printable)
-				{
-					registrationNumber = printable.GetString();
-				}
-				else if (o is Asn1OctetString octets)
-				{
-					addProfessionInfo = octets;
-				}
-				else
-				{
-                    throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
-				}
-			}
-
-			if (e.MoveNext())
-			{
-				o = e.Current;
-				if (o is Asn1OctetString octets)
-				{
-					addProfessionInfo = octets;
-				}
-				else
-				{
-                    throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
-				}
-			}
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 5)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+			m_namingAuthority = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, true, NamingAuthority.GetTagged);
+			m_professionItems = Asn1Sequence.GetInstance(seq[pos++]);
+			m_professionOids = Asn1Utilities.ReadOptional(seq, ref pos, Asn1Sequence.GetOptional);
+            m_registrationNumber = Asn1Utilities.ReadOptional(seq, ref pos, DerPrintableString.GetOptional);
+            m_addProfessionInfo = Asn1Utilities.ReadOptional(seq, ref pos, Asn1OctetString.GetOptional);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
-		/**
+        /**
 		* Constructor from given details.
 		* <p/>
 		* <code>professionItems</code> is mandatory, all other parameters are
@@ -259,24 +204,44 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		* @param registrationNumber Registration number.
 		* @param addProfessionInfo  Additional infos in encoded form.
 		*/
-		public ProfessionInfo(
-			NamingAuthority			namingAuthority,
-			DirectoryString[]		professionItems,
-			DerObjectIdentifier[]	professionOids,
-			string					registrationNumber,
-			Asn1OctetString			addProfessionInfo)
-		{
-			this.namingAuthority = namingAuthority;
-			this.professionItems = new DerSequence(professionItems);
-			if (professionOids != null)
-			{
-				this.professionOids = new DerSequence(professionOids);
-			}
-			this.registrationNumber = registrationNumber;
-			this.addProfessionInfo = addProfessionInfo;
+        public ProfessionInfo(NamingAuthority namingAuthority, DirectoryString[] professionItems,
+            DerObjectIdentifier[] professionOids, string registrationNumber, Asn1OctetString addProfessionInfo)
+        {
+            m_namingAuthority = namingAuthority;
+			m_professionItems = DerSequence.FromElements(professionItems);
+			m_professionOids = professionOids == null ? null : DerSequence.FromElements(professionOids);
+			m_registrationNumber = registrationNumber == null ? null : new DerPrintableString(registrationNumber, true);
+			m_addProfessionInfo = addProfessionInfo;
 		}
 
 		/**
+		* @return Returns the addProfessionInfo.
+		*/
+		public virtual Asn1OctetString AddProfessionInfo => m_addProfessionInfo;
+
+		/**
+		* @return Returns the namingAuthority.
+		*/
+		public virtual NamingAuthority NamingAuthority => m_namingAuthority;
+
+        /**
+		* @return Returns the professionItems.
+		*/
+        public virtual DirectoryString[] GetProfessionItems() =>
+			m_professionItems.MapElements(DirectoryString.GetInstance);
+
+        /**
+		* @return Returns the professionOids.
+		*/
+        public virtual DerObjectIdentifier[] GetProfessionOids() =>
+            m_professionOids?.MapElements(DerObjectIdentifier.GetInstance) ?? new DerObjectIdentifier[0];
+
+		/**
+		* @return Returns the registrationNumber.
+		*/
+		public virtual string RegistrationNumber => m_registrationNumber?.GetString();
+
+        /**
 		* Produce an object suitable for an Asn1OutputStream.
 		* <p/>
 		* Returns:
@@ -297,57 +262,12 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(5);
-            v.AddOptionalTagged(true, 0, namingAuthority);
-            v.Add(professionItems);
-            v.AddOptional(professionOids);
-
-            if (registrationNumber != null)
-            {
-                v.Add(new DerPrintableString(registrationNumber, true));
-            }
-
-            v.AddOptional(addProfessionInfo);
+            v.AddOptionalTagged(true, 0, m_namingAuthority);
+            v.Add(m_professionItems);
+            v.AddOptional(m_professionOids);
+            v.AddOptional(m_registrationNumber);
+            v.AddOptional(m_addProfessionInfo);
             return new DerSequence(v);
         }
-
-		/**
-		* @return Returns the addProfessionInfo.
-		*/
-		public virtual Asn1OctetString AddProfessionInfo
-		{
-			get { return addProfessionInfo; }
-		}
-
-		/**
-		* @return Returns the namingAuthority.
-		*/
-		public virtual NamingAuthority NamingAuthority
-		{
-			get { return namingAuthority; }
-		}
-
-        /**
-		* @return Returns the professionItems.
-		*/
-        public virtual DirectoryString[] GetProfessionItems()
-        {
-            return professionItems.MapElements(DirectoryString.GetInstance);
-        }
-
-        /**
-		* @return Returns the professionOids.
-		*/
-        public virtual DerObjectIdentifier[] GetProfessionOids()
-        {
-            return professionOids?.MapElements(DerObjectIdentifier.GetInstance) ?? new DerObjectIdentifier[0];
-        }
-
-        /**
-		* @return Returns the registrationNumber.
-		*/
-        public virtual string RegistrationNumber
-		{
-			get { return registrationNumber; }
-		}
 	}
 }
diff --git a/crypto/src/asn1/isismtt/x509/Restriction.cs b/crypto/src/asn1/isismtt/x509/Restriction.cs
index 4334d331d..eceffaf96 100644
--- a/crypto/src/asn1/isismtt/x509/Restriction.cs
+++ b/crypto/src/asn1/isismtt/x509/Restriction.cs
@@ -1,34 +1,35 @@
-using System;
-
 using Org.BouncyCastle.Asn1.X500;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 {
-	/**
+    /**
 	* Some other restriction regarding the usage of this certificate.
 	* <p/>
 	* <pre>
 	*  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
 	* </pre>
 	*/
-	public class Restriction
+    public class Restriction
 		: Asn1Encodable
 	{
-		private readonly DirectoryString restriction;
+        public static Restriction GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is Restriction restriction)
+                return restriction;
+            return new Restriction(DirectoryString.GetInstance(obj));
+        }
 
-		public static Restriction GetInstance(object obj)
-		{
-			if (obj is Restriction)
-				return (Restriction) obj;
+        public static Restriction GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Restriction(DirectoryString.GetInstance(taggedObject, declaredExplicit));
 
-			if (obj is IAsn1String)
-				return new Restriction(DirectoryString.GetInstance(obj));
+        public static Restriction GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Restriction(DirectoryString.GetTagged(taggedObject, declaredExplicit));
 
-            throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly DirectoryString m_restriction;
 
-		/**
+        /**
 		* Constructor from DirectoryString.
 		* <p/>
 		* The DirectoryString is of type RestrictionSyntax:
@@ -39,9 +40,9 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @param restriction A IAsn1String.
 		*/
-		private Restriction(DirectoryString restriction)
+        private Restriction(DirectoryString restriction)
 		{
-			this.restriction = restriction;
+			m_restriction = restriction;
 		}
 
 		/**
@@ -51,13 +52,10 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*/
 		public Restriction(string restriction)
 		{
-			this.restriction = new DirectoryString(restriction);
+			m_restriction = new DirectoryString(restriction);
 		}
 
-		public virtual DirectoryString RestrictionString
-		{
-			get { return restriction; }
-		}
+		public virtual DirectoryString RestrictionString => m_restriction;
 
 		/**
 		* Produce an object suitable for an Asn1OutputStream.
@@ -71,9 +69,6 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*
 		* @return an Asn1Object
 		*/
-		public override Asn1Object ToAsn1Object()
-		{
-			return restriction.ToAsn1Object();
-		}
+		public override Asn1Object ToAsn1Object() => m_restriction.ToAsn1Object();
 	}
 }
diff --git a/crypto/src/asn1/x500/DirectoryString.cs b/crypto/src/asn1/x500/DirectoryString.cs
index a04ed0056..c622113d4 100644
--- a/crypto/src/asn1/x500/DirectoryString.cs
+++ b/crypto/src/asn1/x500/DirectoryString.cs
@@ -11,30 +11,50 @@ namespace Org.BouncyCastle.Asn1.X500
 
 		public static DirectoryString GetInstance(object obj)
 		{
-			if (obj == null || obj is DirectoryString)
-				return (DirectoryString) obj;
-
-            if (obj is DerStringBase)
-			{
-				if (obj is DerT61String
-					|| obj is DerPrintableString
-					|| obj is DerUniversalString
-					|| obj is DerUtf8String
-					|| obj is DerBmpString)
-				{
-					return new DirectoryString((DerStringBase) obj);
-				}
-			}
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1Encodable element)
+            {
+                var result = GetOptional(element);
+                if (result != null)
+                    return result;
+            }
+
+            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), nameof(obj));
+        }
 
         public static DirectoryString GetInstance(Asn1TaggedObject obj, bool isExplicit) =>
             Asn1Utilities.GetInstanceChoice(obj, isExplicit, GetInstance);
 
+        public static DirectoryString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DirectoryString directoryString)
+                return directoryString;
+
+			var innerObject = GetOptionalInnerObject(element);
+			if (innerObject != null)
+				return new DirectoryString(innerObject);
+
+			return null;
+        }
+
         public static DirectoryString GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
             Asn1Utilities.GetTaggedChoice(taggedObject, declaredExplicit, GetInstance);
 
+		private static DerStringBase GetOptionalInnerObject(Asn1Encodable element)
+		{
+            return DerT61String.GetOptional(element)
+                ?? DerPrintableString.GetOptional(element)
+                ?? DerUniversalString.GetOptional(element)
+                ?? DerUtf8String.GetOptional(element)
+                ?? DerBmpString.GetOptional(element)
+				?? (DerStringBase)null;
+        }
+
         private DirectoryString(
 			DerStringBase str)
 		{
diff --git a/crypto/src/asn1/x509/GeneralName.cs b/crypto/src/asn1/x509/GeneralName.cs
index 08f85bb8e..ee96ec9ca 100644
--- a/crypto/src/asn1/x509/GeneralName.cs
+++ b/crypto/src/asn1/x509/GeneralName.cs
@@ -46,50 +46,71 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		public static GeneralName GetInstance(object obj)
         {
-			if (obj == null)
-				return null;
-			if (obj is GeneralName generalName)
-				return generalName;
-			return GetInstanceSelection(Asn1TaggedObject.GetInstance(obj));
-		}
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1Encodable element)
+            {
+                var result = GetOptional(element);
+                if (result != null)
+                    return result;
+            }
+
+            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), nameof(obj));
+        }
 
 		public static GeneralName GetInstance(Asn1TaggedObject tagObj, bool explicitly) =>
             Asn1Utilities.GetInstanceChoice(tagObj, explicitly, GetInstance);
 
+        public static GeneralName GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is GeneralName generalName)
+                return generalName;
+
+            if (element is Asn1TaggedObject taggedObject)
+            {
+                Asn1Encodable baseObject = GetOptionalBaseObject(taggedObject);
+                if (baseObject != null)
+                    return new GeneralName(taggedObject.TagNo, baseObject);
+            }
+
+            return null;
+        }
+
         public static GeneralName GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
             Asn1Utilities.GetTaggedChoice(taggedObject, declaredExplicit, GetInstance);
 
-        private static GeneralName GetInstanceSelection(Asn1TaggedObject taggedObject)
-		{
+        private static Asn1Encodable GetOptionalBaseObject(Asn1TaggedObject taggedObject)
+        {
             if (taggedObject.HasContextTag())
-			{
-				int tag = taggedObject.TagNo;
-
-				switch (tag)
-				{
+            {
+                switch (taggedObject.TagNo)
+                {
 				case EdiPartyName:
 				case OtherName:
 				case X400Address:
-					return new GeneralName(tag, Asn1Sequence.GetInstance(taggedObject, false));
+					return Asn1Sequence.GetInstance(taggedObject, false);
 
 				case DnsName:
 				case Rfc822Name:
 				case UniformResourceIdentifier:
-					return new GeneralName(tag, DerIA5String.GetInstance(taggedObject, false));
+					return DerIA5String.GetInstance(taggedObject, false);
 
 				case DirectoryName:
 					// CHOICE so explicit
-					return new GeneralName(tag, X509Name.GetInstance(taggedObject, true));
+					return X509Name.GetInstance(taggedObject, true);
 
 				case IPAddress:
-					return new GeneralName(tag, Asn1OctetString.GetInstance(taggedObject, false));
+					return Asn1OctetString.GetInstance(taggedObject, false);
 
 				case RegisteredID:
-					return new GeneralName(tag, DerObjectIdentifier.GetInstance(taggedObject, false));
-				}
+					return DerObjectIdentifier.GetInstance(taggedObject, false);
+                }
             }
-
-            throw new ArgumentException("unknown tag: " + Asn1Utilities.GetTagText(taggedObject));
+            return null;
         }
 
         private readonly int m_tag;
diff --git a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
index c6f4838db..07a726172 100644
--- a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
+++ b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -72,8 +72,9 @@ namespace Org.BouncyCastle.Asn1.X509
 
         private SubjectPublicKeyInfo(Asn1Sequence seq)
         {
-            if (seq.Count != 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+            int count = seq.Count;
+            if (count != 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
             m_algorithm = AlgorithmIdentifier.GetInstance(seq[0]);
 			m_publicKey = DerBitString.GetInstance(seq[1]);
diff --git a/crypto/src/asn1/x509/Target.cs b/crypto/src/asn1/x509/Target.cs
index eff740143..da3ccccae 100644
--- a/crypto/src/asn1/x509/Target.cs
+++ b/crypto/src/asn1/x509/Target.cs
@@ -62,12 +62,12 @@ namespace Org.BouncyCastle.Asn1.X509
         private Target(
 			Asn1TaggedObject tagObj)
 		{
-			switch ((Choice) tagObj.TagNo)
+			switch (tagObj.TagNo)
 			{
-				case Choice.Name:	// GeneralName is already a choice so explicit
+				case (int)Choice.Name:	// GeneralName is already a choice so explicit
 					targetName = GeneralName.GetInstance(tagObj, true);
 					break;
-				case Choice.Group:
+				case (int)Choice.Group:
 					targetGroup = GeneralName.GetInstance(tagObj, true);
 					break;
 				default:
diff --git a/crypto/src/asn1/x509/X509CertificateStructure.cs b/crypto/src/asn1/x509/X509CertificateStructure.cs
index 5394b2be3..aed326d44 100644
--- a/crypto/src/asn1/x509/X509CertificateStructure.cs
+++ b/crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -1,7 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Asn1.Pkcs;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
     /**
@@ -17,15 +15,6 @@ namespace Org.BouncyCastle.Asn1.X509
     public class X509CertificateStructure
         : Asn1Encodable
     {
-        private readonly TbsCertificateStructure	tbsCert;
-        private readonly AlgorithmIdentifier		sigAlgID;
-        private readonly DerBitString				sig;
-
-        public static X509CertificateStructure GetInstance(Asn1TaggedObject obj, bool explicitly)
-        {
-            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
-        }
-
         public static X509CertificateStructure GetInstance(object obj)
         {
             if (obj == null)
@@ -35,95 +24,74 @@ namespace Org.BouncyCastle.Asn1.X509
             return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
         }
 
-        public X509CertificateStructure(
-            TbsCertificateStructure	tbsCert,
-            AlgorithmIdentifier		sigAlgID,
-            DerBitString			sig)
+        public static X509CertificateStructure GetInstance(Asn1TaggedObject obj, bool explicitly) =>
+            new X509CertificateStructure(Asn1Sequence.GetInstance(obj, explicitly));
+
+        public static X509CertificateStructure GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is X509CertificateStructure x509CertificateStructure)
+                return x509CertificateStructure;
+
+            Asn1Sequence asn1Sequence = Asn1Sequence.GetOptional(element);
+            if (asn1Sequence != null)
+                return new X509CertificateStructure(asn1Sequence);
+
+            return null;
+        }
+
+        public static X509CertificateStructure GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new X509CertificateStructure(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
+
+        private readonly TbsCertificateStructure m_tbsCert;
+        private readonly AlgorithmIdentifier m_sigAlgID;
+        private readonly DerBitString m_sig;
+
+        public X509CertificateStructure(TbsCertificateStructure tbsCert, AlgorithmIdentifier sigAlgID, DerBitString sig)
         {
-            if (tbsCert == null)
-                throw new ArgumentNullException("tbsCert");
-            if (sigAlgID == null)
-                throw new ArgumentNullException("sigAlgID");
-            if (sig == null)
-                throw new ArgumentNullException("sig");
-
-            this.tbsCert = tbsCert;
-            this.sigAlgID = sigAlgID;
-            this.sig = sig;
+            m_tbsCert = tbsCert ?? throw new ArgumentNullException(nameof(tbsCert));
+            m_sigAlgID = sigAlgID ?? throw new ArgumentNullException(nameof(sigAlgID));
+            m_sig = sig ?? throw new ArgumentNullException(nameof(sig));
         }
 
-        private X509CertificateStructure(
-            Asn1Sequence seq)
+        private X509CertificateStructure(Asn1Sequence seq)
         {
-            if (seq.Count != 3)
-                throw new ArgumentException("sequence wrong size for a certificate", "seq");
+            int count = seq.Count;
+            if (count != 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
             //
             // correct x509 certficate
             //
-            tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
-            sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
-            sig = DerBitString.GetInstance(seq[2]);
+            m_tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
+            m_sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+            m_sig = DerBitString.GetInstance(seq[2]);
         }
 
-        public TbsCertificateStructure TbsCertificate
-        {
-            get { return tbsCert; }
-        }
+        public TbsCertificateStructure TbsCertificate => m_tbsCert;
 
-        public int Version
-        {
-            get { return tbsCert.Version; }
-        }
+        public int Version => m_tbsCert.Version;
 
-        public DerInteger SerialNumber
-        {
-            get { return tbsCert.SerialNumber; }
-        }
+        public DerInteger SerialNumber => m_tbsCert.SerialNumber;
 
-        public X509Name Issuer
-        {
-            get { return tbsCert.Issuer; }
-        }
+        public X509Name Issuer => m_tbsCert.Issuer;
 
-        public Time StartDate
-        {
-            get { return tbsCert.StartDate; }
-        }
+        public Time StartDate => m_tbsCert.StartDate;
 
-        public Time EndDate
-        {
-            get { return tbsCert.EndDate; }
-        }
+        public Time EndDate => m_tbsCert.EndDate;
 
-        public X509Name Subject
-        {
-            get { return tbsCert.Subject; }
-        }
+        public X509Name Subject => m_tbsCert.Subject;
 
-        public SubjectPublicKeyInfo SubjectPublicKeyInfo
-        {
-            get { return tbsCert.SubjectPublicKeyInfo; }
-        }
+        public SubjectPublicKeyInfo SubjectPublicKeyInfo => m_tbsCert.SubjectPublicKeyInfo;
 
-        public AlgorithmIdentifier SignatureAlgorithm
-        {
-            get { return sigAlgID; }
-        }
+        public AlgorithmIdentifier SignatureAlgorithm => m_sigAlgID;
 
-        public DerBitString Signature
-        {
-            get { return sig; }
-        }
+        public DerBitString Signature => m_sig;
 
-        public byte[] GetSignatureOctets()
-        {
-            return sig.GetOctets();
-        }
+        public byte[] GetSignatureOctets() => m_sig.GetOctets();
 
-        public override Asn1Object ToAsn1Object()
-        {
-            return new DerSequence(tbsCert, sigAlgID, sig);
-        }
+        public override Asn1Object ToAsn1Object() => new DerSequence(m_tbsCert, m_sigAlgID, m_sig);
     }
 }