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