diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index cdc4843bd..198ec093e 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -144,6 +144,7 @@
<Compile Include="src\asn1\DLSequence.cs" />
<Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\DLTaggedObject.cs" />
+ <Compile Include="src\asn1\DLTaggedObjectParser.cs" />
<Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs" />
<Compile Include="src\asn1\IAsn1Choice.cs" />
<Compile Include="src\asn1\IAsn1Convertible.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index bbcfd9324..849dd3202 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -138,6 +138,7 @@
<Compile Include="src\asn1\DLSequence.cs" />
<Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\DLTaggedObject.cs" />
+ <Compile Include="src\asn1\DLTaggedObjectParser.cs" />
<Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs" />
<Compile Include="src\asn1\IAsn1Choice.cs" />
<Compile Include="src\asn1\IAsn1Convertible.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index 415992207..456a15b19 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -139,6 +139,7 @@
<Compile Include="src\asn1\DLSequence.cs" />
<Compile Include="src\asn1\DLSet.cs" />
<Compile Include="src\asn1\DLTaggedObject.cs" />
+ <Compile Include="src\asn1\DLTaggedObjectParser.cs" />
<Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs" />
<Compile Include="src\asn1\IAsn1Choice.cs" />
<Compile Include="src\asn1\IAsn1Convertible.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 72fcfe5b9..a588a961a 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -579,6 +579,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\asn1\DLTaggedObjectParser.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\asn1\IAsn1ApplicationSpecificParser.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs
index 51af50728..6128c9b78 100644
--- a/crypto/src/asn1/ASN1StreamParser.cs
+++ b/crypto/src/asn1/ASN1StreamParser.cs
@@ -35,105 +35,36 @@ namespace Org.BouncyCastle.Asn1
this.tmpBuffers = tmpBuffers;
}
- internal IAsn1Convertible ReadIndef(int tagNo)
- {
- // Note: INDEF => CONSTRUCTED
-
- // TODO There are other tags that may be constructed (e.g. BIT_STRING)
- switch (tagNo)
- {
- case Asn1Tags.External:
- return new DerExternalParser(this);
- case Asn1Tags.OctetString:
- return new BerOctetStringParser(this);
- case Asn1Tags.Sequence:
- return new BerSequenceParser(this);
- case Asn1Tags.Set:
- return new BerSetParser(this);
- default:
- throw new Asn1Exception("unknown BER object encountered: 0x" + tagNo.ToString("X"));
- }
- }
-
- internal IAsn1Convertible ReadImplicit(bool constructed, int tagNo)
- {
- if (_in is IndefiniteLengthInputStream)
- {
- if (!constructed)
- throw new IOException("indefinite-length primitive encoding encountered");
-
- return ReadIndef(tagNo);
- }
-
- if (constructed)
- {
- switch (tagNo)
- {
- case Asn1Tags.Set:
- return new DerSetParser(this);
- case Asn1Tags.Sequence:
- return new DerSequenceParser(this);
- case Asn1Tags.OctetString:
- return new BerOctetStringParser(this);
- }
- }
- else
- {
- switch (tagNo)
- {
- case Asn1Tags.Set:
- throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
- case Asn1Tags.Sequence:
- throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
- case Asn1Tags.OctetString:
- return new DerOctetStringParser((DefiniteLengthInputStream)_in);
- }
- }
-
- throw new Asn1Exception("implicit tagging not implemented");
- }
-
- internal Asn1Object ReadTaggedObject(int tagClass, int tagNo, bool constructed)
- {
- if (!constructed)
- {
- // Note: !CONSTRUCTED => IMPLICIT
- byte[] contentsOctets = ((DefiniteLengthInputStream)_in).ToArray();
- return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets);
- }
-
- bool isIL = (_in is IndefiniteLengthInputStream);
- Asn1EncodableVector contentsElements = ReadVector();
- return Asn1TaggedObject.CreateConstructed(tagClass, tagNo, isIL, contentsElements);
- }
-
public virtual IAsn1Convertible ReadObject()
{
int tagHdr = _in.ReadByte();
- if (tagHdr == -1)
+ if (tagHdr < 0)
return null;
- // turn off looking for "00" while we resolve the tag
- Set00Check(false);
+ return ImplParseObject(tagHdr);
+ }
+
+ internal IAsn1Convertible ImplParseObject(int tagHdr)
+ {
+ // turn off looking for "00" while we resolve the tag
+ Set00Check(false);
//
// calculate tag number
//
int tagNo = Asn1InputStream.ReadTagNumber(_in, tagHdr);
- bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
-
//
// calculate length
//
int length = Asn1InputStream.ReadLength(_in, _limit,
- tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence || tagNo == Asn1Tags.Set ||
- tagNo == Asn1Tags.External);
+ tagNo == Asn1Tags.BitString || tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence ||
+ tagNo == Asn1Tags.Set || tagNo == Asn1Tags.External);
if (length < 0) // indefinite-length method
{
- if (!isConstructed)
- throw new IOException("indefinite-length primitive encoding encountered");
+ if (0 == (tagHdr & Asn1Tags.Constructed))
+ throw new IOException("indefinite-length primitive encoding encountered");
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit, tmpBuffers);
@@ -144,86 +75,184 @@ namespace Org.BouncyCastle.Asn1
if (Asn1Tags.Application == tagClass)
return new BerApplicationSpecificParser(tagNo, sp);
- return new BerTaggedObjectParser(tagClass, tagNo, true, sp);
+ return new BerTaggedObjectParser(tagClass, tagNo, sp);
}
- return sp.ReadIndef(tagNo);
+ return sp.ParseImplicitConstructedIL(tagNo);
}
else
{
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
+ if (0 == (tagHdr & Asn1Tags.Flags))
+ return ParseImplicitPrimitive(tagNo, defIn);
+
+ Asn1StreamParser sp = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
+
int tagClass = tagHdr & Asn1Tags.Private;
if (0 != tagClass)
{
- Asn1StreamParser sub = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
+ bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
+ // TODO[asn1] Special handling can be removed once ASN1ApplicationSpecific types removed.
if (Asn1Tags.Application == tagClass)
- return (DLApplicationSpecific)sub.ReadTaggedObject(tagClass, tagNo, isConstructed);
-
- return new BerTaggedObjectParser(tagClass, tagNo, isConstructed, sub);
- }
-
- if (!isConstructed)
- {
- // Some primitive encodings can be handled by parsers too...
- switch (tagNo)
{
- case Asn1Tags.OctetString:
- return new DerOctetStringParser(defIn);
+ // This cast is ensuring the current user-expected return type.
+ return (DLApplicationSpecific)sp.LoadTaggedDL(tagClass, tagNo, isConstructed);
}
- try
- {
- return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
- }
- catch (ArgumentException e)
- {
- throw new Asn1Exception("corrupted stream detected", e);
- }
+ return new DLTaggedObjectParser(tagClass, tagNo, isConstructed, sp);
}
- Asn1StreamParser sp = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
-
- // TODO There are other tags that may be constructed (e.g. BitString)
- switch (tagNo)
- {
- case Asn1Tags.OctetString:
- return new BerOctetStringParser(sp);
- case Asn1Tags.Sequence:
- return new DerSequenceParser(sp);
- case Asn1Tags.Set:
- return new DerSetParser(sp);
- case Asn1Tags.External:
- return new DerExternalParser(sp);
- default:
- throw new IOException("unknown tag " + tagNo + " encountered");
- }
+ return sp.ParseImplicitConstructedDL(tagNo);
}
}
- private void Set00Check(
- bool enabled)
- {
- if (_in is IndefiniteLengthInputStream)
- {
- ((IndefiniteLengthInputStream) _in).SetEofOn00(enabled);
- }
- }
+ internal Asn1Object LoadTaggedDL(int tagClass, int tagNo, bool constructed)
+ {
+ if (!constructed)
+ {
+ byte[] contentsOctets = ((DefiniteLengthInputStream)_in).ToArray();
+ return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets);
+ }
+
+ Asn1EncodableVector contentsElements = ReadVector();
+ return Asn1TaggedObject.CreateConstructedDL(tagClass, tagNo, contentsElements);
+ }
+
+ internal Asn1Object LoadTaggedIL(int tagClass, int tagNo)
+ {
+ Asn1EncodableVector contentsElements = ReadVector();
+ return Asn1TaggedObject.CreateConstructedIL(tagClass, tagNo, contentsElements);
+ }
+
+ internal IAsn1Convertible ParseImplicitConstructedDL(int univTagNo)
+ {
+ switch (univTagNo)
+ {
+ // TODO[asn1] DLConstructedBitStringParser
+ //case Asn1Tags.BitString:
+ // return new BerBitStringParser(this);
+ case Asn1Tags.External:
+ return new DerExternalParser(this);
+ case Asn1Tags.OctetString:
+ // TODO[asn1] DLConstructedOctetStringParser
+ return new BerOctetStringParser(this);
+ case Asn1Tags.Set:
+ return new DerSetParser(this);
+ case Asn1Tags.Sequence:
+ return new DerSequenceParser(this);
+ default:
+ throw new Asn1Exception("unknown DL object encountered: 0x" + univTagNo.ToString("X"));
+ }
+ }
+
+ internal IAsn1Convertible ParseImplicitConstructedIL(int univTagNo)
+ {
+ switch (univTagNo)
+ {
+ // TODO[asn1] BerBitStringParser
+ //case Asn1Tags.BitString:
+ // return new BerBitStringParser(this);
+ case Asn1Tags.External:
+ // TODO[asn1] BERExternalParser
+ return new DerExternalParser(this);
+ case Asn1Tags.OctetString:
+ return new BerOctetStringParser(this);
+ case Asn1Tags.Sequence:
+ return new BerSequenceParser(this);
+ case Asn1Tags.Set:
+ return new BerSetParser(this);
+ default:
+ throw new Asn1Exception("unknown BER object encountered: 0x" + univTagNo.ToString("X"));
+ }
+ }
+
+ internal IAsn1Convertible ParseImplicitPrimitive(int univTagNo)
+ {
+ return ParseImplicitPrimitive(univTagNo, (DefiniteLengthInputStream)_in);
+ }
+ internal IAsn1Convertible ParseImplicitPrimitive(int univTagNo, DefiniteLengthInputStream defIn)
+ {
+ // Some primitive encodings can be handled by parsers too...
+ switch (univTagNo)
+ {
+ // TODO[asn1] DLBitStringParser
+ //case Asn1Tags.BitString:
+ // return new DLBitStringParser(defIn);
+ case Asn1Tags.External:
+ throw new Asn1Exception("externals must use constructed encoding (see X.690 8.18)");
+ case Asn1Tags.OctetString:
+ return new DerOctetStringParser(defIn);
+ case Asn1Tags.Set:
+ throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+ case Asn1Tags.Sequence:
+ throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+ }
+
+ try
+ {
+ return Asn1InputStream.CreatePrimitiveDerObject(univTagNo, defIn, tmpBuffers);
+ }
+ catch (ArgumentException e)
+ {
+ throw new Asn1Exception("corrupted stream detected", e);
+ }
+ }
+
+ internal IAsn1Convertible ParseObject(int univTagNo)
+ {
+ if (univTagNo < 0 || univTagNo > 30)
+ throw new ArgumentException("invalid universal tag number: " + univTagNo, "univTagNo");
+
+ int tagHdr = _in.ReadByte();
+ if (tagHdr < 0)
+ return null;
+
+ if ((tagHdr & ~Asn1Tags.Constructed) != univTagNo)
+ throw new IOException("unexpected identifier encountered: " + tagHdr);
+
+ return ImplParseObject(tagHdr);
+ }
+
+ internal Asn1TaggedObjectParser ParseTaggedObject()
+ {
+ int tagHdr = _in.ReadByte();
+ if (tagHdr< 0)
+ return null;
+
+ int tagClass = tagHdr & Asn1Tags.Private;
+ if (0 == tagClass)
+ throw new Asn1Exception("no tagged object found");
+
+ return (Asn1TaggedObjectParser)ImplParseObject(tagHdr);
+ }
+
+ // TODO[asn1] Prefer 'LoadVector'
internal Asn1EncodableVector ReadVector()
{
- IAsn1Convertible obj = ReadObject();
- if (null == obj)
+ int tagHdr = _in.ReadByte();
+ if (tagHdr < 0)
return new Asn1EncodableVector(0);
Asn1EncodableVector v = new Asn1EncodableVector();
do
{
+ IAsn1Convertible obj = ImplParseObject(tagHdr);
+
v.Add(obj.ToAsn1Object());
}
- while ((obj = ReadObject()) != null);
+ while ((tagHdr = _in.ReadByte()) >= 0);
return v;
}
+
+ private void Set00Check(bool enabled)
+ {
+ if (_in is IndefiniteLengthInputStream)
+ {
+ ((IndefiniteLengthInputStream)_in).SetEofOn00(enabled);
+ }
+ }
}
}
diff --git a/crypto/src/asn1/ASN1TaggedObjectParser.cs b/crypto/src/asn1/ASN1TaggedObjectParser.cs
index d125ddc1a..68b83f290 100644
--- a/crypto/src/asn1/ASN1TaggedObjectParser.cs
+++ b/crypto/src/asn1/ASN1TaggedObjectParser.cs
@@ -21,6 +21,15 @@ namespace Org.BouncyCastle.Asn1
/// <exception cref="IOException"/>
IAsn1Convertible ParseBaseUniversal(bool declaredExplicit, int baseTagNo);
+ /// <summary>Needed for open types, until we have better type-guided parsing support.</summary>
+ /// <remarks>
+ /// Use sparingly for other purposes, and prefer <see cref="ParseExplicitBaseTagged"/> or
+ /// <see cref="ParseBaseUniversal(bool, int)"/> where possible. Before using, check for matching tag
+ /// <see cref="TagClass">class</see> and <see cref="TagNo">number</see>.
+ /// </remarks>
+ /// <exception cref="IOException"/>
+ IAsn1Convertible ParseExplicitBaseObject();
+
/// <exception cref="IOException"/>
Asn1TaggedObjectParser ParseExplicitBaseTagged();
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index d03c7a6b5..8ddfc022b 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -75,16 +75,19 @@ namespace Org.BouncyCastle.Asn1
*/
private Asn1Object BuildObject(int tagHdr, int tagNo, int length)
{
- bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
+ // TODO[asn1] Special-case zero length first?
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length, limit);
+ if (0 == (tagHdr & Asn1Tags.Flags))
+ return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
+
int tagClass = tagHdr & Asn1Tags.Private;
if (0 != tagClass)
- return ReadTaggedObject(tagClass, tagNo, isConstructed, defIn);
-
- if (!isConstructed)
- return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
+ {
+ bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
+ return ReadTaggedObjectDL(tagClass, tagNo, isConstructed, defIn);
+ }
switch (tagNo)
{
@@ -103,7 +106,7 @@ namespace Org.BouncyCastle.Asn1
}
}
- internal Asn1Object ReadTaggedObject(int tagClass, int tagNo, bool constructed, DefiniteLengthInputStream defIn)
+ internal Asn1Object ReadTaggedObjectDL(int tagClass, int tagNo, bool constructed, DefiniteLengthInputStream defIn)
{
if (!constructed)
{
@@ -111,9 +114,8 @@ namespace Org.BouncyCastle.Asn1
return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets);
}
- bool isIL = false;
Asn1EncodableVector contentsElements = ReadVector(defIn);
- return Asn1TaggedObject.CreateConstructed(tagClass, tagNo, isIL, contentsElements);
+ return Asn1TaggedObject.CreateConstructedDL(tagClass, tagNo, contentsElements);
}
internal virtual Asn1EncodableVector ReadVector()
@@ -187,11 +189,13 @@ namespace Org.BouncyCastle.Asn1
int tagClass = tagHdr & Asn1Tags.Private;
if (0 != tagClass)
- return sp.ReadTaggedObject(tagClass, tagNo, true);
+ return sp.LoadTaggedIL(tagClass, tagNo);
- // TODO There are other tags that may be constructed (e.g. BitString)
switch (tagNo)
{
+ // TODO[asn1] BerBitStringParser
+ //case Asn1Tags.BitString:
+ // return BerBitStringParser.Parse(sp);
case Asn1Tags.OctetString:
return BerOctetStringParser.Parse(sp);
case Asn1Tags.Sequence:
@@ -199,6 +203,7 @@ namespace Org.BouncyCastle.Asn1
case Asn1Tags.Set:
return BerSetParser.Parse(sp);
case Asn1Tags.External:
+ // TODO[asn1] BerExternalParser
return DerExternalParser.Parse(sp);
default:
throw new IOException("unknown BER object encountered");
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index c7c0db6fc..ce5e9e3f2 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -396,6 +396,11 @@ namespace Org.BouncyCastle.Asn1
return asn1Object;
}
+ public IAsn1Convertible ParseExplicitBaseObject()
+ {
+ return GetExplicitBaseObject();
+ }
+
public Asn1TaggedObjectParser ParseExplicitBaseTagged()
{
return GetExplicitBaseTagged();
@@ -417,38 +422,37 @@ namespace Org.BouncyCastle.Asn1
internal abstract Asn1TaggedObject ReplaceTag(int tagClass, int tagNo);
- internal static Asn1Object CreateConstructed(int tagClass, int tagNo, bool isIL,
- Asn1EncodableVector contentsElements)
+ internal static Asn1Object CreateConstructedDL(int tagClass, int tagNo, Asn1EncodableVector contentsElements)
{
bool maybeExplicit = (contentsElements.Count == 1);
- if (isIL)
- {
- Asn1TaggedObject taggedObject = maybeExplicit
- ? new BerTaggedObject(ParsedExplicit, tagClass, tagNo, contentsElements[0])
- : new BerTaggedObject(ParsedImplicit, tagClass, tagNo, BerSequence.FromVector(contentsElements));
+ Asn1TaggedObject taggedObject = maybeExplicit
+ ? new DLTaggedObject(ParsedExplicit, tagClass, tagNo, contentsElements[0])
+ : new DLTaggedObject(ParsedImplicit, tagClass, tagNo, DLSequence.FromVector(contentsElements));
- switch (tagClass)
- {
- case Asn1Tags.Application:
- return new BerApplicationSpecific(taggedObject);
- default:
- return taggedObject;
- }
- }
- else
+ switch (tagClass)
{
- Asn1TaggedObject taggedObject = maybeExplicit
- ? new DLTaggedObject(ParsedExplicit, tagClass, tagNo, contentsElements[0])
- : new DLTaggedObject(ParsedImplicit, tagClass, tagNo, DLSequence.FromVector(contentsElements));
+ case Asn1Tags.Application:
+ return new DLApplicationSpecific(taggedObject);
+ default:
+ return taggedObject;
+ }
+ }
- switch (tagClass)
- {
- case Asn1Tags.Application:
- return new DLApplicationSpecific(taggedObject);
- default:
- return taggedObject;
- }
+ internal static Asn1Object CreateConstructedIL(int tagClass, int tagNo, Asn1EncodableVector contentsElements)
+ {
+ bool maybeExplicit = (contentsElements.Count == 1);
+
+ Asn1TaggedObject taggedObject = maybeExplicit
+ ? new BerTaggedObject(ParsedExplicit, tagClass, tagNo, contentsElements[0])
+ : new BerTaggedObject(ParsedImplicit, tagClass, tagNo, BerSequence.FromVector(contentsElements));
+
+ switch (tagClass)
+ {
+ case Asn1Tags.Application:
+ return new BerApplicationSpecific(taggedObject);
+ default:
+ return taggedObject;
}
}
diff --git a/crypto/src/asn1/Asn1Tags.cs b/crypto/src/asn1/Asn1Tags.cs
index 692acdf50..670fb7d96 100644
--- a/crypto/src/asn1/Asn1Tags.cs
+++ b/crypto/src/asn1/Asn1Tags.cs
@@ -45,5 +45,7 @@ namespace Org.BouncyCastle.Asn1
public const int Tagged = 0x80;
public const int ContextSpecific = 0x80;
public const int Private = 0xC0;
+
+ public const int Flags = 0xE0;
}
}
diff --git a/crypto/src/asn1/Asn1Utilities.cs b/crypto/src/asn1/Asn1Utilities.cs
index 8a6d931c0..5605d4c54 100644
--- a/crypto/src/asn1/Asn1Utilities.cs
+++ b/crypto/src/asn1/Asn1Utilities.cs
@@ -289,5 +289,41 @@ namespace Org.BouncyCastle.Asn1
return TryParseBaseUniversal(taggedObjectParser, Asn1Tags.ContextSpecific, tagNo, declaredExplicit,
baseTagNo);
}
+
+
+ /*
+ * Wrappers for Asn1TaggedObjectParser.ParseExplicitBaseObject
+ */
+
+ /// <exception cref="IOException"/>
+ public static IAsn1Convertible ParseExplicitBaseObject(Asn1TaggedObjectParser taggedObjectParser, int tagClass,
+ int tagNo)
+ {
+ return CheckTag(taggedObjectParser, tagClass, tagNo).ParseExplicitBaseObject();
+ }
+
+ /// <exception cref="IOException"/>
+ public static IAsn1Convertible ParseExplicitContextBaseObject(Asn1TaggedObjectParser taggedObjectParser,
+ int tagNo)
+ {
+ return ParseExplicitBaseObject(taggedObjectParser, Asn1Tags.ContextSpecific, tagNo);
+ }
+
+ /// <exception cref="IOException"/>
+ public static IAsn1Convertible TryParseExplicitBaseObject(Asn1TaggedObjectParser taggedObjectParser,
+ int tagClass, int tagNo)
+ {
+ if (!taggedObjectParser.HasTag(tagClass, tagNo))
+ return null;
+
+ return taggedObjectParser.ParseExplicitBaseObject();
+ }
+
+ /// <exception cref="IOException"/>
+ public static IAsn1Convertible TryParseExplicitContextBaseObject(Asn1TaggedObjectParser taggedObjectParser,
+ int tagNo)
+ {
+ return TryParseExplicitBaseObject(taggedObjectParser, Asn1Tags.ContextSpecific, tagNo);
+ }
}
}
diff --git a/crypto/src/asn1/BERTaggedObjectParser.cs b/crypto/src/asn1/BERTaggedObjectParser.cs
index a54e3ce38..c87f6cf9a 100644
--- a/crypto/src/asn1/BERTaggedObjectParser.cs
+++ b/crypto/src/asn1/BERTaggedObjectParser.cs
@@ -3,25 +3,24 @@ using System.IO;
namespace Org.BouncyCastle.Asn1
{
+ [Obsolete("Will be made non-public. Test for and use only Asn1TaggedObjectParser.")]
public class BerTaggedObjectParser
: Asn1TaggedObjectParser
{
- private readonly int m_tagClass;
- private readonly int m_tagNo;
- private readonly bool m_constructed;
- private readonly Asn1StreamParser m_parser;
+ internal readonly int m_tagClass;
+ internal readonly int m_tagNo;
+ internal readonly Asn1StreamParser m_parser;
- internal BerTaggedObjectParser(int tagClass, int tagNo, bool constructed, Asn1StreamParser parser)
+ internal BerTaggedObjectParser(int tagClass, int tagNo, Asn1StreamParser parser)
{
- this.m_tagClass = tagClass;
- this.m_tagNo = tagNo;
- this.m_constructed = constructed;
- this.m_parser = parser;
+ m_tagClass = tagClass;
+ m_tagNo = tagNo;
+ m_parser = parser;
}
- public bool IsConstructed
+ public virtual bool IsConstructed
{
- get { return m_constructed; }
+ get { return true; }
}
public int TagClass
@@ -53,40 +52,39 @@ namespace Org.BouncyCastle.Asn1
return ParseBaseUniversal(declaredExplicit, baseTagNo);
}
- public IAsn1Convertible ParseBaseUniversal(bool declaredExplicit, int baseTagNo)
+ public virtual IAsn1Convertible ParseBaseUniversal(bool declaredExplicit, int baseTagNo)
{
if (declaredExplicit)
- {
- if (!m_constructed)
- throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+ return m_parser.ParseObject(baseTagNo);
- // TODO[asn1] Alternate parser method specific to this case
- return m_parser.ReadObject();
- }
-
- return m_parser.ReadImplicit(m_constructed, baseTagNo);
+ return m_parser.ParseImplicitConstructedIL(baseTagNo);
}
- public Asn1TaggedObjectParser ParseExplicitBaseTagged()
+ public virtual IAsn1Convertible ParseExplicitBaseObject()
{
- if (!m_constructed)
- throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+ return m_parser.ReadObject();
+ }
- // TODO[asn1] Alternate parser method specific to this case
- return (Asn1TaggedObjectParser)m_parser.ReadObject();
+ public virtual Asn1TaggedObjectParser ParseExplicitBaseTagged()
+ {
+ return m_parser.ParseTaggedObject();
}
- public Asn1TaggedObjectParser ParseImplicitBaseTagged(int baseTagClass, int baseTagNo)
+ public virtual Asn1TaggedObjectParser ParseImplicitBaseTagged(int baseTagClass, int baseTagNo)
{
- return new BerTaggedObjectParser(baseTagClass, baseTagNo, m_constructed, m_parser);
+ // TODO[asn1] Special handling can be removed once ASN1ApplicationSpecificParser types removed.
+ if (Asn1Tags.Application == baseTagClass)
+ return new BerApplicationSpecificParser(baseTagNo, m_parser);
+
+ return new BerTaggedObjectParser(baseTagClass, baseTagNo, m_parser);
}
- public Asn1Object ToAsn1Object()
+ public virtual Asn1Object ToAsn1Object()
{
try
{
- return m_parser.ReadTaggedObject(TagClass, TagNo, IsConstructed);
- }
+ return m_parser.LoadTaggedIL(TagClass, TagNo);
+ }
catch (IOException e)
{
throw new Asn1ParsingException(e.Message);
diff --git a/crypto/src/asn1/BerApplicationSpecificParser.cs b/crypto/src/asn1/BerApplicationSpecificParser.cs
index 899e76ca5..75b7e7632 100644
--- a/crypto/src/asn1/BerApplicationSpecificParser.cs
+++ b/crypto/src/asn1/BerApplicationSpecificParser.cs
@@ -6,14 +6,14 @@ namespace Org.BouncyCastle.Asn1
: BerTaggedObjectParser, IAsn1ApplicationSpecificParser
{
internal BerApplicationSpecificParser(int tagNo, Asn1StreamParser parser)
- : base(Asn1Tags.Application, tagNo, true, parser)
+ : base(Asn1Tags.Application, tagNo, parser)
{
}
public IAsn1Convertible ReadObject()
{
// NOTE: No way to say you're looking for an implicitly-tagged object via IAsn1ApplicationSpecificParser
- return ParseBaseUniversal(true, -1);
- }
+ return ParseExplicitBaseObject();
+ }
}
}
diff --git a/crypto/src/asn1/DLTaggedObjectParser.cs b/crypto/src/asn1/DLTaggedObjectParser.cs
new file mode 100644
index 000000000..307a6342a
--- /dev/null
+++ b/crypto/src/asn1/DLTaggedObjectParser.cs
@@ -0,0 +1,81 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Parser for definite-length tagged objects.
+ */
+ internal class DLTaggedObjectParser
+ : BerTaggedObjectParser
+ {
+ private readonly bool m_constructed;
+
+ internal DLTaggedObjectParser(int tagClass, int tagNo, bool constructed, Asn1StreamParser parser)
+ : base(tagClass, tagNo, parser)
+ {
+ m_constructed = constructed;
+ }
+
+ public override bool IsConstructed
+ {
+ get { return m_constructed; }
+ }
+
+ public override IAsn1Convertible ParseBaseUniversal(bool declaredExplicit, int baseTagNo)
+ {
+ if (declaredExplicit)
+ {
+ if (!m_constructed)
+ throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+
+ return m_parser.ParseObject(baseTagNo);
+ }
+
+ return m_constructed
+ ? m_parser.ParseImplicitConstructedDL(baseTagNo)
+ : m_parser.ParseImplicitPrimitive(baseTagNo);
+ }
+
+ public override IAsn1Convertible ParseExplicitBaseObject()
+ {
+ if (!m_constructed)
+ throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+
+ return m_parser.ReadObject();
+ }
+
+ public override Asn1TaggedObjectParser ParseExplicitBaseTagged()
+ {
+ if (!m_constructed)
+ throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+
+ return m_parser.ParseTaggedObject();
+ }
+
+ public override Asn1TaggedObjectParser ParseImplicitBaseTagged(int baseTagClass, int baseTagNo)
+ {
+ // TODO[asn1] Special handling can be removed once ASN1ApplicationSpecificParser types removed.
+ if (Asn1Tags.Application == baseTagClass)
+ {
+ // This cast is ensuring the current user-expected return type.
+ return (DLApplicationSpecific)m_parser.LoadTaggedDL(baseTagClass, baseTagNo, m_constructed);
+ }
+
+ return new DLTaggedObjectParser(baseTagClass, baseTagNo, m_constructed, m_parser);
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ try
+ {
+ return m_parser.LoadTaggedDL(TagClass, TagNo, m_constructed);
+ }
+ catch (IOException e)
+ {
+ throw new Asn1ParsingException(e.Message);
+ }
+ }
+ }
+}
+
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index 92443b917..d474034ed 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -126,6 +126,11 @@ namespace Org.BouncyCastle.Asn1
return m_taggedObject.ParseBaseUniversal(declaredExplicit, baseTagNo);
}
+ public IAsn1Convertible ParseExplicitBaseObject()
+ {
+ return TaggedObject.ParseExplicitBaseObject();
+ }
+
public Asn1TaggedObjectParser ParseExplicitBaseTagged()
{
return m_taggedObject.ParseExplicitBaseTagged();
@@ -160,7 +165,7 @@ namespace Org.BouncyCastle.Asn1
public IAsn1Convertible ReadObject()
{
// NOTE: No way to say you're looking for an implicitly-tagged object via IAsn1ApplicationSpecificParser
- return m_taggedObject.GetBaseObject();
+ return ParseExplicitBaseObject();
}
public int TagClass
diff --git a/crypto/src/asn1/cms/ContentInfoParser.cs b/crypto/src/asn1/cms/ContentInfoParser.cs
index 541cc0f59..750d8ba7a 100644
--- a/crypto/src/asn1/cms/ContentInfoParser.cs
+++ b/crypto/src/asn1/cms/ContentInfoParser.cs
@@ -13,28 +13,28 @@ namespace Org.BouncyCastle.Asn1.Cms
*/
public class ContentInfoParser
{
- private DerObjectIdentifier contentType;
- private Asn1TaggedObjectParser content;
+ private readonly DerObjectIdentifier m_contentType;
+ private readonly Asn1TaggedObjectParser m_content;
- public ContentInfoParser(
- Asn1SequenceParser seq)
+ public ContentInfoParser(Asn1SequenceParser seq)
{
- contentType = (DerObjectIdentifier)seq.ReadObject();
- content = (Asn1TaggedObjectParser)seq.ReadObject();
+ m_contentType = (DerObjectIdentifier)seq.ReadObject();
+ m_content = (Asn1TaggedObjectParser)seq.ReadObject();
}
public DerObjectIdentifier ContentType
{
- get { return contentType; }
+ get { return m_contentType; }
}
- public IAsn1Convertible GetContent(
- int tag)
+ public IAsn1Convertible GetContent(int tag)
{
- if (content == null)
+ if (null == m_content)
return null;
- return content.GetObjectParser(tag, true);
- }
+ // TODO[cms] Ideally we could enforce the claimed tag
+ //return Asn1Utilities.ParseContextBaseUniversal(content, 0, true, tag);
+ return Asn1Utilities.ParseExplicitContextBaseObject(m_content, 0);
+ }
}
}
diff --git a/crypto/test/src/asn1/test/InputStreamTest.cs b/crypto/test/src/asn1/test/InputStreamTest.cs
index ab5200905..8f29b41ac 100644
--- a/crypto/test/src/asn1/test/InputStreamTest.cs
+++ b/crypto/test/src/asn1/test/InputStreamTest.cs
@@ -77,7 +77,7 @@ namespace Org.BouncyCastle.Asn1.Tests
// TODO Test data has length issues too; needs to be reworked
//DoTestWithByteArray(classCast1, "unknown object encountered: Org.BouncyCastle.Asn1.DerApplicationSpecific");
- DoTestWithByteArray(classCast2, "unknown object encountered: Org.BouncyCastle.Asn1.BerTaggedObjectParser");
+ DoTestWithByteArray(classCast2, "unknown object encountered: Org.BouncyCastle.Asn1.DLTaggedObjectParser");
DoTestWithByteArray(classCast3, "unknown object encountered in constructed OCTET STRING: Org.BouncyCastle.Asn1.DLTaggedObject");
// TODO Error dependent on parser choices; needs to be reworked
|