1 /* 2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.util; 27 28 import java.io.*; 29 import java.math.BigInteger; 30 import java.util.Arrays; 31 32 /** 33 * Represent an ISO Object Identifier. 34 * 35 * <P>Object Identifiers are arbitrary length hierarchical identifiers. 36 * The individual components are numbers, and they define paths from the 37 * root of an ISO-managed identifier space. You will sometimes see a 38 * string name used instead of (or in addition to) the numerical id. 39 * These are synonyms for the numerical IDs, but are not widely used 40 * since most sites do not know all the requisite strings, while all 41 * sites can parse the numeric forms. 42 * 43 * <P>So for example, JavaSoft has the sole authority to assign the 44 * meaning to identifiers below the 1.3.6.1.4.1.42.2.17 node in the 45 * hierarchy, and other organizations can easily acquire the ability 46 * to assign such unique identifiers. 47 * 48 * @author David Brownell 49 * @author Amit Kapoor 50 * @author Hemma Prafullchandra 51 */ 52 53 public final 54 class ObjectIdentifier implements Serializable 55 { 56 /* 57 * The maximum encoded OID length, excluding the ASN.1 encoding tag and 58 * length. 59 * 60 * In theory, there is no maximum size for OIDs. However, there are some 61 * limitation in practice. 62 * 63 * RFC 5280 mandates support for OIDs that have arc elements with values 64 * that are less than 2^28 (that is, they MUST be between 0 and 65 * 268,435,455, inclusive), and implementations MUST be able to handle 66 * OIDs with up to 20 elements (inclusive). Per RFC 5280, an encoded 67 * OID should be less than 80 bytes for safe interoperability. 68 * 69 * This class could be used for protocols other than X.509 certificates. 70 * To be safe, a relatively large but still reasonable value is chosen 71 * as the restriction in JDK. 72 */ 73 private static final int MAXIMUM_OID_SIZE = 4096; // 2^12 74 75 76 /** 77 * We use the DER value (no tag, no length) as the internal format 78 * @serial 79 */ 80 private byte[] encoding = null; 81 82 private transient volatile String stringForm; 83 84 /* 85 * IMPORTANT NOTES FOR CODE CHANGES (bug 4811968) IN JDK 1.7.0 86 * =========================================================== 87 * 88 * (Almost) serialization compatibility with old versions: 89 * 90 * serialVersionUID is unchanged. Old field "component" is changed to 91 * type Object so that "poison" (unknown object type for old versions) 92 * can be put inside if there are huge components that cannot be saved 93 * as integers. 94 * 95 * New version use the new filed "encoding" only. 96 * 97 * Below are all 4 cases in a serialization/deserialization process: 98 * 99 * 1. old -> old: Not covered here 100 * 2. old -> new: There's no "encoding" field, new readObject() reads 101 * "components" and "componentLen" instead and inits correctly. 102 * 3. new -> new: "encoding" field exists, new readObject() uses it 103 * (ignoring the other 2 fields) and inits correctly. 104 * 4. new -> old: old readObject() only recognizes "components" and 105 * "componentLen" fields. If no huge components are involved, they 106 * are serialized as legal values and old object can init correctly. 107 * Otherwise, old object cannot recognize the form (component not int[]) 108 * and throw a ClassNotFoundException at deserialization time. 109 * 110 * Therfore, for the first 3 cases, exact compatibility is preserved. In 111 * the 4th case, non-huge OID is still supportable in old versions, while 112 * huge OID is not. 113 */ 114 private static final long serialVersionUID = 8697030238860181294L; 115 116 /** 117 * Changed to Object 118 * @serial 119 */ 120 private Object components = null; // path from root 121 /** 122 * @serial 123 */ 124 private int componentLen = -1; // how much is used. 125 126 // Is the components field calculated? 127 private transient boolean componentsCalculated = false; 128 readObject(ObjectInputStream is)129 private void readObject(ObjectInputStream is) 130 throws IOException, ClassNotFoundException { 131 is.defaultReadObject(); 132 133 if (encoding == null) { // from an old version 134 int[] comp = (int[])components; 135 if (componentLen > comp.length) { 136 componentLen = comp.length; 137 } 138 139 // Check the estimated size before it is too later. 140 checkOidSize(componentLen); 141 142 init(comp, componentLen); 143 } else { 144 checkOidSize(encoding.length); 145 } 146 } 147 writeObject(ObjectOutputStream os)148 private void writeObject(ObjectOutputStream os) 149 throws IOException { 150 if (!componentsCalculated) { 151 int[] comps = toIntArray(); 152 if (comps != null) { // every one understands this 153 components = comps; 154 componentLen = comps.length; 155 } else { 156 components = HugeOidNotSupportedByOldJDK.theOne; 157 } 158 componentsCalculated = true; 159 } 160 os.defaultWriteObject(); 161 } 162 163 static class HugeOidNotSupportedByOldJDK implements Serializable { 164 private static final long serialVersionUID = 1L; 165 static HugeOidNotSupportedByOldJDK theOne = new HugeOidNotSupportedByOldJDK(); 166 } 167 168 /** 169 * Constructs, from a string. This string should be of the form 1.23.56. 170 * Validity check included. 171 */ ObjectIdentifier(String oid)172 public ObjectIdentifier (String oid) throws IOException 173 { 174 int ch = '.'; 175 int start = 0; 176 int end = 0; 177 178 int pos = 0; 179 byte[] tmp = new byte[oid.length()]; 180 int first = 0, second; 181 int count = 0; 182 183 try { 184 String comp = null; 185 do { 186 int length = 0; // length of one section 187 end = oid.indexOf(ch,start); 188 if (end == -1) { 189 comp = oid.substring(start); 190 length = oid.length() - start; 191 } else { 192 comp = oid.substring(start,end); 193 length = end - start; 194 } 195 196 if (length > 9) { 197 BigInteger bignum = new BigInteger(comp); 198 if (count == 0) { 199 checkFirstComponent(bignum); 200 first = bignum.intValue(); 201 } else { 202 if (count == 1) { 203 checkSecondComponent(first, bignum); 204 bignum = bignum.add(BigInteger.valueOf(40*first)); 205 } else { 206 checkOtherComponent(count, bignum); 207 } 208 pos += pack7Oid(bignum, tmp, pos); 209 } 210 } else { 211 int num = Integer.parseInt(comp); 212 if (count == 0) { 213 checkFirstComponent(num); 214 first = num; 215 } else { 216 if (count == 1) { 217 checkSecondComponent(first, num); 218 num += 40 * first; 219 } else { 220 checkOtherComponent(count, num); 221 } 222 pos += pack7Oid(num, tmp, pos); 223 } 224 } 225 start = end + 1; 226 count++; 227 228 checkOidSize(pos); 229 } while (end != -1); 230 231 checkCount(count); 232 encoding = new byte[pos]; 233 System.arraycopy(tmp, 0, encoding, 0, pos); 234 this.stringForm = oid; 235 } catch (IOException ioe) { // already detected by checkXXX 236 throw ioe; 237 } catch (Exception e) { 238 throw new IOException("ObjectIdentifier() -- Invalid format: " 239 + e.toString(), e); 240 } 241 } 242 243 /** 244 * Constructor, from an array of integers. 245 * Validity check included. 246 */ ObjectIdentifier(int[] values)247 public ObjectIdentifier(int[] values) throws IOException 248 { 249 checkCount(values.length); 250 checkFirstComponent(values[0]); 251 checkSecondComponent(values[0], values[1]); 252 for (int i=2; i<values.length; i++) 253 checkOtherComponent(i, values[i]); 254 init(values, values.length); 255 } 256 257 /** 258 * Constructor, from an ASN.1 encoded input stream. 259 * Validity check NOT included. 260 * The encoding of the ID in the stream uses "DER", a BER/1 subset. 261 * In this case, that means a triple { typeId, length, data }. 262 * 263 * <P><STRONG>NOTE:</STRONG> When an exception is thrown, the 264 * input stream has not been returned to its "initial" state. 265 * 266 * @param in DER-encoded data holding an object ID 267 * @exception IOException indicates a decoding error 268 */ ObjectIdentifier(DerInputStream in)269 public ObjectIdentifier (DerInputStream in) throws IOException 270 { 271 byte type_id; 272 int bufferEnd; 273 274 /* 275 * Object IDs are a "universal" type, and their tag needs only 276 * one byte of encoding. Verify that the tag of this datum 277 * is that of an object ID. 278 * 279 * Then get and check the length of the ID's encoding. We set 280 * up so that we can use in.available() to check for the end of 281 * this value in the data stream. 282 */ 283 type_id = (byte) in.getByte (); 284 if (type_id != DerValue.tag_ObjectId) 285 throw new IOException ( 286 "ObjectIdentifier() -- data isn't an object ID" 287 + " (tag = " + type_id + ")" 288 ); 289 290 int len = in.getDefiniteLength(); 291 checkOidSize(len); 292 if (len > in.available()) { 293 throw new IOException("ObjectIdentifier length exceeds " + 294 "data available. Length: " + len + ", Available: " + 295 in.available()); 296 } 297 298 encoding = new byte[len]; 299 in.getBytes(encoding); 300 check(encoding); 301 } 302 303 /* 304 * Constructor, from the rest of a DER input buffer; 305 * the tag and length have been removed/verified 306 * Validity check NOT included. 307 */ ObjectIdentifier(DerInputBuffer buf)308 ObjectIdentifier (DerInputBuffer buf) throws IOException 309 { 310 DerInputStream in = new DerInputStream(buf); 311 int len = in.available(); 312 checkOidSize(len); 313 314 encoding = new byte[len]; 315 in.getBytes(encoding); 316 check(encoding); 317 } 318 init(int[] components, int length)319 private void init(int[] components, int length) throws IOException { 320 int pos = 0; 321 byte[] tmp = new byte[length * 5 + 1]; // +1 for empty input 322 323 if (components[1] < Integer.MAX_VALUE - components[0] * 40) { 324 pos += pack7Oid(components[0] * 40 + components[1], tmp, pos); 325 } else { 326 BigInteger big = BigInteger.valueOf(components[1]); 327 big = big.add(BigInteger.valueOf(components[0] * 40)); 328 pos += pack7Oid(big, tmp, pos); 329 } 330 331 for (int i = 2; i < length; i++) { 332 pos += pack7Oid(components[i], tmp, pos); 333 334 checkOidSize(pos); 335 } 336 337 encoding = new byte[pos]; 338 System.arraycopy(tmp, 0, encoding, 0, pos); 339 } 340 341 /** 342 * This method is kept for compatibility reasons. The new implementation 343 * does the check and conversion. All around the JDK, the method is called 344 * in static blocks to initialize pre-defined ObjectIdentifieies. No 345 * obvious performance hurt will be made after this change. 346 * 347 * Old doc: Create a new ObjectIdentifier for internal use. The values are 348 * neither checked nor cloned. 349 */ newInternal(int[] values)350 public static ObjectIdentifier newInternal(int[] values) { 351 try { 352 return new ObjectIdentifier(values); 353 } catch (IOException ex) { 354 throw new RuntimeException(ex); 355 // Should not happen, internal calls always uses legal values. 356 } 357 } 358 359 /* 360 * n.b. the only public interface is DerOutputStream.putOID() 361 */ encode(DerOutputStream out)362 void encode (DerOutputStream out) throws IOException 363 { 364 out.write (DerValue.tag_ObjectId, encoding); 365 } 366 367 /** 368 * Compares this identifier with another, for equality. 369 * 370 * @return true iff the names are identical. 371 */ 372 @Override equals(Object obj)373 public boolean equals(Object obj) { 374 if (this == obj) { 375 return true; 376 } 377 if (obj instanceof ObjectIdentifier == false) { 378 return false; 379 } 380 ObjectIdentifier other = (ObjectIdentifier)obj; 381 return Arrays.equals(encoding, other.encoding); 382 } 383 384 @Override hashCode()385 public int hashCode() { 386 return Arrays.hashCode(encoding); 387 } 388 389 /** 390 * Private helper method for serialization. To be compatible with old 391 * versions of JDK. 392 * @return components in an int array, if all the components are less than 393 * Integer.MAX_VALUE. Otherwise, null. 394 */ toIntArray()395 private int[] toIntArray() { 396 int length = encoding.length; 397 int[] result = new int[20]; 398 int which = 0; 399 int fromPos = 0; 400 for (int i = 0; i < length; i++) { 401 if ((encoding[i] & 0x80) == 0) { 402 // one section [fromPos..i] 403 if (i - fromPos + 1 > 4) { 404 BigInteger big = new BigInteger(pack(encoding, fromPos, i-fromPos+1, 7, 8)); 405 if (fromPos == 0) { 406 result[which++] = 2; 407 BigInteger second = big.subtract(BigInteger.valueOf(80)); 408 if (second.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) { 409 return null; 410 } else { 411 result[which++] = second.intValue(); 412 } 413 } else { 414 if (big.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) { 415 return null; 416 } else { 417 result[which++] = big.intValue(); 418 } 419 } 420 } else { 421 int retval = 0; 422 for (int j = fromPos; j <= i; j++) { 423 retval <<= 7; 424 byte tmp = encoding[j]; 425 retval |= (tmp & 0x07f); 426 } 427 if (fromPos == 0) { 428 if (retval < 80) { 429 result[which++] = retval / 40; 430 result[which++] = retval % 40; 431 } else { 432 result[which++] = 2; 433 result[which++] = retval - 80; 434 } 435 } else { 436 result[which++] = retval; 437 } 438 } 439 fromPos = i+1; 440 } 441 if (which >= result.length) { 442 result = Arrays.copyOf(result, which + 10); 443 } 444 } 445 return Arrays.copyOf(result, which); 446 } 447 448 /** 449 * Returns a string form of the object ID. The format is the 450 * conventional "dot" notation for such IDs, without any 451 * user-friendly descriptive strings, since those strings 452 * will not be understood everywhere. 453 */ 454 @Override toString()455 public String toString() { 456 String s = stringForm; 457 if (s == null) { 458 int length = encoding.length; 459 StringBuilder sb = new StringBuilder(length * 4); 460 461 int fromPos = 0; 462 for (int i = 0; i < length; i++) { 463 if ((encoding[i] & 0x80) == 0) { 464 // one section [fromPos..i] 465 if (fromPos != 0) { // not the first segment 466 sb.append('.'); 467 } 468 if (i - fromPos + 1 > 4) { // maybe big integer 469 BigInteger big = new BigInteger(pack(encoding, fromPos, i-fromPos+1, 7, 8)); 470 if (fromPos == 0) { 471 // first section encoded with more than 4 bytes, 472 // must be 2.something 473 sb.append("2."); 474 sb.append(big.subtract(BigInteger.valueOf(80))); 475 } else { 476 sb.append(big); 477 } 478 } else { // small integer 479 int retval = 0; 480 for (int j = fromPos; j <= i; j++) { 481 retval <<= 7; 482 byte tmp = encoding[j]; 483 retval |= (tmp & 0x07f); 484 } 485 if (fromPos == 0) { 486 if (retval < 80) { 487 sb.append(retval/40); 488 sb.append('.'); 489 sb.append(retval%40); 490 } else { 491 sb.append("2."); 492 sb.append(retval - 80); 493 } 494 } else { 495 sb.append(retval); 496 } 497 } 498 fromPos = i+1; 499 } 500 } 501 s = sb.toString(); 502 stringForm = s; 503 } 504 return s; 505 } 506 507 /** 508 * Repack all bits from input to output. On the both sides, only a portion 509 * (from the least significant bit) of the 8 bits in a byte is used. This 510 * number is defined as the number of useful bits (NUB) for the array. All the 511 * used bits from the input byte array and repacked into the output in the 512 * exactly same order. The output bits are aligned so that the final bit of 513 * the input (the least significant bit in the last byte), when repacked as 514 * the final bit of the output, is still at the least significant position. 515 * Zeroes will be padded on the left side of the first output byte if 516 * necessary. All unused bits in the output are also zeroed. 517 * 518 * For example: if the input is 01001100 with NUB 8, the output which 519 * has a NUB 6 will look like: 520 * 00000001 00001100 521 * The first 2 bits of the output bytes are unused bits. The other bits 522 * turn out to be 000001 001100. While the 8 bits on the right are from 523 * the input, the left 4 zeroes are padded to fill the 6 bits space. 524 * 525 * @param in the input byte array 526 * @param ioffset start point inside <code>in</code> 527 * @param ilength number of bytes to repack 528 * @param iw NUB for input 529 * @param ow NUB for output 530 * @return the repacked bytes 531 */ pack(byte[] in, int ioffset, int ilength, int iw, int ow)532 private static byte[] pack(byte[] in, int ioffset, int ilength, int iw, int ow) { 533 assert (iw > 0 && iw <= 8): "input NUB must be between 1 and 8"; 534 assert (ow > 0 && ow <= 8): "output NUB must be between 1 and 8"; 535 536 if (iw == ow) { 537 return in.clone(); 538 } 539 540 int bits = ilength * iw; // number of all used bits 541 byte[] out = new byte[(bits+ow-1)/ow]; 542 543 // starting from the 0th bit in the input 544 int ipos = 0; 545 546 // the number of padding 0's needed in the output, skip them 547 int opos = (bits+ow-1)/ow*ow-bits; 548 549 while(ipos < bits) { 550 int count = iw - ipos%iw; // unpacked bits in current input byte 551 if (count > ow - opos%ow) { // free space available in output byte 552 count = ow - opos%ow; // choose the smaller number 553 } 554 // and move them! 555 out[opos/ow] |= // paste! 556 (((in[ioffset+ipos/iw]+256) // locate the byte (+256 so that it's never negative) 557 >> (iw-ipos%iw-count)) // move to the end of a byte 558 & ((1 << (count))-1)) // zero out all other bits 559 << (ow-opos%ow-count); // move to the output position 560 ipos += count; // advance 561 opos += count; // advance 562 } 563 return out; 564 } 565 566 /** 567 * Repack from NUB 8 to a NUB 7 OID sub-identifier, remove all 568 * unnecessary 0 headings, set the first bit of all non-tail 569 * output bytes to 1 (as ITU-T Rec. X.690 8.19.2 says), and 570 * paste it into an existing byte array. 571 * @param out the existing array to be pasted into 572 * @param ooffset the starting position to paste 573 * @return the number of bytes pasted 574 */ pack7Oid(byte[] in, int ioffset, int ilength, byte[] out, int ooffset)575 private static int pack7Oid(byte[] in, int ioffset, int ilength, byte[] out, int ooffset) { 576 byte[] pack = pack(in, ioffset, ilength, 8, 7); 577 int firstNonZero = pack.length-1; // paste at least one byte 578 for (int i=pack.length-2; i>=0; i--) { 579 if (pack[i] != 0) { 580 firstNonZero = i; 581 } 582 pack[i] |= 0x80; 583 } 584 System.arraycopy(pack, firstNonZero, out, ooffset, pack.length-firstNonZero); 585 return pack.length-firstNonZero; 586 } 587 588 /** 589 * Repack from NUB 7 to NUB 8, remove all unnecessary 0 590 * headings, and paste it into an existing byte array. 591 * @param out the existing array to be pasted into 592 * @param ooffset the starting position to paste 593 * @return the number of bytes pasted 594 */ pack8(byte[] in, int ioffset, int ilength, byte[] out, int ooffset)595 private static int pack8(byte[] in, int ioffset, int ilength, byte[] out, int ooffset) { 596 byte[] pack = pack(in, ioffset, ilength, 7, 8); 597 int firstNonZero = pack.length-1; // paste at least one byte 598 for (int i=pack.length-2; i>=0; i--) { 599 if (pack[i] != 0) { 600 firstNonZero = i; 601 } 602 } 603 System.arraycopy(pack, firstNonZero, out, ooffset, pack.length-firstNonZero); 604 return pack.length-firstNonZero; 605 } 606 607 /** 608 * Pack the int into a OID sub-identifier DER encoding 609 */ pack7Oid(int input, byte[] out, int ooffset)610 private static int pack7Oid(int input, byte[] out, int ooffset) { 611 byte[] b = new byte[4]; 612 b[0] = (byte)(input >> 24); 613 b[1] = (byte)(input >> 16); 614 b[2] = (byte)(input >> 8); 615 b[3] = (byte)(input); 616 return pack7Oid(b, 0, 4, out, ooffset); 617 } 618 619 /** 620 * Pack the BigInteger into a OID subidentifier DER encoding 621 */ pack7Oid(BigInteger input, byte[] out, int ooffset)622 private static int pack7Oid(BigInteger input, byte[] out, int ooffset) { 623 byte[] b = input.toByteArray(); 624 return pack7Oid(b, 0, b.length, out, ooffset); 625 } 626 627 /** 628 * Private methods to check validity of OID. They must be -- 629 * 1. at least 2 components 630 * 2. all components must be non-negative 631 * 3. the first must be 0, 1 or 2 632 * 4. if the first is 0 or 1, the second must be <40 633 */ 634 635 /** 636 * Check the DER encoding. Since DER encoding defines that the integer bits 637 * are unsigned, so there's no need to check the MSB. 638 */ check(byte[] encoding)639 private static void check(byte[] encoding) throws IOException { 640 int length = encoding.length; 641 if (length < 1 || // too short 642 (encoding[length - 1] & 0x80) != 0) { // not ended 643 throw new IOException("ObjectIdentifier() -- " + 644 "Invalid DER encoding, not ended"); 645 } 646 for (int i=0; i<length; i++) { 647 // 0x80 at the beginning of a subidentifier 648 if (encoding[i] == (byte)0x80 && 649 (i==0 || (encoding[i-1] & 0x80) == 0)) { 650 throw new IOException("ObjectIdentifier() -- " + 651 "Invalid DER encoding, useless extra octet detected"); 652 } 653 } 654 } checkCount(int count)655 private static void checkCount(int count) throws IOException { 656 if (count < 2) { 657 throw new IOException("ObjectIdentifier() -- " + 658 "Must be at least two oid components "); 659 } 660 } checkFirstComponent(int first)661 private static void checkFirstComponent(int first) throws IOException { 662 if (first < 0 || first > 2) { 663 throw new IOException("ObjectIdentifier() -- " + 664 "First oid component is invalid "); 665 } 666 } checkFirstComponent(BigInteger first)667 private static void checkFirstComponent(BigInteger first) throws IOException { 668 if (first.signum() == -1 || first.compareTo(BigInteger.TWO) > 0) { 669 throw new IOException("ObjectIdentifier() -- " + 670 "First oid component is invalid "); 671 } 672 } checkSecondComponent(int first, int second)673 private static void checkSecondComponent(int first, int second) throws IOException { 674 if (second < 0 || first != 2 && second > 39) { 675 throw new IOException("ObjectIdentifier() -- " + 676 "Second oid component is invalid "); 677 } 678 } checkSecondComponent(int first, BigInteger second)679 private static void checkSecondComponent(int first, BigInteger second) throws IOException { 680 if (second.signum() == -1 || 681 first != 2 && 682 second.compareTo(BigInteger.valueOf(39)) == 1) { 683 throw new IOException("ObjectIdentifier() -- " + 684 "Second oid component is invalid "); 685 } 686 } checkOtherComponent(int i, int num)687 private static void checkOtherComponent(int i, int num) throws IOException { 688 if (num < 0) { 689 throw new IOException("ObjectIdentifier() -- " + 690 "oid component #" + (i+1) + " must be non-negative "); 691 } 692 } checkOtherComponent(int i, BigInteger num)693 private static void checkOtherComponent(int i, BigInteger num) throws IOException { 694 if (num.signum() == -1) { 695 throw new IOException("ObjectIdentifier() -- " + 696 "oid component #" + (i+1) + " must be non-negative "); 697 } 698 } 699 checkOidSize(int oidLength)700 private static void checkOidSize(int oidLength) throws IOException { 701 if (oidLength > MAXIMUM_OID_SIZE) { 702 throw new IOException( 703 "ObjectIdentifier encoded length exceeds " + 704 "the restriction in JDK (OId length(>=): " + oidLength + 705 ", Restriction: " + MAXIMUM_OID_SIZE + ")"); 706 } 707 } 708 } 709