diff options
Diffstat (limited to 'crypto/src/asn1/Asn1RelativeOid.cs')
-rw-r--r-- | crypto/src/asn1/Asn1RelativeOid.cs | 227 |
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 + } + } } } |