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