1%% 2%% Copyright Ericsson AB 2019-2019. All Rights Reserved. 3%% 4%% Licensed under the Apache License, Version 2.0 (the "License"); 5%% you may not use this file except in compliance with the License. 6%% You may obtain a copy of the License at 7%% 8%% http://www.apache.org/licenses/LICENSE-2.0 9%% 10%% Unless required by applicable law or agreed to in writing, software 11%% distributed under the License is distributed on an "AS IS" BASIS, 12%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13%% See the License for the specific language governing permissions and 14%% limitations under the License. 15%% 16%% %CopyrightEnd% 17%% 18 19%% 20 21-module(ssl_socket_SUITE). 22 23-behaviour(ct_suite). 24 25-include_lib("common_test/include/ct.hrl"). 26-include_lib("public_key/include/public_key.hrl"). 27 28%% Callback functions 29-export([all/0, 30 groups/0, 31 init_per_suite/1, 32 end_per_suite/1, 33 init_per_group/2, 34 end_per_group/2, 35 init_per_testcase/2, 36 end_per_testcase/2]). 37 38%% Testcases 39-export([getstat/0, 40 getstat/1, 41 socket_options/0, 42 socket_options/1, 43 invalid_inet_get_option/0, 44 invalid_inet_get_option/1, 45 invalid_inet_get_option_not_list/0, 46 invalid_inet_get_option_not_list/1, 47 invalid_inet_get_option_improper_list/0, 48 invalid_inet_get_option_improper_list/1, 49 invalid_inet_set_option/0, 50 invalid_inet_set_option/1, 51 invalid_inet_set_option_not_list/0, 52 invalid_inet_set_option_not_list/1, 53 invalid_inet_set_option_improper_list/0, 54 invalid_inet_set_option_improper_list/1, 55 raw_inet_option/0, 56 raw_inet_option/1 57 ]). 58 59%% Apply export 60-export([socket_options_result/5, 61 get_invalid_inet_option/1, 62 get_invalid_inet_option_not_list/1, 63 get_invalid_inet_option_improper_list/1, 64 set_invalid_inet_option/1, 65 set_invalid_inet_option_not_list/1, 66 set_invalid_inet_option_improper_list/1 67 ]). 68 69-define(TIMEOUT, {seconds, 5}). 70-define(SLEEP, 500). 71%%-------------------------------------------------------------------- 72%% Common Test interface functions ----------------------------------- 73%%-------------------------------------------------------------------- 74all() -> 75 [ 76 {group, tls}, 77 {group, dtls} 78 ]. 79 80groups() -> 81 [ 82 {tls,[], socket_tests() ++ raw_inet_opt()}, 83 {dtls,[], socket_tests()} 84 ]. 85 86socket_tests() -> 87 [ 88 getstat, 89 socket_options, 90 invalid_inet_get_option, 91 invalid_inet_get_option_not_list, 92 invalid_inet_get_option_improper_list, 93 invalid_inet_set_option, 94 invalid_inet_set_option_not_list, 95 invalid_inet_set_option_improper_list 96 ]. 97 98raw_inet_opt() -> 99 [ 100 raw_inet_option 101 ]. 102 103 104init_per_suite(Config0) -> 105 catch crypto:stop(), 106 try crypto:start() of 107 ok -> 108 ssl_test_lib:clean_start(), 109 ssl_test_lib:make_rsa_cert(Config0) 110 catch _:_ -> 111 {skip, "Crypto did not start"} 112 end. 113 114end_per_suite(_Config) -> 115 ssl:stop(), 116 application:unload(ssl), 117 application:stop(crypto). 118 119init_per_group(dtls, Config) -> 120 [{protocol_opts, [{protocol, dtls}]} | proplists:delete(protocol_opts, Config)]; 121init_per_group(tls, Config) -> 122 [{protocol_opts, [{protocol, tls}]} | proplists:delete(protocol_opts, Config)]; 123init_per_group(_GroupName, Config) -> 124 [{client_type, erlang}, 125 {server_type, erlang} | Config]. 126 127end_per_group(_GroupName, Config) -> 128 Config. 129 130init_per_testcase(raw_inet_option, Config) -> 131 ct:timetrap(?TIMEOUT), 132 case os:type() of 133 {unix,linux} -> 134 Config; 135 _ -> 136 {skip, "Raw options are platform-specific"} 137 end; 138init_per_testcase(_TestCase, Config) -> 139 ct:timetrap(?TIMEOUT), 140 Config. 141 142end_per_testcase(_TestCase, Config) -> 143 Config. 144 145%%-------------------------------------------------------------------- 146%% Test Cases -------------------------------------------------------- 147%%-------------------------------------------------------------------- 148 149getstat() -> 150 [{doc,"Test API function getstat/2"}]. 151 152getstat(Config) when is_list(Config) -> 153 ClientOpts = ?config(client_rsa_opts, Config), 154 ServerOpts = ?config(server_rsa_opts, Config), 155 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 156 Server1 = 157 ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 158 {from, self()}, 159 {mfa, {ssl_test_lib, send_recv_result, []}}, 160 {options, [{active, false} | ServerOpts]}]), 161 Port1 = ssl_test_lib:inet_port(Server1), 162 Server2 = 163 ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 164 {from, self()}, 165 {mfa, {ssl_test_lib, send_recv_result, []}}, 166 {options, [{active, false} | ServerOpts]}]), 167 Port2 = ssl_test_lib:inet_port(Server2), 168 {ok, ActiveC} = rpc:call(ClientNode, ssl, connect, 169 [Hostname,Port1,[{active, once}|ClientOpts]]), 170 {ok, PassiveC} = rpc:call(ClientNode, ssl, connect, 171 [Hostname,Port2,[{active, false}|ClientOpts]]), 172 173 ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n", 174 [self(), self(), Server1, Server2]), 175 176 %% We only check that the values are non-zero initially 177 %% (due to the handshake), and that sending more changes the values. 178 179 %% Passive socket. 180 181 {ok, InitialStats} = ssl:getstat(PassiveC), 182 ct:pal("InitialStats ~p~n", [InitialStats]), 183 [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats) 184 || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]), 185 186 ok = ssl:send(PassiveC, "Hello world"), 187 wait_for_send(PassiveC), 188 {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]), 189 ct:pal("SStats ~p~n", [SStats]), 190 [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats) 191 || Name <- [send_cnt, send_oct]]), 192 193 %% Active socket. 194 195 {ok, InitialAStats} = ssl:getstat(ActiveC), 196 ct:pal("InitialAStats ~p~n", [InitialAStats]), 197 [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats) 198 || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]), 199 200 _ = receive 201 {ssl, ActiveC, _} -> 202 ok 203 after 204 ?SLEEP -> 205 exit(timeout) 206 end, 207 208 ok = ssl:send(ActiveC, "Hello world"), 209 wait_for_send(ActiveC), 210 {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]), 211 ct:pal("ASStats ~p~n", [ASStats]), 212 [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats) 213 || Name <- [send_cnt, send_oct]]), 214 215 ok. 216%%-------------------------------------------------------------------- 217socket_options() -> 218 [{doc,"Test API function getopts/2 and setopts/2"}]. 219 220socket_options(Config) when is_list(Config) -> 221 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 222 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 223 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 224 Values = [{mode, list}, {active, true}], 225 %% Shall be the reverse order of Values! 226 Options = [active, mode], 227 228 NewValues = [{mode, binary}, {active, once}], 229 %% Shall be the reverse order of NewValues! 230 NewOptions = [active, mode], 231 232 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 233 {from, self()}, 234 {mfa, {?MODULE, socket_options_result, 235 [Options, Values, NewOptions, NewValues]}}, 236 {options, ServerOpts}]), 237 Port = ssl_test_lib:inet_port(Server), 238 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 239 {host, Hostname}, 240 {from, self()}, 241 {mfa, {?MODULE, socket_options_result, 242 [Options, Values, NewOptions, NewValues]}}, 243 {options, ClientOpts}]), 244 245 ssl_test_lib:check_result(Server, ok, Client, ok), 246 247 ssl_test_lib:close(Server), 248 249 {ok, Listen} = ssl:listen(0, ServerOpts), 250 {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]), 251 ok = ssl:setopts(Listen, [{mode, binary}]), 252 {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]), 253 {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]), 254 ssl:close(Listen). 255 256%%-------------------------------------------------------------------- 257raw_inet_option() -> 258 [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}]. 259 260raw_inet_option(Config) when is_list(Config) -> 261 % 'raw' option values are platform-specific; these are the Linux values: 262 IpProtoTcp = 6, 263 % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably. 264 TcpKeepIdle = 4, 265 KeepAliveTimeSecs = 55, 266 LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}], 267 {ok, LSocket} = ssl:listen(0, LOptions), 268 % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify 269 % exactly which raw option we want, and the size of the buffer. 270 {ok, [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}]} = 271 ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]). 272 273%%-------------------------------------------------------------------- 274 275invalid_inet_get_option() -> 276 [{doc,"Test handling of invalid inet options in getopts"}]. 277 278invalid_inet_get_option(Config) when is_list(Config) -> 279 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 280 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 281 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 282 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 283 {from, self()}, 284 {mfa, {?MODULE, get_invalid_inet_option, []}}, 285 {options, ServerOpts}]), 286 Port = ssl_test_lib:inet_port(Server), 287 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 288 {host, Hostname}, 289 {from, self()}, 290 {mfa, {ssl_test_lib, no_result, []}}, 291 {options, ClientOpts}]), 292 293 ct:log("Testcase ~p, Client ~p Server ~p ~n", 294 [self(), Client, Server]), 295 296 ssl_test_lib:check_result(Server, ok), 297 ssl_test_lib:close(Server), 298 ssl_test_lib:close(Client). 299 300%%-------------------------------------------------------------------- 301invalid_inet_get_option_not_list() -> 302 [{doc,"Test handling of invalid type in getopts"}]. 303 304invalid_inet_get_option_not_list(Config) when is_list(Config) -> 305 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 306 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 307 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 308 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 309 {from, self()}, 310 {mfa, {?MODULE, get_invalid_inet_option_not_list, []}}, 311 {options, ServerOpts}]), 312 Port = ssl_test_lib:inet_port(Server), 313 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 314 {host, Hostname}, 315 {from, self()}, 316 {mfa, {ssl_test_lib, no_result, []}}, 317 {options, ClientOpts}]), 318 319 ct:log("Testcase ~p, Client ~p Server ~p ~n", 320 [self(), Client, Server]), 321 322 ssl_test_lib:check_result(Server, ok), 323 ssl_test_lib:close(Server), 324 ssl_test_lib:close(Client). 325 326%%-------------------------------------------------------------------- 327invalid_inet_get_option_improper_list() -> 328 [{doc,"Test handling of invalid type in getopts"}]. 329 330invalid_inet_get_option_improper_list(Config) when is_list(Config) -> 331 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 332 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 333 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 334 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 335 {from, self()}, 336 {mfa, {?MODULE, get_invalid_inet_option_improper_list, []}}, 337 {options, ServerOpts}]), 338 Port = ssl_test_lib:inet_port(Server), 339 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 340 {host, Hostname}, 341 {from, self()}, 342 {mfa, {ssl_test_lib, no_result, []}}, 343 {options, ClientOpts}]), 344 345 ct:log("Testcase ~p, Client ~p Server ~p ~n", 346 [self(), Client, Server]), 347 348 ssl_test_lib:check_result(Server, ok), 349 ssl_test_lib:close(Server), 350 ssl_test_lib:close(Client). 351 352%%-------------------------------------------------------------------- 353invalid_inet_set_option() -> 354 [{doc,"Test handling of invalid inet options in setopts"}]. 355 356invalid_inet_set_option(Config) when is_list(Config) -> 357 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 358 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 359 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 360 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 361 {from, self()}, 362 {mfa, {?MODULE, set_invalid_inet_option, []}}, 363 {options, ServerOpts}]), 364 Port = ssl_test_lib:inet_port(Server), 365 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 366 {host, Hostname}, 367 {from, self()}, 368 {mfa, {ssl_test_lib, no_result, []}}, 369 {options, ClientOpts}]), 370 371 ct:log("Testcase ~p, Client ~p Server ~p ~n", 372 [self(), Client, Server]), 373 374 ssl_test_lib:check_result(Server, ok), 375 ssl_test_lib:close(Server), 376 ssl_test_lib:close(Client). 377 378%%-------------------------------------------------------------------- 379invalid_inet_set_option_not_list() -> 380 [{doc,"Test handling of invalid type in setopts"}]. 381 382invalid_inet_set_option_not_list(Config) when is_list(Config) -> 383 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 384 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 385 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 386 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 387 {from, self()}, 388 {mfa, {?MODULE, set_invalid_inet_option_not_list, []}}, 389 {options, ServerOpts}]), 390 Port = ssl_test_lib:inet_port(Server), 391 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 392 {host, Hostname}, 393 {from, self()}, 394 {mfa, {ssl_test_lib, no_result, []}}, 395 {options, ClientOpts}]), 396 397 ct:log("Testcase ~p, Client ~p Server ~p ~n", 398 [self(), Client, Server]), 399 400 ssl_test_lib:check_result(Server, ok), 401 ssl_test_lib:close(Server), 402 ssl_test_lib:close(Client). 403 404%%-------------------------------------------------------------------- 405invalid_inet_set_option_improper_list() -> 406 [{doc,"Test handling of invalid tye in setopts"}]. 407 408invalid_inet_set_option_improper_list(Config) when is_list(Config) -> 409 ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), 410 ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), 411 {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), 412 Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 413 {from, self()}, 414 {mfa, {?MODULE, set_invalid_inet_option_improper_list, []}}, 415 {options, ServerOpts}]), 416 Port = ssl_test_lib:inet_port(Server), 417 Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 418 {host, Hostname}, 419 {from, self()}, 420 {mfa, {ssl_test_lib, no_result, []}}, 421 {options, ClientOpts}]), 422 423 ct:log("Testcase ~p, Client ~p Server ~p ~n", 424 [self(), Client, Server]), 425 426 ssl_test_lib:check_result(Server, ok), 427 ssl_test_lib:close(Server), 428 ssl_test_lib:close(Client). 429 430 431%%-------------------------------------------------------------------- 432%% Callback functions ------------------------------------------------ 433%%-------------------------------------------------------------------- 434socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> 435 %% Test get/set emulated opts 436 {ok, DefaultValues} = ssl:getopts(Socket, Options), 437 ssl:setopts(Socket, NewValues), 438 {ok, NewValues} = ssl:getopts(Socket, NewOptions), 439 %% Test get/set inet opts 440 {ok,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]), 441 {ok, All} = ssl:getopts(Socket, []), 442 ct:log("All opts ~p~n", [All]), 443 ok. 444 445get_invalid_inet_option(Socket) -> 446 {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]), 447 ok. 448 449get_invalid_inet_option_not_list(Socket) -> 450 {error, {options, {socket_options, some_invalid_atom_here}}} 451 = ssl:getopts(Socket, some_invalid_atom_here), 452 ok. 453 454get_invalid_inet_option_improper_list(Socket) -> 455 {error, {options, {socket_options, foo,_}}} = ssl:getopts(Socket, [packet | foo]), 456 ok. 457 458set_invalid_inet_option(Socket) -> 459 {error, {options, {socket_options, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]), 460 {error, {options, {socket_options, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]), 461 {error, {options, {socket_options, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]), 462 {error, {options, {socket_options, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]), 463 ok. 464 465set_invalid_inet_option_not_list(Socket) -> 466 {error, {options, {not_a_proplist, some_invalid_atom_here}}} 467 = ssl:setopts(Socket, some_invalid_atom_here), 468 ok. 469 470set_invalid_inet_option_improper_list(Socket) -> 471 {error, {options, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} = 472 ssl:setopts(Socket, [{packet, 0} | {foo, 2}]), 473 ok. 474 475wait_for_send(Socket) -> 476 %% Make sure TLS process processed send message event 477 _ = ssl:connection_information(Socket). 478 479