001package org.apache.commons.ssl.org.bouncycastle.asn1; 002 003import java.io.ByteArrayInputStream; 004import java.io.IOException; 005import java.io.InputStream; 006 007/** 008 * A parser for ASN.1 streams which also returns, where possible, parsers for the objects it encounters. 009 */ 010public class ASN1StreamParser 011{ 012 private final InputStream _in; 013 private final int _limit; 014 private final byte[][] tmpBuffers; 015 016 public ASN1StreamParser( 017 InputStream in) 018 { 019 this(in, StreamUtil.findLimit(in)); 020 } 021 022 public ASN1StreamParser( 023 InputStream in, 024 int limit) 025 { 026 this._in = in; 027 this._limit = limit; 028 029 this.tmpBuffers = new byte[11][]; 030 } 031 032 public ASN1StreamParser( 033 byte[] encoding) 034 { 035 this(new ByteArrayInputStream(encoding), encoding.length); 036 } 037 038 ASN1Encodable readIndef(int tagValue) throws IOException 039 { 040 // Note: INDEF => CONSTRUCTED 041 042 // TODO There are other tags that may be constructed (e.g. BIT_STRING) 043 switch (tagValue) 044 { 045 case BERTags.EXTERNAL: 046 return new DERExternalParser(this); 047 case BERTags.OCTET_STRING: 048 return new BEROctetStringParser(this); 049 case BERTags.SEQUENCE: 050 return new BERSequenceParser(this); 051 case BERTags.SET: 052 return new BERSetParser(this); 053 default: 054 throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue)); 055 } 056 } 057 058 ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException 059 { 060 if (_in instanceof IndefiniteLengthInputStream) 061 { 062 if (!constructed) 063 { 064 throw new IOException("indefinite length primitive encoding encountered"); 065 } 066 067 return readIndef(tag); 068 } 069 070 if (constructed) 071 { 072 switch (tag) 073 { 074 case BERTags.SET: 075 return new DERSetParser(this); 076 case BERTags.SEQUENCE: 077 return new DERSequenceParser(this); 078 case BERTags.OCTET_STRING: 079 return new BEROctetStringParser(this); 080 } 081 } 082 else 083 { 084 switch (tag) 085 { 086 case BERTags.SET: 087 throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)"); 088 case BERTags.SEQUENCE: 089 throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)"); 090 case BERTags.OCTET_STRING: 091 return new DEROctetStringParser((DefiniteLengthInputStream)_in); 092 } 093 } 094 095 // TODO ASN1Exception 096 throw new RuntimeException("implicit tagging not implemented"); 097 } 098 099 ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException 100 { 101 if (!constructed) 102 { 103 // Note: !CONSTRUCTED => IMPLICIT 104 DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in; 105 return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); 106 } 107 108 ASN1EncodableVector v = readVector(); 109 110 if (_in instanceof IndefiniteLengthInputStream) 111 { 112 return v.size() == 1 113 ? new BERTaggedObject(true, tag, v.get(0)) 114 : new BERTaggedObject(false, tag, BERFactory.createSequence(v)); 115 } 116 117 return v.size() == 1 118 ? new DERTaggedObject(true, tag, v.get(0)) 119 : new DERTaggedObject(false, tag, DERFactory.createSequence(v)); 120 } 121 122 public ASN1Encodable readObject() 123 throws IOException 124 { 125 int tag = _in.read(); 126 if (tag == -1) 127 { 128 return null; 129 } 130 131 // 132 // turn of looking for "00" while we resolve the tag 133 // 134 set00Check(false); 135 136 // 137 // calculate tag number 138 // 139 int tagNo = ASN1InputStream.readTagNumber(_in, tag); 140 141 boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0; 142 143 // 144 // calculate length 145 // 146 int length = ASN1InputStream.readLength(_in, _limit); 147 148 if (length < 0) // indefinite length method 149 { 150 if (!isConstructed) 151 { 152 throw new IOException("indefinite length primitive encoding encountered"); 153 } 154 155 IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); 156 ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit); 157 158 if ((tag & BERTags.APPLICATION) != 0) 159 { 160 return new BERApplicationSpecificParser(tagNo, sp); 161 } 162 163 if ((tag & BERTags.TAGGED) != 0) 164 { 165 return new BERTaggedObjectParser(true, tagNo, sp); 166 } 167 168 return sp.readIndef(tagNo); 169 } 170 else 171 { 172 DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); 173 174 if ((tag & BERTags.APPLICATION) != 0) 175 { 176 return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); 177 } 178 179 if ((tag & BERTags.TAGGED) != 0) 180 { 181 return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn)); 182 } 183 184 if (isConstructed) 185 { 186 // TODO There are other tags that may be constructed (e.g. BIT_STRING) 187 switch (tagNo) 188 { 189 case BERTags.OCTET_STRING: 190 // 191 // yes, people actually do this... 192 // 193 return new BEROctetStringParser(new ASN1StreamParser(defIn)); 194 case BERTags.SEQUENCE: 195 return new DERSequenceParser(new ASN1StreamParser(defIn)); 196 case BERTags.SET: 197 return new DERSetParser(new ASN1StreamParser(defIn)); 198 case BERTags.EXTERNAL: 199 return new DERExternalParser(new ASN1StreamParser(defIn)); 200 default: 201 throw new IOException("unknown tag " + tagNo + " encountered"); 202 } 203 } 204 205 // Some primitive encodings can be handled by parsers too... 206 switch (tagNo) 207 { 208 case BERTags.OCTET_STRING: 209 return new DEROctetStringParser(defIn); 210 } 211 212 try 213 { 214 return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers); 215 } 216 catch (IllegalArgumentException e) 217 { 218 throw new ASN1Exception("corrupted stream detected", e); 219 } 220 } 221 } 222 223 private void set00Check(boolean enabled) 224 { 225 if (_in instanceof IndefiniteLengthInputStream) 226 { 227 ((IndefiniteLengthInputStream)_in).setEofOn00(enabled); 228 } 229 } 230 231 ASN1EncodableVector readVector() throws IOException 232 { 233 ASN1EncodableVector v = new ASN1EncodableVector(); 234 235 ASN1Encodable obj; 236 while ((obj = readObject()) != null) 237 { 238 if (obj instanceof InMemoryRepresentable) 239 { 240 v.add(((InMemoryRepresentable)obj).getLoadedObject()); 241 } 242 else 243 { 244 v.add(obj.toASN1Primitive()); 245 } 246 } 247 248 return v; 249 } 250}