diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index 0cececb3f..c3d897efb 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -132,6 +132,7 @@
<Compile Include="src\asn1\DerUniversalString.cs" />
<Compile Include="src\asn1\DerVideotexString.cs" />
<Compile Include="src\asn1\DerVisibleString.cs" />
+ <Compile Include="src\asn1\DLApplicationSpecific.cs" />
<Compile Include="src\asn1\DLSequence.cs" />
<Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\DLTaggedObject.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index 2e82e2432..0ffedcb1a 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -126,6 +126,7 @@
<Compile Include="src\asn1\DerUniversalString.cs" />
<Compile Include="src\asn1\DerVideotexString.cs" />
<Compile Include="src\asn1\DerVisibleString.cs" />
+ <Compile Include="src\asn1\DLApplicationSpecific.cs" />
<Compile Include="src\asn1\DLSequence.cs" />
<Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\DLTaggedObject.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index 29031b947..3cd17d407 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -127,6 +127,7 @@
<Compile Include="src\asn1\DerUniversalString.cs" />
<Compile Include="src\asn1\DerVideotexString.cs" />
<Compile Include="src\asn1\DerVisibleString.cs" />
+ <Compile Include="src\asn1\DLApplicationSpecific.cs" />
<Compile Include="src\asn1\DLSequence.cs" />
<Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\DLTaggedObject.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index b490065e0..870cafbe9 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -519,6 +519,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\asn1\DLApplicationSpecific.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\asn1\DLSequence.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index aaa719ecc..13d1ff283 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -13,18 +13,13 @@ namespace Org.BouncyCastle.Asn1
public abstract class Asn1TaggedObject
: Asn1Object, Asn1TaggedObjectParser
{
- // TODO[asn1] Rewrite DerApplicationSpecific in terms of Asn1TaggedObject and remove this
- internal static bool IsConstructed(bool isExplicit, Asn1Object obj)
- {
- if (isExplicit || obj is Asn1Sequence || obj is Asn1Set)
- return true;
- Asn1TaggedObject tagged = obj as Asn1TaggedObject;
- if (tagged == null)
- return false;
- return IsConstructed(tagged.IsExplicit(), tagged.GetObject());
- }
+ private const int DeclaredExplicit = 1;
+ private const int DeclaredImplicit = 2;
+ // TODO It will probably be better to track parsing constructed vs primitive instead
+ private const int ParsedExplicit = 3;
+ private const int ParsedImplicit = 4;
- public static Asn1TaggedObject GetInstance(object obj)
+ public static Asn1TaggedObject GetInstance(object obj)
{
if (obj == null || obj is Asn1TaggedObject)
{
@@ -57,69 +52,91 @@ namespace Org.BouncyCastle.Asn1
if (Asn1Tags.ContextSpecific != taggedObject.TagClass)
throw new InvalidOperationException("this method only valid for CONTEXT_SPECIFIC tags");
- if (!declaredExplicit)
- throw new ArgumentException("this method not valid for implicitly tagged tagged objects");
+ if (declaredExplicit)
+ return taggedObject.GetExplicitBaseTagged();
- return taggedObject.GetExplicitBaseTagged();
+ throw new ArgumentException("this method not valid for implicitly tagged tagged objects");
}
- internal readonly int tagClass = Asn1Tags.ContextSpecific;
+ internal readonly int explicitness;
+ internal readonly int tagClass;
internal readonly int tagNo;
- internal readonly bool explicitly;
internal readonly Asn1Encodable obj;
- /**
+ /**
+ * @param explicitly true if the object is explicitly tagged.
* @param tagNo the tag number for this object.
* @param obj the tagged object.
*/
- protected Asn1TaggedObject(int tagNo, Asn1Encodable obj)
- : this(true, tagNo, obj)
+ protected Asn1TaggedObject(bool isExplicit, int tagNo, Asn1Encodable obj)
+ : this(isExplicit, Asn1Tags.ContextSpecific, tagNo, obj)
{
}
- /**
- * @param explicitly true if the object is explicitly tagged.
- * @param tagNo the tag number for this object.
- * @param obj the tagged object.
- */
- protected Asn1TaggedObject(bool explicitly, int tagNo, Asn1Encodable obj)
+ protected Asn1TaggedObject(bool isExplicit, int tagClass, int tagNo, Asn1Encodable obj)
+ : this(isExplicit ? DeclaredExplicit : DeclaredImplicit, tagClass, tagNo, obj)
+ {
+ }
+
+ internal Asn1TaggedObject(int explicitness, int tagClass, int tagNo, Asn1Encodable obj)
{
if (null == obj)
throw new ArgumentNullException("obj");
+ if (Asn1Tags.Universal == tagClass || (tagClass & Asn1Tags.Private) != tagClass)
+ throw new ArgumentException("invalid tag class: " + tagClass, "tagClass");
- // IAsn1Choice marker interface 'insists' on explicit tagging
- this.explicitly = explicitly || (obj is IAsn1Choice);
+ this.explicitness = (obj is IAsn1Choice) ? DeclaredExplicit : explicitness;
+ this.tagClass = tagClass;
this.tagNo = tagNo;
this.obj = obj;
}
- protected override bool Asn1Equals(Asn1Object asn1Object)
+ protected override bool Asn1Equals(Asn1Object asn1Object)
{
if (asn1Object is DerApplicationSpecific)
return asn1Object.CallAsn1Equals(this);
Asn1TaggedObject that = asn1Object as Asn1TaggedObject;
- return null != that
- && this.tagClass == that.tagClass
- && this.tagNo == that.tagNo
- && this.explicitly == that.explicitly // TODO Should this be part of equality?
- && this.GetObject().Equals(that.GetObject());
- }
+ if (null == that || this.tagNo != that.tagNo || this.tagClass != that.tagClass)
+ return false;
- protected override int Asn1GetHashCode()
- {
- int code = (tagClass * 7919) ^ tagNo;
+ if (this.explicitness != that.explicitness)
+ {
+ /*
+ * TODO This seems incorrect for some cases of implicit tags e.g. if one is a
+ * declared-implicit SET and the other a parsed object.
+ */
+ if (this.IsExplicit() != that.IsExplicit())
+ return false;
+ }
- // TODO: actually this is wrong - the problem is that a re-encoded
- // object may end up with a different hashCode due to implicit
- // tagging. As implicit tagging is ambiguous if a sequence is involved
- // it seems the only correct method for both equals and hashCode is to
- // compare the encodings...
-// code ^= explicitly.GetHashCode();
+ Asn1Object p1 = this.obj.ToAsn1Object();
+ Asn1Object p2 = that.obj.ToAsn1Object();
- code ^= obj.GetHashCode();
+ if (p1 == p2)
+ return true;
+
+ if (!this.IsExplicit())
+ {
+ try
+ {
+ byte[] d1 = this.GetEncoded();
+ byte[] d2 = that.GetEncoded();
- return code;
+ return Arrays.AreEqual(d1, d2);
+ }
+ catch (IOException)
+ {
+ return false;
+ }
+ }
+
+ return p1.CallAsn1Equals(p2);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return (tagClass * 7919) ^ tagNo ^ (IsExplicit() ? 0x0F : 0xF0) ^ obj.ToAsn1Object().CallAsn1GetHashCode();
}
public int TagClass
@@ -142,6 +159,12 @@ namespace Org.BouncyCastle.Asn1
return this.tagClass == tagClass && this.tagNo == tagNo;
}
+ [Obsolete("Will be removed. Replace with constant return value of 'false'")]
+ public bool IsEmpty()
+ {
+ return false;
+ }
+
/**
* return whether or not the object may be explicitly tagged.
* <p>
@@ -153,13 +176,27 @@ namespace Org.BouncyCastle.Asn1
*/
public bool IsExplicit()
{
- return explicitly;
+ // TODO New methods like 'IsKnownExplicit' etc. to distinguish uncertain cases?
+ switch (explicitness)
+ {
+ case DeclaredExplicit:
+ case ParsedExplicit:
+ return true;
+ default:
+ return false;
+ }
}
- [Obsolete("Will be removed. Replace with constant return value of 'false'")]
- public bool IsEmpty()
+ internal bool IsParsed()
{
- return false;
+ switch (explicitness)
+ {
+ case ParsedExplicit:
+ case ParsedImplicit:
+ return true;
+ default:
+ return false;
+ }
}
/**
@@ -198,6 +235,18 @@ namespace Org.BouncyCastle.Asn1
}
/**
+ * Return true if the object is marked as constructed, false otherwise.
+ *
+ * @return true if constructed, otherwise false.
+ */
+ // TODO Need this public if/when DerApplicationSpecific extends Asn1TaggedObject
+ internal bool IsConstructed()
+ {
+ int encoding = Asn1Encoding == Ber ? Asn1OutputStream.EncodingBer : Asn1OutputStream.EncodingDer;
+ return EncodeConstructed(encoding);
+ }
+
+ /**
* return whatever was following the tag.
* <p>
* Note: tagged objects are generally context dependent if you're
@@ -245,6 +294,34 @@ namespace Org.BouncyCastle.Asn1
return CheckedCast(obj.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");
+
+ switch (explicitness)
+ {
+ case DeclaredExplicit:
+ throw new InvalidOperationException("object explicit - implicit expected.");
+
+ case DeclaredImplicit:
+ {
+ Asn1TaggedObject declared = CheckedCast(obj.ToAsn1Object());
+ if (!declared.HasTag(baseTagClass, baseTagNo))
+ {
+ string expected = Asn1Utilities.GetTagText(baseTagClass, baseTagNo);
+ string found = Asn1Utilities.GetTagText(declared);
+ throw new InvalidOperationException("Expected " + expected + " tag but found " + found);
+ }
+ return declared;
+ }
+
+ // Parsed; return a virtual tag (i.e. that couldn't have been present in the encoding)
+ default:
+ return ReplaceTag(baseTagClass, baseTagNo);
+ }
+ }
+
/**
* Return the object held in this tagged object as a parser assuming it has
* the type of the passed in tag. If the object doesn't have a parser
@@ -267,10 +344,8 @@ namespace Org.BouncyCastle.Asn1
return Asn1Set.GetInstance(this, isExplicit).Parser;
}
- if (isExplicit)
- {
- return GetObject();
- }
+ if (isExplicit)
+ return obj.ToAsn1Object();
throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag);
}
@@ -284,6 +359,8 @@ namespace Org.BouncyCastle.Asn1
internal abstract Asn1Sequence RebuildConstructed(Asn1Object asn1Object);
+ internal abstract Asn1TaggedObject ReplaceTag(int tagClass, int tagNo);
+
internal static Asn1Object CreateConstructed(int tagClass, int tagNo, bool isIL,
Asn1EncodableVector contentsElements)
{
@@ -291,29 +368,47 @@ namespace Org.BouncyCastle.Asn1
if (isIL)
{
- if (Asn1Tags.Application == tagClass)
- return new BerApplicationSpecific(tagNo, contentsElements);
+ Asn1TaggedObject taggedObject = maybeExplicit
+ ? new BerTaggedObject(ParsedExplicit, tagClass, tagNo, contentsElements[0])
+ : new BerTaggedObject(ParsedImplicit, tagClass, tagNo, BerSequence.FromVector(contentsElements));
- return maybeExplicit
- ? new BerTaggedObject(true, tagNo, contentsElements[0])
- : new BerTaggedObject(false, tagNo, BerSequence.FromVector(contentsElements));
+ switch (tagClass)
+ {
+ case Asn1Tags.Application:
+ return new BerApplicationSpecific(taggedObject);
+ default:
+ return taggedObject;
+ }
}
+ else
+ {
+ Asn1TaggedObject taggedObject = maybeExplicit
+ ? new DLTaggedObject(ParsedExplicit, tagClass, tagNo, contentsElements[0])
+ : new DLTaggedObject(ParsedImplicit, tagClass, tagNo, DLSequence.FromVector(contentsElements));
- if (Asn1Tags.Application == tagClass)
- return new DerApplicationSpecific(tagNo, contentsElements);
-
- return maybeExplicit
- ? new DLTaggedObject(true, tagNo, contentsElements[0])
- : new DLTaggedObject(false, tagNo, DLSequence.FromVector(contentsElements));
+ switch (tagClass)
+ {
+ case Asn1Tags.Application:
+ return new DLApplicationSpecific(taggedObject);
+ default:
+ return taggedObject;
+ }
+ }
}
internal static Asn1Object CreatePrimitive(int tagClass, int tagNo, byte[] contentsOctets)
{
// Note: !CONSTRUCTED => IMPLICIT
- if (Asn1Tags.Application == tagClass)
- return new DerApplicationSpecific(false, tagNo, contentsOctets);
+ Asn1TaggedObject taggedObject = new DLTaggedObject(ParsedImplicit, tagClass, tagNo,
+ new DerOctetString(contentsOctets));
- return new DLTaggedObject(false, tagNo, new DerOctetString(contentsOctets));
+ switch (tagClass)
+ {
+ case Asn1Tags.Application:
+ return new DLApplicationSpecific(taggedObject);
+ default:
+ return taggedObject;
+ }
}
private static Asn1TaggedObject CheckedCast(Asn1Object asn1Object)
diff --git a/crypto/src/asn1/BerApplicationSpecific.cs b/crypto/src/asn1/BerApplicationSpecific.cs
index 65fbecbe1..2a874984f 100644
--- a/crypto/src/asn1/BerApplicationSpecific.cs
+++ b/crypto/src/asn1/BerApplicationSpecific.cs
@@ -5,11 +5,43 @@ namespace Org.BouncyCastle.Asn1
public class BerApplicationSpecific
: DerApplicationSpecific
{
- public BerApplicationSpecific(
- int tagNo,
- Asn1EncodableVector vec)
- : base(tagNo, vec)
- {
- }
+ /**
+ * Create an application specific object with an explicit tag
+ *
+ * @param tagNo the tag number for this object.
+ * @param baseEncodable the object to be contained.
+ */
+ public BerApplicationSpecific(int tagNo, Asn1Encodable baseEncodable)
+ : this(true, tagNo, baseEncodable)
+ {
+ }
+
+ /**
+ * Create an application specific object with the tagging style given by the value of explicit.
+ *
+ * @param explicit true if the object is explicitly tagged.
+ * @param tagNo the tag number for this object.
+ * @param baseEncodable the object to be contained.
+ */
+ public BerApplicationSpecific(bool isExplicit, int tagNo, Asn1Encodable baseEncodable)
+ : base(new BerTaggedObject(isExplicit, Asn1Tags.Application, tagNo, baseEncodable))
+ {
+ }
+
+ /**
+ * Create an application specific object which is marked as constructed
+ *
+ * @param tagNo the tag number for this object.
+ * @param contentsElements the objects making up the application specific object.
+ */
+ public BerApplicationSpecific(int tagNo, Asn1EncodableVector contentsElements)
+ : base(new BerTaggedObject(false, Asn1Tags.Application, tagNo, BerSequence.FromVector(contentsElements)))
+ {
+ }
+
+ internal BerApplicationSpecific(Asn1TaggedObject taggedObject)
+ : base(taggedObject)
+ {
+ }
}
}
diff --git a/crypto/src/asn1/BerTaggedObject.cs b/crypto/src/asn1/BerTaggedObject.cs
index fc4d1835a..a97a8e143 100644
--- a/crypto/src/asn1/BerTaggedObject.cs
+++ b/crypto/src/asn1/BerTaggedObject.cs
@@ -10,39 +10,49 @@ namespace Org.BouncyCastle.Asn1
public class BerTaggedObject
: DerTaggedObject
{
- /**
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ [Obsolete("Will be removed")]
+ public BerTaggedObject(int tagNo)
+ : base(false, tagNo, BerSequence.Empty)
+ {
+ }
+
+ /**
* @param tagNo the tag number for this object.
* @param obj the tagged object.
*/
- public BerTaggedObject(
- int tagNo,
- Asn1Encodable obj)
- : base(tagNo, obj)
+ public BerTaggedObject(int tagNo, Asn1Encodable obj)
+ : base(true, tagNo, obj)
{
}
- /**
- * @param explicitly true if an explicitly tagged object.
+ public BerTaggedObject(int tagClass, int tagNo, Asn1Encodable obj)
+ : base(true, tagClass, tagNo, obj)
+ {
+ }
+
+ /**
+ * @param isExplicit true if an explicitly tagged object.
* @param tagNo the tag number for this object.
* @param obj the tagged object.
*/
- public BerTaggedObject(
- bool explicitly,
- int tagNo,
- Asn1Encodable obj)
- : base(explicitly, tagNo, obj)
+ public BerTaggedObject(bool isExplicit, int tagNo, Asn1Encodable obj)
+ : base(isExplicit, tagNo, obj)
{
}
- /**
- * create an implicitly tagged object that contains a zero
- * length sequence.
- */
- public BerTaggedObject(
- int tagNo)
- : base(false, tagNo, BerSequence.Empty)
- {
- }
+ public BerTaggedObject(bool isExplicit, int tagClass, int tagNo, Asn1Encodable obj)
+ : base(isExplicit, tagClass, tagNo, obj)
+ {
+ }
+
+ internal BerTaggedObject(int explicitness, int tagClass, int tagNo, Asn1Encodable obj)
+ : base(explicitness, tagClass, tagNo, obj)
+ {
+ }
internal override string Asn1Encoding
{
@@ -116,5 +126,10 @@ namespace Org.BouncyCastle.Asn1
{
return new BerSequence(asn1Object);
}
+
+ internal override Asn1TaggedObject ReplaceTag(int tagClass, int tagNo)
+ {
+ return new BerTaggedObject(explicitness, tagClass, tagNo, obj);
+ }
}
}
diff --git a/crypto/src/asn1/DLApplicationSpecific.cs b/crypto/src/asn1/DLApplicationSpecific.cs
new file mode 100644
index 000000000..8fffcf65b
--- /dev/null
+++ b/crypto/src/asn1/DLApplicationSpecific.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+ internal class DLApplicationSpecific
+ : DerApplicationSpecific
+ {
+ internal DLApplicationSpecific(int tagNo, Asn1Encodable baseEncodable)
+ : this(true, tagNo, baseEncodable)
+ {
+ }
+
+ internal DLApplicationSpecific(bool isExplicit, int tagNo, Asn1Encodable baseEncodable)
+ : base(new DLTaggedObject(isExplicit, Asn1Tags.Application, tagNo, baseEncodable))
+ {
+ }
+
+ internal DLApplicationSpecific(int tagNo, Asn1EncodableVector contentsElements)
+ : base(new DLTaggedObject(false, Asn1Tags.Application, tagNo, DLSequence.FromVector(contentsElements)))
+ {
+ }
+
+ internal DLApplicationSpecific(Asn1TaggedObject taggedObject)
+ : base(taggedObject)
+ {
+ }
+ }
+}
diff --git a/crypto/src/asn1/DLTaggedObject.cs b/crypto/src/asn1/DLTaggedObject.cs
index 1c5e990b4..314b42799 100644
--- a/crypto/src/asn1/DLTaggedObject.cs
+++ b/crypto/src/asn1/DLTaggedObject.cs
@@ -12,13 +12,23 @@ namespace Org.BouncyCastle.Asn1
{
}
- internal DLTaggedObject(bool explicitly, int tagNo, Asn1Encodable obj)
- : base(explicitly, tagNo, obj)
+ internal DLTaggedObject(int tagClass, int tagNo, Asn1Encodable obj)
+ : base(tagClass, tagNo, obj)
{
}
- internal DLTaggedObject(int tagNo)
- : base(false, tagNo, DLSequence.Empty)
+ internal DLTaggedObject(bool isExplicit, int tagNo, Asn1Encodable obj)
+ : base(isExplicit, tagNo, obj)
+ {
+ }
+
+ internal DLTaggedObject(bool isExplicit, int tagClass, int tagNo, Asn1Encodable obj)
+ : base(isExplicit, tagClass, tagNo, obj)
+ {
+ }
+
+ internal DLTaggedObject(int explicitness, int tagClass, int tagNo, Asn1Encodable obj)
+ : base(explicitness, tagClass, tagNo, obj)
{
}
@@ -97,6 +107,11 @@ namespace Org.BouncyCastle.Asn1
return new DLSequence(asn1Object);
}
+ internal override Asn1TaggedObject ReplaceTag(int tagClass, int tagNo)
+ {
+ return new DLTaggedObject(explicitness, tagClass, tagNo, obj);
+ }
+
private int GetContentsLengthDL(Asn1Object baseObject, bool withBaseID)
{
if (m_contentsLengthDL < 0)
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index bc48d24e5..39c2aec28 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -11,225 +11,219 @@ namespace Org.BouncyCastle.Asn1
public class DerApplicationSpecific
: Asn1Object
{
- private readonly bool isConstructed;
- private readonly int tag;
- private readonly byte[] octets;
-
- internal DerApplicationSpecific(
- bool isConstructed,
- int tag,
- byte[] octets)
- {
- this.isConstructed = isConstructed;
- this.tag = tag;
- this.octets = octets;
- }
-
- public DerApplicationSpecific(
- int tag,
- byte[] octets)
- : this(false, tag, octets)
- {
- }
-
- public DerApplicationSpecific(
- int tag,
- Asn1Encodable obj)
- : this(true, tag, obj)
- {
- }
-
- public DerApplicationSpecific(
- bool isExplicit,
- int tag,
- Asn1Encodable obj)
- {
- Asn1Object asn1Obj = obj.ToAsn1Object();
-
- byte[] data = asn1Obj.GetDerEncoded();
-
- this.isConstructed = Asn1TaggedObject.IsConstructed(isExplicit, asn1Obj);
- this.tag = tag;
-
- if (isExplicit)
- {
- this.octets = data;
- }
- else
- {
- int lenBytes = GetLengthOfHeader(data);
- byte[] tmp = new byte[data.Length - lenBytes];
- Array.Copy(data, lenBytes, tmp, 0, tmp.Length);
- this.octets = tmp;
- }
- }
-
- public DerApplicationSpecific(
- int tagNo,
- Asn1EncodableVector vec)
- {
- this.tag = tagNo;
- this.isConstructed = true;
- MemoryStream bOut = new MemoryStream();
-
- for (int i = 0; i != vec.Count; i++)
- {
- try
- {
- byte[] bs = vec[i].GetDerEncoded();
- bOut.Write(bs, 0, bs.Length);
- }
- catch (IOException e)
- {
- throw new InvalidOperationException("malformed object", e);
- }
- }
- this.octets = bOut.ToArray();
- }
-
- private int GetLengthOfHeader(
- byte[] data)
- {
- int length = data[1]; // TODO: assumes 1 byte tag
-
- if (length == 0x80)
+ public static DerApplicationSpecific GetInstance(object obj)
+ {
+ if (obj == null || obj is DerApplicationSpecific)
{
- return 2; // indefinite-length encoding
+ return (DerApplicationSpecific)obj;
}
-
- if (length > 127)
+ else if (obj is byte[])
{
- int size = length & 0x7f;
-
- // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
- if (size > 4)
+ try
{
- throw new InvalidOperationException("DER length more than 4 bytes: " + size);
+ return GetInstance(FromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("failed to construct application-specific from byte[]: " + e.Message);
}
-
- return size + 2;
}
- return 2;
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
}
- public bool IsConstructed()
+ internal readonly Asn1TaggedObject m_taggedObject;
+
+ /**
+ * Create an application specific object from the passed in data. This will assume
+ * the data does not represent a constructed object.
+ *
+ * @param tagNo the tag number for this object.
+ * @param contentsOctets the encoding of the object's body.
+ */
+ public DerApplicationSpecific(int tagNo, byte[] contentsOctets)
+ : this(new DerTaggedObject(false, Asn1Tags.Application, tagNo, new DerOctetString(contentsOctets)))
{
- return isConstructed;
}
- public byte[] GetContents()
+ /**
+ * Create an application specific object with a tagging of explicit/constructed.
+ *
+ * @param tag the tag number for this object.
+ * @param object the object to be contained.
+ */
+ public DerApplicationSpecific(int tag, Asn1Encodable baseEncodable)
+ : this(true, tag, baseEncodable)
{
- return octets;
}
- public int ApplicationTag
+ /**
+ * Create an application specific object with the tagging style given by the value of explicit.
+ *
+ * @param explicit true if the object is explicitly tagged.
+ * @param tagNo the tag number for this object.
+ * @param baseEncodable the object to be contained.
+ */
+ public DerApplicationSpecific(bool isExplicit, int tagNo, Asn1Encodable baseEncodable)
+ : this(new DerTaggedObject(isExplicit, Asn1Tags.Application, tagNo, baseEncodable))
{
- get { return tag; }
}
- /**
- * Return the enclosed object assuming explicit tagging.
- *
- * @return the resulting object
- * @throws IOException if reconstruction fails.
- */
- public Asn1Object GetObject()
+ /**
+ * Create an application specific object which is marked as constructed
+ *
+ * @param tagNo the tag number for this object.
+ * @param contentsElements the objects making up the application specific object.
+ */
+ public DerApplicationSpecific(int tagNo, Asn1EncodableVector contentsElements)
+ : this(new DerTaggedObject(false, Asn1Tags.Application, tagNo, DerSequence.FromVector(contentsElements)))
{
- return FromByteArray(GetContents());
- }
+ }
- /**
- * Return the enclosed object assuming implicit tagging.
- *
- * @param derTagNo the type tag that should be applied to the object's contents.
- * @return the resulting object
- * @throws IOException if reconstruction fails.
- */
- public Asn1Object GetObject(
- int derTagNo)
- {
- if (derTagNo >= 0x1f)
- throw new IOException("unsupported tag number");
+ internal DerApplicationSpecific(Asn1TaggedObject taggedObject)
+ //: base(taggedObject.explicitness, CheckTagClass(taggedObject.tagClass), taggedObject.tagNo,
+ // taggedObject.obj)
+ {
+ CheckTagClass(taggedObject.TagClass);
- byte[] orig = this.GetEncoded();
- byte[] tmp = ReplaceTagNumber(derTagNo, orig);
+ this.m_taggedObject = taggedObject;
+ }
- if ((orig[0] & Asn1Tags.Constructed) != 0)
- {
- tmp[0] |= Asn1Tags.Constructed;
- }
+ public int ApplicationTag
+ {
+ get { return m_taggedObject.TagNo; }
+ }
- return FromByteArray(tmp);
- }
+ public byte[] GetContents()
+ {
+ return m_taggedObject.GetContents();
+ }
- internal override bool EncodeConstructed(int encoding)
+ public Asn1Object GetEnclosedObject()
{
- return isConstructed;
+ return m_taggedObject.GetBaseObject().ToAsn1Object();
}
- internal override int EncodedLength(int encoding, bool withID)
+ [Obsolete("Use GetEnclosedObject instead")]
+ public Asn1Object GetObject()
{
- return Asn1OutputStream.GetLengthOfEncodingDL(withID, tag, octets.Length);
+ return GetEnclosedObject();
}
- internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+ public Asn1Object GetObject(int tagNo)
+ {
+ // TODO[asn1] Implement Asn1TaggedObject.GetBaseUniversal
+ //return taggedObject.GetBaseUniversal(false, tagNo);
+
+ if (tagNo >= 0x1F)
+ throw new IOException("unsupported tag number");
+
+ byte[] orig = this.GetEncoded();
+ byte[] tmp = ReplaceTagNumber(tagNo, orig);
+
+ if ((orig[0] & Asn1Tags.Constructed) != 0)
+ {
+ tmp[0] |= Asn1Tags.Constructed;
+ }
+
+ return FromByteArray(tmp);
+ }
+
+ public bool HasApplicationTag(int tagNo)
+ {
+ return m_taggedObject.HasTag(Asn1Tags.Application, tagNo);
+ }
+
+ public bool IsConstructed()
+ {
+ return m_taggedObject.IsConstructed();
+ }
+
+ /**
+ * DerApplicationSpecific uses an internal Asn1TaggedObject for the
+ * implementation, and will soon be deprecated in favour of using
+ * Asn1TaggedObject with a tag class of {@link Asn1Tags#Application}. This method
+ * lets you get the internal Asn1TaggedObject so that client code can begin the
+ * migration.
+ */
+ public Asn1TaggedObject TaggedObject
{
- int flags = Asn1Tags.Application;
- if (isConstructed)
- {
- flags |= Asn1Tags.Constructed;
- }
+ get { return m_taggedObject; }
+ }
- asn1Out.WriteEncodingDL(withID, flags, tag, octets);
- }
+ protected override bool Asn1Equals(Asn1Object asn1Object)
+ {
+ Asn1TaggedObject that;
+ if (asn1Object is DerApplicationSpecific)
+ {
+ that = ((DerApplicationSpecific)asn1Object).m_taggedObject;
+ }
+ else if (asn1Object is Asn1TaggedObject)
+ {
+ that = (Asn1TaggedObject)asn1Object;
+ }
+ else
+ {
+ return false;
+ }
+
+ return m_taggedObject.Equals(that);
+ }
- protected override bool Asn1Equals(
- Asn1Object asn1Object)
+ protected override int Asn1GetHashCode()
{
- DerApplicationSpecific other = asn1Object as DerApplicationSpecific;
+ return m_taggedObject.CallAsn1GetHashCode();
+ }
- if (other == null)
- return false;
+ internal override bool EncodeConstructed(int encoding)
+ {
+ return m_taggedObject.EncodeConstructed(encoding);
+ }
- return this.isConstructed == other.isConstructed
- && this.tag == other.tag
- && Arrays.AreEqual(this.octets, other.octets);
+ internal override int EncodedLength(int encoding, bool withID)
+ {
+ return m_taggedObject.EncodedLength(encoding, withID);
}
- protected override int Asn1GetHashCode()
- {
- return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(octets);
+ internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+ {
+ m_taggedObject.Encode(asn1Out, withID);
}
- private byte[] ReplaceTagNumber(
- int newTag,
- byte[] input)
- {
- int tagNo = input[0] & 0x1f;
- int index = 1;
+ private byte[] ReplaceTagNumber(int newTag, byte[] input)
+ {
+ int tagNo = input[0] & 0x1f;
+ int index = 1;
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
- if (tagNo == 0x1f)
- {
- int b = input[index++];
+ if (tagNo == 0x1f)
+ {
+ int b = input[index++];
// X.690-0207 8.1.2.4.2
- // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
- if ((b & 0x7f) == 0) // Note: -1 will pass
- throw new IOException("corrupted stream - invalid high tag number found");
+ // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+ if ((b & 0x7f) == 0) // Note: -1 will pass
+ throw new IOException("corrupted stream - invalid high tag number found");
while ((b & 0x80) != 0)
- {
- b = input[index++];
- }
- }
+ {
+ b = input[index++];
+ }
+ }
int remaining = input.Length - index;
byte[] tmp = new byte[1 + remaining];
tmp[0] = (byte)newTag;
- Array.Copy(input, index, tmp, 1, remaining);
- return tmp;
- }
+ Array.Copy(input, index, tmp, 1, remaining);
+ return tmp;
+ }
+
+ private static int CheckTagClass(int tagClass)
+ {
+ if (Asn1Tags.Application != tagClass)
+ throw new ArgumentException();
+
+ return tagClass;
+ }
}
}
diff --git a/crypto/src/asn1/DerTaggedObject.cs b/crypto/src/asn1/DerTaggedObject.cs
index e58590c8d..66f804ebb 100644
--- a/crypto/src/asn1/DerTaggedObject.cs
+++ b/crypto/src/asn1/DerTaggedObject.cs
@@ -13,38 +13,44 @@ namespace Org.BouncyCastle.Asn1
private int m_contentsLengthDer = -1;
/**
- * @param tagNo the tag number for this object.
- * @param obj the tagged object.
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
*/
- public DerTaggedObject(
- int tagNo,
- Asn1Encodable obj)
- : base(tagNo, obj)
+ [Obsolete("Will be removed")]
+ public DerTaggedObject(int tagNo)
+ : base(false, tagNo, DerSequence.Empty)
+ {
+ }
+
+ public DerTaggedObject(int tagNo, Asn1Encodable obj)
+ : base(true, tagNo, obj)
{
}
- /**
- * @param explicitly true if an explicitly tagged object.
+ public DerTaggedObject(int tagClass, int tagNo, Asn1Encodable obj)
+ : base(true, tagClass, tagNo, obj)
+ {
+ }
+
+ /**
+ * @param isExplicit true if an explicitly tagged object.
* @param tagNo the tag number for this object.
* @param obj the tagged object.
*/
- public DerTaggedObject(
- bool explicitly,
- int tagNo,
- Asn1Encodable obj)
- : base(explicitly, tagNo, obj)
+ public DerTaggedObject(bool isExplicit, int tagNo, Asn1Encodable obj)
+ : base(isExplicit, tagNo, obj)
{
}
- /**
- * create an implicitly tagged object that contains a zero
- * length sequence.
- */
- public DerTaggedObject(
- int tagNo)
- : base(false, tagNo, DerSequence.Empty)
- {
- }
+ public DerTaggedObject(bool isExplicit, int tagClass, int tagNo, Asn1Encodable obj)
+ : base(isExplicit, tagClass, tagNo, obj)
+ {
+ }
+
+ internal DerTaggedObject(int explicitness, int tagClass, int tagNo, Asn1Encodable obj)
+ : base(explicitness, tagClass, tagNo, obj)
+ {
+ }
internal override string Asn1Encoding
{
@@ -108,6 +114,11 @@ namespace Org.BouncyCastle.Asn1
return new DerSequence(asn1Object);
}
+ internal override Asn1TaggedObject ReplaceTag(int tagClass, int tagNo)
+ {
+ return new DerTaggedObject(explicitness, tagClass, tagNo, obj);
+ }
+
private int GetContentsLengthDer(Asn1Object baseObject, bool withBaseID)
{
if (m_contentsLengthDer < 0)
diff --git a/crypto/src/asn1/util/Asn1Dump.cs b/crypto/src/asn1/util/Asn1Dump.cs
index 0d3382d00..f573d3663 100644
--- a/crypto/src/asn1/util/Asn1Dump.cs
+++ b/crypto/src/asn1/util/Asn1Dump.cs
@@ -23,11 +23,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
*
* @param obj the Asn1Object to be dumped out.
*/
- private static void AsString(
- string indent,
- bool verbose,
- Asn1Object obj,
- StringBuilder buf)
+ private static void AsString(string indent, bool verbose, Asn1Object obj, StringBuilder buf)
{
if (obj is Asn1Null)
{
@@ -42,7 +38,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
{
buf.Append("BER Sequence");
}
- else if (obj is DerSequence)
+ else if (!(obj is DLSequence))
{
buf.Append("DER Sequence");
}
@@ -67,7 +63,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
{
buf.Append("BER Set");
}
- else if (obj is DerSet)
+ else if (!(obj is DLSet))
{
buf.Append("DER Set");
}
@@ -85,23 +81,29 @@ namespace Org.BouncyCastle.Asn1.Utilities
AsString(elementsIndent, verbose, set[i].ToAsn1Object(), buf);
}
}
+ else if (obj is DerApplicationSpecific)
+ {
+ AsString(indent, verbose, ((DerApplicationSpecific)obj).TaggedObject, buf);
+ }
else if (obj is Asn1TaggedObject)
{
- string tab = indent + Tab;
buf.Append(indent);
if (obj is BerTaggedObject)
{
- buf.Append("BER Tagged [");
+ buf.Append("BER Tagged ");
+ }
+ else if (!(obj is DLTaggedObject))
+ {
+ buf.Append("DER Tagged ");
}
else
{
- buf.Append("Tagged [");
+ buf.Append("Tagged ");
}
Asn1TaggedObject o = (Asn1TaggedObject)obj;
- buf.Append(o.TagNo.ToString());
- buf.Append(']');
+ buf.Append(Asn1Utilities.GetTagText(o));
if (!o.IsExplicit())
{
@@ -110,7 +112,9 @@ namespace Org.BouncyCastle.Asn1.Utilities
buf.Append(NewLine);
- AsString(tab, verbose, o.GetObject(), buf);
+ string baseIndent = indent + Tab;
+
+ AsString(baseIndent, verbose, o.GetBaseObject().ToAsn1Object(), buf);
}
else if (obj is DerObjectIdentifier)
{
@@ -131,20 +135,20 @@ namespace Org.BouncyCastle.Asn1.Utilities
else if (obj is BerOctetString)
{
byte[] octets = ((Asn1OctetString)obj).GetOctets();
- string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+ string extra = verbose ? DumpBinaryDataAsString(indent, octets) : "";
buf.Append(indent + "BER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
}
else if (obj is DerOctetString)
{
byte[] octets = ((Asn1OctetString)obj).GetOctets();
- string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+ string extra = verbose ? DumpBinaryDataAsString(indent, octets) : "";
buf.Append(indent + "DER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
}
else if (obj is DerBitString)
{
DerBitString bt = (DerBitString)obj;
byte[] bytes = bt.GetBytes();
- string extra = verbose ? dumpBinaryDataAsString(indent, bytes) : "";
+ string extra = verbose ? DumpBinaryDataAsString(indent, bytes) : "";
buf.Append(indent + "DER Bit String" + "[" + bytes.Length + ", " + bt.PadBits + "] " + extra + NewLine);
}
else if (obj is DerIA5String)
@@ -187,14 +191,6 @@ namespace Org.BouncyCastle.Asn1.Utilities
{
buf.Append(indent + "GeneralizedTime(" + ((DerGeneralizedTime)obj).GetTime() + ") " + NewLine);
}
- else if (obj is BerApplicationSpecific)
- {
- buf.Append(outputApplicationSpecific("BER", indent, verbose, (BerApplicationSpecific)obj));
- }
- else if (obj is DerApplicationSpecific)
- {
- buf.Append(outputApplicationSpecific("DER", indent, verbose, (DerApplicationSpecific)obj));
- }
else if (obj is DerEnumerated)
{
DerEnumerated en = (DerEnumerated)obj;
@@ -227,44 +223,13 @@ namespace Org.BouncyCastle.Asn1.Utilities
}
}
- private static string outputApplicationSpecific(
- string type,
- string indent,
- bool verbose,
- DerApplicationSpecific app)
- {
- StringBuilder buf = new StringBuilder();
-
- if (app.IsConstructed())
- {
- try
- {
- Asn1Sequence s = Asn1Sequence.GetInstance(app.GetObject(Asn1Tags.Sequence));
- buf.Append(indent + type + " ApplicationSpecific[" + app.ApplicationTag + "]" + NewLine);
- foreach (Asn1Encodable ae in s)
- {
- AsString(indent + Tab, verbose, ae.ToAsn1Object(), buf);
- }
- }
- catch (IOException e)
- {
- buf.Append(e);
- }
- return buf.ToString();
- }
-
- return indent + type + " ApplicationSpecific[" + app.ApplicationTag + "] ("
- + Hex.ToHexString(app.GetContents()) + ")" + NewLine;
- }
-
/**
* dump out a DER object as a formatted string, in non-verbose mode
*
* @param obj the Asn1Encodable to be dumped out.
* @return the resulting string.
*/
- public static string DumpAsString(
- Asn1Encodable obj)
+ public static string DumpAsString(Asn1Encodable obj)
{
return DumpAsString(obj, false);
}
@@ -276,16 +241,14 @@ namespace Org.BouncyCastle.Asn1.Utilities
* @param verbose if true, dump out the contents of octet and bit strings.
* @return the resulting string.
*/
- public static string DumpAsString(
- Asn1Encodable obj,
- bool verbose)
+ public static string DumpAsString(Asn1Encodable obj, bool verbose)
{
StringBuilder buf = new StringBuilder();
AsString("", verbose, obj.ToAsn1Object(), buf);
return buf.ToString();
}
- private static string dumpBinaryDataAsString(string indent, byte[] bytes)
+ private static string DumpBinaryDataAsString(string indent, byte[] bytes)
{
indent += Tab;
@@ -298,7 +261,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
buf.Append(indent);
buf.Append(Hex.ToHexString(bytes, i, SampleSize));
buf.Append(Tab);
- buf.Append(calculateAscString(bytes, i, SampleSize));
+ buf.Append(CalculateAscString(bytes, i, SampleSize));
buf.Append(NewLine);
}
else
@@ -310,7 +273,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
buf.Append(" ");
}
buf.Append(Tab);
- buf.Append(calculateAscString(bytes, i, bytes.Length - i));
+ buf.Append(CalculateAscString(bytes, i, bytes.Length - i));
buf.Append(NewLine);
}
}
@@ -318,10 +281,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
return buf.ToString();
}
- private static string calculateAscString(
- byte[] bytes,
- int off,
- int len)
+ private static string CalculateAscString(byte[] bytes, int off, int len)
{
StringBuilder buf = new StringBuilder();
|