diff options
Diffstat (limited to 'crypto/src/asn1/ASN1StreamParser.cs')
-rw-r--r-- | crypto/src/asn1/ASN1StreamParser.cs | 289 |
1 files changed, 159 insertions, 130 deletions
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); + } + } } } |