aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2013-03-02 12:59:36 +0100
committerBjörn Gustavsson <[email protected]>2013-05-31 14:52:17 +0200
commitc11b5a2ebb602c76d0957b67a0ca7741c45fea85 (patch)
treeb9dd1abb048ea3359facc5eb20e8511bd5fe430c
parent95af544936f9b6d7b8d03f3f49effaf5c314513d (diff)
downloadotp-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.
-rw-r--r--lib/asn1/src/asn1ct_imm.erl43
-rw-r--r--lib/asn1/src/asn1rtt_per.erl31
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PrimStrings.asn172
-rw-r--r--lib/asn1/test/testPrimStrings.erl33
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),