diff options
author | Björn Gustavsson <[email protected]> | 2013-03-02 12:59:36 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2013-05-31 14:52:17 +0200 |
commit | c11b5a2ebb602c76d0957b67a0ca7741c45fea85 (patch) | |
tree | b9dd1abb048ea3359facc5eb20e8511bd5fe430c /lib | |
parent | 95af544936f9b6d7b8d03f3f49effaf5c314513d (diff) | |
download | otp-c11b5a2ebb602c76d0957b67a0ca7741c45fea85.tar.gz otp-c11b5a2ebb602c76d0957b67a0ca7741c45fea85.tar.bz2 otp-c11b5a2ebb602c76d0957b67a0ca7741c45fea85.zip |
PER: Fix aligments bugs for short strings
The encoder wrongly assumed that a known multiplier string (such as
IA5String) encoded as exactly 16 bits did not need to be aligned to an
octet boundary. X.691 (07/2002) 27.5.7 says that it does. Since an
OCTET STRING encoded to 16 bits (two octets) should not be aligned to
an octet boundary, that means that asnct_imm:dec_string() needs an
additional parameter to determine whether a string of a given length
needs to be aligned.
Furthermore, there is another subtle rule difference: An OCTET STRING
which does not have fixed length is always aligned (in PER), but
a known multiplier string is aligned if its upper bound is greater
than or equal to 16.
In encoding, make sure that short known multiplier strings and
OCTET STRINGs with extensible sizes are not aligned when they are
below the appropriate limit.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/asn1/src/asn1ct_imm.erl | 43 | ||||
-rw-r--r-- | lib/asn1/src/asn1rtt_per.erl | 31 | ||||
-rw-r--r-- | lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 | 72 | ||||
-rw-r--r-- | lib/asn1/test/testPrimStrings.erl | 33 |
4 files changed, 156 insertions, 23 deletions
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 2c5620d5c8..e0e4a5a451 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -117,15 +117,25 @@ per_dec_named_integer(Constraint, NamedList0, Aligned) -> per_dec_k_m_string(StringType, Constraint, Aligned) -> SzConstr = get_constraint(Constraint, 'SizeConstraint'), N = string_num_bits(StringType, Constraint, Aligned), - Imm = dec_string(SzConstr, N, Aligned), + %% X.691 (07/2002) 27.5.7 says if the upper bound times the number + %% of bits is greater than or equal to 16, then the bit field should + %% be aligned. + Imm = dec_string(SzConstr, N, Aligned, fun(_, Ub) -> Ub >= 16 end), Chars = char_tab(Constraint, StringType, N), convert_string(N, Chars, Imm). per_dec_octet_string(Constraint, Aligned) -> - dec_string(Constraint, 8, Aligned). + dec_string(Constraint, 8, Aligned, + %% Aligned unless the size is fixed and =< 16. + fun(Sv, Sv) -> Sv > 16; + (_, _) -> true + end). per_dec_raw_bitstring(Constraint, Aligned) -> - dec_string(Constraint, 1, Aligned). + dec_string(Constraint, 1, Aligned, + fun(Sv, Sv) -> Sv > 16; + (_, _) -> true + end). per_dec_open_type(Aligned) -> {get_bits,decode_unconstrained_length(true, Aligned), @@ -149,21 +159,22 @@ per_dec_restricted_string(Aligned) -> %%% Local functions. %%% -dec_string(Sv, U, _Aligned) when is_integer(Sv), U*Sv =< 16 -> - {get_bits,Sv,[U,binary]}; -dec_string(Sv, U, Aligned) when is_integer(Sv), Sv < 16#10000 -> +dec_string(Sv, U, Aligned0, AF) when is_integer(Sv), Sv < 16#10000 -> + Bits = U*Sv, + Aligned = Aligned0 andalso AF(Bits, Bits), {get_bits,Sv,[U,binary,{align,Aligned}]}; -dec_string([_|_]=C, U, Aligned) when is_list(C) -> - dec_string({hd(C),lists:max(C)}, U, Aligned); -dec_string({Sv,Sv}, U, Aligned) -> - dec_string(Sv, U, Aligned); -dec_string({{_,_}=C,_}, U, Aligned) -> - bit_case(dec_string(C, U, Aligned), - dec_string(no, U, Aligned)); -dec_string({Lb,Ub}, U, Aligned) when Ub < 16#10000 -> - Len = per_dec_constrained(Lb, Ub, Aligned), +dec_string([_|_]=C, U, Aligned, AF) when is_list(C) -> + dec_string({hd(C),lists:max(C)}, U, Aligned, AF); +dec_string({Sv,Sv}, U, Aligned, AF) -> + dec_string(Sv, U, Aligned, AF); +dec_string({{_,_}=C,_}, U, Aligned, AF) -> + bit_case(dec_string(C, U, Aligned, AF), + dec_string(no, U, Aligned, AF)); +dec_string({Lb,Ub}, U, Aligned0, AF) when Ub < 16#10000 -> + Len = per_dec_constrained(Lb, Ub, Aligned0), + Aligned = Aligned0 andalso AF(Lb*U, Ub*U), {get_bits,Len,[U,binary,{align,Aligned}]}; -dec_string(_, U, Aligned) -> +dec_string(_, U, Aligned, _AF) -> Al = [{align,Aligned}], DecRest = fun(V, Buf) -> asn1ct_func:call(per_common, diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index d5952755f8..8d2025d603 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -663,6 +663,19 @@ make_and_set_list([], _) -> %% encode_octet_string(Constraint, Val) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +encode_octet_string({{Sv,Sv},Ext}=SZ, Val) when is_list(Ext), Sv =< 2 -> + Len = length(Val), + try + case encode_length(SZ, Len) of + [0|_]=EncLen -> + [EncLen,45,Sv*8,Sv,Val]; + [_|_]=EncLen -> + [EncLen|octets_to_complete(Len, Val)] + end + catch + exit:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end; encode_octet_string({_,_}=SZ, Val) -> Len = length(Val), try @@ -725,12 +738,24 @@ encode_restricted_string(Val) when is_list(Val)-> encode_known_multiplier_string(SizeC, NumBits, CharOutTab, Val) -> Result = chars_encode2(Val, NumBits, CharOutTab), case SizeC of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> + Ub when is_integer(Ub), Ub*NumBits < 16 -> Result; Ub when is_integer(Ub), Ub =<65535 -> % fixed length [2,Result]; - {Ub,Lb} -> - [encode_length({Ub,Lb},length(Val)),2,Result]; + {{_,Ub},Ext}=SZ when is_list(Ext) -> + Len = length(Val), + case encode_length(SZ, Len) of + [0|_]=EncLen when Ub*NumBits < 16 -> + [EncLen,45,Len*NumBits,Len,Val]; + [_|_]=EncLen -> + [EncLen,2|Result] + end; + {_,Ub}=Range -> + [encode_length(Range, length(Val))| + if + Ub*NumBits < 16 -> Result; + true -> [2|Result] + end]; no -> [encode_length(length(Val)),2,Result] end. diff --git a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 index cfaf4cf034..99fe38c07c 100644 --- a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 @@ -72,6 +72,32 @@ BS1024 ::= BIT STRING (SIZE (1024)) i INTEGER (0..1024) } + OsFixedStringsExt ::= SEQUENCE { + b1 BOOLEAN, -- Unalign + s0 OCTET STRING (SIZE (0, ...)), + s1 OCTET STRING (SIZE (1, ...)), + s2 OCTET STRING (SIZE (2, ...)), + s3 OCTET STRING (SIZE (3, ...)), + b2 BOOLEAN, -- Unalign + s255 OCTET STRING (SIZE (255, ...)), + s256 OCTET STRING (SIZE (256, ...)), + s257 OCTET STRING (SIZE (257, ...)), + i INTEGER (0..1024) + } + + OsVarStringsExt ::= SEQUENCE { + b1 BOOLEAN, -- Unalign + s0 OCTET STRING (SIZE (0, ...)), + s1 OCTET STRING (SIZE (0..1, ...)), + s2 OCTET STRING (SIZE (1..2, ...)), + s3 OCTET STRING (SIZE (2..3, ...)), + b2 BOOLEAN, -- Unalign + s255 OCTET STRING (SIZE (254..255, ...)), + s256 OCTET STRING (SIZE (255..256, ...)), + s257 OCTET STRING (SIZE (256..257, ...)), + i INTEGER (0..1024) + } + OsAlignment ::= SEQUENCE { b1 BOOLEAN, s1 Os, @@ -82,6 +108,52 @@ BS1024 ::= BIT STRING (SIZE (1024)) i INTEGER (0..63) } + IA5FixedStrings ::= SEQUENCE { + b1 BOOLEAN, -- Unalign + s0 IA5String (SIZE (0)), + s1 IA5String (SIZE (1)), + s2 IA5String (SIZE (2)), + s3 IA5String (SIZE (3)), + b2 BOOLEAN, -- Unalign + s4 IA5String (SIZE (4)), + b3 BOOLEAN, -- Unalign + s255 IA5String (SIZE (255)), + s256 IA5String (SIZE (256)), + s257 IA5String (SIZE (257)), + i INTEGER (0..1024) + } + + IA5FixedStringsExt ::= SEQUENCE { + b1 BOOLEAN, -- Unalign + s0 IA5String (SIZE (0, ...)), + s1 IA5String (SIZE (1, ...)), + s2 IA5String (SIZE (2, ...)), + s3 IA5String (SIZE (3, ...)), + b2 BOOLEAN, -- Unalign + s4 IA5String (SIZE (4, ...)), + b3 BOOLEAN, -- Unalign + s255 IA5String (SIZE (255, ...)), + s256 IA5String (SIZE (256, ...)), + s257 IA5String (SIZE (257, ...)), + i INTEGER (0..1024) + } + + IA5VarStringsExt ::= SEQUENCE { + b1 BOOLEAN, -- Unalign + s0 IA5String (SIZE (0, ...)), + s1 IA5String (SIZE (0..1, ...)), + s2 IA5String (SIZE (1..2, ...)), + s3 IA5String (SIZE (2..3, ...)), + b2 BOOLEAN, -- Unalign + s4 IA5String (SIZE (3..4, ...)), + b3 BOOLEAN, -- Unalign + s255 IA5String (SIZE (254..255, ...)), + s256 IA5String (SIZE (255..256, ...)), + s257 IA5String (SIZE (256..257, ...)), + i INTEGER (0..1024) + } + + Ns ::= NumericString NsCon ::= [70] NumericString NsExpCon ::= [71] EXPLICIT NumericString diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl index f8b0c5b05a..66415afe87 100644 --- a/lib/asn1/test/testPrimStrings.erl +++ b/lib/asn1/test/testPrimStrings.erl @@ -255,11 +255,16 @@ octet_string(Rules) -> fragmented_octet_string(Rules), S255 = lists:seq(1, 255), - FixedStrings = {'OsFixedStrings',true,"","1","12","345",true, - S255,[$a|S255],[$a,$b|S255],397}, - roundtrip('OsFixedStrings', FixedStrings), + Strings = {type,true,"","1","12","345",true, + S255,[$a|S255],[$a,$b|S255],397}, + p_roundtrip('OsFixedStrings', Strings), + p_roundtrip('OsFixedStringsExt', Strings), + p_roundtrip('OsVarStringsExt', Strings), + ShortenedStrings = shorten_by_two(Strings), + p_roundtrip('OsFixedStringsExt', ShortenedStrings), + p_roundtrip('OsVarStringsExt', ShortenedStrings), ok. - + fragmented_octet_string(Erules) -> K16 = 1 bsl 14, K32 = K16 + K16, @@ -438,6 +443,15 @@ other_strings(_Rules) -> roundtrip('IA5Visible', lists:seq($\s, $~)), + S255 = lists:seq(0, 127) ++ lists:seq(1, 127), + Strings = {type,true,"","1","12","345",true,"6789",true, + S255,[$a|S255],[$a,$b|S255],397}, + p_roundtrip('IA5FixedStrings', Strings), + p_roundtrip('IA5FixedStringsExt', Strings), + p_roundtrip('IA5VarStringsExt', Strings), + ShortenedStrings = shorten_by_two(Strings), + p_roundtrip('IA5VarStringsExt', ShortenedStrings), + ok. @@ -709,6 +723,17 @@ wrapper_utf8_binary_to_list(L) when is_list(L) -> wrapper_utf8_binary_to_list(B) -> asn1rt:utf8_binary_to_list(B). +shorten_by_two(Tuple) -> + L = [case E of + [_,_|T] -> T; + _ -> E + end || E <- tuple_to_list(Tuple)], + list_to_tuple(L). + +p_roundtrip(Type, Value0) -> + Value = setelement(1, Value0, Type), + roundtrip(Type, Value). + roundtrip(Type, Value) -> {ok,Encoded} = 'PrimStrings':encode(Type, Value), {ok,Value} = 'PrimStrings':decode(Type, Encoded), |