aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2013-08-06 12:05:21 +0200
committerBjörn Gustavsson <[email protected]>2013-08-08 15:30:06 +0200
commit302ad9890fbd71ad54cb6a0ae4f5e6cfe198b485 (patch)
treede88653f5c0acfc4c748bb86c995320add1befb3 /lib/asn1
parent90f6229822c720d7616f9a11d1ca51e522586564 (diff)
downloadotp-302ad9890fbd71ad54cb6a0ae4f5e6cfe198b485.tar.gz
otp-302ad9890fbd71ad54cb6a0ae4f5e6cfe198b485.tar.bz2
otp-302ad9890fbd71ad54cb6a0ae4f5e6cfe198b485.zip
PER, UPER: Fix encoding/decoding of open types greater than 16K
Diffstat (limited to 'lib/asn1')
-rw-r--r--lib/asn1/src/asn1rt_per_bin.erl49
-rw-r--r--lib/asn1/src/asn1rt_per_bin_rt2ct.erl61
-rw-r--r--lib/asn1/src/asn1rt_uper_bin.erl44
-rw-r--r--lib/asn1/test/Makefile1
-rw-r--r--lib/asn1/test/asn1_SUITE.erl7
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Fragmented.asn124
-rw-r--r--lib/asn1/test/testFragmented.erl42
7 files changed, 198 insertions, 30 deletions
diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl
index 5772f09bf4..1f8c9729e7 100644
--- a/lib/asn1/src/asn1rt_per_bin.erl
+++ b/lib/asn1/src/asn1rt_per_bin.erl
@@ -505,12 +505,21 @@ decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
%% | binary
%% Contraint = not used in this version
%%
-encode_open_type(_C, Val) when is_list(Val) ->
- Bin = list_to_binary(Val),
- [encode_length(undefined,size(Bin)),{octets,Bin}]; % octets implies align
-encode_open_type(_C, Val) when is_binary(Val) ->
- [encode_length(undefined,size(Val)),{octets,Val}]. % octets implies align
-%% the binary_to_list is not optimal but compatible with the current solution
+encode_open_type(_Constraint, Val) when is_list(Val) ->
+ encode_open_type_1(list_to_binary(Val));
+encode_open_type(_Constraint, Val) when is_binary(Val) ->
+ encode_open_type_1(Val).
+
+encode_open_type_1(Val0) ->
+ case byte_size(Val0) of
+ Size when Size < 16384 ->
+ [encode_length(undefined, Size),{octets,Val0}];
+ Size ->
+ F = min(Size bsr 14, 4),
+ SegSz = F * ?'16K',
+ <<Val:SegSz/binary,T/binary>> = Val0,
+ [{octets,<<3:2,F:6>>},{octets,Val}|encode_open_type_1(T)]
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% decode_open_type(Buffer,Constraint) -> Value
@@ -518,9 +527,20 @@ encode_open_type(_C, Val) when is_binary(Val) ->
%% Buffer = [byte] with PER encoded data
%% Value = [byte] with decoded data (which must be decoded again as some type)
%%
-decode_open_type(Bytes, _C) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_bin(Bytes2,Len).
+decode_open_type(Bytes, _Constraint) ->
+ decode_open_type_1(Bytes, []).
+
+decode_open_type_1(Bytes0, Acc) ->
+ case decode_length_unlimited(Bytes0) of
+ {Len,Bytes} when Len < ?'16K', Acc =:= [] ->
+ getoctets_as_bin(Bytes, Len);
+ {Len,Bytes1} when Len < ?'16K' ->
+ {Bin,Bytes} = getoctets_as_bin(Bytes1, Len),
+ {iolist_to_binary([Acc,Bin]),Bytes};
+ {Len,Bytes1} ->
+ {Bin,Bytes} = getoctets_as_bin(Bytes1, Len),
+ decode_open_type_1(Bytes, [Acc,Bin])
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList
@@ -884,6 +904,17 @@ decode_small_length(Buffer) ->
decode_length(Remain,undefined)
end.
+decode_length_unlimited(Buffer) ->
+ case align(Buffer) of
+ {0,<<0:1,Oct:7,Rest/binary>>} ->
+ {Oct,{0,Rest}};
+ {0,<<1:1,0:1,Val:14,Rest/binary>>} ->
+ {Val,{0,Rest}};
+ {0,<<1:1,1:1,F:6,Rest/binary>>} ->
+ SegSz = F * ?'16K',
+ {SegSz,{0,Rest}}
+ end.
+
decode_length(Buffer) ->
decode_length(Buffer,undefined).
diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
index 1df757a47f..9ce5b086cd 100644
--- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
+++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
@@ -378,21 +378,32 @@ decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
%% Contraint = not used in this version
%%
encode_open_type(_Constraint, Val) when is_list(Val) ->
- Bin = list_to_binary(Val),
- case size(Bin) of
- Size when Size>255 ->
- [encode_length(undefined,Size),[21,<<Size:16>>,Bin]];
- Size ->
- [encode_length(undefined,Size),[20,Size,Bin]]
- end;
+ encode_open_type_1(list_to_binary(Val));
encode_open_type(_Constraint, Val) when is_binary(Val) ->
- case size(Val) of
- Size when Size>255 ->
- [encode_length(undefined,size(Val)),[21,<<Size:16>>,Val]]; % octets implies align
+ encode_open_type_1(Val).
+
+encode_open_type_1(Val) ->
+ case byte_size(Val) of
+ Size when Size < 256 ->
+ [encode_length(undefined, Size),20,Size,Val];
+ Size when Size < 16384 ->
+ [encode_length(undefined, Size),21,<<Size:16>>,Val];
Size ->
- [encode_length(undefined,Size),[20,Size,Val]]
+ encode_fragmented(Val, Size)
+ end.
+
+encode_fragmented(Val0, Size) ->
+ case Size bsr 14 of
+ F when F >= 4 ->
+ <<Val1:16#8000/binary,Val2:16#8000/binary,T/binary>> = Val0,
+ [20,1,16#C4,<<21,16#8000:16>>,Val1,
+ <<21,16#8000:16>>,Val2|encode_open_type_1(T)];
+ F ->
+ SegSz = F * ?'16K',
+ <<Val:SegSz/binary,T/binary>> = Val0,
+ [<<20,1,3:2,F:6,21,SegSz:16>>,Val|encode_open_type_1(T)]
end.
-%% the binary_to_list is not optimal but compatible with the current solution
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% decode_open_type(Buffer,Constraint) -> Value
@@ -401,8 +412,19 @@ encode_open_type(_Constraint, Val) when is_binary(Val) ->
%% Value = [byte] with decoded data (which must be decoded again as some type)
%%
decode_open_type(Bytes, _Constraint) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_bin(Bytes2,Len).
+ decode_open_type_1(Bytes, []).
+
+decode_open_type_1(Bytes0, Acc) ->
+ case decode_length_unlimited(Bytes0) of
+ {Len,Bytes} when Len < ?'16K', Acc =:= [] ->
+ getoctets_as_bin(Bytes, Len);
+ {Len,Bytes1} when Len < ?'16K' ->
+ {Bin,Bytes} = getoctets_as_bin(Bytes1, Len),
+ {iolist_to_binary([Acc,Bin]),Bytes};
+ {Len,Bytes1} ->
+ <<Bin:Len/binary,Bytes/binary>> = Bytes1,
+ decode_open_type_1(Bytes, [Acc,Bin])
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList
@@ -788,6 +810,17 @@ decode_small_length(Buffer) ->
decode_length(Remain,undefined)
end.
+decode_length_unlimited(Buffer) ->
+ case align(Buffer) of
+ <<0:1,Oct:7,Rest/binary>> ->
+ {Oct,Rest};
+ <<1:1,0:1,Val:14,Rest/binary>> ->
+ {Val,Rest};
+ <<1:1,1:1,F:6,Rest/binary>> ->
+ SegSz = F * ?'16K',
+ {SegSz,Rest}
+ end.
+
decode_length(Buffer) ->
decode_length(Buffer,undefined).
diff --git a/lib/asn1/src/asn1rt_uper_bin.erl b/lib/asn1/src/asn1rt_uper_bin.erl
index abe178a69e..4e18753a16 100644
--- a/lib/asn1/src/asn1rt_uper_bin.erl
+++ b/lib/asn1/src/asn1rt_uper_bin.erl
@@ -323,10 +323,21 @@ decode_fragmented_octets(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) ->
%% | binary
%% Contraint = not used in this version
%%
-encode_open_type(C, Val) when is_list(Val) ->
- encode_open_type(C, list_to_binary(Val));
-encode_open_type(_C, Val) when is_binary(Val) ->
- [encode_length(undefined,size(Val)),Val].
+encode_open_type(_Constraint, Val) when is_list(Val) ->
+ encode_open_type_1(list_to_binary(Val));
+encode_open_type(_Constraint, Val) when is_binary(Val) ->
+ encode_open_type_1(Val).
+
+encode_open_type_1(Val0) ->
+ case byte_size(Val0) of
+ Size when Size < 16384 ->
+ [encode_length(undefined, Size),Val0];
+ Size ->
+ F = min(Size bsr 14, 4),
+ SegSz = F * ?'16K',
+ <<Val:SegSz/binary,T/binary>> = Val0,
+ [<<3:2,F:6>>,Val|encode_open_type_1(T)]
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -335,9 +346,20 @@ encode_open_type(_C, Val) when is_binary(Val) ->
%% Buffer = [byte] with PER encoded data
%% Value = [byte] with decoded data (which must be decoded again as some type)
%%
-decode_open_type(Bytes, _C) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_bin(Bytes2,Len).
+decode_open_type(Bytes, _Constraint) ->
+ decode_open_type_1(Bytes, []).
+
+decode_open_type_1(Bytes0, Acc) ->
+ case decode_length_unlimited(Bytes0) of
+ {Len,Bytes} when Len < ?'16K', Acc =:= [] ->
+ getoctets_as_bin(Bytes, Len);
+ {Len,Bytes1} when Len < ?'16K' ->
+ {Bin,Bytes} = getoctets_as_bin(Bytes1, Len),
+ {iolist_to_binary([Acc,Bin]),Bytes};
+ {Len,Bytes1} ->
+ <<Bin:Len/binary,Bytes/bitstring>> = Bytes1,
+ decode_open_type_1(Bytes, [Acc,Bin])
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList
@@ -632,6 +654,14 @@ decode_small_length(Buffer) ->
decode_length(Remain,undefined)
end.
+decode_length_unlimited(<<0:1,Oct:7,Rest/bitstring>>) ->
+ {Oct,Rest};
+decode_length_unlimited(<<1:1,0:1,Val:14,Rest/bitstring>>) ->
+ {Val,Rest};
+decode_length_unlimited(<<1:1,1:1,F:6,Rest/bitstring>>) ->
+ SegSz = F * ?'16K',
+ {SegSz,Rest}.
+
decode_length(Buffer) ->
decode_length(Buffer,undefined).
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index 6e6374baf1..69b95b40d5 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -109,6 +109,7 @@ MODULES= \
test_modified_x420 \
testX420 \
test_x691 \
+ testFragmented \
asn1_test_lib \
asn1_app_test \
asn1_appup_test \
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index be3a6c52c2..b052529ebd 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -168,6 +168,7 @@ groups() ->
per_open_type,
testInfObjectClass,
testParameterizedInfObj,
+ testFragmented,
testMergeCompile,
testobj,
testDeepTConstr,
@@ -816,6 +817,12 @@ testParameterizedInfObj(Config, Rule, Opts) ->
asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
testParameterizedInfObj:main(Config, Rule).
+testFragmented(Config) ->
+ test(Config, fun testFragmented/3).
+testFragmented(Config, Rule, Opts) ->
+ asn1_test_lib:compile("Fragmented", Config, [Rule|Opts]),
+ testFragmented:main(Rule).
+
testMergeCompile(Config) -> test(Config, fun testMergeCompile/3).
testMergeCompile(Config, Rule, Opts) ->
Files = ["MS.set.asn", "RANAPSET.set.asn1", "Mvrasn4.set.asn",
diff --git a/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1 b/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1
new file mode 100644
index 0000000000..bfc939737f
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/Fragmented.asn1
@@ -0,0 +1,24 @@
+Fragmented DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+FUNCTION ::= CLASS {
+ &code INTEGER UNIQUE,
+ &b BOOLEAN,
+ &ArgumentType
+}
+
+SS ::= SEQUENCE OF OCTET STRING
+
+val1 FUNCTION ::= {
+ &code 1, &b FALSE, &ArgumentType SS
+}
+
+ObjSet FUNCTION ::= { val1 }
+
+PDU ::= SEQUENCE {
+ code FUNCTION.&code ({ObjSet}),
+ b FUNCTION.&b ({ObjSet}{@code}),
+ arg FUNCTION.&ArgumentType ({ObjSet}{@code})
+}
+
+END
diff --git a/lib/asn1/test/testFragmented.erl b/lib/asn1/test/testFragmented.erl
new file mode 100644
index 0000000000..17995a05bf
--- /dev/null
+++ b/lib/asn1/test/testFragmented.erl
@@ -0,0 +1,42 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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(testFragmented).
+
+-export([main/1]).
+
+main(_Erule) ->
+ roundtrip('PDU', {'PDU',1,false,["abc","def"]}),
+ B256 = lists:seq(0, 255),
+ K1 = lists:duplicate(4, B256),
+ K8 = binary_to_list(iolist_to_binary(lists:duplicate(8, K1))),
+ roundtrip('PDU', {'PDU',1,false,[K8,K8]}),
+ roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8]}),
+ roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8]}),
+ roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8]}),
+ roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8,
+ K8,K8,K8,K8,K8,K8]}),
+ roundtrip('PDU', {'PDU',1,false,[K8,K8,K8,K8,K8,K8,K8,K8,
+ K8,K8,K8,K8,K8,K8,K8,K8]}),
+ ok.
+
+roundtrip(T, V) ->
+ {ok,E} = asn1_wrapper:encode('Fragmented', T, V),
+ {ok,V} = asn1_wrapper:decode('Fragmented', T, E),
+ ok.