001 package org.apache.commons.ssl.asn1; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.EOFException; 005 import java.io.IOException; 006 import java.io.InputStream; 007 008 public class ASN1StreamParser { 009 InputStream _in; 010 011 private int _limit; 012 private boolean _eofFound; 013 014 public ASN1StreamParser( 015 InputStream in) { 016 this(in, Integer.MAX_VALUE); 017 } 018 019 public ASN1StreamParser( 020 InputStream in, 021 int limit) { 022 this._in = in; 023 this._limit = limit; 024 } 025 026 public ASN1StreamParser( 027 byte[] encoding) { 028 this(new ByteArrayInputStream(encoding), encoding.length); 029 } 030 031 InputStream getParentStream() { 032 return _in; 033 } 034 035 private int readLength() 036 throws IOException { 037 int length = _in.read(); 038 if (length < 0) { 039 throw new EOFException("EOF found when length expected"); 040 } 041 042 if (length == 0x80) { 043 return -1; // indefinite-length encoding 044 } 045 046 if (length > 127) { 047 int size = length & 0x7f; 048 049 if (size > 4) { 050 throw new IOException("DER length more than 4 bytes"); 051 } 052 053 length = 0; 054 for (int i = 0; i < size; i++) { 055 int next = _in.read(); 056 057 if (next < 0) { 058 throw new EOFException("EOF found reading length"); 059 } 060 061 length = (length << 8) + next; 062 } 063 064 if (length < 0) { 065 throw new IOException("corrupted stream - negative length found"); 066 } 067 068 if (length >= _limit) // after all we must have read at least 1 byte 069 { 070 throw new IOException("corrupted stream - out of bounds length found"); 071 } 072 } 073 074 return length; 075 } 076 077 public DEREncodable readObject() 078 throws IOException { 079 int tag = _in.read(); 080 if (tag == -1) { 081 if (_eofFound) { 082 throw new EOFException("attempt to read past end of file."); 083 } 084 085 _eofFound = true; 086 087 return null; 088 } 089 090 // 091 // turn of looking for "00" while we resolve the tag 092 // 093 set00Check(false); 094 095 // 096 // calculate tag number 097 // 098 int baseTagNo = tag & ~DERTags.CONSTRUCTED; 099 int tagNo = baseTagNo; 100 101 if ((tag & DERTags.TAGGED) != 0) { 102 tagNo = tag & 0x1f; 103 104 // 105 // with tagged object tag number is bottom 5 bits, or stored at the start of the content 106 // 107 if (tagNo == 0x1f) { 108 tagNo = 0; 109 110 int b = _in.read(); 111 112 while ((b >= 0) && ((b & 0x80) != 0)) { 113 tagNo |= (b & 0x7f); 114 tagNo <<= 7; 115 b = _in.read(); 116 } 117 118 if (b < 0) { 119 _eofFound = true; 120 121 throw new EOFException("EOF encountered inside tag value."); 122 } 123 124 tagNo |= (b & 0x7f); 125 } 126 } 127 128 // 129 // calculate length 130 // 131 int length = readLength(); 132 133 if (length < 0) // indefinite length 134 { 135 IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in); 136 137 switch (baseTagNo) { 138 case DERTags.NULL: 139 while (indIn.read() >= 0) { 140 // make sure we skip to end of object 141 } 142 return BERNull.INSTANCE; 143 case DERTags.OCTET_STRING: 144 return new BEROctetStringParser(new ASN1ObjectParser(tag, tagNo, indIn)); 145 case DERTags.SEQUENCE: 146 return new BERSequenceParser(new ASN1ObjectParser(tag, tagNo, indIn)); 147 case DERTags.SET: 148 return new BERSetParser(new ASN1ObjectParser(tag, tagNo, indIn)); 149 default: 150 return new BERTaggedObjectParser(tag, tagNo, indIn); 151 } 152 } else { 153 DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); 154 155 switch (baseTagNo) { 156 case DERTags.INTEGER: 157 return new DERInteger(defIn.toByteArray()); 158 case DERTags.NULL: 159 defIn.toByteArray(); // make sure we read to end of object bytes. 160 return DERNull.INSTANCE; 161 case DERTags.OBJECT_IDENTIFIER: 162 return new DERObjectIdentifier(defIn.toByteArray()); 163 case DERTags.OCTET_STRING: 164 return new DEROctetString(defIn.toByteArray()); 165 case DERTags.SEQUENCE: 166 return new DERSequence(loadVector(defIn, length)).parser(); 167 case DERTags.SET: 168 return new DERSet(loadVector(defIn, length)).parser(); 169 default: 170 return new BERTaggedObjectParser(tag, tagNo, defIn); 171 } 172 } 173 } 174 175 private void set00Check(boolean enabled) { 176 if (_in instanceof IndefiniteLengthInputStream) { 177 ((IndefiniteLengthInputStream) _in).setEofOn00(enabled); 178 } 179 } 180 181 private ASN1EncodableVector loadVector(InputStream in, int length) 182 throws IOException { 183 ASN1InputStream aIn = new ASN1InputStream(in, length); 184 ASN1EncodableVector v = new ASN1EncodableVector(); 185 186 DERObject obj; 187 while ((obj = aIn.readObject()) != null) { 188 v.add(obj); 189 } 190 191 return v; 192 } 193 }