1/*
2 * Copyright (c) 1996, 2010, 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
26package sun.security.util;
27
28import java.io.ByteArrayOutputStream;
29import java.io.OutputStream;
30import java.io.IOException;
31import java.text.SimpleDateFormat;
32import java.util.Date;
33import java.util.TimeZone;
34import java.util.Comparator;
35import java.util.Arrays;
36import java.math.BigInteger;
37import java.util.Locale;
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 */
54public class DerOutputStream
55extends 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>
106     *          <em> <field> [N] IMPLICIT <type></em>
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
202        if (bytes[0] == (byte)0xff) {
203
204            // Eliminate redundant 0xff
205
206            for (int j = 0; j < 3; j++) {
207                if ((bytes[j] == (byte)0xff) &&
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     *
248     * @param bits the bit string, MSB first
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     *
263     * @param bits the bit string, MSB first
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
464     * and with seconds (even if seconds=0) as per RFC 3280.
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
474     * and with seconds (even if seconds=0) as per RFC 3280.
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
503        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US);
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     *
519     * @params len the length of the attribute.
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     *
553     * @params class the tag class type, one of UNIVERSAL, CONTEXT,
554     *                            APPLICATION or PRIVATE
555     * @params form if true, the value is constructed, otherwise it is
556     * primitive.
557     * @params val the tag value
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}
577