summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2024-06-05 17:09:26 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2024-06-05 17:09:26 +0700
commitfc860ec52e9f8eac943c92e7d8cfd812c7a7f1d9 (patch)
tree0baac94ba9a3dad934f081bdeb190d485cc4ec0d /crypto/src/asn1
parentRefactoring in Asn1 (diff)
downloadBouncyCastle.NET-ed25519-fc860ec52e9f8eac943c92e7d8cfd812c7a7f1d9.tar.xz
ASN.1: GetOptional method for all universal types
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/Asn1GeneralizedTime.cs17
-rw-r--r--crypto/src/asn1/Asn1Null.cs17
-rw-r--r--crypto/src/asn1/Asn1ObjectDescriptor.cs17
-rw-r--r--crypto/src/asn1/Asn1OctetString.cs17
-rw-r--r--crypto/src/asn1/Asn1RelativeOid.cs17
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs11
-rw-r--r--crypto/src/asn1/Asn1Set.cs11
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs17
-rw-r--r--crypto/src/asn1/Asn1UtcTime.cs19
-rw-r--r--crypto/src/asn1/DERExternal.cs19
-rw-r--r--crypto/src/asn1/DerBMPString.cs17
-rw-r--r--crypto/src/asn1/DerBitString.cs17
-rw-r--r--crypto/src/asn1/DerBoolean.cs17
-rw-r--r--crypto/src/asn1/DerEnumerated.cs17
-rw-r--r--crypto/src/asn1/DerGeneralString.cs17
-rw-r--r--crypto/src/asn1/DerGraphicString.cs17
-rw-r--r--crypto/src/asn1/DerIA5String.cs17
-rw-r--r--crypto/src/asn1/DerInteger.cs17
-rw-r--r--crypto/src/asn1/DerNumericString.cs17
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs17
-rw-r--r--crypto/src/asn1/DerPrintableString.cs17
-rw-r--r--crypto/src/asn1/DerT61String.cs17
-rw-r--r--crypto/src/asn1/DerUTF8String.cs14
-rw-r--r--crypto/src/asn1/DerUniversalString.cs17
-rw-r--r--crypto/src/asn1/DerVideotexString.cs17
-rw-r--r--crypto/src/asn1/DerVisibleString.cs17
26 files changed, 411 insertions, 20 deletions
diff --git a/crypto/src/asn1/Asn1GeneralizedTime.cs b/crypto/src/asn1/Asn1GeneralizedTime.cs
index 4fe5561a0..86f5f377f 100644
--- a/crypto/src/asn1/Asn1GeneralizedTime.cs
+++ b/crypto/src/asn1/Asn1GeneralizedTime.cs
@@ -56,6 +56,23 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1GeneralizedTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static Asn1GeneralizedTime GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1GeneralizedTime existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1GeneralizedTime converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly string m_timeString;
         private readonly bool m_timeStringCanonical;
         private readonly DateTime m_dateTime;
diff --git a/crypto/src/asn1/Asn1Null.cs b/crypto/src/asn1/Asn1Null.cs
index 992cd09aa..fa0adf71f 100644
--- a/crypto/src/asn1/Asn1Null.cs
+++ b/crypto/src/asn1/Asn1Null.cs
@@ -56,6 +56,23 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1Null)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static Asn1Null GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1Null existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1Null converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         internal Asn1Null()
         {
         }
diff --git a/crypto/src/asn1/Asn1ObjectDescriptor.cs b/crypto/src/asn1/Asn1ObjectDescriptor.cs
index 8d41fa4e4..1f33eeac8 100644
--- a/crypto/src/asn1/Asn1ObjectDescriptor.cs
+++ b/crypto/src/asn1/Asn1ObjectDescriptor.cs
@@ -75,6 +75,23 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1ObjectDescriptor)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static Asn1ObjectDescriptor GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1ObjectDescriptor existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1ObjectDescriptor converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly DerGraphicString m_baseGraphicString;
 
         public Asn1ObjectDescriptor(DerGraphicString baseGraphicString)
diff --git a/crypto/src/asn1/Asn1OctetString.cs b/crypto/src/asn1/Asn1OctetString.cs
index 1713012f5..4fb5f96de 100644
--- a/crypto/src/asn1/Asn1OctetString.cs
+++ b/crypto/src/asn1/Asn1OctetString.cs
@@ -74,6 +74,23 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1OctetString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static Asn1OctetString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1OctetString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1OctetString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         internal readonly byte[] contents;
 
         /**
diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs
index 4a84369c7..d1d9de882 100644
--- a/crypto/src/asn1/Asn1RelativeOid.cs
+++ b/crypto/src/asn1/Asn1RelativeOid.cs
@@ -74,6 +74,23 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1RelativeOid)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static Asn1RelativeOid GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1RelativeOid existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1RelativeOid converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         public static bool TryFromID(string identifier, out Asn1RelativeOid oid)
         {
             if (identifier == null)
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index c23b82ef5..436cc60d4 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -81,14 +81,13 @@ namespace Org.BouncyCastle.Asn1
             if (element == null)
                 throw new ArgumentNullException(nameof(element));
 
-            if (element is Asn1Sequence asn1Sequence)
-                return asn1Sequence;
+            if (element is Asn1Sequence existing)
+                return existing;
 
-            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object))
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1Sequence converted)
             {
-                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
-                if (asn1Object is Asn1Sequence converted)
-                    return converted;
+                return converted;
             }
 
             return null;
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index 6ba0bb413..de3d10380 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -81,14 +81,13 @@ namespace Org.BouncyCastle.Asn1
             if (element == null)
                 throw new ArgumentNullException(nameof(element));
 
-            if (element is Asn1Set asn1Set)
-                return asn1Set;
+            if (element is Asn1Set existing)
+                return existing;
 
-            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object))
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1Set converted)
             {
-                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
-                if (asn1Object is Asn1Set converted)
-                    return converted;
+                return converted;
             }
 
             return null;
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index 0045ad448..f817a1343 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -73,6 +73,23 @@ namespace Org.BouncyCastle.Asn1
             return Asn1Utilities.GetExplicitBaseTagged(CheckInstance(taggedObject, declaredExplicit), tagClass, tagNo);
         }
 
+        public static Asn1TaggedObject GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1TaggedObject existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1TaggedObject converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private static Asn1TaggedObject CheckInstance(object obj)
         {
             return GetInstance(obj ?? throw new ArgumentNullException(nameof(obj)));
diff --git a/crypto/src/asn1/Asn1UtcTime.cs b/crypto/src/asn1/Asn1UtcTime.cs
index 42704f996..665147d51 100644
--- a/crypto/src/asn1/Asn1UtcTime.cs
+++ b/crypto/src/asn1/Asn1UtcTime.cs
@@ -62,7 +62,24 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1UtcTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
-		private readonly string m_timeString;
+        public static Asn1UtcTime GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Asn1UtcTime existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is Asn1UtcTime converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
+        private readonly string m_timeString;
 		private readonly DateTime m_dateTime;
         private readonly bool m_dateTimeLocked;
         private readonly int m_twoDigitYearMax;
diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs
index c89fa8ec7..cc9b93490 100644
--- a/crypto/src/asn1/DERExternal.cs
+++ b/crypto/src/asn1/DERExternal.cs
@@ -56,7 +56,24 @@ namespace Org.BouncyCastle.Asn1
             return (DerExternal)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
-		internal readonly DerObjectIdentifier directReference;
+        public static DerExternal GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerExternal existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerExternal converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
+        internal readonly DerObjectIdentifier directReference;
         internal readonly DerInteger indirectReference;
         internal readonly Asn1ObjectDescriptor dataValueDescriptor;
         internal readonly int encoding;
diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs
index fcada7ad4..4a8ef8c84 100644
--- a/crypto/src/asn1/DerBMPString.cs
+++ b/crypto/src/asn1/DerBMPString.cs
@@ -72,6 +72,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerBmpString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerBmpString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerBmpString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerBmpString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly string m_str;
 
         internal DerBmpString(byte[] contents)
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
index d8b8be27f..8e3f99fd7 100644
--- a/crypto/src/asn1/DerBitString.cs
+++ b/crypto/src/asn1/DerBitString.cs
@@ -64,6 +64,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerBitString)Meta.Instance.GetContextInstance(obj, isExplicit);
         }
 
+        public static DerBitString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerBitString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerBitString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         internal readonly byte[] contents;
 
         public DerBitString(byte data, int padBits)
diff --git a/crypto/src/asn1/DerBoolean.cs b/crypto/src/asn1/DerBoolean.cs
index 0f9388363..419253d2f 100644
--- a/crypto/src/asn1/DerBoolean.cs
+++ b/crypto/src/asn1/DerBoolean.cs
@@ -78,6 +78,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerBoolean)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerBoolean GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerBoolean existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerBoolean converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte value;
 
         public DerBoolean(
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index d46e1153d..9ec1d1919 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -66,6 +66,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerEnumerated)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerEnumerated GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerEnumerated existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerEnumerated converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] contents;
         private readonly int start;
 
diff --git a/crypto/src/asn1/DerGeneralString.cs b/crypto/src/asn1/DerGeneralString.cs
index db99b0328..f8291d4e4 100644
--- a/crypto/src/asn1/DerGeneralString.cs
+++ b/crypto/src/asn1/DerGeneralString.cs
@@ -53,6 +53,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerGeneralString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerGeneralString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerGeneralString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerGeneralString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
 		public DerGeneralString(string str)
diff --git a/crypto/src/asn1/DerGraphicString.cs b/crypto/src/asn1/DerGraphicString.cs
index 8aa7456f7..12d2f91a0 100644
--- a/crypto/src/asn1/DerGraphicString.cs
+++ b/crypto/src/asn1/DerGraphicString.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerGraphicString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerGraphicString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerGraphicString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerGraphicString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
         public DerGraphicString(byte[] contents)
diff --git a/crypto/src/asn1/DerIA5String.cs b/crypto/src/asn1/DerIA5String.cs
index abb8be852..8c523ce4c 100644
--- a/crypto/src/asn1/DerIA5String.cs
+++ b/crypto/src/asn1/DerIA5String.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerIA5String)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerIA5String GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerIA5String existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerIA5String converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
 		public DerIA5String(string str)
diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs
index 59ca6046d..81d6437c7 100644
--- a/crypto/src/asn1/DerInteger.cs
+++ b/crypto/src/asn1/DerInteger.cs
@@ -80,6 +80,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerInteger)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerInteger GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerInteger existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerInteger converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
 		public DerInteger(int value)
         {
             this.bytes = BigInteger.ValueOf(value).ToByteArray();
diff --git a/crypto/src/asn1/DerNumericString.cs b/crypto/src/asn1/DerNumericString.cs
index 44adceb6b..81871f3c9 100644
--- a/crypto/src/asn1/DerNumericString.cs
+++ b/crypto/src/asn1/DerNumericString.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerNumericString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerNumericString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerNumericString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerNumericString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
         public DerNumericString(string str)
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index d09f2c094..ed79ec1d0 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -91,6 +91,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerObjectIdentifier)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerObjectIdentifier GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerObjectIdentifier existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerObjectIdentifier converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         public static bool TryFromID(string identifier, out DerObjectIdentifier oid)
         {
             if (identifier == null)
diff --git a/crypto/src/asn1/DerPrintableString.cs b/crypto/src/asn1/DerPrintableString.cs
index c3b453a9d..910fcafe1 100644
--- a/crypto/src/asn1/DerPrintableString.cs
+++ b/crypto/src/asn1/DerPrintableString.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerPrintableString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerPrintableString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerPrintableString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerPrintableString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
 		public DerPrintableString(string str)
diff --git a/crypto/src/asn1/DerT61String.cs b/crypto/src/asn1/DerT61String.cs
index cc02be41d..8d58747e5 100644
--- a/crypto/src/asn1/DerT61String.cs
+++ b/crypto/src/asn1/DerT61String.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerT61String)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerT61String GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerT61String existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerT61String converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
         public DerT61String(string str)
diff --git a/crypto/src/asn1/DerUTF8String.cs b/crypto/src/asn1/DerUTF8String.cs
index 6e933ba4b..05b061fca 100644
--- a/crypto/src/asn1/DerUTF8String.cs
+++ b/crypto/src/asn1/DerUTF8String.cs
@@ -72,14 +72,16 @@ namespace Org.BouncyCastle.Asn1
         {
             if (element == null)
                 throw new ArgumentNullException(nameof(element));
-            if (element is DerUtf8String derUtf8String)
-                return derUtf8String;
-            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object))
+
+            if (element is DerUtf8String existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerUtf8String converted)
             {
-                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
-                if (asn1Object is DerUtf8String converted)
-                    return converted;
+                return converted;
             }
+
             return null;
         }
 
diff --git a/crypto/src/asn1/DerUniversalString.cs b/crypto/src/asn1/DerUniversalString.cs
index 806c869e5..c05a87a69 100644
--- a/crypto/src/asn1/DerUniversalString.cs
+++ b/crypto/src/asn1/DerUniversalString.cs
@@ -72,6 +72,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerUniversalString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerUniversalString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerUniversalString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerUniversalString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
         public DerUniversalString(byte[] contents)
diff --git a/crypto/src/asn1/DerVideotexString.cs b/crypto/src/asn1/DerVideotexString.cs
index de236e195..086fdbe94 100644
--- a/crypto/src/asn1/DerVideotexString.cs
+++ b/crypto/src/asn1/DerVideotexString.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerVideotexString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerVideotexString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerVideotexString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerVideotexString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
         public DerVideotexString(byte[] contents)
diff --git a/crypto/src/asn1/DerVisibleString.cs b/crypto/src/asn1/DerVisibleString.cs
index 55bfe8604..9eec322e0 100644
--- a/crypto/src/asn1/DerVisibleString.cs
+++ b/crypto/src/asn1/DerVisibleString.cs
@@ -68,6 +68,23 @@ namespace Org.BouncyCastle.Asn1
             return (DerVisibleString)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static DerVisibleString GetOptional(Asn1Encodable element)
+        {
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is DerVisibleString existing)
+                return existing;
+
+            if (element is IAsn1Convertible asn1Convertible && !(element is Asn1Object) &&
+                asn1Convertible.ToAsn1Object() is DerVisibleString converted)
+            {
+                return converted;
+            }
+
+            return null;
+        }
+
         private readonly byte[] m_contents;
 
         public DerVisibleString(string str)