DerObjectIdentifier
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities;
using System;
using System.IO;
using System.Text;
using System.Threading;
namespace Org.BouncyCastle.Asn1
{
public class DerObjectIdentifier : Asn1Object
{
internal class Meta : Asn1UniversalType
{
internal static readonly Asn1UniversalType Instance = new Meta();
private Meta()
: base(typeof(DerObjectIdentifier), 6)
{
}
internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
{
return CreatePrimitive(octetString.GetOctets(), false);
}
}
private const int MaxContentsLength = 4096;
private const int MaxIdentifierLength = 16385;
private const long LongLimit = 72057594037927808;
private static readonly DerObjectIdentifier[] Cache = new DerObjectIdentifier[1024];
private readonly byte[] m_contents;
private string m_identifier;
public string Id => GetID();
public static DerObjectIdentifier FromContents(byte[] contents)
{
if (contents == null)
throw new ArgumentNullException("contents");
return CreatePrimitive(contents, true);
}
public static DerObjectIdentifier GetInstance(object obj)
{
if (obj == null)
return null;
DerObjectIdentifier derObjectIdentifier = obj as DerObjectIdentifier;
if (derObjectIdentifier != null)
return derObjectIdentifier;
IAsn1Convertible asn1Convertible = obj as IAsn1Convertible;
if (asn1Convertible != null) {
if (!(obj is Asn1Object)) {
DerObjectIdentifier derObjectIdentifier2 = asn1Convertible.ToAsn1Object() as DerObjectIdentifier;
if (derObjectIdentifier2 != null)
return derObjectIdentifier2;
}
} else {
byte[] array = obj as byte[];
if (array != null)
try {
return (DerObjectIdentifier)Meta.Instance.FromByteArray(array);
} catch (IOException ex) {
throw new ArgumentException("failed to construct object identifier from byte[]: " + ex.Message);
}
}
throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
}
public static DerObjectIdentifier GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
{
if (!declaredExplicit && !taggedObject.IsParsed() && taggedObject.HasContextTag()) {
Asn1Object asn1Object = taggedObject.GetBaseObject().ToAsn1Object();
if (!(asn1Object is DerObjectIdentifier))
return FromContents(Asn1OctetString.GetInstance(asn1Object).GetOctets());
}
return (DerObjectIdentifier)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
}
public static DerObjectIdentifier GetOptional(Asn1Encodable element)
{
if (element == null)
throw new ArgumentNullException("element");
DerObjectIdentifier derObjectIdentifier = element as DerObjectIdentifier;
if (derObjectIdentifier != null)
return derObjectIdentifier;
return null;
}
public static DerObjectIdentifier GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit)
{
return (DerObjectIdentifier)Meta.Instance.GetTagged(taggedObject, declaredExplicit);
}
public static bool TryFromID(string identifier, out DerObjectIdentifier oid)
{
if (identifier == null)
throw new ArgumentNullException("identifier");
if (identifier.Length <= 16385 && IsValidIdentifier(identifier)) {
byte[] array = ParseIdentifier(identifier);
if (array.Length <= 4096) {
oid = new DerObjectIdentifier(array, identifier);
return true;
}
}
oid = null;
return false;
}
public DerObjectIdentifier(string identifier)
{
CheckIdentifier(identifier);
byte[] array = ParseIdentifier(identifier);
CheckContentsLength(array.Length);
m_contents = array;
m_identifier = identifier;
}
private DerObjectIdentifier(byte[] contents, string identifier)
{
m_contents = contents;
m_identifier = identifier;
}
public virtual DerObjectIdentifier Branch(string branchID)
{
Asn1RelativeOid.CheckIdentifier(branchID);
byte[] contents;
if (branchID.Length <= 2) {
CheckContentsLength(m_contents.Length + 1);
int num = branchID[0] - 48;
if (branchID.Length == 2) {
num *= 10;
num += branchID[1] - 48;
}
contents = Arrays.Append(m_contents, (byte)num);
} else {
byte[] array = Asn1RelativeOid.ParseIdentifier(branchID);
CheckContentsLength(m_contents.Length + array.Length);
contents = Arrays.Concatenate(m_contents, array);
}
string identifier = GetID() + "." + branchID;
return new DerObjectIdentifier(contents, identifier);
}
public string GetID()
{
return Objects.EnsureSingletonInitialized(ref m_identifier, m_contents, ParseContents);
}
public virtual bool On(DerObjectIdentifier stem)
{
byte[] contents = m_contents;
byte[] contents2 = stem.m_contents;
int num = contents2.Length;
if (contents.Length > num)
return Arrays.AreEqual(contents, 0, num, contents2, 0, num);
return false;
}
public override string ToString()
{
return GetID();
}
protected override bool Asn1Equals(Asn1Object asn1Object)
{
DerObjectIdentifier derObjectIdentifier = asn1Object as DerObjectIdentifier;
if (derObjectIdentifier != null)
return Arrays.AreEqual(m_contents, derObjectIdentifier.m_contents);
return false;
}
protected override int Asn1GetHashCode()
{
return Arrays.GetHashCode(m_contents);
}
internal override IAsn1Encoding GetEncoding(int encoding)
{
return new PrimitiveEncoding(0, 6, m_contents);
}
internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
{
return new PrimitiveEncoding(tagClass, tagNo, m_contents);
}
internal sealed override DerEncoding GetEncodingDer()
{
return new PrimitiveDerEncoding(0, 6, m_contents);
}
internal sealed override DerEncoding GetEncodingDerImplicit(int tagClass, int tagNo)
{
return new PrimitiveDerEncoding(tagClass, tagNo, m_contents);
}
internal static void CheckContentsLength(int contentsLength)
{
if (contentsLength > 4096)
throw new ArgumentException("exceeded OID contents length limit");
}
internal static void CheckIdentifier(string identifier)
{
if (identifier == null)
throw new ArgumentNullException("identifier");
if (identifier.Length > 16385)
throw new ArgumentException("exceeded OID contents length limit");
if (!IsValidIdentifier(identifier))
throw new FormatException("string " + identifier + " not a valid OID");
}
internal static DerObjectIdentifier CreatePrimitive(byte[] contents, bool clone)
{
CheckContentsLength(contents.Length);
uint hashCode = (uint)Arrays.GetHashCode(contents);
hashCode ^= hashCode >> 20;
hashCode ^= hashCode >> 10;
hashCode &= 1023;
DerObjectIdentifier derObjectIdentifier = Volatile.Read(ref Cache[hashCode]);
if (derObjectIdentifier != null && Arrays.AreEqual(contents, derObjectIdentifier.m_contents))
return derObjectIdentifier;
if (!Asn1RelativeOid.IsValidContents(contents))
throw new ArgumentException("invalid OID contents", "contents");
DerObjectIdentifier derObjectIdentifier2 = new DerObjectIdentifier(clone ? Arrays.Clone(contents) : contents, null);
DerObjectIdentifier derObjectIdentifier3 = Interlocked.CompareExchange(ref Cache[hashCode], derObjectIdentifier2, derObjectIdentifier);
if (derObjectIdentifier3 != derObjectIdentifier && derObjectIdentifier3 != null && Arrays.AreEqual(contents, derObjectIdentifier3.m_contents))
return derObjectIdentifier3;
return derObjectIdentifier2;
}
private static bool IsValidIdentifier(string identifier)
{
if (identifier.Length < 3 || identifier[1] != '.')
return false;
char c = identifier[0];
if (c < '0' || c > '2')
return false;
if (!Asn1RelativeOid.IsValidIdentifier(identifier, 2))
return false;
if (c == '2')
return true;
if (identifier.Length == 3 || identifier[3] == '.')
return true;
if (identifier.Length == 4 || identifier[4] == '.')
return identifier[2] < '4';
return false;
}
private static string ParseContents(byte[] contents)
{
StringBuilder stringBuilder = new StringBuilder();
long num = 0;
BigInteger bigInteger = null;
bool flag = true;
for (int i = 0; i != contents.Length; i++) {
int num2 = contents[i];
if (num <= 72057594037927808) {
num += (num2 & 127);
if ((num2 & 128) == 0) {
if (flag) {
if (num < 40)
stringBuilder.Append('0');
else if (num < 80) {
stringBuilder.Append('1');
num -= 40;
} else {
stringBuilder.Append('2');
num -= 80;
}
flag = false;
}
stringBuilder.Append('.');
stringBuilder.Append(num);
num = 0;
} else
num <<= 7;
} else {
if (bigInteger == null)
bigInteger = BigInteger.ValueOf(num);
bigInteger = bigInteger.Or(BigInteger.ValueOf(num2 & 127));
if ((num2 & 128) == 0) {
if (flag) {
stringBuilder.Append('2');
bigInteger = bigInteger.Subtract(BigInteger.ValueOf(80));
flag = false;
}
stringBuilder.Append('.');
stringBuilder.Append(bigInteger);
bigInteger = null;
num = 0;
} else
bigInteger = bigInteger.ShiftLeft(7);
}
}
return stringBuilder.ToString();
}
private static byte[] ParseIdentifier(string identifier)
{
MemoryStream memoryStream = new MemoryStream();
OidTokenizer oidTokenizer = new OidTokenizer(identifier);
string s = oidTokenizer.NextToken();
int num = int.Parse(s) * 40;
s = oidTokenizer.NextToken();
if (s.Length <= 18)
Asn1RelativeOid.WriteField(memoryStream, num + long.Parse(s));
else
Asn1RelativeOid.WriteField(memoryStream, new BigInteger(s).Add(BigInteger.ValueOf(num)));
while (oidTokenizer.HasMoreTokens) {
s = oidTokenizer.NextToken();
if (s.Length <= 18)
Asn1RelativeOid.WriteField(memoryStream, long.Parse(s));
else
Asn1RelativeOid.WriteField(memoryStream, new BigInteger(s));
}
return memoryStream.ToArray();
}
}
}