From 32ceae264dc39331174d9db71fe38948648c7989 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Mon, 6 Feb 2023 15:40:40 +0700 Subject: New tagged object methods and refactoring --- crypto/src/asn1/ASN1TaggedObjectParser.cs | 6 ++ crypto/src/asn1/Asn1TaggedObject.cs | 131 ++++++++++++++++-------------- crypto/src/asn1/Asn1Utilities.cs | 108 +++++++++++++++++++++++- crypto/src/asn1/BERTaggedObjectParser.cs | 10 +++ crypto/src/asn1/BerTaggedObject.cs | 2 +- crypto/src/asn1/DLTaggedObject.cs | 2 +- crypto/src/asn1/DerTaggedObject.cs | 2 +- 7 files changed, 192 insertions(+), 69 deletions(-) diff --git a/crypto/src/asn1/ASN1TaggedObjectParser.cs b/crypto/src/asn1/ASN1TaggedObjectParser.cs index 0b53b6abf..3e3acda6e 100644 --- a/crypto/src/asn1/ASN1TaggedObjectParser.cs +++ b/crypto/src/asn1/ASN1TaggedObjectParser.cs @@ -10,10 +10,16 @@ namespace Org.BouncyCastle.Asn1 int TagNo { get; } + // TODO[api] + //bool HasContextTag(); + bool HasContextTag(int tagNo); bool HasTag(int tagClass, int tagNo); + // TODO[api] + //bool HasTagClass(int tagClass); + /// IAsn1Convertible ParseBaseUniversal(bool declaredExplicit, int baseTagNo); diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs index 63ab6a5d0..314170750 100644 --- a/crypto/src/asn1/Asn1TaggedObject.cs +++ b/crypto/src/asn1/Asn1TaggedObject.cs @@ -41,52 +41,56 @@ namespace Org.BouncyCastle.Asn1 } catch (IOException e) { - throw new ArgumentException("failed to construct tagged object from byte[]: " + e.Message); + throw new ArgumentException("failed to construct tagged object from byte[]", nameof(obj), e); } } - throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj"); + throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), nameof(obj)); } public static Asn1TaggedObject GetInstance(object obj, int tagClass) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - Asn1TaggedObject taggedObject = GetInstance(obj); - if (tagClass != taggedObject.TagClass) - throw new ArgumentException("unexpected tag in GetInstance: " + Asn1Utilities.GetTagText(taggedObject)); - - return taggedObject; + return Asn1Utilities.CheckTagClass(CheckInstance(obj), tagClass); } public static Asn1TaggedObject GetInstance(object obj, int tagClass, int tagNo) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); + return Asn1Utilities.CheckTag(CheckInstance(obj), tagClass, tagNo); + } - Asn1TaggedObject taggedObject = GetInstance(obj); - if (!taggedObject.HasTag(tagClass, tagNo)) - throw new ArgumentException("unexpected tag in GetInstance: " + Asn1Utilities.GetTagText(taggedObject)); + public static Asn1TaggedObject GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + { + return Asn1Utilities.GetExplicitContextBaseTagged(CheckInstance(taggedObject, declaredExplicit)); + } - return taggedObject; + public static Asn1TaggedObject GetInstance(Asn1TaggedObject taggedObject, int tagClass, bool declaredExplicit) + { + return Asn1Utilities.GetExplicitBaseTagged(CheckInstance(taggedObject, declaredExplicit), tagClass); } - public static Asn1TaggedObject GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + public static Asn1TaggedObject GetInstance(Asn1TaggedObject taggedObject, int tagClass, int tagNo, + bool declaredExplicit) { - if (Asn1Tags.ContextSpecific != taggedObject.TagClass) - throw new InvalidOperationException("this method only valid for CONTEXT_SPECIFIC tags"); + return Asn1Utilities.GetExplicitBaseTagged(CheckInstance(taggedObject, declaredExplicit), tagClass, tagNo); + } - if (declaredExplicit) - return taggedObject.GetExplicitBaseTagged(); + private static Asn1TaggedObject CheckInstance(object obj) + { + return GetInstance(obj ?? throw new ArgumentNullException(nameof(obj))); + } - throw new ArgumentException("this method not valid for implicitly tagged tagged objects"); + private static Asn1TaggedObject CheckInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + { + if (!declaredExplicit) + throw new ArgumentException("this method not valid for implicitly tagged tagged objects"); + + return taggedObject ?? throw new ArgumentNullException(nameof(taggedObject)); } - internal readonly int explicitness; - internal readonly int tagClass; - internal readonly int tagNo; - internal readonly Asn1Encodable obj; + internal readonly int m_explicitness; + internal readonly int m_tagClass; + internal readonly int m_tagNo; + internal readonly Asn1Encodable m_object; /** * @param explicitly true if the object is explicitly tagged. @@ -106,23 +110,23 @@ namespace Org.BouncyCastle.Asn1 internal Asn1TaggedObject(int explicitness, int tagClass, int tagNo, Asn1Encodable obj) { if (null == obj) - throw new ArgumentNullException("obj"); + throw new ArgumentNullException(nameof(obj)); if (Asn1Tags.Universal == tagClass || (tagClass & Asn1Tags.Private) != tagClass) - throw new ArgumentException("invalid tag class: " + tagClass, "tagClass"); + throw new ArgumentException("invalid tag class: " + tagClass, nameof(tagClass)); - this.explicitness = (obj is IAsn1Choice) ? DeclaredExplicit : explicitness; - this.tagClass = tagClass; - this.tagNo = tagNo; - this.obj = obj; + m_explicitness = obj is IAsn1Choice ? DeclaredExplicit : explicitness; + m_tagClass = tagClass; + m_tagNo = tagNo; + m_object = obj; } protected override bool Asn1Equals(Asn1Object asn1Object) { Asn1TaggedObject that = asn1Object as Asn1TaggedObject; - if (null == that || this.tagNo != that.tagNo || this.tagClass != that.tagClass) + if (null == that || this.m_tagNo != that.m_tagNo || this.m_tagClass != that.m_tagClass) return false; - if (this.explicitness != that.explicitness) + if (this.m_explicitness != that.m_explicitness) { /* * TODO This seems incorrect for some cases of implicit tags e.g. if one is a @@ -132,8 +136,8 @@ namespace Org.BouncyCastle.Asn1 return false; } - Asn1Object p1 = this.obj.ToAsn1Object(); - Asn1Object p2 = that.obj.ToAsn1Object(); + Asn1Object p1 = this.m_object.ToAsn1Object(); + Asn1Object p2 = that.m_object.ToAsn1Object(); if (p1 == p2) return true; @@ -158,27 +162,31 @@ namespace Org.BouncyCastle.Asn1 protected override int Asn1GetHashCode() { - return (tagClass * 7919) ^ tagNo ^ (IsExplicit() ? 0x0F : 0xF0) ^ obj.ToAsn1Object().CallAsn1GetHashCode(); + return (m_tagClass * 7919) ^ m_tagNo ^ (IsExplicit() ? 0x0F : 0xF0) ^ m_object.ToAsn1Object().CallAsn1GetHashCode(); } - public int TagClass - { - get { return tagClass; } - } + public int TagClass => m_tagClass; + + public int TagNo => m_tagNo; - public int TagNo + public bool HasContextTag() { - get { return tagNo; } + return m_tagClass == Asn1Tags.ContextSpecific; } public bool HasContextTag(int tagNo) { - return this.tagClass == Asn1Tags.ContextSpecific && this.tagNo == tagNo; + return m_tagClass == Asn1Tags.ContextSpecific && m_tagNo == tagNo; } public bool HasTag(int tagClass, int tagNo) { - return this.tagClass == tagClass && this.tagNo == tagNo; + return m_tagClass == tagClass && m_tagNo == tagNo; + } + + public bool HasTagClass(int tagClass) + { + return m_tagClass == tagClass; } /** @@ -193,7 +201,7 @@ namespace Org.BouncyCastle.Asn1 public bool IsExplicit() { // TODO New methods like 'IsKnownExplicit' etc. to distinguish uncertain cases? - switch (explicitness) + switch (m_explicitness) { case DeclaredExplicit: case ParsedExplicit: @@ -205,7 +213,7 @@ namespace Org.BouncyCastle.Asn1 internal bool IsParsed() { - switch (explicitness) + switch (m_explicitness) { case ParsedExplicit: case ParsedImplicit: @@ -224,10 +232,9 @@ namespace Org.BouncyCastle.Asn1 */ public Asn1Object GetObject() { - if (Asn1Tags.ContextSpecific != TagClass) - throw new InvalidOperationException("this method only valid for CONTEXT_SPECIFIC tags"); + Asn1Utilities.CheckTagClass(this, Asn1Tags.ContextSpecific); - return obj.ToAsn1Object(); + return m_object.ToAsn1Object(); } /** @@ -238,7 +245,7 @@ namespace Org.BouncyCastle.Asn1 */ public Asn1Encodable GetBaseObject() { - return obj; + return m_object; } /** @@ -252,7 +259,7 @@ namespace Org.BouncyCastle.Asn1 if (!IsExplicit()) throw new InvalidOperationException("object implicit - explicit expected."); - return obj; + return m_object; } public Asn1TaggedObject GetExplicitBaseTagged() @@ -260,22 +267,22 @@ namespace Org.BouncyCastle.Asn1 if (!IsExplicit()) throw new InvalidOperationException("object implicit - explicit expected."); - return CheckedCast(obj.ToAsn1Object()); + return CheckedCast(m_object.ToAsn1Object()); } public Asn1TaggedObject GetImplicitBaseTagged(int baseTagClass, int baseTagNo) { if (Asn1Tags.Universal == baseTagClass || (baseTagClass & Asn1Tags.Private) != baseTagClass) - throw new ArgumentException("invalid base tag class: " + baseTagClass, "baseTagClass"); + throw new ArgumentException("invalid base tag class: " + baseTagClass, nameof(baseTagClass)); - switch (explicitness) + switch (m_explicitness) { case DeclaredExplicit: throw new InvalidOperationException("object explicit - implicit expected."); case DeclaredImplicit: { - Asn1TaggedObject declared = CheckedCast(obj.ToAsn1Object()); + Asn1TaggedObject declared = CheckedCast(m_object.ToAsn1Object()); return Asn1Utilities.CheckTag(declared, baseTagClass, baseTagNo); } @@ -289,7 +296,7 @@ namespace Org.BouncyCastle.Asn1 { Asn1UniversalType universalType = Asn1UniversalTypes.Get(tagNo); if (null == universalType) - throw new ArgumentException("unsupported UNIVERSAL tag number: " + tagNo, "tagNo"); + throw new ArgumentException("unsupported UNIVERSAL tag number: " + tagNo, nameof(tagNo)); return GetBaseUniversal(declaredExplicit, universalType); } @@ -301,14 +308,14 @@ namespace Org.BouncyCastle.Asn1 if (!IsExplicit()) throw new InvalidOperationException("object explicit - implicit expected."); - return universalType.CheckedCast(obj.ToAsn1Object()); + return universalType.CheckedCast(m_object.ToAsn1Object()); } - if (DeclaredExplicit == explicitness) + if (DeclaredExplicit == m_explicitness) throw new InvalidOperationException("object explicit - implicit expected."); - Asn1Object baseObject = obj.ToAsn1Object(); - switch (explicitness) + Asn1Object baseObject = m_object.ToAsn1Object(); + switch (m_explicitness) { case ParsedExplicit: return universalType.FromImplicitConstructed(RebuildConstructed(baseObject)); @@ -360,7 +367,7 @@ namespace Org.BouncyCastle.Asn1 public override string ToString() { - return Asn1Utilities.GetTagText(tagClass, tagNo) + obj; + return Asn1Utilities.GetTagText(m_tagClass, m_tagNo) + m_object; } internal abstract string Asn1Encoding { get; } diff --git a/crypto/src/asn1/Asn1Utilities.cs b/crypto/src/asn1/Asn1Utilities.cs index 6ccdfc43a..07f8aad03 100644 --- a/crypto/src/asn1/Asn1Utilities.cs +++ b/crypto/src/asn1/Asn1Utilities.cs @@ -7,6 +7,28 @@ namespace Org.BouncyCastle.Asn1 { public abstract class Asn1Utilities { + internal static Asn1TaggedObject CheckTagClass(Asn1TaggedObject taggedObject, int tagClass) + { + if (!taggedObject.HasTagClass(tagClass)) + { + string expected = GetTagClassText(tagClass); + string found = GetTagClassText(taggedObject); + throw new InvalidOperationException("Expected " + expected + " tag but found " + found); + } + return taggedObject; + } + + internal static Asn1TaggedObjectParser CheckTagClass(Asn1TaggedObjectParser taggedObjectParser, int tagClass) + { + if (taggedObjectParser.TagClass != tagClass) + { + string expected = GetTagClassText(tagClass); + string found = GetTagClassText(taggedObjectParser); + throw new InvalidOperationException("Expected " + expected + " tag but found " + found); + } + return taggedObjectParser; + } + internal static Asn1TaggedObject CheckTag(Asn1TaggedObject taggedObject, int tagClass, int tagNo) { if (!taggedObject.HasTag(tagClass, tagNo)) @@ -48,6 +70,31 @@ namespace Org.BouncyCastle.Asn1 } + public static string GetTagClassText(int tagClass) + { + switch (tagClass) + { + case Asn1Tags.Application: + return "APPLICATION"; + case Asn1Tags.ContextSpecific: + return "CONTEXT"; + case Asn1Tags.Private: + return "PRIVATE"; + default: + return "UNIVERSAL"; + } + } + + public static string GetTagClassText(Asn1TaggedObject taggedObject) + { + return GetTagClassText(taggedObject.TagClass); + } + + public static string GetTagClassText(Asn1TaggedObjectParser taggedObjectParser) + { + return GetTagClassText(taggedObjectParser.TagClass); + } + internal static string GetTagText(Asn1Tag tag) { return GetTagText(tag.TagClass, tag.TagNo); @@ -68,13 +115,13 @@ namespace Org.BouncyCastle.Asn1 switch (tagClass) { case Asn1Tags.Application: - return "[APPLICATION " + tagNo + "]"; + return string.Format("[APPLICATION {0}]", tagNo); case Asn1Tags.ContextSpecific: - return "[CONTEXT " + tagNo + "]"; + return string.Format("[CONTEXT {0}]", tagNo); case Asn1Tags.Private: - return "[PRIVATE " + tagNo + "]"; + return string.Format("[PRIVATE {0}]", tagNo); default: - return "[UNIVERSAL " + tagNo + "]"; + return string.Format("[UNIVERSAL {0}]", tagNo); } } @@ -111,16 +158,34 @@ namespace Org.BouncyCastle.Asn1 * Wrappers for Asn1TaggedObject.GetExplicitBaseTagged */ + public static Asn1TaggedObject GetExplicitBaseTagged(Asn1TaggedObject taggedObject, int tagClass) + { + return CheckTagClass(taggedObject, tagClass).GetExplicitBaseTagged(); + } + public static Asn1TaggedObject GetExplicitBaseTagged(Asn1TaggedObject taggedObject, int tagClass, int tagNo) { return CheckTag(taggedObject, tagClass, tagNo).GetExplicitBaseTagged(); } + public static Asn1TaggedObject GetExplicitContextBaseTagged(Asn1TaggedObject taggedObject) + { + return GetExplicitBaseTagged(taggedObject, Asn1Tags.ContextSpecific); + } + public static Asn1TaggedObject GetExplicitContextBaseTagged(Asn1TaggedObject taggedObject, int tagNo) { return GetExplicitBaseTagged(taggedObject, Asn1Tags.ContextSpecific, tagNo); } + public static Asn1TaggedObject TryGetExplicitBaseTagged(Asn1TaggedObject taggedObject, int tagClass) + { + if (!taggedObject.HasTagClass(tagClass)) + return null; + + return taggedObject.GetExplicitBaseTagged(); + } + public static Asn1TaggedObject TryGetExplicitBaseTagged(Asn1TaggedObject taggedObject, int tagClass, int tagNo) { if (!taggedObject.HasTag(tagClass, tagNo)) @@ -129,6 +194,11 @@ namespace Org.BouncyCastle.Asn1 return taggedObject.GetExplicitBaseTagged(); } + public static Asn1TaggedObject TryGetExplicitContextBaseTagged(Asn1TaggedObject taggedObject) + { + return TryGetExplicitBaseTagged(taggedObject, Asn1Tags.ContextSpecific); + } + public static Asn1TaggedObject TryGetExplicitContextBaseTagged(Asn1TaggedObject taggedObject, int tagNo) { return TryGetExplicitBaseTagged(taggedObject, Asn1Tags.ContextSpecific, tagNo); @@ -203,6 +273,13 @@ namespace Org.BouncyCastle.Asn1 * Wrappers for Asn1TaggedObjectParser.ParseExplicitBaseTagged */ + /// + public static Asn1TaggedObjectParser ParseExplicitBaseTagged(Asn1TaggedObjectParser taggedObjectParser, + int tagClass) + { + return CheckTagClass(taggedObjectParser, tagClass).ParseExplicitBaseTagged(); + } + /// public static Asn1TaggedObjectParser ParseExplicitBaseTagged(Asn1TaggedObjectParser taggedObjectParser, int tagClass, int tagNo) @@ -210,6 +287,12 @@ namespace Org.BouncyCastle.Asn1 return CheckTag(taggedObjectParser, tagClass, tagNo).ParseExplicitBaseTagged(); } + /// + public static Asn1TaggedObjectParser ParseExplicitContextBaseTagged(Asn1TaggedObjectParser taggedObjectParser) + { + return ParseExplicitBaseTagged(taggedObjectParser, Asn1Tags.ContextSpecific); + } + /// public static Asn1TaggedObjectParser ParseExplicitContextBaseTagged(Asn1TaggedObjectParser taggedObjectParser, int tagNo) @@ -217,6 +300,16 @@ namespace Org.BouncyCastle.Asn1 return ParseExplicitBaseTagged(taggedObjectParser, Asn1Tags.ContextSpecific, tagNo); } + /// + public static Asn1TaggedObjectParser TryParseExplicitBaseTagged(Asn1TaggedObjectParser taggedObjectParser, + int tagClass) + { + if (taggedObjectParser.TagClass != tagClass) + return null; + + return taggedObjectParser.ParseExplicitBaseTagged(); + } + /// public static Asn1TaggedObjectParser TryParseExplicitBaseTagged(Asn1TaggedObjectParser taggedObjectParser, int tagClass, int tagNo) @@ -227,6 +320,13 @@ namespace Org.BouncyCastle.Asn1 return taggedObjectParser.ParseExplicitBaseTagged(); } + /// + public static Asn1TaggedObjectParser TryParseExplicitContextBaseTagged( + Asn1TaggedObjectParser taggedObjectParser) + { + return TryParseExplicitBaseTagged(taggedObjectParser, Asn1Tags.ContextSpecific); + } + /// public static Asn1TaggedObjectParser TryParseExplicitContextBaseTagged( Asn1TaggedObjectParser taggedObjectParser, int tagNo) diff --git a/crypto/src/asn1/BERTaggedObjectParser.cs b/crypto/src/asn1/BERTaggedObjectParser.cs index ecb4a4a13..b1a8cd896 100644 --- a/crypto/src/asn1/BERTaggedObjectParser.cs +++ b/crypto/src/asn1/BERTaggedObjectParser.cs @@ -32,6 +32,11 @@ namespace Org.BouncyCastle.Asn1 get { return m_tagNo; } } + public bool HasContextTag() + { + return m_tagClass == Asn1Tags.ContextSpecific; + } + public bool HasContextTag(int tagNo) { return m_tagClass == Asn1Tags.ContextSpecific && m_tagNo == tagNo; @@ -42,6 +47,11 @@ namespace Org.BouncyCastle.Asn1 return m_tagClass == tagClass && m_tagNo == tagNo; } + public bool HasTagClass(int tagClass) + { + return m_tagClass == tagClass; + } + public virtual IAsn1Convertible ParseBaseUniversal(bool declaredExplicit, int baseTagNo) { if (declaredExplicit) diff --git a/crypto/src/asn1/BerTaggedObject.cs b/crypto/src/asn1/BerTaggedObject.cs index 4970b76f9..c200a74de 100644 --- a/crypto/src/asn1/BerTaggedObject.cs +++ b/crypto/src/asn1/BerTaggedObject.cs @@ -82,7 +82,7 @@ namespace Org.BouncyCastle.Asn1 internal override Asn1TaggedObject ReplaceTag(int tagClass, int tagNo) { - return new BerTaggedObject(explicitness, tagClass, tagNo, obj); + return new BerTaggedObject(m_explicitness, tagClass, tagNo, m_object); } } } diff --git a/crypto/src/asn1/DLTaggedObject.cs b/crypto/src/asn1/DLTaggedObject.cs index c06dd8e87..30e3334e2 100644 --- a/crypto/src/asn1/DLTaggedObject.cs +++ b/crypto/src/asn1/DLTaggedObject.cs @@ -69,7 +69,7 @@ namespace Org.BouncyCastle.Asn1 internal override Asn1TaggedObject ReplaceTag(int tagClass, int tagNo) { - return new DLTaggedObject(explicitness, tagClass, tagNo, obj); + return new DLTaggedObject(m_explicitness, tagClass, tagNo, m_object); } } } diff --git a/crypto/src/asn1/DerTaggedObject.cs b/crypto/src/asn1/DerTaggedObject.cs index 9d9997dc6..dbcc19760 100644 --- a/crypto/src/asn1/DerTaggedObject.cs +++ b/crypto/src/asn1/DerTaggedObject.cs @@ -76,7 +76,7 @@ namespace Org.BouncyCastle.Asn1 internal override Asn1TaggedObject ReplaceTag(int tagClass, int tagNo) { - return new DerTaggedObject(explicitness, tagClass, tagNo, obj); + return new DerTaggedObject(m_explicitness, tagClass, tagNo, m_object); } } } -- cgit 1.4.1