diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-11-08 22:57:03 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-11-08 22:57:03 +0700 |
commit | 8bef2160dc81d3c29d5bf18950f4fdeaa4da06d0 (patch) | |
tree | 630cf1cf57acbe5551ccf887415510f3e1f93474 /crypto/src | |
parent | Lazy ASN.1 enumeration and refactoring (diff) | |
download | BouncyCastle.NET-ed25519-8bef2160dc81d3c29d5bf18950f4fdeaa4da06d0.tar.xz |
ASN.1: Add support for relative OIDs
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/asn1/Asn1InputStream.cs | 2 | ||||
-rw-r--r-- | crypto/src/asn1/Asn1RelativeOid.cs | 296 | ||||
-rw-r--r-- | crypto/src/asn1/DerObjectIdentifier.cs | 231 | ||||
-rw-r--r-- | crypto/src/asn1/util/Asn1Dump.cs | 4 |
4 files changed, 373 insertions, 160 deletions
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs index 4cca8aaf5..23431093e 100644 --- a/crypto/src/asn1/Asn1InputStream.cs +++ b/crypto/src/asn1/Asn1InputStream.cs @@ -452,6 +452,8 @@ namespace Org.BouncyCastle.Asn1 return new DerOctetString(bytes); case Asn1Tags.PrintableString: return new DerPrintableString(bytes); + case Asn1Tags.RelativeOid: + return Asn1RelativeOid.CreatePrimitive(bytes, false); case Asn1Tags.T61String: return new DerT61String(bytes); case Asn1Tags.UniversalString: diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs new file mode 100644 index 000000000..e1ee5309a --- /dev/null +++ b/crypto/src/asn1/Asn1RelativeOid.cs @@ -0,0 +1,296 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + public class Asn1RelativeOid + : Asn1Object + { + public static Asn1RelativeOid FromContents(byte[] contents) + { + return CreatePrimitive(contents, true); + } + + public static Asn1RelativeOid GetInstance(object obj) + { + if (obj == null || obj is Asn1RelativeOid) + { + return (Asn1RelativeOid)obj; + } + else if (obj is IAsn1Convertible) + { + Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); + if (asn1Object is Asn1RelativeOid) + return (Asn1RelativeOid)asn1Object; + } + else if (obj is byte[]) + { + try + { + return GetInstance(FromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new ArgumentException("failed to construct relative OID from byte[]: " + e.Message); + } + } + + throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj"); + } + + public static Asn1RelativeOid GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + { + Asn1Object baseObject = taggedObject.GetObject(); + + if (declaredExplicit || baseObject is Asn1RelativeOid) + { + return GetInstance(baseObject); + } + + return FromContents(Asn1OctetString.GetInstance(baseObject).GetOctets()); + } + + private const long LongLimit = (Int64.MaxValue >> 7) - 0x7F; + + private readonly string identifier; + private byte[] contents; + + public Asn1RelativeOid(string identifier) + { + if (identifier == null) + throw new ArgumentNullException("identifier"); + if (!IsValidIdentifier(identifier, 0)) + throw new FormatException("string " + identifier + " not a relative OID"); + + this.identifier = identifier; + } + + private Asn1RelativeOid(Asn1RelativeOid oid, string branchID) + { + if (!IsValidIdentifier(branchID, 0)) + throw new FormatException("string " + branchID + " not a valid relative OID branch"); + + this.identifier = oid.Id + "." + branchID; + } + + private Asn1RelativeOid(byte[] contents, bool clone) + { + this.identifier = ParseContents(contents); + this.contents = clone ? Arrays.Clone(contents) : contents; + } + + public virtual Asn1RelativeOid Branch(string branchID) + { + return new Asn1RelativeOid(this, branchID); + } + + public string Id + { + get { return identifier; } + } + + public override string ToString() + { + return identifier; + } + + protected override bool Asn1Equals(Asn1Object asn1Object) + { + Asn1RelativeOid that = asn1Object as Asn1RelativeOid; + return null != that + && this.identifier == that.identifier; + } + + protected override int Asn1GetHashCode() + { + return identifier.GetHashCode(); + } + + internal override bool EncodeConstructed() + { + return false; + } + + internal override int EncodedLength(bool withID) + { + return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length); + } + + internal override void Encode(Asn1OutputStream asn1Out, bool withID) + { + asn1Out.WriteEncodingDL(withID, Asn1Tags.RelativeOid, GetContents()); + } + + private void DoOutput(MemoryStream bOut) + { + OidTokenizer tok = new OidTokenizer(identifier); + while (tok.HasMoreTokens) + { + string token = tok.NextToken(); + if (token.Length <= 18) + { + WriteField(bOut, Int64.Parse(token)); + } + else + { + WriteField(bOut, new BigInteger(token)); + } + } + } + + private byte[] GetContents() + { + lock (this) + { + if (contents == null) + { + MemoryStream bOut = new MemoryStream(); + DoOutput(bOut); + contents = bOut.ToArray(); + } + + return contents; + } + } + + internal static Asn1RelativeOid CreatePrimitive(byte[] contents, bool clone) + { + return new Asn1RelativeOid(contents, clone); + } + + internal static bool IsValidIdentifier(string identifier, int from) + { + int digitCount = 0; + + int pos = identifier.Length; + while (--pos >= from) + { + char ch = identifier[pos]; + + if (ch == '.') + { + if (0 == digitCount || (digitCount > 1 && identifier[pos + 1] == '0')) + return false; + + digitCount = 0; + } + else if ('0' <= ch && ch <= '9') + { + ++digitCount; + } + else + { + return false; + } + } + + if (0 == digitCount || (digitCount > 1 && identifier[pos + 1] == '0')) + return false; + + return true; + } + + internal static void WriteField(Stream outputStream, long fieldValue) + { + byte[] result = new byte[9]; + int pos = 8; + result[pos] = (byte)((int)fieldValue & 0x7F); + while (fieldValue >= (1L << 7)) + { + fieldValue >>= 7; + result[--pos] = (byte)((int)fieldValue | 0x80); + } + outputStream.Write(result, pos, 9 - pos); + } + + internal static void WriteField(Stream outputStream, BigInteger fieldValue) + { + int byteCount = (fieldValue.BitLength + 6) / 7; + if (byteCount == 0) + { + outputStream.WriteByte(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount - 1; i >= 0; i--) + { + tmp[i] = (byte)(tmpValue.IntValue | 0x80); + tmpValue = tmpValue.ShiftRight(7); + } + tmp[byteCount - 1] &= 0x7F; + outputStream.Write(tmp, 0, tmp.Length); + } + } + + private static string ParseContents(byte[] contents) + { + StringBuilder objId = new StringBuilder(); + long value = 0; + BigInteger bigValue = null; + bool first = true; + + for (int i = 0; i != contents.Length; i++) + { + int b = contents[i]; + + if (value <= LongLimit) + { + value += b & 0x7F; + if ((b & 0x80) == 0) + { + if (first) + { + first = false; + } + else + { + objId.Append('.'); + } + + objId.Append(value); + value = 0; + } + else + { + value <<= 7; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.ValueOf(value); + } + bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7F)); + if ((b & 0x80) == 0) + { + if (first) + { + first = false; + } + else + { + objId.Append('.'); + } + + objId.Append(bigValue); + bigValue = null; + value = 0; + } + else + { + bigValue = bigValue.ShiftLeft(7); + } + } + } + + return objId.ToString(); + } + } +} diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs index 4821d3b22..08451b82f 100644 --- a/crypto/src/asn1/DerObjectIdentifier.cs +++ b/crypto/src/asn1/DerObjectIdentifier.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Text; -using System.Text.RegularExpressions; using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities; @@ -16,9 +15,6 @@ namespace Org.BouncyCastle.Asn1 return CreatePrimitive(contents, true); } - private readonly string identifier; - private byte[] contents; - /** * return an Oid from the passed in object * @@ -51,31 +47,26 @@ namespace Org.BouncyCastle.Asn1 throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj"); } - /** - * return an object Identifier from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicitly true if the object is meant to be explicitly - * tagged false otherwise. - * @exception ArgumentException if the tagged object cannot - * be converted. - */ - public static DerObjectIdentifier GetInstance( - Asn1TaggedObject obj, - bool explicitly) + public static DerObjectIdentifier GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) { - Asn1Object o = obj.GetObject(); + Asn1Object baseObject = taggedObject.GetObject(); - if (explicitly || o is DerObjectIdentifier) + if (declaredExplicit || baseObject is DerObjectIdentifier) { - return GetInstance(o); + return GetInstance(baseObject); } - return FromContents(Asn1OctetString.GetInstance(o).GetOctets()); + return FromContents(Asn1OctetString.GetInstance(baseObject).GetOctets()); } - public DerObjectIdentifier( - string identifier) + private const long LongLimit = (Int64.MaxValue >> 7) - 0x7F; + + private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024]; + + private readonly string identifier; + private byte[] contents; + + public DerObjectIdentifier(string identifier) { if (identifier == null) throw new ArgumentNullException("identifier"); @@ -85,18 +76,18 @@ namespace Org.BouncyCastle.Asn1 this.identifier = identifier; } - internal DerObjectIdentifier(DerObjectIdentifier oid, string branchID) + private DerObjectIdentifier(DerObjectIdentifier oid, string branchID) { - if (!IsValidBranchID(branchID, 0)) + if (!Asn1RelativeOid.IsValidIdentifier(branchID, 0)) throw new ArgumentException("string " + branchID + " not a valid OID branch", "branchID"); this.identifier = oid.Id + "." + branchID; } - // TODO Change to ID? - public string Id + private DerObjectIdentifier(byte[] contents, bool clone) { - get { return identifier; } + this.identifier = ParseContents(contents); + this.contents = clone ? Arrays.Clone(contents) : contents; } public virtual DerObjectIdentifier Branch(string branchID) @@ -104,6 +95,11 @@ namespace Org.BouncyCastle.Asn1 return new DerObjectIdentifier(this, branchID); } + public string Id + { + get { return identifier; } + } + /** * Return true if this oid is an extension of the passed in branch, stem. * @param stem the arc or branch that is a possible parent. @@ -115,48 +111,36 @@ namespace Org.BouncyCastle.Asn1 return id.Length > stemId.Length && id[stemId.Length] == '.' && Platform.StartsWith(id, stemId); } - internal DerObjectIdentifier(byte[] contents, bool clone) + public override string ToString() { - this.identifier = MakeOidStringFromBytes(contents); - this.contents = clone ? Arrays.Clone(contents) : contents; + return identifier; } - private void WriteField( - Stream outputStream, - long fieldValue) + protected override bool Asn1Equals(Asn1Object asn1Object) { - byte[] result = new byte[9]; - int pos = 8; - result[pos] = (byte)(fieldValue & 0x7f); - while (fieldValue >= (1L << 7)) - { - fieldValue >>= 7; - result[--pos] = (byte)((fieldValue & 0x7f) | 0x80); - } - outputStream.Write(result, pos, 9 - pos); + DerObjectIdentifier that = asn1Object as DerObjectIdentifier; + return null != that + && this.identifier == that.identifier; } - private void WriteField( - Stream outputStream, - BigInteger fieldValue) + protected override int Asn1GetHashCode() { - int byteCount = (fieldValue.BitLength + 6) / 7; - if (byteCount == 0) - { - outputStream.WriteByte(0); - } - else - { - BigInteger tmpValue = fieldValue; - byte[] tmp = new byte[byteCount]; - for (int i = byteCount-1; i >= 0; i--) - { - tmp[i] = (byte) ((tmpValue.IntValue & 0x7f) | 0x80); - tmpValue = tmpValue.ShiftRight(7); - } - tmp[byteCount-1] &= 0x7f; - outputStream.Write(tmp, 0, tmp.Length); - } + return identifier.GetHashCode(); + } + + internal override bool EncodeConstructed() + { + return false; + } + + internal override int EncodedLength(bool withID) + { + return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length); + } + + internal override void Encode(Asn1OutputStream asn1Out, bool withID) + { + asn1Out.WriteEncodingDL(withID, Asn1Tags.ObjectIdentifier, GetContents()); } private void DoOutput(MemoryStream bOut) @@ -169,11 +153,11 @@ namespace Org.BouncyCastle.Asn1 token = tok.NextToken(); if (token.Length <= 18) { - WriteField(bOut, first + Int64.Parse(token)); + Asn1RelativeOid.WriteField(bOut, first + Int64.Parse(token)); } else { - WriteField(bOut, new BigInteger(token).Add(BigInteger.ValueOf(first))); + Asn1RelativeOid.WriteField(bOut, new BigInteger(token).Add(BigInteger.ValueOf(first))); } while (tok.HasMoreTokens) @@ -181,11 +165,11 @@ namespace Org.BouncyCastle.Asn1 token = tok.NextToken(); if (token.Length <= 18) { - WriteField(bOut, Int64.Parse(token)); + Asn1RelativeOid.WriteField(bOut, Int64.Parse(token)); } else { - WriteField(bOut, new BigInteger(token)); + Asn1RelativeOid.WriteField(bOut, new BigInteger(token)); } } } @@ -205,72 +189,21 @@ namespace Org.BouncyCastle.Asn1 } } - internal override bool EncodeConstructed() - { - return false; - } - - internal override int EncodedLength(bool withID) - { - return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length); - } - - internal override void Encode(Asn1OutputStream asn1Out, bool withID) - { - asn1Out.WriteEncodingDL(withID, Asn1Tags.ObjectIdentifier, GetContents()); - } - - protected override int Asn1GetHashCode() - { - return identifier.GetHashCode(); - } - - protected override bool Asn1Equals( - Asn1Object asn1Object) - { - DerObjectIdentifier other = asn1Object as DerObjectIdentifier; - - if (other == null) - return false; - - return this.identifier.Equals(other.identifier); - } - - public override string ToString() - { - return identifier; - } - - private static bool IsValidBranchID(string branchID, int start) + internal static DerObjectIdentifier CreatePrimitive(byte[] contents, bool clone) { - int digitCount = 0; + int hashCode = Arrays.GetHashCode(contents); + int first = hashCode & 1023; - int pos = branchID.Length; - while (--pos >= start) + lock (cache) { - char ch = branchID[pos]; - - if (ch == '.') - { - if (0 == digitCount || (digitCount > 1 && branchID[pos + 1] == '0')) - return false; - - digitCount = 0; - } - else if ('0' <= ch && ch <= '9') - { - ++digitCount; - } - else + DerObjectIdentifier entry = cache[first]; + if (entry != null && Arrays.AreEqual(contents, entry.GetContents())) { - return false; + return entry; } - } - - if (0 == digitCount || (digitCount > 1 && branchID[pos + 1] == '0')) - return false; - return true; + return cache[first] = new DerObjectIdentifier(contents, clone); + } } private static bool IsValidIdentifier(string identifier) @@ -282,27 +215,24 @@ namespace Org.BouncyCastle.Asn1 if (first < '0' || first > '2') return false; - return IsValidBranchID(identifier, 2); + return Asn1RelativeOid.IsValidIdentifier(identifier, 2); } - private const long LONG_LIMIT = (long.MaxValue >> 7) - 0x7f; - - private static string MakeOidStringFromBytes( - byte[] bytes) + private static string ParseContents(byte[] contents) { - StringBuilder objId = new StringBuilder(); - long value = 0; - BigInteger bigValue = null; - bool first = true; + StringBuilder objId = new StringBuilder(); + long value = 0; + BigInteger bigValue = null; + bool first = true; - for (int i = 0; i != bytes.Length; i++) + for (int i = 0; i != contents.Length; i++) { - int b = bytes[i]; + int b = contents[i]; - if (value <= LONG_LIMIT) + if (value <= LongLimit) { - value += (b & 0x7f); - if ((b & 0x80) == 0) // end of number reached + value += b & 0x7F; + if ((b & 0x80) == 0) { if (first) { @@ -338,7 +268,7 @@ namespace Org.BouncyCastle.Asn1 { bigValue = BigInteger.ValueOf(value); } - bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f)); + bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7F)); if ((b & 0x80) == 0) { if (first) @@ -362,24 +292,5 @@ namespace Org.BouncyCastle.Asn1 return objId.ToString(); } - - private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024]; - - internal static DerObjectIdentifier CreatePrimitive(byte[] contents, bool clone) - { - int hashCode = Arrays.GetHashCode(contents); - int first = hashCode & 1023; - - lock (cache) - { - DerObjectIdentifier entry = cache[first]; - if (entry != null && Arrays.AreEqual(contents, entry.GetContents())) - { - return entry; - } - - return cache[first] = new DerObjectIdentifier(contents, clone); - } - } } } diff --git a/crypto/src/asn1/util/Asn1Dump.cs b/crypto/src/asn1/util/Asn1Dump.cs index c82abd5c6..0d3382d00 100644 --- a/crypto/src/asn1/util/Asn1Dump.cs +++ b/crypto/src/asn1/util/Asn1Dump.cs @@ -116,6 +116,10 @@ namespace Org.BouncyCastle.Asn1.Utilities { buf.Append(indent + "ObjectIdentifier(" + ((DerObjectIdentifier)obj).Id + ")" + NewLine); } + else if (obj is Asn1RelativeOid) + { + buf.Append(indent + "RelativeOID(" + ((Asn1RelativeOid)obj).Id + ")" + NewLine); + } else if (obj is DerBoolean) { buf.Append(indent + "Boolean(" + ((DerBoolean)obj).IsTrue + ")" + NewLine); |