Generic asn.1 parser

Sean Hinde <>
Wed Apr 11 17:28:30 CEST 2001


Hi,

I felt the need for an asn.1 parser which would decode generic asn.1 data
into a tree structure. Here's the result in case anyone else might have felt
this need!

It seems to work fine for a whole bunch of c7 MAP messages (which include
nested indefinite length constructor tags). I guess if it deals with those
it should be in a reasonably working state :)

The output format is a bit arbritrary.

Don't sue me if it causes your business to fail etc. Please let me know if
you improve it

I use atoms quite a bit - does anyone have a good feel for the performance
impact of this over using integers for matching and tagging?

Rgds,
Sean

%%-----------------------------------------------------------------------
%% Decode asn1 coded binary into parse tree
%% Handles indefinite length if re-assembly has already been
%% done - should be relatively easy to allow for segmented though
%% as we keep a count of unrequited indefinite length
%% constructor tags.
%%-----------------------------------------------------------------------
asn1_decode(Bin) ->
    asn1_decode(Bin, 0).
  
asn1_decode(<<>>, 0) ->
    [];
asn1_decode(Bin, N0) ->
    {Class, Form, Tag, Rest, N} = get_tag(Bin, N0),
    case tag_type(Class, Form, Tag) of
	indefinite_end ->
	    asn1_decode(Rest, N);
	Constructor when Constructor == set;
			     Constructor == seq;
			     Constructor == constructor ->
	    case get_length(Rest) of
		{indefinite, Rest1} ->
		    [{{Constructor, indef, Class, Tag}, asn1_decode(Rest1,
N+1)}];
		{Len, Rest1} ->
		    {Data, Rest2} = get_content(Len, Rest1),
		    [{{Constructor, Class, Tag}, asn1_decode(Data, 0)}|
		     asn1_decode(Rest2, N)]
	    end;
	tag ->
	    {Len, Rest1} = get_length(Rest),				   
	    {Data, Rest2} = get_content(Len, Rest1),
	    [{{tag, fmt_class(Class), Tag}, Data}|asn1_decode(Rest2, N)]
    end.
	    

%% Get tag data. 0:1, 0:15 gets around compiler
%% bug as I haven't updated my PC yet..
get_tag(<<0:1, 0:15, Rest/binary>>, 0) ->
    exit(unexpected_end_of_indefinite_length);
get_tag(<<0:1, 0:15, Rest/binary>>, N) ->
    {indefinite_end, 0, 0, Rest, N-1};
get_tag(<<Class:2, Form:1, Tag:5, Rest/binary>>, N) ->
    {Tag1, Rest1} = get_tag1(Tag, Rest),
    {Class, Form, Tag1, Rest1, N}.

%% Handle extension parts of the tag field
get_tag1(31, <<0:1, Tag:7, Rest/binary>>) ->
    {Tag, Rest};
get_tag1(31, <<1:1, Msb:7, _:1, Lsb:7, Rest/binary>>) ->
    {Msb*128+Lsb, Rest};
get_tag1(Tag, Rest) ->
    {Tag, Rest}.
	    
% Do short and long definite length forms
% And *now*... indefinite length!
get_length(<<0:1, Len:7, Rest/binary>>) ->
    {Len, Rest};
get_length(<<1:1, 0:7, Rest/binary>>) ->
    {indefinite, Rest};
get_length(<<1:1, Len_len:7, Rest/binary>>) ->
    <<Len:Len_len/unit:8, Rest1/binary>> = Rest,
    {Len, Rest1}.

% Get actual content of field
get_content(Len, Rest) ->
    <<Data:Len/binary, Rest1/binary>> = Rest,
    {Data, Rest1}.
    
% tag_type(Class, Form, Tag) -> tag|seq|set|constructor
tag_type(indefinite_end, _, _) -> indefinite_end;
tag_type(Class, 0, Tag) -> tag;
tag_type(0, 1, 16)       -> seq;
tag_type(0, 1, 17)       -> set;
tag_type(Class, 1, Els) -> constructor.

fmt_class(0) -> univ;
fmt_class(1) -> app;
fmt_class(2) -> context;
fmt_class(3) -> priv.





NOTICE AND DISCLAIMER:
This email (including attachments) is confidential.  If you have received
this email in error please notify the sender immediately and delete this
email from your system without copying or disseminating it or placing any
reliance upon its contents.  We cannot accept liability for any breaches of
confidence arising through use of email.  Any opinions expressed in this
email (including attachments) are those of the author and do not necessarily
reflect our opinions.  We will not accept responsibility for any commitments
made by our employees outside the scope of our business.  We do not warrant
the accuracy or completeness of such information.




More information about the erlang-questions mailing list