1 /* DERWriter.java -- write Java types in DER format.
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.java
.security
.der
;
41 import gnu
.java
.security
.OID
;
43 import java
.io
.ByteArrayOutputStream
;
44 import java
.io
.IOException
;
45 import java
.io
.OutputStream
;
47 import java
.math
.BigInteger
;
49 import java
.text
.SimpleDateFormat
;
51 import java
.util
.Date
;
52 import java
.util
.Iterator
;
53 import java
.util
.List
;
55 import java
.util
.TimeZone
;
58 * Methods that allow various Java types to be written as a DER
59 * (Distinguished Encoding Rules) stream to the specified output stream.
60 * DER is used to encode ASN.1 constructions, but this class provides no
61 * methods for interacting with ASN.1. Rather, callers should construct
62 * their output objects properly for whatever ASN.1 construct is being
65 * <p>This class only defines static methods; there are no instance
68 * @author Casey Marshall (csm@gnu.org)
70 public class DERWriter
implements DER
74 // ------------------------------------------------------------------------
76 /** This class only has static methods. */
82 // ------------------------------------------------------------------------
84 public static int write(OutputStream out
, DERValue object
)
87 if (DER
.CONSTRUCTED_VALUE
.equals (object
.getValue ()))
89 out
.write (object
.getEncoded ());
90 return object
.getLength ();
93 out
.write(object
.getExternalTag());
94 Object value
= object
.getValue();
100 if (value
instanceof Boolean
)
101 return writeBoolean(out
, (Boolean
) value
);
102 else if (value
instanceof BigInteger
)
103 return writeInteger(out
, (BigInteger
) value
);
104 else if (value
instanceof Date
)
105 return writeDate(out
, object
.getExternalTag(), (Date
) value
);
106 else if (value
instanceof String
)
107 return writeString(out
, object
.getExternalTag(), (String
) value
);
108 else if (value
instanceof List
)
109 return writeSequence(out
, (List
) value
);
110 else if (value
instanceof Set
)
111 return writeSet(out
, (Set
) value
);
112 else if (value
instanceof BitString
)
113 return writeBitString(out
, (BitString
) value
);
114 else if (value
instanceof OID
)
115 return writeOID(out
, (OID
) value
);
116 else if (value
instanceof byte[])
118 writeLength(out
, ((byte[]) value
).length
);
119 out
.write((byte[]) value
);
120 return ((byte[]) value
).length
;
122 else if (value
instanceof DERValue
)
124 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
125 write(bout
, (DERValue
) value
);
126 byte[] buf
= bout
.toByteArray();
127 writeLength(out
, buf
.length
);
132 throw new DEREncodingException("cannot encode " + value
.getClass().getName());
135 public static int definiteEncodingSize(int length
)
139 else if (length
< 256)
141 else if (length
< 65536)
143 else if (length
< 16777216)
150 // ------------------------------------------------------------------------
153 * Write a BOOLEAN type to the given output stream.
155 * @param out The sink output stream.
156 * @param b The boolean value to write.
158 private static int writeBoolean(OutputStream out
, Boolean b
)
162 if (b
.booleanValue())
170 * Write an INTEGER type to the given output stream.
172 * @param out The sink output stream.
173 * @param integer The integer to write.
175 private static int writeInteger(OutputStream out
, BigInteger integer
)
178 byte[] bytes
= integer
.toByteArray();
179 writeLength(out
, bytes
.length
);
184 private static int writeSequence(OutputStream out
, List sequence
)
187 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
188 for (Iterator i
= sequence
.iterator(); i
.hasNext(); )
190 write(bout
, (DERValue
) i
.next());
192 byte[] buf
= bout
.toByteArray();
193 writeLength(out
, buf
.length
);
198 private static int writeSet(OutputStream out
, Set set
)
201 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
202 for (Iterator i
= set
.iterator(); i
.hasNext(); )
204 write(bout
, (DERValue
) i
.next());
206 byte[] buf
= bout
.toByteArray();
207 writeLength(out
, buf
.length
);
212 private static int writeOID(OutputStream out
, OID oid
)
215 byte[] der
= oid
.getDER();
216 writeLength(out
, der
.length
);
221 private static int writeBitString(OutputStream out
, BitString bs
)
224 byte[] buf
= bs
.getShiftedByteArray();
225 writeLength(out
, buf
.length
+ 1);
226 out
.write(bs
.getIgnoredBits());
228 return buf
.length
+ 1;
231 private static int writeString(OutputStream out
, int tag
, String str
)
238 case PRINTABLE_STRING
:
240 case VIDEOTEX_STRING
:
248 case UNIVERSAL_STRING
:
258 writeLength(out
, b
.length
);
263 private static byte[] toIso88591(String string
)
265 byte[] result
= new byte[string
.length()];
266 for (int i
= 0; i
< string
.length(); i
++)
267 result
[i
] = (byte) string
.charAt(i
);
271 private static byte[] toUtf16Be(String string
)
273 byte[] result
= new byte[string
.length() * 2];
274 for (int i
= 0; i
< string
.length(); i
++)
276 result
[i
*2 ] = (byte) ((string
.charAt(i
) >>> 8) & 0xFF);
277 result
[i
*2+1] = (byte) (string
.charAt(i
) & 0xFF);
282 private static byte[] toUtf8(String string
)
284 ByteArrayOutputStream buf
=
285 new ByteArrayOutputStream((int)(string
.length() * 1.5));
286 for (int i
= 0; i
< string
.length(); i
++)
288 char c
= string
.charAt(i
);
293 buf
.write(0xC0 | ((c
>>> 6) & 0x3F));
294 buf
.write(0x80 | (c
& 0x3F));
298 buf
.write(0xE0 | ((c
>>> 12) & 0x0F));
299 buf
.write(0x80 | ((c
>>> 6) & 0x3F));
300 buf
.write(0x80 | (c
& 0x3F));
303 return buf
.toByteArray();
306 private static int writeDate(OutputStream out
, int tag
, Date date
)
309 SimpleDateFormat sdf
= null;
310 if ((tag
& 0x1F) == UTC_TIME
)
311 sdf
= new SimpleDateFormat("yyMMddHHmmss'Z'");
313 sdf
= new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'");
314 sdf
.setTimeZone(TimeZone
.getTimeZone("UTC"));
315 byte[] b
= sdf
.format(date
).getBytes("ISO-8859-1");
316 writeLength(out
, b
.length
);
322 // ------------------------------------------------------------------------
324 static void writeLength(OutputStream out
, int len
) throws IOException
333 else if (len
< 65536)
339 else if (len
< 16777216)
342 out
.write(len
>> 16);
349 out
.write(len
>> 24);
350 out
.write(len
>> 16);