001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package dummyCA;
028:
029: import java.io.UnsupportedEncodingException;
030: import java.io.IOException;
031: import java.io.PrintStream;
032: import java.util.StringTokenizer;
033: import java.util.Calendar;
034:
035: /**
036: * Used to represent each Type, Length, Value structure in a DER buffer.
037: */
038: class TLV {
039: /** ASN context specific flag used in types (0x80). */
040: static final int CONTEXT = 0x80;
041: /** ASN constructed flag used in types (0x20). */
042: static final int CONSTRUCTED = 0x20;
043: /** ASN constructed flag used in types (0x20). */
044: static final int EXPLICIT = CONSTRUCTED;
045: /** ANY_STRING type used as a place holder. [UNIVERSAL 0] */
046: static final int ANY_STRING_TYPE = 0x00; // our own impl
047: /** ASN BOOLEAN type used in certificate parsing. [UNIVERSAL 1] */
048: static final int BOOLEAN_TYPE = 1;
049: /** ASN INTEGER type used in certificate parsing. [UNIVERSAL 2] */
050: static final int INTEGER_TYPE = 2;
051: /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 3] */
052: static final int BITSTRING_TYPE = 3;
053: /** ASN OCTET STRING type used in certificate parsing. [UNIVERSAL 4] */
054: static final int OCTETSTR_TYPE = 4;
055: /** ASN NULL type used in certificate parsing. [UNIVERSAL 5] */
056: static final int NULL_TYPE = 5;
057: /** ASN OBJECT ID type used in certificate parsing. [UNIVERSAL 6] */
058: static final int OID_TYPE = 6;
059: /** ASN UTF8String type used in certificate parsing. [UNIVERSAL 12] */
060: static final int UTF8STR_TYPE = 12;
061: /**
062: * ASN SEQUENCE type used in certificate parsing.
063: * [UNIVERSAL CONSTRUCTED 16]
064: */
065: static final int SEQUENCE_TYPE = CONSTRUCTED + 16;
066: /**
067: * ASN SET type used in certificate parsing.
068: * [UNIVERSAL CONSTRUCTED 17]
069: */
070: static final int SET_TYPE = CONSTRUCTED + 17;
071: /** ASN PrintableString type used in certificate parsing. [UNIVERSAL 19] */
072: static final int PRINTSTR_TYPE = 19;
073: /** ASN TELETEX STRING type used in certificate parsing. [UNIVERSAL 20] */
074: static final int TELETEXSTR_TYPE = 20;
075: /** ASN IA5 STRING type used in certificate parsing. [UNIVERSAL 22] */
076: static final int IA5STR_TYPE = 22;
077: /** ASN UCT time type used in certificate parsing [UNIVERSAL 23] */
078: static final int UCT_TIME_TYPE = 23;
079: /**
080: * ASN Generalized time type used in certificate parsing.
081: * [UNIVERSAL 24]
082: */
083: static final int GEN_TIME_TYPE = 24;
084: /**
085: * ASN UniversalString type used in certificate parsing.
086: * [UNIVERSAL 28].
087: */
088: static final int UNIVSTR_TYPE = 28;
089: /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 30] */
090: static final int BMPSTR_TYPE = 30;
091: /**
092: * Context specific explicit type for certificate version.
093: * [CONTEXT EXPLICIT 0]
094: */
095: static final int VERSION_TYPE = CONTEXT + EXPLICIT + 0;
096: /**
097: * Context specific explicit type for certificate extensions.
098: * [CONTEXT EXPLICIT 3]
099: */
100: static final int EXTENSIONS_TYPE = CONTEXT + EXPLICIT + 3;
101:
102: /**
103: * Converts a subsequence of bytes into a printable OID,
104: * a string of decimal digits, each separated by a ".".
105: *
106: * @param buffer byte array containing the bytes to be converted
107: * @param offset starting offset of the byte subsequence inside b
108: * @param length number of bytes to be converted
109: *
110: * @return printable OID
111: */
112: static String OIDtoString(byte[] buffer, int offset, int length) {
113: StringBuffer result;
114: int end;
115: int t;
116: int x;
117: int y;
118:
119: if (length == 0) {
120: return "";
121: }
122:
123: result = new StringBuffer(40);
124:
125: end = offset + length;
126:
127: /*
128: * first byte (t) always represents the first 2 values (x, y).
129: * t = (x * 40) + y;
130: */
131: t = buffer[offset++] & 0xff;
132: x = t / 40;
133: y = t - (x * 40);
134:
135: result.append(x);
136: result.append('.');
137: result.append(y);
138:
139: x = 0;
140: while (offset < end) {
141: // 7 bit per byte, bit 8 = 0 means the end of a value
142: x = x << 7;
143:
144: t = buffer[offset++];
145: if (t >= 0) {
146: x += t;
147: result.append('.');
148: result.append(x);
149: x = 0;
150: } else {
151: x += t & 0x7f;
152: }
153: }
154:
155: return result.toString();
156: }
157:
158: /** OID must fit into byte array of this size. */
159: private static final int MAX_OID_SIZE = 50;
160:
161: /**
162: * Converts a printable OID into a subsequence of bytes.
163: * @param oid printable OID
164: * @return byte array containing the OID
165: */
166: static byte[] StringToOID(String oid) {
167:
168: StringTokenizer t = new StringTokenizer(oid, ".");
169:
170: int[] values = new int[t.countTokens()];
171: for (int i = 0; i < values.length; i++) {
172: values[i] = Integer.parseInt(t.nextToken(), 10);
173: }
174:
175: byte[] x = new byte[MAX_OID_SIZE];
176:
177: int i = 0;
178: x[i++] = (byte) (values[0] * 40 + values[1]);
179:
180: for (int j = 2; j < values.length; j++) {
181:
182: int k = values[j];
183:
184: int p = 0;
185:
186: while (true) {
187: p += 1;
188: k = k >> 7;
189: if (k == 0) {
190: break;
191: }
192: }
193:
194: k = values[j];
195: while (p > 0) {
196:
197: x[i] = (byte) (k >> ((p - 1) * 7));
198:
199: if (p == 1) {
200: x[i] &= 0x7f;
201: } else {
202: x[i] |= 0x80;
203: }
204: p--;
205: i++;
206: }
207: }
208:
209: byte[] data = new byte[i];
210: System.arraycopy(x, 0, data, 0, i);
211: return data;
212: }
213:
214: /** Hexadecimal digits. */
215: static char[] hc = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
216: '9', 'A', 'B', 'C', 'D', 'E', 'F' };
217:
218: /**
219: * Converts a subsequence of bytes in a byte array into a
220: * corresponding string of hexadecimal digits, each separated by a ":".
221: *
222: * @param b byte array containing the bytes to be converted
223: * @param off starting offset of the byte subsequence inside b
224: * @param len number of bytes to be converted
225: * @param max print a single "+" instead of the bytes after max,
226: * -1 for no max.
227: * @return a string of corresponding hexadecimal digits or
228: * an error string
229: */
230: static String hexEncode(byte[] b, int off, int len, int max) {
231: char[] r;
232: int v;
233: int i;
234: int j;
235:
236: if ((b == null) || (len == 0)) {
237: return "";
238: }
239:
240: if ((off < 0) || (len < 0)) {
241: throw new ArrayIndexOutOfBoundsException();
242: }
243:
244: r = new char[len * 3];
245:
246: for (i = 0, j = 0;;) {
247: v = b[off + i] & 0xff;
248: r[j++] = hc[v >>> 4];
249: r[j++] = hc[v & 0x0f];
250:
251: i++;
252: if (i >= len) {
253: break;
254: }
255:
256: if (i == max) {
257: r[j++] = ' ';
258: r[j++] = '+';
259: break;
260: }
261:
262: r[j++] = ':';
263: }
264:
265: return (new String(r, 0, j));
266: }
267:
268: /** Raw DER type. */
269: int type;
270: /** Number of bytes that make up the value. */
271: int length;
272: /** Offset of the value. */
273: int valueOffset;
274: /** Non-null for constructed types, the first child TLV. */
275: TLV child;
276: /** The next TLV in the parent sequence. */
277: TLV next;
278: /** Size of tag and length in DER encoding. */
279: int TLSize;
280: /** Buffer that contains the DER encoded TLV. */
281: byte[] data;
282:
283: /**
284: * Constructs a TLV structure, recursing down for constructed types.
285: *
286: * @param buffer DER buffer
287: * @param offset where to start parsing
288: *
289: * @exception IndexOutOfBoundException if the DER is corrupt
290: */
291: TLV(byte[] buffer, int offset) {
292:
293: boolean constructed;
294: int size;
295:
296: int start = offset;
297: data = buffer;
298:
299: type = buffer[offset++] & 0xff;
300:
301: // recurse for constructed types, bit 6 = 1
302: constructed = (type & 0x20) == 0x20;
303:
304: if ((type & 0x1f) == 0x1f) {
305: // multi byte type, 7 bits per byte, only last byte bit 8 as zero
306:
307: type = 0;
308: for (;;) {
309: int temp = buffer[offset++];
310: type = type << 7;
311: if (temp >= 0) {
312: type += temp;
313: break;
314: }
315:
316: // stip off bit 8
317: temp = temp & 0x7f;
318: type += temp;
319: }
320: }
321:
322: size = buffer[offset++] & 0xff;
323: if (size >= 128) {
324: int sizeLen = size - 128;
325:
326: // NOTE: for now, all sizes must fit int two bytes
327: if (sizeLen > 2) {
328: throw new RuntimeException("TLV size to large");
329: }
330:
331: size = 0;
332: while (sizeLen > 0) {
333: size = (size << 8) + (buffer[offset++] & 0xff);
334: sizeLen--;
335: }
336: }
337:
338: TLSize = offset - start;
339: length = size;
340: valueOffset = offset;
341:
342: if (constructed) {
343: int end;
344: TLV temp;
345:
346: end = offset + length;
347:
348: child = new TLV(buffer, offset);
349: temp = child;
350: for (;;) {
351: offset = temp.valueOffset + temp.length;
352: if (offset >= end) {
353: break;
354: }
355:
356: temp.next = new TLV(buffer, offset);
357: temp = temp.next;
358: }
359: }
360: }
361:
362: /**
363: * Constructs a TLV structure.
364: * @param tag tag of new TLV
365: */
366: TLV(int tag) {
367: type = tag;
368: }
369:
370: /**
371: * Constructs a TLV structure.
372: * @param tag tag of new TLV
373: * @param bytes value of new TLV
374: */
375: public TLV(int tag, byte[] bytes) {
376:
377: type = tag;
378: length = bytes.length;
379:
380: data = new byte[length + 4];
381: int i = putHeader(data, 0);
382:
383: TLSize = i;
384: valueOffset = i;
385: System.arraycopy(bytes, 0, data, i, bytes.length);
386: }
387:
388: /**
389: * Creates UTCTime TLV structure for given date.
390: * @param time date
391: */
392: public static TLV createUTCTime(Calendar time) {
393: byte[] data = new byte[13];
394: putDigits(data, 0, time.get(Calendar.YEAR));
395: putDigits(data, 2, time.get(Calendar.MONTH) + 1);
396: putDigits(data, 4, time.get(Calendar.DAY_OF_MONTH));
397: putDigits(data, 6, time.get(Calendar.HOUR_OF_DAY));
398: putDigits(data, 8, time.get(Calendar.MINUTE));
399: putDigits(data, 10, time.get(Calendar.SECOND));
400: data[12] = 0x5a;
401: return new TLV(UCT_TIME_TYPE, data);
402: }
403:
404: /**
405: * Places two ASCII encoded decimal digits into byte array.
406: * @param data byte aray
407: * @param offset the index of the first byte
408: * @param value the value to be placed into the buffer
409: */
410: private static void putDigits(byte[] data, int offset, int value) {
411:
412: value = value % 100;
413: data[offset++] = (byte) (0x30 | (value / 10));
414: data[offset++] = (byte) (0x30 | (value % 10));
415: }
416:
417: /**
418: * Print the a TLV structure, recursing down for constructed types.
419: */
420: void print() {
421: print(System.out, 0);
422: }
423:
424: /**
425: * Print the a TLV structure, recursing down for constructed types.
426: * @param out output stream
427: */
428: void print(PrintStream out) {
429: print(out, 0);
430: }
431:
432: /**
433: * Prints the a TLV structure, recursing down for constructed types.
434: * @param out output stream
435: * @param level what level this TLV is at
436: */
437: private void print(PrintStream out, int level) {
438:
439: for (int i = 0; i < level; i++) {
440: out.print(" ");
441: }
442:
443: byte[] buffer;
444:
445: if (data != null) {
446: buffer = data;
447: } else {
448: buffer = getDERData();
449: }
450:
451: if (child == null) {
452: out.print("Type: 0x" + Integer.toHexString(type)
453: + " length: " + length + " value: ");
454: if (type == PRINTSTR_TYPE || type == TELETEXSTR_TYPE
455: || type == UTF8STR_TYPE || type == IA5STR_TYPE
456: || type == UNIVSTR_TYPE) {
457: try {
458: out.print(new String(buffer, valueOffset, length,
459: "UTF-8"));
460: } catch (UnsupportedEncodingException e) {
461: // ignore
462: }
463: } else if (type == OID_TYPE) {
464: out.print(OIDtoString(buffer, valueOffset, length));
465: } else {
466: out
467: .print(hexEncode(buffer, valueOffset, length,
468: 999999));
469: }
470:
471: out.println("");
472: } else {
473: if (type == SET_TYPE) {
474: out.print("Set:");
475: } else {
476: out.print("Sequence:");
477: }
478:
479: out.println(" (0x" + Integer.toHexString(type) + " "
480: + length + ")");
481:
482: child.print(out, level + 1);
483: }
484:
485: if (next != null) {
486: next.print(out, level);
487: }
488: }
489:
490: /**
491: * Returns string representation of OID represented by this TLV.
492: * @return string representation of OID represented by this TLV
493: * @throws IOException if TLV doesn't contain OID
494: */
495: String getOID() throws IOException {
496:
497: if (type != OID_TYPE) {
498: throw new IOException("OID expected");
499: }
500: return OIDtoString(data, valueOffset, length);
501: }
502:
503: /**
504: * Returns the value field of this TLV.
505: * @return the value field of this TLV
506: */
507: byte[] getValue() {
508:
509: if (data == null) {
510: return copy().getValue();
511: }
512:
513: byte[] x = new byte[length];
514: System.arraycopy(data, valueOffset, x, 0, length);
515: return x;
516: }
517:
518: /**
519: * Places tag and length values into the buffer.
520: * @param x byte buffer
521: * @param i offset
522: * @return value offset in the buffer
523: */
524: private int putHeader(byte[] x, int i) {
525:
526: x[i++] = (byte) type;
527:
528: if (length < 128) {
529: x[i++] = (byte) length;
530: } else if (length < 256) {
531: x[i++] = (byte) 0x81;
532: x[i++] = (byte) length;
533: } else {
534: x[i++] = (byte) 0x82;
535: x[i++] = (byte) (length >> 8);
536: x[i++] = (byte) length;
537: }
538: return i;
539: }
540:
541: /**
542: * Returns DER encoded TLV.
543: * @return DER encoded TLV
544: */
545: byte[] getDERData() {
546:
547: if (data == null) {
548:
549: byte[] x = new byte[getDERSize()];
550:
551: int i = putHeader(x, 0);
552:
553: TLV c = child;
554:
555: while (c != null) {
556: byte[] cdata = c.getDERData();
557: System.arraycopy(cdata, 0, x, i, cdata.length);
558: i += cdata.length;
559: c = c.next;
560: }
561: if (i != x.length) {
562: throw new RuntimeException("debug");
563: }
564:
565: return x;
566: }
567:
568: byte[] x = new byte[length + TLSize];
569: System.arraycopy(data, valueOffset - TLSize, x, 0, length
570: + TLSize);
571: return x;
572: }
573:
574: /**
575: * Returns the size of DER encoded TLV.
576: * @return the size of DER encoded TLV
577: */
578: private int getDERSize() {
579:
580: if (data == null) {
581:
582: int size = 0;
583:
584: TLV c = child;
585:
586: while (c != null) {
587: size += c.getDERSize();
588: c = c.next;
589: }
590:
591: length = size;
592:
593: // length size
594: if (size < 128) {
595: size += 1;
596: } else {
597: size += 1;
598: int i = size;
599: while (i != 0) {
600: size += 1;
601: i = i >> 8;
602: }
603: }
604:
605: // tag size - only one byte tags are used
606: size += 1;
607:
608: TLSize = size - length;
609: }
610: return length + TLSize;
611: }
612:
613: /**
614: * Creates a copy of this TLV. The value of field next of the new TLV is
615: * null.
616: * @return a copy of this TLV
617: */
618: TLV copy() {
619: return new TLV(getDERData(), 0);
620: }
621: }
|