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/DerInputBuffer.java
38830 views
1
/*
2
* Copyright (c) 1996, 2020, 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.ByteArrayInputStream;
29
import java.io.IOException;
30
import java.math.BigInteger;
31
import java.util.Date;
32
import sun.util.calendar.CalendarDate;
33
import sun.util.calendar.CalendarSystem;
34
35
/**
36
* DER input buffer ... this is the main abstraction in the DER library
37
* which actively works with the "untyped byte stream" abstraction. It
38
* does so with impunity, since it's not intended to be exposed to
39
* anyone who could violate the "typed value stream" DER model and hence
40
* corrupt the input stream of DER values.
41
*
42
* @author David Brownell
43
*/
44
class DerInputBuffer extends ByteArrayInputStream implements Cloneable {
45
46
boolean allowBER = true;
47
48
// used by sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java
49
DerInputBuffer(byte[] buf) {
50
this(buf, true);
51
}
52
53
DerInputBuffer(byte[] buf, boolean allowBER) {
54
super(buf);
55
this.allowBER = allowBER;
56
}
57
58
DerInputBuffer(byte[] buf, int offset, int len, boolean allowBER) {
59
super(buf, offset, len);
60
this.allowBER = allowBER;
61
}
62
63
DerInputBuffer dup() {
64
try {
65
DerInputBuffer retval = (DerInputBuffer)clone();
66
retval.mark(Integer.MAX_VALUE);
67
return retval;
68
} catch (CloneNotSupportedException e) {
69
throw new IllegalArgumentException(e.toString());
70
}
71
}
72
73
byte[] toByteArray() {
74
int len = available();
75
if (len <= 0)
76
return null;
77
byte[] retval = new byte[len];
78
79
System.arraycopy(buf, pos, retval, 0, len);
80
return retval;
81
}
82
83
int peek() throws IOException {
84
if (pos >= count)
85
throw new IOException("out of data");
86
else
87
return buf[pos];
88
}
89
90
/**
91
* Compares this DerInputBuffer for equality with the specified
92
* object.
93
*/
94
public boolean equals(Object other) {
95
if (other instanceof DerInputBuffer)
96
return equals((DerInputBuffer)other);
97
else
98
return false;
99
}
100
101
boolean equals(DerInputBuffer other) {
102
if (this == other)
103
return true;
104
105
int max = this.available();
106
if (other.available() != max)
107
return false;
108
for (int i = 0; i < max; i++) {
109
if (this.buf[this.pos + i] != other.buf[other.pos + i]) {
110
return false;
111
}
112
}
113
return true;
114
}
115
116
/**
117
* Returns a hashcode for this DerInputBuffer.
118
*
119
* @return a hashcode for this DerInputBuffer.
120
*/
121
public int hashCode() {
122
int retval = 0;
123
124
int len = available();
125
int p = pos;
126
127
for (int i = 0; i < len; i++)
128
retval += buf[p + i] * i;
129
return retval;
130
}
131
132
void truncate(int len) throws IOException {
133
if (len > available())
134
throw new IOException("insufficient data");
135
count = pos + len;
136
}
137
138
/**
139
* Returns the integer which takes up the specified number
140
* of bytes in this buffer as a BigInteger.
141
* @param len the number of bytes to use.
142
* @param makePositive whether to always return a positive value,
143
* irrespective of actual encoding
144
* @return the integer as a BigInteger.
145
*/
146
BigInteger getBigInteger(int len, boolean makePositive) throws IOException {
147
if (len > available())
148
throw new IOException("short read of integer");
149
150
if (len == 0) {
151
throw new IOException("Invalid encoding: zero length Int value");
152
}
153
154
byte[] bytes = new byte[len];
155
156
System.arraycopy(buf, pos, bytes, 0, len);
157
skip(len);
158
159
// BER allows leading 0s but DER does not
160
if (!allowBER && (len >= 2 && (bytes[0] == 0) && (bytes[1] >= 0))) {
161
throw new IOException("Invalid encoding: redundant leading 0s");
162
}
163
164
if (makePositive) {
165
return new BigInteger(1, bytes);
166
} else {
167
return new BigInteger(bytes);
168
}
169
}
170
171
/**
172
* Returns the integer which takes up the specified number
173
* of bytes in this buffer.
174
* @throws IOException if the result is not within the valid
175
* range for integer, i.e. between Integer.MIN_VALUE and
176
* Integer.MAX_VALUE.
177
* @param len the number of bytes to use.
178
* @return the integer.
179
*/
180
public int getInteger(int len) throws IOException {
181
182
BigInteger result = getBigInteger(len, false);
183
if (result.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) {
184
throw new IOException("Integer below minimum valid value");
185
}
186
if (result.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
187
throw new IOException("Integer exceeds maximum valid value");
188
}
189
return result.intValue();
190
}
191
192
/**
193
* Returns the bit string which takes up the specified
194
* number of bytes in this buffer.
195
*/
196
public byte[] getBitString(int len) throws IOException {
197
if (len > available())
198
throw new IOException("short read of bit string");
199
200
if (len == 0) {
201
throw new IOException("Invalid encoding: zero length bit string");
202
}
203
204
int numOfPadBits = buf[pos];
205
if ((numOfPadBits < 0) || (numOfPadBits > 7)) {
206
throw new IOException("Invalid number of padding bits");
207
}
208
// minus the first byte which indicates the number of padding bits
209
byte[] retval = new byte[len - 1];
210
System.arraycopy(buf, pos + 1, retval, 0, len - 1);
211
if (numOfPadBits != 0) {
212
// get rid of the padding bits
213
retval[len - 2] &= (0xff << numOfPadBits);
214
}
215
skip(len);
216
return retval;
217
}
218
219
/**
220
* Returns the bit string which takes up the rest of this buffer.
221
*/
222
byte[] getBitString() throws IOException {
223
return getBitString(available());
224
}
225
226
/**
227
* Returns the bit string which takes up the rest of this buffer.
228
* The bit string need not be byte-aligned.
229
*/
230
BitArray getUnalignedBitString() throws IOException {
231
if (pos >= count)
232
return null;
233
/*
234
* Just copy the data into an aligned, padded octet buffer,
235
* and consume the rest of the buffer.
236
*/
237
int len = available();
238
int unusedBits = buf[pos] & 0xff;
239
if (unusedBits > 7 ) {
240
throw new IOException("Invalid value for unused bits: " + unusedBits);
241
}
242
byte[] bits = new byte[len - 1];
243
// number of valid bits
244
int length = (bits.length == 0) ? 0 : bits.length * 8 - unusedBits;
245
246
System.arraycopy(buf, pos + 1, bits, 0, len - 1);
247
248
BitArray bitArray = new BitArray(length, bits);
249
pos = count;
250
return bitArray;
251
}
252
253
/**
254
* Returns the UTC Time value that takes up the specified number
255
* of bytes in this buffer.
256
* @param len the number of bytes to use
257
*/
258
public Date getUTCTime(int len) throws IOException {
259
if (len > available())
260
throw new IOException("short read of DER UTC Time");
261
262
if (len < 11 || len > 17)
263
throw new IOException("DER UTC Time length error");
264
265
return getTime(len, false);
266
}
267
268
/**
269
* Returns the Generalized Time value that takes up the specified
270
* number of bytes in this buffer.
271
* @param len the number of bytes to use
272
*/
273
public Date getGeneralizedTime(int len) throws IOException {
274
if (len > available())
275
throw new IOException("short read of DER Generalized Time");
276
277
if (len < 13)
278
throw new IOException("DER Generalized Time length error");
279
280
return getTime(len, true);
281
282
}
283
284
/**
285
* Private helper routine to extract time from the der value.
286
* @param len the number of bytes to use
287
* @param generalized true if Generalized Time is to be read, false
288
* if UTC Time is to be read.
289
*/
290
private Date getTime(int len, boolean generalized) throws IOException {
291
292
/*
293
* UTC time encoded as ASCII chars:
294
* YYMMDDhhmmZ
295
* YYMMDDhhmmssZ
296
* YYMMDDhhmm+hhmm
297
* YYMMDDhhmm-hhmm
298
* YYMMDDhhmmss+hhmm
299
* YYMMDDhhmmss-hhmm
300
* UTC Time is broken in storing only two digits of year.
301
* If YY < 50, we assume 20YY;
302
* if YY >= 50, we assume 19YY, as per RFC 5280.
303
*
304
* Generalized time has a four-digit year and allows any
305
* precision specified in ISO 8601. However, for our purposes,
306
* we will only allow the same format as UTC time, except that
307
* fractional seconds (millisecond precision) are supported.
308
*/
309
310
int year, month, day, hour, minute, second, millis;
311
String type = null;
312
313
if (generalized) {
314
type = "Generalized";
315
year = 1000 * toDigit(buf[pos++], type);
316
year += 100 * toDigit(buf[pos++], type);
317
year += 10 * toDigit(buf[pos++], type);
318
year += toDigit(buf[pos++], type);
319
len -= 2; // For the two extra YY
320
} else {
321
type = "UTC";
322
year = 10 * toDigit(buf[pos++], type);
323
year += toDigit(buf[pos++], type);
324
325
if (year < 50) // origin 2000
326
year += 2000;
327
else
328
year += 1900; // origin 1900
329
}
330
331
month = 10 * toDigit(buf[pos++], type);
332
month += toDigit(buf[pos++], type);
333
334
day = 10 * toDigit(buf[pos++], type);
335
day += toDigit(buf[pos++], type);
336
337
hour = 10 * toDigit(buf[pos++], type);
338
hour += toDigit(buf[pos++], type);
339
340
minute = 10 * toDigit(buf[pos++], type);
341
minute += toDigit(buf[pos++], type);
342
343
len -= 10; // YYMMDDhhmm
344
345
/*
346
* We allow for non-encoded seconds, even though the
347
* IETF-PKIX specification says that the seconds should
348
* always be encoded even if it is zero.
349
*/
350
351
millis = 0;
352
if (len > 2) {
353
second = 10 * toDigit(buf[pos++], type);
354
second += toDigit(buf[pos++], type);
355
len -= 2;
356
// handle fractional seconds (if present)
357
if (generalized && (buf[pos] == '.' || buf[pos] == ',')) {
358
len --;
359
if (len == 0) {
360
throw new IOException("Parse " + type +
361
" time, empty fractional part");
362
}
363
pos++;
364
int precision = 0;
365
while (buf[pos] != 'Z' &&
366
buf[pos] != '+' &&
367
buf[pos] != '-') {
368
// Validate all digits in the fractional part but
369
// store millisecond precision only
370
int thisDigit = toDigit(buf[pos], type);
371
precision++;
372
len--;
373
if (len == 0) {
374
throw new IOException("Parse " + type +
375
" time, invalid fractional part");
376
}
377
pos++;
378
switch (precision) {
379
case 1:
380
millis += 100 * thisDigit;
381
break;
382
case 2:
383
millis += 10 * thisDigit;
384
break;
385
case 3:
386
millis += thisDigit;
387
break;
388
}
389
}
390
if (precision == 0) {
391
throw new IOException("Parse " + type +
392
" time, empty fractional part");
393
}
394
}
395
} else
396
second = 0;
397
398
if (month == 0 || day == 0
399
|| month > 12 || day > 31
400
|| hour >= 24 || minute >= 60 || second >= 60)
401
throw new IOException("Parse " + type + " time, invalid format");
402
403
/*
404
* Generalized time can theoretically allow any precision,
405
* but we're not supporting that.
406
*/
407
CalendarSystem gcal = CalendarSystem.getGregorianCalendar();
408
CalendarDate date = gcal.newCalendarDate(null); // no time zone
409
date.setDate(year, month, day);
410
date.setTimeOfDay(hour, minute, second, millis);
411
long time = gcal.getTime(date);
412
413
/*
414
* Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm
415
*/
416
if (! (len == 1 || len == 5))
417
throw new IOException("Parse " + type + " time, invalid offset");
418
419
int hr, min;
420
421
switch (buf[pos++]) {
422
case '+':
423
if (len != 5) {
424
throw new IOException("Parse " + type + " time, invalid offset");
425
}
426
hr = 10 * toDigit(buf[pos++], type);
427
hr += toDigit(buf[pos++], type);
428
min = 10 * toDigit(buf[pos++], type);
429
min += toDigit(buf[pos++], type);
430
431
if (hr >= 24 || min >= 60)
432
throw new IOException("Parse " + type + " time, +hhmm");
433
434
time -= ((hr * 60) + min) * 60 * 1000;
435
break;
436
437
case '-':
438
if (len != 5) {
439
throw new IOException("Parse " + type + " time, invalid offset");
440
}
441
hr = 10 * toDigit(buf[pos++], type);
442
hr += toDigit(buf[pos++], type);
443
min = 10 * toDigit(buf[pos++], type);
444
min += toDigit(buf[pos++], type);
445
446
if (hr >= 24 || min >= 60)
447
throw new IOException("Parse " + type + " time, -hhmm");
448
449
time += ((hr * 60) + min) * 60 * 1000;
450
break;
451
452
case 'Z':
453
if (len != 1) {
454
throw new IOException("Parse " + type + " time, invalid format");
455
}
456
break;
457
458
default:
459
throw new IOException("Parse " + type + " time, garbage offset");
460
}
461
return new Date(time);
462
}
463
464
/**
465
* Converts byte (represented as a char) to int.
466
* @throws IOException if integer is not a valid digit in the specified
467
* radix (10)
468
*/
469
private static int toDigit(byte b, String type) throws IOException {
470
if (b < '0' || b > '9') {
471
throw new IOException("Parse " + type + " time, invalid format");
472
}
473
return b - '0';
474
}
475
}
476
477