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