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., 59 Temple Place, Suite 330, 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 out
.write(object
.getExternalTag());
88 Object value
= object
.getValue();
94 if (value
instanceof Boolean
)
95 return writeBoolean(out
, (Boolean
) value
);
96 else if (value
instanceof BigInteger
)
97 return writeInteger(out
, (BigInteger
) value
);
98 else if (value
instanceof Date
)
99 return writeDate(out
, object
.getExternalTag(), (Date
) value
);
100 else if (value
instanceof String
)
101 return writeString(out
, object
.getExternalTag(), (String
) value
);
102 else if (value
instanceof List
)
103 return writeSequence(out
, (List
) value
);
104 else if (value
instanceof Set
)
105 return writeSet(out
, (Set
) value
);
106 else if (value
instanceof BitString
)
107 return writeBitString(out
, (BitString
) value
);
108 else if (value
instanceof OID
)
109 return writeOID(out
, (OID
) value
);
110 else if (value
instanceof byte[])
112 writeLength(out
, ((byte[]) value
).length
);
113 out
.write((byte[]) value
);
114 return ((byte[]) value
).length
;
116 else if (value
instanceof DERValue
)
118 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
119 write(bout
, (DERValue
) value
);
120 byte[] buf
= bout
.toByteArray();
121 writeLength(out
, buf
.length
);
126 throw new DEREncodingException("cannot encode " + value
.getClass().getName());
129 public static int definiteEncodingSize(int length
)
133 else if (length
< 256)
135 else if (length
< 65536)
137 else if (length
< 16777216)
144 // ------------------------------------------------------------------------
147 * Write a BOOLEAN type to the given output stream.
149 * @param out The sink output stream.
150 * @param b The boolean value to write.
152 private static int writeBoolean(OutputStream out
, Boolean b
)
156 if (b
.booleanValue())
164 * Write an INTEGER type to the given output stream.
166 * @param out The sink output stream.
167 * @param integer The integer to write.
169 private static int writeInteger(OutputStream out
, BigInteger integer
)
172 byte[] bytes
= integer
.toByteArray();
173 writeLength(out
, bytes
.length
);
178 private static int writeSequence(OutputStream out
, List sequence
)
181 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
182 for (Iterator i
= sequence
.iterator(); i
.hasNext(); )
184 write(bout
, (DERValue
) i
.next());
186 byte[] buf
= bout
.toByteArray();
187 writeLength(out
, buf
.length
);
192 private static int writeSet(OutputStream out
, Set set
)
195 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
196 for (Iterator i
= set
.iterator(); i
.hasNext(); )
198 write(bout
, (DERValue
) i
.next());
200 byte[] buf
= bout
.toByteArray();
201 writeLength(out
, buf
.length
);
206 private static int writeOID(OutputStream out
, OID oid
)
209 byte[] der
= oid
.getDER();
210 writeLength(out
, der
.length
);
215 private static int writeBitString(OutputStream out
, BitString bs
)
218 byte[] buf
= bs
.getShiftedByteArray();
219 out
.write(buf
.length
+ 1);
220 out
.write(bs
.getIgnoredBits());
225 private static int writeString(OutputStream out
, int tag
, String str
)
232 case PRINTABLE_STRING
:
234 case VIDEOTEX_STRING
:
242 case UNIVERSAL_STRING
:
252 writeLength(out
, b
.length
);
257 private static byte[] toIso88591(String string
)
259 byte[] result
= new byte[string
.length()];
260 for (int i
= 0; i
< string
.length(); i
++)
261 result
[i
] = (byte) string
.charAt(i
);
265 private static byte[] toUtf16Be(String string
)
267 byte[] result
= new byte[string
.length() * 2];
268 for (int i
= 0; i
< string
.length(); i
++)
270 result
[i
*2 ] = (byte) ((string
.charAt(i
) >>> 8) & 0xFF);
271 result
[i
*2+1] = (byte) (string
.charAt(i
) & 0xFF);
276 private static byte[] toUtf8(String string
)
278 ByteArrayOutputStream buf
=
279 new ByteArrayOutputStream((int)(string
.length() * 1.5));
280 for (int i
= 0; i
< string
.length(); i
++)
282 char c
= string
.charAt(i
);
287 buf
.write(0xC0 | ((c
>>> 6) & 0x3F));
288 buf
.write(0x80 | (c
& 0x3F));
292 buf
.write(0xE0 | ((c
>>> 12) & 0x0F));
293 buf
.write(0x80 | ((c
>>> 6) & 0x3F));
294 buf
.write(0x80 | (c
& 0x3F));
297 return buf
.toByteArray();
300 private static int writeDate(OutputStream out
, int tag
, Date date
)
303 SimpleDateFormat sdf
= null;
304 if ((tag
& 0x1F) == UTC_TIME
)
305 sdf
= new SimpleDateFormat("yyMMddHHmmss'Z'");
307 sdf
= new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'");
308 sdf
.setTimeZone(TimeZone
.getTimeZone("UTC"));
309 byte[] b
= sdf
.format(date
).getBytes("ISO-8859-1");
310 writeLength(out
, b
.length
);
316 // ------------------------------------------------------------------------
318 static void writeLength(OutputStream out
, int len
) throws IOException
327 else if (len
< 65536)
333 else if (len
< 16777216)
336 out
.write(len
>> 16);
343 out
.write(len
>> 24);
344 out
.write(len
>> 16);