tree: 190eb7bb0209ffdcade1c0f2719675c177551d39 [path history] [tgz]
  1. src/
  2. pom.xml
  3. README.md
kerby-asn1/README.md

kerby-asn1

A ASN1 parser with easy and simple API

// encoding
Asn1Integer aValue = new Asn1Integer(8899);
byte[] encoded = aValue.encode();

// decoding
byte[] contentToDecode = ...
Asn1Integer decodedValue = new Asn1Integer();
decodedValue.decode(contentToDecode);
Integer value = decodedValue.getValue();

Data-driven ASN1 encoding/decoding framework and parser

With the following definition from Kerberos protocol

 AuthorizationData ::= SEQUENCE OF SEQUENCE {
     ad-type         [0] Int32,
     ad-data         [1] OCTET STRING
 }

You can model AuthzDataEntry as follows

public class AuthzDataEntry extends Asn1SequenceType {
    static int AD_TYPE = 0;
    static int AD_DATA = 1;

    public AuthzDataEntry() {
        super(new Asn1FieldInfo[] {
                new Asn1FieldInfo(AD_TYPE, Asn1Integer.class),
                new Asn1FieldInfo(AD_DATA, Asn1OctetString.class)
        });
    }

    public int getAuthzType() {
        Integer value = getFieldAsInteger(AD_TYPE);
        return value;
    }

    public byte[] getAuthzData() {
        return getFieldAsOctetBytes(AD_DATA);
    }
}

And then define AuthorizationData simply

public class AuthorizationData extends Asn1SequenceOf<AuthzDataEntry> {

}

Then you can process with above definitions, encode and decode, without caring about the details.

Think about how to implement the following more complex and pratical sample from ITU-T Rec. X.680 ISO/IEC 8824-1:

A.1 ASN.1 description of the record structure
The structure of the hypothetical personnel record is formally described below using ASN.1 specified in
ITU-T Rec. X.680 | ISO/IEC 8824-1 for defining types.

PersonnelRecord ::= [APPLICATION 0] IMPLICIT SET {
    Name Name,
    title [0] VisibleString,
    number EmployeeNumber,
    dateOfHire [1] Date,
    nameOfSpouse [2] Name,
    children [3] IMPLICIT
    SEQUENCE OF ChildInformation DEFAULT {} 
}

ChildInformation ::= SET {
    name Name,
    dateOfBirth [0] Date
}

Name ::= [APPLICATION 1] IMPLICIT SEQUENCE {
    givenName VisibleString,
    initial VisibleString,
    familyName VisibleString
}

EmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER
Date ::= [APPLICATION 3] IMPLICIT VisibleString -- YYYYMMDD

Similarly as above, we can have (from the unit test codes):

public class PersonnelRecord extends TaggingSet {
    private static int NAME = 0;
    private static int TITLE = 1;
    private static int NUMBER = 2;
    private static int DATEOFHIRE= 3;
    private static int NAMEOFSPOUSE = 4;
    private static int CHILDREN = 5;

    static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
            new Asn1FieldInfo(NAME, -1, Name.class),
            new Asn1FieldInfo(TITLE, 0, Asn1VisibleString.class),
            new Asn1FieldInfo(NUMBER, -1, EmployeeNumber.class),
            new Asn1FieldInfo(DATEOFHIRE, 1, Date.class),
            new Asn1FieldInfo(NAMEOFSPOUSE, 2, Name.class),
            new Asn1FieldInfo(CHILDREN, 3, Children.class, true)
    };

    public PersonnelRecord() {
        super(0, fieldInfos, true);
        setEncodingOption(EncodingOption.IMPLICIT);
    }

    public void setName(Name name) {
        setFieldAs(NAME, name);
    }

    public Name getName() {
        return getFieldAs(NAME, Name.class);
    }

    public void setTitle(String title) {
        setFieldAs(TITLE, new Asn1VisibleString(title));
    }

    public String getTitle() {
        return getFieldAsString(TITLE);
    }

    public void setEmployeeNumber(EmployeeNumber employeeNumber) {
        setFieldAs(NUMBER, employeeNumber);
    }

    public EmployeeNumber getEmployeeNumber() {
        return getFieldAs(NUMBER, EmployeeNumber.class);
    }

    public void setDateOfHire(Date dateOfHire) {
        setFieldAs(DATEOFHIRE, dateOfHire);
    }

    public Date getDateOfHire() {
        return getFieldAs(DATEOFHIRE, Date.class);
    }

    public void setNameOfSpouse(Name spouse) {
        setFieldAs(NAMEOFSPOUSE, spouse);
    }

    public Name getNameOfSpouse() {
        return getFieldAs(NAMEOFSPOUSE, Name.class);
    }

    public void setChildren(Children children) {
        setFieldAs(CHILDREN, children);
    }

    public Children getChildren() {
        return getFieldAs(CHILDREN, Children.class);
    }

    public static class Children extends Asn1SequenceOf<ChildInformation> {
        public Children(ChildInformation ... children) {
            super();
            for (ChildInformation child : children) {
                addElement(child);
            }
        }

        public Children() {
            super();
        }
    }

    public static class ChildInformation extends Asn1SetType {
        private static int NAME = 0;
        private static int DATEOFBIRTH = 1;

        static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
                new Asn1FieldInfo(NAME, -1, Name.class),
                new Asn1FieldInfo(DATEOFBIRTH, 0, Date.class)
        };

        public ChildInformation() {
            super(tags);
        }

        public void setName(Name name) {
            setFieldAs(NAME, name);
        }

        public Name getName() {
            return getFieldAs(NAME, Name.class);
        }

        public void setDateOfBirth(Date date) {
            setFieldAs(DATEOFBIRTH, date);
        }

        public Date getDateOfBirth() {
            return getFieldAs(DATEOFBIRTH, Date.class);
        }
    }

    public static class Name extends TaggingSequence {
        private static int GIVENNAME = 0;
        private static int INITIAL = 1;
        private static int FAMILYNAME = 2;

        static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
                new Asn1FieldInfo(GIVENNAME, -1, Asn1VisibleString.class),
                new Asn1FieldInfo(INITIAL, -1, Asn1VisibleString.class),
                new Asn1FieldInfo(FAMILYNAME, -1, Asn1VisibleString.class)
        };

        public Name() {
            super(1, tags, true);
            setEncodingOption(EncodingOption.IMPLICIT);
        }

        public Name(String givenName, String initial, String familyName) {
            this();
            setGivenName(givenName);
            setInitial(initial);
            setFamilyName(familyName);
        }

        public void setGivenName(String givenName) {
            setFieldAs(GIVENNAME, new Asn1VisibleString(givenName));
        }

        public String getGivenName() {
            return getFieldAsString(GIVENNAME);
        }

        public void setInitial(String initial) {
            setFieldAs(INITIAL, new Asn1VisibleString(initial));
        }

        public String getInitial() {
            return getFieldAsString(INITIAL);
        }

        public void setFamilyName(String familyName) {
            setFieldAs(FAMILYNAME, new Asn1VisibleString(familyName));
        }

        public String getFamilyName() {
            return getFieldAsString(FAMILYNAME);
        }
    }

    public static class EmployeeNumber extends Asn1Tagging<Asn1Integer> {
        public EmployeeNumber(Integer value) {
            super(2, new Asn1Integer(value), true);
            setEncodingOption(EncodingOption.IMPLICIT);
        }
        public EmployeeNumber() {
            this(null);
        }
    }

    public static class Date extends Asn1Tagging<Asn1VisibleString> {
        public Date(String value) {
            super(3, new Asn1VisibleString(value), true);
            setEncodingOption(EncodingOption.IMPLICIT);
        }
        public Date() {
            this(null);
        }
    }
}

Notes

  • 90% tests coverage for DER encoding
  • For BER & CER encoding, to be fully supported
  • No extra dependency

License

Apache V2 License