KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > asn1 > BER


1 /*_############################################################################
2   _##
3   _## SNMP4J - BER.java
4   _##
5   _## Copyright 2003-2007 Frank Fock and Jochen Katz (SNMP4J.org)
6   _##
7   _## Licensed under the Apache License, Version 2.0 (the "License");
8   _## you may not use this file except in compliance with the License.
9   _## You may obtain a copy of the License at
10   _##
11   _## http://www.apache.org/licenses/LICENSE-2.0
12   _##
13   _## Unless required by applicable law or agreed to in writing, software
14   _## distributed under the License is distributed on an "AS IS" BASIS,
15   _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   _## See the License for the specific language governing permissions and
17   _## limitations under the License.
18   _##
19   _##########################################################################*/

20
21
22
23
24
25 package org.snmp4j.asn1;
26
27 import java.io.OutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29
30 /**
31  * The BER class provides utility methods for the BER encoding and decoding.
32  *
33  * @author Jochen Katz & Frank Fock
34  * @version 1.7.4
35  */

36 public class BER {
37
38   public static final byte ASN_BOOLEAN = 0x01;
39   public static final byte ASN_INTEGER = 0x02;
40   public static final byte ASN_BIT_STR = 0x03;
41   public static final byte ASN_OCTET_STR = 0x04;
42   public static final byte ASN_NULL = 0x05;
43   public static final byte ASN_OBJECT_ID = 0x06;
44   public static final byte ASN_SEQUENCE = 0x10;
45   public static final byte ASN_SET = 0x11;
46   public static final byte ASN_UNIVERSAL = 0x00;
47   public static final byte ASN_APPLICATION = 0x40;
48   public static final byte ASN_CONTEXT = (byte)0x80;
49   public static final byte ASN_PRIVATE = (byte)0xC0;
50   public static final byte ASN_PRIMITIVE = (byte)0x00;
51   public static final byte ASN_CONSTRUCTOR = (byte)0x20;
52
53   public static final byte ASN_LONG_LEN = (byte)0x80;
54   public static final byte ASN_EXTENSION_ID = (byte)0x1F;
55   public static final byte ASN_BIT8 = (byte)0x80;
56
57   public static final byte INTEGER = ASN_UNIVERSAL | 0x02;
58   public static final byte INTEGER32 = ASN_UNIVERSAL | 0x02;
59   public static final byte BITSTRING = ASN_UNIVERSAL | 0x03;
60   public static final byte OCTETSTRING = ASN_UNIVERSAL | 0x04;
61   public static final byte NULL = ASN_UNIVERSAL | 0x05;
62   public static final byte OID = ASN_UNIVERSAL | 0x06;
63   public static final byte SEQUENCE = ASN_CONSTRUCTOR | 0x10;
64
65   public static final byte IPADDRESS = ASN_APPLICATION | 0x00;
66   public static final byte COUNTER = ASN_APPLICATION | 0x01;
67   public static final byte COUNTER32 = ASN_APPLICATION | 0x01;
68   public static final byte GAUGE = ASN_APPLICATION | 0x02;
69   public static final byte GAUGE32 = ASN_APPLICATION | 0x02;
70   public static final byte TIMETICKS = ASN_APPLICATION | 0x03;
71   public static final byte OPAQUE = ASN_APPLICATION | 0x04;
72   public static final byte COUNTER64 = ASN_APPLICATION | 0x06;
73
74   public static final int NOSUCHOBJECT = 0x80;
75   public static final int NOSUCHINSTANCE = 0x81;
76   public static final int ENDOFMIBVIEW = 0x82;
77
78   private static final int LENMASK = 0x0ff;
79   public static final int MAX_OID_LENGTH = 127;
80
81   private static boolean checkSequenceLength = true;
82   private static boolean checkValueLength = true;
83
84   /**
85    * The <code>MutableByte</code> class serves for exchanging type information
86    * from the various decode* methods.
87    *
88    * @author Frank Fock
89    * @version 1.0
90    */

91   public static class MutableByte {
92     byte value = 0;
93
94     public MutableByte() { }
95
96     public MutableByte(byte value) {
97       setValue(value);
98     }
99
100     public void setValue(byte value) {
101       this.value = value;
102     }
103
104     public byte getValue() {
105       return value;
106     }
107   }
108
109   /**
110    * Encodes an ASN.1 header for an object with the ID and
111    * length specified.
112    * @param os
113    * an <code>OutputStream</code> to which the header is encoded.
114    * @param type
115    * the type of the ASN.1 object. Must be < 30, i.e. no extension octets.
116    * @param length
117    * the length of the object. The maximum length is 0xFFFFFFFF;
118    * @throws IOException
119    */

120   public static final void encodeHeader(OutputStream JavaDoc os, int type, int length)
121       throws IOException JavaDoc
122   {
123     os.write(type);
124     encodeLength(os, length);
125   }
126
127   /**
128    * Encodes an ASN.1 header for an object with the ID and
129    * length specified with a fixed length of the encoded length as supplied.
130    * @param os
131    * an <code>OutputStream</code> to which the header is encoded.
132    * @param type
133    * the type of the ASN.1 object. Must be < 30, i.e. no extension octets.
134    * @param length
135    * the length of the object. The maximum length is 0xFFFFFFFF;
136    * @param numBytesLength
137    * the number of bytes used to encode the length of the length.
138    * @throws IOException
139    */

140   public static final void encodeHeader(OutputStream JavaDoc os, int type, int length,
141                                         int numBytesLength)
142       throws IOException JavaDoc
143   {
144     os.write(type);
145     encodeLength(os, length, numBytesLength);
146   }
147
148   /**
149    * Compute the space needed to encode the length.
150    *
151    * @param length
152    * Length to encode
153    * @return
154    * the count of bytes needed to encode the value <code>length</code>
155    */

156   public static final int getBERLengthOfLength(int length) {
157     if (length < 0) {
158       return 5;
159     }
160     else if (length < 0x80){
161       return 1;
162     }
163     else if (length <= 0xFF){
164       return 2;
165     }
166     else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
167       return 3;
168     }
169     else if (length <= 0xFFFFFF) { /* 0xFFFF < length <= 0xFFFFFF */
170       return 4;
171     }
172     return 5;
173   }
174
175   /**
176    * Encodes the length of an ASN.1 object.
177    * @param os
178    * an <code>OutputStream</code> to which the length is encoded.
179    * @param length
180    * the length of the object. The maximum length is 0xFFFFFFFF;
181    * @throws IOException
182    */

183   public static final void encodeLength(OutputStream JavaDoc os, int length)
184       throws IOException JavaDoc
185   {
186     if (length < 0) {
187       os.write(0x04 | ASN_LONG_LEN);
188       os.write((length >> 24) & 0xFF);
189       os.write((length >> 16) & 0xFF);
190       os.write((length >> 8) & 0xFF);
191       os.write(length & 0xFF);
192     }
193     else if (length < 0x80){
194       os.write(length);
195     }
196     else if (length <= 0xFF){
197       os.write((0x01 | ASN_LONG_LEN));
198       os.write(length);
199     }
200     else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
201       os.write(0x02 | ASN_LONG_LEN);
202       os.write((length >> 8) & 0xFF);
203       os.write(length & 0xFF);
204     }
205     else if (length <= 0xFFFFFF) { /* 0xFFFF < length <= 0xFFFFFF */
206       os.write(0x03 | ASN_LONG_LEN);
207       os.write((length >> 16) & 0xFF);
208       os.write((length >> 8) & 0xFF);
209       os.write(length & 0xFF);
210     }
211     else {
212       os.write(0x04 | ASN_LONG_LEN);
213       os.write((length >> 24) & 0xFF);
214       os.write((length >> 16) & 0xFF);
215       os.write((length >> 8) & 0xFF);
216       os.write(length & 0xFF);
217     }
218   }
219
220   /**
221    * Encodes the length of an ASN.1 object.
222    * @param os
223    * an <code>OutputStream</code> to which the length is encoded.
224    * @param length
225    * the length of the object. The maximum length is 0xFFFFFFFF;
226    * @param numLengthBytes
227    * the number of bytes to be used to encode the length using the long
228    * form.
229    * @throws IOException
230    */

231   public static final void encodeLength(OutputStream JavaDoc os, int length,
232                                         int numLengthBytes)
233       throws IOException JavaDoc
234   {
235     os.write((numLengthBytes | ASN_LONG_LEN));
236     for (int i=(numLengthBytes-1)*8; i>=0; i-=8) {
237       os.write(((length >> i) & 0xFF));
238     }
239   }
240
241   /**
242    * Encode a signed integer.
243    * @param os
244    * an <code>OutputStream</code> to which the length is encoded.
245    * @param type
246    * the tag type for the integer (typically 0x02)
247    * @param value
248    * the integer value to encode.
249    * @throws IOException
250    */

251   public static final void encodeInteger(OutputStream JavaDoc os, byte type, int value)
252       throws IOException JavaDoc
253   {
254     int integer = value;
255     int mask;
256     int intsize = 4;
257
258     /*
259      * Truncate "unnecessary" bytes off of the most significant end of this
260      * 2's complement integer. There should be no sequence of 9
261      * consecutive 1's or 0's at the most significant end of the
262      * integer.
263      */

264     mask = 0x1FF << ((8 * 3) - 1);
265     /* mask is 0xFF800000 on a big-endian machine */
266     while((((integer & mask) == 0) || ((integer & mask) == mask))
267           && intsize > 1){
268       intsize--;
269       integer <<= 8;
270     }
271     encodeHeader(os, type, intsize);
272     mask = 0xFF << (8 * 3);
273     /* mask is 0xFF000000 on a big-endian machine */
274     while ((intsize--) > 0){
275       os.write(((integer & mask) >> (8 * 3)));
276       integer <<= 8;
277     }
278   }
279
280   /**
281    * Encode an unsigned integer.
282    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
283    * @param os
284    * an <code>OutputStream</code> to which the length is encoded.
285    * @param type
286    * the tag type for the integer (typically 0x02)
287    * @param value
288    * the integer value to encode.
289    * @throws IOException
290    */

291   public static final void encodeUnsignedInteger(OutputStream JavaDoc os, byte type, long value)
292       throws IOException JavaDoc
293   {
294     // figure out the len
295
int len = 1;
296     if ((( value >> 24) & LENMASK) != 0) {
297       len = 4;
298     }
299     else if ((( value >> 16) & LENMASK) !=0) {
300       len = 3;
301     }
302     else if ((( value >> 8) & LENMASK) !=0) {
303       len = 2;
304     }
305     // check for 5 byte len where first byte will be
306
// a null
307
if ((( value >> (8 * (len -1))) & 0x080) !=0) {
308       len++;
309     }
310
311     // build up the header
312
encodeHeader(os, type, len); // length of BER encoded item
313

314     // special case, add a null byte for len of 5
315
if (len == 5) {
316       os.write(0);
317       for (int x=1; x<len; x++) {
318         os.write((int) (value >> (8 * (4 - x) & LENMASK)));
319       }
320     }
321     else
322     {
323       for (int x=0; x<len; x++) {
324         os.write((int) (value >> (8 * ((len - 1) - x) & LENMASK)));
325       }
326     }
327   }
328
329   /**
330    * Encode an ASN.1 octet string filled with the supplied input string.
331    * @param os
332    * an <code>OutputStream</code> to which the length is encoded.
333    * @param type
334    * the tag type for the integer (typically 0x02)
335    * @param string
336    * the <code>byte</code> array containing the octet string value.
337    * @throws IOException
338    */

339   public static final void encodeString(OutputStream JavaDoc os, byte type, byte[] string)
340       throws IOException JavaDoc
341   {
342     /*
343     * ASN.1 octet string ::= primstring | cmpdstring
344     * primstring ::= 0x04 asnlength byte {byte}*
345     * cmpdstring ::= 0x24 asnlength string {string}*
346     * This code will never send a compound string.
347     */

348     encodeHeader(os, type, string.length);
349     // fixed
350
os.write(string);
351   }
352
353   /**
354    * Encode an ASN.1 header for a sequence with the ID and length specified.
355    * This only works on data types < 30, i.e. no extension octets.
356    * The maximum length is 0xFFFF;
357    *
358    * @param os
359    * an <code>OutputStream</code> to which the length is encoded.
360    * @param type
361    * the tag type for the integer (typically 0x02)
362    * @param length
363    * the length of the sequence to encode.
364    * @throws IOException
365    */

366   public static final void encodeSequence(OutputStream JavaDoc os, byte type, int length)
367       throws IOException JavaDoc
368   {
369     os.write(type);
370     encodeLength(os, length);
371   }
372
373   /**
374    * Gets the payload length in bytes of the BER encoded OID value.
375    * @param value
376    * an array of unsigned integer values representing an object identifier.
377    * @return
378    * the BER encoded length of the OID without header and length.
379    */

380   public static final int getOIDLength(int[] value) {
381     int length = 1; // for first 2 subids
382
for (int i = 2; i < value.length; i++) {
383       long v = value[i] & 0xFFFFFFFFL;
384       if (v < 0x80) { // 7 bits long subid
385
length += 1;
386       }
387       else if (v < 0x4000) { // 14 bits long subid
388
length += 2;
389       }
390       else if (v < 0x200000) { // 21 bits long subid
391
length += 3;
392       }
393       else if (v < 0x10000000) { // 28 bits long subid
394
length += 4;
395       }
396       else { // 32 bits long subid
397
length += 5;
398       }
399     }
400     return length;
401   }
402
403  /**
404   * Encode an ASN.1 oid filled with the supplied oid value.
405   *
406   * @param os
407   * an <code>OutputStream</code> to which the length is encoded.
408   * @param type
409   * the tag type for the integer (typically 0x06)
410   * @param oid
411   * the <code>int</code> array containing the OID value.
412   * @throws IOException
413   */

414   public static final void encodeOID(OutputStream JavaDoc os, byte type, int[] oid)
415       throws IOException JavaDoc
416   {
417     /*
418      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
419      * subidentifier ::= {leadingbyte}* lastbyte
420      * leadingbyte ::= 1 7bitvalue
421      * lastbyte ::= 0 7bitvalue
422      */

423     encodeHeader(os, type, getOIDLength(oid));
424
425     int encodedLength = oid.length;
426     int rpos = 0;
427
428     if (oid.length < 2){
429       os.write(0);
430       encodedLength = 0;
431     }
432     else {
433       os.write(((oid[1] + (oid[0] * 40)) & 0xFF));
434       encodedLength -= 2;
435       rpos = 2;
436     }
437
438     while (encodedLength-- > 0){
439       long subid = (oid[rpos++] & 0xFFFFFFFFL);
440       if (subid < 127) {
441         os.write((int)subid & 0xFF);
442       }
443       else {
444         long mask = 0x7F; /* handle subid == 0 case */
445         long bits = 0;
446
447         /* testmask *MUST* !!!! be of an unsigned type */
448         for (long testmask = 0x7F, testbits = 0; testmask != 0;
449              testmask <<= 7, testbits += 7) {
450           if ((subid & testmask) > 0) { /* if any bits set */
451             mask = testmask;
452             bits = testbits;
453           }
454         }
455         /* mask can't be zero here */
456         for (; mask != 0x7F; mask >>= 7, bits -= 7){
457           /* fix a mask that got truncated above */
458           if (mask == 0x1E00000) {
459             mask = 0xFE00000;
460           }
461           os.write((int)(((subid & mask) >> bits) | ASN_BIT8));
462         }
463         os.write((int)(subid & mask));
464       }
465     }
466   }
467
468
469   public static final void encodeUnsignedInt64(OutputStream JavaDoc os, byte type, long value)
470       throws IOException JavaDoc
471   {
472     int len;
473     /*
474      * Truncate "unnecessary" bytes off of the most significant end of this
475      * 2's complement integer. There should be no sequence of 9
476      * consecutive 1's or 0's at the most significant end of the
477      * integer.
478      */

479     for (len = 8; len > 1; len--) {
480       if (((value >> (8 * (len - 1))) & 0xFF) != 0) {
481         break;
482       }
483     }
484     if ((( value >> (8 * (len -1))) & 0x080) !=0) {
485       len++;
486     }
487     encodeHeader(os, type, len);
488     if (len == 9) {
489       os.write(0);
490       len--;
491     }
492     for (int x=0; x<len; x++) {
493       os.write((int) (value >> (8 * ((len - 1) - x) & LENMASK)));
494     }
495   }
496
497   /**
498    * Decodes a ASN.1 length.
499    * @param is
500    * an <code>InputStream</code>
501    * @return
502    * the decoded length.
503    * @throws IOException
504    */

505   public static final int decodeLength(BERInputStream is)
506       throws IOException JavaDoc
507   {
508     return decodeLength(is, true);
509   }
510
511   /**
512    * Decodes a ASN.1 length.
513    * @param is
514    * an <code>InputStream</code>
515    * @param checkLength
516    * if <code>false</code> length check is always suppressed.
517    * @return
518    * the decoded length.
519    * @throws IOException
520    */

521   public static final int decodeLength(BERInputStream is, boolean checkLength)
522       throws IOException JavaDoc
523   {
524     int length = 0;
525     int lengthbyte = is.read();
526
527     if ((lengthbyte & ASN_LONG_LEN) > 0) {
528       lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
529       if (lengthbyte == 0){
530         throw new IOException JavaDoc("Indefinite lengths are not supported");
531       }
532       if (lengthbyte > 4){
533         throw new IOException JavaDoc("Data length > 4 bytes are not supported!");
534       }
535       for (int i=0; i<lengthbyte; i++) {
536         int l = is.read() & 0xFF;
537         length |= (l << (8*((lengthbyte-1)-i)));
538       }
539       if (length < 0) {
540          throw new IOException JavaDoc("SNMP does not support data lengths > 2^31");
541       }
542     }
543     else { /* short asnlength */
544       length = lengthbyte & 0xFF;
545     }
546     /**
547      * If activated we do a length check here: length > is.available() -> throw
548      * exception
549      */

550     if (checkLength) {
551       checkLength(is, length);
552     }
553     return length;
554   }
555
556   /**
557    * Decodes an ASN.1 header for an object with the ID and
558    * length specified.
559    * On entry, datalength is input as the number of valid bytes following
560    * "data". On exit, it is returned as the number of valid bytes
561    * in this object following the id and length.
562    *
563    * This only works on data types < 30, i.e. no extension octets.
564    * The maximum length is 0xFFFF;
565    *
566    * @param is
567    * the BERInputStream to decode.
568    * @param type
569    * returns the type of the object at the current position in the input
570    * stream.
571    * @param checkLength
572    * if <code>false</code> length check is always suppressed.
573    * @return
574    * the decoded length of the object.
575    * @throws IOException
576    */

577   public static final int decodeHeader(BERInputStream is, MutableByte type,
578                                        boolean checkLength)
579       throws IOException JavaDoc
580   {
581     /* this only works on data types < 30, i.e. no extension octets */
582     byte t = (byte)is.read();
583     if ((t & ASN_EXTENSION_ID) == ASN_EXTENSION_ID) {
584       throw new IOException JavaDoc("Cannot process extension IDs"+
585                             getPositionMessage(is));
586     }
587     type.setValue(t);
588     return decodeLength(is, checkLength);
589   }
590
591   /**
592    * Decodes an ASN.1 header for an object with the ID and
593    * length specified.
594    * On entry, datalength is input as the number of valid bytes following
595    * "data". On exit, it is returned as the number of valid bytes
596    * in this object following the id and length.
597    *
598    * This only works on data types < 30, i.e. no extension octets.
599    * The maximum length is 0xFFFF;
600    *
601    * @param is
602    * the BERInputStream to decode.
603    * @param type
604    * returns the type of the object at the current position in the input
605    * stream.
606    * @return
607    * the decoded length of the object.
608    * @throws IOException
609    */

610   public static final int decodeHeader(BERInputStream is, MutableByte type)
611       throws IOException JavaDoc
612   {
613     return decodeHeader(is, type, true);
614   }
615
616   public static final int decodeInteger(BERInputStream is, MutableByte type)
617       throws IOException JavaDoc
618   {
619     int length;
620     int value = 0;
621
622     type.setValue((byte)is.read());
623
624     if ((type.value != 0x02) && (type.value != 0x43) &&
625         (type.value != 0x41)) {
626       throw new IOException JavaDoc("Wrong ASN.1 type. Not an integer: "+type.value+
627                             getPositionMessage(is));
628     }
629     length = decodeLength(is);
630     if (length > 4) {
631       throw new IOException JavaDoc("Length greater than 32bit are not supported "+
632                             " for integers: "+getPositionMessage(is));
633     }
634     int b = is.read() & 0xFF;
635     if ((b & 0x80) > 0) {
636       value = -1; /* integer is negative */
637     }
638     while (length-- > 0) {
639       value = (value << 8) | b;
640       if (length > 0) {
641         b = is.read();
642       }
643     }
644     return value;
645   }
646
647   private static String JavaDoc getPositionMessage(BERInputStream is) {
648     return " at position "+is.getPosition();
649   }
650
651   public static final long decodeUnsignedInteger(BERInputStream is, MutableByte type)
652       throws IOException JavaDoc
653   {
654     int length;
655     long value = 0;
656
657     // get the type
658
type.setValue((byte)is.read());
659     if ((type.value != 0x02) && (type.value != 0x43) &&
660         (type.value != 0x41) && (type.value != 0x42) &&
661         (type.value != 0x47)) {
662       throw new IOException JavaDoc("Wrong ASN.1 type. Not an unsigned integer: "+
663                             type.value+
664                             getPositionMessage(is));
665     }
666     // pick up the len
667
length = decodeLength(is);
668
669     // check for legal uint size
670
int b = is.read();
671     if ((length > 5) || ((length > 4) && (b != 0x00))) {
672       throw new IOException JavaDoc("Only 32bit unsigned integers are supported"+
673                             getPositionMessage(is));
674     }
675
676     // check for leading 0 octet
677
if (b == 0x00) {
678       if (length > 1) {
679         b = is.read();
680       }
681       length--;
682     }
683
684     // calculate the value
685
for (int i=0; i<length; i++) {
686       value = (value << 8) | (b & 0xFF);
687       if (i+1<length) {
688         b = is.read();
689       }
690     }
691     return value;
692   }
693
694   public static final byte[] decodeString(BERInputStream is, MutableByte type)
695       throws IOException JavaDoc
696   {
697     /*
698      * ASN.1 octet string ::= primstring | cmpdstring
699      * primstring ::= 0x04 asnlength byte {byte}*
700      * cmpdstring ::= 0x24 asnlength string {string}*
701      * ipaddress ::= 0x40 4 byte byte byte byte
702      */

703     // get the type
704
type.setValue((byte)is.read());
705     if ((type.value != BER.OCTETSTRING) && (type.value != 0x24) &&
706         (type.value != BER.IPADDRESS) && (type.value != BER.OPAQUE) &&
707         (type.value != BER.BITSTRING) &&
708         (type.value != 0x45)) {
709       throw new IOException JavaDoc("Wrong ASN.1 type. Not a string: "+type.value+
710                             getPositionMessage(is));
711     }
712     int length = decodeLength(is);
713
714     byte[] value = new byte[length];
715     int pos = 0;
716
717     while ((pos < length) && (is.available()>0)) {
718       int read = is.read(value);
719       if (read > 0) {
720         pos += read;
721       }
722       else if (read < 0) {
723         throw new IOException JavaDoc("Wrong string length "+read+" < "+length);
724       }
725     }
726     return value;
727   }
728
729
730   public static final int[] decodeOID(BERInputStream is, MutableByte type)
731       throws IOException JavaDoc
732   {
733     /*
734      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
735      * subidentifier ::= {leadingbyte}* lastbyte
736      * leadingbyte ::= 1 7bitvalue
737      * lastbyte ::= 0 7bitvalue
738      */

739     int subidentifier;
740     int length;
741
742     // get the type
743
type.setValue((byte)is.read());
744     if (type.value != 0x06) {
745       throw new IOException JavaDoc("Wrong type. Not an OID: "+type.value+
746                             getPositionMessage(is));
747     }
748     length = decodeLength(is);
749
750     int[] oid = new int[length+2];
751     /* Handle invalid object identifier encodings of the form 06 00 robustly */
752     if (length == 0) {
753       oid[0] = oid[1] = 0;
754     }
755     int pos = 1;
756     while (length > 0){
757       subidentifier = 0;
758       int b;
759       do { /* shift and add in low order 7 bits */
760         int next = is.read();
761         if (next < 0) {
762           throw new IOException JavaDoc("Unexpected end of input stream" +
763                                 getPositionMessage(is));
764         }
765         b = next & 0xFF;
766         subidentifier = (subidentifier << 7) + (b & ~ASN_BIT8);
767         length--;
768       } while ((length > 0) && ((b & ASN_BIT8) != 0)); /* last byte has high bit clear */
769       oid[pos++] = subidentifier;
770     }
771
772     /*
773     * The first two subidentifiers are encoded into the first component
774     * with the value (X * 40) + Y, where:
775     * X is the value of the first subidentifier.
776     * Y is the value of the second subidentifier.
777     */

778     subidentifier = oid[1];
779     if (subidentifier == 0x2B){
780       oid[0] = 1;
781       oid[1] = 3;
782     }
783     else {
784       oid[1] = (subidentifier % 40);
785       oid[0] = ((subidentifier - oid[1]) / 40);
786     }
787     if (pos < 2) {
788       pos = 2;
789     }
790     int[] value = new int[pos];
791     System.arraycopy(oid, 0, value, 0, pos);
792     return value;
793   }
794
795   public static final void decodeNull(BERInputStream is, MutableByte type)
796       throws IOException JavaDoc
797   {
798     // get the type
799
type.setValue((byte)(is.read() & 0xFF));
800     if ((type.value != (byte)0x05) && (type.value != (byte)0x80) &&
801         (type.value != (byte)0x81) && (type.value != (byte)0x82)) {
802       throw new IOException JavaDoc("Wrong ASN.1 type. Is not null: " + type.value+
803                             getPositionMessage(is));
804     }
805     int length = decodeLength(is);
806     if (length != 0) {
807       throw new IOException JavaDoc("Invalid Null encoding, length is not zero: "+
808                             length+getPositionMessage(is));
809     }
810   }
811
812   public static final long decodeUnsignedInt64(BERInputStream is, MutableByte type)
813       throws IOException JavaDoc
814   {
815     // get the type
816
type.setValue((byte)is.read());
817     if ((type.value != 0x02) && (type.value != 0x46)) {
818       throw new IOException JavaDoc("Wrong type. Not an integer 64: "+type.value+
819                             getPositionMessage(is));
820     }
821     int length = decodeLength(is);
822     int b = is.read() & 0xFF;
823     if (length > 9) {
824       throw new IOException JavaDoc("Invalid 64bit unsigned integer length: "+length+
825                             getPositionMessage(is));
826     }
827     // check for leading 0 octet
828
if (b == 0x00) {
829       if (length > 1) {
830         b = is.read();
831       }
832       length--;
833     }
834     long value = 0;
835     // calculate the value
836
for (int i=0; i<length; i++) {
837       value = (value << 8) | (b & 0xFF);
838       if (i+1<length) {
839         b = is.read();
840       }
841     }
842     return value;
843   }
844
845   /**
846    * Gets the SEQUENCE length checking mode.
847    * @return
848    * <code>true</code> if the length of a parsed SEQUENCE should be checked
849    * against the real length of the objects parsed.
850    */

851   public static boolean isCheckSequenceLength() {
852     return checkSequenceLength;
853   }
854
855   /**
856    * Sets the application wide SEQUENCE length checking mode.
857    * @param checkSequenceLen
858    * specifies whether he length of a parsed SEQUENCE should be checked
859    * against the real length of the objects parsed.
860    */

861   public static void setCheckSequenceLength(boolean checkSequenceLen) {
862     checkSequenceLength = checkSequenceLen;
863   }
864
865   public static void checkSequenceLength(int expectedLength,
866                                          BERSerializable sequence)
867       throws IOException JavaDoc
868   {
869     if ((isCheckSequenceLength()) &&
870         (expectedLength != sequence.getBERPayloadLength())) {
871       throw new IOException JavaDoc("The actual length of the SEQUENCE object "+
872                             sequence.getClass().getName()+
873                             " is "+sequence.getBERPayloadLength()+", but "+
874                             expectedLength+" was expected");
875     }
876   }
877
878   public static void checkSequenceLength(int expectedLength, int actualLength,
879                                          BERSerializable sequence)
880       throws IOException JavaDoc
881   {
882     if ((isCheckSequenceLength()) &&
883         (expectedLength != actualLength)) {
884       throw new IOException JavaDoc("The actual length of the SEQUENCE object "+
885                             sequence.getClass().getName()+
886                             " is "+actualLength+", but "+
887                             expectedLength+" was expected");
888     }
889   }
890
891   /**
892    * Checks whether the length of that was encoded is also available from the
893    * stream.
894    *
895    * @param is InputStream
896    * @param length int
897    * @throws IOException
898    * if the bytes that are given in length cannot be read from the input
899    * stream (without blocking).
900    */

901   private static void checkLength(BERInputStream is, int length) throws
902       IOException JavaDoc {
903     if (!checkValueLength) {
904       return;
905     }
906     if ((length < 0) || (length > is.getAvailableBytes())) {
907       throw new IOException JavaDoc("The encoded length "+
908                             length+
909                             " exceeds the number of bytes left in input"+
910                             getPositionMessage(is)+
911                             " which actually is "+is.getAvailableBytes());
912     }
913   }
914
915   public boolean isCheckValueLength() {
916     return checkValueLength;
917   }
918
919   public void setCheckValueLength(boolean checkValueLength) {
920     BER.checkValueLength = checkValueLength;
921   }
922
923 }
924
925
926
Popular Tags