diff options
Diffstat (limited to 'core/src/main/jdk1.1/org/spongycastle/asn1/ASN1StreamParser.java')
-rw-r--r-- | core/src/main/jdk1.1/org/spongycastle/asn1/ASN1StreamParser.java | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/core/src/main/jdk1.1/org/spongycastle/asn1/ASN1StreamParser.java b/core/src/main/jdk1.1/org/spongycastle/asn1/ASN1StreamParser.java new file mode 100644 index 00000000..bbaef056 --- /dev/null +++ b/core/src/main/jdk1.1/org/spongycastle/asn1/ASN1StreamParser.java @@ -0,0 +1,247 @@ +package org.spongycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ASN1StreamParser +{ + private InputStream _in; + private int _limit; + private byte[][] tmpBuffers; + + public ASN1StreamParser( + InputStream in) + { + this(in, StreamUtil.findLimit(in)); + } + + public ASN1StreamParser( + InputStream in, + int limit) + { + this._in = in; + this._limit = limit; + + this.tmpBuffers = new byte[11][]; + } + + public ASN1StreamParser( + byte[] encoding) + { + this(new ByteArrayInputStream(encoding), encoding.length); + } + + ASN1Encodable readIndef(int tagValue) throws IOException + { + // Note: INDEF => CONSTRUCTED + + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagValue) + { + case BERTags.EXTERNAL: + return new DERExternalParser(this); + case BERTags.OCTET_STRING: + return new BEROctetStringParser(this); + case BERTags.SEQUENCE: + return new BERSequenceParser(this); + case BERTags.SET: + return new BERSetParser(this); + default: + throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue)); + } + } + + ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException + { + if (_in instanceof IndefiniteLengthInputStream) + { + if (!constructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + return readIndef(tag); + } + + if (constructed) + { + switch (tag) + { + case BERTags.SET: + return new DERSetParser(this); + case BERTags.SEQUENCE: + return new DERSequenceParser(this); + case BERTags.OCTET_STRING: + return new BEROctetStringParser(this); + } + } + else + { + switch (tag) + { + case BERTags.SET: + throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)"); + case BERTags.SEQUENCE: + throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)"); + case BERTags.OCTET_STRING: + return new DEROctetStringParser((DefiniteLengthInputStream)_in); + } + } + + // TODO ASN1Exception + throw new RuntimeException("implicit tagging not implemented"); + } + + ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException + { + if (!constructed) + { + // Note: !CONSTRUCTED => IMPLICIT + DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in; + return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); + } + + ASN1EncodableVector v = readVector(); + + if (_in instanceof IndefiniteLengthInputStream) + { + return v.size() == 1 + ? new BERTaggedObject(true, tag, v.get(0)) + : new BERTaggedObject(false, tag, BERFactory.createSequence(v)); + } + + return v.size() == 1 + ? new DERTaggedObject(true, tag, v.get(0)) + : new DERTaggedObject(false, tag, DERFactory.createSequence(v)); + } + + public ASN1Encodable readObject() + throws IOException + { + int tag = _in.read(); + if (tag == -1) + { + return null; + } + + // + // turn of looking for "00" while we resolve the tag + // + set00Check(false); + + // + // calculate tag number + // + int tagNo = ASN1InputStream.readTagNumber(_in, tag); + + boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0; + + // + // calculate length + // + int length = ASN1InputStream.readLength(_in, _limit); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); + ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit); + + if ((tag & BERTags.APPLICATION) != 0) + { + return new BERApplicationSpecificParser(tagNo, sp); + } + + if ((tag & BERTags.TAGGED) != 0) + { + return new BERTaggedObjectParser(true, tagNo, sp); + } + + return sp.readIndef(tagNo); + } + else + { + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); + + if ((tag & BERTags.APPLICATION) != 0) + { + return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + } + + if ((tag & BERTags.TAGGED) != 0) + { + return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn)); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case BERTags.OCTET_STRING: + // + // yes, people actually do this... + // + return new BEROctetStringParser(new ASN1StreamParser(defIn)); + case BERTags.SEQUENCE: + return new DERSequenceParser(new ASN1StreamParser(defIn)); + case BERTags.SET: + return new DERSetParser(new ASN1StreamParser(defIn)); + case BERTags.EXTERNAL: + return new DERExternalParser(new ASN1StreamParser(defIn)); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } + + // Some primitive encodings can be handled by parsers too... + switch (tagNo) + { + case BERTags.OCTET_STRING: + return new DEROctetStringParser(defIn); + } + + try + { + return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers); + } + catch (IllegalArgumentException e) + { + throw new ASN1Exception("corrupted stream detected", e); + } + } + } + + private void set00Check(boolean enabled) + { + if (_in instanceof IndefiniteLengthInputStream) + { + ((IndefiniteLengthInputStream)_in).setEofOn00(enabled); + } + } + + ASN1EncodableVector readVector() throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + ASN1Encodable obj; + while ((obj = readObject()) != null) + { + if (obj instanceof InMemoryRepresentable) + { + v.add(((InMemoryRepresentable)obj).getLoadedObject()); + } + else + { + v.add(obj.toASN1Primitive()); + } + } + + return v; + } +} |