1 /*
2  * @(#) $Id: ASN1Type.java,v 1.3 2003/07/08 08:13:52 pankaj Exp $
3  *
4  * Copyright (c) 2002-03 by Pankaj Kumar (http://www.pankaj-k.net). 
5  * All rights reserved.
6  *
7  * The license governing the use of this file can be found in the 
8  * root directory of the containing software.
9  */
10package org.jstk.asn1;
11
12import java.io.IOException;
13import java.util.logging.Logger;
14
15public abstract class ASN1Type {
16    // tag classes
17    public static final byte UNIVERSAL = 0;
18    public static final byte APPLICATION = 0x40;
19    public static final byte CONTEXT = (byte)0x80;
20    public static final byte PRIVATE = (byte)0xc0;
21
22    // Masks for interpreting the tag
23    public static final byte CLASSBITS = (byte)0xc0;
24    public static final byte TAGBITS = 0x1f;
25
26    // Primitive or constructed flags
27    public static final byte PRIMITIVE = 0;
28    public static final byte CONSTRUCTED = 0x20;
29
30    // Tagging methods
31    public static final int NONE = 0;
32    public static final int IMPLICIT = 1;
33    public static final int EXPLICIT = 2;
34
35    // Universal tags
36    public static final int ANY = 0;
37    public static final int BOOLEAN = 1;
38    public static final int INTEGER = 2;
39    public static final int BIT_STRING = 3;
40    public static final int OCTET_STRING = 4;
41    public static final int NULL = 5;
42    public static final int OID = 6;
43    public static final int SEQUENCE = 16;
44    public static final int SET = 17;
45    public static final int PrintableString = 19;
46    public static final int T61String = 20;
47    public static final int IA5String = 22;
48    public static final int UTCTime = 23;
49
50    public static final Logger logger = Logger.getLogger("org.jstk.asn1");
51    // variables to hold different values
52    protected byte tagClass;
53    protected int taggingMethod;
54    protected int tagNumber;
55    protected byte consMask = PRIMITIVE;
56    protected int type;
57    protected int length;
58
59    // flags and values
60    protected boolean optional = false;
61    protected byte[] defvalue = null;
62
63    protected byte[]    value;
64    public ASN1Type(byte tagClass, int taggingMethod, int tagNumber, int type){
65        this.tagClass = tagClass;
66        this.taggingMethod = taggingMethod;
67        this.tagNumber = tagNumber;
68        this.type = type;
69    }
70
71    public void setTagClass(byte tagClass){
72        this.tagClass = tagClass;
73    }
74    public byte getTagClass(){
75        return tagClass;
76    }
77
78    public void setTaggingMethod(int taggingMethod){
79        this.taggingMethod = taggingMethod;
80    }
81    public int getTaggingMethod(){
82        return taggingMethod;
83    }
84
85    public void setTagNumber(int tagNumber){
86        this.tagNumber = tagNumber;
87    }
88    public int getTagNumber(){
89        return tagNumber;
90    }
91
92    public void setType(int type){
93        this.type = type;
94    }
95    public int getType(){
96        return type;
97    }
98
99    public void setConsMask(byte consMask){
00        this.consMask = consMask;
01    }
02    public int getConsMask(){
03        return consMask;
04    }
05
06    public void setOptional(boolean flag){
07        this.optional = flag;
08    }
09
10    public byte[] getValue(){
11        return value;
12    }
13    public void setValue(byte[] value){
14        this.value = value;
15        this.length = (value != null ? value.length : 0);
16    }
17
18    public void setLength(int length){
19        this.length = length;
20    }
21
22    public void decode(ASN1PullParser parser) throws ASN1PullParserException, IOException {
23        logger.entering(getClass().getName(), "decode");
24        boolean processEvent = true;
25        int event = parser.next();
26        length = parser.getLength();
27        logger.fine("[ASN1Type.decode()] event = " + event + ", off = " + parser.getOffset() +
28            ", len = " + length);
29
30        if ((event != tagNumber) || (parser.getTagClass() != tagClass)){
31            if (optional || (defvalue != null)){
32                parser.prev();      //skip
33                processEvent = false;
34                length = 0;
35                logger.fine("skipping ..." +
36                    (optional ? "optional tag not found" : "assuming default value"));
37            } else {
38                throw new ASN1PullParserException("unexpected type");
39            }
40        }
41        consMask = parser.getConsMask();
42        if (processEvent)
43            value = parser.getContent();
44        logger.exiting(getClass().getName(), "decode");
45    }
46
47    protected byte[] encodeLen(int length){
48        int len = length;
49        int lenOctets = 0;
50        if (len > 127){
51            while (len != 0){
52                ++lenOctets;
53                len = (len >> 8);
54            }
55        }
56        byte[] bytes = new byte[1 + lenOctets];
57        len = length;
58        if (len > 127){
59            bytes[0] = (byte)(0x80 | lenOctets);
60            while (lenOctets > 0){
61                bytes[lenOctets] = (byte)(len & 0x000000ff);
62                len = (len >> 8);
63                --lenOctets;
64            }
65        } else {
66            bytes[0] = (byte)len;
67        }
68        return bytes;
69    }
70
71    // Not very efficeint, but will do.
72    protected byte[] encode1(){
73        if ((optional || defvalue != null) && (length == 0))
74            return null;
75        byte idOctet = (byte)(tagClass | consMask | tagNumber);
76        byte[] lenEncoding = encodeLen(length);
77        int len = 0;
78        if (value != null)
79            len = value.length;
80        byte[] bytes = new byte[1 + lenEncoding.length + len];
81        bytes[0] = idOctet;
82        for (int i = 0; i < lenEncoding.length; i++){
83            bytes[1 + i] = lenEncoding[i];
84        }
85        for (int i = 0; i < len; i++){
86            bytes[1 + lenEncoding.length + i] = value[i];
87        }
88        logger.fine("[ASN1Type.encode1()] idOctet = " + Integer.toHexString(idOctet) +
89            ", #lenOctets = " + lenEncoding.length + ", length = " + length + ", len = " + len);
90        return bytes;
91    }
92    public byte[] encode(){
93        logger.entering(getClass().getName(), "encode");
94        byte[] bytes = encode1();
95        logger.exiting(getClass().getName(), "encode");
96        return bytes;
97    }
98}