summary refs log tree commit diff
path: root/crypto/src/asn1/Asn1RelativeOid.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/Asn1RelativeOid.cs')
-rw-r--r--crypto/src/asn1/Asn1RelativeOid.cs227
1 files changed, 135 insertions, 92 deletions
diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs
index 1d2ecb3df..f43a85479 100644
--- a/crypto/src/asn1/Asn1RelativeOid.cs
+++ b/crypto/src/asn1/Asn1RelativeOid.cs
@@ -24,6 +24,9 @@ namespace Org.BouncyCastle.Asn1
 
         public static Asn1RelativeOid FromContents(byte[] contents)
         {
+            if (contents == null)
+                throw new ArgumentNullException(nameof(contents));
+
             return CreatePrimitive(contents, true);
         }
 
@@ -61,10 +64,24 @@ namespace Org.BouncyCastle.Asn1
             return (Asn1RelativeOid)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
+        public static bool TryFromID(string identifier, out Asn1RelativeOid oid)
+        {
+            if (identifier == null)
+                throw new ArgumentNullException(nameof(identifier));
+            if (!IsValidIdentifier(identifier, 0))
+            {
+                oid = default;
+                return false;
+            }
+
+            oid = new Asn1RelativeOid(ParseIdentifier(identifier), identifier);
+            return true;
+        }
+
         private const long LongLimit = (long.MaxValue >> 7) - 0x7F;
 
-        private readonly string identifier;
-        private byte[] contents;
+        private readonly byte[] m_contents;
+        private string m_identifier;
 
         public Asn1RelativeOid(string identifier)
         {
@@ -73,7 +90,8 @@ namespace Org.BouncyCastle.Asn1
             if (!IsValidIdentifier(identifier, 0))
                 throw new FormatException("string " + identifier + " not a relative OID");
 
-            this.identifier = identifier;
+            m_contents = ParseIdentifier(identifier);
+            m_identifier = identifier;
         }
 
         private Asn1RelativeOid(Asn1RelativeOid oid, string branchID)
@@ -81,86 +99,92 @@ namespace Org.BouncyCastle.Asn1
             if (!IsValidIdentifier(branchID, 0))
                 throw new FormatException("string " + branchID + " not a valid relative OID branch");
 
-            this.identifier = oid.Id + "." + branchID;
+            m_contents = Arrays.Concatenate(oid.m_contents, ParseIdentifier(branchID));
+            m_identifier = oid.GetID() + "." + branchID;
         }
 
         private Asn1RelativeOid(byte[] contents, bool clone)
         {
-            this.identifier = ParseContents(contents);
-            this.contents = clone ? Arrays.Clone(contents) : contents;
+            if (!IsValidContents(contents))
+                throw new ArgumentException("invalid relative OID contents", nameof(contents));
+
+            m_contents = clone ? Arrays.Clone(contents) : contents;
+            m_identifier = null;
         }
 
-        public virtual Asn1RelativeOid Branch(string branchID)
+        private Asn1RelativeOid(byte[] contents, string identifier)
         {
-            return new Asn1RelativeOid(this, branchID);
+            m_contents = contents;
+            m_identifier = identifier;
         }
 
-        public string Id
+        public virtual Asn1RelativeOid Branch(string branchID)
         {
-            get { return identifier; }
+            return new Asn1RelativeOid(this, branchID);
         }
 
-        public override string ToString()
+        public string GetID()
         {
-            return identifier;
+            return Objects.EnsureSingletonInitialized(ref m_identifier, m_contents, ParseContents);
         }
 
+        // TODO[api]
+        //[Obsolete("Use 'GetID' instead")]
+        public string Id => GetID();
+
+        public override string ToString() => GetID();
+
         protected override bool Asn1Equals(Asn1Object asn1Object)
         {
-            Asn1RelativeOid that = asn1Object as Asn1RelativeOid;
-            return null != that
-                && this.identifier == that.identifier;
+            return asn1Object is Asn1RelativeOid that
+                && Arrays.AreEqual(this.m_contents, that.m_contents);
         }
 
         protected override int Asn1GetHashCode()
         {
-            return identifier.GetHashCode();
+            return Arrays.GetHashCode(m_contents);
         }
 
         internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.RelativeOid, GetContents());
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.RelativeOid, m_contents);
         }
 
         internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return new PrimitiveEncoding(tagClass, tagNo, GetContents());
+            return new PrimitiveEncoding(tagClass, tagNo, m_contents);
         }
 
         internal sealed override DerEncoding GetEncodingDer()
         {
-            return new PrimitiveDerEncoding(Asn1Tags.Universal, Asn1Tags.RelativeOid, GetContents());
+            return new PrimitiveDerEncoding(Asn1Tags.Universal, Asn1Tags.RelativeOid, m_contents);
         }
 
         internal sealed override DerEncoding GetEncodingDerImplicit(int tagClass, int tagNo)
         {
-            return new PrimitiveDerEncoding(tagClass, tagNo, GetContents());
+            return new PrimitiveDerEncoding(tagClass, tagNo, m_contents);
         }
 
-        private byte[] GetContents() => Objects.EnsureSingletonInitialized(ref contents, identifier, CreateContents);
+        internal static Asn1RelativeOid CreatePrimitive(byte[] contents, bool clone)
+        {
+            return new Asn1RelativeOid(contents, clone);
+        }
 
-        private static byte[] CreateContents(string identifier)
+        internal static bool IsValidContents(byte[] contents)
         {
-            MemoryStream bOut = new MemoryStream();
-            OidTokenizer tok = new OidTokenizer(identifier);
-            while (tok.HasMoreTokens)
+            if (contents.Length < 1)
+                return false;
+
+            bool subIDStart = true;
+            for (int i = 0; i < contents.Length; ++i)
             {
-                string token = tok.NextToken();
-                if (token.Length <= 18)
-                {
-                    WriteField(bOut, long.Parse(token));
-                }
-                else
-                {
-                    WriteField(bOut, new BigInteger(token));
-                }
+                if (subIDStart && contents[i] == 0x80)
+                    return false;
+
+                subIDStart = (contents[i] & 0x80) == 0;
             }
-            return bOut.ToArray();
-        }
 
-        internal static Asn1RelativeOid CreatePrimitive(byte[] contents, bool clone)
-        {
-            return new Asn1RelativeOid(contents, clone);
+            return subIDStart;
         }
 
         internal static bool IsValidIdentifier(string identifier, int from)
@@ -195,59 +219,7 @@ namespace Org.BouncyCastle.Asn1
             return true;
         }
 
-        internal static void WriteField(Stream outputStream, long fieldValue)
-        {
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            Span<byte> result = stackalloc byte[9];
-#else
-            byte[] result = new byte[9];
-#endif
-            int pos = 8;
-            result[pos] = (byte)((int)fieldValue & 0x7F);
-            while (fieldValue >= (1L << 7))
-            {
-                fieldValue >>= 7;
-                result[--pos] = (byte)((int)fieldValue | 0x80);
-            }
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            outputStream.Write(result[pos..]);
-#else
-            outputStream.Write(result, pos, 9 - pos);
-#endif
-        }
-
-        internal static void WriteField(Stream outputStream, BigInteger fieldValue)
-        {
-            int byteCount = (fieldValue.BitLength + 6) / 7;
-            if (byteCount == 0)
-            {
-                outputStream.WriteByte(0);
-            }
-            else
-            {
-                BigInteger tmpValue = fieldValue;
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-                Span<byte> tmp = byteCount <= 16
-                    ? stackalloc byte[byteCount]
-                    : new byte[byteCount];
-#else
-                byte[] tmp = new byte[byteCount];
-#endif
-                for (int i = byteCount - 1; i >= 0; i--)
-                {
-                    tmp[i] = (byte)(tmpValue.IntValue | 0x80);
-                    tmpValue = tmpValue.ShiftRight(7);
-                }
-                tmp[byteCount - 1] &= 0x7F;
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-                outputStream.Write(tmp);
-#else
-                outputStream.Write(tmp, 0, tmp.Length);
-#endif
-            }
-        }
-
-        private static string ParseContents(byte[] contents)
+        internal static string ParseContents(byte[] contents)
         {
             StringBuilder objId = new StringBuilder();
             long value = 0;
@@ -311,5 +283,76 @@ namespace Org.BouncyCastle.Asn1
 
             return objId.ToString();
         }
+
+        internal static byte[] ParseIdentifier(string identifier)
+        {
+            MemoryStream bOut = new MemoryStream();
+            OidTokenizer tok = new OidTokenizer(identifier);
+            while (tok.HasMoreTokens)
+            {
+                string token = tok.NextToken();
+                if (token.Length <= 18)
+                {
+                    WriteField(bOut, long.Parse(token));
+                }
+                else
+                {
+                    WriteField(bOut, new BigInteger(token));
+                }
+            }
+            return bOut.ToArray();
+        }
+
+        internal static void WriteField(Stream outputStream, long fieldValue)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> result = stackalloc byte[9];
+#else
+            byte[] result = new byte[9];
+#endif
+            int pos = 8;
+            result[pos] = (byte)((int)fieldValue & 0x7F);
+            while (fieldValue >= (1L << 7))
+            {
+                fieldValue >>= 7;
+                result[--pos] = (byte)((int)fieldValue | 0x80);
+            }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            outputStream.Write(result[pos..]);
+#else
+            outputStream.Write(result, pos, 9 - pos);
+#endif
+        }
+
+        internal static void WriteField(Stream outputStream, BigInteger fieldValue)
+        {
+            int byteCount = (fieldValue.BitLength + 6) / 7;
+            if (byteCount == 0)
+            {
+                outputStream.WriteByte(0);
+            }
+            else
+            {
+                BigInteger tmpValue = fieldValue;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                Span<byte> tmp = byteCount <= 16
+                    ? stackalloc byte[byteCount]
+                    : new byte[byteCount];
+#else
+                byte[] tmp = new byte[byteCount];
+#endif
+                for (int i = byteCount - 1; i >= 0; i--)
+                {
+                    tmp[i] = (byte)(tmpValue.IntValue | 0x80);
+                    tmpValue = tmpValue.ShiftRight(7);
+                }
+                tmp[byteCount - 1] &= 0x7F;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                outputStream.Write(tmp);
+#else
+                outputStream.Write(tmp, 0, tmp.Length);
+#endif
+            }
+        }
     }
 }