001/* 002 * Copyright 2009-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2014 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.asn1; 022 023 024 025import java.io.IOException; 026import java.io.OutputStream; 027import java.io.Serializable; 028import java.nio.ByteBuffer; 029import java.util.concurrent.atomic.AtomicBoolean; 030 031import com.unboundid.util.ByteStringBuffer; 032import com.unboundid.util.DebugType; 033import com.unboundid.util.Mutable; 034import com.unboundid.util.ThreadSafety; 035import com.unboundid.util.ThreadSafetyLevel; 036 037import static com.unboundid.util.Debug.*; 038 039 040 041/** 042 * This class provides a mechanism for writing one or more ASN.1 elements into a 043 * byte string buffer. It may be cleared and re-used any number of times, and 044 * the contents may be written to an {@code OutputStream} or {@code ByteBuffer}, 045 * or copied to a byte array. {@code ASN1Buffer} instances are not threadsafe 046 * and should not be accessed concurrently by multiple threads. 047 */ 048@Mutable() 049@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 050public final class ASN1Buffer 051 implements Serializable 052{ 053 /** 054 * The default maximum buffer size. 055 */ 056 private static final int DEFAULT_MAX_BUFFER_SIZE = 1048576; 057 058 059 060 /** 061 * An array that will be inserted when completing a sequence whose 062 * multi-byte length should be encoded with one byte for the header and one 063 * byte for the number of value bytes. 064 */ 065 private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_ONE = 066 { (byte) 0x81, (byte) 0x00 }; 067 068 069 070 /** 071 * An array that will be inserted when completing a sequence whose 072 * multi-byte length should be encoded with one byte for the header and two 073 * bytes for the number of value bytes. 074 */ 075 private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_TWO = 076 { (byte) 0x82, (byte) 0x00, (byte) 0x00 }; 077 078 079 080 /** 081 * An array that will be inserted when completing a sequence whose 082 * multi-byte length should be encoded with one byte for the header and three 083 * bytes for the number of value bytes. 084 */ 085 private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_THREE = 086 { (byte) 0x83, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; 087 088 089 090 /** 091 * An array that will be inserted when completing a sequence whose 092 * multi-byte length should be encoded with one byte for the header and four 093 * bytes for the number of value bytes. 094 */ 095 private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_FOUR = 096 { (byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; 097 098 099 100 /** 101 * The serial version UID for this serializable class. 102 */ 103 private static final long serialVersionUID = -4898230771376551562L; 104 105 106 107 // Indicates whether to zero out the contents of the buffer the next time it 108 // is cleared in order to wipe out any sensitive data it may contain. 109 private final AtomicBoolean zeroBufferOnClear; 110 111 // The buffer to which all data will be written. 112 private final ByteStringBuffer buffer; 113 114 // The maximum buffer size that should be retained. 115 private final int maxBufferSize; 116 117 118 119 /** 120 * Creates a new instance of this ASN.1 buffer. 121 */ 122 public ASN1Buffer() 123 { 124 this(DEFAULT_MAX_BUFFER_SIZE); 125 } 126 127 128 129 /** 130 * Creates a new instance of this ASN.1 buffer with an optional maximum 131 * retained size. If a maximum size is defined, then this buffer may be used 132 * to hold elements larger than that, but when the buffer is cleared it will 133 * be shrunk to the maximum size. 134 * 135 * @param maxBufferSize The maximum buffer size that will be retained by 136 * this ASN.1 buffer. A value less than or equal to 137 * zero indicates that no maximum size should be 138 * enforced. 139 */ 140 public ASN1Buffer(final int maxBufferSize) 141 { 142 this.maxBufferSize = maxBufferSize; 143 144 buffer = new ByteStringBuffer(); 145 zeroBufferOnClear = new AtomicBoolean(false); 146 } 147 148 149 150 /** 151 * Indicates whether the content of the buffer should be zeroed out the next 152 * time it is cleared in order to wipe any sensitive information it may 153 * contain. 154 * 155 * @return {@code true} if the content of the buffer should be zeroed out the 156 * next time it is cleared, or {@code false} if not. 157 */ 158 public boolean zeroBufferOnClear() 159 { 160 return zeroBufferOnClear.get(); 161 } 162 163 164 165 /** 166 * Specifies that the content of the buffer should be zeroed out the next time 167 * it is cleared in order to wipe any sensitive information it may contain. 168 */ 169 public void setZeroBufferOnClear() 170 { 171 zeroBufferOnClear.set(true); 172 } 173 174 175 176 /** 177 * Clears the contents of this buffer. If there are any outstanding sequences 178 * or sets that have been created but not closed, then they must no longer be 179 * used and any attempt to do so may yield unpredictable results. 180 */ 181 public void clear() 182 { 183 buffer.clear(zeroBufferOnClear.getAndSet(false)); 184 185 if ((maxBufferSize > 0) && (buffer.capacity() > maxBufferSize)) 186 { 187 buffer.setCapacity(maxBufferSize); 188 } 189 } 190 191 192 193 /** 194 * Retrieves the current length of this buffer in bytes. 195 * 196 * @return The current length of this buffer in bytes. 197 */ 198 public int length() 199 { 200 return buffer.length(); 201 } 202 203 204 205 /** 206 * Adds the provided ASN.1 element to this ASN.1 buffer. 207 * 208 * @param element The element to be added. It must not be {@code null}. 209 */ 210 public void addElement(final ASN1Element element) 211 { 212 element.encodeTo(buffer); 213 } 214 215 216 217 /** 218 * Adds a Boolean element to this ASN.1 buffer using the default BER type. 219 * 220 * @param booleanValue The value to use for the Boolean element. 221 */ 222 public void addBoolean(final boolean booleanValue) 223 { 224 addBoolean(ASN1Constants.UNIVERSAL_BOOLEAN_TYPE, booleanValue); 225 } 226 227 228 229 /** 230 * Adds a Boolean element to this ASN.1 buffer using the provided BER type. 231 * 232 * @param type The BER type to use for the Boolean element. 233 * @param booleanValue The value to use for the Boolean element. 234 */ 235 public void addBoolean(final byte type, final boolean booleanValue) 236 { 237 buffer.append(type); 238 buffer.append((byte) 0x01); 239 240 if (booleanValue) 241 { 242 buffer.append((byte) 0xFF); 243 } 244 else 245 { 246 buffer.append((byte) 0x00); 247 } 248 } 249 250 251 252 /** 253 * Adds an enumerated element to this ASN.1 buffer using the default BER type. 254 * 255 * @param intValue The value to use for the enumerated element. 256 */ 257 public void addEnumerated(final int intValue) 258 { 259 addInteger(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE, intValue); 260 } 261 262 263 264 /** 265 * Adds an enumerated element to this ASN.1 buffer using the provided BER 266 * type. 267 * 268 * @param type The BER type to use for the enumerated element. 269 * @param intValue The value to use for the enumerated element. 270 */ 271 public void addEnumerated(final byte type, final int intValue) 272 { 273 addInteger(type, intValue); 274 } 275 276 277 278 /** 279 * Adds an integer element to this ASN.1 buffer using the default BER type. 280 * 281 * @param intValue The value to use for the integer element. 282 */ 283 public void addInteger(final int intValue) 284 { 285 addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, intValue); 286 } 287 288 289 290 /** 291 * Adds an integer element to this ASN.1 buffer using the provided BER type. 292 * 293 * @param type The BER type to use for the integer element. 294 * @param intValue The value to use for the integer element. 295 */ 296 public void addInteger(final byte type, final int intValue) 297 { 298 buffer.append(type); 299 300 if (intValue < 0) 301 { 302 if ((intValue & 0xFFFFFF80) == 0xFFFFFF80) 303 { 304 buffer.append((byte) 0x01); 305 buffer.append((byte) (intValue & 0xFF)); 306 } 307 else if ((intValue & 0xFFFF8000) == 0xFFFF8000) 308 { 309 buffer.append((byte) 0x02); 310 buffer.append((byte) ((intValue >> 8) & 0xFF)); 311 buffer.append((byte) (intValue & 0xFF)); 312 } 313 else if ((intValue & 0xFF800000) == 0xFF800000) 314 { 315 buffer.append((byte) 0x03); 316 buffer.append((byte) ((intValue >> 16) & 0xFF)); 317 buffer.append((byte) ((intValue >> 8) & 0xFF)); 318 buffer.append((byte) (intValue & 0xFF)); 319 } 320 else 321 { 322 buffer.append((byte) 0x04); 323 buffer.append((byte) ((intValue >> 24) & 0xFF)); 324 buffer.append((byte) ((intValue >> 16) & 0xFF)); 325 buffer.append((byte) ((intValue >> 8) & 0xFF)); 326 buffer.append((byte) (intValue & 0xFF)); 327 } 328 } 329 else 330 { 331 if ((intValue & 0x0000007F) == intValue) 332 { 333 buffer.append((byte) 0x01); 334 buffer.append((byte) (intValue & 0x7F)); 335 } 336 else if ((intValue & 0x00007FFF) == intValue) 337 { 338 buffer.append((byte) 0x02); 339 buffer.append((byte) ((intValue >> 8) & 0x7F)); 340 buffer.append((byte) (intValue & 0xFF)); 341 } 342 else if ((intValue & 0x007FFFFF) == intValue) 343 { 344 buffer.append((byte) 0x03); 345 buffer.append((byte) ((intValue >> 16) & 0x7F)); 346 buffer.append((byte) ((intValue >> 8) & 0xFF)); 347 buffer.append((byte) (intValue & 0xFF)); 348 } 349 else 350 { 351 buffer.append((byte) 0x04); 352 buffer.append((byte) ((intValue >> 24) & 0x7F)); 353 buffer.append((byte) ((intValue >> 16) & 0xFF)); 354 buffer.append((byte) ((intValue >> 8) & 0xFF)); 355 buffer.append((byte) (intValue & 0xFF)); 356 } 357 } 358 } 359 360 361 362 /** 363 * Adds an integer element to this ASN.1 buffer using the default BER type. 364 * 365 * @param longValue The value to use for the integer element. 366 */ 367 public void addInteger(final long longValue) 368 { 369 addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, longValue); 370 } 371 372 373 374 /** 375 * Adds an integer element to this ASN.1 buffer using the provided BER type. 376 * 377 * @param type The BER type to use for the integer element. 378 * @param longValue The value to use for the integer element. 379 */ 380 public void addInteger(final byte type, final long longValue) 381 { 382 buffer.append(type); 383 384 if (longValue < 0) 385 { 386 if ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L) 387 { 388 buffer.append((byte) 0x01); 389 buffer.append((byte) (longValue & 0xFFL)); 390 } 391 else if ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L) 392 { 393 buffer.append((byte) 0x02); 394 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 395 buffer.append((byte) (longValue & 0xFFL)); 396 } 397 else if ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L) 398 { 399 buffer.append((byte) 0x03); 400 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 401 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 402 buffer.append((byte) (longValue & 0xFFL)); 403 } 404 else if ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L) 405 { 406 buffer.append((byte) 0x04); 407 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 408 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 409 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 410 buffer.append((byte) (longValue & 0xFFL)); 411 } 412 else if ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L) 413 { 414 buffer.append((byte) 0x05); 415 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 416 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 417 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 418 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 419 buffer.append((byte) (longValue & 0xFFL)); 420 } 421 else if ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L) 422 { 423 buffer.append((byte) 0x06); 424 buffer.append((byte) ((longValue >> 40) & 0xFFL)); 425 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 426 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 427 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 428 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 429 buffer.append((byte) (longValue & 0xFFL)); 430 } 431 else if ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L) 432 { 433 buffer.append((byte) 0x07); 434 buffer.append((byte) ((longValue >> 48) & 0xFFL)); 435 buffer.append((byte) ((longValue >> 40) & 0xFFL)); 436 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 437 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 438 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 439 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 440 buffer.append((byte) (longValue & 0xFFL)); 441 } 442 else 443 { 444 buffer.append((byte) 0x08); 445 buffer.append((byte) ((longValue >> 56) & 0xFFL)); 446 buffer.append((byte) ((longValue >> 48) & 0xFFL)); 447 buffer.append((byte) ((longValue >> 40) & 0xFFL)); 448 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 449 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 450 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 451 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 452 buffer.append((byte) (longValue & 0xFFL)); 453 } 454 } 455 else 456 { 457 if ((longValue & 0x000000000000007FL) == longValue) 458 { 459 buffer.append((byte) 0x01); 460 buffer.append((byte) (longValue & 0x7FL)); 461 } 462 else if ((longValue & 0x0000000000007FFFL) == longValue) 463 { 464 buffer.append((byte) 0x02); 465 buffer.append((byte) ((longValue >> 8) & 0x7FL)); 466 buffer.append((byte) (longValue & 0xFFL)); 467 } 468 else if ((longValue & 0x00000000007FFFFFL) == longValue) 469 { 470 buffer.append((byte) 0x03); 471 buffer.append((byte) ((longValue >> 16) & 0x7FL)); 472 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 473 buffer.append((byte) (longValue & 0xFFL)); 474 } 475 else if ((longValue & 0x000000007FFFFFFFL) == longValue) 476 { 477 buffer.append((byte) 0x04); 478 buffer.append((byte) ((longValue >> 24) & 0x7FL)); 479 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 480 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 481 buffer.append((byte) (longValue & 0xFFL)); 482 } 483 else if ((longValue & 0x0000007FFFFFFFFFL) == longValue) 484 { 485 buffer.append((byte) 0x05); 486 buffer.append((byte) ((longValue >> 32) & 0x7FL)); 487 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 488 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 489 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 490 buffer.append((byte) (longValue & 0xFFL)); 491 } 492 else if ((longValue & 0x00007FFFFFFFFFFFL) == longValue) 493 { 494 buffer.append((byte) 0x06); 495 buffer.append((byte) ((longValue >> 40) & 0x7FL)); 496 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 497 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 498 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 499 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 500 buffer.append((byte) (longValue & 0xFFL)); 501 } 502 else if ((longValue & 0x007FFFFFFFFFFFFFL) == longValue) 503 { 504 buffer.append((byte) 0x07); 505 buffer.append((byte) ((longValue >> 48) & 0x7FL)); 506 buffer.append((byte) ((longValue >> 40) & 0xFFL)); 507 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 508 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 509 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 510 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 511 buffer.append((byte) (longValue & 0xFFL)); 512 } 513 else 514 { 515 buffer.append((byte) 0x08); 516 buffer.append((byte) ((longValue >> 56) & 0x7FL)); 517 buffer.append((byte) ((longValue >> 48) & 0xFFL)); 518 buffer.append((byte) ((longValue >> 40) & 0xFFL)); 519 buffer.append((byte) ((longValue >> 32) & 0xFFL)); 520 buffer.append((byte) ((longValue >> 24) & 0xFFL)); 521 buffer.append((byte) ((longValue >> 16) & 0xFFL)); 522 buffer.append((byte) ((longValue >> 8) & 0xFFL)); 523 buffer.append((byte) (longValue & 0xFFL)); 524 } 525 } 526 } 527 528 529 530 /** 531 * Adds a null element to this ASN.1 buffer using the default BER type. 532 */ 533 public void addNull() 534 { 535 addNull(ASN1Constants.UNIVERSAL_NULL_TYPE); 536 } 537 538 539 540 /** 541 * Adds a null element to this ASN.1 buffer using the provided BER type. 542 * 543 * @param type The BER type to use for the null element. 544 */ 545 public void addNull(final byte type) 546 { 547 buffer.append(type); 548 buffer.append((byte) 0x00); 549 } 550 551 552 553 /** 554 * Adds an octet string element to this ASN.1 buffer using the default BER 555 * type and no value. 556 */ 557 public void addOctetString() 558 { 559 addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE); 560 } 561 562 563 564 /** 565 * Adds an octet string element to this ASN.1 buffer using the provided BER 566 * type and no value. 567 * 568 * @param type The BER type to use for the octet string element. 569 */ 570 public void addOctetString(final byte type) 571 { 572 buffer.append(type); 573 buffer.append((byte) 0x00); 574 } 575 576 577 578 /** 579 * Adds an octet string element to this ASN.1 buffer using the default BER 580 * type. 581 * 582 * @param value The value to use for the octet string element. 583 */ 584 public void addOctetString(final byte[] value) 585 { 586 addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value); 587 } 588 589 590 591 /** 592 * Adds an octet string element to this ASN.1 buffer using the default BER 593 * type. 594 * 595 * @param value The value to use for the octet string element. 596 */ 597 public void addOctetString(final CharSequence value) 598 { 599 if (value == null) 600 { 601 addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE); 602 } 603 else 604 { 605 addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, 606 value.toString()); 607 } 608 } 609 610 611 612 /** 613 * Adds an octet string element to this ASN.1 buffer using the default BER 614 * type. 615 * 616 * @param value The value to use for the octet string element. 617 */ 618 public void addOctetString(final String value) 619 { 620 addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value); 621 } 622 623 624 625 /** 626 * Adds an octet string element to this ASN.1 buffer using the provided BER 627 * type. 628 * 629 * @param type The BER type to use for the octet string element. 630 * @param value The value to use for the octet string element. 631 */ 632 public void addOctetString(final byte type, final byte[] value) 633 { 634 buffer.append(type); 635 636 if (value == null) 637 { 638 buffer.append((byte) 0x00); 639 } 640 else 641 { 642 ASN1Element.encodeLengthTo(value.length, buffer); 643 buffer.append(value); 644 } 645 } 646 647 648 649 /** 650 * Adds an octet string element to this ASN.1 buffer using the provided BER 651 * type. 652 * 653 * @param type The BER type to use for the octet string element. 654 * @param value The value to use for the octet string element. 655 */ 656 public void addOctetString(final byte type, final CharSequence value) 657 { 658 if (value == null) 659 { 660 addOctetString(type); 661 } 662 else 663 { 664 addOctetString(type, value.toString()); 665 } 666 } 667 668 669 670 /** 671 * Adds an octet string element to this ASN.1 buffer using the provided BER 672 * type. 673 * 674 * @param type The BER type to use for the octet string element. 675 * @param value The value to use for the octet string element. 676 */ 677 public void addOctetString(final byte type, final String value) 678 { 679 buffer.append(type); 680 681 if (value == null) 682 { 683 buffer.append((byte) 0x00); 684 } 685 else 686 { 687 // We'll assume that the string contains only ASCII characters and 688 // therefore the number of bytes will equal the number of characters. 689 // However, save the position in case we're wrong and need to re-encode. 690 final int lengthStartPos = buffer.length(); 691 ASN1Element.encodeLengthTo(value.length(), buffer); 692 693 final int valueStartPos = buffer.length(); 694 buffer.append(value); 695 696 if (buffer.length() != (valueStartPos + value.length())) 697 { 698 final byte[] valueBytes = new byte[buffer.length() - valueStartPos]; 699 System.arraycopy(buffer.getBackingArray(), valueStartPos, valueBytes, 0, 700 valueBytes.length); 701 702 buffer.setLength(lengthStartPos); 703 ASN1Element.encodeLengthTo(valueBytes.length, buffer); 704 buffer.append(valueBytes); 705 } 706 } 707 } 708 709 710 711 /** 712 * Begins adding elements to an ASN.1 sequence using the default BER type. 713 * 714 * @return An object that may be used to indicate when the end of the 715 * sequence has been reached. Once all embedded sequence elements 716 * have been added, then the {@link ASN1BufferSequence#end} method 717 * MUST be called to ensure that the sequence is properly encoded. 718 */ 719 public ASN1BufferSequence beginSequence() 720 { 721 return beginSequence(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE); 722 } 723 724 725 726 /** 727 * Begins adding elements to an ASN.1 sequence using the provided BER type. 728 * 729 * @param type The BER type to use for the sequence. 730 * 731 * @return An object that may be used to indicate when the end of the 732 * sequence has been reached. Once all embedded sequence elements 733 * have been added, then the {@link ASN1BufferSequence#end} method 734 * MUST be called to ensure that the sequence is properly encoded. 735 */ 736 public ASN1BufferSequence beginSequence(final byte type) 737 { 738 buffer.append(type); 739 return new ASN1BufferSequence(this); 740 } 741 742 743 744 /** 745 * Begins adding elements to an ASN.1 set using the default BER type. 746 * 747 * @return An object that may be used to indicate when the end of the set has 748 * been reached. Once all embedded set elements have been added, 749 * then the {@link ASN1BufferSet#end} method MUST be called to ensure 750 * that the set is properly encoded. 751 */ 752 public ASN1BufferSet beginSet() 753 { 754 return beginSet(ASN1Constants.UNIVERSAL_SET_TYPE); 755 } 756 757 758 759 /** 760 * Begins adding elements to an ASN.1 set using the provided BER type. 761 * 762 * @param type The BER type to use for the set. 763 * 764 * @return An object that may be used to indicate when the end of the set has 765 * been reached. Once all embedded set elements have been added, 766 * then the {@link ASN1BufferSet#end} method MUST be called to ensure 767 * that the set is properly encoded. 768 */ 769 public ASN1BufferSet beginSet(final byte type) 770 { 771 buffer.append(type); 772 return new ASN1BufferSet(this); 773 } 774 775 776 777 /** 778 * Ensures that the appropriate length is inserted into the internal buffer 779 * after all elements in a sequence or set have been added. 780 * 781 * @param valueStartPos The position in which the first value was added. 782 */ 783 void endSequenceOrSet(final int valueStartPos) 784 { 785 final int length = buffer.length() - valueStartPos; 786 if (length == 0) 787 { 788 buffer.append((byte) 0x00); 789 return; 790 } 791 792 if ((length & 0x7F) == length) 793 { 794 buffer.insert(valueStartPos, (byte) length); 795 } 796 else if ((length & 0xFF) == length) 797 { 798 buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_ONE); 799 800 final byte[] backingArray = buffer.getBackingArray(); 801 backingArray[valueStartPos+1] = (byte) (length & 0xFF); 802 } 803 else if ((length & 0xFFFF) == length) 804 { 805 buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_TWO); 806 807 final byte[] backingArray = buffer.getBackingArray(); 808 backingArray[valueStartPos+1] = (byte) ((length >> 8) & 0xFF); 809 backingArray[valueStartPos+2] = (byte) (length & 0xFF); 810 } 811 else if ((length & 0xFFFFFF) == length) 812 { 813 buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_THREE); 814 815 final byte[] backingArray = buffer.getBackingArray(); 816 backingArray[valueStartPos+1] = (byte) ((length >> 16) & 0xFF); 817 backingArray[valueStartPos+2] = (byte) ((length >> 8) & 0xFF); 818 backingArray[valueStartPos+3] = (byte) (length & 0xFF); 819 } 820 else 821 { 822 buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_FOUR); 823 824 final byte[] backingArray = buffer.getBackingArray(); 825 backingArray[valueStartPos+1] = (byte) ((length >> 24) & 0xFF); 826 backingArray[valueStartPos+2] = (byte) ((length >> 16) & 0xFF); 827 backingArray[valueStartPos+3] = (byte) ((length >> 8) & 0xFF); 828 backingArray[valueStartPos+4] = (byte) (length & 0xFF); 829 } 830 } 831 832 833 834 /** 835 * Writes the contents of this buffer to the provided output stream. 836 * 837 * @param outputStream The output stream to which the data should be 838 * written. 839 * 840 * @throws IOException If a problem occurs while writing to the provided 841 * output stream. 842 */ 843 public void writeTo(final OutputStream outputStream) 844 throws IOException 845 { 846 if (debugEnabled(DebugType.ASN1)) 847 { 848 debugASN1Write(this); 849 } 850 851 buffer.write(outputStream); 852 } 853 854 855 856 /** 857 * Retrieves a byte array containing the contents of this ASN.1 buffer. 858 * 859 * @return A byte array containing the contents of this ASN.1 buffer. 860 */ 861 public byte[] toByteArray() 862 { 863 return buffer.toByteArray(); 864 } 865 866 867 868 /** 869 * Retrieves a byte buffer that wraps the data associated with this ASN.1 870 * buffer. The position will be set to the beginning of the data, and the 871 * limit will be set to one byte after the end of the data. The contents 872 * of the returned byte buffer must not be altered in any way, and the 873 * contents of this ASN.1 buffer must not be altered until the 874 * {@code ByteBuffer} is no longer needed. 875 * 876 * @return A byte buffer that wraps the data associated with this ASN.1 877 * buffer. 878 */ 879 public ByteBuffer asByteBuffer() 880 { 881 return ByteBuffer.wrap(buffer.getBackingArray(), 0, buffer.length()); 882 } 883}