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