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