001/* 002 * Copyright 2007-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-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.util.ArrayList; 026import java.util.Collection; 027 028import com.unboundid.util.ByteStringBuffer; 029import com.unboundid.util.Debug; 030import com.unboundid.util.NotMutable; 031import com.unboundid.util.ThreadSafety; 032import com.unboundid.util.ThreadSafetyLevel; 033 034import static com.unboundid.asn1.ASN1Messages.*; 035 036 037 038/** 039 * This class provides an ASN.1 sequence element, which is used to hold an 040 * ordered set of zero or more other elements (potentially including additional 041 * "envelope" element types like other sequences and/or sets). 042 */ 043@NotMutable() 044@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 045public final class ASN1Sequence 046 extends ASN1Element 047{ 048 /** 049 * The serial version UID for this serializable class. 050 */ 051 private static final long serialVersionUID = 7294248008273774906L; 052 053 054 055 /* 056 * NOTE: This class uses lazy initialization for the encoded value. The 057 * encoded value should only be needed by the getValue() method, which is used 058 * by ASN1Element.encode(). Even though this class is externally immutable, 059 * that does not by itself make it completely threadsafe, because weirdness in 060 * the Java memory model could allow the assignment to be performed out of 061 * order. By passing the value through a volatile variable any time the value 062 * is set other than in the constructor (which will always be safe) we ensure 063 * that this reordering cannot happen. 064 * 065 * In the majority of cases, passing the value through assignments to 066 * valueBytes through a volatile variable is much faster than declaring 067 * valueBytes itself to be volatile because a volatile variable cannot be held 068 * in CPU caches or registers and must only be accessed from memory visible to 069 * all threads. Since the value may be read much more often than it is 070 * written, passing it through a volatile variable rather than making it 071 * volatile directly can help avoid that penalty when possible. 072 */ 073 074 075 076 // The set of ASN.1 elements contained in this sequence. 077 private final ASN1Element[] elements; 078 079 // The encoded representation of the value, if available. 080 private byte[] encodedValue; 081 082 // A volatile variable used to guard publishing the encodedValue array. See 083 // the note above to explain why this is needed. 084 private volatile byte[] encodedValueGuard; 085 086 087 088 /** 089 * Creates a new ASN.1 sequence with the default BER type and no encapsulated 090 * elements. 091 */ 092 public ASN1Sequence() 093 { 094 super(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE); 095 096 elements = ASN1Constants.NO_ELEMENTS; 097 encodedValue = ASN1Constants.NO_VALUE; 098 } 099 100 101 102 /** 103 * Creates a new ASN.1 sequence with the specified BER type and no 104 * encapsulated elements. 105 * 106 * @param type The BER type to use for this element. 107 */ 108 public ASN1Sequence(final byte type) 109 { 110 super(type); 111 112 elements = ASN1Constants.NO_ELEMENTS; 113 encodedValue = ASN1Constants.NO_VALUE; 114 } 115 116 117 118 /** 119 * Creates a new ASN.1 sequence with the default BER type and the provided set 120 * of elements. 121 * 122 * @param elements The set of elements to include in this sequence. 123 */ 124 public ASN1Sequence(final ASN1Element... elements) 125 { 126 super(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE); 127 128 if (elements == null) 129 { 130 this.elements = ASN1Constants.NO_ELEMENTS; 131 } 132 else 133 { 134 this.elements = elements; 135 } 136 137 encodedValue = null; 138 } 139 140 141 142 /** 143 * Creates a new ASN.1 sequence with the default BER type and the provided set 144 * of elements. 145 * 146 * @param elements The set of elements to include in this sequence. 147 */ 148 public ASN1Sequence(final Collection<? extends ASN1Element> elements) 149 { 150 super(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE); 151 152 if ((elements == null) || elements.isEmpty()) 153 { 154 this.elements = ASN1Constants.NO_ELEMENTS; 155 } 156 else 157 { 158 this.elements = new ASN1Element[elements.size()]; 159 elements.toArray(this.elements); 160 } 161 162 encodedValue = null; 163 } 164 165 166 167 /** 168 * Creates a new ASN.1 sequence with the specified BER type and the provided 169 * set of elements. 170 * 171 * @param type The BER type to use for this element. 172 * @param elements The set of elements to include in this sequence. 173 */ 174 public ASN1Sequence(final byte type, final ASN1Element... elements) 175 { 176 super(type); 177 178 if (elements == null) 179 { 180 this.elements = ASN1Constants.NO_ELEMENTS; 181 } 182 else 183 { 184 this.elements = elements; 185 } 186 187 encodedValue = null; 188 } 189 190 191 192 /** 193 * Creates a new ASN.1 sequence with the specified BER type and the provided 194 * set of elements. 195 * 196 * @param type The BER type to use for this element. 197 * @param elements The set of elements to include in this sequence. 198 */ 199 public ASN1Sequence(final byte type, 200 final Collection<? extends ASN1Element> elements) 201 { 202 super(type); 203 204 if ((elements == null) || elements.isEmpty()) 205 { 206 this.elements = ASN1Constants.NO_ELEMENTS; 207 } 208 else 209 { 210 this.elements = new ASN1Element[elements.size()]; 211 elements.toArray(this.elements); 212 } 213 214 encodedValue = null; 215 } 216 217 218 219 /** 220 * Creates a new ASN.1 sequence with the specified type, set of elements, and 221 * encoded value. 222 * 223 * @param type The BER type to use for this element. 224 * @param elements The set of elements to include in this sequence. 225 * @param value The pre-encoded value for this element. 226 */ 227 private ASN1Sequence(final byte type, final ASN1Element[] elements, 228 final byte[] value) 229 { 230 super(type); 231 232 this.elements = elements; 233 encodedValue = value; 234 } 235 236 237 238 /** 239 * {@inheritDoc} 240 */ 241 @Override() 242 byte[] getValueArray() 243 { 244 return getValue(); 245 } 246 247 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override() 253 int getValueOffset() 254 { 255 return 0; 256 } 257 258 259 260 /** 261 * {@inheritDoc} 262 */ 263 @Override() 264 public int getValueLength() 265 { 266 return getValue().length; 267 } 268 269 270 271 /** 272 * {@inheritDoc} 273 */ 274 @Override() 275 public byte[] getValue() 276 { 277 if (encodedValue == null) 278 { 279 encodedValueGuard = encodeElements(elements); 280 encodedValue = encodedValueGuard; 281 } 282 283 return encodedValue; 284 } 285 286 287 288 /** 289 * {@inheritDoc} 290 */ 291 @Override() 292 public void encodeTo(final ByteStringBuffer buffer) 293 { 294 buffer.append(getType()); 295 296 if (elements.length == 0) 297 { 298 buffer.append((byte) 0x00); 299 return; 300 } 301 302 // In this case, it will likely be faster to just go ahead and append 303 // encoded representations of all of the elements and insert the length 304 // later once we know it. 305 final int originalLength = buffer.length(); 306 for (final ASN1Element e : elements) 307 { 308 e.encodeTo(buffer); 309 } 310 311 buffer.insert(originalLength, 312 encodeLength(buffer.length() - originalLength)); 313 } 314 315 316 317 /** 318 * Encodes the provided set of elements to a byte array suitable for use as 319 * the element value. 320 * 321 * @param elements The set of elements to be encoded. 322 * 323 * @return A byte array containing the encoded elements. 324 */ 325 static byte[] encodeElements(final ASN1Element[] elements) 326 { 327 if ((elements == null) || (elements.length == 0)) 328 { 329 return ASN1Constants.NO_VALUE; 330 } 331 332 int totalLength = 0; 333 final int numElements = elements.length; 334 final byte[][] encodedElements = new byte[numElements][]; 335 for (int i=0; i < numElements; i++) 336 { 337 encodedElements[i] = elements[i].encode(); 338 totalLength += encodedElements[i].length; 339 } 340 341 int pos = 0; 342 final byte[] b = new byte[totalLength]; 343 for (int i=0; i < numElements; i++) 344 { 345 System.arraycopy(encodedElements[i], 0, b, pos, 346 encodedElements[i].length); 347 pos += encodedElements[i].length; 348 } 349 350 return b; 351 } 352 353 354 355 /** 356 * Retrieves the set of encapsulated elements held in this sequence. 357 * 358 * @return The set of encapsulated elements held in this sequence. 359 */ 360 public ASN1Element[] elements() 361 { 362 return elements; 363 } 364 365 366 367 /** 368 * Decodes the contents of the provided byte array as a sequence element. 369 * 370 * @param elementBytes The byte array to decode as an ASN.1 sequence 371 * element. 372 * 373 * @return The decoded ASN.1 sequence element. 374 * 375 * @throws ASN1Exception If the provided array cannot be decoded as a 376 * sequence element. 377 */ 378 public static ASN1Sequence decodeAsSequence(final byte[] elementBytes) 379 throws ASN1Exception 380 { 381 try 382 { 383 int valueStartPos = 2; 384 int length = (elementBytes[1] & 0x7F); 385 if (length != elementBytes[1]) 386 { 387 final int numLengthBytes = length; 388 389 length = 0; 390 for (int i=0; i < numLengthBytes; i++) 391 { 392 length <<= 8; 393 length |= (elementBytes[valueStartPos++] & 0xFF); 394 } 395 } 396 397 if ((elementBytes.length - valueStartPos) != length) 398 { 399 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 400 (elementBytes.length - valueStartPos))); 401 } 402 403 final byte[] value = new byte[length]; 404 System.arraycopy(elementBytes, valueStartPos, value, 0, length); 405 406 int numElements = 0; 407 final ArrayList<ASN1Element> elementList = new ArrayList<>(5); 408 try 409 { 410 int pos = 0; 411 while (pos < value.length) 412 { 413 final byte type = value[pos++]; 414 415 final byte firstLengthByte = value[pos++]; 416 int l = (firstLengthByte & 0x7F); 417 if (l != firstLengthByte) 418 { 419 final int numLengthBytes = l; 420 l = 0; 421 for (int i=0; i < numLengthBytes; i++) 422 { 423 l <<= 8; 424 l |= (value[pos++] & 0xFF); 425 } 426 } 427 428 final int posPlusLength = pos + l; 429 if ((l < 0) || (posPlusLength < 0) || (posPlusLength > value.length)) 430 { 431 throw new ASN1Exception( 432 ERR_SEQUENCE_BYTES_DECODE_LENGTH_EXCEEDS_AVAILABLE.get()); 433 } 434 435 elementList.add(new ASN1Element(type, value, pos, l)); 436 pos += l; 437 numElements++; 438 } 439 } 440 catch (final ASN1Exception ae) 441 { 442 throw ae; 443 } 444 catch (final Exception e) 445 { 446 Debug.debugException(e); 447 throw new ASN1Exception(ERR_SEQUENCE_BYTES_DECODE_EXCEPTION.get(e), e); 448 } 449 450 int i = 0; 451 final ASN1Element[] elements = new ASN1Element[numElements]; 452 for (final ASN1Element e : elementList) 453 { 454 elements[i++] = e; 455 } 456 457 return new ASN1Sequence(elementBytes[0], elements, value); 458 } 459 catch (final ASN1Exception ae) 460 { 461 Debug.debugException(ae); 462 throw ae; 463 } 464 catch (final Exception e) 465 { 466 Debug.debugException(e); 467 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 468 } 469 } 470 471 472 473 /** 474 * Decodes the provided ASN.1 element as a sequence element. 475 * 476 * @param element The ASN.1 element to be decoded. 477 * 478 * @return The decoded ASN.1 sequence element. 479 * 480 * @throws ASN1Exception If the provided element cannot be decoded as a 481 * sequence element. 482 */ 483 public static ASN1Sequence decodeAsSequence(final ASN1Element element) 484 throws ASN1Exception 485 { 486 int numElements = 0; 487 final ArrayList<ASN1Element> elementList = new ArrayList<>(5); 488 final byte[] value = element.getValue(); 489 490 try 491 { 492 int pos = 0; 493 while (pos < value.length) 494 { 495 final byte type = value[pos++]; 496 497 final byte firstLengthByte = value[pos++]; 498 int length = (firstLengthByte & 0x7F); 499 if (length != firstLengthByte) 500 { 501 final int numLengthBytes = length; 502 length = 0; 503 for (int i=0; i < numLengthBytes; i++) 504 { 505 length <<= 8; 506 length |= (value[pos++] & 0xFF); 507 } 508 } 509 510 final int posPlusLength = pos + length; 511 if ((length < 0) || (posPlusLength < 0) || 512 (posPlusLength > value.length)) 513 { 514 throw new ASN1Exception( 515 ERR_SEQUENCE_DECODE_LENGTH_EXCEEDS_AVAILABLE.get( 516 String.valueOf(element))); 517 } 518 519 elementList.add(new ASN1Element(type, value, pos, length)); 520 pos += length; 521 numElements++; 522 } 523 } 524 catch (final ASN1Exception ae) 525 { 526 throw ae; 527 } 528 catch (final Exception e) 529 { 530 Debug.debugException(e); 531 throw new ASN1Exception( 532 ERR_SEQUENCE_DECODE_EXCEPTION.get(String.valueOf(element), e), e); 533 } 534 535 int i = 0; 536 final ASN1Element[] elements = new ASN1Element[numElements]; 537 for (final ASN1Element e : elementList) 538 { 539 elements[i++] = e; 540 } 541 542 return new ASN1Sequence(element.getType(), elements, value); 543 } 544 545 546 547 /** 548 * {@inheritDoc} 549 */ 550 @Override() 551 public void toString(final StringBuilder buffer) 552 { 553 buffer.append('['); 554 for (int i=0; i < elements.length; i++) 555 { 556 if (i > 0) 557 { 558 buffer.append(','); 559 } 560 elements[i].toString(buffer); 561 } 562 buffer.append(']'); 563 } 564}