1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package davmail.ldap;
27
28 import java.io.UnsupportedEncodingException;
29 import java.nio.charset.StandardCharsets;
30
31
32
33
34
35
36
37 public final class BerDecoder extends Ber {
38
39 private int origOffset;
40
41
42
43
44 public BerDecoder(byte[] buf, int offset, int bufsize) {
45
46 this.buf = buf;
47 this.bufsize = bufsize;
48 this.origOffset = offset;
49
50 reset();
51 }
52
53
54
55
56
57 public void reset() {
58 offset = origOffset;
59 }
60
61
62
63
64
65
66 public int getParsePosition() {
67 return offset;
68 }
69
70
71
72
73 public int parseLength() throws DecodeException {
74
75 int lengthbyte = parseByte();
76
77 if ((lengthbyte & 0x80) == 0x80) {
78
79 lengthbyte &= 0x7f;
80
81 if (lengthbyte == 0) {
82 throw new DecodeException(
83 "Indefinite length not supported");
84 }
85
86 if (lengthbyte > 4) {
87 throw new DecodeException("encoding too long");
88 }
89
90 if (bufsize - offset < lengthbyte) {
91 throw new DecodeException("Insufficient data");
92 }
93
94 int retval = 0;
95
96 for( int i = 0; i < lengthbyte; i++) {
97 retval = (retval << 8) + (buf[offset++] & 0xff);
98 }
99 if (retval < 0) {
100 throw new DecodeException("Invalid length bytes");
101 }
102 return retval;
103 } else {
104 return lengthbyte;
105 }
106 }
107
108
109
110
111
112
113
114 public int parseSeq(int[] rlen) throws DecodeException {
115
116 int seq = parseByte();
117 int len = parseLength();
118 if (rlen != null) {
119 rlen[0] = len;
120 }
121 return seq;
122 }
123
124
125
126
127
128
129 @SuppressWarnings("unused")
130 void seek(int i) throws DecodeException {
131 if (offset + i > bufsize || offset + i < 0) {
132 throw new DecodeException("array index out of bounds");
133 }
134 offset += i;
135 }
136
137
138
139
140
141 public int parseByte() throws DecodeException {
142 if (bufsize - offset < 1) {
143 throw new DecodeException("Insufficient data");
144 }
145 return buf[offset++] & 0xff;
146 }
147
148
149
150
151
152
153 public int peekByte() throws DecodeException {
154 if (bufsize - offset < 1) {
155 throw new DecodeException("Insufficient data");
156 }
157 return buf[offset] & 0xff;
158 }
159
160
161
162
163
164 @SuppressWarnings("UnusedReturnValue")
165 public boolean parseBoolean() throws DecodeException {
166 return (parseIntWithTag(ASN_BOOLEAN) != 0x00);
167 }
168
169
170
171
172
173 public int parseEnumeration() throws DecodeException {
174 return parseIntWithTag(ASN_ENUMERATED);
175 }
176
177
178
179
180
181 public int parseInt() throws DecodeException {
182 return parseIntWithTag(ASN_INTEGER);
183 }
184
185
186
187
188
189
190
191 protected int parseIntWithTag(int tag) throws DecodeException {
192
193
194 if (parseByte() != tag) {
195 throw new DecodeException("Encountered ASN.1 tag " +
196 (buf[offset - 1] & 0xff) +
197 " (expected tag " + tag + ")");
198 }
199
200 int len = parseLength();
201
202 if (len > 4) {
203 throw new DecodeException("INTEGER too long");
204 } else if (len > bufsize - offset) {
205 throw new DecodeException("Insufficient data");
206 }
207
208 byte fb = buf[offset++];
209 int value;
210
211 value = fb & 0x7F;
212 for( int i = 1 ; i < len; i++) {
213 value <<= 8;
214 value |= (buf[offset++] & 0xff);
215 }
216
217 if ((fb & 0x80) == 0x80) {
218 value = -value;
219 }
220
221 return value;
222 }
223
224
225
226
227 public String parseString(boolean decodeUTF8) throws DecodeException {
228 return parseStringWithTag(ASN_SIMPLE_STRING, decodeUTF8, null);
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243 public String parseStringWithTag(int tag, boolean decodeUTF8, int[] rlen)
244 throws DecodeException {
245
246 int st;
247 int origOffset = offset;
248
249 if ((st = parseByte()) != tag) {
250 throw new DecodeException("Encountered ASN.1 tag " +
251 Integer.toString((byte)st) + " (expected tag " + tag + ")");
252 }
253
254 int len = parseLength();
255
256 if (len > bufsize - offset) {
257 throw new DecodeException("Insufficient data");
258 }
259
260 String retstr;
261 if (len == 0) {
262 retstr = "";
263 } else {
264 byte[] buf2 = new byte[len];
265
266 System.arraycopy(buf, offset, buf2, 0, len);
267 if (decodeUTF8) {
268 retstr = new String(buf2, StandardCharsets.UTF_8);
269 } else {
270 try {
271 retstr = new String(buf2, "8859_1");
272 } catch (UnsupportedEncodingException e) {
273 throw new DecodeException("8859_1 not available on platform");
274 }
275 }
276 offset += len;
277 }
278
279 if (rlen != null) {
280 rlen[0] = offset - origOffset;
281 }
282
283 return retstr;
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 public byte[] parseOctetString(int tag, int[] rlen) throws DecodeException {
301
302 int origOffset = offset;
303 int st;
304 if ((st = parseByte()) != tag) {
305
306 throw new DecodeException("Encountered ASN.1 tag " +
307 st +
308 " (expected tag " + tag + ")");
309 }
310
311 int len = parseLength();
312
313 if (len > bufsize - offset) {
314 throw new DecodeException("Insufficient data");
315 }
316
317 byte[] retarr = new byte[len];
318 if (len > 0) {
319 System.arraycopy(buf, offset, retarr, 0, len);
320 offset += len;
321 }
322
323 if (rlen != null) {
324 rlen[0] = offset - origOffset;
325 }
326
327 return retarr;
328 }
329
330
331
332
333 public int bytesLeft() {
334 return bufsize - offset;
335 }
336 }