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 wim_data;
028:
029: import java.io.UnsupportedEncodingException;
030: import java.io.IOException;
031: import java.io.PrintStream;
032: import java.util.Calendar;
033: import java.lang.RuntimeException;
034:
035: /**
036: * Used to represent Type, Length, Value structure in a DER buffer.
037: */
038: public 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 hack
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 ENUMERATED type. [UNIVERSAL 10] */
060: static final int ENUMERATED_TYPE = 10;
061: /** ASN UTF8String type used in certificate parsing. [UNIVERSAL 12] */
062: static final int UTF8STR_TYPE = 12;
063: /**
064: * ASN SEQUENCE type used in certificate parsing.
065: * [UNIVERSAL CONSTRUCTED 16]
066: */
067: static final int SEQUENCE_TYPE = CONSTRUCTED + 16;
068: /**
069: * ASN SET type used in certificate parsing.
070: * [UNIVERSAL CONSTRUCTED 17]
071: */
072: static final int SET_TYPE = CONSTRUCTED + 17;
073: /** ASN PrintableString type used in certificate parsing. [UNIVERSAL 19] */
074: static final int PRINTSTR_TYPE = 19;
075: /** ASN TELETEX STRING type used in certificate parsing. [UNIVERSAL 20] */
076: static final int TELETEXSTR_TYPE = 20;
077: /** ASN IA5 STRING type used in certificate parsing. [UNIVERSAL 22] */
078: static final int IA5STR_TYPE = 22;
079: /** ASN UCT time type used in certificate parsing [UNIVERSAL 23] */
080: static final int UCT_TIME_TYPE = 23;
081: /**
082: * ASN Generalized time type used in certificate parsing.
083: * [UNIVERSAL 24]
084: */
085: static final int GEN_TIME_TYPE = 24;
086: /**
087: * ASN UniversalString type used in certificate parsing.
088: * [UNIVERSAL 28].
089: */
090: static final int UNIVSTR_TYPE = 28;
091: /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 30] */
092: static final int BMPSTR_TYPE = 30;
093: /**
094: * Context specific explicit type for certificate version.
095: * [CONTEXT EXPLICIT 0]
096: */
097: static final int VERSION_TYPE = CONTEXT + EXPLICIT + 0;
098: /**
099: * Context specific explicit type for certificate extensions.
100: * [CONTEXT EXPLICIT 3]
101: */
102: static final int EXTENSIONS_TYPE = CONTEXT + EXPLICIT + 3;
103:
104: /** Raw DER type. */
105: int type;
106: /** Number of bytes that make up the value. */
107: int length;
108: /** Offset of the value. */
109: int valueOffset;
110: /** Non-null for constructed types, the first child TLV. */
111: TLV child;
112: /** The next TLV in the parent sequence. */
113: TLV next;
114: /** Buffer that contains the DER encoded TLV. */
115: byte[] data;
116:
117: /**
118: * Constructs a TLV structure, recursing down for constructed types.
119: * @param buffer DER buffer
120: * @param offset where to start parsing
121: * @exception java.lang.IndexOutOfBoundsException if the DER is corrupt
122: */
123: public TLV(byte[] buffer, int offset) {
124:
125: boolean constructed;
126: int size;
127:
128: int start = offset;
129: data = buffer;
130:
131: type = buffer[offset++] & 0xff;
132:
133: // recurse for constructed types, bit 6 = 1
134: constructed = (type & 0x20) == 0x20;
135:
136: if ((type & 0x1f) == 0x1f) {
137: // multi byte type, 7 bits per byte, only last byte bit 8 as zero
138: throw new RuntimeException("Invalid tag");
139: }
140:
141: size = buffer[offset++] & 0xff;
142: if (size >= 128) {
143: int sizeLen = size - 128;
144:
145: // NOTE: for now, all sizes must fit int 3 bytes
146: if (sizeLen > 3) {
147: throw new RuntimeException("TLV size to large");
148: }
149:
150: size = 0;
151: while (sizeLen > 0) {
152: size = (size << 8) + (buffer[offset++] & 0xff);
153: sizeLen--;
154: }
155: }
156:
157: length = size;
158: valueOffset = offset;
159:
160: if (constructed && length != 0) {
161:
162: int end = offset + length;
163: child = new TLV(buffer, offset);
164: TLV temp = child;
165:
166: for (;;) {
167: offset = temp.valueOffset + temp.length;
168: if (offset == end) {
169: break;
170: }
171: if (offset > end) {
172: throw new RuntimeException("incorrect structure");
173: }
174: temp.next = new TLV(buffer, offset);
175: temp = temp.next;
176: }
177: }
178: }
179:
180: /**
181: * Constructs a TLV structure.
182: * @param tag tag of new TLV
183: */
184: TLV(int tag) {
185: type = tag;
186: }
187:
188: /**
189: * Constructs a TLV structure.
190: * @param tag tag of new TLV
191: * @param bytes value of new TLV
192: */
193: public TLV(int tag, byte[] bytes) {
194:
195: type = tag;
196: length = bytes.length;
197:
198: data = new byte[length + 4];
199: int i = putHeader(data, 0);
200:
201: valueOffset = i;
202: System.arraycopy(bytes, 0, data, i, bytes.length);
203: }
204:
205: /**
206: * Creates UTCTime TLV structure for given date.
207: * @param time date
208: * @return new TLV object
209: */
210: public static TLV createUTCTime(Calendar time) {
211: byte[] data = new byte[13];
212: putDigits(data, 0, time.get(Calendar.YEAR));
213: putDigits(data, 2, time.get(Calendar.MONTH) + 1);
214: putDigits(data, 4, time.get(Calendar.DAY_OF_MONTH));
215: putDigits(data, 6, time.get(Calendar.HOUR_OF_DAY));
216: putDigits(data, 8, time.get(Calendar.MINUTE));
217: putDigits(data, 10, time.get(Calendar.SECOND));
218: data[12] = 0x5a;
219: return new TLV(UCT_TIME_TYPE, data);
220: }
221:
222: /**
223: * Creates new sequence.
224: * @return new TLV object
225: */
226: public static TLV createSequence() {
227: return new TLV(SEQUENCE_TYPE);
228: }
229:
230: /**
231: * Creates new integer.
232: * @param data buffer containing the value
233: * @return new TLV object
234: */
235: public static TLV createInteger(byte[] data) {
236: return new TLV(INTEGER_TYPE, data);
237: }
238:
239: /**
240: * Creates new octet string.
241: * @param data buffer containing the value
242: * @return new TLV object
243: */
244: public static TLV createOctetString(byte[] data) {
245: return new TLV(OCTETSTR_TYPE, data);
246: }
247:
248: /**
249: * Creates new OID object.
250: * @param oid string representation of OID.
251: * @return new TLV object
252: */
253: public static TLV createOID(String oid) {
254: return new TLV(TLV.OID_TYPE, Utils.StringToOID(oid));
255: }
256:
257: /**
258: * Creates new UTF8 string.
259: * @param s string value
260: * @return new TLV object
261: */
262: public static TLV createUTF8String(String s) {
263: try {
264: return new TLV(TLV.UTF8STR_TYPE, s.getBytes("UTF-8"));
265: } catch (UnsupportedEncodingException e) {
266: }
267: return null;
268: }
269:
270: /**
271: * Creates new integer.
272: * @param value the value of new integer
273: * @return new TLV object
274: */
275: public static TLV createInteger(long value) {
276:
277: int check = (value < 0) ? -1 : 0;
278:
279: int i = 1;
280: while (true) {
281: if (value >> (i * 8) == check) {
282: byte v = (byte) (value >> ((i - 1) * 8));
283: if (value < 0 ? v > 0 : v < 0) {
284: i++;
285: }
286: break;
287: }
288: i++;
289: }
290:
291: byte[] data = new byte[i];
292: while (i > 0) {
293: i--;
294: data[i] = (byte) value;
295: value = value >> 8;
296: }
297: return new TLV(TLV.INTEGER_TYPE, data);
298: }
299:
300: /**
301: * Creates a copy of this TLV. The value of field next of the new TLV is
302: * null.
303: * @return a copy of this TLV
304: */
305: public TLV copy() {
306: return new TLV(getDERData(), 0);
307: }
308:
309: /**
310: * Sets the next DER entry for this object.
311: * @param next TLV object
312: * @return the value of next to allow call chaining
313: */
314: public TLV setNext(TLV next) {
315: this .next = next;
316: return next;
317: }
318:
319: /**
320: * Sets the child DER entry for this object.
321: * @param child TLV object
322: * @return the value of child field to allow call chaining
323: */
324: public TLV setChild(TLV child) {
325: this .child = child;
326: return child;
327: }
328:
329: /**
330: * Sets the (implicit) tag value for this object.
331: * @param tag tag value
332: * @return <code>this</code> value to allow call chaining
333: */
334: public TLV setTag(int tag) {
335: this .type = tag;
336: return this ;
337: }
338:
339: /**
340: * Print the a TLV structure, recursing down for constructed types.
341: */
342: public void print() {
343: print(System.out, 0);
344: }
345:
346: /**
347: * Print the a TLV structure, recursing down for constructed types.
348: * @param out output stream
349: */
350: public void print(PrintStream out) {
351: print(out, 0);
352: }
353:
354: /**
355: * Returns string representation of OID represented by this TLV.
356: * @return string representation of OID represented by this TLV
357: * @throws java.io.IOException if TLV doesn't contain OID
358: */
359: public String getOID() throws IOException {
360:
361: if (type != OID_TYPE) {
362: throw new IOException("OID expected");
363: }
364: return Utils.OIDtoString(data, valueOffset, length);
365: }
366:
367: /**
368: * Returns the value field of this TLV.
369: * @return the value field of this TLV
370: */
371: public byte[] getValue() {
372:
373: if (data == null) {
374: getDERSize();
375: }
376: byte[] x = new byte[length];
377: getValue_(x, 0);
378: return x;
379: }
380:
381: /**
382: * Places the value field of this TLV into the buffer.
383: * @param buffer destination buffer
384: * @param offset offset in the buffer
385: * @return TLV size in bytes
386: */
387: public int getValue(byte[] buffer, int offset) {
388:
389: if (data == null) {
390: getDERSize();
391: }
392: return getValue_(buffer, offset);
393: }
394:
395: /**
396: * Returns DER encoded TLV.
397: * @return DER encoded TLV
398: */
399: public byte[] getDERData() {
400:
401: byte[] x = new byte[getDERSize()];
402: getDERData_(x, 0);
403: return x;
404: }
405:
406: /**
407: * Returns DER encoded TLV.
408: * @param buffer destination buffer
409: * @param offset offset in the buffer
410: * @return DER encoded TLV
411: */
412: public int getDERData(byte[] buffer, int offset) {
413:
414: getDERSize();
415: return getDERData_(buffer, offset);
416: }
417:
418: /**
419: * Returns the size of DER encoded TLV.
420: * @return the size of DER encoded TLV
421: */
422: public int getDERSize() {
423:
424: if (data == null) {
425: length = 0;
426: TLV c = child;
427: while (c != null) {
428: length += c.getDERSize();
429: c = c.next;
430: }
431: }
432: return length + getTLSize();
433: }
434:
435: /**
436: * Places two ASCII encoded decimal digits into byte array.
437: * @param data byte aray
438: * @param offset the index of the first byte
439: * @param value the value to be placed into the buffer
440: */
441: private static void putDigits(byte[] data, int offset, int value) {
442:
443: value = value % 100;
444: data[offset++] = (byte) (0x30 | (value / 10));
445: data[offset++] = (byte) (0x30 | (value % 10));
446: }
447:
448: /**
449: * Prints the a TLV structure, recursing down for constructed types.
450: * @param out output stream
451: * @param level what level this TLV is at
452: */
453: private void print(PrintStream out, int level) {
454:
455: for (int i = 0; i < level; i++) {
456: out.print(" ");
457: }
458:
459: byte[] buffer;
460:
461: if (data != null) {
462: buffer = data;
463: } else {
464: buffer = getDERData();
465: }
466:
467: if (child == null) {
468: out.print("Type: 0x" + Integer.toHexString(type)
469: + " length: " + length + " value: ");
470: if (type == PRINTSTR_TYPE || type == TELETEXSTR_TYPE
471: || type == UTF8STR_TYPE || type == IA5STR_TYPE
472: || type == UNIVSTR_TYPE) {
473: try {
474: out.print(new String(buffer, valueOffset, length,
475: "UTF-8"));
476: } catch (UnsupportedEncodingException e) {
477: // ignore
478: }
479: } else if (type == OID_TYPE) {
480: out.print(Utils
481: .OIDtoString(buffer, valueOffset, length));
482: } else {
483: out.print(Utils.hexEncode(buffer, valueOffset, length));
484: }
485:
486: out.println("");
487: } else {
488: if (type == SET_TYPE) {
489: out.print("Set:");
490: } else {
491: out.print("Sequence:");
492: }
493:
494: out.println(" (0x" + Integer.toHexString(type) + " "
495: + length + ")");
496:
497: child.print(out, level + 1);
498: }
499:
500: if (next != null) {
501: next.print(out, level);
502: }
503: }
504:
505: /**
506: * Places the value field of this TLV into the buffer.
507: * @param buffer destination buffer
508: * @param offset offset in the buffer
509: * @return TLV size in bytes
510: */
511: private int getValue_(byte[] buffer, int offset) {
512:
513: if (data == null) {
514: TLV c = child;
515: while (c != null) {
516: offset += c.getDERData_(buffer, offset);
517: c = c.next;
518: }
519: } else {
520: System.arraycopy(data, valueOffset, buffer, offset, length);
521: }
522: return length;
523: }
524:
525: /**
526: * Places tag and length values into the buffer.
527: * @param x byte buffer
528: * @param i offset
529: * @return value offset in the buffer
530: */
531: private int putHeader(byte[] x, int i) {
532:
533: x[i++] = (byte) type;
534:
535: if (length < 128) {
536: x[i++] = (byte) length;
537: } else if (length < 256) {
538: x[i++] = (byte) 0x81;
539: x[i++] = (byte) length;
540: } else {
541: x[i++] = (byte) 0x82;
542: x[i++] = (byte) (length >> 8);
543: x[i++] = (byte) length;
544: }
545: return i;
546: }
547:
548: /**
549: * Places DER encoded TLV into the buffer.
550: * @param buffer destination buffer
551: * @param offset offset in the buffer
552: * @return TLV size
553: */
554: private int getDERData_(byte[] buffer, int offset) {
555:
556: int initialOffset = offset;
557: offset = putHeader(buffer, offset);
558:
559: if (data == null) {
560: TLV c = child;
561: while (c != null) {
562: offset += c.getDERData_(buffer, offset);
563: c = c.next;
564: }
565: } else {
566: System.arraycopy(data, valueOffset, buffer, offset, length);
567: offset += length;
568: }
569: return (offset - initialOffset);
570: }
571:
572: /**
573: * Returns size in bytes of tag and length.
574: * @return size in bytes of tag and length
575: */
576: private int getTLSize() {
577:
578: int TLSize = 2;
579: if (length >= 128) {
580: int i = length;
581: while (i != 0) {
582: TLSize++;
583: i = i >> 8;
584: }
585: }
586: return TLSize;
587: }
588: }
|