001: /*_############################################################################
002: _##
003: _## SNMP4J - BER.java
004: _##
005: _## Copyright (C) 2003-2008 Frank Fock and Jochen Katz (SNMP4J.org)
006: _##
007: _## Licensed under the Apache License, Version 2.0 (the "License");
008: _## you may not use this file except in compliance with the License.
009: _## You may obtain a copy of the License at
010: _##
011: _## http://www.apache.org/licenses/LICENSE-2.0
012: _##
013: _## Unless required by applicable law or agreed to in writing, software
014: _## distributed under the License is distributed on an "AS IS" BASIS,
015: _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: _## See the License for the specific language governing permissions and
017: _## limitations under the License.
018: _##
019: _##########################################################################*/
020:
021: package org.snmp4j.asn1;
022:
023: import java.io.OutputStream;
024: import java.io.IOException;
025:
026: /**
027: * The BER class provides utility methods for the BER encoding and decoding.
028: *
029: * @author Jochen Katz & Frank Fock
030: * @version 1.7.4
031: */
032: public class BER {
033:
034: public static final byte ASN_BOOLEAN = 0x01;
035: public static final byte ASN_INTEGER = 0x02;
036: public static final byte ASN_BIT_STR = 0x03;
037: public static final byte ASN_OCTET_STR = 0x04;
038: public static final byte ASN_NULL = 0x05;
039: public static final byte ASN_OBJECT_ID = 0x06;
040: public static final byte ASN_SEQUENCE = 0x10;
041: public static final byte ASN_SET = 0x11;
042: public static final byte ASN_UNIVERSAL = 0x00;
043: public static final byte ASN_APPLICATION = 0x40;
044: public static final byte ASN_CONTEXT = (byte) 0x80;
045: public static final byte ASN_PRIVATE = (byte) 0xC0;
046: public static final byte ASN_PRIMITIVE = (byte) 0x00;
047: public static final byte ASN_CONSTRUCTOR = (byte) 0x20;
048:
049: public static final byte ASN_LONG_LEN = (byte) 0x80;
050: public static final byte ASN_EXTENSION_ID = (byte) 0x1F;
051: public static final byte ASN_BIT8 = (byte) 0x80;
052:
053: public static final byte INTEGER = ASN_UNIVERSAL | 0x02;
054: public static final byte INTEGER32 = ASN_UNIVERSAL | 0x02;
055: public static final byte BITSTRING = ASN_UNIVERSAL | 0x03;
056: public static final byte OCTETSTRING = ASN_UNIVERSAL | 0x04;
057: public static final byte NULL = ASN_UNIVERSAL | 0x05;
058: public static final byte OID = ASN_UNIVERSAL | 0x06;
059: public static final byte SEQUENCE = ASN_CONSTRUCTOR | 0x10;
060:
061: public static final byte IPADDRESS = ASN_APPLICATION | 0x00;
062: public static final byte COUNTER = ASN_APPLICATION | 0x01;
063: public static final byte COUNTER32 = ASN_APPLICATION | 0x01;
064: public static final byte GAUGE = ASN_APPLICATION | 0x02;
065: public static final byte GAUGE32 = ASN_APPLICATION | 0x02;
066: public static final byte TIMETICKS = ASN_APPLICATION | 0x03;
067: public static final byte OPAQUE = ASN_APPLICATION | 0x04;
068: public static final byte COUNTER64 = ASN_APPLICATION | 0x06;
069:
070: public static final int NOSUCHOBJECT = 0x80;
071: public static final int NOSUCHINSTANCE = 0x81;
072: public static final int ENDOFMIBVIEW = 0x82;
073:
074: private static final int LENMASK = 0x0ff;
075: public static final int MAX_OID_LENGTH = 127;
076:
077: private static boolean checkSequenceLength = true;
078: private static boolean checkValueLength = true;
079:
080: /**
081: * The <code>MutableByte</code> class serves for exchanging type information
082: * from the various decode* methods.
083: *
084: * @author Frank Fock
085: * @version 1.0
086: */
087: public static class MutableByte {
088: byte value = 0;
089:
090: public MutableByte() {
091: }
092:
093: public MutableByte(byte value) {
094: setValue(value);
095: }
096:
097: public void setValue(byte value) {
098: this .value = value;
099: }
100:
101: public byte getValue() {
102: return value;
103: }
104: }
105:
106: /**
107: * Encodes an ASN.1 header for an object with the ID and
108: * length specified.
109: * @param os
110: * an <code>OutputStream</code> to which the header is encoded.
111: * @param type
112: * the type of the ASN.1 object. Must be < 30, i.e. no extension octets.
113: * @param length
114: * the length of the object. The maximum length is 0xFFFFFFFF;
115: * @throws IOException
116: */
117: public static final void encodeHeader(OutputStream os, int type,
118: int length) throws IOException {
119: os.write(type);
120: encodeLength(os, length);
121: }
122:
123: /**
124: * Encodes an ASN.1 header for an object with the ID and
125: * length specified with a fixed length of the encoded length as supplied.
126: * @param os
127: * an <code>OutputStream</code> to which the header is encoded.
128: * @param type
129: * the type of the ASN.1 object. Must be < 30, i.e. no extension octets.
130: * @param length
131: * the length of the object. The maximum length is 0xFFFFFFFF;
132: * @param numBytesLength
133: * the number of bytes used to encode the length of the length.
134: * @throws IOException
135: */
136: public static final void encodeHeader(OutputStream os, int type,
137: int length, int numBytesLength) throws IOException {
138: os.write(type);
139: encodeLength(os, length, numBytesLength);
140: }
141:
142: /**
143: * Compute the space needed to encode the length.
144: *
145: * @param length
146: * Length to encode
147: * @return
148: * the count of bytes needed to encode the value <code>length</code>
149: */
150: public static final int getBERLengthOfLength(int length) {
151: if (length < 0) {
152: return 5;
153: } else if (length < 0x80) {
154: return 1;
155: } else if (length <= 0xFF) {
156: return 2;
157: } else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
158: return 3;
159: } else if (length <= 0xFFFFFF) { /* 0xFFFF < length <= 0xFFFFFF */
160: return 4;
161: }
162: return 5;
163: }
164:
165: /**
166: * Encodes the length of an ASN.1 object.
167: * @param os
168: * an <code>OutputStream</code> to which the length is encoded.
169: * @param length
170: * the length of the object. The maximum length is 0xFFFFFFFF;
171: * @throws IOException
172: */
173: public static final void encodeLength(OutputStream os, int length)
174: throws IOException {
175: if (length < 0) {
176: os.write(0x04 | ASN_LONG_LEN);
177: os.write((length >> 24) & 0xFF);
178: os.write((length >> 16) & 0xFF);
179: os.write((length >> 8) & 0xFF);
180: os.write(length & 0xFF);
181: } else if (length < 0x80) {
182: os.write(length);
183: } else if (length <= 0xFF) {
184: os.write((0x01 | ASN_LONG_LEN));
185: os.write(length);
186: } else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
187: os.write(0x02 | ASN_LONG_LEN);
188: os.write((length >> 8) & 0xFF);
189: os.write(length & 0xFF);
190: } else if (length <= 0xFFFFFF) { /* 0xFFFF < length <= 0xFFFFFF */
191: os.write(0x03 | ASN_LONG_LEN);
192: os.write((length >> 16) & 0xFF);
193: os.write((length >> 8) & 0xFF);
194: os.write(length & 0xFF);
195: } else {
196: os.write(0x04 | ASN_LONG_LEN);
197: os.write((length >> 24) & 0xFF);
198: os.write((length >> 16) & 0xFF);
199: os.write((length >> 8) & 0xFF);
200: os.write(length & 0xFF);
201: }
202: }
203:
204: /**
205: * Encodes the length of an ASN.1 object.
206: * @param os
207: * an <code>OutputStream</code> to which the length is encoded.
208: * @param length
209: * the length of the object. The maximum length is 0xFFFFFFFF;
210: * @param numLengthBytes
211: * the number of bytes to be used to encode the length using the long
212: * form.
213: * @throws IOException
214: */
215: public static final void encodeLength(OutputStream os, int length,
216: int numLengthBytes) throws IOException {
217: os.write((numLengthBytes | ASN_LONG_LEN));
218: for (int i = (numLengthBytes - 1) * 8; i >= 0; i -= 8) {
219: os.write(((length >> i) & 0xFF));
220: }
221: }
222:
223: /**
224: * Encode a signed integer.
225: * @param os
226: * an <code>OutputStream</code> to which the length is encoded.
227: * @param type
228: * the tag type for the integer (typically 0x02)
229: * @param value
230: * the integer value to encode.
231: * @throws IOException
232: */
233: public static final void encodeInteger(OutputStream os, byte type,
234: int value) throws IOException {
235: int integer = value;
236: int mask;
237: int intsize = 4;
238:
239: /*
240: * Truncate "unnecessary" bytes off of the most significant end of this
241: * 2's complement integer. There should be no sequence of 9
242: * consecutive 1's or 0's at the most significant end of the
243: * integer.
244: */
245: mask = 0x1FF << ((8 * 3) - 1);
246: /* mask is 0xFF800000 on a big-endian machine */
247: while ((((integer & mask) == 0) || ((integer & mask) == mask))
248: && intsize > 1) {
249: intsize--;
250: integer <<= 8;
251: }
252: encodeHeader(os, type, intsize);
253: mask = 0xFF << (8 * 3);
254: /* mask is 0xFF000000 on a big-endian machine */
255: while ((intsize--) > 0) {
256: os.write(((integer & mask) >> (8 * 3)));
257: integer <<= 8;
258: }
259: }
260:
261: /**
262: * Encode an unsigned integer.
263: * ASN.1 integer ::= 0x02 asnlength byte {byte}*
264: * @param os
265: * an <code>OutputStream</code> to which the length is encoded.
266: * @param type
267: * the tag type for the integer (typically 0x02)
268: * @param value
269: * the integer value to encode.
270: * @throws IOException
271: */
272: public static final void encodeUnsignedInteger(OutputStream os,
273: byte type, long value) throws IOException {
274: // figure out the len
275: int len = 1;
276: if (((value >> 24) & LENMASK) != 0) {
277: len = 4;
278: } else if (((value >> 16) & LENMASK) != 0) {
279: len = 3;
280: } else if (((value >> 8) & LENMASK) != 0) {
281: len = 2;
282: }
283: // check for 5 byte len where first byte will be
284: // a null
285: if (((value >> (8 * (len - 1))) & 0x080) != 0) {
286: len++;
287: }
288:
289: // build up the header
290: encodeHeader(os, type, len); // length of BER encoded item
291:
292: // special case, add a null byte for len of 5
293: if (len == 5) {
294: os.write(0);
295: for (int x = 1; x < len; x++) {
296: os.write((int) (value >> (8 * (4 - x) & LENMASK)));
297: }
298: } else {
299: for (int x = 0; x < len; x++) {
300: os
301: .write((int) (value >> (8 * ((len - 1) - x) & LENMASK)));
302: }
303: }
304: }
305:
306: /**
307: * Encode an ASN.1 octet string filled with the supplied input string.
308: * @param os
309: * an <code>OutputStream</code> to which the length is encoded.
310: * @param type
311: * the tag type for the integer (typically 0x02)
312: * @param string
313: * the <code>byte</code> array containing the octet string value.
314: * @throws IOException
315: */
316: public static final void encodeString(OutputStream os, byte type,
317: byte[] string) throws IOException {
318: /*
319: * ASN.1 octet string ::= primstring | cmpdstring
320: * primstring ::= 0x04 asnlength byte {byte}*
321: * cmpdstring ::= 0x24 asnlength string {string}*
322: * This code will never send a compound string.
323: */
324: encodeHeader(os, type, string.length);
325: // fixed
326: os.write(string);
327: }
328:
329: /**
330: * Encode an ASN.1 header for a sequence with the ID and length specified.
331: * This only works on data types < 30, i.e. no extension octets.
332: * The maximum length is 0xFFFF;
333: *
334: * @param os
335: * an <code>OutputStream</code> to which the length is encoded.
336: * @param type
337: * the tag type for the integer (typically 0x02)
338: * @param length
339: * the length of the sequence to encode.
340: * @throws IOException
341: */
342: public static final void encodeSequence(OutputStream os, byte type,
343: int length) throws IOException {
344: os.write(type);
345: encodeLength(os, length);
346: }
347:
348: /**
349: * Gets the payload length in bytes of the BER encoded OID value.
350: * @param value
351: * an array of unsigned integer values representing an object identifier.
352: * @return
353: * the BER encoded length of the OID without header and length.
354: */
355: public static final int getOIDLength(int[] value) {
356: int length = 1; // for first 2 subids
357: for (int i = 2; i < value.length; i++) {
358: long v = value[i] & 0xFFFFFFFFL;
359: if (v < 0x80) { // 7 bits long subid
360: length += 1;
361: } else if (v < 0x4000) { // 14 bits long subid
362: length += 2;
363: } else if (v < 0x200000) { // 21 bits long subid
364: length += 3;
365: } else if (v < 0x10000000) { // 28 bits long subid
366: length += 4;
367: } else { // 32 bits long subid
368: length += 5;
369: }
370: }
371: return length;
372: }
373:
374: /**
375: * Encode an ASN.1 oid filled with the supplied oid value.
376: *
377: * @param os
378: * an <code>OutputStream</code> to which the length is encoded.
379: * @param type
380: * the tag type for the integer (typically 0x06)
381: * @param oid
382: * the <code>int</code> array containing the OID value.
383: * @throws IOException
384: */
385: public static final void encodeOID(OutputStream os, byte type,
386: int[] oid) throws IOException {
387: /*
388: * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
389: * subidentifier ::= {leadingbyte}* lastbyte
390: * leadingbyte ::= 1 7bitvalue
391: * lastbyte ::= 0 7bitvalue
392: */
393: encodeHeader(os, type, getOIDLength(oid));
394:
395: int encodedLength = oid.length;
396: int rpos = 0;
397:
398: if (oid.length < 2) {
399: os.write(0);
400: encodedLength = 0;
401: } else {
402: os.write(((oid[1] + (oid[0] * 40)) & 0xFF));
403: encodedLength -= 2;
404: rpos = 2;
405: }
406:
407: while (encodedLength-- > 0) {
408: long subid = (oid[rpos++] & 0xFFFFFFFFL);
409: if (subid < 127) {
410: os.write((int) subid & 0xFF);
411: } else {
412: long mask = 0x7F; /* handle subid == 0 case */
413: long bits = 0;
414:
415: /* testmask *MUST* !!!! be of an unsigned type */
416: for (long testmask = 0x7F, testbits = 0; testmask != 0; testmask <<= 7, testbits += 7) {
417: if ((subid & testmask) > 0) { /* if any bits set */
418: mask = testmask;
419: bits = testbits;
420: }
421: }
422: /* mask can't be zero here */
423: for (; mask != 0x7F; mask >>= 7, bits -= 7) {
424: /* fix a mask that got truncated above */
425: if (mask == 0x1E00000) {
426: mask = 0xFE00000;
427: }
428: os
429: .write((int) (((subid & mask) >> bits) | ASN_BIT8));
430: }
431: os.write((int) (subid & mask));
432: }
433: }
434: }
435:
436: public static final void encodeUnsignedInt64(OutputStream os,
437: byte type, long value) throws IOException {
438: int len;
439: /*
440: * Truncate "unnecessary" bytes off of the most significant end of this
441: * 2's complement integer. There should be no sequence of 9
442: * consecutive 1's or 0's at the most significant end of the
443: * integer.
444: */
445: for (len = 8; len > 1; len--) {
446: if (((value >> (8 * (len - 1))) & 0xFF) != 0) {
447: break;
448: }
449: }
450: if (((value >> (8 * (len - 1))) & 0x080) != 0) {
451: len++;
452: }
453: encodeHeader(os, type, len);
454: if (len == 9) {
455: os.write(0);
456: len--;
457: }
458: for (int x = 0; x < len; x++) {
459: os.write((int) (value >> (8 * ((len - 1) - x) & LENMASK)));
460: }
461: }
462:
463: /**
464: * Decodes a ASN.1 length.
465: * @param is
466: * an <code>InputStream</code>
467: * @return
468: * the decoded length.
469: * @throws IOException
470: */
471: public static final int decodeLength(BERInputStream is)
472: throws IOException {
473: return decodeLength(is, true);
474: }
475:
476: /**
477: * Decodes a ASN.1 length.
478: * @param is
479: * an <code>InputStream</code>
480: * @param checkLength
481: * if <code>false</code> length check is always suppressed.
482: * @return
483: * the decoded length.
484: * @throws IOException
485: */
486: public static final int decodeLength(BERInputStream is,
487: boolean checkLength) throws IOException {
488: int length = 0;
489: int lengthbyte = is.read();
490:
491: if ((lengthbyte & ASN_LONG_LEN) > 0) {
492: lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
493: if (lengthbyte == 0) {
494: throw new IOException(
495: "Indefinite lengths are not supported");
496: }
497: if (lengthbyte > 4) {
498: throw new IOException(
499: "Data length > 4 bytes are not supported!");
500: }
501: for (int i = 0; i < lengthbyte; i++) {
502: int l = is.read() & 0xFF;
503: length |= (l << (8 * ((lengthbyte - 1) - i)));
504: }
505: if (length < 0) {
506: throw new IOException(
507: "SNMP does not support data lengths > 2^31");
508: }
509: } else { /* short asnlength */
510: length = lengthbyte & 0xFF;
511: }
512: /**
513: * If activated we do a length check here: length > is.available() -> throw
514: * exception
515: */
516: if (checkLength) {
517: checkLength(is, length);
518: }
519: return length;
520: }
521:
522: /**
523: * Decodes an ASN.1 header for an object with the ID and
524: * length specified.
525: * On entry, datalength is input as the number of valid bytes following
526: * "data". On exit, it is returned as the number of valid bytes
527: * in this object following the id and length.
528: *
529: * This only works on data types < 30, i.e. no extension octets.
530: * The maximum length is 0xFFFF;
531: *
532: * @param is
533: * the BERInputStream to decode.
534: * @param type
535: * returns the type of the object at the current position in the input
536: * stream.
537: * @param checkLength
538: * if <code>false</code> length check is always suppressed.
539: * @return
540: * the decoded length of the object.
541: * @throws IOException
542: */
543: public static final int decodeHeader(BERInputStream is,
544: MutableByte type, boolean checkLength) throws IOException {
545: /* this only works on data types < 30, i.e. no extension octets */
546: byte t = (byte) is.read();
547: if ((t & ASN_EXTENSION_ID) == ASN_EXTENSION_ID) {
548: throw new IOException("Cannot process extension IDs"
549: + getPositionMessage(is));
550: }
551: type.setValue(t);
552: return decodeLength(is, checkLength);
553: }
554:
555: /**
556: * Decodes an ASN.1 header for an object with the ID and
557: * length specified.
558: * On entry, datalength is input as the number of valid bytes following
559: * "data". On exit, it is returned as the number of valid bytes
560: * in this object following the id and length.
561: *
562: * This only works on data types < 30, i.e. no extension octets.
563: * The maximum length is 0xFFFF;
564: *
565: * @param is
566: * the BERInputStream to decode.
567: * @param type
568: * returns the type of the object at the current position in the input
569: * stream.
570: * @return
571: * the decoded length of the object.
572: * @throws IOException
573: */
574: public static final int decodeHeader(BERInputStream is,
575: MutableByte type) throws IOException {
576: return decodeHeader(is, type, true);
577: }
578:
579: public static final int decodeInteger(BERInputStream is,
580: MutableByte type) throws IOException {
581: int length;
582: int value = 0;
583:
584: type.setValue((byte) is.read());
585:
586: if ((type.value != 0x02) && (type.value != 0x43)
587: && (type.value != 0x41)) {
588: throw new IOException("Wrong ASN.1 type. Not an integer: "
589: + type.value + getPositionMessage(is));
590: }
591: length = decodeLength(is);
592: if (length > 4) {
593: throw new IOException(
594: "Length greater than 32bit are not supported "
595: + " for integers: "
596: + getPositionMessage(is));
597: }
598: int b = is.read() & 0xFF;
599: if ((b & 0x80) > 0) {
600: value = -1; /* integer is negative */
601: }
602: while (length-- > 0) {
603: value = (value << 8) | b;
604: if (length > 0) {
605: b = is.read();
606: }
607: }
608: return value;
609: }
610:
611: private static String getPositionMessage(BERInputStream is) {
612: return " at position " + is.getPosition();
613: }
614:
615: public static final long decodeUnsignedInteger(BERInputStream is,
616: MutableByte type) throws IOException {
617: int length;
618: long value = 0;
619:
620: // get the type
621: type.setValue((byte) is.read());
622: if ((type.value != 0x02) && (type.value != 0x43)
623: && (type.value != 0x41) && (type.value != 0x42)
624: && (type.value != 0x47)) {
625: throw new IOException(
626: "Wrong ASN.1 type. Not an unsigned integer: "
627: + type.value + getPositionMessage(is));
628: }
629: // pick up the len
630: length = decodeLength(is);
631:
632: // check for legal uint size
633: int b = is.read();
634: if ((length > 5) || ((length > 4) && (b != 0x00))) {
635: throw new IOException(
636: "Only 32bit unsigned integers are supported"
637: + getPositionMessage(is));
638: }
639:
640: // check for leading 0 octet
641: if (b == 0x00) {
642: if (length > 1) {
643: b = is.read();
644: }
645: length--;
646: }
647:
648: // calculate the value
649: for (int i = 0; i < length; i++) {
650: value = (value << 8) | (b & 0xFF);
651: if (i + 1 < length) {
652: b = is.read();
653: }
654: }
655: return value;
656: }
657:
658: public static final byte[] decodeString(BERInputStream is,
659: MutableByte type) throws IOException {
660: /*
661: * ASN.1 octet string ::= primstring | cmpdstring
662: * primstring ::= 0x04 asnlength byte {byte}*
663: * cmpdstring ::= 0x24 asnlength string {string}*
664: * ipaddress ::= 0x40 4 byte byte byte byte
665: */
666: // get the type
667: type.setValue((byte) is.read());
668: if ((type.value != BER.OCTETSTRING) && (type.value != 0x24)
669: && (type.value != BER.IPADDRESS)
670: && (type.value != BER.OPAQUE)
671: && (type.value != BER.BITSTRING)
672: && (type.value != 0x45)) {
673: throw new IOException("Wrong ASN.1 type. Not a string: "
674: + type.value + getPositionMessage(is));
675: }
676: int length = decodeLength(is);
677:
678: byte[] value = new byte[length];
679: int pos = 0;
680:
681: while ((pos < length) && (is.available() > 0)) {
682: int read = is.read(value);
683: if (read > 0) {
684: pos += read;
685: } else if (read < 0) {
686: throw new IOException("Wrong string length " + read
687: + " < " + length);
688: }
689: }
690: return value;
691: }
692:
693: public static final int[] decodeOID(BERInputStream is,
694: MutableByte type) throws IOException {
695: /*
696: * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
697: * subidentifier ::= {leadingbyte}* lastbyte
698: * leadingbyte ::= 1 7bitvalue
699: * lastbyte ::= 0 7bitvalue
700: */
701: int subidentifier;
702: int length;
703:
704: // get the type
705: type.setValue((byte) is.read());
706: if (type.value != 0x06) {
707: throw new IOException("Wrong type. Not an OID: "
708: + type.value + getPositionMessage(is));
709: }
710: length = decodeLength(is);
711:
712: int[] oid = new int[length + 2];
713: /* Handle invalid object identifier encodings of the form 06 00 robustly */
714: if (length == 0) {
715: oid[0] = oid[1] = 0;
716: }
717: int pos = 1;
718: while (length > 0) {
719: subidentifier = 0;
720: int b;
721: do { /* shift and add in low order 7 bits */
722: int next = is.read();
723: if (next < 0) {
724: throw new IOException(
725: "Unexpected end of input stream"
726: + getPositionMessage(is));
727: }
728: b = next & 0xFF;
729: subidentifier = (subidentifier << 7) + (b & ~ASN_BIT8);
730: length--;
731: } while ((length > 0) && ((b & ASN_BIT8) != 0)); /* last byte has high bit clear */
732: oid[pos++] = subidentifier;
733: }
734:
735: /*
736: * The first two subidentifiers are encoded into the first component
737: * with the value (X * 40) + Y, where:
738: * X is the value of the first subidentifier.
739: * Y is the value of the second subidentifier.
740: */
741: subidentifier = oid[1];
742: if (subidentifier == 0x2B) {
743: oid[0] = 1;
744: oid[1] = 3;
745: } else {
746: oid[1] = (subidentifier % 40);
747: oid[0] = ((subidentifier - oid[1]) / 40);
748: }
749: if (pos < 2) {
750: pos = 2;
751: }
752: int[] value = new int[pos];
753: System.arraycopy(oid, 0, value, 0, pos);
754: return value;
755: }
756:
757: public static final void decodeNull(BERInputStream is,
758: MutableByte type) throws IOException {
759: // get the type
760: type.setValue((byte) (is.read() & 0xFF));
761: if ((type.value != (byte) 0x05) && (type.value != (byte) 0x80)
762: && (type.value != (byte) 0x81)
763: && (type.value != (byte) 0x82)) {
764: throw new IOException("Wrong ASN.1 type. Is not null: "
765: + type.value + getPositionMessage(is));
766: }
767: int length = decodeLength(is);
768: if (length != 0) {
769: throw new IOException(
770: "Invalid Null encoding, length is not zero: "
771: + length + getPositionMessage(is));
772: }
773: }
774:
775: public static final long decodeUnsignedInt64(BERInputStream is,
776: MutableByte type) throws IOException {
777: // get the type
778: type.setValue((byte) is.read());
779: if ((type.value != 0x02) && (type.value != 0x46)) {
780: throw new IOException("Wrong type. Not an integer 64: "
781: + type.value + getPositionMessage(is));
782: }
783: int length = decodeLength(is);
784: int b = is.read() & 0xFF;
785: if (length > 9) {
786: throw new IOException(
787: "Invalid 64bit unsigned integer length: " + length
788: + getPositionMessage(is));
789: }
790: // check for leading 0 octet
791: if (b == 0x00) {
792: if (length > 1) {
793: b = is.read();
794: }
795: length--;
796: }
797: long value = 0;
798: // calculate the value
799: for (int i = 0; i < length; i++) {
800: value = (value << 8) | (b & 0xFF);
801: if (i + 1 < length) {
802: b = is.read();
803: }
804: }
805: return value;
806: }
807:
808: /**
809: * Gets the SEQUENCE length checking mode.
810: * @return
811: * <code>true</code> if the length of a parsed SEQUENCE should be checked
812: * against the real length of the objects parsed.
813: */
814: public static boolean isCheckSequenceLength() {
815: return checkSequenceLength;
816: }
817:
818: /**
819: * Sets the application wide SEQUENCE length checking mode.
820: * @param checkSequenceLen
821: * specifies whether he length of a parsed SEQUENCE should be checked
822: * against the real length of the objects parsed.
823: */
824: public static void setCheckSequenceLength(boolean checkSequenceLen) {
825: checkSequenceLength = checkSequenceLen;
826: }
827:
828: public static void checkSequenceLength(int expectedLength,
829: BERSerializable sequence) throws IOException {
830: if ((isCheckSequenceLength())
831: && (expectedLength != sequence.getBERPayloadLength())) {
832: throw new IOException(
833: "The actual length of the SEQUENCE object "
834: + sequence.getClass().getName() + " is "
835: + sequence.getBERPayloadLength() + ", but "
836: + expectedLength + " was expected");
837: }
838: }
839:
840: public static void checkSequenceLength(int expectedLength,
841: int actualLength, BERSerializable sequence)
842: throws IOException {
843: if ((isCheckSequenceLength())
844: && (expectedLength != actualLength)) {
845: throw new IOException(
846: "The actual length of the SEQUENCE object "
847: + sequence.getClass().getName() + " is "
848: + actualLength + ", but " + expectedLength
849: + " was expected");
850: }
851: }
852:
853: /**
854: * Checks whether the length of that was encoded is also available from the
855: * stream.
856: *
857: * @param is InputStream
858: * @param length int
859: * @throws IOException
860: * if the bytes that are given in length cannot be read from the input
861: * stream (without blocking).
862: */
863: private static void checkLength(BERInputStream is, int length)
864: throws IOException {
865: if (!checkValueLength) {
866: return;
867: }
868: if ((length < 0) || (length > is.getAvailableBytes())) {
869: throw new IOException("The encoded length " + length
870: + " exceeds the number of bytes left in input"
871: + getPositionMessage(is) + " which actually is "
872: + is.getAvailableBytes());
873: }
874: }
875:
876: public boolean isCheckValueLength() {
877: return checkValueLength;
878: }
879:
880: public void setCheckValueLength(boolean checkValueLength) {
881: BER.checkValueLength = checkValueLength;
882: }
883:
884: }
|