1
10package org.jstk.asn1;
11
12import java.io.*;
13import java.util.*;
14import org.jstk.pem.*;
15import org.jstk.JSTKOptions;
16
17public class DefASN1PullParser implements ASN1PullParser {
18 private InputStream is;
19 private int curTagNumber = 0;
20 private byte curTagClass = 0x00;
21 private byte consMask = ASN1Type.PRIMITIVE;
22 private int curLength = 0;
23 private int curOffset = 0;
24 private int startOffset = 0;
25 private int curDepth = 0;
26 private int curHLength = 0;
27 private byte[] curContent = null;
28
29 private boolean prevFlag = false;
30 private int curEvent;
31
32 static class STypeObj {
33 int remainingLen;
34 int type;
35 STypeObj(int len, int type){
36 this.remainingLen = len;
37 this.type = type;
38 }
39 };
40
41 private Stack activeSTypes = new Stack();
42
43 public int next() throws ASN1PullParserException, IOException {
44 if (prevFlag){
45 prevFlag = false;
46 return curEvent;
47 }
48
49 curContent = null;
50 STypeObj activeSTypeObj = null;
52 if (!activeSTypes.empty()){
53 activeSTypeObj = (STypeObj)activeSTypes.peek();
54 if (activeSTypeObj.remainingLen == 0){
55 activeSTypes.pop();
56 --curDepth;
57 curEvent = (activeSTypeObj.type == SEQ ? END_SEQ : END_SET);
60 return curEvent;
61 }
62 }
63
64 if (is.available() == 0){ curEvent = EOF;
67 return (curEvent);
68 }
69
70 startOffset = curOffset;
71 byte curOctet = read(is); curTagClass = (byte)(curOctet & CLASSBITS);
75 curTagNumber = (int)(curOctet & TAGBITS);
76 consMask = (byte)(curOctet & (byte)ASN1Type.CONSTRUCTED);
77
79 if (curTagNumber == TAGBITS){ System.out.println("High tag number format");
82 curTagNumber = 0;
83 int noOctets = 0;
84 do {
85 curOctet = (byte)is.read();
86 curTagNumber = 128*curTagNumber + (curOctet & 0x7f);
87 ++noOctets;
88 if (noOctets > 4)
89 throw new ASN1PullParserException("tag number more than 4 octets");
90 } while ((curOctet & 0x80) == 0x80); }
92
93 curOctet = read(is);
95 if ((curOctet & 0x80) == 0){ curLength = curOctet & 0x7f;
97 } else { int noOctets = curOctet & 0x7f;
99 if (noOctets > 4)
00 throw new ASN1PullParserException("length more than 4 octets");
01 curLength = 0;
02 for (int i = 0; i < noOctets; i++){
03 curOctet = read(is);
04 curLength = 256*curLength + (curOctet & 0xff);
05 }
06 }
07
08 curHLength = curOffset - startOffset;
09 if (activeSTypeObj != null){
11 activeSTypeObj.remainingLen -= (curHLength + curLength);
12 }
13 curEvent = curTagNumber;
14 if (curTagNumber == SET){
15 activeSTypes.push(new STypeObj(curLength, SET));
16 ++curDepth;
17 curEvent = START_SET;
18 } else if (curTagNumber == SEQ){
19 activeSTypes.push(new STypeObj(curLength, SEQ));
20 ++curDepth;
21 curEvent = START_SEQ;
22 } else if (consMask == ASN1Type.CONSTRUCTED){
23 if (activeSTypeObj != null){
24 activeSTypeObj.remainingLen += curLength;
25 }
26 }
27
28 if (consMask == ASN1Type.PRIMITIVE)
29 curContent = read(is, curLength);
30 return curEvent;
31 }
32
33 public void prev() throws ASN1PullParserException {
34 prevFlag = true;
35 }
36
37 public int getOffset(){
38 return startOffset;
39 }
40
41 public int getDepth(){
42 return curDepth;
43 }
44
45 public int getHLength(){
46 return curHLength;
47 }
48
49 public int getLength(){
50 return curLength;
51 }
52
53 public int getType(){
54 return curTagNumber;
55 }
56
57 public int getTagNumber(){
58 return curTagNumber;
59 }
60
61 public byte getTagClass(){
62 return curTagClass;
63 }
64
65 public byte getConsMask(){
66 return consMask;
67 }
68
69 public String getTypeString(){
70 if ((consMask == ASN1Type.CONSTRUCTED) && (curTagNumber != SEQ) && (curTagNumber != SET)){
71 return "cons: [" + curTagNumber + "]";
72 }
73 switch (curTagNumber){
74 case BOOLEAN: return "prim: BOOLEAN";
75 case INTEGER: return "prim: INTEGER";
76 case BIT_STRING: return "prim: BIT STRING";
77 case OCTET_STRING: return "prim: OCTET STRING";
78 case NULL: return "prim: NULL";
79 case OID: return "prim: OBJECT";
80 case SEQ: return "cons: SEQUENCE";
81 case SET: return "cons: SET";
82 case PrintableString: return "prim: PRINTABLESTRING";
83 case T61String: return "prim: T61STRING";
84 case IA5String: return "prim: IA5STRING";
85 case UTCTime: return "prim: UTCTIME";
86 default: return "cons: " + curTagNumber;
87 }
88 }
89
90 public byte[] getContent(){
91 return curContent;
92 }
93 public int getInteger(){
94 return 0;
95 }
96 public void setInput(java.io.InputStream is){
97 this.is = is;
98 curOffset = 0;
99 }
00
01 public byte read(InputStream is) throws IOException {
02 int curByte = is.read();
03 if (curByte == -1)
04 throw new IOException("unexpected end of file");
05 ++curOffset;
06 return (byte)curByte;
07 }
08
09 public byte[] read(InputStream is, int nbytes) throws IOException {
10 byte[] bytes = new byte[nbytes];
11 int n = is.read(bytes);
12 if (n < nbytes)
13 throw new IOException("unexpected end of file");
14 curOffset += nbytes;
15 return bytes;
16 }
17
18 private static String formatInt(int num, int size){
19 String numS = Integer.toString(num);
20 return formatString(numS, size, false);
21 }
22
23 private static String formatString(String s, int size, boolean leftJustify){
24 StringBuffer sb = new StringBuffer();
25 if (s.length() >= size)
26 return s;
27 if (leftJustify)
28 sb.append(s);
29 for (int i = size - s.length(); i > 0; i--)
30 sb.append(" ");
31 if (!leftJustify)
32 sb.append(s);
33 return sb.toString();
34 }
35
36 public static void printParsed(InputStream is) throws IOException, ASN1PullParserException {
37 DefASN1PullParser parser = new DefASN1PullParser();
38 parser.setInput(is);
39 parser.printParsed(System.out);
40 }
41
42 public void printParsed(PrintStream ps) throws IOException, ASN1PullParserException {
43 int event;
44 while ((event =next()) != EOF){
45 if (event == END_SEQ || event == END_SET)
46 continue;
47
48 StringBuffer sb = new StringBuffer();
49 sb.append(formatInt(getOffset(), 5));
50 sb.append(":d=");
51 sb.append(formatInt(getDepth(), 1));
52 sb.append(" hl=");
53 sb.append(formatInt(getHLength(), 1));
54 sb.append(" l=");
55 sb.append(formatInt(getLength(), 4));
56 sb.append(" ");
57 sb.append(formatString(getTypeString(), 24, true));
58
59 if (event == OID){
60 sb.append(":");
61 ASN1Oid oid = new ASN1Oid();
62 oid.setValue(getContent());
63 sb.append(formatString(OidMap.getName(oid.toString()), 28, true));
64 } else if (event == PrintableString){
65 sb.append(":");
66 ASN1PrintableString aps = new ASN1PrintableString();
67 aps.setValue(getContent());
68 sb.append(formatString(aps.toString(), 28, true));
69 } else if (event == INTEGER){
70 sb.append(":");
71 ASN1Integer ai = new ASN1Integer();
72 ai.setValue(getContent());
73 sb.append(formatString(ai.toString(), 28, true));
74 } else if (event == BOOLEAN){
75 sb.append(":");
76 ASN1Boolean ab = new ASN1Boolean();
77 ab.setValue(getContent());
78 sb.append(formatString(ab.toString(), 28, true));
79 }
80 ps.println(sb.toString());
81 }
82 }
83
84 public static ASN1PullParser getInstance(byte[] bytes){
85 ASN1PullParser parser = new DefASN1PullParser();
86 parser.setInput(new ByteArrayInputStream(bytes));
87 return parser;
88 }
89
90 public static ASN1PullParser getInstance(InputStream is){
91 ASN1PullParser parser = new DefASN1PullParser();
92 parser.setInput(is);
93 return parser;
94 }
95
96 public static void main(String[] args) throws Exception {
97 if (args.length < 1 || "help".equalsIgnoreCase(args[0]) || "-help".equalsIgnoreCase(args[0])){
98 System.out.println("Usage::asn1parse <infile> [-encode <outfile>]");
99 return;
00 }
01 String file = args[0];
02 InputStream is = PEMData.getDERInputStream(file);
03 printParsed(is);
04
05 JSTKOptions opts = new JSTKOptions();
06 opts.parse(args, 1);
07 String outfile = opts.get("encode");
08 if (outfile != null){
09 System.out.println("Writing the data in DER format to file: " + outfile);
10 FileOutputStream fos = new FileOutputStream(outfile);
11 is = PEMData.getDERInputStream(file);
12 DefASN1PullParser parser = new DefASN1PullParser();
13 parser.setInput(is);
14
15 ASN1Any any = new ASN1Any();
16 any.decode(parser);
17 byte[] encoded = any.encode();
18 fos.write(encoded);
19 fos.close();
20 }
21 }
22
23}