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