001 package org.apache.commons.ssl.asn1; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.EOFException; 005 import java.io.FilterInputStream; 006 import java.io.IOException; 007 import java.io.InputStream; 008 009 /** 010 * Don't use this class. It will eventually disappear, use ASN1InputStream. 011 * <br> 012 * This class is scheduled for removal. 013 * 014 * @deprecated use ASN1InputStream 015 */ 016 public class DERInputStream 017 extends FilterInputStream implements DERTags { 018 /** @deprecated use ASN1InputStream */ 019 public DERInputStream( 020 InputStream is) { 021 super(is); 022 } 023 024 protected int readLength() 025 throws IOException { 026 int length = read(); 027 if (length < 0) { 028 throw new IOException("EOF found when length expected"); 029 } 030 031 if (length == 0x80) { 032 return -1; // indefinite-length encoding 033 } 034 035 if (length > 127) { 036 int size = length & 0x7f; 037 038 if (size > 4) { 039 throw new IOException("DER length more than 4 bytes"); 040 } 041 042 length = 0; 043 for (int i = 0; i < size; i++) { 044 int next = read(); 045 046 if (next < 0) { 047 throw new IOException("EOF found reading length"); 048 } 049 050 length = (length << 8) + next; 051 } 052 053 if (length < 0) { 054 throw new IOException("corrupted stream - negative length found"); 055 } 056 } 057 058 return length; 059 } 060 061 protected void readFully( 062 byte[] bytes) 063 throws IOException { 064 int left = bytes.length; 065 066 if (left == 0) { 067 return; 068 } 069 070 while (left > 0) { 071 int l = read(bytes, bytes.length - left, left); 072 073 if (l < 0) { 074 throw new EOFException("unexpected end of stream"); 075 } 076 077 left -= l; 078 } 079 } 080 081 /** 082 * build an object given its tag and a byte stream to construct it 083 * from. 084 */ 085 protected DERObject buildObject( 086 int tag, 087 byte[] bytes) 088 throws IOException { 089 switch (tag) { 090 case NULL: 091 return null; 092 case SEQUENCE | CONSTRUCTED: 093 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); 094 BERInputStream dIn = new BERInputStream(bIn); 095 DERConstructedSequence seq = new DERConstructedSequence(); 096 097 try { 098 for (; ;) { 099 DERObject obj = dIn.readObject(); 100 101 seq.addObject(obj); 102 } 103 } 104 catch (EOFException ex) { 105 return seq; 106 } 107 case SET | CONSTRUCTED: 108 bIn = new ByteArrayInputStream(bytes); 109 dIn = new BERInputStream(bIn); 110 111 ASN1EncodableVector v = new ASN1EncodableVector(); 112 113 try { 114 for (; ;) { 115 DERObject obj = dIn.readObject(); 116 117 v.add(obj); 118 } 119 } 120 catch (EOFException ex) { 121 return new DERConstructedSet(v); 122 } 123 case BOOLEAN: 124 return new DERBoolean(bytes); 125 case INTEGER: 126 return new DERInteger(bytes); 127 case ENUMERATED: 128 return new DEREnumerated(bytes); 129 case OBJECT_IDENTIFIER: 130 return new DERObjectIdentifier(bytes); 131 case BIT_STRING: 132 int padBits = bytes[0]; 133 byte[] data = new byte[bytes.length - 1]; 134 135 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 136 137 return new DERBitString(data, padBits); 138 case UTF8_STRING: 139 return new DERUTF8String(bytes); 140 case PRINTABLE_STRING: 141 return new DERPrintableString(bytes); 142 case IA5_STRING: 143 return new DERIA5String(bytes); 144 case T61_STRING: 145 return new DERT61String(bytes); 146 case VISIBLE_STRING: 147 return new DERVisibleString(bytes); 148 case UNIVERSAL_STRING: 149 return new DERUniversalString(bytes); 150 case GENERAL_STRING: 151 return new DERGeneralString(bytes); 152 case BMP_STRING: 153 return new DERBMPString(bytes); 154 case OCTET_STRING: 155 return new DEROctetString(bytes); 156 case UTC_TIME: 157 return new DERUTCTime(bytes); 158 case GENERALIZED_TIME: 159 return new DERGeneralizedTime(bytes); 160 default: 161 // 162 // with tagged object tag number is bottom 5 bits 163 // 164 if ((tag & TAGGED) != 0) { 165 if ((tag & 0x1f) == 0x1f) { 166 throw new IOException("unsupported high tag encountered"); 167 } 168 169 if (bytes.length == 0) // empty tag! 170 { 171 if ((tag & CONSTRUCTED) == 0) { 172 return new DERTaggedObject(false, tag & 0x1f, new DERNull()); 173 } else { 174 return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence()); 175 } 176 } 177 178 // 179 // simple type - implicit... return an octet string 180 // 181 if ((tag & CONSTRUCTED) == 0) { 182 return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes)); 183 } 184 185 bIn = new ByteArrayInputStream(bytes); 186 dIn = new BERInputStream(bIn); 187 188 DEREncodable dObj = dIn.readObject(); 189 190 // 191 // explicitly tagged (probably!) - if it isn't we'd have to 192 // tell from the context 193 // 194 if (dIn.available() == 0) { 195 return new DERTaggedObject(tag & 0x1f, dObj); 196 } 197 198 // 199 // another implicit object, we'll create a sequence... 200 // 201 seq = new DERConstructedSequence(); 202 203 seq.addObject(dObj); 204 205 try { 206 for (; ;) { 207 dObj = dIn.readObject(); 208 209 seq.addObject(dObj); 210 } 211 } 212 catch (EOFException ex) { 213 // ignore -- 214 } 215 216 return new DERTaggedObject(false, tag & 0x1f, seq); 217 } 218 219 return new DERUnknownTag(tag, bytes); 220 } 221 } 222 223 public DERObject readObject() 224 throws IOException { 225 int tag = read(); 226 if (tag == -1) { 227 throw new EOFException(); 228 } 229 230 int length = readLength(); 231 byte[] bytes = new byte[length]; 232 233 readFully(bytes); 234 235 return buildObject(tag, bytes); 236 } 237 }