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