1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46:
47: import ;
48:
49: import ;
50:
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56:
57:
70: public class DERWriter implements DER
71: {
72:
73:
74:
75:
76:
77: private DERWriter()
78: {
79: }
80:
81:
82:
83:
84: public static int write(OutputStream out, DERValue object)
85: throws IOException
86: {
87: out.write(object.getExternalTag());
88: Object value = object.getValue();
89: if (value == null)
90: {
91: writeLength(out, 0);
92: return 0;
93: }
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[])
111: {
112: writeLength(out, ((byte[]) value).length);
113: out.write((byte[]) value);
114: return ((byte[]) value).length;
115: }
116: else if (value instanceof DERValue)
117: {
118: ByteArrayOutputStream bout = new ByteArrayOutputStream();
119: write(bout, (DERValue) value);
120: byte[] buf = bout.toByteArray();
121: writeLength(out, buf.length);
122: out.write(buf);
123: return buf.length;
124: }
125: else
126: throw new DEREncodingException("cannot encode " + value.getClass().getName());
127: }
128:
129: public static int definiteEncodingSize(int length)
130: {
131: if (length < 128)
132: return 1;
133: else if (length < 256)
134: return 2;
135: else if (length < 65536)
136: return 3;
137: else if (length < 16777216)
138: return 4;
139: else
140: return 5;
141: }
142:
143:
144:
145:
146:
152: private static int writeBoolean(OutputStream out, Boolean b)
153: throws IOException
154: {
155: writeLength(out, 1);
156: if (b.booleanValue())
157: out.write(0xFF);
158: else
159: out.write(0);
160: return 1;
161: }
162:
163:
169: private static int writeInteger(OutputStream out, BigInteger integer)
170: throws IOException
171: {
172: byte[] bytes = integer.toByteArray();
173: writeLength(out, bytes.length);
174: out.write(bytes);
175: return bytes.length;
176: }
177:
178: private static int writeSequence(OutputStream out, List sequence)
179: throws IOException
180: {
181: ByteArrayOutputStream bout = new ByteArrayOutputStream();
182: for (Iterator i = sequence.iterator(); i.hasNext(); )
183: {
184: write(bout, (DERValue) i.next());
185: }
186: byte[] buf = bout.toByteArray();
187: writeLength(out, buf.length);
188: out.write(buf);
189: return buf.length;
190: }
191:
192: private static int writeSet(OutputStream out, Set set)
193: throws IOException
194: {
195: ByteArrayOutputStream bout = new ByteArrayOutputStream();
196: for (Iterator i = set.iterator(); i.hasNext(); )
197: {
198: write(bout, (DERValue) i.next());
199: }
200: byte[] buf = bout.toByteArray();
201: writeLength(out, buf.length);
202: out.write(buf);
203: return buf.length;
204: }
205:
206: private static int writeOID(OutputStream out, OID oid)
207: throws IOException
208: {
209: byte[] der = oid.getDER();
210: writeLength(out, der.length);
211: out.write(der);
212: return der.length;
213: }
214:
215: private static int writeBitString(OutputStream out, BitString bs)
216: throws IOException
217: {
218: byte[] buf = bs.getShiftedByteArray();
219: out.write(buf.length + 1);
220: out.write(bs.getIgnoredBits());
221: out.write(buf);
222: return buf.length;
223: }
224:
225: private static int writeString(OutputStream out, int tag, String str)
226: throws IOException
227: {
228: byte[] b = null;
229: switch (tag & 0x1F)
230: {
231: case NUMERIC_STRING:
232: case PRINTABLE_STRING:
233: case T61_STRING:
234: case VIDEOTEX_STRING:
235: case IA5_STRING:
236: case GRAPHIC_STRING:
237: case ISO646_STRING:
238: case GENERAL_STRING:
239: b = toIso88591(str);
240: break;
241:
242: case UNIVERSAL_STRING:
243: case BMP_STRING:
244: b = toUtf16Be(str);
245: break;
246:
247: case UTF8_STRING:
248: default:
249: b = toUtf8(str);
250: break;
251: }
252: writeLength(out, b.length);
253: out.write(b);
254: return b.length;
255: }
256:
257: private static byte[] toIso88591(String string)
258: {
259: byte[] result = new byte[string.length()];
260: for (int i = 0; i < string.length(); i++)
261: result[i] = (byte) string.charAt(i);
262: return result;
263: }
264:
265: private static byte[] toUtf16Be(String string)
266: {
267: byte[] result = new byte[string.length() * 2];
268: for (int i = 0; i < string.length(); i++)
269: {
270: result[i*2 ] = (byte) ((string.charAt(i) >>> 8) & 0xFF);
271: result[i*2+1] = (byte) (string.charAt(i) & 0xFF);
272: }
273: return result;
274: }
275:
276: private static byte[] toUtf8(String string)
277: {
278: ByteArrayOutputStream buf =
279: new ByteArrayOutputStream((int)(string.length() * 1.5));
280: for (int i = 0; i < string.length(); i++)
281: {
282: char c = string.charAt(i);
283: if (c < 0x0080)
284: buf.write(c & 0xFF);
285: else if (c < 0x0800)
286: {
287: buf.write(0xC0 | ((c >>> 6) & 0x3F));
288: buf.write(0x80 | (c & 0x3F));
289: }
290: else
291: {
292: buf.write(0xE0 | ((c >>> 12) & 0x0F));
293: buf.write(0x80 | ((c >>> 6) & 0x3F));
294: buf.write(0x80 | (c & 0x3F));
295: }
296: }
297: return buf.toByteArray();
298: }
299:
300: private static int writeDate(OutputStream out, int tag, Date date)
301: throws IOException
302: {
303: SimpleDateFormat sdf = null;
304: if ((tag & 0x1F) == UTC_TIME)
305: sdf = new SimpleDateFormat("yyMMddHHmmss'Z'");
306: else
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);
311: out.write(b);
312: return b.length;
313: }
314:
315:
316:
317:
318: static void writeLength(OutputStream out, int len) throws IOException
319: {
320: if (len < 128)
321: out.write(len);
322: else if (len < 256)
323: {
324: out.write(0x81);
325: out.write(len);
326: }
327: else if (len < 65536)
328: {
329: out.write(0x82);
330: out.write(len >> 8);
331: out.write(len);
332: }
333: else if (len < 16777216)
334: {
335: out.write(0x83);
336: out.write(len >> 16);
337: out.write(len >> 8);
338: out.write(len);
339: }
340: else
341: {
342: out.write(0x84);
343: out.write(len >> 24);
344: out.write(len >> 16);
345: out.write(len >> 8);
346: out.write(len);
347: }
348: }
349: }