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
38 public final class BerEncoder extends Ber {
39
40 private int curSeqIndex;
41 private int[] seqOffset;
42 private static final int INITIAL_SEQUENCES = 16;
43 private static final int DEFAULT_BUFSIZE = 1024;
44
45
46 private static final int BUF_GROWTH_FACTOR = 8;
47
48
49
50
51 public BerEncoder() {
52 this(DEFAULT_BUFSIZE);
53 }
54
55
56
57
58
59
60 public BerEncoder(int bufsize) {
61 buf = new byte[bufsize];
62 this.bufsize = bufsize;
63 offset = 0;
64
65 seqOffset = new int[INITIAL_SEQUENCES];
66 curSeqIndex = 0;
67 }
68
69
70
71
72
73 public void reset() {
74 while (offset > 0) {
75 buf[--offset] = 0;
76 }
77 while (curSeqIndex > 0) {
78 seqOffset[--curSeqIndex] = 0;
79 }
80 }
81
82
83
84
85
86
87 public int getDataLen() {
88 return offset;
89 }
90
91
92
93
94
95
96
97
98
99 public byte[] getBuf() {
100 if (curSeqIndex != 0) {
101 throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");
102 }
103 return buf;
104 }
105
106
107
108
109
110
111 @SuppressWarnings("unused")
112 public byte[] getTrimmedBuf() {
113 int len = getDataLen();
114 byte[] trimBuf = new byte[len];
115
116 System.arraycopy(getBuf(), 0, trimBuf, 0, len);
117 return trimBuf;
118 }
119
120
121
122
123
124
125 public void beginSeq(int tag) {
126
127
128 if (curSeqIndex >= seqOffset.length) {
129 int[] seqOffsetTmp = new int[seqOffset.length * 2];
130
131 System.arraycopy(seqOffset, 0, seqOffsetTmp, 0, seqOffset.length);
132 seqOffset = seqOffsetTmp;
133 }
134
135 encodeByte(tag);
136 seqOffset[curSeqIndex] = offset;
137
138
139
140
141
142
143 ensureFreeBytes(3);
144 offset += 3;
145
146 curSeqIndex++;
147 }
148
149
150
151
152 public void endSeq() throws EncodeException {
153 curSeqIndex--;
154 if (curSeqIndex < 0) {
155 throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");
156 }
157
158 int start = seqOffset[curSeqIndex] + 3;
159 int len = offset - start;
160
161 if (len <= 0x7f) {
162 shiftSeqData(start, len, -2);
163 buf[seqOffset[curSeqIndex]] = (byte) len;
164 } else if (len <= 0xff) {
165 shiftSeqData(start, len, -1);
166 buf[seqOffset[curSeqIndex]] = (byte) 0x81;
167 buf[seqOffset[curSeqIndex] + 1] = (byte) len;
168 } else if (len <= 0xffff) {
169 buf[seqOffset[curSeqIndex]] = (byte) 0x82;
170 buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 8);
171 buf[seqOffset[curSeqIndex] + 2] = (byte) len;
172 } else if (len <= 0xffffff) {
173 shiftSeqData(start, len, 1);
174 buf[seqOffset[curSeqIndex]] = (byte) 0x83;
175 buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 16);
176 buf[seqOffset[curSeqIndex] + 2] = (byte) (len >> 8);
177 buf[seqOffset[curSeqIndex] + 3] = (byte) len;
178 } else {
179 throw new EncodeException("SEQUENCE too long");
180 }
181 }
182
183
184
185
186
187 private void shiftSeqData(int start, int len, int shift) {
188 if (shift > 0) {
189 ensureFreeBytes(shift);
190 }
191 System.arraycopy(buf, start, buf, start + shift, len);
192 offset += shift;
193 }
194
195
196
197
198 public void encodeByte(int b) {
199 ensureFreeBytes(1);
200 buf[offset++] = (byte) b;
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 public void encodeInt(int i) {
217 encodeInt(i, 0x02);
218 }
219
220
221
222
223
224
225
226 public void encodeInt(int i, int tag) {
227 int mask = 0xff800000;
228 int intsize = 4;
229
230 while( (((i & mask) == 0) || ((i & mask) == mask)) && (intsize > 1) ) {
231 intsize--;
232 i <<= 8;
233 }
234
235 encodeInt(i, tag, intsize);
236 }
237
238
239
240
241 private void encodeInt(int i, int tag, int intsize) {
242
243
244
245
246
247 if (intsize > 4) {
248 throw new IllegalArgumentException("BER encode error: INTEGER too long.");
249 }
250
251 ensureFreeBytes(2 + intsize);
252
253 buf[offset++] = (byte) tag;
254 buf[offset++] = (byte) intsize;
255
256 int mask = 0xff000000;
257
258 while (intsize-- > 0) {
259 buf[offset++] = (byte) ((i & mask) >> 24);
260 i <<= 8;
261 }
262 }
263
264
265
266
267
268
269
270 @SuppressWarnings("unused")
271 public void encodeBoolean(boolean b) {
272 encodeBoolean(b, ASN_BOOLEAN);
273 }
274
275
276
277
278
279
280
281
282 public void encodeBoolean(boolean b, int tag) {
283 ensureFreeBytes(3);
284
285 buf[offset++] = (byte) tag;
286 buf[offset++] = 0x01;
287 buf[offset++] = b ? (byte) 0xff : (byte) 0x00;
288 }
289
290
291
292
293
294
295
296
297 public void encodeString(String str, boolean encodeUTF8)
298 throws EncodeException {
299 encodeString(str, ASN_OCTET_STR, encodeUTF8);
300 }
301
302
303
304
305
306
307
308 public void encodeString(String str, int tag, boolean encodeUTF8)
309 throws EncodeException {
310
311 encodeByte(tag);
312
313 int i = 0;
314 int count;
315 byte[] bytes = null;
316
317 if (str == null) {
318 count = 0;
319 } else if (encodeUTF8) {
320 bytes = str.getBytes(StandardCharsets.UTF_8);
321 count = bytes.length;
322 } else {
323 try {
324 bytes = str.getBytes("8859_1");
325 count = bytes.length;
326 } catch (UnsupportedEncodingException e) {
327 throw new EncodeException("8859_1 not available on platform");
328 }
329 }
330
331 encodeLength(count);
332
333 ensureFreeBytes(count);
334 while (i < count) {
335 buf[offset++] = bytes[i++];
336 }
337 }
338
339
340
341
342 public void encodeOctetString(byte[] tb, int tag, int tboffset, int length)
343 throws EncodeException {
344
345 encodeByte(tag);
346 encodeLength(length);
347
348 if (length > 0) {
349 ensureFreeBytes(length);
350 System.arraycopy(tb, tboffset, buf, offset, length);
351 offset += length;
352 }
353 }
354
355
356
357
358 public void encodeOctetString(byte[] tb, int tag) throws EncodeException {
359 encodeOctetString(tb, tag, 0, tb.length);
360 }
361
362 private void encodeLength(int len) throws EncodeException {
363 ensureFreeBytes(4);
364
365 if (len < 128) {
366 buf[offset++] = (byte) len;
367 } else if (len <= 0xff) {
368 buf[offset++] = (byte) 0x81;
369 buf[offset++] = (byte) len;
370 } else if (len <= 0xffff) {
371 buf[offset++] = (byte) 0x82;
372 buf[offset++] = (byte) (len >> 8);
373 buf[offset++] = (byte) (len & 0xff);
374 } else if (len <= 0xffffff) {
375 buf[offset++] = (byte) 0x83;
376 buf[offset++] = (byte) (len >> 16);
377 buf[offset++] = (byte) (len >> 8);
378 buf[offset++] = (byte) (len & 0xff);
379 } else {
380 throw new EncodeException("string too long");
381 }
382 }
383
384
385
386
387 @SuppressWarnings("unused")
388 public void encodeStringArray(String[] strs, boolean encodeUTF8)
389 throws EncodeException {
390 if (strs == null)
391 return;
392 for (String str : strs) {
393 encodeString(str, encodeUTF8);
394 }
395 }
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413 private void ensureFreeBytes(int len) {
414 if (bufsize - offset < len) {
415 int newsize = bufsize * BUF_GROWTH_FACTOR;
416 if (newsize - offset < len) {
417 newsize += len;
418 }
419 byte[] newbuf = new byte[newsize];
420
421 System.arraycopy(buf, 0, newbuf, 0, offset);
422
423 buf = newbuf;
424 bufsize = newsize;
425 }
426 }
427 }