summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2024-07-01 21:32:14 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2024-07-01 21:32:14 +0700
commit3c9d8a7198b04fa80f034c372fba4eea65c31e3b (patch)
treee1ee1e6c0a747dc4025acb490fd3cf9f2cde9b12
parentAsn1Sequence subclass static methods (diff)
downloadBouncyCastle.NET-ed25519-3c9d8a7198b04fa80f034c372fba4eea65c31e3b.tar.xz
Refactoring in Asn1.X509.Qualified
-rw-r--r--crypto/src/asn1/x509/qualified/BiometricData.cs105
-rw-r--r--crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs3
-rw-r--r--crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs8
-rw-r--r--crypto/src/asn1/x509/qualified/MonetaryValue.cs77
-rw-r--r--crypto/src/asn1/x509/qualified/QCStatement.cs73
-rw-r--r--crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs1
-rw-r--r--crypto/src/asn1/x509/qualified/SemanticsInformation.cs105
-rw-r--r--crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs8
8 files changed, 163 insertions, 217 deletions
diff --git a/crypto/src/asn1/x509/qualified/BiometricData.cs b/crypto/src/asn1/x509/qualified/BiometricData.cs
index 816ffd26d..c2ede413d 100644
--- a/crypto/src/asn1/x509/qualified/BiometricData.cs
+++ b/crypto/src/asn1/x509/qualified/BiometricData.cs
@@ -17,88 +17,69 @@ namespace Org.BouncyCastle.Asn1.X509.Qualified
     public class BiometricData
         : Asn1Encodable
     {
-        private readonly TypeOfBiometricData typeOfBiometricData;
-        private readonly AlgorithmIdentifier hashAlgorithm;
-        private readonly Asn1OctetString     biometricDataHash;
-        private readonly DerIA5String        sourceDataUri;
-
-        public static BiometricData GetInstance(
-            object obj)
+        public static BiometricData GetInstance(object obj)
         {
-            if (obj == null || obj is BiometricData)
-            {
-                return (BiometricData)obj;
-            }
+            if (obj == null)
+                return null;
+            if (obj is BiometricData biometricData)
+                return biometricData;
+            return new BiometricData(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static BiometricData GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new BiometricData(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-            if (obj is Asn1Sequence)
-            {
-				return new BiometricData(Asn1Sequence.GetInstance(obj));
-            }
+        public static BiometricData GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new BiometricData(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly TypeOfBiometricData m_typeOfBiometricData;
+        private readonly AlgorithmIdentifier m_hashAlgorithm;
+        private readonly Asn1OctetString m_biometricDataHash;
+        private readonly DerIA5String m_sourceDataUri;
 
-		private BiometricData(
-			Asn1Sequence seq)
+        private BiometricData(Asn1Sequence seq)
         {
-			typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[0]);
-			hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
-			biometricDataHash = Asn1OctetString.GetInstance(seq[2]);
+            int count = seq.Count, pos = 0;
+            if (count < 3 || count > 4)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-			if (seq.Count > 3)
-			{
-				sourceDataUri = DerIA5String.GetInstance(seq[3]);
-			}
-        }
+            m_typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[pos++]);
+			m_hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[pos++]);
+			m_biometricDataHash = Asn1OctetString.GetInstance(seq[pos++]);
+            m_sourceDataUri = Asn1Utilities.ReadOptional(seq, ref pos, DerIA5String.GetOptional);
 
-		public BiometricData(
-            TypeOfBiometricData	typeOfBiometricData,
-            AlgorithmIdentifier	hashAlgorithm,
-            Asn1OctetString		biometricDataHash,
-            DerIA5String		sourceDataUri)
-        {
-            this.typeOfBiometricData = typeOfBiometricData;
-            this.hashAlgorithm = hashAlgorithm;
-            this.biometricDataHash = biometricDataHash;
-            this.sourceDataUri = sourceDataUri;
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
         }
 
-        public BiometricData(
-            TypeOfBiometricData	typeOfBiometricData,
-            AlgorithmIdentifier	hashAlgorithm,
-            Asn1OctetString		biometricDataHash)
+        public BiometricData(TypeOfBiometricData typeOfBiometricData, AlgorithmIdentifier hashAlgorithm,
+            Asn1OctetString biometricDataHash)
+            : this(typeOfBiometricData, hashAlgorithm, biometricDataHash, null)
         {
-            this.typeOfBiometricData = typeOfBiometricData;
-            this.hashAlgorithm = hashAlgorithm;
-            this.biometricDataHash = biometricDataHash;
-            this.sourceDataUri = null;
         }
 
-        public TypeOfBiometricData TypeOfBiometricData
+        public BiometricData(TypeOfBiometricData typeOfBiometricData, AlgorithmIdentifier hashAlgorithm,
+            Asn1OctetString biometricDataHash, DerIA5String sourceDataUri)
         {
-			get { return typeOfBiometricData; }
+            m_typeOfBiometricData = typeOfBiometricData ?? throw new ArgumentNullException(nameof(typeOfBiometricData));
+            m_hashAlgorithm = hashAlgorithm ?? throw new ArgumentNullException(nameof(hashAlgorithm));
+            m_biometricDataHash = biometricDataHash ?? throw new ArgumentNullException(nameof(biometricDataHash));
+            m_sourceDataUri = sourceDataUri;
         }
 
-		public AlgorithmIdentifier HashAlgorithm
-		{
-			get { return hashAlgorithm; }
-		}
+        public TypeOfBiometricData TypeOfBiometricData => m_typeOfBiometricData;
+
+        public AlgorithmIdentifier HashAlgorithm => m_hashAlgorithm;
 
-		public Asn1OctetString BiometricDataHash
-		{
-			get { return biometricDataHash; }
-		}
+        public Asn1OctetString BiometricDataHash => m_biometricDataHash;
 
-		public DerIA5String SourceDataUri
-		{
-			get { return sourceDataUri; }
-		}
+        public DerIA5String SourceDataUri => m_sourceDataUri;
 
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(typeOfBiometricData, hashAlgorithm, biometricDataHash);
-            v.AddOptional(sourceDataUri);
-            return new DerSequence(v);
+            return m_sourceDataUri == null
+                ?  new DerSequence(m_typeOfBiometricData, m_hashAlgorithm, m_biometricDataHash)
+                :  new DerSequence(m_typeOfBiometricData, m_hashAlgorithm, m_biometricDataHash, m_sourceDataUri);
         }
     }
 }
diff --git a/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs b/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
index 86a4eee0a..c55bfd303 100644
--- a/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
+++ b/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
@@ -4,7 +4,8 @@ using Org.BouncyCastle.Asn1;
 
 namespace Org.BouncyCastle.Asn1.X509.Qualified
 {
-	public abstract class EtsiQCObjectIdentifiers
+    // TODO[api] Make static
+    public abstract class EtsiQCObjectIdentifiers
 	{
 		//
 		// base id
diff --git a/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs b/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
index a90a33ae2..61f55af87 100644
--- a/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
+++ b/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
@@ -48,7 +48,13 @@ namespace Org.BouncyCastle.Asn1.X509.Qualified
 			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
         }
 
-		public Iso4217CurrencyCode(
+        public static Iso4217CurrencyCode GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            Asn1Utilities.GetInstanceChoice(taggedObject, declaredExplicit, GetInstance);
+
+        public static Iso4217CurrencyCode GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            Asn1Utilities.GetTaggedChoice(taggedObject, declaredExplicit, GetInstance);
+
+        public Iso4217CurrencyCode(
             int numeric)
         {
             if (numeric > NumericMaxSize || numeric < NumericMinSize)
diff --git a/crypto/src/asn1/x509/qualified/MonetaryValue.cs b/crypto/src/asn1/x509/qualified/MonetaryValue.cs
index be4cd1142..b79d5d50a 100644
--- a/crypto/src/asn1/x509/qualified/MonetaryValue.cs
+++ b/crypto/src/asn1/x509/qualified/MonetaryValue.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.X509.Qualified
 {
@@ -18,65 +17,49 @@ namespace Org.BouncyCastle.Asn1.X509.Qualified
     public class MonetaryValue
         : Asn1Encodable
     {
-        internal Iso4217CurrencyCode	currency;
-        internal DerInteger				amount;
-        internal DerInteger				exponent;
-
-		public static MonetaryValue GetInstance(
-            object obj)
+        public static MonetaryValue GetInstance(object obj)
         {
-            if (obj == null || obj is MonetaryValue)
-            {
-                return (MonetaryValue) obj;
-            }
+            if (obj == null)
+                return null;
+            if (obj is MonetaryValue monetaryValue)
+                return monetaryValue;
+            return new MonetaryValue(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static MonetaryValue GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new MonetaryValue(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-			if (obj is Asn1Sequence)
-            {
-                return new MonetaryValue(Asn1Sequence.GetInstance(obj));
-            }
+        public static MonetaryValue GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new MonetaryValue(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly Iso4217CurrencyCode m_currency;
+        private readonly DerInteger m_amount;
+        private readonly DerInteger m_exponent;
 
-		private MonetaryValue(
-            Asn1Sequence seq)
+        private MonetaryValue(Asn1Sequence seq)
         {
-			if (seq.Count != 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+            int count = seq.Count;
+            if (count != 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            currency = Iso4217CurrencyCode.GetInstance(seq[0]);
-            amount = DerInteger.GetInstance(seq[1]);
-            exponent = DerInteger.GetInstance(seq[2]);
+            m_currency = Iso4217CurrencyCode.GetInstance(seq[0]);
+            m_amount = DerInteger.GetInstance(seq[1]);
+            m_exponent = DerInteger.GetInstance(seq[2]);
         }
 
-		public MonetaryValue(
-            Iso4217CurrencyCode	currency,
-            int					amount,
-            int					exponent)
+        public MonetaryValue(Iso4217CurrencyCode currency, int amount, int exponent)
         {
-            this.currency = currency;
-            this.amount = new DerInteger(amount);
-            this.exponent = new DerInteger(exponent);
+            m_currency = currency ?? throw new ArgumentNullException(nameof(currency));
+            m_amount = new DerInteger(amount);
+            m_exponent = new DerInteger(exponent);
         }
 
-		public Iso4217CurrencyCode Currency
-		{
-			get { return currency; }
-		}
+		public Iso4217CurrencyCode Currency => m_currency;
 
-		public BigInteger Amount
-		{
-			get { return amount.Value; }
-		}
+        public BigInteger Amount => m_amount.Value;
 
-		public BigInteger Exponent
-		{
-			get { return exponent.Value; }
-		}
+        public BigInteger Exponent => m_exponent.Value;
 
-		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/x509/qualified/QCStatement.cs b/crypto/src/asn1/x509/qualified/QCStatement.cs
index bfa515392..cdbf78b2e 100644
--- a/crypto/src/asn1/x509/qualified/QCStatement.cs
+++ b/crypto/src/asn1/x509/qualified/QCStatement.cs
@@ -1,7 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509.Qualified
 {
     /**
@@ -15,65 +13,60 @@ namespace Org.BouncyCastle.Asn1.X509.Qualified
     public class QCStatement
         : Asn1Encodable
     {
-        private readonly DerObjectIdentifier	qcStatementId;
-        private readonly Asn1Encodable			qcStatementInfo;
-
-		public static QCStatement GetInstance(
-            object obj)
+        public static QCStatement GetInstance(object obj)
         {
-            if (obj == null || obj is QCStatement)
-            {
-                return (QCStatement) obj;
-            }
+            if (obj == null)
+                return null;
+            if (obj is QCStatement qcStatement)
+                return qcStatement;
+            return new QCStatement(Asn1Sequence.GetInstance(obj));
+        }
 
-			if (obj is Asn1Sequence)
-            {
-				return new QCStatement(Asn1Sequence.GetInstance(obj));
-            }
+        public static QCStatement GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new QCStatement(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-		}
+        public static QCStatement GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new QCStatement(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-		private QCStatement(
-            Asn1Sequence seq)
+        private readonly DerObjectIdentifier m_statementId;
+        private readonly Asn1Encodable m_statementInfo;
+
+        private QCStatement(Asn1Sequence seq)
         {
-			qcStatementId = DerObjectIdentifier.GetInstance(seq[0]);
+            int count = seq.Count;
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+            m_statementId = DerObjectIdentifier.GetInstance(seq[0]);
 
 			if (seq.Count > 1)
 			{
-				qcStatementInfo = seq[1];
+				m_statementInfo = seq[1];
 			}
         }
 
-		public QCStatement(
-            DerObjectIdentifier qcStatementId)
+        // TODO[api] Rename parameter
+		public QCStatement(DerObjectIdentifier qcStatementId)
+            : this(qcStatementId, null)
         {
-            this.qcStatementId = qcStatementId;
         }
 
-        public QCStatement(
-            DerObjectIdentifier qcStatementId,
-            Asn1Encodable       qcStatementInfo)
+        // TODO[api] Rename parameters
+        public QCStatement(DerObjectIdentifier qcStatementId, Asn1Encodable qcStatementInfo)
         {
-            this.qcStatementId = qcStatementId;
-            this.qcStatementInfo = qcStatementInfo;
+            m_statementId = qcStatementId ?? throw new ArgumentNullException(nameof(qcStatementId));
+            m_statementInfo = qcStatementInfo;
         }
 
-		public DerObjectIdentifier StatementId
-		{
-			get { return qcStatementId; }
-		}
+        public DerObjectIdentifier StatementId => m_statementId;
 
-		public Asn1Encodable StatementInfo
-		{
-			get { return qcStatementInfo; }
-		}
+        public Asn1Encodable StatementInfo => m_statementInfo;
 
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(qcStatementId);
-            v.AddOptional(qcStatementInfo);
-            return new DerSequence(v);
+            return m_statementInfo == null
+                ?  new DerSequence(m_statementId)
+                :  new DerSequence(m_statementId, m_statementInfo);
         }
     }
 }
diff --git a/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs b/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
index 8ebd69edb..7dd91c977 100644
--- a/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
+++ b/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
@@ -4,6 +4,7 @@ using Org.BouncyCastle.Asn1;
 
 namespace Org.BouncyCastle.Asn1.X509.Qualified
 {
+    // TODO[api] Make static
     public sealed class Rfc3739QCObjectIdentifiers
     {
 		private Rfc3739QCObjectIdentifiers()
diff --git a/crypto/src/asn1/x509/qualified/SemanticsInformation.cs b/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
index 36a15edec..c82e5f1a1 100644
--- a/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
+++ b/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
@@ -1,7 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509.Qualified
 {
     /**
@@ -21,92 +19,69 @@ namespace Org.BouncyCastle.Asn1.X509.Qualified
     public class SemanticsInformation
 		: Asn1Encodable
     {
-        private readonly DerObjectIdentifier	semanticsIdentifier;
-        private readonly GeneralName[]			nameRegistrationAuthorities;
-
-		public static SemanticsInformation GetInstance(
-			object obj)
+        public static SemanticsInformation GetInstance(object obj)
         {
-            if (obj == null || obj is SemanticsInformation)
-            {
-                return (SemanticsInformation) obj;
-            }
+            if (obj == null)
+                return null;
+            if (obj is SemanticsInformation semanticsInformation)
+                return semanticsInformation;
+            return new SemanticsInformation(Asn1Sequence.GetInstance(obj));
+        }
 
-			if (obj is Asn1Sequence)
-            {
-                return new SemanticsInformation(Asn1Sequence.GetInstance(obj));
-            }
+        public static SemanticsInformation GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new SemanticsInformation(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
 
-			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-		}
+        public static SemanticsInformation GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new SemanticsInformation(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
-		public SemanticsInformation(Asn1Sequence seq)
+        private readonly DerObjectIdentifier m_semanticsIdentifier;
+        private readonly GeneralName[] m_nameRegistrationAuthorities;
+
+        public SemanticsInformation(Asn1Sequence seq)
         {
-            if (seq.Count < 1)
-                throw new ArgumentException("no objects in SemanticsInformation");
+            int count = seq.Count, pos = 0;
 
-			var e = seq.GetEnumerator();
-			e.MoveNext();
-            var obj = e.Current;
-            if (obj is DerObjectIdentifier oid)
-            {
-                semanticsIdentifier = oid;
-                if (e.MoveNext())
-                {
-                    obj = e.Current;
-                }
-                else
-                {
-                    obj = null;
-                }
-            }
+            // NOTE: At least one of 'semanticsIdentifier' or 'nameRegistrationAuthorities' must be present
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            if (obj != null)
-            {
-                this.nameRegistrationAuthorities = Asn1Sequence.GetInstance(obj).MapElements(GeneralName.GetInstance);
-            }
-        }
+            m_semanticsIdentifier = Asn1Utilities.ReadOptional(seq, ref pos, DerObjectIdentifier.GetOptional);
+            m_nameRegistrationAuthorities = Asn1Utilities.ReadOptional(seq, ref pos, Asn1Sequence.GetOptional)
+                ?.MapElements(GeneralName.GetInstance);
 
-        public SemanticsInformation(
-            DerObjectIdentifier semanticsIdentifier,
-            GeneralName[] generalNames)
-        {
-            this.semanticsIdentifier = semanticsIdentifier;
-            this.nameRegistrationAuthorities = generalNames;
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
         }
 
-		public SemanticsInformation(
-			DerObjectIdentifier semanticsIdentifier)
+        public SemanticsInformation(DerObjectIdentifier semanticsIdentifier)
+            : this(semanticsIdentifier, null)
         {
-            this.semanticsIdentifier = semanticsIdentifier;
         }
 
-        public SemanticsInformation(
-			GeneralName[] generalNames)
+        // TODO[api] Rename parameter
+        public SemanticsInformation(GeneralName[] generalNames)
+            : this(null, generalNames)
         {
-            this.nameRegistrationAuthorities = generalNames;
         }
 
-		public DerObjectIdentifier SemanticsIdentifier 
+        public SemanticsInformation(DerObjectIdentifier semanticsIdentifier, GeneralName[] generalNames)
         {
-            get { return semanticsIdentifier; }
-        }
+            if (semanticsIdentifier == null && generalNames == null)
+                throw new ArgumentException("At least one option must be present");
 
-		public GeneralName[] GetNameRegistrationAuthorities()
-        {
-            return nameRegistrationAuthorities;
+            m_semanticsIdentifier = semanticsIdentifier;
+            m_nameRegistrationAuthorities = generalNames;
         }
 
+		public DerObjectIdentifier SemanticsIdentifier  => m_semanticsIdentifier;
+
+        public GeneralName[] GetNameRegistrationAuthorities() => m_nameRegistrationAuthorities;
+
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(2);
-            v.AddOptional(semanticsIdentifier);
-
-            if (null != nameRegistrationAuthorities)
-            {
-                v.Add(new DerSequence(nameRegistrationAuthorities));
-            }
-
+            v.AddOptional(m_semanticsIdentifier);
+            v.AddOptional(DerSequence.FromElementsOptional(m_nameRegistrationAuthorities));
             return new DerSequence(v);
         }
     }
diff --git a/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs b/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
index a4e2e4555..44da4cfa1 100644
--- a/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
+++ b/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
@@ -49,7 +49,13 @@ namespace Org.BouncyCastle.Asn1.X509.Qualified
 			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
 		}
 
-		public TypeOfBiometricData(
+        public static TypeOfBiometricData GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            Asn1Utilities.GetInstanceChoice(taggedObject, declaredExplicit, GetInstance);
+
+        public static TypeOfBiometricData GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            Asn1Utilities.GetTaggedChoice(taggedObject, declaredExplicit, GetInstance);
+
+        public TypeOfBiometricData(
 			int predefinedBiometricType)
         {
             if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature)