1 /*
2 * Copyright (c) 1996, 2016, 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
64 * awkward to deal with. That's where BER is useful, since BER
65 * handles streaming data relatively well.
66 */
67 DerInputBuffer buffer;
68
69 /** The DER tag of the value; one of the tag_ constants. */
70 public byte tag;
71
72 /**
73 * Create a DER input stream from a data buffer. The buffer is not
74 * copied, it is shared. Accordingly, the buffer should be treated
75 * as read-only.
76 *
77 * @param data the buffer from which to create the string (CONSUMED)
78 */
79 public DerInputStream(byte[] data) throws IOException {
80 init(data, 0, data.length, true);
81 }
82
83 /**
84 * Create a DER input stream from part of a data buffer.
85 * The buffer is not copied, it is shared. Accordingly, the
86 * buffer should be treated as read-only.
87 *
88 * @param data the buffer from which to create the string (CONSUMED)
89 * @param offset the first index of <em>data</em> which will
90 * be read as DER input in the new stream
91 * @param len how long a chunk of the buffer to use,
92 * starting at "offset"
93 */
94 public DerInputStream(byte[] data, int offset, int len) throws IOException {
95 init(data, offset, len, true);
96 }
97
98 /**
99 * Create a DER input stream from part of a data buffer with
100 * additional arg to indicate whether to allow constructed
101 * indefinite-length encoding.
102 * The buffer is not copied, it is shared. Accordingly, the
103 * buffer should be treated as read-only.
104 *
105 * @param data the buffer from which to create the string (CONSUMED)
106 * @param offset the first index of <em>data</em> which will
107 * be read as DER input in the new stream
108 * @param len how long a chunk of the buffer to use,
109 * starting at "offset"
110 * @param allowIndefiniteLength whether to allow constructed
111 * indefinite-length encoding
112 */
113 public DerInputStream(byte[] data, int offset, int len,
114 boolean allowIndefiniteLength) throws IOException {
115 init(data, offset, len, allowIndefiniteLength);
116 }
117
118 /*
119 * private helper routine
120 */
121 private void init(byte[] data, int offset, int len,
122 boolean allowIndefiniteLength) throws IOException {
123 if ((offset+2 > data.length) || (offset+len > data.length)) {
124 throw new IOException("Encoding bytes too short");
125 }
126 // check for indefinite length encoding
127 if (DerIndefLenConverter.isIndefinite(data[offset+1])) {
128 if (!allowIndefiniteLength) {
129 throw new IOException("Indefinite length BER encoding found");
130 } else {
131 byte[] inData = new byte[len];
132 System.arraycopy(data, offset, inData, 0, len);
133
134 DerIndefLenConverter derIn = new DerIndefLenConverter();
135 buffer = new DerInputBuffer(derIn.convert(inData));
136 }
137 } else
138 buffer = new DerInputBuffer(data, offset, len);
139 buffer.mark(Integer.MAX_VALUE);
140 }
141
142 DerInputStream(DerInputBuffer buf) {
143 buffer = buf;
144 buffer.mark(Integer.MAX_VALUE);
145 }
146
147 /**
148 * Creates a new DER input stream from part of this input stream.
149 *
150 * @param len how long a chunk of the current input stream to use,
151 * starting at the current position.
152 * @param do_skip true if the existing data in the input stream should
153 * be skipped. If this value is false, the next data read
154 * on this stream and the newly created stream will be the
155 * same.
156 */
157 public DerInputStream subStream(int len, boolean do_skip)
158 throws IOException {
382 * same encoding, except for the initial tag, so both use
383 * this same helper routine.
384 */
385 protected DerValue[] readVector(int startLen) throws IOException {
386 DerInputStream newstr;
387
388 byte lenByte = (byte)buffer.read();
389 int len = getLength(lenByte, buffer);
390
391 if (len == -1) {
392 // indefinite length encoding found
393 int readLen = buffer.available();
394 int offset = 2; // for tag and length bytes
395 byte[] indefData = new byte[readLen + offset];
396 indefData[0] = tag;
397 indefData[1] = lenByte;
398 DataInputStream dis = new DataInputStream(buffer);
399 dis.readFully(indefData, offset, readLen);
400 dis.close();
401 DerIndefLenConverter derIn = new DerIndefLenConverter();
402 buffer = new DerInputBuffer(derIn.convert(indefData));
403 if (tag != buffer.read())
404 throw new IOException("Indefinite length encoding" +
405 " not supported");
406 len = DerInputStream.getDefiniteLength(buffer);
407 }
408
409 if (len == 0)
410 // return empty array instead of null, which should be
411 // used only for missing optionals
412 return new DerValue[0];
413
414 /*
415 * Create a temporary stream from which to read the data,
416 * unless it's not really needed.
417 */
418 if (buffer.available() == len)
419 newstr = this;
420 else
421 newstr = subStream(len, true);
422
423 /*
424 * Pull values out of the stream.
425 */
426 Vector<DerValue> vec = new Vector<>(startLen);
427 DerValue value;
428
429 do {
430 value = new DerValue(newstr.buffer);
431 vec.addElement(value);
432 } while (newstr.available() > 0);
433
434 if (newstr.available() != 0)
435 throw new IOException("Extra data at end of vector");
436
437 /*
438 * Now stick them into the array we're returning.
439 */
440 int i, max = vec.size();
441 DerValue[] retval = new DerValue[max];
442
443 for (i = 0; i < max; i++)
444 retval[i] = vec.elementAt(i);
445
446 return retval;
447 }
448
449 /**
450 * Get a single DER-encoded value from the input stream.
|
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
64 * awkward to deal with. That's where BER is useful, since BER
65 * handles streaming data relatively well.
66 */
67 DerInputBuffer buffer;
68
69 /** The DER tag of the value; one of the tag_ constants. */
70 public byte tag;
71
72 /**
73 * Create a DER input stream from a data buffer. The buffer is not
74 * copied, it is shared. Accordingly, the buffer should be treated
75 * as read-only.
76 *
77 * @param data the buffer from which to create the string (CONSUMED)
78 */
79 public DerInputStream(byte[] data) throws IOException {
80 init(data, 0, data.length, true);
81 }
82
83 /**
84 * Create a DER input stream from part of a data buffer with
85 * additional arg to control whether DER checks are enforced.
86 * The buffer is not copied, it is shared. Accordingly, the
87 * buffer should be treated as read-only.
88 *
89 * @param data the buffer from which to create the string (CONSUMED)
90 * @param offset the first index of <em>data</em> which will
91 * be read as DER input in the new stream
92 * @param len how long a chunk of the buffer to use,
93 * starting at "offset"
94 * @param allowBER whether to allow constructed indefinite-length
95 * encoding as well as tolerate leading 0s
96 */
97 public DerInputStream(byte[] data, int offset, int len,
98 boolean allowBER) throws IOException {
99 init(data, offset, len, allowBER);
100 }
101
102 /**
103 * Create a DER input stream from part of a data buffer.
104 * The buffer is not copied, it is shared. Accordingly, the
105 * buffer should be treated as read-only.
106 *
107 * @param data the buffer from which to create the string (CONSUMED)
108 * @param offset the first index of <em>data</em> which will
109 * be read as DER input in the new stream
110 * @param len how long a chunk of the buffer to use,
111 * starting at "offset"
112 */
113 public DerInputStream(byte[] data, int offset, int len) throws IOException {
114 init(data, offset, len, true);
115 }
116
117 /*
118 * private helper routine
119 */
120 private void init(byte[] data, int offset, int len, boolean allowBER) throws IOException {
121 if ((offset+2 > data.length) || (offset+len > data.length)) {
122 throw new IOException("Encoding bytes too short");
123 }
124 // check for indefinite length encoding
125 if (DerIndefLenConverter.isIndefinite(data[offset+1])) {
126 if (!allowBER) {
127 throw new IOException("Indefinite length BER encoding found");
128 } else {
129 byte[] inData = new byte[len];
130 System.arraycopy(data, offset, inData, 0, len);
131
132 DerIndefLenConverter derIn = new DerIndefLenConverter();
133 buffer = new DerInputBuffer(derIn.convert(inData), allowBER);
134 }
135 } else {
136 buffer = new DerInputBuffer(data, offset, len, allowBER);
137 }
138 buffer.mark(Integer.MAX_VALUE);
139 }
140
141 DerInputStream(DerInputBuffer buf) {
142 buffer = buf;
143 buffer.mark(Integer.MAX_VALUE);
144 }
145
146 /**
147 * Creates a new DER input stream from part of this input stream.
148 *
149 * @param len how long a chunk of the current input stream to use,
150 * starting at the current position.
151 * @param do_skip true if the existing data in the input stream should
152 * be skipped. If this value is false, the next data read
153 * on this stream and the newly created stream will be the
154 * same.
155 */
156 public DerInputStream subStream(int len, boolean do_skip)
157 throws IOException {
381 * same encoding, except for the initial tag, so both use
382 * this same helper routine.
383 */
384 protected DerValue[] readVector(int startLen) throws IOException {
385 DerInputStream newstr;
386
387 byte lenByte = (byte)buffer.read();
388 int len = getLength(lenByte, buffer);
389
390 if (len == -1) {
391 // indefinite length encoding found
392 int readLen = buffer.available();
393 int offset = 2; // for tag and length bytes
394 byte[] indefData = new byte[readLen + offset];
395 indefData[0] = tag;
396 indefData[1] = lenByte;
397 DataInputStream dis = new DataInputStream(buffer);
398 dis.readFully(indefData, offset, readLen);
399 dis.close();
400 DerIndefLenConverter derIn = new DerIndefLenConverter();
401 buffer = new DerInputBuffer(derIn.convert(indefData), buffer.allowBER);
402
403 if (tag != buffer.read())
404 throw new IOException("Indefinite length encoding" +
405 " not supported");
406 len = DerInputStream.getDefiniteLength(buffer);
407 }
408
409 if (len == 0)
410 // return empty array instead of null, which should be
411 // used only for missing optionals
412 return new DerValue[0];
413
414 /*
415 * Create a temporary stream from which to read the data,
416 * unless it's not really needed.
417 */
418 if (buffer.available() == len)
419 newstr = this;
420 else
421 newstr = subStream(len, true);
422
423 /*
424 * Pull values out of the stream.
425 */
426 Vector<DerValue> vec = new Vector<>(startLen);
427 DerValue value;
428
429 do {
430 value = new DerValue(newstr.buffer, buffer.allowBER);
431 vec.addElement(value);
432 } while (newstr.available() > 0);
433
434 if (newstr.available() != 0)
435 throw new IOException("Extra data at end of vector");
436
437 /*
438 * Now stick them into the array we're returning.
439 */
440 int i, max = vec.size();
441 DerValue[] retval = new DerValue[max];
442
443 for (i = 0; i < max; i++)
444 retval[i] = vec.elementAt(i);
445
446 return retval;
447 }
448
449 /**
450 * Get a single DER-encoded value from the input stream.
|