1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
package org.bouncycastle.asn1;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ASN1StreamParser
{
private final InputStream _in;
private final int _limit;
private static int findLimit(InputStream in)
{
if (in instanceof DefiniteLengthInputStream)
{
return ((DefiniteLengthInputStream)in).getRemaining();
}
return Integer.MAX_VALUE;
}
public ASN1StreamParser(
InputStream in)
{
this(in, findLimit(in));
}
public ASN1StreamParser(
InputStream in,
int limit)
{
this._in = in;
this._limit = limit;
}
public ASN1StreamParser(
byte[] encoding)
{
this(new ByteArrayInputStream(encoding), encoding.length);
}
public DEREncodable 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 & DERTags.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);
if ((tag & DERTags.APPLICATION) != 0)
{
ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
return new BERApplicationSpecificParser(tagNo, sp);
}
if ((tag & DERTags.TAGGED) != 0)
{
return new BERTaggedObjectParser(tag, tagNo, indIn);
}
ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
switch (tagNo)
{
case DERTags.OCTET_STRING:
return new BEROctetStringParser(sp);
case DERTags.SEQUENCE:
return new BERSequenceParser(sp);
case DERTags.SET:
return new BERSetParser(sp);
case DERTags.EXTERNAL:{
return new DERExternalParser(sp);
}
default:
throw new IOException("unknown BER object encountered: 0x" + Integer.toHexString(tagNo));
}
}
else
{
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
if ((tag & DERTags.APPLICATION) != 0)
{
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
}
if ((tag & DERTags.TAGGED) != 0)
{
return new BERTaggedObjectParser(tag, tagNo, defIn);
}
if (isConstructed)
{
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
switch (tagNo)
{
case DERTags.OCTET_STRING:
//
// yes, people actually do this...
//
return new BEROctetStringParser(new ASN1StreamParser(defIn));
case DERTags.SEQUENCE:
return new DERSequenceParser(new ASN1StreamParser(defIn));
case DERTags.SET:
return new DERSetParser(new ASN1StreamParser(defIn));
case DERTags.EXTERNAL:
return new DERExternalParser(new ASN1StreamParser(defIn));
default:
// TODO Add DERUnknownTagParser class?
return new DERUnknownTag(true, tagNo, defIn.toByteArray());
}
}
// Some primitive encodings can be handled by parsers too...
switch (tagNo)
{
case DERTags.OCTET_STRING:
return new DEROctetStringParser(defIn);
}
return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn.toByteArray());
}
}
private void set00Check(boolean enabled)
{
if (_in instanceof IndefiniteLengthInputStream)
{
((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
}
}
ASN1EncodableVector readVector() throws IOException
{
ASN1EncodableVector v = new ASN1EncodableVector();
DEREncodable obj;
while ((obj = readObject()) != null)
{
v.add(obj.getDERObject());
}
return v;
}
}
|