blob: 4416dd47d5649eda52021b0e9f8f65bcaa8374f5 [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001package aQute.libg.asn1;
2
3import java.io.*;
4import java.text.*;
5import java.util.*;
6
7public class BER implements Types {
8 DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss\\Z");
9
10 final DataInputStream xin;
11 long position;
12
13 public BER(InputStream in) {
14 this.xin = new DataInputStream(in);
15 }
16
17 public void dump(PrintStream out) throws Exception {
18 int type = readByte();
19 long length = readLength();
20 if (type == -1 || length == -1)
21 throw new EOFException("Empty file");
22 dump(out, type, length, "");
23 }
24
25 void dump(PrintStream out, int type, long length, String indent)
26 throws Exception {
27 int clss = type >> 6;
28 int nmbr = type & 0x1F;
29 boolean cnst = (type & 0x20) != 0;
30
31 String tag = "[" + nmbr + "]";
32 if (clss == 0)
33 tag = TAGS[nmbr];
34
35 if (cnst) {
36 System.err.printf("%5d %s %s %s%n", length, indent, CLASSES[clss],
37 tag);
38 while (length > 1) {
39 long atStart = getPosition();
40 int t2 = read();
41 long l2 = readLength();
42 dump(out, t2, l2, indent + " ");
43 length -= getPosition() - atStart;
44 }
45 } else {
46 assert length < Integer.MAX_VALUE;
47 assert length >= 0;
48 byte[] data = new byte[(int) length];
49 readFully(data);
50 String summary;
51
52 switch (nmbr) {
53 case BOOLEAN:
54 assert length == 1;
55 summary = data[0] != 0 ? "true" : "false";
56 break;
57
58 case INTEGER:
59 long n = toLong(data);
60 summary = n + "";
61 break;
62
63 case UTF8_STRING:
64 case IA5STRING:
65 case VISIBLE_STRING:
66 case UNIVERSAL_STRING:
67 case PRINTABLE_STRING:
68 case UTCTIME:
69 summary = new String(data, "UTF-8");
70 break;
71
72 case OBJECT_IDENTIFIER:
73 summary = readOID(data);
74 break;
75
76 case GENERALIZED_TIME:
77 case GRAPHIC_STRING:
78 case GENERAL_STRING:
79 case CHARACTER_STRING:
80
81 case REAL:
82 case EOC:
83 case BIT_STRING:
84 case OCTET_STRING:
85 case NULL:
86 case OBJECT_DESCRIPTOR:
87 case EXTERNAL:
88 case ENUMERATED:
89 case EMBEDDED_PDV:
90 case RELATIVE_OID:
91 case NUMERIC_STRING:
92 case T61_STRING:
93 case VIDEOTEX_STRING:
94 case BMP_STRING:
95 default:
96 StringBuilder sb = new StringBuilder();
97 for (int i = 0; i < 10 && i < data.length; i++) {
98 sb.append(Integer.toHexString(data[i]));
99 }
100 if (data.length > 10) {
101 sb.append("...");
102 }
103 summary = sb.toString();
104 break;
105 }
106 out.printf("%5d %s %s %s %s\n", length, indent, CLASSES[clss], tag,
107 summary);
108 }
109 }
110
111 long toLong(byte[] data) {
112 if (data[0] < 0) {
113 for (int i = 0; i < data.length; i++)
114 data[i] = (byte) (0xFF ^ data[i]);
115
116 return -(toLong(data) + 1);
117 }
118 long n = 0;
119 for (int i = 0; i < data.length; i++) {
120 n = n * 256 + data[i];
121 }
122 return n;
123 }
124
125 /**
126 * 8.1.3.3 For the definite form, the length octets shall consist of one or
127 * more octets, and shall represent the number of octets in the contents
128 * octets using either the short form (see 8.1.3.4) or the long form (see
129 * 8.1.3.5) as a sender's option. NOTE – The short form can only be used if
130 * the number of octets in the contents octets is less than or equal to 127.
131 * 8.1.3.4 In the short form, the length octets shall consist of a single
132 * octet in which bit 8 is zero and bits 7 to 1 encode the number of octets
133 * in the contents octets (which may be zero), as an unsigned binary integer
134 * with bit 7 as the most significant bit. EXAMPLE L = 38 can be encoded as
135 * 001001102 8.1.3.5 In the long form, the length octets shall consist of an
136 * initial octet and one or more subsequent octets. The initial octet shall
137 * be encoded as follows: a) bit 8 shall be one; b) bits 7 to 1 shall encode
138 * the number of subsequent octets in the length octets, as an unsigned
139 * binary integer with bit 7 as the most significant bit; c) the value
140 * 111111112 shall not be used. ISO/IEC 8825-1:2003 (E) NOTE 1 – This
141 * restriction is introduced for possible future extension. Bits 8 to 1 of
142 * the first subsequent octet, followed by bits 8 to 1 of the second
143 * subsequent octet, followed in turn by bits 8 to 1 of each further octet
144 * up to and including the last subsequent octet, shall be the encoding of
145 * an unsigned binary integer equal to the number of octets in the contents
146 * octets, with bit 8 of the first subsequent octet as the most significant
147 * bit. EXAMPLE L = 201 can be encoded as: 100000012 110010012 NOTE 2 – In
148 * the long form, it is a sender's option whether to use more length octets
149 * than the minimum necessary. 8.1.3.6 For the indefinite form, the length
150 * octets indicate that the contents octets are terminated by
151 * end-of-contents octets (see 8.1.5), and shall consist of a single octet.
152 * 8.1.3.6.1 The single octet shall have bit 8 set to one, and bits 7 to 1
153 * set to zero. 8.1.3.6.2 If this form of length is used, then
154 * end-of-contents octets (see 8.1.5) shall be present in the encoding
155 * following the contents octets. 8.1.4 Contents octets The contents octets
156 * shall consist of zero, one or more octets, and shall encode the data
157 * value as specified in subsequent clauses. NOTE – The contents octets
158 * depend on the type of the data value; subsequent clauses follow the same
159 * sequence as the definition of types in ASN.1. 8.1.5 End-of-contents
160 * octets The end-of-contents octets shall be present if the length is
161 * encoded as specified in 8.1.3.6, otherwise they shall not be present. The
162 * end-of-contents octets shall consist of two zero octets. NOTE – The
163 * end-of-contents octets can be considered as the encoding of a value whose
164 * tag is universal class, whose form is primitive, whose number of the tag
165 * is zero, and whose contents are absent, thus:
166 *
167 * End-of-contents Length Contents 0016 0016 Absent
168 *
169 * @return
170 */
171 private long readLength() throws IOException {
172 long n = readByte();
173 if (n > 0) {
174 // short form
175 return n;
176 }
177 // long form
178 int count = (int) (n & 0x7F);
179 if (count == 0) {
180 // indefinite form
181 return 0;
182 }
183 n = 0;
184 while (count-- > 0) {
185 n = n * 256 + read();
186 }
187 return n;
188 }
189
190 private int readByte() throws IOException {
191 position++;
192 return xin.readByte();
193 }
194
195 private void readFully(byte[] data) throws IOException {
196 position += data.length;
197 xin.readFully(data);
198 }
199
200 private long getPosition() {
201 return position;
202 }
203
204 private int read() throws IOException {
205 position++;
206 return xin.read();
207 }
208
209 String readOID(byte[] data) {
210 StringBuilder sb = new StringBuilder();
211 sb.append((0xFF & data[0]) / 40);
212 sb.append(".");
213 sb.append((0xFF & data[0]) % 40);
214
215 int i = 0;
216 while (++i < data.length) {
217 int n = 0;
218 while (data[i] < 0) {
219 n = n * 128 + (0x7F & data[i]);
220 i++;
221 }
222 n = n * 128 + data[i];
223 sb.append(".");
224 sb.append(n);
225 }
226
227 return sb.toString();
228 }
229
230 int getPayloadLength(PDU pdu) throws Exception {
231 switch (pdu.getTag() & 0x1F) {
232 case EOC:
233 return 1;
234
235 case BOOLEAN:
236 return 1;
237
238 case INTEGER:
239 return size(pdu.getInt());
240
241 case UTF8_STRING:
242 String s = pdu.getString();
243 byte[] encoded = s.getBytes("UTF-8");
244 return encoded.length;
245
246 case IA5STRING:
247 case VISIBLE_STRING:
248 case UNIVERSAL_STRING:
249 case PRINTABLE_STRING:
250 case GENERALIZED_TIME:
251 case GRAPHIC_STRING:
252 case GENERAL_STRING:
253 case CHARACTER_STRING:
254 case UTCTIME:
255 case NUMERIC_STRING: {
256 String str = pdu.getString();
257 encoded = str.getBytes("ASCII");
258 return encoded.length;
259 }
260
261 case OBJECT_IDENTIFIER:
262 case REAL:
263 case BIT_STRING:
264 return pdu.getBytes().length;
265
266 case OCTET_STRING:
267 case NULL:
268 case OBJECT_DESCRIPTOR:
269 case EXTERNAL:
270 case ENUMERATED:
271 case EMBEDDED_PDV:
272 case RELATIVE_OID:
273 case T61_STRING:
274 case VIDEOTEX_STRING:
275 case BMP_STRING:
276 return pdu.getBytes().length;
277
278 default:
279 throw new IllegalArgumentException("Invalid type: " + pdu);
280 }
281 }
282
283 int size(long value) {
284 if (value < 128)
285 return 1;
286
287 if (value <= 0xFF)
288 return 2;
289
290 if (value <= 0xFFFF)
291 return 3;
292
293 if (value <= 0xFFFFFF)
294 return 4;
295
296 if (value <= 0xFFFFFFFF)
297 return 5;
298
299 if (value <= 0xFFFFFFFFFFL)
300 return 6;
301
302 if (value <= 0xFFFFFFFFFFFFL)
303 return 7;
304
305 if (value <= 0xFFFFFFFFFFFFFFL)
306 return 8;
307
308 if (value <= 0xFFFFFFFFFFFFFFFFL)
309 return 9;
310
311 throw new IllegalArgumentException("length too long");
312 }
313
314 public void write(OutputStream out, PDU pdu) throws Exception {
315 byte id = 0;
316
317 switch (pdu.getClss()) {
318 case UNIVERSAL:
319 id |= 0;
320 break;
321 case APPLICATION:
322 id |= 0x40;
323 break;
324 case CONTEXT:
325 id |= 0x80;
326 break;
327 case PRIVATE:
328 id |= 0xC0;
329 break;
330 }
331
332 if (pdu.isConstructed())
333 id |= 0x20;
334
335 int tag = pdu.getTag();
336 if (tag >= 0 && tag < 31) {
337 id |= tag;
338 } else {
339 throw new UnsupportedOperationException("Cant do tags > 30");
340 }
341
342 out.write(id);
343
344 int length = getPayloadLength(pdu);
345 int size = size(length);
346 if (size == 1) {
347 out.write(length);
348 } else {
349 out.write(size);
350 while (--size >= 0) {
351 byte data = (byte) ((length >> (size * 8)) & 0xFF);
352 out.write(data);
353 }
354 }
355 writePayload(out, pdu);
356 }
357
358 void writePayload(OutputStream out, PDU pdu) throws Exception {
359 switch (pdu.getTag()) {
360 case EOC:
361 out.write(0);
362 break;
363
364 case BOOLEAN:
365 if (pdu.getBoolean())
366 out.write(-1);
367 else
368 out.write(0);
369 break;
370
371 case ENUMERATED:
372 case INTEGER: {
373 long value = pdu.getInt();
374 int size = size(value);
375 for (int i = size; i >= 0; i--) {
376 byte b = (byte) ((value >> (i * 8)) & 0xFF);
377 out.write(b);
378 }
379 }
380
381 case BIT_STRING: {
382 byte bytes[] = pdu.getBytes();
383 int unused = bytes[0];
384 assert unused <= 7;
385 int[] mask = { 0xFF, 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1 };
386 bytes[bytes.length - 1] &= (byte) mask[unused];
387 out.write(bytes);
388 break;
389 }
390
391 case RELATIVE_OID:
392 case OBJECT_IDENTIFIER: {
393 int[] oid = pdu.getOID();
394 assert oid.length > 2;
395 assert oid[0] < 4;
396 assert oid[1] < 40;
397 byte top = (byte) (oid[0] * 40 + oid[1]);
398 out.write(top);
399 for (int i = 2; i < oid.length; i++) {
400 putOid(out,oid[i]);
401 }
402 break;
403 }
404
405 case OCTET_STRING: {
406 byte bytes[] = pdu.getBytes();
407 out.write(bytes);
408 break;
409 }
410
411 case NULL:
412 break;
413
414 case BMP_STRING:
415 case GRAPHIC_STRING:
416 case VISIBLE_STRING:
417 case GENERAL_STRING:
418 case UNIVERSAL_STRING:
419 case CHARACTER_STRING:
420 case NUMERIC_STRING:
421 case PRINTABLE_STRING:
422 case VIDEOTEX_STRING:
423 case T61_STRING:
424 case REAL:
425 case EMBEDDED_PDV:
426 case EXTERNAL:
427 throw new UnsupportedEncodingException("dont know real, embedded PDV or external");
428
429 case UTF8_STRING: {
430 String s = pdu.getString();
431 byte [] data = s.getBytes("UTF-8");
432 out.write(data);
433 break;
434 }
435
436 case OBJECT_DESCRIPTOR:
437 case IA5STRING:
438 String s = pdu.getString();
439 byte [] data = s.getBytes("ASCII");
440 out.write(data);
441 break;
442
443
444 case SEQUENCE:
445 case SET: {
446 PDU pdus[] = pdu.getChildren();
447 for ( PDU p : pdus ) {
448 write(out, p);
449 }
450 }
451
452
453 case UTCTIME:
454 case GENERALIZED_TIME:
455 Date date = pdu.getDate();
456 String ss= df.format(date);
457 byte d[] = ss.getBytes("ASCII");
458 out.write(d);
459 break;
460
461 }
462 }
463
464
465 private void putOid(OutputStream out, int i) throws IOException {
466 if (i > 127) {
467 putOid(out, i >> 7);
468 out.write(0x80 + (i & 0x7F));
469 } else
470 out.write(i & 0x7F);
471 }
472}