History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/util/ObjectIdentifier.java (1 of 18352 files). Show all

Unified · Split

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