26 Mart 2008 Çarşamba

Java Asn1 Compiler (open source)

(download link : http://sourceforge.net/projects/jac-asn1/)

JAC, is an open source asn1 compiler that I have completed in 2 months during my internship at Turkcell Technology. It was the last 2 months of my internship (July-August, 2007).

JAC (Java Asn.1 Compiler)
is a tool to parse the asn.1 file, create .java classes of defined asn.1 data types and do encoding/decoding of instances of the generated java classes.
It is used in the end-to-end communications due to the asn.1 principles.

Before starting to develop the project I have searched and examined lots of open source compilers but a good free java asn.1 compiler that supports BER encoding was not available on the net. There were lots of open source compilers but they were not sufficient for our needs.

In the end of the internship, we gave my project the name "JAC (Java Asn1 Compiler)".
And I have hosted it on sourceforge.net as an open source project after getting the permission from Trukcell Technology.
The link of my project for download is here :


More About JAC - Java Asn.1 Compiler

JAC (Java Asn.1 Compiler)
is a tool for you if you want to
(1) parse your asn.1 file
(2) create .java classes of data types defined in your asn.1 file and
(3) do encoding/decoding of instances of your generated classes.
BER, CER and DER are all supported. Just download and start using immediately.
Just forget all asn1 byte streams, and take the advantage of OOP!

All generated java classes by JAC, have the followings inside:

Public member data variable(s) to hold data of the generated type.
Constructor(s) to initialize the object.
Set(..) Method to set the variables of the object.
• An encode(..) method to create asn.1 byte stream which is the output to send.
• A decode(..) method to create the java object from the received encoded input stream.
• A print(..) method to print the contents of the object.

So, JAC gives the opportunity to user working with Java objects instead of playing with complex asn.1 byte streams.
During encoding JAC writes a Java object to an output byte stream which is the encoded output before sending, and when decoding creates a Java object from the received byte stream which is the received encoded input, due to the principles of asn1 standards.

There are clear examples under the download package of my project about the term "asn.1" and asn.1 files.
In the Power Point document "JAC (Java ASN1 Compiler).ppt" there are good examples of how to create .java classes from asn.1 files and do encoding/decoding by use of JAC.
In this power point slide show you can find all features and capabilities of JAC.

And also note that, each new version information is specified in the file "Version.txt" file under the download package.

JAC class extension hierharchy is shown briefly on the figure below :

modified W.Woody's asn.1 library package

JAC's package

Created .java classes by JAC

Please feel free to contact me about the project (JAC - Java Asn1 Compiler).
Any questions, suggestions or comments will be welcomed.

30 yorum:

Adsız dedi ki...

It is a great tool. I am trying to use it.
Does it support DER and CER encoding in addition to the BER? I went through the classes and saw the BerXXXX classes. I did not see any DerXXX or CerXXX class.

Junling (junlingw[at]cisco.com)

Fatih Batuk dedi ki...


DER and CER are basically just variants of BER. No need to define CERXXX classes.
This project supports BER, DER and CER.

The examples in TestProject.java class are all BER processing. To encoding in CER or DER just create your output parameter with correct parameter such as :

BerOutputStream out_der =
new BerOutputStream(stream,BerOutputStream.ENCODING_DER);

Note that there is no similiar constructor for BerInputStream. That's because CER and DER encoded byte streams are legal BER streams. CER and DER essantially are subsets of BER.

For more information you can look JAC.ppt document and TestProject.java class for encoding/decoding examples..

Best Regards

Adsız dedi ki...

Hi Fatih,

I successfully generate classes for my ASN structure, but problem is i got ASN binary file which contains multiple records.

Please guide me how i can read binary stream and then how i can set value for each Tag?

I successfully convert binary file into Hex.

Please guide me how i can parse binary or hexa files which contain multiple records.

Thanks & Regards,

Fatih Batuk dedi ki...


First of all you should start the JAC and create your java classes of your asn1 types in your asn1 file: MySequence.java MyIntegere.java.. etc..

You say you have an output stream that contains encoded asn1 types.
To decode these byte streams (i.e. to fill asn1 variables in java)
you need to know the order of asn1 types defined in your binary file.

And then just surround your binary file with BerInputStream such as :

FileInputStream fs = new FileInputStream(yourBinaryFile); //See FileInputStream class usage (jdk 1.6)

BerInputStream in = new BerInputStream(fs);

//then what is the first encoded ans1 type in your binary file? For example if it is "MySequence"

MySequence seq = new MySequence();

//now your sequence object is created and filled succesfully according to the binary data in your file
//then what is the second encoded asn1 type in your binary file? For example if it is the asn1 definition "MyInteger"

MyInteger myInt = new MyInteger();
//now your asn1 integer object is filled succesfully according to the binary data in your file

I hope this will help. See also the java code in JAC.ppt file under download package.

With warmest regards

Imran dedi ki...

Hi Fatih,

I successfully generated class files but when i set my sequence it give me following error

FileInputStream fs = new FileInputStream( new File("c:\\ASN.ber") );
BerInputStream in = new BerInputStream(fs);

Following is error:

>> During decoding, the encoded tag value in the byte array does not match with this object's tag number !
at com.turkcelltech.jac.Sequence.decode(Sequence.java:97)
at com.turkcelltech.jac.cdr.CDREnc.main(CDREnc.java:72)

Following is my CDR format


roaming-cdr [0] ROAMING-CDR

timestamp Timestamp,
type RoamingCdrType,
msisdn [0] ISDN-AddressString OPTIONAL,
imsi [1] IMSI,
vlr ISDN-AddressString

;....... other asn1 records


And hex encoded CDR in file is like this :

[tag for the pdu = a0] [length=27] [timestamp octet string tag = 04] [length = 08] 00 00 00 fe 6d 0c d1 74 [enumerated tag = 0a] [length = 01] 02 [msisdn context specific tag = 80] [length = 06] 64 0784 7076 f0 [imsi context specific tag = 81] [length = 08] 42 00 07 21 00 28 30 f6 [vlr octet string tag = 04] [length = 06] 64 07 17 00 99 f1

and my file contains many records.

Fatih Batuk dedi ki...

Hi Imran,

I think I understood your problem. In your asn1 file there is a choice object that contains a roaming_CDR sequence object and it is tagged as "[0]" in the choice record. It is not an exact ROAMING_CDR object. It is an inner object of the choice type CDR
So your error during decoding is normal.

Please try the following :

CDR mycdr = new CDR();


Imran dedi ki...

Hi Fatih,

Thanks for your response. It solved my decoding problem.

My asn1 encoded file sometimes contain 50 records and sometimes 60 records so to decode that file I require multiple instances of sequence object.

My question is that do there any way to get number of records in one file, so I could create array of objects accordingly and by running while loop decode all records.


Fatih Batuk dedi ki...

Hi Imran,

why don't you try the following form :

FileInputStream fs = new FileInputStream( new File("c:\\ASN.ber") );
BerInputStream in = new BerInputStream(fs);

int number_of_records = 0;

CDR mycdr;

while ( in.available() > 0 ) {
mycdr = new CDR();

// do your operations with your decoded object "mycdr" ...

Did this solve your problem ? Please acknowledge me


imran dedi ki...

Many many many thanks for your help its working as I want, it was really great experience to interact with you. I learned lot from you.

I have added you in my yahoo IM with id please accept that also.


Dave Klassen dedi ki...

What is your philosophical view point about why the state variable existed in the choasinmotion distribution? and... Do you think that the according to the ASN.1 spec 'state' should not be a part of a parser library (That is as much as I could conclude after reading the code and creating my own manual parser classes.).

I am thinking that any code depending on the parser jar, should decide how to handle state, not the parser library itself (Using callbacks etc.). What I am asking for is your opinion on how you would handle state if such a thing were necessary in a dependent application. Or your philosophy about why you made the change, and moving forward for dependent projects, how do you suggest applications that require state incorporate such a thing?

Naveen dedi ki...

A BLOG BY FATIH BATUK: Java Asn1 Compiler (open source)

I have downloaded the 2.0 JAC and trying to use it to decode a smiple asn1 packet and i am getting an error called " >> During decoding, the encoded tag value in the byte array does not match with this object's tag number !" . I tried to fix it the way you have explained to Imran but still i get the same error. For reference i am posting the entire asn.1 file i used to create the .java files and the java file which i used to decode.

first i used the javacc to create the necessary java files:
java javacc.AsnParser -d /home/login95/asnParser -p small small.asn // this created a directory and inside it created relevant java files

My asn file format is as below (small.asn)


DataPacket ::= SEQUENCE {
operation [0] OCTET STRING,
parameters [1] Packet

Packet ::= SEQUENCE {
retrieve [0] RetrievePacket

RetrievePacket ::= SEQUENCE {


//sample datapacket
30 0D // DataPacket
80 01 FF // Operation
A0 08 //Retrieve
80 06 380101020101 //DataOID

Next i switched to this directory and wrote a small java file (TestFile.java)
package small;

import java.io.*;
import java.util.BitSet;
import java.util.Date;
import examples.*;

import com.turkcelltech.jac.*;
import com.chaosinmotion.asn1.*;

public class TestFile
public static void main(String[] args)

FileInputStream fs = new FileInputStream(new File("/root/asnParser/vault/small/mypacket.ber"));
BerInputStream in = new BerInputStream(fs);
MySequence seq = new MySequence();

}catch(Exception ex){
System.err.println("encode: Exception: " + ex.getMessage());

Waiting for you help .....

Fatih Batuk dedi ki...


Sorry for my late response.
Actually, first of all you should think why you need to decode your data with a manual parser implementation. If you have already tried to use auto decoding (i.e. using AutoParser.java) that I wrote in my project and if it does not support for you, then you can try writing your own ManualParser for your specific encoded data. Remember that, "sequence of" and "set of" objects even with tagged types can also be decoded by our AutoParser.

And your point.. the "state" variable in BerParser.java class... I deleted that variable because it is not necessary in my implementation. Just have a look at the ManualParser.java class to understand the manual decoding algorithm.

And if you wanna understand the goal of state variable in the W.Woody's asn1 library you should look to the TestParser.java class in my project. In that class, Woody just gives an example parser implementation just for usage of his pure asn.1 library.

Shortly, I tried to simplify the manual decoding mechanism in my project. And I removed the state variable.
If you look more closer to the code, you will reliaze that Woody handles the decoding issue in a digfferent way. Because of that, the state variable was mandatory for his algorithm.
If you still want to learn more about to the "state variable" why Woody used it, you may try to ask it to W.Woody (http://chaosinmotion.com/blog/?p=124)

I hope this was helpful
Best Regards

William Woody dedi ki...

Dave Klassen:

Hi; I'm Bill Woody, the author of the ASN.1 Ber libraries that Fatih Batuk is using in his JAC library.

The intent of the 'state' variable in the BerParser.java class was to track the current state--roughly corresponding to the current statement--being parsed, thus allowing you to build an ASN.1 BER parser using just one class deriving from the BerParser.java class.

To give an example, suppose we have the following ASN.1 protocol:

A :== CHOICE {
b B,
c C
f D,

(Yeah, this is pretty contrived.)

We can write one parser class derived from BerParser as:

public class TestParser2 extends BerParser
private static final int A = BerParser.START;
private static final int B = 1;
private static final int C = 2;
private static final int D = 3;

public BerNode create(int tag, int state, BerInputStream stream) throws IOException
switch (state) {
case A:
if (tag == (Tag.APPLICATION | 0)) {
// reached statement B
return new BerSequence(tag, B, this, stream);
} else if (tag == (Tag.APPLICATION | 1)) {
// reached statement C
return new BerSequence(tag, C, this, stream);
} else {
throw new AsnEncodingException("Unknown tag: " + tag);

case C:
if (tag == (Tag.APPLICATION | 2)) {
// reached statement D
return new BerSequence(tag, D, this, stream);
} else {
throw new AsnEncodingException("Unknown tag: " + tag);

case B:
case D:
// Because both statements only have primitives if we are called
// there is an unknown tag in the stream
throw new AsnEncodingException("Unknown tag: " + tag);
throw new AsnEncodingException("Unknown state: " + state); // will never happen

Here's what is happening: the 'create' method in my TestParser2 class is only called when an unknown tag is seen in the data stream. (One interesting side effect of this is that the parser will accept any stream of primitive tokens in any of the sequences above--that is, the parser will be overly permissive. So if we send (for statement B) three integers instead of two, the parser will simply accept those three integers.

Only when we see the [APPLICATION n] tags will the 'create' method get called. The first time the 'create' statement is called the 'state' variable is set to the constant START; this indicates we are at whatever 'start' state (typically, the first ASN.1 statement in the description). In our contrived example above, it indicates that we're parsing tags that correspond to statement A.

Depending on the tag we receive in statement A, we could be parsing an input stream corresponding to a sequence B or a sequence C; we examine the tag and create a BerSequence B or a BerSequence C. If inside a C we see a sequence D, we can create a BerSequence D.

There were a couple of ways that the problem of tracking the current 'state' (that is, where you are in the ASN.1 description) while parsing a token stream. One way is to build a recursive descent parser. This would then involve building an explicit class BerParserA, BerParserB, BerParserC, and BerParserD which can then examine and decide based on the current set of tokens what to do--and has the advantage of not being overly permissive. In this case, the parsing 'state' is implied by the current class being used to parse the stream.

I took the tactic of passing a state variable around--this has the advantage of allowing the entire parsing engine for a particular protocol to be rolled into a single class, and to reduce the amount of code that needs to be written--since if I'm receiving a protocol that uses a lot of UNIVERSAL types, parsing UNIVERSAL types can be handled automatically.

(Thus, if you have a protocol:

b B,
c C
b :== SEQUENCE {
c :== SEQUENCE {

-- Yeah, another stupid, contrived example

Then you wont have to write any code at all; 'create' can be left blank.)

Unfortunately I haven't had the time to look at Fatih Batuk's ASN.1 parser in detail--my job took me away from playing with ASN.1 around the time Mr. Batuk started writing his code. But having an ASN.1 parser automatically build the network of classes necessary to properly parse a token stream is preferable to my BerParser solution. I created the BerParser solution--modeling it on the Netscape BER parser for their LDAP code--so I could write an LDAP parser quickly and compactly.

Hope this helps.

Dave Klassen dedi ki...

Hey thanks for the info. Exactly what I was looking for. I am very glad to receive the whole package compiler and parser. I actually had some custom ASN.1 spec I was implementing for. It had pretty much everything except the application specific tags. I had to write many manual Parser classes because the spec. was quite variable, and included a choice between 6 different complex/universal types.

I'm pretty new to ASN.1, so I also incorporated the asn1c project for proofing a general ASN.1 spec and automatically generating a detailed description. From this I ran jac to compile the classes. In my own opinion I think it worked excellent. Its made me a believer in ASN.1. Forget XML I'm going backt to the basics. Write better code and reduce your telcom data footprint/charges.

Fatih Batuk dedi ki...

Hi Naveen,

Sorry for my late response. I totally forgot your post.
In your example here, you use the MySequence.java class.
Instead of that you should use your generated class "DataPacket.java"
So the true format will be in the following form.
DataPacket dp = new DataPacket();

Wissam dedi ki...

Dear Mr.Batuk,

Would you please help me with the below problem:

the ASN.1 format is as the below:
SDPCallDataRecord ::= CHOICE {
cDRProcessed [1] CDRProcessed,
accountAdjustment [2] AccountAdjustment,
negativeBalance [3] NegativeBalance,
bonusAdjustment [4] BonusAdjustment,
serviceFeeDeduction [5] ServiceFeeDeduction,
lifeCycleChange [6] LifeCycleChange,
negativeBalanceBarred [7] NegativeBalanceBarred,
valueVoucherExpiry [8] ValueVoucherExpiry,
periodicAdjustment [9] PeriodicAdjustment,
periodicReset [10] PeriodicReset,
temporaryBlock [11] TemporaryBlock

CDRProcessed ::= SEQUENCE {
recordType [1] RecordType,
sdpID [2] NodeID,
AccountAdjustment ::= SEQUENCE {
adjustmentRecordType [1] AdjustmentRecordType,
sdpID [2] NodeID,

I have tried to use the TestParser2 sent by Mr.William with my own specifications but it doesn't work.
would you please suggest the best strategy to write a parser for the above schema using your JAC library.

Thank you very much.

Antonio Bello dedi ki...

Hello, I'm working on a project that requires the parsing of a file asn.
When I read Eclipse AsnParser by the message: ASN.1 file successfully parsed.
and then the program exits.
I can not understand why, maybe not seemed fairly my asn.
I am convinced of this because if the file asn put words in case the message is still the same.
You could help me? Of course it is unnecessary to specify that with your file asn everything works perfectly.
Thank you,

Fatih Batuk dedi ki...

Hi Wissam,
You do not need to write a manual parser class for your asn1 file above. Just download JAC and import in into your eclipse workspace and put your asn1 file under the project folder and then run the "AsnParser.java" class with correct program arguments.
The arguments are respectively:

-d (target_directory) -p (package_name) (asn.1_file_name)

a correct example is:

-d C:\JavaAsn1Compiler -p test myAsn1.txt

And all of these details are written in the "Readme.html" file.
And you should implicitly examine the TestParser.java class too see the examples of use of the JAC.

Fatih Batuk dedi ki...

Hi Antonoi Bello,
It is really hard to understand your problem. You should tell your problem in detail. This is not sufficient.

I do not know your ans1 file but you should be careful for the followings to use the JAC:
1) JAC does not support the inner type definitions. For example:

CDRProcessed ::= SEQUENCE {
cdrProcDedicatedAccounts [31] SEQUENCE (SIZE (1..255)) OF CDRProcDedicatedAccount OPTIONAL,

If you have an inner type definition like above, firstly you should "tune" your asn1 file. Just remove the inner type definitions in your file.
For example just convert the above line as follows:

CDRProcessed ::= SEQUENCE {
cdrProcDedicatedAccounts [31] SequenceOfCDRProcDedicatedAccount OPTIONAL,

SequenceOfCDRProcDedicatedAccount ::= SEQUENCE OF CDRProcDedicatedAccount

So that's it. Just modify all the inner type definitions if you have any.

2) Do not forget that:

The supported asn.1 data types for JAC are the most common asn.1 types:

If you have a different asn.1 definition in your file you cannot use JAC.

3) "AUTOMATIC TAGGING", which is not prefered to use in many cases, is not supported.

4) JAC does not understand the "imports". All of the definitions should be in 1 file.

5) You should clerly read the "JAC.ppt" and "Readme.html" files and examine the "TestProject.java" under the "test" package to understand the use of JAC clearly.

Ashish dedi ki...

Hi Fatih,

I am new to ASN and I have been asked to research on it. I am exploring your JAC (Java Asn.1 Compiler). It is a great tool but I am stuck with a problem and not able to proceed further. Following is my CDR format -


CallDetailOutputRecord ::= CHOICE {
sCFPDPRecord [0] SCFPDPRecord,
diameterCreditControlRecord [3] DiameterCreditControlRecord,
fBCRatingRecord [4] FBCRatingRecord,
rTCCreditControlRecord [5] RTCCreditControlRecord

I able to decode like this

CallDetailOutputRecord cdr = new CallDetailOutputRecord();

but in case I donot know if the record is of type SCFPDPRecord,SCFSMSMORecord,SCFSMSMORecord,DiameterCreditControlRecord,FBCRatingRecord or RTCCreditControlRecord because the CallDetailOutputRecord is of type CHOICE, how can I decode the records


Fatih Batuk dedi ki...

Hi Ashish,

Nowadays in my spare times I was working on the problem that you specified. In 2.0 version of JAC auto decoding in Choice objects is not supported.
But it is almost finished. I will e-mail you the new version when finished. Please contact me via e-mail about this issue (see my blogger profile page for my e-mail)

ashish dedi ki...

Hi Fatih,

I would appreciate if you could tell how to print the value of variable of type OctetString. If I use the getValue function it returns me a junk value.


Bhavana dedi ki...

Hi, I have worked on your Java version and seems great. Could you pls tell me if I can generate C code also using this compiler.


Fatih Batuk dedi ki...

You cannot generate C code with JAC. But there are diffrent open source asn1 C compilers on the net.

William Woody dedi ki...

An OctetString is actually an array of 8-bit bytes, and not necessarily a printable string. (I've seen protocols use an OctetString as an image, for example.)

If you know your OctetString contains a printable string, you can get the value (BerOctetString.getValue()), and convert it to a String using one of the byte array to string conversion constructors.

Eduardo dedi ki...

Hi Fatih,
First thanks for your great asn1 compiler. Jac is helping me a lot with my project.
Im pretty new to ASN1 (around 1 week) and my first problem is about one ASN1 type: Operation.
Is there support available to "operation" on JAC?
how can i use that?

This is my asn1 code:

monitorStart OPERATION ::=
{ ARGUMENT MonitorStartArgument
RESULT MonitorStartResult
ERRORS {universalFailure}
CODE local: 71

I've already created the MonitorStartArgument object and the MonitorStartResult object, but how could i describe an operation on JAC?

is there some recommended tutorial or forum?

Thanks in advance.

Adsız dedi ki...

I found this site using [url=http://google.com]google.com[/url] And i want to thank you for your work. You have done really very good site. Great work, great site! Thank you!

Sorry for offtopic

dany dedi ki...

Hi Fatih,
First thanks for your great asn1 compiler.

I have a little question for you.

JAC support the asn1 "NUMERICSTRING"?


Fatih Batuk dedi ki...

JAC does not support NUMERICSTRING. In the 'known limitations' part you can find this information. And also it is writing above.

Manish dedi ki...

Hi Fatih,

Thanks for this great parser. I am trying to use JAC for parsing some HUAWEI CDR files. I have recreated the essential parts where I am facing problems in the following ASN1 file.


MyChc ::= CHOICE {

Report ::= SEQUENCE {
message-Identifier INTEGER (0 .. 65535),
choice-list SEQUENCE OF MyChc


This is the function to test it:

public static void main(String[] args) throws IOException {

//outputstream for encoding
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
BerOutputStream out = new BerOutputStream(outStream);

//input stream for decoding
ByteArrayInputStream inputStream;
BerInputStream in;

MyChc chc1 = new MyChc();
chc1.myString22.setValue(new byte[]{9,2,6,11,21});
MyChc chc2 = new MyChc();
chc2.myString11.setValue(new byte[]{6,11,21});

Report report = new Report();

outStream = new ByteArrayOutputStream();
out = new BerOutputStream(outStream);
System.out.print("\n -- SEQUENCE OF INTEGER ");

//decode it:
inputStream = new ByteArrayInputStream(outStream.toByteArray());
in = new BerInputStream(inputStream);
Report generatedReport = new Report();

//check some parameter to see that whether it is decoded succesfully or not:


When I run this code with the generated classes, I am able to encode the data to get the following bytestream in hex:

30 15 02 01 03 30 10 66 07 04 05 09 02 06 0B 15 65 05 04 03 06 0B 15

however while decoding the same string I am getting an error:

Exception in thread "main" java.lang.NullPointerException
at com.chaosinmotion.asn1.BerConstruct.(BerConstruct.java:196)
at com.chaosinmotion.asn1.BerSequence.(BerSequence.java:114)
at com.turkcelltech.jac.AutoParser.readSeq(AutoParser.java:229)
at com.chaosinmotion.asn1.BerConstruct.(BerConstruct.java:120)
at com.chaosinmotion.asn1.BerSequence.(BerSequence.java:102)
at com.turkcelltech.jac.Sequence.decode(Sequence.java:104)
at sequenceOfChoice.testSeqOfChoice.main(testSeqOfChoice.java:42)

During debugging I found that the sequenceOf variable does not have it's content set. It would be great if you could identify a method to make this work.