BitMeister ASN.1 library

BitMeister ASN.1 library (BM ASN.1) is a class library for translating data types defined by Abstract Syntax Notation One (ASN.1) into Java classes for processing in Java programs.

See:
          Description

Packages
jp.bitmeister.asn1.annotation Contains the annotations used for defining ASN.1 types.
jp.bitmeister.asn1.codec Contains the interfaces used for ASN.1 codecs.
jp.bitmeister.asn1.codec.ber Contains the codec classes used for BER(Basic Encoding Rules) encoding and decoding.
jp.bitmeister.asn1.exception Contains the exceptions related to this library.
jp.bitmeister.asn1.processor Contains the classes and interfaces used for processors which apply some process to ASN.1 data.
jp.bitmeister.asn1.type Contains the common classes and interfaces used for defining ASN.1 types and processing ASN.1 data.
jp.bitmeister.asn1.type.builtin Contains the classes which represents built-in ASN.1 types.
jp.bitmeister.asn1.type.useful Contains the classes which represents useful ASN.1 types.
jp.bitmeister.asn1.value Contains the classes which represents ASN.1 values.

 

BitMeister ASN.1 library (BM ASN.1) is a class library for translating data types defined by Abstract Syntax Notation One (ASN.1) into Java classes for processing in Java programs.

Overview

BM ASN.1 contains classes that represent ASN.1 data types; annotation interfaces used for adding static information related to ASN.1 type definitions; and runtime processor classes. BM ASN.1 provides a more efficient way to write Java codes for systems using presentation protocols defined with ASN.1 notations.

Current version of BM ASN.1 provides,

Short Instruction

The following text displays how to translate ASN.1 notations into the BM ASN.1 library class definitions and how to use these classes. This short instruction uses following example ASN.1 definition 'FrightStatusTypes'.

FrightStatusTypes DEFINITIONS AUTOMATIC TAGS ::= BEGIN
        
        FrightNumber ::= PrintableString
        
        Airport ::= ENUMERATED {
                tokyo(0),
                osaka(1),
                nagoya(2),
                fukuoka(3)
        }
        
        Information ::= SEQUENCE {
                airport         Airport,
                scheduled       UTCTime,
                actual          UTCTime OPTIONAL
        }
        
        Status ::= CHOICE {
                onTime  NULL,
                delay   INTEGER
        }
        
        FrightStatus ::= [APPLICATION 0] IMPLICIT SEQUENCE {
                frightNo        FrightNumber,
                departure       [0] IMPLICIT Information,
                arrival         [1] IMPLICIT Information,
                status          [2] Status
        }
        
        AllFrights ::= SEQUENCE OF FrightStatus
        
END

Defining ASN.1 type classes

All ASN.1 types in BM ASN.1 are defined as a sub-class of ASN1Type class. User defined ASN.1 types shall not extend ASN1Type directly but use one of the built-in classes contained in the jp.bitmeister.asn1.type.builtin package and the jp.bitmeister.asn1.type.useful package as the base class. Static information related to ASN.1 definition can be added by using annotations contained in the jp.bitmeister.asn1.annotation package.

public class FrightNumber extends PrintableString {}

Enumerations defined in an 'ENUMERATED' type are defined as public static final fields of a sub-class of ENUMERATED class and annotated as ASN1Enumeration.

public class Airport extends ENUMERATED {
        
        @ASN1Enumeration
        public static final int tokyo = 0;
        
        @ASN1Enumeration
        public static final int osaka = 1;
        
        @ASN1Enumeration
        public static final int nagoya = 2;
        
        @ASN1Enumeration
        public static final int fukuoka = 3;
        
}

Elements of a 'SEQUENCE' type are translated into fields of a sub-class of SEQUENCE. For defining a field as an element, ASN1Element annotation is used. Each element fields must be a public mutable instance field.

public class FrightInformation extends SEQUENCE {
        
        @ASN1Element(0)
        public Airport airport;
        
        @ASN1Element(1)
        public GeneralizedTime scheduled;
        
        @ASN1Element(value = 2, optional = true)
        public GeneralizedTime actual;
        
}

ASN1Tag annotation is used for providing ASN.1 tag information. Tag information can be added to classes and fields.

@ASN1Tag(value = 0, tagClass = ASN1TagClass.APPLICATION, tagMode = ASN1TagMode.IMPLICIT)
public class FrightStatus extends SEQUENCE {

        @ASN1Element(0)
        public FrightNumber frightNo;
        
        @ASN1Element(1)
        @ASN1Tag(value = 0, tagMode = ASN1TagMode.IMPLICIT)
        public Information departure;
        
        @ASN1Element(2)
        @ASN1Tag(value = 1, tagMode = ASN1TagMode.IMPLICIT)
        public Information arrival;
        
        @ASN1Element(3)
        @ASN1Tag(2)
        public Status status;
        
}

Classes that represents collection types (i.e. SEQUENCE_OF, SET_OF) have a genelic type variable. The type of component of the collection shall be set to the type variable and the class object of the type must be passed to constructor of parent class.

public static class AllFrights extends SEQUENCE_OF<FrightStatus> {

        public AllFrights() {
                super(FrightStatus.class);
        }
        
}

Some constructors may be declared in these types for easy initialization. When defining constructors with arguments, constructor with no argument must also be defined.

public class FrightNumber extends PrintableString {

        public FrightNumber() {}

        public FrightNumber(String value) {
                super(value);
        }
        
}

public class FrightStatus extends SEQUENCE {

        ...
        
        public FrightStatus() {}
        
        public FrightStatus(FrightNumber frightNo, Information departure,
                        Information arrival, Status status) {
                this.frightNo = frightNo;
                this.departure = departure;
                this.arrival = arrival;
                this.status = status;
        }
        
}

Defining ASN.1 Modules

An ASN.1 module is defined as a sub-class of ASN1Module class. If an ASN.1 type defined as a member class of an ASN.1 module class, the type is included in the module automatically. Default tagging mode of a module can be specified by using ASN1ModuleTags annotation.

@ASN1ModuleTags(ASN1TagDefault.AUTOMATIC_TAGS)
public class FrightStatusTypes extends ASN1Module {

        public static class FrightNumber extends PrintableString {

                public FrightNumber() {}

                public FrightNumber(String value) {
                        super(value);
                }
        }
        
        public static class Airport extends ENUMERATED {
                
                @ASN1Enumeration
                public static final int tokyo = 0;
                
        ...

An ASN.1 type not defined as a member class of a module class must specify the module to be included by using ASN1ModuleRef annotation.

@ASN1ModuleRef(FrightStatusTypes.class)
@ASN1Tag(value = 0, tagClass = ASN1TagClass.APPLICATION, tagMode = ASN1TagMode.IMPLICIT)
public class FrightStatus extends SEQUENCE {

        @ASN1Element(0)
        public FrightNumber frightNo;
        
        ...

And the module must register the ASN.1 type by the register method.

@ASN1ModuleTags(ASN1DefaultTags.IMPLICIT_TAGS)
public class FrightStatusTypes extends ASN1Module {
        
        public FrightStatusTypes() {
                register(FrightStatus.class);
        }
        
        ...

Assigning value to ASN.1 data

The set method or constructors can be used for assigning value to simple ASN.1 type classes (e.g. BOOLEAN, INTEGER etc.). The value of an ASN.1 data can be got by using value method. Some other methods dedicated to each simple types are also implimented.

        BOOLEAN bool = new BOOLEAN(true);
        if (bool.value()) {
                bool.set(false);
        }
        
        INTEGER number = new INTEGER(100);
        if (number.isIntValue()) {
                int value = number.intValue();
        }

User defined simple ASN.1 type classes also use the set method for assigning value.

        FrightNumber frightNo = new FrightNumber();
        frightNo.set("JP041");

If a constructor with argument is declared in a user defined ASN.1 type class, initializing code can be shorter.

        FrightNumber frightNo = new FrightNumber("JP041");      

For setting value to an element of a structured type, just assign an ASN.1 type data to the element field of the class.

        FrightStatus status = new FrightStatus();
        status.frightNo = new FrightNumber("JP041");
        status.departure = new Information();
        status.departure.airport = new Airport(Airport.tokyo);
        ...     

Value of a selective type (i.e. CHOICE) data also can set by assigning value to a field of the class. The field that have been assigned value become the selected alternative. If 2 or more alternatives have been assigned value, processing (e.g. encoding, decoding etc.) for the data might fail. clear method can be used for clearing current selection.

        Status status = new Status();
        status.onTime = new NULL();
        status.clear();
        status.delay = new INTEGER(10);

If a constructor with arguments is declared for easy initializetion in these classes, FrightStatus can be initialized by the following code.

        FrightStatus status = new FrightStatus(
                        new FrightNumber("JP041"),
                        new Information(
                                        new Airport(Airport.tokyo),
                                        new UTCTime("110627073000"),
                                        new UTCTime("110627073500")
                                        ),
                        new Information(
                                        new Airport(Airport.fukuoka),
                                        new UTCTime("110627090000"),
                                        null
                                        ),
                        new Status(ASN1TagClass.CONTEXT_SPECIFIC, 1, new INTEGER(5))
                        );

Encoding and decoding ASN.1 data

Current BM ASN.1 provides DER (Distinguised Encoding Rules) encoding and BER (Basic Encoding Rules) decoding. The encode method on DerEncoder takes an ASN.1 type data as the argument. It encodes the data and writes the result to an OutputStream.

        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        DerEncoder enc = new DerEncoder(bo);
        enc.encode(status);

A BerDecoder reads bytes from an InputStream and decode them to an ASN.1 type data. The decode method that takes a Class object of an ASN.1 type class as the argument sets the result to an instance of the type and returns it. If the ASN.1 tag decoded from the bytes does not match the type, the method throws an ASN1DecodingException.

        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        BerDecoder dec = new BerDecoder(bi);
        FrightStatus result = dec.decode(FrightStatus.class);

When the decode method with no arguments is called, a BerDecoder specifies the ASN.1 type by the decoded ASN.1 tag. A BerDecoder searches the type within ASN.1 modules that registered to the ASN1Modules class by using method.

        ASN1Modules.using(new FrightStatusTypes());

        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        BerDecoder dec = new BerDecoder(bi);
        ASN1Type result = dec.decode();

toString method

All ASN.1 type classes in BM ASN.1 implement toString method. Following code

System.out.println(result);
displays following result on the console.
FrightStatus ::= [APPLICATION 0] IMPLICIT SEQUENCE {
        frightNo        FrightNumber ::= PrintableString        "JP041",
        departure       [0] IMPLICIT    Information ::= SEQUENCE {
                airport [0] IMPLICIT    Airport ::= ENUMERATED  tokyo(0),
                scheduled       [1] IMPLICIT    UTCTime "110626223000Z" [2011/06/27 07:30:00.0 JST],
                actual  [2] IMPLICIT    UTCTime "110626223500Z" [2011/06/27 07:35:00.0 JST] OPTIONAL },
        arrival [1] IMPLICIT    Information ::= SEQUENCE {
                airport [0] IMPLICIT    Airport ::= ENUMERATED  fukuoka(3),
                scheduled       [1] IMPLICIT    UTCTime "110627000000Z" [2011/06/27 09:00:00.0 JST],
                actual  [2] IMPLICIT    <No value> OPTIONAL },
        status  [2] Status ::= CHOICE {
                delay   [1] IMPLICIT    INTEGER (5) } }