Home | History | Annotate | Download | only in asn1
      1 package org.bouncycastle.asn1;
      2 
      3 import java.io.ByteArrayInputStream;
      4 import java.io.IOException;
      5 import java.io.InputStream;
      6 
      7 public class ASN1StreamParser
      8 {
      9     private final InputStream _in;
     10     private final int         _limit;
     11     private final byte[][] tmpBuffers;
     12 
     13     public ASN1StreamParser(
     14         InputStream in)
     15     {
     16         this(in, StreamUtil.findLimit(in));
     17     }
     18 
     19     public ASN1StreamParser(
     20         InputStream in,
     21         int         limit)
     22     {
     23         this._in = in;
     24         this._limit = limit;
     25 
     26         this.tmpBuffers = new byte[11][];
     27     }
     28 
     29     public ASN1StreamParser(
     30         byte[] encoding)
     31     {
     32         this(new ByteArrayInputStream(encoding), encoding.length);
     33     }
     34 
     35     ASN1Encodable readIndef(int tagValue) throws IOException
     36     {
     37         // Note: INDEF => CONSTRUCTED
     38 
     39         // TODO There are other tags that may be constructed (e.g. BIT_STRING)
     40         switch (tagValue)
     41         {
     42             case BERTags.EXTERNAL:
     43                 return new DERExternalParser(this);
     44             case BERTags.OCTET_STRING:
     45                 return new BEROctetStringParser(this);
     46             case BERTags.SEQUENCE:
     47                 return new BERSequenceParser(this);
     48             case BERTags.SET:
     49                 return new BERSetParser(this);
     50             default:
     51                 throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
     52         }
     53     }
     54 
     55     ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException
     56     {
     57         if (_in instanceof IndefiniteLengthInputStream)
     58         {
     59             if (!constructed)
     60             {
     61                 throw new IOException("indefinite length primitive encoding encountered");
     62             }
     63 
     64             return readIndef(tag);
     65         }
     66 
     67         if (constructed)
     68         {
     69             switch (tag)
     70             {
     71                 case BERTags.SET:
     72                     return new DERSetParser(this);
     73                 case BERTags.SEQUENCE:
     74                     return new DERSequenceParser(this);
     75                 case BERTags.OCTET_STRING:
     76                     return new BEROctetStringParser(this);
     77             }
     78         }
     79         else
     80         {
     81             switch (tag)
     82             {
     83                 case BERTags.SET:
     84                     throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
     85                 case BERTags.SEQUENCE:
     86                     throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
     87                 case BERTags.OCTET_STRING:
     88                     return new DEROctetStringParser((DefiniteLengthInputStream)_in);
     89             }
     90         }
     91 
     92         // TODO ASN1Exception
     93         throw new RuntimeException("implicit tagging not implemented");
     94     }
     95 
     96     ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException
     97     {
     98         if (!constructed)
     99         {
    100             // Note: !CONSTRUCTED => IMPLICIT
    101             DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
    102             return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray()));
    103         }
    104 
    105         ASN1EncodableVector v = readVector();
    106 
    107         if (_in instanceof IndefiniteLengthInputStream)
    108         {
    109             return v.size() == 1
    110                 ?   new BERTaggedObject(true, tag, v.get(0))
    111                 :   new BERTaggedObject(false, tag, BERFactory.createSequence(v));
    112         }
    113 
    114         return v.size() == 1
    115             ?   new DERTaggedObject(true, tag, v.get(0))
    116             :   new DERTaggedObject(false, tag, DERFactory.createSequence(v));
    117     }
    118 
    119     public ASN1Encodable readObject()
    120         throws IOException
    121     {
    122         int tag = _in.read();
    123         if (tag == -1)
    124         {
    125             return null;
    126         }
    127 
    128         //
    129         // turn of looking for "00" while we resolve the tag
    130         //
    131         set00Check(false);
    132 
    133         //
    134         // calculate tag number
    135         //
    136         int tagNo = ASN1InputStream.readTagNumber(_in, tag);
    137 
    138         boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;
    139 
    140         //
    141         // calculate length
    142         //
    143         int length = ASN1InputStream.readLength(_in, _limit);
    144 
    145         if (length < 0) // indefinite length method
    146         {
    147             if (!isConstructed)
    148             {
    149                 throw new IOException("indefinite length primitive encoding encountered");
    150             }
    151 
    152             IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
    153             ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
    154 
    155             if ((tag & BERTags.APPLICATION) != 0)
    156             {
    157                 return new BERApplicationSpecificParser(tagNo, sp);
    158             }
    159 
    160             if ((tag & BERTags.TAGGED) != 0)
    161             {
    162                 return new BERTaggedObjectParser(true, tagNo, sp);
    163             }
    164 
    165             return sp.readIndef(tagNo);
    166         }
    167         else
    168         {
    169             DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
    170 
    171             if ((tag & BERTags.APPLICATION) != 0)
    172             {
    173                 return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
    174             }
    175 
    176             if ((tag & BERTags.TAGGED) != 0)
    177             {
    178                 return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
    179             }
    180 
    181             if (isConstructed)
    182             {
    183                 // TODO There are other tags that may be constructed (e.g. BIT_STRING)
    184                 switch (tagNo)
    185                 {
    186                     case BERTags.OCTET_STRING:
    187                         //
    188                         // yes, people actually do this...
    189                         //
    190                         return new BEROctetStringParser(new ASN1StreamParser(defIn));
    191                     case BERTags.SEQUENCE:
    192                         return new DERSequenceParser(new ASN1StreamParser(defIn));
    193                     case BERTags.SET:
    194                         return new DERSetParser(new ASN1StreamParser(defIn));
    195                     case BERTags.EXTERNAL:
    196                         return new DERExternalParser(new ASN1StreamParser(defIn));
    197                     default:
    198                         throw new IOException("unknown tag " + tagNo + " encountered");
    199                 }
    200             }
    201 
    202             // Some primitive encodings can be handled by parsers too...
    203             switch (tagNo)
    204             {
    205                 case BERTags.OCTET_STRING:
    206                     return new DEROctetStringParser(defIn);
    207             }
    208 
    209             try
    210             {
    211                 return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
    212             }
    213             catch (IllegalArgumentException e)
    214             {
    215                 throw new ASN1Exception("corrupted stream detected", e);
    216             }
    217         }
    218     }
    219 
    220     private void set00Check(boolean enabled)
    221     {
    222         if (_in instanceof IndefiniteLengthInputStream)
    223         {
    224             ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
    225         }
    226     }
    227 
    228     ASN1EncodableVector readVector() throws IOException
    229     {
    230         ASN1EncodableVector v = new ASN1EncodableVector();
    231 
    232         ASN1Encodable obj;
    233         while ((obj = readObject()) != null)
    234         {
    235             if (obj instanceof InMemoryRepresentable)
    236             {
    237                 v.add(((InMemoryRepresentable)obj).getLoadedObject());
    238             }
    239             else
    240             {
    241                 v.add(obj.toASN1Primitive());
    242             }
    243         }
    244 
    245         return v;
    246     }
    247 }
    248