View Javadoc
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  
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;
37  import 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   */
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>
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 }