1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22-module(openssl_mfl_SUITE).
23-include_lib("common_test/include/ct.hrl").
24
25%% Common test
26-export([all/0,
27         groups/0,
28         init_per_suite/1,
29         init_per_group/2,
30         init_per_testcase/2,
31         end_per_suite/1,
32         end_per_group/2,
33         end_per_testcase/2]).
34
35%% Testcases
36-export([openssl_client/1,
37         openssl_server/1,
38         reuse_session_erlang_server/1,
39         reuse_session_erlang_client/1]).
40
41-define(SLEEP, 500).
42%%--------------------------------------------------------------------
43%% Common Test interface functions -----------------------------------
44%%--------------------------------------------------------------------
45
46all() ->
47    case ssl_test_lib:openssl_dtls_maxfraglen_support() of
48        true ->
49            [{group, 'tlsv1.3'},
50             {group, 'tlsv1.2'},
51             {group, 'tlsv1.1'},
52             {group, 'tlsv1'},
53             {group, 'dtlsv1.2'},
54             {group, 'dtlsv1'}];
55        false ->
56            [{group, 'tlsv1.3'},
57             {group, 'tlsv1.2'},
58             {group, 'tlsv1.1'},
59             {group, 'tlsv1'}]
60    end.
61
62groups() ->
63    [{'tlsv1.3', [], common_tests()},
64     {'tlsv1.2', [], common_tests() ++ pre_tls_1_3()},
65     {'tlsv1.1', [], common_tests() ++ pre_tls_1_3()},
66     {'tlsv1', [], common_tests() ++ pre_tls_1_3()},
67     {'dtlsv1.2', [], common_tests() ++ pre_tls_1_3()},
68     {'dtlsv1', [], common_tests() ++ pre_tls_1_3()}
69    ].
70
71init_per_suite(Config0) ->
72    catch crypto:stop(),
73    try crypto:start() of
74	ok ->
75            case ssl_test_lib:openssl_maxfraglen_support() of
76                true ->
77                    ssl_test_lib:clean_start(),
78                    ssl:clear_pem_cache(),
79                    Config = ssl_test_lib:make_rsa_cert(Config0),
80                    ssl_test_lib:cert_options(Config);
81                false ->
82                    {skip, "max_fragment_length not supported by OpenSSL"}
83            end
84    catch _:_ ->
85	    {skip, "Crypto did not start"}
86    end.
87
88end_per_suite(_Config) ->
89    ssl:stop(),
90    application:stop(crypto).
91
92init_per_group(GroupName, Config) ->
93    ssl_test_lib:init_per_group_openssl(GroupName, Config).
94
95end_per_group(GroupName, Config) ->
96    ssl_test_lib:end_per_group(GroupName, Config).
97
98init_per_testcase(_TestCase, Config) ->
99    ct:timetrap({seconds, 10}),
100    Config.
101
102end_per_testcase(_TestCase, Config) ->
103    Config.
104
105common_tests() ->
106    [openssl_client, openssl_server].
107
108pre_tls_1_3() ->
109    [reuse_session_erlang_server, reuse_session_erlang_client].
110
111%%--------------------------------------------------------------------
112%% Test Cases --------------------------------------------------------
113%%--------------------------------------------------------------------
114openssl_server(Config) when is_list(Config) ->
115    openssl_server(512, Config),
116    openssl_server(2048, Config).
117
118%--------------------------------------------------------------------------------
119%% check max_fragment_length interworking with openssl client
120openssl_client(Config) when is_list(Config) ->
121    openssl_client(1024, Config),
122    openssl_client(4096, Config).
123
124%--------------------------------------------------------------------------------
125reuse_session_erlang_server(Config) when is_list(Config) ->
126    ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
127    ClientOpts = proplists:get_value(client_rsa_opts, Config),
128
129    {_, ServerNode, _} = ssl_test_lib:run_where(Config),
130
131    MFL = 512,
132    Data = "reuse_session_erlang_server " ++ lists:duplicate(MFL, $r),
133
134    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
135                                        {from, self()},
136                                        {mfa, {ssl_test_lib, active_recv, [length(Data)]}},
137                                        {reconnect_times, 5},
138                                        {options,  ServerOpts}]),
139    Port = ssl_test_lib:inet_port(Server),
140
141    {_Client, OpenSSLPort} = ssl_test_lib:start_client(openssl, [{port, Port},
142                                                                 {reconnect, true},
143                                                                 {maxfrag, MFL},
144                                                                 {options, ClientOpts},
145                                                                 return_port], Config),
146    max_frag_len_test(Server, OpenSSLPort, MFL, Data),
147    ssl_test_lib:close(Server).
148
149%%--------------------------------------------------------------------
150
151reuse_session_erlang_client(Config) when is_list(Config) ->
152    process_flag(trap_exit, true),
153    ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
154    ServerOpts = proplists:get_value(server_rsa_opts, Config),
155    {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
156
157    MFL = 512,
158    Data = "reuse_session_erlang_client " ++ lists:duplicate(MFL, $r),
159    ClientOpts = [{max_fragment_length, MFL} | ClientOpts0],
160
161    {Server, OpenSSLPort} = ssl_test_lib:start_server(openssl, [{maxfrag, MFL}, return_port],
162                                                      [{server_opts, ServerOpts} | Config]),
163    Port = ssl_test_lib:inet_port(Server),
164
165
166    Client0 =
167        ssl_test_lib:start_client([{node, ClientNode},
168                                   {port, Port}, {host, Hostname},
169                                   {mfa, {ssl_test_lib, session_id, []}},
170                                   {from, self()},
171                                   {options, [{reuse_sessions, save}, {verify, verify_peer}| ClientOpts]}]),
172
173    SID = receive
174              {Client0, Id0} ->
175                  Id0
176          end,
177
178    %% quit s_server's current session so we can interact with the next client
179    true = port_command(OpenSSLPort, "q\n"),
180    ssl_test_lib:close(Client0),
181
182    Client1 =
183        ssl_test_lib:start_client([{node, ClientNode},
184                                   {port, Port}, {host, Hostname},
185                                   {mfa, {ssl_test_lib, session_id, []}},
186                                   {from, self()},  {options, [{reuse_session, SID} | ClientOpts]}]),
187    receive
188        {Client1, SID} ->
189            ok
190    after ?SLEEP ->
191            ct:fail(session_not_reused)
192    end,
193
194    ErlRecvFun = fun() ->
195                         Data = ssl_test_lib:check_active_receive(Client1, Data)
196                 end,
197    max_frag_len_test(Client1, OpenSSLPort, MFL, Data, ErlRecvFun),
198    ssl_test_lib:close(Client1).
199
200
201openssl_client(MFL, Config) ->
202    ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
203    ClientOpts = proplists:get_value(client_rsa_opts, Config),
204    {_, ServerNode, _} = ssl_test_lib:run_where(Config),
205
206    Data = "mfl_openssl_server " ++ lists:duplicate(MFL, $s),
207    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
208                                        {from, self()},
209                                        {mfa, {ssl_test_lib, active_recv, [length(Data)]}},
210                                        {options, ServerOpts}]),
211    Port = ssl_test_lib:inet_port(Server),
212
213    {_Client, OpenSSLPort} = ssl_test_lib:start_client(openssl, [{port, Port},
214                                                                 {maxfrag, MFL},
215                                                                 {options, ClientOpts},
216                                                                 return_port], Config),
217
218    max_frag_len_test(Server, OpenSSLPort, MFL, Data).
219
220%% -------------------------------------------------------------------------------
221%% Internal functions
222%%--------------------------------------------------------------------------------
223
224openssl_server(MFL, Config) ->
225    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
226    ServerOpts = proplists:get_value(server_rsa_opts, Config),
227    {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
228    Data = "mfl_openssl_server " ++ lists:duplicate(MFL, $s),
229
230    {Server, OpenSSLPort} = ssl_test_lib:start_server(openssl, [{maxfrag, MFL},
231                                                                return_port],
232                                                      [{server_opts, ServerOpts} | Config]),
233    Port = ssl_test_lib:inet_port(Server),
234
235    Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
236                                        {host, Hostname},
237                                        {from, self()},
238                                        {mfa, {ssl_test_lib,
239                                               active_recv, [length(Data)]}},
240                                        {options, [{max_fragment_length, MFL} | ClientOpts]}]),
241
242    max_frag_len_test(Client, OpenSSLPort, MFL, Data).
243
244%% ------------------------------------------------------------
245max_frag_len_test(ErlProc, OpenSSL, MFL, Data) ->
246    ErlRecvFun = fun() ->
247                         receive
248                             {ErlProc, Data} ->
249                                 ok
250                         end
251                 end,
252    max_frag_len_test(ErlProc, OpenSSL, MFL, Data, ErlRecvFun).
253
254max_frag_len_test(ErlProc, OpenSSL, MFL, Data, ErlRecvFun) ->
255    true = port_command(OpenSSL, Data),
256    ErlRecvFun(),
257
258    ErlProc ! get_socket,
259    ErlSocket = receive
260                    {ErlProc, {socket, ErlSocket0}} ->
261                        ErlSocket0
262                end,
263    ssl_test_lib:assert_mfl(ErlSocket, MFL).
264