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