author | redestad |
Mon, 08 Oct 2018 18:16:03 +0200 | |
changeset 52040 | d8aebcc2d3ac |
parent 47216 | 71c04702a3d5 |
child 59024 | b046ba510bbc |
permissions | -rw-r--r-- |
2 | 1 |
/* |
6109
007c43113d09
6670889: Keystore created under Hindi Locale causing ArrayIndexOutOfBoundsException
weijun
parents:
5506
diff
changeset
|
2 |
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.security.util; |
|
27 |
||
28 |
import java.io.ByteArrayOutputStream; |
|
29 |
import java.io.OutputStream; |
|
30 |
import java.io.IOException; |
|
31 |
import java.text.SimpleDateFormat; |
|
32 |
import java.util.Date; |
|
33 |
import java.util.TimeZone; |
|
34 |
import java.util.Comparator; |
|
35 |
import java.util.Arrays; |
|
36 |
import java.math.BigInteger; |
|
6109
007c43113d09
6670889: Keystore created under Hindi Locale causing ArrayIndexOutOfBoundsException
weijun
parents:
5506
diff
changeset
|
37 |
import java.util.Locale; |
2 | 38 |
|
39 |
||
40 |
/** |
|
41 |
* Output stream marshaling DER-encoded data. This is eventually provided |
|
42 |
* in the form of a byte array; there is no advance limit on the size of |
|
43 |
* that byte array. |
|
44 |
* |
|
45 |
* <P>At this time, this class supports only a subset of the types of |
|
46 |
* DER data encodings which are defined. That subset is sufficient for |
|
47 |
* generating most X.509 certificates. |
|
48 |
* |
|
49 |
* |
|
50 |
* @author David Brownell |
|
51 |
* @author Amit Kapoor |
|
52 |
* @author Hemma Prafullchandra |
|
53 |
*/ |
|
54 |
public class DerOutputStream |
|
55 |
extends ByteArrayOutputStream implements DerEncoder { |
|
56 |
/** |
|
57 |
* Construct an DER output stream. |
|
58 |
* |
|
59 |
* @param size how large a buffer to preallocate. |
|
60 |
*/ |
|
61 |
public DerOutputStream(int size) { super(size); } |
|
62 |
||
63 |
/** |
|
64 |
* Construct an DER output stream. |
|
65 |
*/ |
|
66 |
public DerOutputStream() { } |
|
67 |
||
68 |
/** |
|
69 |
* Writes tagged, pre-marshaled data. This calcuates and encodes |
|
70 |
* the length, so that the output data is the standard triple of |
|
71 |
* { tag, length, data } used by all DER values. |
|
72 |
* |
|
73 |
* @param tag the DER value tag for the data, such as |
|
74 |
* <em>DerValue.tag_Sequence</em> |
|
75 |
* @param buf buffered data, which must be DER-encoded |
|
76 |
*/ |
|
77 |
public void write(byte tag, byte[] buf) throws IOException { |
|
78 |
write(tag); |
|
79 |
putLength(buf.length); |
|
80 |
write(buf, 0, buf.length); |
|
81 |
} |
|
82 |
||
83 |
/** |
|
84 |
* Writes tagged data using buffer-to-buffer copy. As above, |
|
85 |
* this writes a standard DER record. This is often used when |
|
86 |
* efficiently encapsulating values in sequences. |
|
87 |
* |
|
88 |
* @param tag the DER value tag for the data, such as |
|
89 |
* <em>DerValue.tag_Sequence</em> |
|
90 |
* @param out buffered data |
|
91 |
*/ |
|
92 |
public void write(byte tag, DerOutputStream out) throws IOException { |
|
93 |
write(tag); |
|
94 |
putLength(out.count); |
|
95 |
write(out.buf, 0, out.count); |
|
96 |
} |
|
97 |
||
98 |
/** |
|
99 |
* Writes implicitly tagged data using buffer-to-buffer copy. As above, |
|
100 |
* this writes a standard DER record. This is often used when |
|
101 |
* efficiently encapsulating implicitly tagged values. |
|
102 |
* |
|
103 |
* @param tag the DER value of the context-specific tag that replaces |
|
104 |
* original tag of the value in the output, such as in |
|
105 |
* <pre> |
|
30374 | 106 |
* <em> {@code <field> [N] IMPLICIT <type>}</em> |
2 | 107 |
* </pre> |
108 |
* For example, <em>FooLength [1] IMPLICIT INTEGER</em>, with value=4; |
|
109 |
* would be encoded as "81 01 04" whereas in explicit |
|
110 |
* tagging it would be encoded as "A1 03 02 01 04". |
|
111 |
* Notice that the tag is A1 and not 81, this is because with |
|
112 |
* explicit tagging the form is always constructed. |
|
113 |
* @param value original value being implicitly tagged |
|
114 |
*/ |
|
115 |
public void writeImplicit(byte tag, DerOutputStream value) |
|
116 |
throws IOException { |
|
117 |
write(tag); |
|
118 |
write(value.buf, 1, value.count-1); |
|
119 |
} |
|
120 |
||
121 |
/** |
|
122 |
* Marshals pre-encoded DER value onto the output stream. |
|
123 |
*/ |
|
124 |
public void putDerValue(DerValue val) throws IOException { |
|
125 |
val.encode(this); |
|
126 |
} |
|
127 |
||
128 |
/* |
|
129 |
* PRIMITIVES -- these are "universal" ASN.1 simple types. |
|
130 |
* |
|
131 |
* BOOLEAN, INTEGER, BIT STRING, OCTET STRING, NULL |
|
132 |
* OBJECT IDENTIFIER, SEQUENCE(OF), SET(OF) |
|
133 |
* PrintableString, T61String, IA5String, UTCTime |
|
134 |
*/ |
|
135 |
||
136 |
/** |
|
137 |
* Marshals a DER boolean on the output stream. |
|
138 |
*/ |
|
139 |
public void putBoolean(boolean val) throws IOException { |
|
140 |
write(DerValue.tag_Boolean); |
|
141 |
putLength(1); |
|
142 |
if (val) { |
|
143 |
write(0xff); |
|
144 |
} else { |
|
145 |
write(0); |
|
146 |
} |
|
147 |
} |
|
148 |
||
149 |
/** |
|
150 |
* Marshals a DER enumerated on the output stream. |
|
151 |
* @param i the enumerated value. |
|
152 |
*/ |
|
153 |
public void putEnumerated(int i) throws IOException { |
|
154 |
write(DerValue.tag_Enumerated); |
|
155 |
putIntegerContents(i); |
|
156 |
} |
|
157 |
||
158 |
/** |
|
159 |
* Marshals a DER integer on the output stream. |
|
160 |
* |
|
161 |
* @param i the integer in the form of a BigInteger. |
|
162 |
*/ |
|
163 |
public void putInteger(BigInteger i) throws IOException { |
|
164 |
write(DerValue.tag_Integer); |
|
165 |
byte[] buf = i.toByteArray(); // least number of bytes |
|
166 |
putLength(buf.length); |
|
167 |
write(buf, 0, buf.length); |
|
168 |
} |
|
169 |
||
170 |
/** |
|
171 |
* Marshals a DER integer on the output stream. |
|
172 |
* @param i the integer in the form of an Integer. |
|
173 |
*/ |
|
174 |
public void putInteger(Integer i) throws IOException { |
|
175 |
putInteger(i.intValue()); |
|
176 |
} |
|
177 |
||
178 |
/** |
|
179 |
* Marshals a DER integer on the output stream. |
|
180 |
* @param i the integer. |
|
181 |
*/ |
|
182 |
public void putInteger(int i) throws IOException { |
|
183 |
write(DerValue.tag_Integer); |
|
184 |
putIntegerContents(i); |
|
185 |
} |
|
186 |
||
187 |
private void putIntegerContents(int i) throws IOException { |
|
188 |
||
189 |
byte[] bytes = new byte[4]; |
|
190 |
int start = 0; |
|
191 |
||
192 |
// Obtain the four bytes of the int |
|
193 |
||
194 |
bytes[3] = (byte) (i & 0xff); |
|
195 |
bytes[2] = (byte)((i & 0xff00) >>> 8); |
|
196 |
bytes[1] = (byte)((i & 0xff0000) >>> 16); |
|
197 |
bytes[0] = (byte)((i & 0xff000000) >>> 24); |
|
198 |
||
199 |
// Reduce them to the least number of bytes needed to |
|
200 |
// represent this int |
|
201 |
||
3077
4be3e0e4d42c
6855671: DerOutputStream encodes negative integer incorrectly
weijun
parents:
2
diff
changeset
|
202 |
if (bytes[0] == (byte)0xff) { |
2 | 203 |
|
204 |
// Eliminate redundant 0xff |
|
205 |
||
206 |
for (int j = 0; j < 3; j++) { |
|
3077
4be3e0e4d42c
6855671: DerOutputStream encodes negative integer incorrectly
weijun
parents:
2
diff
changeset
|
207 |
if ((bytes[j] == (byte)0xff) && |
2 | 208 |
((bytes[j+1] & 0x80) == 0x80)) |
209 |
start++; |
|
210 |
else |
|
211 |
break; |
|
212 |
} |
|
213 |
} else if (bytes[0] == 0x00) { |
|
214 |
||
215 |
// Eliminate redundant 0x00 |
|
216 |
||
217 |
for (int j = 0; j < 3; j++) { |
|
218 |
if ((bytes[j] == 0x00) && |
|
219 |
((bytes[j+1] & 0x80) == 0)) |
|
220 |
start++; |
|
221 |
else |
|
222 |
break; |
|
223 |
} |
|
224 |
} |
|
225 |
||
226 |
putLength(4 - start); |
|
227 |
for (int k = start; k < 4; k++) |
|
228 |
write(bytes[k]); |
|
229 |
} |
|
230 |
||
231 |
/** |
|
232 |
* Marshals a DER bit string on the output stream. The bit |
|
233 |
* string must be byte-aligned. |
|
234 |
* |
|
235 |
* @param bits the bit string, MSB first |
|
236 |
*/ |
|
237 |
public void putBitString(byte[] bits) throws IOException { |
|
238 |
write(DerValue.tag_BitString); |
|
239 |
putLength(bits.length + 1); |
|
240 |
write(0); // all of last octet is used |
|
241 |
write(bits); |
|
242 |
} |
|
243 |
||
244 |
/** |
|
245 |
* Marshals a DER bit string on the output stream. |
|
246 |
* The bit strings need not be byte-aligned. |
|
247 |
* |
|
30374 | 248 |
* @param ba the bit string, MSB first |
2 | 249 |
*/ |
250 |
public void putUnalignedBitString(BitArray ba) throws IOException { |
|
251 |
byte[] bits = ba.toByteArray(); |
|
252 |
||
253 |
write(DerValue.tag_BitString); |
|
254 |
putLength(bits.length + 1); |
|
255 |
write(bits.length*8 - ba.length()); // excess bits in last octet |
|
256 |
write(bits); |
|
257 |
} |
|
258 |
||
259 |
/** |
|
260 |
* Marshals a truncated DER bit string on the output stream. |
|
261 |
* The bit strings need not be byte-aligned. |
|
262 |
* |
|
30374 | 263 |
* @param ba the bit string, MSB first |
2 | 264 |
*/ |
265 |
public void putTruncatedUnalignedBitString(BitArray ba) throws IOException { |
|
266 |
putUnalignedBitString(ba.truncate()); |
|
267 |
} |
|
268 |
||
269 |
/** |
|
270 |
* DER-encodes an ASN.1 OCTET STRING value on the output stream. |
|
271 |
* |
|
272 |
* @param octets the octet string |
|
273 |
*/ |
|
274 |
public void putOctetString(byte[] octets) throws IOException { |
|
275 |
write(DerValue.tag_OctetString, octets); |
|
276 |
} |
|
277 |
||
278 |
/** |
|
279 |
* Marshals a DER "null" value on the output stream. These are |
|
280 |
* often used to indicate optional values which have been omitted. |
|
281 |
*/ |
|
282 |
public void putNull() throws IOException { |
|
283 |
write(DerValue.tag_Null); |
|
284 |
putLength(0); |
|
285 |
} |
|
286 |
||
287 |
/** |
|
288 |
* Marshals an object identifier (OID) on the output stream. |
|
289 |
* Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct. |
|
290 |
*/ |
|
291 |
public void putOID(ObjectIdentifier oid) throws IOException { |
|
292 |
oid.encode(this); |
|
293 |
} |
|
294 |
||
295 |
/** |
|
296 |
* Marshals a sequence on the output stream. This supports both |
|
297 |
* the ASN.1 "SEQUENCE" (zero to N values) and "SEQUENCE OF" |
|
298 |
* (one to N values) constructs. |
|
299 |
*/ |
|
300 |
public void putSequence(DerValue[] seq) throws IOException { |
|
301 |
DerOutputStream bytes = new DerOutputStream(); |
|
302 |
int i; |
|
303 |
||
304 |
for (i = 0; i < seq.length; i++) |
|
305 |
seq[i].encode(bytes); |
|
306 |
||
307 |
write(DerValue.tag_Sequence, bytes); |
|
308 |
} |
|
309 |
||
310 |
/** |
|
311 |
* Marshals the contents of a set on the output stream without |
|
312 |
* ordering the elements. Ok for BER encoding, but not for DER |
|
313 |
* encoding. |
|
314 |
* |
|
315 |
* For DER encoding, use orderedPutSet() or orderedPutSetOf(). |
|
316 |
*/ |
|
317 |
public void putSet(DerValue[] set) throws IOException { |
|
318 |
DerOutputStream bytes = new DerOutputStream(); |
|
319 |
int i; |
|
320 |
||
321 |
for (i = 0; i < set.length; i++) |
|
322 |
set[i].encode(bytes); |
|
323 |
||
324 |
write(DerValue.tag_Set, bytes); |
|
325 |
} |
|
326 |
||
327 |
/** |
|
328 |
* Marshals the contents of a set on the output stream. Sets |
|
329 |
* are semantically unordered, but DER requires that encodings of |
|
330 |
* set elements be sorted into ascending lexicographical order |
|
331 |
* before being output. Hence sets with the same tags and |
|
332 |
* elements have the same DER encoding. |
|
333 |
* |
|
334 |
* This method supports the ASN.1 "SET OF" construct, but not |
|
335 |
* "SET", which uses a different order. |
|
336 |
*/ |
|
337 |
public void putOrderedSetOf(byte tag, DerEncoder[] set) throws IOException { |
|
338 |
putOrderedSet(tag, set, lexOrder); |
|
339 |
} |
|
340 |
||
341 |
/** |
|
342 |
* Marshals the contents of a set on the output stream. Sets |
|
343 |
* are semantically unordered, but DER requires that encodings of |
|
344 |
* set elements be sorted into ascending tag order |
|
345 |
* before being output. Hence sets with the same tags and |
|
346 |
* elements have the same DER encoding. |
|
347 |
* |
|
348 |
* This method supports the ASN.1 "SET" construct, but not |
|
349 |
* "SET OF", which uses a different order. |
|
350 |
*/ |
|
351 |
public void putOrderedSet(byte tag, DerEncoder[] set) throws IOException { |
|
352 |
putOrderedSet(tag, set, tagOrder); |
|
353 |
} |
|
354 |
||
355 |
/** |
|
356 |
* Lexicographical order comparison on byte arrays, for ordering |
|
357 |
* elements of a SET OF objects in DER encoding. |
|
358 |
*/ |
|
359 |
private static ByteArrayLexOrder lexOrder = new ByteArrayLexOrder(); |
|
360 |
||
361 |
/** |
|
362 |
* Tag order comparison on byte arrays, for ordering elements of |
|
363 |
* SET objects in DER encoding. |
|
364 |
*/ |
|
365 |
private static ByteArrayTagOrder tagOrder = new ByteArrayTagOrder(); |
|
366 |
||
367 |
/** |
|
368 |
* Marshals a the contents of a set on the output stream with the |
|
369 |
* encodings of its sorted in increasing order. |
|
370 |
* |
|
371 |
* @param order the order to use when sorting encodings of components. |
|
372 |
*/ |
|
373 |
private void putOrderedSet(byte tag, DerEncoder[] set, |
|
374 |
Comparator<byte[]> order) throws IOException { |
|
375 |
DerOutputStream[] streams = new DerOutputStream[set.length]; |
|
376 |
||
377 |
for (int i = 0; i < set.length; i++) { |
|
378 |
streams[i] = new DerOutputStream(); |
|
379 |
set[i].derEncode(streams[i]); |
|
380 |
} |
|
381 |
||
382 |
// order the element encodings |
|
383 |
byte[][] bufs = new byte[streams.length][]; |
|
384 |
for (int i = 0; i < streams.length; i++) { |
|
385 |
bufs[i] = streams[i].toByteArray(); |
|
386 |
} |
|
387 |
Arrays.<byte[]>sort(bufs, order); |
|
388 |
||
389 |
DerOutputStream bytes = new DerOutputStream(); |
|
390 |
for (int i = 0; i < streams.length; i++) { |
|
391 |
bytes.write(bufs[i]); |
|
392 |
} |
|
393 |
write(tag, bytes); |
|
394 |
||
395 |
} |
|
396 |
||
397 |
/** |
|
398 |
* Marshals a string as a DER encoded UTF8String. |
|
399 |
*/ |
|
400 |
public void putUTF8String(String s) throws IOException { |
|
401 |
writeString(s, DerValue.tag_UTF8String, "UTF8"); |
|
402 |
} |
|
403 |
||
404 |
/** |
|
405 |
* Marshals a string as a DER encoded PrintableString. |
|
406 |
*/ |
|
407 |
public void putPrintableString(String s) throws IOException { |
|
408 |
writeString(s, DerValue.tag_PrintableString, "ASCII"); |
|
409 |
} |
|
410 |
||
411 |
/** |
|
412 |
* Marshals a string as a DER encoded T61String. |
|
413 |
*/ |
|
414 |
public void putT61String(String s) throws IOException { |
|
415 |
/* |
|
416 |
* Works for characters that are defined in both ASCII and |
|
417 |
* T61. |
|
418 |
*/ |
|
419 |
writeString(s, DerValue.tag_T61String, "ISO-8859-1"); |
|
420 |
} |
|
421 |
||
422 |
/** |
|
423 |
* Marshals a string as a DER encoded IA5String. |
|
424 |
*/ |
|
425 |
public void putIA5String(String s) throws IOException { |
|
426 |
writeString(s, DerValue.tag_IA5String, "ASCII"); |
|
427 |
} |
|
428 |
||
429 |
/** |
|
430 |
* Marshals a string as a DER encoded BMPString. |
|
431 |
*/ |
|
432 |
public void putBMPString(String s) throws IOException { |
|
433 |
writeString(s, DerValue.tag_BMPString, "UnicodeBigUnmarked"); |
|
434 |
} |
|
435 |
||
436 |
/** |
|
437 |
* Marshals a string as a DER encoded GeneralString. |
|
438 |
*/ |
|
439 |
public void putGeneralString(String s) throws IOException { |
|
440 |
writeString(s, DerValue.tag_GeneralString, "ASCII"); |
|
441 |
} |
|
442 |
||
443 |
/** |
|
444 |
* Private helper routine for writing DER encoded string values. |
|
445 |
* @param s the string to write |
|
446 |
* @param stringTag one of the DER string tags that indicate which |
|
447 |
* encoding should be used to write the string out. |
|
448 |
* @param enc the name of the encoder that should be used corresponding |
|
449 |
* to the above tag. |
|
450 |
*/ |
|
451 |
private void writeString(String s, byte stringTag, String enc) |
|
452 |
throws IOException { |
|
453 |
||
454 |
byte[] data = s.getBytes(enc); |
|
455 |
write(stringTag); |
|
456 |
putLength(data.length); |
|
457 |
write(data); |
|
458 |
} |
|
459 |
||
460 |
/** |
|
461 |
* Marshals a DER UTC time/date value. |
|
462 |
* |
|
463 |
* <P>YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time |
|
26967
c182469301ee
8037550: Update RFC references in javadoc to RFC 5280
juh
parents:
25859
diff
changeset
|
464 |
* and with seconds (even if seconds=0) as per RFC 5280. |
2 | 465 |
*/ |
466 |
public void putUTCTime(Date d) throws IOException { |
|
467 |
putTime(d, DerValue.tag_UtcTime); |
|
468 |
} |
|
469 |
||
470 |
/** |
|
471 |
* Marshals a DER Generalized Time/date value. |
|
472 |
* |
|
473 |
* <P>YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time |
|
26967
c182469301ee
8037550: Update RFC references in javadoc to RFC 5280
juh
parents:
25859
diff
changeset
|
474 |
* and with seconds (even if seconds=0) as per RFC 5280. |
2 | 475 |
*/ |
476 |
public void putGeneralizedTime(Date d) throws IOException { |
|
477 |
putTime(d, DerValue.tag_GeneralizedTime); |
|
478 |
} |
|
479 |
||
480 |
/** |
|
481 |
* Private helper routine for marshalling a DER UTC/Generalized |
|
482 |
* time/date value. If the tag specified is not that for UTC Time |
|
483 |
* then it defaults to Generalized Time. |
|
484 |
* @param d the date to be marshalled |
|
485 |
* @param tag the tag for UTC Time or Generalized Time |
|
486 |
*/ |
|
487 |
private void putTime(Date d, byte tag) throws IOException { |
|
488 |
||
489 |
/* |
|
490 |
* Format the date. |
|
491 |
*/ |
|
492 |
||
493 |
TimeZone tz = TimeZone.getTimeZone("GMT"); |
|
494 |
String pattern = null; |
|
495 |
||
496 |
if (tag == DerValue.tag_UtcTime) { |
|
497 |
pattern = "yyMMddHHmmss'Z'"; |
|
498 |
} else { |
|
499 |
tag = DerValue.tag_GeneralizedTime; |
|
500 |
pattern = "yyyyMMddHHmmss'Z'"; |
|
501 |
} |
|
502 |
||
6109
007c43113d09
6670889: Keystore created under Hindi Locale causing ArrayIndexOutOfBoundsException
weijun
parents:
5506
diff
changeset
|
503 |
SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US); |
2 | 504 |
sdf.setTimeZone(tz); |
505 |
byte[] time = (sdf.format(d)).getBytes("ISO-8859-1"); |
|
506 |
||
507 |
/* |
|
508 |
* Write the formatted date. |
|
509 |
*/ |
|
510 |
||
511 |
write(tag); |
|
512 |
putLength(time.length); |
|
513 |
write(time); |
|
514 |
} |
|
515 |
||
516 |
/** |
|
517 |
* Put the encoding of the length in the stream. |
|
518 |
* |
|
30374 | 519 |
* @param len the length of the attribute. |
2 | 520 |
* @exception IOException on writing errors. |
521 |
*/ |
|
522 |
public void putLength(int len) throws IOException { |
|
523 |
if (len < 128) { |
|
524 |
write((byte)len); |
|
525 |
||
526 |
} else if (len < (1 << 8)) { |
|
527 |
write((byte)0x081); |
|
528 |
write((byte)len); |
|
529 |
||
530 |
} else if (len < (1 << 16)) { |
|
531 |
write((byte)0x082); |
|
532 |
write((byte)(len >> 8)); |
|
533 |
write((byte)len); |
|
534 |
||
535 |
} else if (len < (1 << 24)) { |
|
536 |
write((byte)0x083); |
|
537 |
write((byte)(len >> 16)); |
|
538 |
write((byte)(len >> 8)); |
|
539 |
write((byte)len); |
|
540 |
||
541 |
} else { |
|
542 |
write((byte)0x084); |
|
543 |
write((byte)(len >> 24)); |
|
544 |
write((byte)(len >> 16)); |
|
545 |
write((byte)(len >> 8)); |
|
546 |
write((byte)len); |
|
547 |
} |
|
548 |
} |
|
549 |
||
550 |
/** |
|
551 |
* Put the tag of the attribute in the stream. |
|
552 |
* |
|
30374 | 553 |
* @param tagClass the tag class type, one of UNIVERSAL, CONTEXT, |
554 |
* APPLICATION or PRIVATE |
|
555 |
* @param form if true, the value is constructed, otherwise it is |
|
2 | 556 |
* primitive. |
30374 | 557 |
* @param val the tag value |
2 | 558 |
*/ |
559 |
public void putTag(byte tagClass, boolean form, byte val) { |
|
560 |
byte tag = (byte)(tagClass | val); |
|
561 |
if (form) { |
|
562 |
tag |= (byte)0x20; |
|
563 |
} |
|
564 |
write(tag); |
|
565 |
} |
|
566 |
||
567 |
/** |
|
568 |
* Write the current contents of this <code>DerOutputStream</code> |
|
569 |
* to an <code>OutputStream</code>. |
|
570 |
* |
|
571 |
* @exception IOException on output error. |
|
572 |
*/ |
|
573 |
public void derEncode(OutputStream out) throws IOException { |
|
574 |
out.write(toByteArray()); |
|
575 |
} |
|
576 |
} |