summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/Asn1GeneralizedTime.cs9
-rw-r--r--crypto/src/asn1/Asn1Null.cs22
-rw-r--r--crypto/src/asn1/Asn1ObjectDescriptor.cs22
-rw-r--r--crypto/src/asn1/Asn1OctetString.cs23
-rw-r--r--crypto/src/asn1/Asn1OutputStream.cs16
-rw-r--r--crypto/src/asn1/Asn1RelativeOid.cs22
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs23
-rw-r--r--crypto/src/asn1/Asn1Set.cs23
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs21
-rw-r--r--crypto/src/asn1/ConstructedBitStream.cs52
-rw-r--r--crypto/src/asn1/ConstructedOctetStream.cs52
-rw-r--r--crypto/src/asn1/DERExternal.cs22
-rw-r--r--crypto/src/asn1/DefiniteLengthInputStream.cs21
-rw-r--r--crypto/src/asn1/DerBMPString.cs22
-rw-r--r--crypto/src/asn1/DerBitString.cs23
-rw-r--r--crypto/src/asn1/DerBoolean.cs22
-rw-r--r--crypto/src/asn1/DerEnumerated.cs22
-rw-r--r--crypto/src/asn1/DerGeneralString.cs22
-rw-r--r--crypto/src/asn1/DerGraphicString.cs22
-rw-r--r--crypto/src/asn1/DerIA5String.cs22
-rw-r--r--crypto/src/asn1/DerInteger.cs22
-rw-r--r--crypto/src/asn1/DerNumericString.cs22
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs22
-rw-r--r--crypto/src/asn1/DerPrintableString.cs22
-rw-r--r--crypto/src/asn1/DerT61String.cs22
-rw-r--r--crypto/src/asn1/DerUTF8String.cs22
-rw-r--r--crypto/src/asn1/DerUniversalString.cs25
-rw-r--r--crypto/src/asn1/DerVideotexString.cs22
-rw-r--r--crypto/src/asn1/DerVisibleString.cs25
-rw-r--r--crypto/src/asn1/IndefiniteLengthInputStream.cs23
-rw-r--r--crypto/src/asn1/cmp/CertReqTemplateContent.cs5
-rw-r--r--crypto/src/asn1/cmp/CmpObjectIdentifiers.cs3
-rw-r--r--crypto/src/asn1/cmp/CrlSource.cs2
-rw-r--r--crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs5
-rw-r--r--crypto/src/asn1/cms/OtherRevocationInfoFormat.cs8
-rw-r--r--crypto/src/asn1/cms/Time.cs8
-rw-r--r--crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs11
-rw-r--r--crypto/src/asn1/x509/KeyPurposeId.cs90
-rw-r--r--crypto/src/asn1/x509/Time.cs8
39 files changed, 554 insertions, 296 deletions
diff --git a/crypto/src/asn1/Asn1GeneralizedTime.cs b/crypto/src/asn1/Asn1GeneralizedTime.cs
index e844c8ca2..139384c1a 100644
--- a/crypto/src/asn1/Asn1GeneralizedTime.cs
+++ b/crypto/src/asn1/Asn1GeneralizedTime.cs
@@ -11,8 +11,7 @@ namespace Org.BouncyCastle.Asn1
      * Base class representing the ASN.1 GeneralizedTime type.
      * <p>
      * The main difference between these and UTC time is a 4 digit year.
-     * </p>
-     * <p>
+     * </p><p>
      * One second resolution date+time on UTC timezone (Z)
      * with 4 digit year (valid from 0001 to 9999).
      * </p><p>
@@ -24,18 +23,18 @@ namespace Org.BouncyCastle.Asn1
      *
      * <h3>11: Restrictions on BER employed by both CER and DER</h3>
      * <h4>11.7 GeneralizedTime </h4>
-     * <p>
+     * </p><p>
      * <b>11.7.1</b> The encoding shall terminate with a "Z",
      * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on
      * GeneralizedTime.
      * </p><p>
      * <b>11.7.2</b> The seconds element shall always be present.
-     * </p>
-     * <p>
+     * </p><p>
      * <b>11.7.3</b> The fractional-seconds elements, if present,
      * shall omit all trailing zeros; if the elements correspond to 0,
      * they shall be wholly omitted, and the decimal point element also
      * shall be omitted.
+     * </p>
      */
     public class Asn1GeneralizedTime
         : Asn1Object
diff --git a/crypto/src/asn1/Asn1Null.cs b/crypto/src/asn1/Asn1Null.cs
index 9ea9b4375..77304c0fb 100644
--- a/crypto/src/asn1/Asn1Null.cs
+++ b/crypto/src/asn1/Asn1Null.cs
@@ -25,21 +25,23 @@ namespace Org.BouncyCastle.Asn1
 
         public static Asn1Null GetInstance(object obj)
         {
-            if (obj == null || obj is Asn1Null)
-            {
-                return (Asn1Null)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1Null asn1Null)
+                return asn1Null;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is Asn1Null)
-                    return (Asn1Null)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1Null converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (Asn1Null)Meta.Instance.FromByteArray((byte[])obj);
+                    return (Asn1Null)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/Asn1ObjectDescriptor.cs b/crypto/src/asn1/Asn1ObjectDescriptor.cs
index 9c99f441e..13521a744 100644
--- a/crypto/src/asn1/Asn1ObjectDescriptor.cs
+++ b/crypto/src/asn1/Asn1ObjectDescriptor.cs
@@ -36,21 +36,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1ObjectDescriptor GetInstance(object obj)
         {
-            if (obj == null || obj is Asn1ObjectDescriptor)
-            {
-                return (Asn1ObjectDescriptor)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1ObjectDescriptor asn1ObjectDescriptor)
+                return asn1ObjectDescriptor;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is Asn1ObjectDescriptor)
-                    return (Asn1ObjectDescriptor)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1ObjectDescriptor converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (Asn1ObjectDescriptor)Meta.Instance.FromByteArray((byte[])obj);
+                    return (Asn1ObjectDescriptor)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/Asn1OctetString.cs b/crypto/src/asn1/Asn1OctetString.cs
index d34686134..8f7da8800 100644
--- a/crypto/src/asn1/Asn1OctetString.cs
+++ b/crypto/src/asn1/Asn1OctetString.cs
@@ -36,22 +36,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1OctetString GetInstance(object obj)
         {
-            if (obj == null || obj is Asn1OctetString)
-            {
-                return (Asn1OctetString)obj;
-            }
-            //else if (obj is Asn1OctetStringParser)
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1OctetString asn1OctetString)
+                return asn1OctetString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is Asn1OctetString)
-                    return (Asn1OctetString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1OctetString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (Asn1OctetString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (Asn1OctetString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs
index 59178ea31..163e3848c 100644
--- a/crypto/src/asn1/Asn1OutputStream.cs
+++ b/crypto/src/asn1/Asn1OutputStream.cs
@@ -1,5 +1,10 @@
 using System;
 using System.IO;
+using System.Diagnostics;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Buffers.Binary;
+using System.Numerics;
+#endif
 
 using Org.BouncyCastle.Utilities.IO;
 
@@ -73,15 +78,19 @@ namespace Org.BouncyCastle.Asn1
         {
             if (dl < 128)
             {
+                Debug.Assert(dl >= 0);
                 WriteByte((byte)dl);
                 return;
             }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            Span<byte> stack = stackalloc byte[5];
+            Span<byte> encoding = stackalloc byte[5];
+            BinaryPrimitives.WriteUInt32BigEndian(encoding[1..], (uint)dl);
+            int leadingZeroBytes = BitOperations.LeadingZeroCount((uint)dl) / 8;
+            encoding[leadingZeroBytes] = (byte)(0x84 - leadingZeroBytes);
+            Write(encoding[leadingZeroBytes..]);
 #else
             byte[] stack = new byte[5];
-#endif
             int pos = stack.Length;
 
             do
@@ -94,9 +103,6 @@ namespace Org.BouncyCastle.Asn1
             int count = stack.Length - pos;
             stack[--pos] = (byte)(0x80 | count);
 
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            Write(stack[pos..]);
-#else
             Write(stack, pos, count + 1);
 #endif
         }
diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs
index a1997864d..3c4bf237a 100644
--- a/crypto/src/asn1/Asn1RelativeOid.cs
+++ b/crypto/src/asn1/Asn1RelativeOid.cs
@@ -29,21 +29,23 @@ namespace Org.BouncyCastle.Asn1
 
         public static Asn1RelativeOid GetInstance(object obj)
         {
-            if (obj == null || obj is Asn1RelativeOid)
-            {
-                return (Asn1RelativeOid)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1RelativeOid asn1RelativeOid)
+                return asn1RelativeOid;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is Asn1RelativeOid)
-                    return (Asn1RelativeOid)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1RelativeOid converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (Asn1RelativeOid)FromByteArray((byte[])obj);
+                    return (Asn1RelativeOid)FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index 1a123e26d..a8191de99 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -30,22 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1Sequence GetInstance(object obj)
         {
-            if (obj == null || obj is Asn1Sequence)
-            {
-                return (Asn1Sequence)obj;
-            }
-            //else if (obj is Asn1SequenceParser)
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1Sequence asn1Sequence)
+                return asn1Sequence;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is Asn1Sequence)
-                    return (Asn1Sequence)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1Sequence converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (Asn1Sequence)Meta.Instance.FromByteArray((byte[])obj);
+                    return (Asn1Sequence)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index faec50eb0..2b3810e43 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -31,22 +31,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static Asn1Set GetInstance(object obj)
         {
-            if (obj == null || obj is Asn1Set)
-            {
-                return (Asn1Set)obj;
-            }
-            //else if (obj is Asn1SetParser)
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1Set asn1Set)
+                return asn1Set;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is Asn1Set)
-                    return (Asn1Set)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1Set converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (Asn1Set)Meta.Instance.FromByteArray((byte[])obj);
+                    return (Asn1Set)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index 46aa137a8..63ab6a5d0 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -21,22 +21,23 @@ namespace Org.BouncyCastle.Asn1
 
         public static Asn1TaggedObject GetInstance(object obj)
 		{
-            if (obj == null || obj is Asn1TaggedObject) 
-            {
-                return (Asn1TaggedObject)obj;
-            }
-            //else if (obj is Asn1TaggedObjectParser)
-            else if (obj is IAsn1Convertible asn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1TaggedObject asn1TaggedObject)
+                return asn1TaggedObject;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
                 Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
-                if (asn1Object is Asn1TaggedObject taggedObject)
-                    return taggedObject;
+                if (asn1Object is Asn1TaggedObject converted)
+                    return converted;
             }
-            else if (obj is byte[] byteArray)
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return CheckedCast(FromByteArray(byteArray));
+                    return CheckedCast(FromByteArray(bytes));
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/ConstructedBitStream.cs b/crypto/src/asn1/ConstructedBitStream.cs
index 49f54fc1b..f089dac75 100644
--- a/crypto/src/asn1/ConstructedBitStream.cs
+++ b/crypto/src/asn1/ConstructedBitStream.cs
@@ -33,6 +33,9 @@ namespace Org.BouncyCastle.Asn1
         {
             Streams.ValidateBufferArguments(buffer, offset, count);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return Read(buffer.AsSpan(offset, count));
+#else
             if (count < 1)
                 return 0;
 
@@ -75,8 +78,57 @@ namespace Org.BouncyCastle.Asn1
                     m_currentStream = m_currentParser.GetBitStream();
                 }
             }
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public override int Read(Span<byte> buffer)
+        {
+            if (buffer.IsEmpty)
+                return 0;
+
+            if (m_currentStream == null)
+            {
+                if (!m_first)
+                    return 0;
+
+                m_currentParser = GetNextParser();
+                if (m_currentParser == null)
+                    return 0;
+
+                m_first = false;
+                m_currentStream = m_currentParser.GetBitStream();
+            }
+
+            int totalRead = 0;
+
+            for (;;)
+            {
+                int numRead = m_currentStream.Read(buffer[totalRead..]);
+
+                if (numRead > 0)
+                {
+                    totalRead += numRead;
+
+                    if (totalRead == buffer.Length)
+                        return totalRead;
+                }
+                else
+                {
+                    m_padBits = m_currentParser.PadBits;
+                    m_currentParser = GetNextParser();
+                    if (m_currentParser == null)
+                    {
+                        m_currentStream = null;
+                        return totalRead;
+                    }
+
+                    m_currentStream = m_currentParser.GetBitStream();
+                }
+            }
+        }
+#endif
+
         public override int ReadByte()
         {
             if (m_currentStream == null)
diff --git a/crypto/src/asn1/ConstructedOctetStream.cs b/crypto/src/asn1/ConstructedOctetStream.cs
index 12aa14e74..d005f9fe7 100644
--- a/crypto/src/asn1/ConstructedOctetStream.cs
+++ b/crypto/src/asn1/ConstructedOctetStream.cs
@@ -1,3 +1,4 @@
+using System;
 using System.IO;
 
 using Org.BouncyCastle.Utilities;
@@ -22,6 +23,9 @@ namespace Org.BouncyCastle.Asn1
 		{
 			Streams.ValidateBufferArguments(buffer, offset, count);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			return Read(buffer.AsSpan(offset, count));
+#else
 			if (count < 1)
                 return 0;
 
@@ -63,8 +67,56 @@ namespace Org.BouncyCastle.Asn1
 					m_currentStream = next.GetOctetStream();
 				}
 			}
+#endif
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public override int Read(Span<byte> buffer)
+		{
+			if (buffer.IsEmpty)
+                return 0;
+
+			if (m_currentStream == null)
+			{
+				if (!m_first)
+					return 0;
+
+                Asn1OctetStringParser next = GetNextParser();
+                if (next == null)
+                    return 0;
+
+				m_first = false;
+				m_currentStream = next.GetOctetStream();
+			}
+
+			int totalRead = 0;
+
+			for (;;)
+			{
+				int numRead = m_currentStream.Read(buffer[totalRead..]);
+
+				if (numRead > 0)
+				{
+					totalRead += numRead;
+
+					if (totalRead == buffer.Length)
+						return totalRead;
+				}
+				else
+				{
+                    Asn1OctetStringParser next = GetNextParser();
+                    if (next == null)
+					{
+						m_currentStream = null;
+						return totalRead;
+					}
+
+					m_currentStream = next.GetOctetStream();
+				}
+			}
+		}
+#endif
+
 		public override int ReadByte()
 		{
 			if (m_currentStream == null)
diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs
index 9fba95165..207930062 100644
--- a/crypto/src/asn1/DERExternal.cs
+++ b/crypto/src/asn1/DERExternal.cs
@@ -25,21 +25,23 @@ namespace Org.BouncyCastle.Asn1
 
         public static DerExternal GetInstance(object obj)
         {
-            if (obj == null || obj is DerExternal)
-            {
-                return (DerExternal)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerExternal derExternal)
+                return derExternal;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerExternal)
-                    return (DerExternal)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerExternal converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerExternal)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerExternal)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DefiniteLengthInputStream.cs b/crypto/src/asn1/DefiniteLengthInputStream.cs
index ed5bd2446..89f0d5a62 100644
--- a/crypto/src/asn1/DefiniteLengthInputStream.cs
+++ b/crypto/src/asn1/DefiniteLengthInputStream.cs
@@ -79,6 +79,27 @@ namespace Org.BouncyCastle.Asn1
             return numRead;
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public override int Read(Span<byte> buffer)
+        {
+            if (_remaining == 0)
+                return 0;
+
+            int toRead = System.Math.Min(buffer.Length, _remaining);
+            int numRead = _in.Read(buffer[..toRead]);
+
+            if (numRead < 1)
+                throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+            if ((_remaining -= numRead) == 0)
+            {
+                SetParentEofDetect();
+            }
+
+            return numRead;
+        }
+#endif
+
         internal void ReadAllIntoByteArray(byte[] buf)
         {
             if (_remaining != buf.Length)
diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs
index a289eed1b..284a4b830 100644
--- a/crypto/src/asn1/DerBMPString.cs
+++ b/crypto/src/asn1/DerBMPString.cs
@@ -31,21 +31,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerBmpString GetInstance(object obj)
         {
-            if (obj == null || obj is DerBmpString)
-            {
-                return (DerBmpString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerBmpString derBmpString)
+                return derBmpString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerBmpString)
-                    return (DerBmpString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerBmpString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerBmpString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerBmpString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
index 8aab88353..44b3bb95a 100644
--- a/crypto/src/asn1/DerBitString.cs
+++ b/crypto/src/asn1/DerBitString.cs
@@ -38,22 +38,23 @@ namespace Org.BouncyCastle.Asn1
 		 */
 		public static DerBitString GetInstance(object obj)
 		{
-			if (obj == null || obj is DerBitString)
-			{
-				return (DerBitString)obj;
-			}
-            //else if (obj is Asn1BitStringParser)
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+			if (obj is DerBitString derBitString)
+				return derBitString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerBitString)
-                    return (DerBitString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerBitString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return GetInstance(FromByteArray((byte[])obj));
+                    return GetInstance(FromByteArray(bytes));
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerBoolean.cs b/crypto/src/asn1/DerBoolean.cs
index ad578ae80..6256db6e0 100644
--- a/crypto/src/asn1/DerBoolean.cs
+++ b/crypto/src/asn1/DerBoolean.cs
@@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerBoolean GetInstance(object obj)
         {
-            if (obj == null || obj is DerBoolean)
-            {
-                return (DerBoolean)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerBoolean derBoolean)
+                return derBoolean;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerBoolean)
-                    return (DerBoolean)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerBoolean converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerBoolean)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerBoolean)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index 920b3dc8e..b85c5a43e 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -28,21 +28,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerEnumerated GetInstance(object obj)
         {
-            if (obj == null || obj is DerEnumerated)
-            {
-                return (DerEnumerated)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerEnumerated derEnumerated)
+                return derEnumerated;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerEnumerated)
-                    return (DerEnumerated)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerEnumerated converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerEnumerated)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerEnumerated)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerGeneralString.cs b/crypto/src/asn1/DerGeneralString.cs
index e6637732a..6a378307d 100644
--- a/crypto/src/asn1/DerGeneralString.cs
+++ b/crypto/src/asn1/DerGeneralString.cs
@@ -22,21 +22,23 @@ namespace Org.BouncyCastle.Asn1
 
         public static DerGeneralString GetInstance(object obj)
         {
-            if (obj == null || obj is DerGeneralString)
-            {
-                return (DerGeneralString) obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerGeneralString derGeneralString)
+                return derGeneralString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerGeneralString)
-                    return (DerGeneralString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerGeneralString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerGeneralString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerGeneralString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerGraphicString.cs b/crypto/src/asn1/DerGraphicString.cs
index cb32d14eb..85330eb33 100644
--- a/crypto/src/asn1/DerGraphicString.cs
+++ b/crypto/src/asn1/DerGraphicString.cs
@@ -29,21 +29,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerGraphicString GetInstance(object obj)
         {
-            if (obj == null || obj is DerGraphicString)
-            {
-                return (DerGraphicString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerGraphicString derGraphicString)
+                return derGraphicString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerGraphicString)
-                    return (DerGraphicString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerGraphicString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerGraphicString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerGraphicString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerIA5String.cs b/crypto/src/asn1/DerIA5String.cs
index a56879831..de2860130 100644
--- a/crypto/src/asn1/DerIA5String.cs
+++ b/crypto/src/asn1/DerIA5String.cs
@@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerIA5String GetInstance(object obj)
         {
-            if (obj == null || obj is DerIA5String)
-            {
-                return (DerIA5String)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerIA5String derIA5String)
+                return derIA5String;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerIA5String)
-                    return (DerIA5String)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerIA5String converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerIA5String)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerIA5String)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs
index c8d4e47df..05a790743 100644
--- a/crypto/src/asn1/DerInteger.cs
+++ b/crypto/src/asn1/DerInteger.cs
@@ -42,21 +42,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerInteger GetInstance(object obj)
         {
-            if (obj == null || obj is DerInteger)
-            {
-                return (DerInteger)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerInteger derInteger)
+                return derInteger;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerInteger)
-                    return (DerInteger)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerInteger converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerInteger)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerInteger)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerNumericString.cs b/crypto/src/asn1/DerNumericString.cs
index 693ff7d6e..819d946b1 100644
--- a/crypto/src/asn1/DerNumericString.cs
+++ b/crypto/src/asn1/DerNumericString.cs
@@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerNumericString GetInstance(object obj)
         {
-            if (obj == null || obj is DerNumericString)
-            {
-                return (DerNumericString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerNumericString derNumericString)
+                return derNumericString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerNumericString)
-                    return (DerNumericString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerNumericString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerNumericString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerNumericString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index b10f8f8b6..cb5771958 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -34,21 +34,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerObjectIdentifier GetInstance(object obj)
         {
-            if (obj == null || obj is DerObjectIdentifier)
-            {
-                return (DerObjectIdentifier)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerObjectIdentifier derObjectIdentifier)
+                return derObjectIdentifier;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerObjectIdentifier)
-                    return (DerObjectIdentifier)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerObjectIdentifier converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerObjectIdentifier)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerObjectIdentifier)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerPrintableString.cs b/crypto/src/asn1/DerPrintableString.cs
index 3c44a2d52..5830afa47 100644
--- a/crypto/src/asn1/DerPrintableString.cs
+++ b/crypto/src/asn1/DerPrintableString.cs
@@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerPrintableString GetInstance(object obj)
         {
-            if (obj == null || obj is DerPrintableString)
-            {
-                return (DerPrintableString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerPrintableString derPrintableString)
+                return derPrintableString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerPrintableString)
-                    return (DerPrintableString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerPrintableString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerPrintableString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerPrintableString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerT61String.cs b/crypto/src/asn1/DerT61String.cs
index a0e4f1d22..45f57ae0a 100644
--- a/crypto/src/asn1/DerT61String.cs
+++ b/crypto/src/asn1/DerT61String.cs
@@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerT61String GetInstance(object obj)
         {
-            if (obj == null || obj is DerT61String)
-            {
-                return (DerT61String)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerT61String derT61String)
+                return derT61String;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerT61String)
-                    return (DerT61String)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerT61String converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerT61String)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerT61String)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerUTF8String.cs b/crypto/src/asn1/DerUTF8String.cs
index d15a19d39..9472f5082 100644
--- a/crypto/src/asn1/DerUTF8String.cs
+++ b/crypto/src/asn1/DerUTF8String.cs
@@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerUtf8String GetInstance(object obj)
         {
-            if (obj == null || obj is DerUtf8String)
-            {
-                return (DerUtf8String)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerUtf8String derUtf8String)
+                return derUtf8String;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerUtf8String)
-                    return (DerUtf8String)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerUtf8String converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerUtf8String)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerUtf8String)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerUniversalString.cs b/crypto/src/asn1/DerUniversalString.cs
index e4e93bd7d..1183ed1f3 100644
--- a/crypto/src/asn1/DerUniversalString.cs
+++ b/crypto/src/asn1/DerUniversalString.cs
@@ -32,24 +32,25 @@ namespace Org.BouncyCastle.Asn1
          *
          * @exception ArgumentException if the object cannot be converted.
          */
-        public static DerUniversalString GetInstance(
-            object obj)
+        public static DerUniversalString GetInstance(object obj)
         {
-            if (obj == null || obj is DerUniversalString)
-            {
-                return (DerUniversalString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerUniversalString derUniversalString)
+                return derUniversalString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerUniversalString)
-                    return (DerUniversalString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerUniversalString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerUniversalString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerUniversalString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerVideotexString.cs b/crypto/src/asn1/DerVideotexString.cs
index a5fbe0602..636af0499 100644
--- a/crypto/src/asn1/DerVideotexString.cs
+++ b/crypto/src/asn1/DerVideotexString.cs
@@ -29,21 +29,23 @@ namespace Org.BouncyCastle.Asn1
          */
         public static DerVideotexString GetInstance(object obj)
         {
-            if (obj == null || obj is DerVideotexString)
-            {
-                return (DerVideotexString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerVideotexString derVideotexString)
+                return derVideotexString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerVideotexString)
-                    return (DerVideotexString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerVideotexString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerVideotexString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerVideotexString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/DerVisibleString.cs b/crypto/src/asn1/DerVisibleString.cs
index 359370040..77fe54c9a 100644
--- a/crypto/src/asn1/DerVisibleString.cs
+++ b/crypto/src/asn1/DerVisibleString.cs
@@ -28,24 +28,25 @@ namespace Org.BouncyCastle.Asn1
          *
          * @exception ArgumentException if the object cannot be converted.
          */
-        public static DerVisibleString GetInstance(
-            object obj)
+        public static DerVisibleString GetInstance(object obj)
         {
-            if (obj == null || obj is DerVisibleString)
-            {
-                return (DerVisibleString)obj;
-            }
-            else if (obj is IAsn1Convertible)
+            if (obj == null)
+                return null;
+
+            if (obj is DerVisibleString derVisibleString)
+                return derVisibleString;
+
+            if (obj is IAsn1Convertible asn1Convertible)
             {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerVisibleString)
-                    return (DerVisibleString)asn1Object;
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is DerVisibleString converted)
+                    return converted;
             }
-            else if (obj is byte[])
+            else if (obj is byte[] bytes)
             {
                 try
                 {
-                    return (DerVisibleString)Meta.Instance.FromByteArray((byte[])obj);
+                    return (DerVisibleString)Meta.Instance.FromByteArray(bytes);
                 }
                 catch (IOException e)
                 {
diff --git a/crypto/src/asn1/IndefiniteLengthInputStream.cs b/crypto/src/asn1/IndefiniteLengthInputStream.cs
index 1c8bd9a15..e192e9e8b 100644
--- a/crypto/src/asn1/IndefiniteLengthInputStream.cs
+++ b/crypto/src/asn1/IndefiniteLengthInputStream.cs
@@ -57,7 +57,28 @@ namespace Org.BouncyCastle.Asn1
 			return numRead + 1;
 		}
 
-		public override int ReadByte()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public override int Read(Span<byte> buffer)
+        {
+            // Only use this optimisation if we aren't checking for 00
+            if (_eofOn00 || buffer.Length <= 1)
+                return base.Read(buffer);
+
+            if (_lookAhead < 0)
+                return 0;
+
+            int numRead = _in.Read(buffer[1..]);
+            if (numRead <= 0)
+                throw new EndOfStreamException();
+
+            buffer[0] = (byte)_lookAhead;
+            _lookAhead = RequireByte();
+
+            return numRead + 1;
+        }
+#endif
+
+        public override int ReadByte()
 		{
             if (_eofOn00 && _lookAhead <= 0)
             {
diff --git a/crypto/src/asn1/cmp/CertReqTemplateContent.cs b/crypto/src/asn1/cmp/CertReqTemplateContent.cs
index b229cd28b..c25c71ad1 100644
--- a/crypto/src/asn1/cmp/CertReqTemplateContent.cs
+++ b/crypto/src/asn1/cmp/CertReqTemplateContent.cs
@@ -9,12 +9,13 @@ namespace Org.BouncyCastle.Asn1.Cmp
      * GenRep:    {id-it 19}, CertReqTemplateContent | &lt; absent &gt;
      * <p>
      * CertReqTemplateValue  ::= CertReqTemplateContent
-     * <p>
+     * </p><p>
      * CertReqTemplateContent ::= SEQUENCE {
      * certTemplate           CertTemplate,
      * keySpec                Controls OPTIONAL }
-     * <p>
+     * </p><p>
      * Controls  ::= SEQUENCE SIZE (1..MAX) OF AttributeTypeAndValue
+     * </p>
      */
     public class CertReqTemplateContent
         : Asn1Encodable
diff --git a/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs b/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
index fa83841a4..1b3227c47 100644
--- a/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
+++ b/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
@@ -234,8 +234,9 @@ namespace Org.BouncyCastle.Asn1.Cmp
          * 1.2.840.113549.1.9.16.1.21
          * <p>
          * id-ct   OBJECT IDENTIFIER ::= { id-smime  1 }  -- content types
-         * <p>
+         * </p><p>
          * id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21}
+         * </p>
          */
         public static readonly DerObjectIdentifier ct_encKeyWithID = new DerObjectIdentifier("1.2.840.113549.1.9.16.1.21");
 
diff --git a/crypto/src/asn1/cmp/CrlSource.cs b/crypto/src/asn1/cmp/CrlSource.cs
index 13aaa526a..9e2526ec2 100644
--- a/crypto/src/asn1/cmp/CrlSource.cs
+++ b/crypto/src/asn1/cmp/CrlSource.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
      * CRLSource ::= CHOICE {
      * dpn          [0] DistributionPointName,
      * issuer       [1] GeneralNames }
-     * <p>
+     * </p>
      */
     public class CrlSource
         : Asn1Encodable, IAsn1Choice
diff --git a/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs b/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs
index b1eaf616d..696b08b94 100644
--- a/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs
+++ b/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs
@@ -7,14 +7,15 @@ namespace Org.BouncyCastle.Asn1.Cmp
      * GenRep:    {id-it 18}, RootCaKeyUpdateContent | &lt; absent &gt;
      * <p>
      * RootCaCertValue ::= CMPCertificate
-     * <p>
+     * </p><p>
      * RootCaKeyUpdateValue ::= RootCaKeyUpdateContent
-     * <p>
+     * </p><p>
      * RootCaKeyUpdateContent ::= SEQUENCE {
      * newWithNew       CMPCertificate,
      * newWithOld   [0] CMPCertificate OPTIONAL,
      * oldWithNew   [1] CMPCertificate OPTIONAL
      * }
+     * </p>
      */
     public class RootCaKeyUpdateContent
         : Asn1Encodable
diff --git a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
index 78354896f..f6335cdac 100644
--- a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
+++ b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace Org.BouncyCastle.Asn1.Cms
+namespace Org.BouncyCastle.Asn1.Cms
 {
     public class OtherRevocationInfoFormat
         : Asn1Encodable
@@ -44,8 +42,8 @@ namespace Org.BouncyCastle.Asn1.Cms
          */
         public static OtherRevocationInfoFormat GetInstance(object obj)
         {
-            if (obj is OtherRevocationInfoFormat)
-                return (OtherRevocationInfoFormat)obj;
+            if (obj is OtherRevocationInfoFormat otherRevocationInfoFormat)
+                return otherRevocationInfoFormat;
             if (obj != null)
                 return new OtherRevocationInfoFormat(Asn1Sequence.GetInstance(obj));
             return null;
diff --git a/crypto/src/asn1/cms/Time.cs b/crypto/src/asn1/cms/Time.cs
index 89f1e4dae..67c73285b 100644
--- a/crypto/src/asn1/cms/Time.cs
+++ b/crypto/src/asn1/cms/Time.cs
@@ -35,17 +35,15 @@ namespace Org.BouncyCastle.Asn1.Cms
          */
         public Time(DateTime date)
         {
-            string d = date.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+            DateTime d = date.ToUniversalTime();
 
-			int year = int.Parse(d.Substring(0, 4));
-
-			if (year < 1950 || year > 2049)
+			if (d.Year < 1950 || d.Year > 2049)
             {
                 time = new DerGeneralizedTime(d);
             }
             else
             {
-                time = new DerUtcTime(d.Substring(2));
+                time = new DerUtcTime(d);
             }
         }
 
diff --git a/crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs b/crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs
new file mode 100644
index 000000000..e7208bab2
--- /dev/null
+++ b/crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Asn1.Cryptlib
+{
+    internal class CryptlibObjectIdentifiers
+    {
+        internal static readonly DerObjectIdentifier cryptlib = new DerObjectIdentifier("1.3.6.1.4.1.3029");
+
+        internal static readonly DerObjectIdentifier ecc = cryptlib.Branch("1.5");
+
+        internal static readonly DerObjectIdentifier curvey25519 = ecc.Branch("1");
+    }
+}
diff --git a/crypto/src/asn1/x509/KeyPurposeId.cs b/crypto/src/asn1/x509/KeyPurposeId.cs
index 1a564b97a..d0b9bb7e6 100644
--- a/crypto/src/asn1/x509/KeyPurposeId.cs
+++ b/crypto/src/asn1/x509/KeyPurposeId.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace Org.BouncyCastle.Asn1.X509
 {
     /**
@@ -9,30 +11,86 @@ namespace Org.BouncyCastle.Asn1.X509
     public sealed class KeyPurposeID
         : DerObjectIdentifier
     {
-        private const string IdKP = "1.3.6.1.5.5.7.3";
+        private const string id_kp = "1.3.6.1.5.5.7.3";
 
-		private KeyPurposeID(
-			string id)
+		private KeyPurposeID(string id)
 			: base(id)
         {
         }
 
 		public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0");
-        public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1");
-        public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2");
-        public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3");
-        public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4");
-        public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5");
-        public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6");
-        public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7");
-        public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8");
-        public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9");
-
-		//
+
+        public static readonly KeyPurposeID id_kp_serverAuth = new KeyPurposeID(id_kp + ".1");
+        public static readonly KeyPurposeID id_kp_clientAuth = new KeyPurposeID(id_kp + ".2");
+        public static readonly KeyPurposeID id_kp_codeSigning = new KeyPurposeID(id_kp + ".3");
+        public static readonly KeyPurposeID id_kp_emailProtection = new KeyPurposeID(id_kp + ".4");
+        public static readonly KeyPurposeID id_kp_ipsecEndSystem = new KeyPurposeID(id_kp + ".5");
+        public static readonly KeyPurposeID id_kp_ipsecTunnel = new KeyPurposeID(id_kp + ".6");
+        public static readonly KeyPurposeID id_kp_ipsecUser = new KeyPurposeID(id_kp + ".7");
+        public static readonly KeyPurposeID id_kp_timeStamping = new KeyPurposeID(id_kp + ".8");
+        public static readonly KeyPurposeID id_kp_OCSPSigning = new KeyPurposeID(id_kp + ".9");
+        public static readonly KeyPurposeID id_kp_dvcs = new KeyPurposeID(id_kp + ".10");
+        public static readonly KeyPurposeID id_kp_sbgpCertAAServerAuth = new KeyPurposeID(id_kp + ".11");
+        public static readonly KeyPurposeID id_kp_scvp_responder = new KeyPurposeID(id_kp + ".12");
+        public static readonly KeyPurposeID id_kp_eapOverPPP = new KeyPurposeID(id_kp + ".13");
+        public static readonly KeyPurposeID id_kp_eapOverLAN = new KeyPurposeID(id_kp + ".14");
+        public static readonly KeyPurposeID id_kp_scvpServer = new KeyPurposeID(id_kp + ".15");
+        public static readonly KeyPurposeID id_kp_scvpClient = new KeyPurposeID(id_kp + ".16");
+        public static readonly KeyPurposeID id_kp_ipsecIKE = new KeyPurposeID(id_kp + ".17");
+        public static readonly KeyPurposeID id_kp_capwapAC = new KeyPurposeID(id_kp + ".18");
+        public static readonly KeyPurposeID id_kp_capwapWTP = new KeyPurposeID(id_kp + ".19");
+
+        public static readonly KeyPurposeID id_kp_cmcCA = new KeyPurposeID(id_kp + ".27");
+        public static readonly KeyPurposeID id_kp_cmcRA = new KeyPurposeID(id_kp + ".28");
+        public static readonly KeyPurposeID id_kp_cmKGA = new KeyPurposeID(id_kp + ".32");
+
+        //
         // microsoft key purpose ids
         //
-        public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+        public static readonly KeyPurposeID id_kp_smartcardlogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+
+        public static readonly KeyPurposeID id_kp_macAddress = new KeyPurposeID("1.3.6.1.1.1.1.22");
+
+        /// <summary>Microsoft Server Gated Crypto (msSGC).</summary>
+        /// <remarks>see https://www.alvestrand.no/objectid/1.3.6.1.4.1.311.10.3.3.html</remarks>
+        public static readonly KeyPurposeID id_kp_msSGC = new KeyPurposeID("1.3.6.1.4.1.311.10.3.3");
+
+        private const string id_pkinit = "1.3.6.1.5.2.3";
+
+        public static readonly KeyPurposeID scSysNodeNumber = new KeyPurposeID(id_pkinit + ".0");
+        public static readonly KeyPurposeID id_pkinit_authData = new KeyPurposeID(id_pkinit + ".1");
+        public static readonly KeyPurposeID id_pkinit_DHKeyData = new KeyPurposeID(id_pkinit + ".2");
+        public static readonly KeyPurposeID id_pkinit_rkeyData = new KeyPurposeID(id_pkinit + ".3");
+        public static readonly KeyPurposeID keyPurposeClientAuth = new KeyPurposeID(id_pkinit + ".4");
+        public static readonly KeyPurposeID keyPurposeKdc = new KeyPurposeID(id_pkinit + ".5");
+
+        /// <summary>Netscape Server Gated Crypto (nsSGC).</summary>
+        /// <remarks>see https://www.alvestrand.no/objectid/2.16.840.1.113730.4.1.html</remarks>
+        public static readonly KeyPurposeID id_kp_nsSGC = new KeyPurposeID("2.16.840.1.113730.4.1");
+
+        [Obsolete("Use 'id_kp_serverAuth' instead")]
+        public static readonly KeyPurposeID IdKPServerAuth = id_kp_serverAuth;
+        [Obsolete("Use 'id_kp_clientAuth' instead")]
+        public static readonly KeyPurposeID IdKPClientAuth = id_kp_clientAuth;
+        [Obsolete("Use 'id_kp_codeSigning' instead")]
+        public static readonly KeyPurposeID IdKPCodeSigning = id_kp_codeSigning;
+        [Obsolete("Use 'id_kp_emailProtection' instead")]
+        public static readonly KeyPurposeID IdKPEmailProtection = id_kp_emailProtection;
+        [Obsolete("Use 'id_kp_ipsecEndSystem' instead")]
+        public static readonly KeyPurposeID IdKPIpsecEndSystem = id_kp_ipsecEndSystem;
+        [Obsolete("Use 'id_kp_ipsecTunnel' instead")]
+        public static readonly KeyPurposeID IdKPIpsecTunnel = id_kp_ipsecTunnel;
+        [Obsolete("Use 'id_kp_ipsecUser' instead")]
+        public static readonly KeyPurposeID IdKPIpsecUser = id_kp_ipsecUser;
+        [Obsolete("Use 'id_kp_timeStamping' instead")]
+        public static readonly KeyPurposeID IdKPTimeStamping = id_kp_timeStamping;
+        [Obsolete("Use 'id_kp_OCSPSigning' instead")]
+        public static readonly KeyPurposeID IdKPOcspSigning = id_kp_OCSPSigning;
+
+        [Obsolete("Use 'id_kp_smartcardlogon' instead")]
+        public static readonly KeyPurposeID IdKPSmartCardLogon = id_kp_smartcardlogon;
 
-        public static readonly KeyPurposeID IdKPMacAddress = new KeyPurposeID("1.3.6.1.1.1.1.22");
+        [Obsolete("Use 'id_kp_macAddress' instead")]
+        public static readonly KeyPurposeID IdKPMacAddress = id_kp_macAddress;
     }
 }
diff --git a/crypto/src/asn1/x509/Time.cs b/crypto/src/asn1/x509/Time.cs
index 1a6ac15c0..8260043aa 100644
--- a/crypto/src/asn1/x509/Time.cs
+++ b/crypto/src/asn1/x509/Time.cs
@@ -35,17 +35,15 @@ namespace Org.BouncyCastle.Asn1.X509
          */
         public Time(DateTime date)
         {
-            string d = date.ToUniversalTime().ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+            DateTime d = date.ToUniversalTime();
 
-            int year = int.Parse(d.Substring(0, 4));
-
-            if (year < 1950 || year > 2049)
+            if (d.Year < 1950 || d.Year > 2049)
             {
                 time = new DerGeneralizedTime(d);
             }
             else
             {
-                time = new DerUtcTime(d.Substring(2));
+                time = new DerUtcTime(d);
             }
         }