1 package org.bouncycastle.asn1; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.EOFException; 5 import java.io.FilterInputStream; 6 import java.io.IOException; 7 import java.io.InputStream; 8 9 /** 10 * Don't use this class. It will eventually disappear, use ASN1InputStream. 11 * <br> 12 * This class is scheduled for removal. 13 * @deprecated use ASN1InputStream 14 */ 15 public class DERInputStream 16 extends FilterInputStream implements DERTags 17 { 18 /** 19 * @deprecated use ASN1InputStream 20 */ 21 public DERInputStream( 22 InputStream is) 23 { 24 super(is); 25 } 26 27 protected int readLength() 28 throws IOException 29 { 30 int length = read(); 31 if (length < 0) 32 { 33 throw new IOException("EOF found when length expected"); 34 } 35 36 if (length == 0x80) 37 { 38 return -1; // indefinite-length encoding 39 } 40 41 if (length > 127) 42 { 43 int size = length & 0x7f; 44 45 if (size > 4) 46 { 47 throw new IOException("DER length more than 4 bytes"); 48 } 49 50 length = 0; 51 for (int i = 0; i < size; i++) 52 { 53 int next = read(); 54 55 if (next < 0) 56 { 57 throw new IOException("EOF found reading length"); 58 } 59 60 length = (length << 8) + next; 61 } 62 63 if (length < 0) 64 { 65 throw new IOException("corrupted steam - negative length found"); 66 } 67 } 68 69 return length; 70 } 71 72 protected void readFully( 73 byte[] bytes) 74 throws IOException 75 { 76 int left = bytes.length; 77 78 if (left == 0) 79 { 80 return; 81 } 82 83 while (left > 0) 84 { 85 int l = read(bytes, bytes.length - left, left); 86 87 if (l < 0) 88 { 89 throw new EOFException("unexpected end of stream"); 90 } 91 92 left -= l; 93 } 94 } 95 96 /** 97 * build an object given its tag and a byte stream to construct it 98 * from. 99 */ 100 protected DERObject buildObject( 101 int tag, 102 byte[] bytes) 103 throws IOException 104 { 105 switch (tag) 106 { 107 case NULL: 108 return null; 109 case SEQUENCE | CONSTRUCTED: 110 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); 111 BERInputStream dIn = new BERInputStream(bIn); 112 DERConstructedSequence seq = new DERConstructedSequence(); 113 114 try 115 { 116 for (;;) 117 { 118 DERObject obj = dIn.readObject(); 119 120 seq.addObject(obj); 121 } 122 } 123 catch (EOFException ex) 124 { 125 return seq; 126 } 127 case SET | CONSTRUCTED: 128 bIn = new ByteArrayInputStream(bytes); 129 dIn = new BERInputStream(bIn); 130 131 ASN1EncodableVector v = new ASN1EncodableVector(); 132 133 try 134 { 135 for (;;) 136 { 137 DERObject obj = dIn.readObject(); 138 139 v.add(obj); 140 } 141 } 142 catch (EOFException ex) 143 { 144 return new DERConstructedSet(v); 145 } 146 case BOOLEAN: 147 // BEGIN android-changed 148 return DERBoolean.getInstance(bytes); 149 // BEGIN android-changed 150 case INTEGER: 151 return new DERInteger(bytes); 152 case ENUMERATED: 153 return new DEREnumerated(bytes); 154 case OBJECT_IDENTIFIER: 155 return new DERObjectIdentifier(bytes); 156 case BIT_STRING: 157 int padBits = bytes[0]; 158 byte[] data = new byte[bytes.length - 1]; 159 160 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 161 162 return new DERBitString(data, padBits); 163 case UTF8_STRING: 164 return new DERUTF8String(bytes); 165 case PRINTABLE_STRING: 166 return new DERPrintableString(bytes); 167 case IA5_STRING: 168 return new DERIA5String(bytes); 169 case T61_STRING: 170 return new DERT61String(bytes); 171 case VISIBLE_STRING: 172 return new DERVisibleString(bytes); 173 case UNIVERSAL_STRING: 174 return new DERUniversalString(bytes); 175 case GENERAL_STRING: 176 return new DERGeneralString(bytes); 177 case BMP_STRING: 178 return new DERBMPString(bytes); 179 case OCTET_STRING: 180 return new DEROctetString(bytes); 181 case UTC_TIME: 182 return new DERUTCTime(bytes); 183 case GENERALIZED_TIME: 184 return new DERGeneralizedTime(bytes); 185 default: 186 // 187 // with tagged object tag number is bottom 5 bits 188 // 189 if ((tag & TAGGED) != 0) 190 { 191 if ((tag & 0x1f) == 0x1f) 192 { 193 throw new IOException("unsupported high tag encountered"); 194 } 195 196 if (bytes.length == 0) // empty tag! 197 { 198 if ((tag & CONSTRUCTED) == 0) 199 { 200 // BEGIN android-changed 201 return new DERTaggedObject(false, tag & 0x1f, DERNull.THE_ONE); 202 // END android-changed 203 } 204 else 205 { 206 return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence()); 207 } 208 } 209 210 // 211 // simple type - implicit... return an octet string 212 // 213 if ((tag & CONSTRUCTED) == 0) 214 { 215 return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes)); 216 } 217 218 bIn = new ByteArrayInputStream(bytes); 219 dIn = new BERInputStream(bIn); 220 221 DEREncodable dObj = dIn.readObject(); 222 223 // 224 // explicitly tagged (probably!) - if it isn't we'd have to 225 // tell from the context 226 // 227 if (dIn.available() == 0) 228 { 229 return new DERTaggedObject(tag & 0x1f, dObj); 230 } 231 232 // 233 // another implicit object, we'll create a sequence... 234 // 235 seq = new DERConstructedSequence(); 236 237 seq.addObject(dObj); 238 239 try 240 { 241 for (;;) 242 { 243 dObj = dIn.readObject(); 244 245 seq.addObject(dObj); 246 } 247 } 248 catch (EOFException ex) 249 { 250 // ignore -- 251 } 252 253 return new DERTaggedObject(false, tag & 0x1f, seq); 254 } 255 256 return new DERUnknownTag(tag, bytes); 257 } 258 } 259 260 public DERObject readObject() 261 throws IOException 262 { 263 int tag = read(); 264 if (tag == -1) 265 { 266 throw new EOFException(); 267 } 268 269 int length = readLength(); 270 byte[] bytes = new byte[length]; 271 272 readFully(bytes); 273 274 return buildObject(tag, bytes); 275 } 276 } 277