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