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 acl_data;
028:
029: import java.io.PrintStream;
030: import java.io.UnsupportedEncodingException;
031: import java.util.Calendar;
032:
033: /**
034: * Used to represent each Type, Length, Value structure in a DER buffer.
035: */
036: public class TLV {
037:
038: /*
039: * This class is used to parse DER encoded data (BER indefinite
040: * length is also supported) and assemble new DER data structures
041: * from elements. It is not safe to modify elements of constructed
042: * DER value that was created using parsing constructor or copy()
043: * method.
044: */
045:
046: /** ASN context specific flag used in types (0x80). */
047: public static final int CONTEXT = 0x80;
048: /** ASN constructed flag used in types (0x20). */
049: public static final int CONSTRUCTED = 0x20;
050: /** ASN constructed flag used in types (0x20). */
051: public static final int EXPLICIT = CONSTRUCTED;
052: /** ANY_STRING type used as a place holder. [UNIVERSAL 0] */
053: public static final int ANY_STRING_TYPE = 0x00; // our own impl
054: /** ASN BOOLEAN type used in certificate parsing. [UNIVERSAL 1] */
055: public static final int BOOLEAN_TYPE = 1;
056: /** ASN INTEGER type used in certificate parsing. [UNIVERSAL 2] */
057: public static final int INTEGER_TYPE = 2;
058: /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 3] */
059: public static final int BITSTRING_TYPE = 3;
060: /** ASN OCTET STRING type used in certificate parsing. [UNIVERSAL 4] */
061: public static final int OCTETSTR_TYPE = 4;
062: /** ASN NULL type used in certificate parsing. [UNIVERSAL 5] */
063: public static final int NULL_TYPE = 5;
064: /** ASN OBJECT ID type used in certificate parsing. [UNIVERSAL 6] */
065: public static final int OID_TYPE = 6;
066: /** ASN ENUMERATED type. [UNIVERSAL 10] */
067: public static final int ENUMERATED_TYPE = 10;
068: /** ASN UTF8String type used in certificate parsing. [UNIVERSAL 12] */
069: public static final int UTF8STR_TYPE = 12;
070: /**
071: * ASN SEQUENCE type used in certificate parsing.
072: * [UNIVERSAL CONSTRUCTED 16]
073: */
074: public static final int SEQUENCE_TYPE = CONSTRUCTED + 16;
075: /**
076: * ASN SET type used in certificate parsing.
077: * [UNIVERSAL CONSTRUCTED 17]
078: */
079: public static final int SET_TYPE = CONSTRUCTED + 17;
080: /** ASN PrintableString type used in certificate parsing. [UNIVERSAL 19] */
081: public static final int PRINTSTR_TYPE = 19;
082: /** ASN TELETEX STRING type used in certificate parsing. [UNIVERSAL 20] */
083: public static final int TELETEXSTR_TYPE = 20;
084: /** ASN IA5 STRING type used in certificate parsing. [UNIVERSAL 22] */
085: public static final int IA5STR_TYPE = 22;
086: /** ASN UCT time type used in certificate parsing. [UNIVERSAL 23] */
087: public static final int UCT_TIME_TYPE = 23;
088: /**
089: * ASN Generalized time type used in certificate parsing.
090: * [UNIVERSAL 24]
091: */
092: public static final int GEN_TIME_TYPE = 24;
093: /**
094: * ASN UniversalString type used in certificate parsing.
095: * [UNIVERSAL 28].
096: */
097: public static final int UNIVSTR_TYPE = 28;
098: /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 30] */
099: public static final int BMPSTR_TYPE = 30;
100: /**
101: * Context specific explicit type for certificate version.
102: * [CONTEXT EXPLICIT 0]
103: */
104: public static final int VERSION_TYPE = CONTEXT + EXPLICIT + 0;
105: /**
106: * Context specific explicit type for certificate extensions.
107: * [CONTEXT EXPLICIT 3]
108: */
109: public static final int EXTENSIONS_TYPE = CONTEXT + EXPLICIT + 3;
110:
111: /** Raw DER type. */
112: public int type;
113: /** Number of bytes that make up the value. */
114: public int length;
115: /** Offset of the value. */
116: public int valueOffset;
117: /** Non-null for constructed types, the first child TLV. */
118: public TLV child;
119: /** The next TLV in the parent sequence. */
120: public TLV next;
121: /** Buffer that contains the DER encoded TLV. */
122: public byte[] data;
123:
124: /**
125: * Constructs a TLV structure, recursing down for constructed types.
126: * @param buffer DER buffer
127: * @param offset where to start parsing
128: * @exception IndexOutOfBoundsException if the DER is corrupt
129: * @throws TLVException in case of parsing error
130: */
131: public TLV(byte[] buffer, int offset) throws TLVException {
132:
133: try {
134: data = buffer;
135: type = buffer[offset++] & 0xff;
136:
137: if ((type & 0x1f) == 0x1f) {
138: // multi byte type, 7 bits per byte,
139: // only last byte bit 8 as zero
140: throw new TLVException("Invalid tag");
141: }
142:
143: int size = buffer[offset++] & 0xff;
144: boolean indefinite = (size == 128);
145: if (indefinite) {
146: if ((type & 0x20) == 0) {
147: throw new TLVException("Invalid length");
148: }
149: } else if (size >= 128) {
150: int sizeLen = size - 128;
151:
152: // NOTE: for now, all sizes must fit int 3 bytes
153: if (sizeLen > 3) {
154: throw new TLVException("TLV is too large");
155: }
156:
157: size = 0;
158: while (sizeLen > 0) {
159: size = (size << 8) + (buffer[offset++] & 0xff);
160: sizeLen--;
161: }
162: }
163:
164: length = size;
165: valueOffset = offset;
166:
167: if ((type & 0x20) == 0 || length == 0) {
168: return;
169: }
170:
171: // constructed and not empty
172:
173: TLV prev = null;
174: while (true) {
175: if (indefinite && data[offset] == 0
176: && data[offset + 1] == 0) {
177: length = offset - valueOffset;
178: return;
179: }
180:
181: TLV temp = new TLV(buffer, offset);
182: offset = (data[offset + 1] == (byte) 0x80 ? 2 : 0)
183: + temp.valueOffset + temp.length;
184:
185: if (prev == null) {
186: child = temp;
187: } else {
188: prev.next = temp;
189: }
190: prev = temp;
191:
192: if (indefinite) {
193: continue;
194: }
195: if (offset == valueOffset + length) {
196: break;
197: }
198: if (offset > valueOffset + length) {
199: throw new TLVException("incorrect structure");
200: }
201: }
202: } catch (RuntimeException e) {
203: throw new TLVException("parser error");
204: }
205: }
206:
207: /**
208: * Constructs a TLV structure.
209: * @param tag tag of new TLV
210: */
211: public TLV(int tag) {
212: type = tag;
213: }
214:
215: /**
216: * Constructs a TLV structure.
217: * @param tag tag of the new TLV
218: * @param bytes value of the new TLV
219: */
220: public TLV(int tag, byte[] bytes) {
221: type = tag;
222: valueOffset = 0;
223: length = bytes.length;
224: data = bytes;
225: }
226:
227: /**
228: * Constructs a TLV structure.
229: * @param tag tag of the new TLV
230: * @param bytes data for new TLV
231: * @param offset of data
232: */
233: public TLV(int tag, byte[] bytes, int offset) {
234: type = tag;
235: valueOffset = offset;
236: length = bytes.length - offset;
237: data = bytes;
238: }
239:
240: /**
241: * Creates UTCTime TLV structure for given date.
242: * @param time date
243: * @return TLV value representing this date
244: */
245: public static TLV createUTCTime(Calendar time) {
246: byte[] data = new byte[13];
247: putDigits(data, 0, time.get(Calendar.YEAR));
248: putDigits(data, 2, time.get(Calendar.MONTH) + 1);
249: putDigits(data, 4, time.get(Calendar.DAY_OF_MONTH));
250: putDigits(data, 6, time.get(Calendar.HOUR_OF_DAY));
251: putDigits(data, 8, time.get(Calendar.MINUTE));
252: putDigits(data, 10, time.get(Calendar.SECOND));
253: data[12] = 0x5a;
254: return new TLV(UCT_TIME_TYPE, data);
255: }
256:
257: /**
258: * Creates TLV object of type sequence.
259: * @return new object
260: */
261: public static TLV createSequence() {
262: return new TLV(SEQUENCE_TYPE);
263: }
264:
265: /**
266: * Creates TLV object of type integer.
267: * @param data value
268: * @return new object
269: */
270: public static TLV createInteger(byte[] data) {
271: return new TLV(INTEGER_TYPE, data);
272: }
273:
274: /**
275: * Creates TLV object of type octet string.
276: * @param data value
277: * @return new object
278: */
279: public static TLV createOctetString(byte[] data) {
280: return new TLV(OCTETSTR_TYPE, data);
281: }
282:
283: /**
284: * Creates TLV object of type octet string.
285: * @param p_data byte[] value
286: * @param offset int offset in the p_data
287: * @param length int number of bytes from the p_data
288: * @return new object
289: */
290: public static TLV createOctetString(byte[] p_data, int offset,
291: int length) {
292: byte[] data = new byte[length];
293: for (int i = 0; i < length; i++) {
294: data[i] = p_data[i + offset];
295: }
296: return new TLV(OCTETSTR_TYPE, data);
297: }
298:
299: /**
300: * Creates TLV object of type bit string.
301: * @param p_data byte[] value
302: * @param notUsed int number of bytes from the p_data that are not used
303: * @return new TLV object
304: */
305: public static TLV createBitString(byte[] p_data, int notUsed) {
306: byte[] data = new byte[p_data.length + 1];
307: data[0] = (byte) notUsed;
308: for (int i = 0; i < p_data.length; i++) {
309: data[i + 1] = p_data[i];
310: }
311: return new TLV(BITSTRING_TYPE, data);
312: }
313:
314: /**
315: * Creates TLV object of type OID.
316: * @param oid OID in text form
317: * @return new object
318: */
319: public static TLV createOID(String oid) {
320: return new TLV(TLV.OID_TYPE, Utils.StringToOID(oid));
321: }
322:
323: /**
324: * Creates TLV object of type UTF8 string.
325: * @param s string value
326: * @return new object
327: */
328: public static TLV createUTF8String(String s) {
329: return new TLV(TLV.UTF8STR_TYPE, Utils.stringToBytes(s));
330: }
331:
332: /**
333: * Creates TLV object of type integer.
334: * @param value value
335: * @return new object
336: */
337: public static TLV createInteger(long value) {
338:
339: int check = (value < 0) ? -1 : 0;
340:
341: int i = 1;
342: while (i < 8) {
343: if (value >> (i * 8) == check) {
344: byte v = (byte) (value >> ((i - 1) * 8));
345: if (value < 0 ? v > 0 : v < 0) {
346: i++;
347: }
348: break;
349: }
350: i++;
351: }
352:
353: byte[] data = new byte[i];
354: while (i > 0) {
355: i--;
356: data[i] = (byte) value;
357: value = value >> 8;
358: }
359: return new TLV(TLV.INTEGER_TYPE, data);
360: }
361:
362: /**
363: * Creates a copy of this TLV. The value of field next of the new
364: * TLV is null.
365: * @return a copy of this TLV
366: */
367: public TLV copy() {
368: try {
369: return new TLV(getDERData(), 0);
370: } catch (TLVException e) {
371: }
372: return null;
373: }
374:
375: /**
376: * Sets next element for this TLV object.
377: * @param next the next object
378: * @return the passed value to allow chaining
379: */
380: public TLV setNext(TLV next) {
381: this .next = next;
382: return next;
383: }
384:
385: /**
386: * Sets child element for this TLV object.
387: * @param child the child object
388: * @return the passed value to allow chaining
389: */
390: public TLV setChild(TLV child) {
391: this .child = child;
392: return child;
393: }
394:
395: /**
396: * Sets the (implicit) tag value for this object.
397: * @param tag tag value
398: * @return <code>this</code> value to allow call chaining
399: */
400: public TLV setTag(int tag) {
401: this .type = tag;
402: return this ;
403: }
404:
405: /**
406: * Returns the value field of this TLV.
407: * @return the value field of this TLV
408: */
409: public byte[] getValue() {
410:
411: if (data == null) {
412: getDERSize();
413: }
414: byte[] x = new byte[length];
415: getValue_(x, 0);
416: return x;
417: }
418:
419: /**
420: * Returns DER encoded TLV.
421: * @return DER encoded TLV
422: */
423: public byte[] getDERData() {
424:
425: byte[] x = new byte[getDERSize()];
426: getDERData_(x, 0);
427: return x;
428: }
429:
430: /**
431: * Returns DER encoded TLV.
432: * @param buffer target buffer
433: * @param offset offset in the buffer
434: * @return value length
435: */
436: public int getDERData(byte[] buffer, int offset) {
437:
438: getDERSize();
439: return getDERData_(buffer, offset);
440: }
441:
442: /**
443: * Returns the size of DER encoded TLV.
444: * @return the size of DER encoded TLV
445: */
446: public int getDERSize() {
447:
448: if (data == null) {
449: length = 0;
450: TLV c = child;
451: while (c != null) {
452: length += c.getDERSize();
453: c = c.next;
454: }
455: }
456: return length + getTLSize();
457: }
458:
459: /**
460: * Returns integer value.
461: * @return integer value
462: * @throws TLVException if this TLV doesn't represent integer value
463: */
464: public int getInteger() throws TLVException {
465:
466: if (type != INTEGER_TYPE && ((type & 0xf0) != 0x80)) {
467: throw new TLVException("invalid type - getInteger");
468: }
469: return getIntegerValue();
470: }
471:
472: /**
473: * Returns octet string value as integer.
474: * @return integer value
475: * @throws TLVException if this TLV is not octet string
476: */
477: public int getId() throws TLVException {
478:
479: if (type != OCTETSTR_TYPE) {
480: throw new TLVException("invalid type - getId");
481: }
482: return getIntegerValue();
483: }
484:
485: /**
486: * Returns the value of enumerated type.
487: * @return the value
488: * @throws TLVException if TLV type is invalid
489: */
490: public int getEnumerated() throws TLVException {
491:
492: if (type != ENUMERATED_TYPE) {
493: throw new TLVException("invalid type - getEnumerated");
494: }
495: return getIntegerValue();
496: }
497:
498: /**
499: * Returns the value of TLV as integer.
500: * @return the integer value
501: * @throws TLVException if the value is too long
502: */
503: private int getIntegerValue() throws TLVException {
504:
505: int l = data[valueOffset] < 0 ? -1 : 0;
506: int check = l << 24;
507:
508: for (int i = 0; i < length; i++) {
509: if ((l & 0xff000000) != check) {
510: throw new TLVException("Integer value is too big");
511: }
512: l = (l << 8) | (data[valueOffset + i] & 0xff);
513: }
514: return l;
515: }
516:
517: /**
518: * Returns string represented by this UTF8 string.
519: * @return string value
520: * @throws TLVException if TLV type is invalid
521: */
522: public String getUTF8() throws TLVException {
523:
524: if (type != UTF8STR_TYPE && ((type & 0xf0) != 0x80)) {
525: throw new TLVException("invalid type - getUTF8");
526: }
527:
528: try {
529: return new String(data, valueOffset, length, Utils.utf8);
530: } catch (UnsupportedEncodingException e) {
531: throw new TLVException("invalid encoding");
532: }
533: }
534:
535: /**
536: * Returns true if this value represents string.
537: * @return true if this value represents string
538: */
539: public boolean isString() {
540: return (type == TELETEXSTR_TYPE || type == PRINTSTR_TYPE
541: || type == UNIVSTR_TYPE || type == UTF8STR_TYPE || type == BMPSTR_TYPE);
542: }
543:
544: /**
545: * Returns time represented by this TLV.
546: * @return time value
547: * @throws TLVException if TLV type is invalid
548: */
549: public Calendar getTime() throws TLVException {
550:
551: if (type != GEN_TIME_TYPE && type != UCT_TIME_TYPE) {
552: throw new TLVException("invalid type - getType");
553: }
554:
555: Calendar c = Calendar.getInstance();
556:
557: int offset;
558: int year;
559: if (type == GEN_TIME_TYPE) {
560: year = getTimeComponent(0, 4);
561: offset = 4;
562: } else {
563: year = getTimeComponent(0, 2);
564: year += (year >= 50) ? 1900 : 2000;
565: offset = 2;
566: }
567: c.set(Calendar.YEAR, year);
568: c.set(Calendar.MONTH, getTimeComponent(offset, 2) - 1);
569: offset += 2;
570: c.set(Calendar.DAY_OF_MONTH, getTimeComponent(offset, 2));
571: offset += 2;
572: c.set(Calendar.HOUR_OF_DAY, getTimeComponent(offset, 2));
573: offset += 2;
574: c.set(Calendar.MINUTE, getTimeComponent(offset, 2));
575: offset += 2;
576: c.set(Calendar.SECOND, getTimeComponent(offset, 2));
577:
578: return c;
579: }
580:
581: /**
582: * Returns decoded BCD value.
583: * @param offset value offset
584: * @param len value length
585: * @return decoded value
586: */
587: private int getTimeComponent(int offset, int len) {
588:
589: int value = 0;
590: while (len-- > 0) {
591: value = value * 10 + (data[valueOffset + offset++] - 0x30);
592: }
593: return value;
594: }
595:
596: /**
597: * Skips optional element of DER structure with given tag.
598: * @param type tag of optional value
599: * @return this object if type doesn't match or the next one if it
600: * does
601: */
602: public TLV skipOptional(int type) {
603:
604: if (this .type == type) {
605: return next;
606: }
607: return this ;
608: }
609:
610: /**
611: * Returns the value of flag stored in bitsring value.
612: * @param index flag index
613: * @return true if the flag is set
614: * @throws TLVException if TLV type is invalid
615: */
616: public boolean checkFlag(int index) throws TLVException {
617:
618: if (type != BITSTRING_TYPE) {
619: throw new TLVException("invalid type - checkFlag");
620: }
621:
622: int i = (length - 1) * 8 - data[valueOffset];
623: if (index >= i) {
624: return false;
625: }
626:
627: return ((data[valueOffset + 1 + (index / 8)] << index % 8) & 0x80) != 0;
628: }
629:
630: /**
631: * Compares the value of this TLV with given value.
632: * @param data the value to be compared
633: * @return true if TLV object contains the same value
634: */
635: public boolean valueEquals(byte[] data) {
636: return Utils.byteMatch(this .data, valueOffset, length, data, 0,
637: data.length);
638: }
639:
640: /**
641: * Places two ASCII encoded decimal digits into byte array.
642: * @param data byte aray
643: * @param offset the index of the first byte
644: * @param value the value to be placed into the buffer
645: */
646: private static void putDigits(byte[] data, int offset, int value) {
647:
648: value = value % 100;
649: data[offset++] = (byte) (0x30 | (value / 10));
650: data[offset++] = (byte) (0x30 | (value % 10));
651: }
652:
653: /**
654: * Print the a TLV structure, recursing down for constructed types.
655: */
656: public void print() {
657: print(System.out, 0);
658: }
659:
660: /**
661: * Print the a TLV structure, recursing down for constructed types.
662: * @param out output stream
663: */
664: public void print(PrintStream out) {
665: print(out, 0);
666: }
667:
668: /**
669: * Prints the a TLV structure, recursing down for constructed types.
670: * @param out output stream
671: * @param level what level this TLV is at
672: */
673: private void print(PrintStream out, int level) {
674:
675: for (int i = 0; i < level; i++) {
676: out.print(" ");
677: }
678:
679: byte[] buffer;
680:
681: if (data != null) {
682: buffer = data;
683: } else {
684: buffer = getDERData();
685: }
686:
687: if (child == null) {
688: out.print("Type: 0x" + Integer.toHexString(type)
689: + " length: " + length + " value: ");
690: if (type == PRINTSTR_TYPE || type == TELETEXSTR_TYPE
691: || type == UTF8STR_TYPE || type == IA5STR_TYPE
692: || type == UNIVSTR_TYPE) {
693: try {
694: out.print(new String(buffer, valueOffset, length,
695: Utils.utf8));
696: } catch (UnsupportedEncodingException e) {
697: // ignore
698: }
699: } else if (type == OID_TYPE) {
700: out.print(Utils
701: .OIDtoString(buffer, valueOffset, length));
702: } else {
703: out.print(Utils.hexNumber(buffer, valueOffset, length));
704: }
705:
706: out.println("");
707: } else {
708: if (type == SET_TYPE) {
709: out.print("Set:");
710: } else {
711: out.print("Sequence:");
712: }
713:
714: out.println(" (0x" + Integer.toHexString(type) + " "
715: + length + ")");
716:
717: child.print(out, level + 1);
718: }
719:
720: if (next != null) {
721: next.print(out, level);
722: }
723: }
724:
725: /**
726: * Places the value field of this TLV into the buffer.
727: * @param buffer target buffer
728: * @param offset index of the first byte
729: * @return value length
730: */
731: private int getValue_(byte[] buffer, int offset) {
732:
733: if (data == null) {
734: TLV c = child;
735: while (c != null) {
736: offset += c.getDERData(buffer, offset);
737: c = c.next;
738: }
739: } else {
740: System.arraycopy(data, valueOffset, buffer, offset, length);
741: }
742: return length;
743: }
744:
745: /**
746: * Places tag and length values into the buffer.
747: * @param x byte buffer
748: * @param i offset
749: * @return value offset in the buffer
750: */
751: private int putHeader(byte[] x, int i) {
752:
753: x[i++] = (byte) type;
754:
755: if (length < 128) {
756: x[i++] = (byte) length;
757: } else if (length < 256) {
758: x[i++] = (byte) 0x81;
759: x[i++] = (byte) length;
760: } else {
761: x[i++] = (byte) 0x82;
762: x[i++] = (byte) (length >> 8);
763: x[i++] = (byte) length;
764: }
765: return i;
766: }
767:
768: /**
769: * Returns DER encoded TLV.
770: * @param buffer target buffer
771: * @param offset offset in the buffer
772: * @return value length
773: */
774: private int getDERData_(byte[] buffer, int offset) {
775:
776: int initialOffset = offset;
777: offset = putHeader(buffer, offset);
778:
779: if (data == null) {
780: TLV c = child;
781: while (c != null) {
782: offset += c.getDERData_(buffer, offset);
783: c = c.next;
784: }
785: } else {
786: System.arraycopy(data, valueOffset, buffer, offset, length);
787: offset += length;
788: }
789: return (offset - initialOffset);
790: }
791:
792: /**
793: * Returns the size of tag and length encoding.
794: * @return the size of tag and length encoding
795: */
796: private int getTLSize() {
797:
798: int TLSize = 2;
799: if (length >= 128) {
800: int i = length;
801: while (i != 0) {
802: TLSize++;
803: i = i >> 8;
804: }
805: }
806: return TLSize;
807: }
808:
809: /**
810: * Compares this object with other TLV object.
811: * @param t TLV object
812: * @return true if both objects have the same type and contain
813: * the same data
814: */
815: public boolean match(TLV t) {
816:
817: if (type != t.type) {
818: return false;
819: }
820: if (t.data == null) {
821: t = t.copy();
822: }
823: if (data == null) {
824: t.match(this);
825: }
826: return Utils.byteMatch(data, valueOffset, length, t.data,
827: t.valueOffset, t.length);
828: }
829:
830: }
|