001/* 002 * Copyright 2017-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2017-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) 2017-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 com.unboundid.util.Debug; 041import com.unboundid.util.NotMutable; 042import com.unboundid.util.NotNull; 043import com.unboundid.util.Nullable; 044import com.unboundid.util.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046 047import static com.unboundid.asn1.ASN1Messages.*; 048 049 050 051/** 052 * This class provides an ASN.1 bit string element, whose value represents a 053 * series of zero or more bits, where each bit is either one or zero. 054 */ 055@NotMutable() 056@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 057public final class ASN1BitString 058 extends ASN1Element 059{ 060 /** 061 * The serial version UID for this serializable class. 062 */ 063 private static final long serialVersionUID = -5962171503831966571L; 064 065 066 067 // An array of the bits in this bit string, where true is 1 and false is 0. 068 @NotNull private final boolean[] bits; 069 070 // The bytes represented by the bits that comprise this bit string. 071 @Nullable private final byte[] bytes; 072 073 074 075 /** 076 * Creates a new ASN.1 bit string element with the default BER type and the 077 * provided set of bits. 078 * 079 * @param bits The bits to include in the bit string. Each {@code boolean} 080 * value of {@code true} represents a bit of one, and each 081 * {@code boolean} value of {@code false} represents a bit of 082 * zero. It must not be {@code null} but may be empty. 083 */ 084 public ASN1BitString(@NotNull final boolean... bits) 085 { 086 this(ASN1Constants.UNIVERSAL_BIT_STRING_TYPE, bits); 087 } 088 089 090 091 /** 092 * Creates a new ASN.1 bit string element with the specified BER type and the 093 * provided set of bits. 094 * 095 * @param type The BER type to use for this element. 096 * @param bits The bits to include in the bit string. Each {@code boolean} 097 * value of {@code true} represents a bit of one, and each 098 * {@code boolean} value of {@code false} represents a bit of 099 * zero. It must not be {@code null} but may be empty. 100 */ 101 public ASN1BitString(final byte type, @NotNull final boolean... bits) 102 { 103 this(type, bits, null, encodeValue(bits)); 104 } 105 106 107 108 /** 109 * Creates a new ASN.1 bit string element with the provided information. 110 * 111 * @param type The BER type to use for this element. 112 * @param bits The bits to include in the bit string. Each 113 * {@code boolean} value of {@code true} represents a 114 * bit of one, and each {@code boolean} value of 115 * {@code false} represents a bit of zero. It must not 116 * be {@code null} but may be empty. 117 * @param bytes The bytes represented by the bits that comprise this 118 * bit string. This may be {@code null} if it has not 119 * yet been determined, or if the number of bits is not 120 * an even multiple of eight. 121 * @param encodedValue The encoded value for this element. 122 */ 123 private ASN1BitString(final byte type, @NotNull final boolean[] bits, 124 @Nullable final byte[] bytes, 125 @NotNull final byte[] encodedValue) 126 { 127 super(type, encodedValue); 128 129 this.bits = bits; 130 131 if (bytes == null) 132 { 133 if ((bits.length % 8) == 0) 134 { 135 this.bytes = new byte[bits.length / 8]; 136 137 byte currentByte = 0x00; 138 int byteIndex = 0; 139 for (int i=0; i < bits.length; i++) 140 { 141 currentByte <<= 1; 142 if (bits[i]) 143 { 144 currentByte |= 0x01; 145 } 146 147 if (((i + 1) % 8) == 0) 148 { 149 this.bytes[byteIndex++] = currentByte; 150 currentByte = 0x00; 151 } 152 } 153 } 154 else 155 { 156 this.bytes = null; 157 } 158 } 159 else 160 { 161 this.bytes = bytes; 162 } 163 } 164 165 166 167 /** 168 * Creates a new ASN.1 bit string with the default BER type and a value 169 * created from the provided string representation. 170 * 171 * @param stringRepresentation A string representation of the bit string to 172 * create. It must not be {@code null}, but may 173 * be empty. It must be comprised only of the 174 * characters '1' and '0'. 175 * 176 * @throws ASN1Exception If the provided string does not represent a valid 177 * bit string value. 178 */ 179 public ASN1BitString(@NotNull final String stringRepresentation) 180 throws ASN1Exception 181 { 182 this(ASN1Constants.UNIVERSAL_BIT_STRING_TYPE, stringRepresentation); 183 } 184 185 186 187 /** 188 * Creates a new ASN.1 bit string with the default BER type and a value 189 * created from the provided string representation. 190 * 191 * @param type The BER type to use for this element. 192 * @param stringRepresentation A string representation of the bit string to 193 * create. It must not be {@code null}, but may 194 * be empty. It must be comprised only of the 195 * characters '1' and '0'. 196 * 197 * @throws ASN1Exception If the provided string does not represent a valid 198 * bit string value. 199 */ 200 public ASN1BitString(final byte type, 201 @NotNull final String stringRepresentation) 202 throws ASN1Exception 203 { 204 this(type, getBits(stringRepresentation)); 205 } 206 207 208 209 /** 210 * Decodes the provided string representation of a bit string into an array of 211 * bits. 212 * 213 * @param s A string representation of the bit string to create. It must 214 * not be {@code null}, but may be empty. It must be comprised 215 * only of the characters '1' and '0'. 216 * 217 * @return An array of {@code boolean} values that correspond to the bits in 218 * this bit string. 219 * 220 * @throws ASN1Exception If the provided string does not represent a valid 221 * bit string value. 222 */ 223 @NotNull() 224 private static boolean[] getBits(@NotNull final String s) 225 throws ASN1Exception 226 { 227 final char[] chars = s.toCharArray(); 228 final boolean[] bits = new boolean[chars.length]; 229 for (int i=0; i < chars.length; i++) 230 { 231 if (chars[i] == '0') 232 { 233 bits[i] = false; 234 } 235 else if (chars[i] == '1') 236 { 237 bits[i] = true; 238 } 239 else 240 { 241 throw new ASN1Exception( 242 ERR_BIT_STRING_DECODE_STRING_INVALID_CHAR.get()); 243 } 244 } 245 246 return bits; 247 } 248 249 250 251 /** 252 * Generates an encoded value for a bit string with the specified set of 253 * bits. 254 * 255 * @param bits The bits to include in the bit string. Each {@code boolean} 256 * value of {@code true} represents a bit of one, and each 257 * {@code boolean} value of {@code false} represents a bit of 258 * zero. It must not be {@code null} but may be empty. 259 * 260 * @return The encoded value. 261 */ 262 @NotNull() 263 private static byte[] encodeValue(@NotNull final boolean... bits) 264 { 265 // A bit string value always has at least one byte, and that byte specifies 266 // the number of padding bits needed in the last byte. The remaining bytes 267 // are used to hold the bits, with eight bits per byte. If the number of 268 // bits provided is not a multiple of eight, then it will be assumed that 269 // there are enough extra bits of zero to make an even last byte. 270 final byte[] encodedValue; 271 final int paddingBitsNeeded; 272 final int numBitsMod8 = (bits.length % 8); 273 if (numBitsMod8 == 0) 274 { 275 paddingBitsNeeded = 0; 276 encodedValue = new byte[(bits.length / 8) + 1]; 277 } 278 else 279 { 280 paddingBitsNeeded = 8 - numBitsMod8; 281 encodedValue = new byte[(bits.length / 8) + 2]; 282 } 283 284 encodedValue[0] = (byte) paddingBitsNeeded; 285 286 byte currentByte = 0x00; 287 int bitIndex = 0; 288 int encodedValueIndex = 1; 289 for (final boolean bit : bits) 290 { 291 currentByte <<= 1; 292 if (bit) 293 { 294 currentByte |= 0x01; 295 } 296 297 bitIndex++; 298 if ((bitIndex % 8) == 0) 299 { 300 encodedValue[encodedValueIndex] = currentByte; 301 currentByte = 0x00; 302 encodedValueIndex++; 303 } 304 } 305 306 if (paddingBitsNeeded > 0) 307 { 308 currentByte <<= paddingBitsNeeded; 309 encodedValue[encodedValueIndex] = currentByte; 310 } 311 312 return encodedValue; 313 } 314 315 316 317 /** 318 * Retrieves an array of {@code boolean} values that correspond to the bits in 319 * this bit string. Each {@code boolean} value of {@code true} represents a 320 * bit of one, and each {@code boolean} value of {@code false} represents a 321 * bit of zero. 322 * 323 * @return An array of {@code boolean} values that correspond to the bits in 324 * this bit string. 325 */ 326 @NotNull() 327 public boolean[] getBits() 328 { 329 return bits; 330 } 331 332 333 334 /** 335 * Retrieves the bytes represented by the bits that comprise this bit string, 336 * if the number of bits is a multiple of eight. 337 * 338 * @return The bytes represented by the bits that comprise this bit string. 339 * 340 * @throws ASN1Exception If the number of bits in this bit string is not a 341 * multiple of eight. 342 */ 343 @NotNull() 344 public byte[] getBytes() 345 throws ASN1Exception 346 { 347 if (bytes == null) 348 { 349 throw new ASN1Exception( 350 ERR_BIT_STRING_GET_BYTES_NOT_MULTIPLE_OF_EIGHT_BITS.get( 351 bits.length)); 352 } 353 else 354 { 355 return bytes; 356 } 357 } 358 359 360 361 /** 362 * Retrieves an array of booleans that represent the bits in the provided 363 * array of bytes. 364 * 365 * @param bytes The bytes for which to retrieve the corresponding bits. It 366 * must not be {@code null}. 367 * 368 * @return An array of the bits that make up the provided bytes. 369 */ 370 @NotNull() 371 public static boolean[] getBitsForBytes(@NotNull final byte... bytes) 372 { 373 final boolean[] bits = new boolean[bytes.length * 8]; 374 for (int i=0; i < bytes.length; i++) 375 { 376 final byte b = bytes[i]; 377 bits[i * 8] = ((b & 0x80) == 0x80); 378 bits[(i * 8) + 1] = ((b & 0x40) == 0x40); 379 bits[(i * 8) + 2] = ((b & 0x20) == 0x20); 380 bits[(i * 8) + 3] = ((b & 0x10) == 0x10); 381 bits[(i * 8) + 4] = ((b & 0x08) == 0x08); 382 bits[(i * 8) + 5] = ((b & 0x04) == 0x04); 383 bits[(i * 8) + 6] = ((b & 0x02) == 0x02); 384 bits[(i * 8) + 7] = ((b & 0x01) == 0x01); 385 } 386 387 return bits; 388 } 389 390 391 392 /** 393 * Decodes the contents of the provided byte array as a bit string element. 394 * 395 * @param elementBytes The byte array to decode as an ASN.1 bit string 396 * element. 397 * 398 * @return The decoded ASN.1 bit string element. 399 * 400 * @throws ASN1Exception If the provided array cannot be decoded as a bit 401 * string element. 402 */ 403 @NotNull() 404 public static ASN1BitString decodeAsBitString( 405 @NotNull final byte[] elementBytes) 406 throws ASN1Exception 407 { 408 try 409 { 410 int valueStartPos = 2; 411 int length = (elementBytes[1] & 0x7F); 412 if (length != elementBytes[1]) 413 { 414 final int numLengthBytes = length; 415 416 length = 0; 417 for (int i=0; i < numLengthBytes; i++) 418 { 419 length <<= 8; 420 length |= (elementBytes[valueStartPos++] & 0xFF); 421 } 422 } 423 424 if ((elementBytes.length - valueStartPos) != length) 425 { 426 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 427 (elementBytes.length - valueStartPos))); 428 } 429 430 final byte[] elementValue = new byte[length]; 431 System.arraycopy(elementBytes, valueStartPos, elementValue, 0, length); 432 final boolean[] bits = decodeValue(elementValue); 433 434 final byte[] bytes; 435 if ((bits.length % 8) == 0) 436 { 437 bytes = new byte[elementValue.length - 1]; 438 System.arraycopy(elementValue, 1, bytes, 0, bytes.length); 439 } 440 else 441 { 442 bytes = null; 443 } 444 445 return new ASN1BitString(elementBytes[0], bits, bytes, elementValue); 446 } 447 catch (final ASN1Exception ae) 448 { 449 Debug.debugException(ae); 450 throw ae; 451 } 452 catch (final Exception e) 453 { 454 Debug.debugException(e); 455 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 456 } 457 } 458 459 460 461 /** 462 * Decodes the provided ASN.1 element as a bit string element. 463 * 464 * @param element The ASN.1 element to be decoded. 465 * 466 * @return The decoded ASN.1 bit string element. 467 * 468 * @throws ASN1Exception If the provided element cannot be decoded as a bit 469 * string element. 470 */ 471 @NotNull() 472 public static ASN1BitString decodeAsBitString( 473 @NotNull final ASN1Element element) 474 throws ASN1Exception 475 { 476 final byte[] elementValue = element.getValue(); 477 final boolean[] bits = decodeValue(elementValue); 478 479 final byte[] bytes; 480 if ((bits.length % 8) == 0) 481 { 482 bytes = new byte[elementValue.length - 1]; 483 System.arraycopy(elementValue, 1, bytes, 0, bytes.length); 484 } 485 else 486 { 487 bytes = null; 488 } 489 490 return new ASN1BitString(element.getType(), bits, bytes, 491 element.getValue()); 492 } 493 494 495 496 /** 497 * Decodes the provided value into a set of bits. 498 * 499 * @param elementValue The bytes that comprise the encoded value for a 500 * bit string element. 501 * 502 * @return An array of {@code boolean} values that correspond to the bits in 503 * this bit string. 504 * 505 * @throws ASN1Exception If the provided value cannot be decoded as a valid 506 * bit string. 507 */ 508 @NotNull() 509 private static boolean[] decodeValue(@NotNull final byte[] elementValue) 510 throws ASN1Exception 511 { 512 if (elementValue.length == 0) 513 { 514 throw new ASN1Exception(ERR_BIT_STRING_DECODE_EMPTY_VALUE.get()); 515 } 516 517 final int paddingBitsNeeded = (elementValue[0] & 0xFF); 518 if (paddingBitsNeeded > 7) 519 { 520 throw new ASN1Exception( 521 ERR_BIT_STRING_DECODE_INVALID_PADDING_BIT_COUNT.get( 522 paddingBitsNeeded)); 523 } 524 525 if ((paddingBitsNeeded > 0) && (elementValue.length == 1)) 526 { 527 throw new ASN1Exception( 528 ERR_BIT_STRING_DECODE_NONZERO_PADDING_BIT_COUNT_WITH_NO_MORE_BYTES. 529 get()); 530 } 531 532 int bitsIndex = 0; 533 final int numBits = ((elementValue.length - 1) * 8) - paddingBitsNeeded; 534 final boolean[] bits = new boolean[numBits]; 535 for (int i=1; i < elementValue.length; i++) 536 { 537 byte b = elementValue[i]; 538 if ((i == (elementValue.length - 1)) && (paddingBitsNeeded > 0)) 539 { 540 for (int j=0; j < (8 - paddingBitsNeeded); j++) 541 { 542 bits[bitsIndex++] = ((b & 0x80) == 0x80); 543 b <<= 1; 544 } 545 } 546 else 547 { 548 bits[bitsIndex++] = ((b & 0x80) == 0x80); 549 bits[bitsIndex++] = ((b & 0x40) == 0x40); 550 bits[bitsIndex++] = ((b & 0x20) == 0x20); 551 bits[bitsIndex++] = ((b & 0x10) == 0x10); 552 bits[bitsIndex++] = ((b & 0x08) == 0x08); 553 bits[bitsIndex++] = ((b & 0x04) == 0x04); 554 bits[bitsIndex++] = ((b & 0x02) == 0x02); 555 bits[bitsIndex++] = ((b & 0x01) == 0x01); 556 } 557 } 558 559 return bits; 560 } 561 562 563 564 /** 565 * {@inheritDoc} 566 */ 567 @Override() 568 public void toString(@NotNull final StringBuilder buffer) 569 { 570 buffer.ensureCapacity(buffer.length() + bits.length); 571 for (final boolean bit : bits) 572 { 573 if (bit) 574 { 575 buffer.append('1'); 576 } 577 else 578 { 579 buffer.append('0'); 580 } 581 } 582 } 583}