%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2000-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% -module(asn1rt_ber_bin). -export([decode_length/1, encode_real/2, encode_real/3, decode_real/2, decode_real/4, decode_tag/1]). -include("asn1_records.hrl"). %% the encoding of class of tag bits 8 and 7 -define(UNIVERSAL, 0). %%% primitive or constructed encoding % bit 6 -define(PRIMITIVE, 0). -define(CONSTRUCTED, 2#00100000). %%% The tag-number for universal types -define(N_REAL, 9). encode_tag_val({Class, Form, TagNo}) when (TagNo =< 30) -> <<(Class bsr 6):2,(Form bsr 5):1,TagNo:5>>; encode_tag_val({Class, Form, TagNo}) -> {Octets,_Len} = mk_object_val(TagNo), BinOct = list_to_binary(Octets), <<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>. %%=============================================================================== %% Decode a tag %% %% decode_tag(OctetListBuffer) -> {{Class, Form, TagNo}, RestOfBuffer, RemovedBytes} %%=============================================================================== %% multiple octet tag decode_tag(<>) -> {TagNo, Buffer1, RemovedBytes} = decode_tag(Buffer, 0, 1), {{(Class bsl 6), (Form bsl 5), TagNo}, Buffer1, RemovedBytes}; %% single tag (< 31 tags) decode_tag(<>) -> {{(Class bsl 6), (Form bsl 5), TagNo}, Buffer, 1}. %% last partial tag decode_tag(<<0:1,PartialTag:7, Buffer/binary>>, TagAck, RemovedBytes) -> TagNo = (TagAck bsl 7) bor PartialTag, %%<> = <>, {TagNo, Buffer, RemovedBytes+1}; % more tags decode_tag(<<_:1,PartialTag:7, Buffer/binary>>, TagAck, RemovedBytes) -> TagAck1 = (TagAck bsl 7) bor PartialTag, %%<> = <>, decode_tag(Buffer, TagAck1, RemovedBytes+1). %%------------------------------------------------------------------ %% check_tags_i is the same as check_tags except that it stops and %% returns the remaining tags not checked when it encounters an %% indefinite length field %% only called internally within this module check_tags_i([Tag], Buffer, OptOrMand) -> % optimized very usual case {[],check_one_tag(Tag, Buffer, OptOrMand)}; check_tags_i(Tags, Buffer, OptOrMand) -> check_tags_i(Tags, Buffer, 0, OptOrMand). check_tags_i([Tag1,Tag2|TagRest], Buffer, Rb, OptOrMand) when Tag1#tag.type == 'IMPLICIT' -> check_tags_i([Tag1#tag{type=Tag2#tag.type}|TagRest], Buffer, Rb, OptOrMand); check_tags_i([Tag1|TagRest], Buffer, Rb, OptOrMand) -> {Form_Length,Buffer2,Rb1} = check_one_tag(Tag1, Buffer, OptOrMand), case TagRest of [] -> {TagRest, {Form_Length, Buffer2, Rb + Rb1}}; _ -> case Form_Length of {?CONSTRUCTED,_} -> {TagRest, {Form_Length, Buffer2, Rb + Rb1}}; _ -> check_tags_i(TagRest, Buffer2, Rb + Rb1, mandatory) end end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This function is called from generated code check_one_tag(Tag=#tag{class=ExpectedClass,number=ExpectedNumber}, Buffer, OptOrMand) -> case catch decode_tag(Buffer) of {'EXIT',_Reason} -> tag_error(no_data,Tag,Buffer,OptOrMand); {{ExpectedClass,Form,ExpectedNumber},Buffer2,Rb} -> {{L,Buffer3},RemBytes2} = decode_length(Buffer2), {{Form,L}, Buffer3, RemBytes2+Rb}; {ErrorTag,_,_} -> tag_error(ErrorTag, Tag, Buffer, OptOrMand) end. tag_error(ErrorTag, Tag, Buffer, OptOrMand) -> case OptOrMand of mandatory -> exit({error,{asn1, {invalid_tag, {ErrorTag, Tag, Buffer}}}}); _ -> exit({error,{asn1, {no_optional_tag, {ErrorTag, Tag, Buffer}}}}) end. %%======================================================================= %% %% Encode all tags in the list Tags and return a possibly deep list of %% bytes with tag and length encoded %% %% prepend_tags(Tags, BytesSoFar, LenSoFar) -> {Bytes, Len} encode_tags(Tags, BytesSoFar, LenSoFar) -> NewTags = encode_tags1(Tags, []), %% NewTags contains the resulting tags in reverse order encode_tags2(NewTags, BytesSoFar, LenSoFar). %encode_tags2([#tag{class=?UNIVERSAL,number=No}|Trest], BytesSoFar, LenSoFar) -> % {Bytes2,L2} = encode_length(LenSoFar), % encode_tags2(Trest,[[No|Bytes2],BytesSoFar], LenSoFar + 1 + L2); encode_tags2([Tag|Trest], BytesSoFar, LenSoFar) -> {Bytes1,L1} = encode_one_tag(Tag), {Bytes2,L2} = encode_length(LenSoFar), encode_tags2(Trest, [Bytes1,Bytes2|BytesSoFar], LenSoFar + L1 + L2); encode_tags2([], BytesSoFar, LenSoFar) -> {BytesSoFar,LenSoFar}. encode_tags1([Tag1, Tag2| Trest], Acc) when Tag1#tag.type =:= 'IMPLICIT' -> encode_tags1([Tag1#tag{type=Tag2#tag.type,form=Tag2#tag.form}|Trest],Acc); encode_tags1([Tag1 | Trest], Acc) -> encode_tags1(Trest, [Tag1|Acc]); encode_tags1([], Acc) -> Acc. % the resulting tags are returned in reverse order encode_one_tag(Bin) when is_binary(Bin) -> {Bin,byte_size(Bin)}; encode_one_tag(#tag{class=Class,number=No,type=Type, form = Form}) -> NewForm = case Type of 'EXPLICIT' -> ?CONSTRUCTED; _ -> Form end, Bytes = encode_tag_val({Class,NewForm,No}), {Bytes,size(Bytes)}. %%============================================================================ %% %% Real value, ITU_T X.690 Chapter 8.5 %%============================================================================ %% %% encode real value %%============================================================================ %% only base 2 internally so far!! encode_real(_C,0, DoTag) -> dotag(DoTag, ?N_REAL, {[],0}); encode_real(_C,'PLUS-INFINITY', DoTag) -> dotag(DoTag, ?N_REAL, {[64],1}); encode_real(_C,'MINUS-INFINITY', DoTag) -> dotag(DoTag, ?N_REAL, {[65],1}); encode_real(C,Val, DoTag) when is_tuple(Val); is_list(Val) -> dotag(DoTag, ?N_REAL, encode_real(C,Val)). %%%%%%%%%%%%%% %% only base 2 encoding! %% binary encoding: %% +------------+ +------------+ +-+-+-+-+---+---+ %% | (tag)9 | | n + p + 1 | |1|S|BB |FF |EE | %% +------------+ +------------+ +-+-+-+-+---+---+ %% %% +------------+ +------------+ %% | | | | %% +------------+ ...+------------+ %% n octets for exponent %% %% +------------+ +------------+ %% | | | | %% +------------+ ...+------------+ %% p octets for pos mantissa %% %% S is 0 for positive sign %% 1 for negative sign %% BB: encoding base, 00 = 2, (01 = 8, 10 = 16) %% 01 and 10 not used %% FF: scale factor 00 = 0 (used in base 2 encoding) %% EE: encoding of the exponent: %% 00 - on the following octet %% 01 - on the 2 following octets %% 10 - on the 3 following octets %% 11 - encoding of the length of the two's-complement encoding of %% exponent on the following octet, and two's-complement %% encoding of exponent on the other octets. %% %% In DER and base 2 encoding the mantissa is encoded as value 0 or %% bit shifted until it is an odd number. Thus, do this for BER as %% well. %% This interface also used by RT_COMMON encode_real(_C,{Mantissa, Base, Exponent}) when Base =:= 2 -> %% io:format("Mantissa: ~w Base: ~w, Exp: ~w~n",[Man, Base, Exp]), {Man,ExpAdd} = truncate_zeros(Mantissa), %% DER adjustment Exp = Exponent + ExpAdd, OctExp = if Exp >= 0 -> list_to_binary(encode_integer_pos(Exp, [])); true -> list_to_binary(encode_integer_neg(Exp, [])) end, %% ok = io:format("OctExp: ~w~n",[OctExp]), SignBit = if Man > 0 -> 0; % bit 7 is pos or neg, no Zeroval true -> 1 end, %% ok = io:format("SignBitMask: ~w~n",[SignBitMask]), SFactor = 0, OctExpLen = size(OctExp), if OctExpLen > 255 -> exit({error,{asn1, {to_big_exp_in_encode_real, OctExpLen}}}); true -> true %% make real assert later.. end, {LenCode, EOctets} = case OctExpLen of % bit 2,1 1 -> {0, OctExp}; 2 -> {1, OctExp}; 3 -> {2, OctExp}; _ -> {3, <>} end, BB = 0, %% 00 for base 2 FirstOctet = <<1:1,SignBit:1,BB:2,SFactor:2,LenCode:2>>, OctMantissa = if Man > 0 -> list_to_binary(minimum_octets(Man)); true -> list_to_binary(minimum_octets(-(Man))) % signbit keeps track of sign end, %% ok = io:format("LenMask: ~w EOctets: ~w~nFirstOctet: ~w OctMantissa: ~w OctExpLen: ~w~n", [LenMask, EOctets, FirstOctet, OctMantissa, OctExpLen]), Bin = <>, {Bin, size(Bin)}; encode_real(C,{Mantissa,Base,Exponent}) when Base =:= 10, is_integer(Mantissa), is_integer(Exponent) -> %% always encode as NR3 due to DER on the format %% mmmm.Eseeee where %% m := digit %% s := '-' | '+' | [] %% '+' only allowed in +0 %% e := digit %% ex: 1234.E-5679 %% {Man,AddExp} = truncate_zeros(Mantissa,0), %% ManNum = trunc(Mantissa), %% {TruncatedMan,NumZeros} = truncate_zeros10(Mantissa), ManStr = integer_to_list(Mantissa), encode_real_as_string(C,ManStr,Exponent); encode_real(_C,{_,Base,_}) -> exit({error,{asn1, {encode_real_non_supported_encodeing, Base}}}); %% base 10 encode_real(C,Real) when is_list(Real) -> %% The Real string may come in as a NR1, NR2 or NR3 string. {Mantissa, Exponent} = case string:tokens(Real,"Ee") of [NR2] -> {NR2,0}; [NR3MB,NR3E] -> %% remove beginning zeros {NR3MB,list_to_integer(NR3E)} end, %% .Decimal | Number | Number.Decimal ZeroDecimal = fun("0") -> ""; (L) -> L end, {NewMantissa,LenDecimal} = case Mantissa of [$.|Dec] -> NewMan = remove_trailing_zeros(Dec), {NewMan,length(ZeroDecimal(NewMan))}; _ -> case string:tokens(Mantissa,",.") of [Num] -> %% No decimal-mark {integer_to_list(list_to_integer(Num)),0}; [Num,Dec] -> NewDec = ZeroDecimal(remove_trailing_zeros(Dec)), NewMan = integer_to_list(list_to_integer(Num)) ++ NewDec, {integer_to_list(list_to_integer(NewMan)), length(NewDec)} end end, % DER_Exponent = integer_to_list(Exponent - ExpReduce), encode_real_as_string(C,NewMantissa,Exponent - LenDecimal). encode_real_as_string(_C,Mantissa,Exponent) when is_list(Mantissa), is_integer(Exponent) -> %% Remove trailing zeros in Mantissa and add this to Exponent TruncMant = remove_trailing_zeros(Mantissa), ExpIncr = length(Mantissa) - length(TruncMant), ExpStr = integer_to_list(Exponent + ExpIncr), ExpBin = case ExpStr of "0" -> <<"E+0">>; _ -> ExpB = list_to_binary(ExpStr), <<$E,ExpB/binary>> end, ManBin = list_to_binary(TruncMant), NR3 = 3, {<>,2 + size(ManBin) + size(ExpBin)}. remove_trailing_zeros(IntStr) -> case lists:dropwhile(fun($0)-> true; (_) -> false end, lists:reverse(IntStr)) of [] -> "0"; ReversedIntStr -> lists:reverse(ReversedIntStr) end. truncate_zeros(Num) -> truncate_zeros(Num,0). truncate_zeros(0,Sum) -> {0,Sum}; truncate_zeros(M,Sum) -> case M band 16#f =:= M band 16#e of true -> truncate_zeros(M bsr 1,Sum+1); _ -> {M,Sum} end. %%============================================================================ %% decode real value %% %% decode_real([OctetBufferList], tuple|value, tag|notag) -> %% {{Mantissa, Base, Exp} | realval | PLUS-INFINITY | MINUS-INFINITY | 0, %% RestBuff} %% %% only for base 2 decoding sofar!! %%============================================================================ decode_real(Buffer, C, Tags, OptOrMand) -> NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_REAL}), decode_real_notag(Buffer, C, NewTags, OptOrMand). %% This interface used by RT_COMMON decode_real(Buffer,Len) -> decode_real2(Buffer,[],Len,0). decode_real_notag(Buffer, C, Tags, OptOrMand) -> {_RestTags, {{_,Len}, Buffer0, Rb0}} = check_tags_i(Tags, Buffer, OptOrMand), decode_real2(Buffer0, C, Len, Rb0). decode_real2(Buffer, _C, 0, _RemBytes) -> {0,Buffer}; decode_real2(Buffer0, _C, Len, RemBytes1) -> <> = Buffer0, if First =:= 2#01000000 -> {'PLUS-INFINITY', Buffer2}; First =:= 2#01000001 -> {'MINUS-INFINITY', Buffer2}; %% First =:= 2#00000000 -> {0, Buffer2}; First =:= 1 orelse First =:= 2 orelse First =:= 3 -> %% charcter string encoding of base 10 {NRx,Rest} = split_binary(Buffer2,Len-1), {binary_to_list(NRx),Rest,Len}; true -> %% have some check here to verify only supported bases (2) %% not base 8 or 16 <<_B7:1,Sign:1,BB:2,_FF:2,EE:2>> = <>, Base = case BB of 0 -> 2; % base 2, only one so far _ -> exit({error,{asn1, {non_supported_base, BB}}}) end, {FirstLen, {Exp, Buffer3,_Rb2}, RemBytes2} = case EE of 0 -> {2, decode_integer2(1, Buffer2, RemBytes1), RemBytes1+1}; 1 -> {3, decode_integer2(2, Buffer2, RemBytes1), RemBytes1+2}; 2 -> {4, decode_integer2(3, Buffer2, RemBytes1), RemBytes1+3}; 3 -> <> = Buffer2, { ExpLen1 + 2, decode_integer2(ExpLen1, RestBuffer, RemBytes1), RemBytes1+ExpLen1} end, %% io:format("FirstLen: ~w, Exp: ~w, Buffer3: ~w ~n", Length = Len - FirstLen, <> = Buffer3, {{Mantissa, Buffer4}, RemBytes3} = if Sign =:= 0 -> %% io:format("sign plus~n"), {{LongInt, RestBuff}, 1 + Length}; true -> %% io:format("sign minus~n"), {{-LongInt, RestBuff}, 1 + Length} end, {{Mantissa, Base, Exp}, Buffer4, RemBytes2+RemBytes3} end. encode_integer_pos(0, L=[B|_Acc]) when B < 128 -> L; encode_integer_pos(N, Acc) -> encode_integer_pos((N bsr 8), [N band 16#ff| Acc]). encode_integer_neg(-1, L=[B1|_T]) when B1 > 127 -> L; encode_integer_neg(N, Acc) -> encode_integer_neg(N bsr 8, [N band 16#ff|Acc]). %%%%%%%%%%% %% mk_object_val(Value) -> {OctetList, Len} %% returns a Val as a list of octets, the 8 bit is allways set to one except %% for the last octet, where its 0 %% mk_object_val(Val) when Val =< 127 -> {[255 band Val], 1}; mk_object_val(Val) -> mk_object_val(Val bsr 7, [Val band 127], 1). mk_object_val(0, Ack, Len) -> {Ack, Len}; mk_object_val(Val, Ack, Len) -> mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1). %%============================================================================ %% Length handling %% %% Encode length %% %% encode_length(Int | indefinite) -> %% [<127]| [128 + Int (<127),OctetList] | [16#80] %%============================================================================ encode_length(L) when L =< 16#7F -> {[L],1}; encode_length(L) -> Oct = minimum_octets(L), Len = length(Oct), if Len =< 126 -> {[ (16#80+Len) | Oct ],Len+1}; true -> exit({error,{asn1, to_long_length_oct, Len}}) end. %% Val must be >= 0 minimum_octets(Val) -> minimum_octets(Val,[]). minimum_octets(0,Acc) -> Acc; minimum_octets(Val, Acc) -> minimum_octets((Val bsr 8),[Val band 16#FF | Acc]). %%=========================================================================== %% Decode length %% %% decode_length(OctetList) -> {{indefinite, RestOctetsL}, NoRemovedBytes} | %% {{Length, RestOctetsL}, NoRemovedBytes} %%=========================================================================== decode_length(<<1:1,0:7,T/binary>>) -> {{indefinite, T}, 1}; decode_length(<<0:1,Length:7,T/binary>>) -> {{Length,T},1}; decode_length(<<1:1,LL:7,T/binary>>) -> <> = T, {{Length,Rest}, LL+1}. dotag([], Tag, {Bytes,Len}) -> dotag_universal(Tag,Bytes,Len); dotag(Tags, Tag, {Bytes,Len}) -> encode_tags(Tags ++ [#tag{class=?UNIVERSAL,number=Tag,form=?PRIMITIVE}], Bytes, Len). dotag_universal(UniversalTag,Bytes,Len) when Len =< 16#7F-> {[UniversalTag,Len,Bytes],2+Len}; dotag_universal(UniversalTag,Bytes,Len) -> {EncLen,LenLen}=encode_length(Len), {[UniversalTag,EncLen,Bytes],1+LenLen+Len}. %% decoding postitive integer values. decode_integer2(Len,Bin = <<0:1,_:7,_Bs/binary>>,RemovedBytes) -> <> = Bin, {Int,Buffer2,RemovedBytes}; %% decoding negative integer values. decode_integer2(Len,<<1:1,B2:7,Bs/binary>>,RemovedBytes) -> <> = <>, Int = N - (1 bsl (8 * Len - 1)), {Int,Buffer2,RemovedBytes}. new_tags([],LastTag) -> [LastTag]; new_tags(Tags = [#tag{type='IMPLICIT'}],_LastTag) -> Tags; new_tags([T1 = #tag{type='IMPLICIT'},#tag{type=T2Type}|Rest],LastTag) -> new_tags([T1#tag{type=T2Type}|Rest],LastTag); new_tags(Tags,LastTag) -> case lists:last(Tags) of #tag{type='IMPLICIT'} -> Tags; _ -> Tags ++ [LastTag] end.