Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/util/ObjectIdentifier.java
38830 views
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
final public
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
transient private boolean componentsCalculated = false;
128
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
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
*/
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
*/
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
*/
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
*/
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
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
*/
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
*/
362
void encode (DerOutputStream out) throws IOException
363
{
364
out.write (DerValue.tag_ObjectId, encoding);
365
}
366
367
/**
368
* @deprecated Use equals((Object)oid)
369
*/
370
@Deprecated
371
public boolean equals(ObjectIdentifier other) {
372
return equals((Object)other);
373
}
374
375
/**
376
* Compares this identifier with another, for equality.
377
*
378
* @return true iff the names are identical.
379
*/
380
@Override
381
public boolean equals(Object obj) {
382
if (this == obj) {
383
return true;
384
}
385
if (obj instanceof ObjectIdentifier == false) {
386
return false;
387
}
388
ObjectIdentifier other = (ObjectIdentifier)obj;
389
return Arrays.equals(encoding, other.encoding);
390
}
391
392
@Override
393
public int hashCode() {
394
return Arrays.hashCode(encoding);
395
}
396
397
/**
398
* Private helper method for serialization. To be compatible with old
399
* versions of JDK.
400
* @return components in an int array, if all the components are less than
401
* Integer.MAX_VALUE. Otherwise, null.
402
*/
403
private int[] toIntArray() {
404
int length = encoding.length;
405
int[] result = new int[20];
406
int which = 0;
407
int fromPos = 0;
408
for (int i = 0; i < length; i++) {
409
if ((encoding[i] & 0x80) == 0) {
410
// one section [fromPos..i]
411
if (i - fromPos + 1 > 4) {
412
BigInteger big = new BigInteger(pack(encoding, fromPos, i-fromPos+1, 7, 8));
413
if (fromPos == 0) {
414
result[which++] = 2;
415
BigInteger second = big.subtract(BigInteger.valueOf(80));
416
if (second.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) {
417
return null;
418
} else {
419
result[which++] = second.intValue();
420
}
421
} else {
422
if (big.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) {
423
return null;
424
} else {
425
result[which++] = big.intValue();
426
}
427
}
428
} else {
429
int retval = 0;
430
for (int j = fromPos; j <= i; j++) {
431
retval <<= 7;
432
byte tmp = encoding[j];
433
retval |= (tmp & 0x07f);
434
}
435
if (fromPos == 0) {
436
if (retval < 80) {
437
result[which++] = retval / 40;
438
result[which++] = retval % 40;
439
} else {
440
result[which++] = 2;
441
result[which++] = retval - 80;
442
}
443
} else {
444
result[which++] = retval;
445
}
446
}
447
fromPos = i+1;
448
}
449
if (which >= result.length) {
450
result = Arrays.copyOf(result, which + 10);
451
}
452
}
453
return Arrays.copyOf(result, which);
454
}
455
456
/**
457
* Returns a string form of the object ID. The format is the
458
* conventional "dot" notation for such IDs, without any
459
* user-friendly descriptive strings, since those strings
460
* will not be understood everywhere.
461
*/
462
@Override
463
public String toString() {
464
String s = stringForm;
465
if (s == null) {
466
int length = encoding.length;
467
StringBuffer sb = new StringBuffer(length * 4);
468
469
int fromPos = 0;
470
for (int i = 0; i < length; i++) {
471
if ((encoding[i] & 0x80) == 0) {
472
// one section [fromPos..i]
473
if (fromPos != 0) { // not the first segment
474
sb.append('.');
475
}
476
if (i - fromPos + 1 > 4) { // maybe big integer
477
BigInteger big = new BigInteger(pack(encoding, fromPos, i-fromPos+1, 7, 8));
478
if (fromPos == 0) {
479
// first section encoded with more than 4 bytes,
480
// must be 2.something
481
sb.append("2.");
482
sb.append(big.subtract(BigInteger.valueOf(80)));
483
} else {
484
sb.append(big);
485
}
486
} else { // small integer
487
int retval = 0;
488
for (int j = fromPos; j <= i; j++) {
489
retval <<= 7;
490
byte tmp = encoding[j];
491
retval |= (tmp & 0x07f);
492
}
493
if (fromPos == 0) {
494
if (retval < 80) {
495
sb.append(retval/40);
496
sb.append('.');
497
sb.append(retval%40);
498
} else {
499
sb.append("2.");
500
sb.append(retval - 80);
501
}
502
} else {
503
sb.append(retval);
504
}
505
}
506
fromPos = i+1;
507
}
508
}
509
s = sb.toString();
510
stringForm = s;
511
}
512
return s;
513
}
514
515
/**
516
* Repack all bits from input to output. On the both sides, only a portion
517
* (from the least significant bit) of the 8 bits in a byte is used. This
518
* number is defined as the number of useful bits (NUB) for the array. All the
519
* used bits from the input byte array and repacked into the output in the
520
* exactly same order. The output bits are aligned so that the final bit of
521
* the input (the least significant bit in the last byte), when repacked as
522
* the final bit of the output, is still at the least significant position.
523
* Zeroes will be padded on the left side of the first output byte if
524
* necessary. All unused bits in the output are also zeroed.
525
*
526
* For example: if the input is 01001100 with NUB 8, the output which
527
* has a NUB 6 will look like:
528
* 00000001 00001100
529
* The first 2 bits of the output bytes are unused bits. The other bits
530
* turn out to be 000001 001100. While the 8 bits on the right are from
531
* the input, the left 4 zeroes are padded to fill the 6 bits space.
532
*
533
* @param in the input byte array
534
* @param ioffset start point inside <code>in</code>
535
* @param ilength number of bytes to repack
536
* @param iw NUB for input
537
* @param ow NUB for output
538
* @return the repacked bytes
539
*/
540
private static byte[] pack(byte[] in, int ioffset, int ilength, int iw, int ow) {
541
assert (iw > 0 && iw <= 8): "input NUB must be between 1 and 8";
542
assert (ow > 0 && ow <= 8): "output NUB must be between 1 and 8";
543
544
if (iw == ow) {
545
return in.clone();
546
}
547
548
int bits = ilength * iw; // number of all used bits
549
byte[] out = new byte[(bits+ow-1)/ow];
550
551
// starting from the 0th bit in the input
552
int ipos = 0;
553
554
// the number of padding 0's needed in the output, skip them
555
int opos = (bits+ow-1)/ow*ow-bits;
556
557
while(ipos < bits) {
558
int count = iw - ipos%iw; // unpacked bits in current input byte
559
if (count > ow - opos%ow) { // free space available in output byte
560
count = ow - opos%ow; // choose the smaller number
561
}
562
// and move them!
563
out[opos/ow] |= // paste!
564
(((in[ioffset+ipos/iw]+256) // locate the byte (+256 so that it's never negative)
565
>> (iw-ipos%iw-count)) // move to the end of a byte
566
& ((1 << (count))-1)) // zero out all other bits
567
<< (ow-opos%ow-count); // move to the output position
568
ipos += count; // advance
569
opos += count; // advance
570
}
571
return out;
572
}
573
574
/**
575
* Repack from NUB 8 to a NUB 7 OID sub-identifier, remove all
576
* unnecessary 0 headings, set the first bit of all non-tail
577
* output bytes to 1 (as ITU-T Rec. X.690 8.19.2 says), and
578
* paste it into an existing byte array.
579
* @param out the existing array to be pasted into
580
* @param ooffset the starting position to paste
581
* @return the number of bytes pasted
582
*/
583
private static int pack7Oid(byte[] in, int ioffset, int ilength, byte[] out, int ooffset) {
584
byte[] pack = pack(in, ioffset, ilength, 8, 7);
585
int firstNonZero = pack.length-1; // paste at least one byte
586
for (int i=pack.length-2; i>=0; i--) {
587
if (pack[i] != 0) {
588
firstNonZero = i;
589
}
590
pack[i] |= 0x80;
591
}
592
System.arraycopy(pack, firstNonZero, out, ooffset, pack.length-firstNonZero);
593
return pack.length-firstNonZero;
594
}
595
596
/**
597
* Repack from NUB 7 to NUB 8, remove all unnecessary 0
598
* headings, and paste it into an existing byte array.
599
* @param out the existing array to be pasted into
600
* @param ooffset the starting position to paste
601
* @return the number of bytes pasted
602
*/
603
private static int pack8(byte[] in, int ioffset, int ilength, byte[] out, int ooffset) {
604
byte[] pack = pack(in, ioffset, ilength, 7, 8);
605
int firstNonZero = pack.length-1; // paste at least one byte
606
for (int i=pack.length-2; i>=0; i--) {
607
if (pack[i] != 0) {
608
firstNonZero = i;
609
}
610
}
611
System.arraycopy(pack, firstNonZero, out, ooffset, pack.length-firstNonZero);
612
return pack.length-firstNonZero;
613
}
614
615
/**
616
* Pack the int into a OID sub-identifier DER encoding
617
*/
618
private static int pack7Oid(int input, byte[] out, int ooffset) {
619
byte[] b = new byte[4];
620
b[0] = (byte)(input >> 24);
621
b[1] = (byte)(input >> 16);
622
b[2] = (byte)(input >> 8);
623
b[3] = (byte)(input);
624
return pack7Oid(b, 0, 4, out, ooffset);
625
}
626
627
/**
628
* Pack the BigInteger into a OID subidentifier DER encoding
629
*/
630
private static int pack7Oid(BigInteger input, byte[] out, int ooffset) {
631
byte[] b = input.toByteArray();
632
return pack7Oid(b, 0, b.length, out, ooffset);
633
}
634
635
/**
636
* Private methods to check validity of OID. They must be --
637
* 1. at least 2 components
638
* 2. all components must be non-negative
639
* 3. the first must be 0, 1 or 2
640
* 4. if the first is 0 or 1, the second must be <40
641
*/
642
643
/**
644
* Check the DER encoding. Since DER encoding defines that the integer bits
645
* are unsigned, so there's no need to check the MSB.
646
*/
647
private static void check(byte[] encoding) throws IOException {
648
int length = encoding.length;
649
if (length < 1 || // too short
650
(encoding[length - 1] & 0x80) != 0) { // not ended
651
throw new IOException("ObjectIdentifier() -- " +
652
"Invalid DER encoding, not ended");
653
}
654
for (int i=0; i<length; i++) {
655
// 0x80 at the beginning of a subidentifier
656
if (encoding[i] == (byte)0x80 &&
657
(i==0 || (encoding[i-1] & 0x80) == 0)) {
658
throw new IOException("ObjectIdentifier() -- " +
659
"Invalid DER encoding, useless extra octet detected");
660
}
661
}
662
}
663
private static void checkCount(int count) throws IOException {
664
if (count < 2) {
665
throw new IOException("ObjectIdentifier() -- " +
666
"Must be at least two oid components ");
667
}
668
}
669
private static void checkFirstComponent(int first) throws IOException {
670
if (first < 0 || first > 2) {
671
throw new IOException("ObjectIdentifier() -- " +
672
"First oid component is invalid ");
673
}
674
}
675
private static void checkFirstComponent(BigInteger first) throws IOException {
676
if (first.signum() == -1 ||
677
first.compareTo(BigInteger.valueOf(2)) == 1) {
678
throw new IOException("ObjectIdentifier() -- " +
679
"First oid component is invalid ");
680
}
681
}
682
private static void checkSecondComponent(int first, int second) throws IOException {
683
if (second < 0 || first != 2 && second > 39) {
684
throw new IOException("ObjectIdentifier() -- " +
685
"Second oid component is invalid ");
686
}
687
}
688
private static void checkSecondComponent(int first, BigInteger second) throws IOException {
689
if (second.signum() == -1 ||
690
first != 2 &&
691
second.compareTo(BigInteger.valueOf(39)) == 1) {
692
throw new IOException("ObjectIdentifier() -- " +
693
"Second oid component is invalid ");
694
}
695
}
696
private static void checkOtherComponent(int i, int num) throws IOException {
697
if (num < 0) {
698
throw new IOException("ObjectIdentifier() -- " +
699
"oid component #" + (i+1) + " must be non-negative ");
700
}
701
}
702
private static void checkOtherComponent(int i, BigInteger num) throws IOException {
703
if (num.signum() == -1) {
704
throw new IOException("ObjectIdentifier() -- " +
705
"oid component #" + (i+1) + " must be non-negative ");
706
}
707
}
708
709
private static void checkOidSize(int oidLength) throws IOException {
710
if (oidLength > MAXIMUM_OID_SIZE) {
711
throw new IOException(
712
"ObjectIdentifier encoded length exceeds " +
713
"the restriction in JDK (OId length(>=): " + oidLength +
714
", Restriction: " + MAXIMUM_OID_SIZE + ")");
715
}
716
}
717
}
718
719