1 /* 2 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package com.sun.jmx.snmp; 28 29 30 31 32 /** 33 * The <CODE>BerDecoder</CODE> class is used for decoding 34 * BER-encoded data. 35 * 36 * A <CODE>BerDecoder</CODE> needs to be set up with the byte string containing 37 * the encoding. It maintains a current position in the byte string. 38 * 39 * Methods allows to fetch integer, string, OID, etc., from the current 40 * position. After a fetch the current position is moved forward. 41 * 42 * A fetch throws a <CODE>BerException</CODE> if the encoding is not of the 43 * expected type. 44 * 45 * <p><b>This API is a Sun Microsystems internal API and is subject 46 * to change without notice.</b></p> 47 * 48 * @since 1.5 49 */ 50 51 public class BerDecoder { 52 53 /** 54 * Constructs a new decoder and attaches it to the specified byte string. 55 * 56 * @param b The byte string containing the encoded data. 57 */ 58 59 public BerDecoder(byte b[]) { 60 bytes = b ; 61 reset() ; 62 } 63 64 public void reset() { 65 next = 0 ; 66 stackTop = 0 ; 67 } 68 69 /** 70 * Fetch an integer. 71 * 72 * @return The decoded integer. 73 * 74 * @exception BerException Current position does not point to an integer. 75 */ 76 77 public int fetchInteger() throws BerException { 78 return fetchInteger(IntegerTag) ; 79 } 80 81 82 /** 83 * Fetch an integer with the specified tag. 84 * 85 * @param tag The expected tag. 86 * 87 * @return The decoded integer. 88 * 89 * @exception BerException Current position does not point to an integer 90 * or the tag is not the expected one. 91 */ 92 93 public int fetchInteger(int tag) throws BerException { 94 int result = 0 ; 95 final int backup = next ; 96 try { 97 if (fetchTag() != tag) { 98 throw new BerException() ; 99 } 100 result = fetchIntegerValue() ; 101 } 102 catch(BerException e) { 103 next = backup ; 104 throw e ; 105 } 106 107 return result ; 108 } 109 110 111 112 /** 113 * Fetch an integer and return a long value. 114 * 115 * @return The decoded integer. 116 * 117 * @exception BerException Current position does not point to an integer. 118 */ 119 120 public long fetchIntegerAsLong() throws BerException { 121 return fetchIntegerAsLong(IntegerTag) ; 122 } 123 124 125 /** 126 * Fetch an integer with the specified tag and return a long value. 127 * 128 * @param tag The expected tag. 129 * 130 * @return The decoded integer. 131 * 132 * @exception BerException Current position does not point to an integer 133 * or the tag is not the expected one. 134 */ 135 136 public long fetchIntegerAsLong(int tag) throws BerException { 137 long result = 0 ; 138 final int backup = next ; 139 try { 140 if (fetchTag() != tag) { 141 throw new BerException() ; 142 } 143 result = fetchIntegerValueAsLong() ; 144 } 145 catch(BerException e) { 146 next = backup ; 147 throw e ; 148 } 149 150 return result ; 151 } 152 153 154 155 /** 156 * Fetch an octet string. 157 * 158 * @return The decoded string. 159 * 160 * @exception BerException Current position does not point to an octet string. 161 */ 162 163 public byte[] fetchOctetString() throws BerException { 164 return fetchOctetString(OctetStringTag) ; 165 } 166 167 168 /** 169 * Fetch an octet string with a specified tag. 170 * 171 * @param tag The expected tag. 172 * 173 * @return The decoded string. 174 * 175 * @exception BerException Current position does not point to an octet string 176 * or the tag is not the expected one. 177 */ 178 179 public byte[] fetchOctetString(int tag) throws BerException { 180 byte[] result = null ; 181 final int backup = next ; 182 try { 183 if (fetchTag() != tag) { 184 throw new BerException() ; 185 } 186 result = fetchStringValue() ; 187 } 188 catch(BerException e) { 189 next = backup ; 190 throw e ; 191 } 192 193 return result ; 194 } 195 196 197 /** 198 * Fetch an object identifier. 199 * 200 * @return The decoded object identifier as an array of long. 201 */ 202 203 public long[] fetchOid() throws BerException { 204 return fetchOid(OidTag) ; 205 } 206 207 208 /** 209 * Fetch an object identifier with a specified tag. 210 * 211 * @param tag The expected tag. 212 * 213 * @return The decoded object identifier as an array of long. 214 * 215 * @exception BerException Current position does not point to an oid 216 * or the tag is not the expected one. 217 */ 218 219 public long[] fetchOid(int tag) throws BerException { 220 long[] result = null ; 221 final int backup = next ; 222 try { 223 if (fetchTag() != tag) { 224 throw new BerException() ; 225 } 226 result = fetchOidValue() ; 227 } 228 catch(BerException e) { 229 next = backup ; 230 throw e ; 231 } 232 233 return result ; 234 } 235 236 237 /** 238 * Fetch a <CODE>NULL</CODE> value. 239 * 240 * @exception BerException Current position does not point to <CODE>NULL</CODE> value. 241 */ 242 243 public void fetchNull() throws BerException { 244 fetchNull(NullTag) ; 245 } 246 247 248 /** 249 * Fetch a <CODE>NULL</CODE> value with a specified tag. 250 * 251 * @param tag The expected tag. 252 * 253 * @exception BerException Current position does not point to 254 * <CODE>NULL</CODE> value or the tag is not the expected one. 255 */ 256 257 public void fetchNull(int tag) throws BerException { 258 final int backup = next ; 259 try { 260 if (fetchTag() != tag) { 261 throw new BerException() ; 262 } 263 final int length = fetchLength(); 264 if (length != 0) throw new BerException(); 265 } 266 catch(BerException e) { 267 next = backup ; 268 throw e ; 269 } 270 } 271 272 273 274 /** 275 * Fetch an <CODE>ANY</CODE> value. In fact, this method does not decode anything 276 * it simply returns the next TLV as an array of bytes. 277 * 278 * @return The TLV as a byte array. 279 * 280 * @exception BerException The next TLV is really badly encoded... 281 */ 282 283 public byte[] fetchAny() throws BerException { 284 byte[] result = null ; 285 final int backup = next ; 286 try { 287 final int tag = fetchTag() ; 288 final int contentLength = fetchLength() ; 289 if (contentLength < 0) throw new BerException() ; 290 final int tlvLength = next + contentLength - backup ; 291 if (contentLength > (bytes.length - next)) 292 throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); 293 final byte[] data = new byte[tlvLength] ; 294 java.lang.System.arraycopy(bytes,backup,data,0,tlvLength); 295 // for (int i = 0 ; i < tlvLength ; i++) { 296 // data[i] = bytes[backup + i] ; 297 // } 298 next = next + contentLength ; 299 result = data; 300 } 301 catch(IndexOutOfBoundsException e) { 302 next = backup ; 303 throw new BerException() ; 304 } 305 // catch(Error e) { 306 // debug("fetchAny: Error decoding BER: " + e); 307 // throw e; 308 // } 309 310 return result ; 311 } 312 313 314 /** 315 * Fetch an <CODE>ANY</CODE> value with a specific tag. 316 * 317 * @param tag The expected tag. 318 * 319 * @return The TLV as a byte array. 320 * 321 * @exception BerException The next TLV is really badly encoded... 322 */ 323 324 public byte[] fetchAny(int tag) throws BerException { 325 if (getTag() != tag) { 326 throw new BerException() ; 327 } 328 return fetchAny() ; 329 } 330 331 332 333 /** 334 * Fetch a sequence header. 335 * The decoder computes the end position of the sequence and push it 336 * on its stack. 337 * 338 * @exception BerException Current position does not point to a sequence header. 339 */ 340 341 public void openSequence() throws BerException { 342 openSequence(SequenceTag) ; 343 } 344 345 346 /** 347 * Fetch a sequence header with a specific tag. 348 * 349 * @param tag The expected tag. 350 * 351 * @exception BerException Current position does not point to a sequence header 352 * or the tag is not the expected one. 353 */ 354 355 public void openSequence(int tag) throws BerException { 356 final int backup = next ; 357 try { 358 if (fetchTag() != tag) { 359 throw new BerException() ; 360 } 361 final int l = fetchLength() ; 362 if (l < 0) throw new BerException(); 363 if (l > (bytes.length - next)) throw new BerException(); 364 stackBuf[stackTop++] = next + l ; 365 } 366 catch(BerException e) { 367 next = backup ; 368 throw e ; 369 } 370 } 371 372 373 /** 374 * Close a sequence. 375 * The decode pull the stack and verifies that the current position 376 * matches with the calculated end of the sequence. If not it throws 377 * an exception. 378 * 379 * @exception BerException The sequence is not expected to finish here. 380 */ 381 382 public void closeSequence() throws BerException { 383 if (stackBuf[stackTop - 1] == next) { 384 stackTop-- ; 385 } 386 else { 387 throw new BerException() ; 388 } 389 } 390 391 392 /** 393 * Return <CODE>true</CODE> if the end of the current sequence is not reached. 394 * When this method returns <CODE>false</CODE>, <CODE>closeSequence</CODE> can (and must) be 395 * invoked. 396 * 397 * @return <CODE>true</CODE> if there is still some data in the sequence. 398 */ 399 400 public boolean cannotCloseSequence() { 401 return (next < stackBuf[stackTop - 1]) ; 402 } 403 404 405 /** 406 * Get the tag of the data at the current position. 407 * Current position is unchanged. 408 * 409 * @return The next tag. 410 */ 411 412 public int getTag() throws BerException { 413 int result = 0 ; 414 final int backup = next ; 415 try { 416 result = fetchTag() ; 417 } 418 finally { 419 next = backup ; 420 } 421 422 return result ; 423 } 424 425 426 427 public String toString() { 428 final StringBuffer result = new StringBuffer(bytes.length * 2) ; 429 for (int i = 0 ; i < bytes.length ; i++) { 430 final int b = (bytes[i] > 0) ? bytes[i] : bytes[i] + 256 ; 431 if (i == next) { 432 result.append("(") ; 433 } 434 result.append(Character.forDigit(b / 16, 16)) ; 435 result.append(Character.forDigit(b % 16, 16)) ; 436 if (i == next) { 437 result.append(")") ; 438 } 439 } 440 if (bytes.length == next) { 441 result.append("()") ; 442 } 443 444 return new String(result) ; 445 } 446 447 448 // 449 // Some standard tags 450 // 451 public final static int BooleanTag = 1 ; 452 public final static int IntegerTag = 2 ; 453 public final static int OctetStringTag = 4 ; 454 public final static int NullTag = 5 ; 455 public final static int OidTag = 6 ; 456 public final static int SequenceTag = 0x30 ; 457 458 459 460 461 ////////////////////////// PRIVATE /////////////////////////////// 462 463 464 465 /** 466 * Fetch a tag and move the current position forward. 467 * 468 * @return The tag 469 */ 470 471 private final int fetchTag() throws BerException { 472 int result = 0 ; 473 final int backup = next ; 474 475 try { 476 final byte b0 = bytes[next++] ; 477 result = (b0 >= 0) ? b0 : b0 + 256 ; 478 if ((result & 31) == 31) { 479 while ((bytes[next] & 128) != 0) { 480 result = result << 7 ; 481 result = result | (bytes[next++] & 127); 482 } 483 } 484 } 485 catch(IndexOutOfBoundsException e) { 486 next = backup ; 487 throw new BerException() ; 488 } 489 490 return result ; 491 } 492 493 494 /** 495 * Fetch a length and move the current position forward. 496 * 497 * @return The length 498 */ 499 500 private final int fetchLength() throws BerException { 501 int result = 0 ; 502 final int backup = next ; 503 504 try { 505 final byte b0 = bytes[next++] ; 506 if (b0 >= 0) { 507 result = b0 ; 508 } 509 else { 510 for (int c = 128 + b0 ; c > 0 ; c--) { 511 final byte bX = bytes[next++] ; 512 result = result << 8 ; 513 result = result | ((bX >= 0) ? bX : bX+256) ; 514 } 515 } 516 } 517 catch(IndexOutOfBoundsException e) { 518 next = backup ; 519 throw new BerException() ; 520 } 521 522 return result ; 523 } 524 525 526 /** 527 * Fetch an integer value and move the current position forward. 528 * 529 * @return The integer 530 */ 531 532 private int fetchIntegerValue() throws BerException { 533 int result = 0 ; 534 final int backup = next ; 535 536 try { 537 final int length = fetchLength() ; 538 if (length <= 0) throw new BerException() ; 539 if (length > (bytes.length - next)) throw 540 new IndexOutOfBoundsException("Decoded length exceeds buffer"); 541 final int end = next + length ; 542 result = bytes[next++] ; 543 while (next < end) { 544 final byte b = bytes[next++] ; 545 if (b < 0) { 546 result = (result << 8) | (256 + b) ; 547 } 548 else { 549 result = (result << 8) | b ; 550 } 551 } 552 } 553 catch(BerException e) { 554 next = backup ; 555 throw e ; 556 } 557 catch(IndexOutOfBoundsException e) { 558 next = backup ; 559 throw new BerException() ; 560 } 561 catch(ArithmeticException e) { 562 next = backup ; 563 throw new BerException() ; 564 } 565 return result ; 566 } 567 568 569 /** 570 * Fetch an integer value and return a long value. 571 * FIX ME: someday we could have only on fetchIntegerValue() which always 572 * returns a long value. 573 * 574 * @return The integer 575 */ 576 577 private final long fetchIntegerValueAsLong() throws BerException { 578 long result = 0 ; 579 final int backup = next ; 580 581 try { 582 final int length = fetchLength() ; 583 if (length <= 0) throw new BerException() ; 584 if (length > (bytes.length - next)) throw 585 new IndexOutOfBoundsException("Decoded length exceeds buffer"); 586 587 final int end = next + length ; 588 result = bytes[next++] ; 589 while (next < end) { 590 final byte b = bytes[next++] ; 591 if (b < 0) { 592 result = (result << 8) | (256 + b) ; 593 } 594 else { 595 result = (result << 8) | b ; 596 } 597 } 598 } 599 catch(BerException e) { 600 next = backup ; 601 throw e ; 602 } 603 catch(IndexOutOfBoundsException e) { 604 next = backup ; 605 throw new BerException() ; 606 } 607 catch(ArithmeticException e) { 608 next = backup ; 609 throw new BerException() ; 610 } 611 return result ; 612 } 613 614 615 /** 616 * Fetch a byte string and move the current position forward. 617 * 618 * @return The byte string 619 */ 620 621 private byte[] fetchStringValue() throws BerException { 622 byte[] result = null ; 623 final int backup = next ; 624 625 try { 626 final int length = fetchLength() ; 627 if (length < 0) throw new BerException() ; 628 if (length > (bytes.length - next)) 629 throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); 630 final byte data[] = new byte[length] ; 631 java.lang.System.arraycopy(bytes,next,data,0,length); 632 next += length; 633 // int i = 0 ; 634 // while (i < length) { 635 // result[i++] = bytes[next++] ; 636 // } 637 result = data; 638 } 639 catch(BerException e) { 640 next = backup ; 641 throw e ; 642 } 643 catch(IndexOutOfBoundsException e) { 644 next = backup ; 645 throw new BerException() ; 646 } 647 catch(ArithmeticException e) { 648 next = backup ; 649 throw new BerException() ; 650 } 651 // catch(Error e) { 652 // debug("fetchStringValue: Error decoding BER: " + e); 653 // throw e; 654 // } 655 656 return result ; 657 } 658 659 660 661 /** 662 * Fetch an oid and move the current position forward. 663 * 664 * @return The oid 665 */ 666 667 private final long[] fetchOidValue() throws BerException { 668 long[] result = null ; 669 final int backup = next ; 670 671 try { 672 final int length = fetchLength() ; 673 if (length <= 0) throw new BerException() ; 674 if (length > (bytes.length - next)) 675 throw new IndexOutOfBoundsException("Decoded length exceeds buffer"); 676 // Count how many bytes have their 8th bit to 0 677 // -> this gives the number of components in the oid 678 int subidCount = 2 ; 679 for (int i = 1 ; i < length ; i++) { 680 if ((bytes[next + i] & 0x80) == 0) { 681 subidCount++ ; 682 } 683 } 684 final int datalen = subidCount; 685 final long[] data = new long[datalen]; 686 final byte b0 = bytes[next++] ; 687 688 // bugId 4641746 689 // The 8th bit of the first byte should always be set to 0 690 if (b0 < 0) throw new BerException(); 691 692 // bugId 4641746 693 // The first sub Id cannot be greater than 2 694 final long lb0 = b0 / 40 ; 695 if (lb0 > 2) throw new BerException(); 696 697 final long lb1 = b0 % 40; 698 data[0] = lb0 ; 699 data[1] = lb1 ; 700 int i = 2 ; 701 while (i < datalen) { 702 long subid = 0 ; 703 byte b = bytes[next++] ; 704 while ((b & 0x80) != 0) { 705 subid = (subid << 7) | (b & 0x7f) ; 706 // bugId 4654674 707 if (subid < 0) throw new BerException(); 708 b = bytes[next++] ; 709 } 710 subid = (subid << 7) | b ; 711 // bugId 4654674 712 if (subid < 0) throw new BerException(); 713 data[i++] = subid ; 714 } 715 result = data; 716 } 717 catch(BerException e) { 718 next = backup ; 719 throw e ; 720 } 721 catch(IndexOutOfBoundsException e) { 722 next = backup ; 723 throw new BerException() ; 724 } 725 // catch(Error e) { 726 // debug("fetchOidValue: Error decoding BER: " + e); 727 // throw e; 728 // } 729 730 return result ; 731 } 732 733 // private static final void debug(String str) { 734 // System.out.println(str); 735 // } 736 737 // 738 // This is the byte array containing the encoding. 739 // 740 private final byte bytes[]; 741 742 // 743 // This is the current location. It is the next byte 744 // to be decoded. It's an index in bytes[]. 745 // 746 private int next = 0 ; 747 748 // 749 // This is the stack where end of sequences are kept. 750 // A value is computed and pushed in it each time openSequence() 751 // is invoked. 752 // A value is pulled and checked each time closeSequence() is called. 753 // 754 private final int stackBuf[] = new int[200] ; 755 private int stackTop = 0 ; 756 757 }