001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.asn1.util; 021 022 023import java.io.IOException; 024import java.io.OutputStream; 025import java.math.BigInteger; 026import java.util.Arrays; 027 028import org.apache.directory.api.asn1.DecoderException; 029import org.apache.directory.api.i18n.I18n; 030 031 032/** 033 * An immutable representation of an object identifier that provides conversion 034 * between their <code>String</code>, and encoded <code>byte[]</code> 035 * representations. 036 * 037 * <p> The encoding of OID values is performed according to 038 * <a href='http://www.itu.int/rec/T-REC-X.690/en'>itu X.690</a> section 8.19. 039 * Specifically:</p> 040 * 041 * <p><b>8.19.2</b> The contents octets shall be an (ordered) list of encodings 042 * of subidentifiers (see 8.19.3 and 8.19.4) concatenated together. Each 043 * subidentifier is represented as a series of (one or more) octets. Bit 8 of 044 * each octet indicates whether it is the last in the series: bit 8 of the last 045 * octet is zero; bit 8 of each preceding octet is one. Bits 7 to 1 of the 046 * octets in the series collectively encode the subidentifier. Conceptually, 047 * these groups of bits are concatenated to form an unsigned binary number whose 048 * most significant bit is bit 7 of the first octet and whose least significant 049 * bit is bit 1 of the last octet. The subidentifier shall be encoded in the 050 * fewest possible octets, that is, the leading octet of the subidentifier shall 051 * not have the value 0x80. </p> 052 * 053 * <p><b>8.19.3</b> The number of subidentifiers (N) shall be one less than the 054 * number of object identifier components in the object identifier value being 055 * encoded.</p> 056 * 057 * <p><b>8.19.4</b> The numerical value of the first subidentifier is derived 058 * from the values of the first two object identifier components in the object 059 * identifier value being encoded, using the formula: 060 * <br><code>(X*40) + Y</code><br> 061 * where X is the value of the first object identifier component and Y is the 062 * value of the second object identifier component. <i>NOTE – This packing of 063 * the first two object identifier components recognizes that only three values 064 * are allocated from the root node, and at most 39 subsequent values from nodes 065 * reached by X = 0 and X = 1.</i></p> 066 * 067 * <p>For example, the OID "2.12.3456.7" would be turned into a list of 3 values: 068 * <code>[((2*40)+12), 3456, 7]</code>. The first of which, 069 * <code>92</code>, would be encoded as the bytes <code>0x5C</code>, the second 070 * would be <code>[0x9B, 0x00]</code>, and the third as <code>0x07</code> 071 * giving the final encoding <code>[0x5C, 0x9B, 0x00, 0x07]</code>.</p> 072 * 073 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 074 */ 075public final class Oid 076{ 077 /** A byte[] representation of an OID */ 078 private byte[] oidBytes; 079 080 /** The OID as a String */ 081 private String oidString; 082 083 private static final BigInteger JOINT_ISO_ITU_T = new BigInteger( "80" ); 084 085 /** 086 * The OID FSA states. We have the following Finite State Automaton : 087 * 088 * <pre> 089 * (Start) --['0','1']--> (A) 090 * (start) --['2']--> (F) 091 * 092 * (A) --['.']--> (B) 093 * 094 * (B) --['0']--> (D) 095 * (B) --['1'..'3']--> (C) 096 * (B) --['4'..'9']--> (E) 097 * 098 * (C) --[]--> (End) 099 * (C) --['.']--> (K) 100 * (C) --['0'..'9']--> (E) 101 * 102 * (D) --[]--> (End) 103 * (D) --['.']--> (K) 104 * 105 * (E) --[]--> (End) 106 * (E) --['.']--> (K) 107 * 108 * (F) --['.']--> (G) 109 * 110 * (G) --['0']--> (I) 111 * (G) --['1'..'9']--> (H) 112 * 113 * (H) --[]--> (End) 114 * (H) --['.']--> (K) 115 * (H) --['0'..'9']--> (J) 116 * 117 * (I) --[]--> (End) 118 * (I) --['.']--> (K) 119 * 120 * (J) --[]--> (End) 121 * (J) --['.']--> (K) 122 * (J) --['0'..'9']--> (J) 123 * 124 * (K) --['0']--> (M) 125 * (K) --['1'..'9']--> (L) 126 * 127 * (L) --[]--> (End) 128 * (L) --['.']--> (K) 129 * (L) --['0'..'9']--> (L) 130 * 131 * (M) --[]--> (End) 132 * (M) --['.']--> (K) 133 * </pre> 134 */ 135 private enum OidFSAState 136 { 137 START, 138 STATE_A, 139 STATE_B, 140 STATE_C, 141 STATE_D, 142 STATE_E, 143 STATE_F, 144 STATE_G, 145 STATE_H, 146 STATE_I, 147 STATE_J, 148 STATE_K, 149 STATE_L, 150 STATE_M, 151 } 152 153 154 /** 155 * Creates a new instance of Oid. 156 * 157 * @param oidString The OID as a String 158 * @param oidBytes The OID as a byte[] 159 */ 160 private Oid( String oidString, byte[] oidBytes ) 161 { 162 this.oidString = oidString; 163 this.oidBytes = new byte[oidBytes.length]; 164 System.arraycopy( oidBytes, 0, this.oidBytes, 0, oidBytes.length ); 165 } 166 167 168 /** 169 * {@inheritDoc} 170 */ 171 @Override 172 public boolean equals( Object other ) 173 { 174 return ( other instanceof Oid ) 175 && oidString.equals( ( ( Oid ) other ).oidString ); 176 } 177 178 179 /** 180 * Decodes an OID from a <code>byte[]</code>. 181 * 182 * @param oidBytes The encoded<code>byte[]</code> 183 * @return A new Oid 184 * @throws DecoderException When the OID is not valid 185 */ 186 public static Oid fromBytes( byte[] oidBytes ) throws DecoderException 187 { 188 if ( ( oidBytes == null ) || ( oidBytes.length < 1 ) ) 189 { 190 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, Arrays.toString( oidBytes ) ) ); 191 } 192 193 StringBuilder builder = new StringBuilder(); 194 long value = 0; 195 int valStart = 0; 196 int valLength = 0; 197 boolean firstArc = true; 198 199 for ( int i = 0; i < oidBytes.length; i++ ) 200 { 201 value |= oidBytes[i] & 0x7F; 202 203 if ( oidBytes[i] < 0 ) 204 { 205 // leading 1, so value continues 206 value = value << 7; 207 valLength++; 208 } 209 else 210 { 211 valLength++; 212 213 if ( valLength > 8 ) 214 { 215 // Above 9 bytes, we won't be able to store the value in a long... 216 // Compute the number of necessary bytes 217 int nbBytes = valLength * 7 / 8; 218 219 if ( valLength % 7 != 0 ) 220 { 221 nbBytes++; 222 } 223 224 byte[] result = new byte[nbBytes]; 225 226 // Now iterate on the incoming bytes 227 int pos = nbBytes - 1; 228 int valEnd = valStart + valLength - 1; 229 int j = 0; 230 231 while ( j < valLength - 8 ) 232 { 233 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 1] << 7 ) | ( oidBytes[valEnd - j] & 0x7F ) ); 234 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 2] << 6 ) | ( ( oidBytes[valEnd - j - 1] & 0x7E ) >> 1 ) ); 235 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 3] << 5 ) | ( ( oidBytes[valEnd - j - 2] & 0x7C ) >> 2 ) ); 236 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 4] << 4 ) | ( ( oidBytes[valEnd - j - 3] & 0x78 ) >> 3 ) ); 237 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 5] << 3 ) | ( ( oidBytes[valEnd - j - 4] & 0x70 ) >> 4 ) ); 238 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 6] << 2 ) | ( ( oidBytes[valEnd - j - 5] & 0x60 ) >> 5 ) ); 239 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 7] << 1 ) | ( ( oidBytes[valEnd - j - 6] & 0x40 ) >> 6 ) ); 240 j += 8; 241 } 242 243 switch ( valLength - j ) 244 { 245 case 7 : 246 result[pos--] = ( byte ) ( ( oidBytes[5] << 7 ) | ( oidBytes[6] & 0x7F ) ); 247 result[pos--] = ( byte ) ( ( oidBytes[4] << 6 ) | ( ( oidBytes[5] & 0x7E ) >> 1 ) ); 248 result[pos--] = ( byte ) ( ( oidBytes[3] << 5 ) | ( ( oidBytes[4] & 0x7C ) >> 2 ) ); 249 result[pos--] = ( byte ) ( ( oidBytes[2] << 4 ) | ( ( oidBytes[3] & 0x78 ) >> 3 ) ); 250 result[pos--] = ( byte ) ( ( oidBytes[1] << 3 ) | ( ( oidBytes[2] & 0x70 ) >> 4 ) ); 251 result[pos--] = ( byte ) ( ( oidBytes[0] << 2 ) | ( ( oidBytes[1] & 0x60 ) >> 5 ) ); 252 result[pos] = ( byte ) ( ( oidBytes[0] & 0x40 ) >> 6 ); 253 break; 254 255 case 6 : 256 result[pos--] = ( byte ) ( ( oidBytes[4] << 7 ) | ( oidBytes[5] & 0x7F ) ); 257 result[pos--] = ( byte ) ( ( oidBytes[3] << 6 ) | ( ( oidBytes[4] & 0x7E ) >> 1 ) ); 258 result[pos--] = ( byte ) ( ( oidBytes[2] << 5 ) | ( ( oidBytes[3] & 0x7C ) >> 2 ) ); 259 result[pos--] = ( byte ) ( ( oidBytes[1] << 4 ) | ( ( oidBytes[2] & 0x78 ) >> 3 ) ); 260 result[pos--] = ( byte ) ( ( oidBytes[0] << 3 ) | ( ( oidBytes[1] & 0x70 ) >> 4 ) ); 261 result[pos] = ( byte ) ( ( oidBytes[0] & 0x60 ) >> 5 ); 262 break; 263 264 case 5 : 265 result[pos--] = ( byte ) ( ( oidBytes[3] << 7 ) | ( oidBytes[4] & 0x7F ) ); 266 result[pos--] = ( byte ) ( ( oidBytes[2] << 6 ) | ( ( oidBytes[3] & 0x7E ) >> 1 ) ); 267 result[pos--] = ( byte ) ( ( oidBytes[1] << 5 ) | ( ( oidBytes[2] & 0x7C ) >> 2 ) ); 268 result[pos--] = ( byte ) ( ( oidBytes[0] << 4 ) | ( ( oidBytes[1] & 0x78 ) >> 3 ) ); 269 result[pos] = ( byte ) ( ( oidBytes[0] & 0x70 ) >> 4 ); 270 break; 271 272 case 4 : 273 result[pos--] = ( byte ) ( ( oidBytes[2] << 7 ) | ( oidBytes[3] & 0x7F ) ); 274 result[pos--] = ( byte ) ( ( oidBytes[1] << 6 ) | ( ( oidBytes[2] & 0x7E ) >> 1 ) ); 275 result[pos--] = ( byte ) ( ( oidBytes[0] << 5 ) | ( ( oidBytes[1] & 0x7C ) >> 2 ) ); 276 result[pos] = ( byte ) ( ( oidBytes[0] & 0x78 ) >> 3 ); 277 break; 278 279 case 3 : 280 result[pos--] = ( byte ) ( ( oidBytes[1] << 7 ) | ( oidBytes[2] & 0x7F ) ); 281 result[pos--] = ( byte ) ( ( oidBytes[0] << 6 ) | ( ( oidBytes[1] & 0x7E ) >> 1 ) ); 282 result[pos] = ( byte ) ( ( oidBytes[0] & 0x7C ) >> 2 ); 283 break; 284 285 case 2 : 286 result[pos--] = ( byte ) ( ( oidBytes[0] << 7 ) | ( oidBytes[1] & 0x7F ) ); 287 result[pos] = ( byte ) ( ( oidBytes[0] & 0x7E ) >> 1 ); 288 break; 289 290 case 1 : 291 result[pos] = ( byte ) ( oidBytes[0] & 0x7F ); 292 break; 293 294 default : 295 // Exist to please checkstyle... 296 break; 297 } 298 299 BigInteger bigInteger; 300 301 if ( ( result[0] & 0x80 ) == 0x80 ) 302 { 303 byte[] newResult = new byte[result.length + 1]; 304 System.arraycopy( result, 0, newResult, 1, result.length ); 305 result = newResult; 306 } 307 308 bigInteger = new BigInteger( result ); 309 310 if ( firstArc ) 311 { 312 // This is a joint-iso-itu-t(2) arc 313 bigInteger = bigInteger.subtract( JOINT_ISO_ITU_T ); 314 builder.append( '2' ); 315 } 316 317 builder.append( '.' ).append( bigInteger.toString() ); 318 } 319 else 320 { 321 // value completed 322 if ( firstArc ) 323 { 324 // first value special processing 325 if ( value >= 80 ) 326 { 327 // starts with 2 328 builder.append( '2' ); 329 value = value - 80; 330 } 331 else 332 { 333 // starts with 0 or 1 334 long one = value / 40; 335 long two = value % 40; 336 337 if ( ( one < 0 ) || ( one > 2 ) || ( two < 0 ) || ( ( one < 2 ) && ( two > 39 ) ) ) 338 { 339 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, 340 Arrays.toString( oidBytes ) ) ); 341 } 342 343 if ( one < 2 ) 344 { 345 builder.append( one ); 346 value = two; 347 } 348 } 349 350 firstArc = false; 351 } 352 353 // normal processing 354 builder.append( '.' ).append( value ); 355 } 356 357 valStart = i; 358 valLength = 0; 359 value = 0; 360 } 361 } 362 363 return new Oid( builder.toString(), oidBytes ); 364 } 365 366 367 /** 368 * Process state A 369 * <pre> 370 * (Start) --['0','1']--> (A) 371 * (start) --['2']--> (F) 372 * </pre> 373 */ 374 private static OidFSAState processStateStart( String oid, byte[] buffer, int pos ) throws DecoderException 375 { 376 char c = oid.charAt( pos ); 377 378 switch ( c ) 379 { 380 case '0' : 381 case '1' : 382 buffer[0] = ( byte ) ( ( c - '0' ) * 40 ); 383 return OidFSAState.STATE_A; 384 385 case '2' : 386 return OidFSAState.STATE_F; 387 388 default : 389 // This is an error 390 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "Should start with 0, 1 or 2" ) ); 391 } 392 } 393 394 395 /** 396 * Process state B 397 * <pre> 398 * (A) --['.']--> (B) 399 * </pre> 400 */ 401 private static OidFSAState processStateA( String oid, int pos ) throws DecoderException 402 { 403 if ( oid.charAt( pos ) != '.' ) 404 { 405 // Expecting a Dot here 406 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a '.' is expected" ) ); 407 } 408 409 return OidFSAState.STATE_B; 410 } 411 412 413 /** 414 * Process state B 415 * <pre> 416 * (B) --['0']--> (D) 417 * (B) --['1'..'3']--> (C) 418 * (B) --['4'..'9']--> (E) 419 * </pre> 420 */ 421 private static OidFSAState processStateB( String oid, byte[] buffer, int pos ) throws DecoderException 422 { 423 char c = oid.charAt( pos ); 424 425 switch ( c ) 426 { 427 case '0' : 428 return OidFSAState.STATE_D; 429 430 case '1' : 431 case '2' : 432 case '3' : 433 // We may have a second digit. Atm, store the current one in the second psotion 434 buffer[1] = ( byte ) ( c - '0' ); 435 436 return OidFSAState.STATE_C; 437 438 case '4' : 439 case '5' : 440 case '6' : 441 case '7' : 442 case '8' : 443 case '9' : 444 buffer[0] += ( byte ) ( c - '0' ); 445 return OidFSAState.STATE_E; 446 447 default : 448 // Expecting a digit here 449 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 450 } 451 } 452 453 454 /** 455 * Process state C 456 * <pre> 457 * (C) --['.']--> (K) 458 * (C) --['0'..'9']--> (E) 459 * </pre> 460 */ 461 private static OidFSAState processStateC( String oid, byte[] buffer, int pos ) throws DecoderException 462 { 463 char c = oid.charAt( pos ); 464 465 switch ( c ) 466 { 467 case '0' : 468 case '1' : 469 case '2' : 470 case '3' : 471 case '4' : 472 case '5' : 473 case '6' : 474 case '7' : 475 case '8' : 476 case '9' : 477 buffer[0] += ( byte ) ( buffer[1] * 10 + ( c - '0' ) ); 478 buffer[1] = 0; 479 return OidFSAState.STATE_E; 480 481 case '.' : 482 buffer[0] += buffer[1]; 483 buffer[1] = 0; 484 return OidFSAState.STATE_K; 485 486 default : 487 // Expecting a digit here 488 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 489 } 490 } 491 492 493 /** 494 * Process state D and E 495 * <pre> 496 * (D) --['.']--> (K) 497 * (E) --['.']--> (K) 498 * </pre> 499 */ 500 private static OidFSAState processStateDE( String oid, byte[] buffer, int pos ) throws DecoderException 501 { 502 char c = oid.charAt( pos ); 503 504 if ( c != '.' ) 505 { 506 // Expecting a '.' here 507 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a dot is expected" ) ); 508 } 509 510 // Store the first byte into it 511 buffer[0] = ( byte ) ( buffer[0] | buffer[1] ); 512 buffer[1] = 0; 513 514 return OidFSAState.STATE_K; 515 } 516 517 518 /** 519 * Process state F 520 * <pre> 521 * (F) --['.']--> (G) 522 * </pre> 523 */ 524 private static OidFSAState processStateF( String oid, int pos ) throws DecoderException 525 { 526 if ( oid.charAt( pos ) != '.' ) 527 { 528 // Expecting a Dot here 529 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a '.' is expected" ) ); 530 } 531 532 return OidFSAState.STATE_G; 533 } 534 535 536 /** 537 * Process state G 538 * <pre> 539 * (G) --['0']--> (I) 540 * (G) --['1'..'9']--> (H) 541 * </pre> 542 */ 543 private static OidFSAState processStateG( String oid, byte[] buffer, int pos ) throws DecoderException 544 { 545 char c = oid.charAt( pos ); 546 547 switch ( c ) 548 { 549 case '0' : 550 buffer[0] = ( byte ) 80; 551 return OidFSAState.STATE_I; 552 553 case '1' : 554 case '2' : 555 case '3' : 556 case '4' : 557 case '5' : 558 case '6' : 559 case '7' : 560 case '8' : 561 case '9' : 562 // Store the read digit in the second position in the buffer 563 buffer[0] = ( byte ) ( c - '0' ); 564 return OidFSAState.STATE_H; 565 566 default : 567 // Expecting a digit here 568 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 569 } 570 } 571 572 573 /** 574 * Process state H 575 * <pre> 576 * (H) --['.']--> (K) 577 * (H) --['0'..'9']--> (J) 578 * </pre> 579 */ 580 private static OidFSAState processStateH( String oid, byte[] buffer, int pos ) throws DecoderException 581 { 582 char c = oid.charAt( pos ); 583 584 switch ( c ) 585 { 586 case '0' : 587 case '1' : 588 case '2' : 589 case '3' : 590 case '4' : 591 case '5' : 592 case '6' : 593 case '7' : 594 case '8' : 595 case '9' : 596 // Store the read digit in the first position in the buffer 597 buffer[1] = ( byte ) ( c - '0' ); 598 return OidFSAState.STATE_J; 599 600 case '.' : 601 // The first 2 arcs are single digit, we can collapse them in one byte. 602 buffer[0] = ( byte ) ( 80 + buffer[0] ); 603 604 return OidFSAState.STATE_K; 605 606 default : 607 // Expecting a digit here 608 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 609 } 610 } 611 612 613 /** 614 * Process state I 615 * <pre> 616 * (I) --['.']--> (K) 617 * </pre> 618 */ 619 private static OidFSAState processStateI( String oid, byte[] buffer, int pos ) throws DecoderException 620 { 621 char c = oid.charAt( pos ); 622 623 if ( c == '.' ) 624 { 625 // The first 2 arcs are single digit, we can collapse them in one byte. 626 buffer[0] = ( byte ) ( 80 + buffer[1] ); 627 628 return OidFSAState.STATE_K; 629 } 630 else 631 { 632 // Expecting a digit here 633 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 634 } 635 } 636 637 638 /** 639 * Process state J 640 * <pre> 641 * (J) --['.']--> (K) 642 * (J) --['0'..'9']--> (J) 643 * </pre> 644 */ 645 private static OidFSAState processStateJ( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException 646 { 647 char c = oid.charAt( pos ); 648 649 switch ( c ) 650 { 651 case '.' : 652 return OidFSAState.STATE_K; 653 654 case '0' : 655 case '1' : 656 case '2' : 657 case '3' : 658 case '4' : 659 case '5' : 660 case '6' : 661 case '7' : 662 case '8' : 663 case '9' : 664 // Store the new digit at the right position in the buffer 665 buffer[bufferPos] = ( byte ) ( c - '0' ); 666 return OidFSAState.STATE_J; 667 668 default : 669 // Expecting a digit here 670 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 671 } 672 } 673 674 675 /** 676 * Process state J 677 * <pre> 678 * (K) --['0']--> (M) 679 * (K) --['1'..'9']--> (L) 680 * </pre> 681 */ 682 private static OidFSAState processStateK( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException 683 { 684 char c = oid.charAt( pos ); 685 686 switch ( c ) 687 { 688 case '0' : 689 buffer[bufferPos] = 0x00; 690 return OidFSAState.STATE_M; 691 692 case '1' : 693 case '2' : 694 case '3' : 695 case '4' : 696 case '5' : 697 case '6' : 698 case '7' : 699 case '8' : 700 case '9' : 701 // Store the new digit at the right position in the buffer 702 return OidFSAState.STATE_L; 703 704 default : 705 // Expecting a digit here 706 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit is expected" ) ); 707 } 708 } 709 710 711 /** 712 * Process state J 713 * <pre> 714 * (L) --['.']--> (K) 715 * (L) --['0'..'9']--> (L) 716 * </pre> 717 */ 718 private static OidFSAState processStateL( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException 719 { 720 char c = oid.charAt( pos ); 721 722 switch ( c ) 723 { 724 case '.' : 725 return OidFSAState.STATE_K; 726 727 case '0' : 728 case '1' : 729 case '2' : 730 case '3' : 731 case '4' : 732 case '5' : 733 case '6' : 734 case '7' : 735 case '8' : 736 case '9' : 737 // Store the new digit at the right position in the buffer 738 buffer[bufferPos] = ( byte ) ( c - '0' ); 739 740 return OidFSAState.STATE_L; 741 742 default : 743 // Expecting a digit here 744 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a digit or a dot is expected" ) ); 745 } 746 } 747 748 749 /** 750 * Process state J 751 * <pre> 752 * (M) --['.']--> (K) 753 * </pre> 754 */ 755 private static OidFSAState processStateM( String oid, int pos ) throws DecoderException 756 { 757 char c = oid.charAt( pos ); 758 759 if ( c == '.' ) 760 { 761 return OidFSAState.STATE_K; 762 } 763 else 764 { 765 // Expecting a '.' here 766 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "a '.' is expected" ) ); 767 } 768 } 769 770 771 /** 772 * Convert a list of digits to a list of 7 bits bytes. We must start by the end, and we don't 773 * know how many bytes we will need, except when we will be done with the conversion. 774 */ 775 private static int convert( String oid, byte[] buffer, int start, int nbDigits, int posBuffer, boolean isJointIsoItuT ) 776 { 777 if ( nbDigits < 3 ) 778 { 779 // Speedup when we have a number in [0..99] : it's guaranteed to be hold 780 // by a single byte. 781 if ( isJointIsoItuT ) 782 { 783 // Another special case : this is an OID that starts with '2.' 784 buffer[0] = ( byte ) ( 80 + ( oid.charAt( 2 ) - '0' ) * 10 + ( oid.charAt( 3 ) - '0' ) ); 785 786 if ( buffer[0] < 0 ) 787 { 788 // Here, we need 2 bytes 789 buffer[1] = ( byte ) ( buffer[0] & 0x007F ); 790 buffer[0] = ( byte ) 0x81; 791 792 return 2; 793 } 794 else 795 { 796 return 1; 797 } 798 } 799 else 800 { 801 if ( nbDigits == 1 ) 802 { 803 buffer[posBuffer] = ( byte ) ( oid.charAt( start ) - '0' ); 804 } 805 else 806 { 807 buffer[posBuffer] = ( byte ) ( ( oid.charAt( start ) - '0' ) * 10 + ( oid.charAt( start + 1 ) - '0' ) ); 808 809 } 810 return 1; 811 } 812 813 } 814 else if ( nbDigits < 19 ) 815 { 816 // The value can be hold in a Long if it's up to 999999999999999999 817 // Convert the String to a long : 818 String number = oid.substring( start, start + nbDigits ); 819 820 long value = Long.parseLong( number ); 821 822 if ( isJointIsoItuT ) 823 { 824 value += 80L; 825 } 826 827 // Convert the long to a byte array 828 if ( ( value & 0xFFFFFFFFFFFFFF80L ) == 0 ) 829 { 830 // The value will be hold in one byte 831 buffer[posBuffer] = ( byte ) ( value ); 832 833 return 1; 834 } 835 836 if ( ( value & 0xFFFFFFFFFFFFC000L ) == 0 ) 837 { 838 // The value is between 0x80 and 0x3FFF : it will be hold in 2 bytes 839 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 840 buffer[posBuffer + 1] = ( byte ) ( value & 0x000000000000007FL ); 841 842 return 2; 843 } 844 845 if ( ( value & 0xFFFFFFFFFFE00000L ) == 0 ) 846 { 847 // The value is between 0x4000 and 0x1FFFFF : it will be hold in 3 bytes 848 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 849 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 850 buffer[posBuffer + 2] = ( byte ) ( value & 0x000000000000007FL ); 851 852 return 3; 853 } 854 855 if ( ( value & 0xFFFFFFFFF0000000L ) == 0 ) 856 { 857 // The value is between 0x200000 and 0xFFFFFFF : it will be hold in 4 bytes 858 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 859 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 860 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 861 buffer[posBuffer + 3] = ( byte ) ( value & 0x000000000000007FL ); 862 863 return 4; 864 } 865 866 if ( ( value & 0xFFFFFFF800000000L ) == 0 ) 867 { 868 // The value is between 0x10000000 and 0x7FFFFFFFF : it will be hold in 5 bytes 869 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 870 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 871 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 872 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 873 buffer[posBuffer + 4] = ( byte ) ( value & 0x000000000000007FL ); 874 875 return 5; 876 } 877 878 if ( ( value & 0xFFFFFC0000000000L ) == 0 ) 879 { 880 // The value is between 0x800000000 and 0x3FFFFFFFFFF : it will be hold in 6 bytes 881 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 882 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 883 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 884 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 885 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 886 buffer[posBuffer + 5] = ( byte ) ( value & 0x000000000000007FL ); 887 888 return 6; 889 } 890 891 if ( ( value & 0xFFFE000000000000L ) == 0 ) 892 { 893 // The value is between 0x40000000000 and 0x1FFFFFFFFFFFF : it will be hold in 7 bytes 894 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 ); 895 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 896 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 897 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 898 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 899 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 900 buffer[posBuffer + 6] = ( byte ) ( value & 0x000000000000007FL ); 901 902 return 7; 903 } 904 905 if ( ( value & 0xFF00000000000000L ) == 0 ) 906 { 907 // The value is between 0x2000000000000 and 0xFF000000000000 : it will be hold in 8 bytes 908 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00FE000000000000L ) >> 49 ) | 0x80 ); 909 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 ); 910 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 911 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 912 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 913 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 914 buffer[posBuffer + 6] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 915 buffer[posBuffer + 7] = ( byte ) ( value & 0x000000000000007FL ); 916 917 return 8; 918 } 919 else 920 { 921 // The value is between 0x100000000000000 and 0x7F00000000000000 : it will be hold in 9 bytes 922 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x7F00000000000000L ) >> 56 ) | 0x80 ); 923 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00FE000000000000L ) >> 49 ) | 0x80 ); 924 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 ); 925 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 926 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 927 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 928 buffer[posBuffer + 6] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 929 buffer[posBuffer + 7] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 930 buffer[posBuffer + 8] = ( byte ) ( value & 0x000000000000007FL ); 931 932 return 9; 933 } 934 } 935 else 936 { 937 // The value is bigger than 9999999999999999999, we need to use a BigInteger 938 // First, get the number of bytes we need to store the value in base 16 939 String number = oid.substring( start, start + nbDigits ); 940 BigInteger bigInteger = new BigInteger( number ); 941 942 if ( isJointIsoItuT ) 943 { 944 bigInteger = bigInteger.add( JOINT_ISO_ITU_T ); 945 posBuffer = 0; 946 } 947 948 byte[] bytes = bigInteger.toByteArray(); 949 950 // Now, convert this value to the ASN.1 OID format : we store the value 951 // as 7 bits bytes 952 int nbNeededBytes = ( bytes.length * 8 ) / 7; 953 954 switch ( ( bytes.length - 1 ) % 7 ) 955 { 956 case 0 : 957 if ( ( bytes[0] & 0x0080 ) != 0 ) 958 { 959 nbNeededBytes++; 960 } 961 962 break; 963 964 case 1 : 965 if ( ( bytes[0] & 0x00C0 ) != 0 ) 966 { 967 nbNeededBytes++; 968 } 969 970 break; 971 972 case 2 : 973 if ( ( bytes[0] & 0x00E0 ) != 0 ) 974 { 975 nbNeededBytes++; 976 } 977 978 break; 979 980 case 3 : 981 if ( ( bytes[0] & 0x00F0 ) != 0 ) 982 { 983 nbNeededBytes++; 984 } 985 986 break; 987 988 case 4 : 989 if ( ( bytes[0] & 0x00F8 ) != 0 ) 990 { 991 nbNeededBytes++; 992 } 993 994 break; 995 996 case 5 : 997 if ( ( bytes[0] & 0x00FC ) != 0 ) 998 { 999 nbNeededBytes++; 1000 } 1001 1002 break; 1003 1004 case 6 : 1005 if ( ( bytes[0] & 0x00FE ) != 0 ) 1006 { 1007 nbNeededBytes++; 1008 } 1009 1010 break; 1011 1012 default : 1013 // Exist to please checkstyle... 1014 break; 1015 } 1016 1017 byte[] converted = new byte[nbNeededBytes]; 1018 1019 int posConverted = nbNeededBytes - 1; 1020 int posBytes = bytes.length - 1; 1021 int counter = 0; 1022 byte reminder = 0; 1023 1024 while ( posBytes >= 0 ) 1025 { 1026 byte newByte = ( byte ) ( ( bytes[posBytes] & 0x00FF ) << counter ); 1027 converted[posConverted] = ( byte ) ( reminder | newByte | 0x0080 ); 1028 reminder = ( byte ) ( ( bytes[posBytes] & 0x00FF ) >> ( 7 - counter ) ); 1029 counter = ( counter + 1 ) % 8; 1030 posConverted--; 1031 1032 if ( counter != 0 ) 1033 { 1034 posBytes--; 1035 } 1036 else 1037 { 1038 reminder = 0; 1039 } 1040 } 1041 1042 converted[nbNeededBytes - 1] &= 0x7F; 1043 1044 // Copy the converted bytes in the buffer 1045 System.arraycopy( converted, 0, buffer, posBuffer, nbNeededBytes ); 1046 1047 return nbNeededBytes; 1048 } 1049 } 1050 1051 1052 /** 1053 * Returns an OID object representing <code>oidString</code>. 1054 * 1055 * @param oidString The string representation of the OID 1056 * @return A new Oid 1057 * @throws DecoderException When the OID is not valid 1058 */ 1059 public static Oid fromString( String oidString ) throws DecoderException 1060 { 1061 if ( ( oidString == null ) || oidString.isEmpty() ) 1062 { 1063 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "empty" ) ); 1064 } 1065 1066 // Create a buffer that is wide enough to contain all the values 1067 byte[] buffer = new byte[oidString.length()]; 1068 1069 OidFSAState state = OidFSAState.START; 1070 1071 // A counter of chars used for an arc. In 1.2.45345, this counter will be 5 for the '45345' arc. 1072 int arcNbChars = 0; 1073 1074 // The position in the buffer where we accumulate the result. 1075 int bufPos = 0; 1076 1077 // The position in the OID string where we started to read an arc 1078 int startArc = 0; 1079 1080 // The number of bytes in the resulting OID byte[] 1081 int nbBytes; 1082 1083 for ( int i = 0; i < oidString.length(); i++ ) 1084 { 1085 switch ( state ) 1086 { 1087 case START : 1088 // (Start) --['0'..'1']--> (A) 1089 // (start) --['2']--> (F) 1090 state = processStateStart( oidString, buffer, i ); 1091 break; 1092 1093 case STATE_A : 1094 // (A) --['.']--> (B) 1095 state = processStateA( oidString, i ); 1096 1097 1098 break; 1099 1100 case STATE_B : 1101 // (B) --['0']--> (D) 1102 // (B) --['1'..'3']--> (C) 1103 // (B) --['4'..'9']--> (E) 1104 state = processStateB( oidString, buffer, i ); 1105 1106 break; 1107 1108 case STATE_C : 1109 // (C) --['.']--> (K) 1110 // (C) --['0'..'9']--> (E) 1111 state = processStateC( oidString, buffer, i ); 1112 1113 // the next arc will be store at position 1 in the buffer 1114 bufPos = 1; 1115 1116 break; 1117 1118 case STATE_D : 1119 // (D) --['.']--> (K) 1120 // Fallthrough 1121 1122 case STATE_E : 1123 // (E) --['.']--> (K) 1124 state = processStateDE( oidString, buffer, i ); 1125 1126 // the next arc will be store at position 1 in teh buffer 1127 bufPos = 1; 1128 1129 break; 1130 1131 case STATE_F : 1132 // (F) --['.']--> (G) 1133 state = processStateF( oidString, i ); 1134 1135 break; 1136 1137 case STATE_G : 1138 // (G) --['0']--> (I) 1139 // (G) --['1'..'9']--> (H) 1140 state = processStateG( oidString, buffer, i ); 1141 arcNbChars = 1; 1142 startArc = i; 1143 1144 break; 1145 1146 case STATE_H : 1147 // (H) --['.']--> (K) 1148 // (H) --['0'..'9']--> (J) 1149 state = processStateH( oidString, buffer, i ); 1150 1151 if ( state == OidFSAState.STATE_J ) 1152 { 1153 // We have already two digits 1154 arcNbChars = 2; 1155 bufPos = 0; 1156 } 1157 1158 break; 1159 1160 case STATE_I : 1161 // (I) --['.']--> (K) 1162 state = processStateI( oidString, buffer, i ); 1163 1164 // Set the arc position to buffer[1], we haven't yet accumulated digits. 1165 bufPos = 1; 1166 1167 break; 1168 1169 case STATE_J : 1170 // (J) --['.']--> (K) 1171 // (J) --['0'..'9']--> (J) 1172 state = processStateJ( oidString, buffer, arcNbChars + bufPos, i ); 1173 1174 if ( state == OidFSAState.STATE_J ) 1175 { 1176 // We can increment the number of digit for this arc 1177 arcNbChars++; 1178 } 1179 else 1180 { 1181 // We are done with the first arc : convert it 1182 bufPos += convert( oidString, buffer, bufPos, arcNbChars, 0, true ); 1183 } 1184 1185 break; 1186 1187 case STATE_K : 1188 startArc = i; 1189 state = processStateK( oidString, buffer, bufPos, i ); 1190 1191 if ( state == OidFSAState.STATE_M ) 1192 { 1193 bufPos++; 1194 } 1195 else 1196 { 1197 arcNbChars = 1; 1198 } 1199 1200 break; 1201 1202 case STATE_L : 1203 state = processStateL( oidString, buffer, arcNbChars + bufPos, i ); 1204 1205 if ( state == OidFSAState.STATE_L ) 1206 { 1207 arcNbChars++; 1208 break; 1209 } 1210 else 1211 { 1212 // We are done with the arc : convert it 1213 bufPos += convert( oidString, buffer, startArc, arcNbChars, bufPos, false ); 1214 } 1215 1216 break; 1217 1218 case STATE_M : 1219 state = processStateM( oidString, i ); 1220 break; 1221 1222 default : 1223 // Exist to please checkstyle... 1224 break; 1225 } 1226 } 1227 1228 // End of the string : check that we are in a correct state for a completion 1229 // The only valid exit states are : 1230 // (C) --[]--> (End) 1231 // (D) --[]--> (End) 1232 // (E) --[]--> (End) 1233 // (H) --[]--> (End) 1234 // (I) --[]--> (End) 1235 // (J) --[]--> (End) 1236 // (L) --[]--> (End) 1237 // (M) --[]--> (End) 1238 switch ( state ) 1239 { 1240 case STATE_C : 1241 // (C) --[]--> (End) 1242 // fallthrough 1243 1244 case STATE_D : 1245 // (D) --[]--> (End) 1246 // fallthrough 1247 1248 case STATE_E : 1249 // (E) --[]--> (End) 1250 // fallthrough 1251 1252 case STATE_H : 1253 // (H) --[]--> (End) 1254 // fallthrough 1255 1256 case STATE_I : 1257 // (I) --[]--> (End) 1258 byte[] bytes = new byte[1]; 1259 bytes[0] = ( byte ) ( buffer[0] | buffer[1] ); 1260 1261 return new Oid( oidString, bytes ); 1262 1263 case STATE_J : 1264 // (J) --[]--> (End) 1265 nbBytes = convert( oidString, buffer, 2, arcNbChars, 0, true ); 1266 bytes = new byte[nbBytes]; 1267 System.arraycopy( buffer, 0, bytes, 0, nbBytes ); 1268 1269 return new Oid( oidString, bytes ); 1270 1271 case STATE_L : 1272 bufPos += convert( oidString, buffer, startArc, arcNbChars, bufPos, false ); 1273 bytes = new byte[bufPos]; 1274 System.arraycopy( buffer, 0, bytes, 0, bufPos ); 1275 1276 return new Oid( oidString, bytes ); 1277 1278 case STATE_M : 1279 bytes = new byte[bufPos]; 1280 System.arraycopy( buffer, 0, bytes, 0, bufPos ); 1281 1282 return new Oid( oidString, bytes ); 1283 1284 default : 1285 // This should never happen... 1286 throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "Wrong OID" ) ); 1287 } 1288 } 1289 1290 1291 /** 1292 * Returns the length of the encoded <code>byte[]</code> representation. 1293 * 1294 * @return The length of the byte[] 1295 */ 1296 public int getEncodedLength() 1297 { 1298 return oidBytes.length; 1299 } 1300 1301 1302 /** 1303 * {@inheritDoc} 1304 */ 1305 @Override 1306 public int hashCode() 1307 { 1308 return oidString.hashCode(); 1309 } 1310 1311 1312 /** 1313 * Returns true if <code>oidString</code> is a valid string representation 1314 * of an OID. This method simply calls {@link #fromString(String)} and 1315 * returns true if no exception was thrown. As such, it should not be used 1316 * in an attempt to check if a string is a valid OID before calling 1317 * {@link #fromString(String)}. 1318 * 1319 * @param oidString The string to test 1320 * @return True, if <code>oidString</code> is valid 1321 */ 1322 public static boolean isOid( String oidString ) 1323 { 1324 try 1325 { 1326 Oid.fromString( oidString ); 1327 1328 return true; 1329 } 1330 catch ( DecoderException e ) 1331 { 1332 return false; 1333 } 1334 } 1335 1336 1337 /** 1338 * Returns the <code>byte[]</code> representation of the OID. The 1339 * <code>byte[]</code> that is returned is <i>copied</i> from the internal 1340 * value so as to preserve the immutability of an OID object. If the 1341 * output of a call to this method is intended to be written to a stream, 1342 * the {@link #writeBytesTo(OutputStream)} should be used instead as it will 1343 * avoid creating this copy. 1344 * 1345 * @return The encoded <code>byte[]</code> representation of the OID. 1346 */ 1347 public byte[] toBytes() 1348 { 1349 return Arrays.copyOf( oidBytes, oidBytes.length ); 1350 } 1351 1352 1353 /** 1354 * Returns the string representation of the OID. 1355 * 1356 * @return The string representation of the OID 1357 */ 1358 @Override 1359 public String toString() 1360 { 1361 return oidString; 1362 } 1363 1364 1365 /** 1366 * Writes the bytes respresenting this OID to the provided buffer. This 1367 * should be used in preference to the {@link #toBytes()} method in order 1368 * to prevent the creation of copies of the actual <code>byte[]</code>. 1369 * 1370 * @param buffer The buffer to write the bytes into 1371 */ 1372 public void writeBytesTo( java.nio.ByteBuffer buffer ) 1373 { 1374 buffer.put( oidBytes ); 1375 } 1376 1377 1378 /** 1379 * Writes the bytes respresenting this OID to the provided stream. This 1380 * should be used in preference to the {@link #toBytes()} method in order 1381 * to prevent the creation of copies of the actual <code>byte[]</code>. 1382 * 1383 * @param outputStream The stream to write the bytes to 1384 * @throws IOException When we can't write the OID into a Stream 1385 */ 1386 public void writeBytesTo( OutputStream outputStream ) throws IOException 1387 { 1388 outputStream.write( oidBytes ); 1389 } 1390}