./ct_report/coverage/ejabberd_tls.COVER.html

1 %%%=============================================================================
2 %%% @copyright (C) 1999-2018, Erlang Solutions Ltd
3 %%% @author Denys Gonchar <denys.gonchar@erlang-solutions.com>
4 %%% @doc this module provides general TLS interface for MongooseIM.
5 %%%
6 %%% by default tls_module is set to fast_tls, alternatively it can be any
7 %%% module that implements ejabberd_tls behaviour
8 %%% @end
9 %%%=============================================================================
10 -module(ejabberd_tls).
11 -copyright("2018, Erlang Solutions Ltd.").
12 -author('denys.gonchar@erlang-solutions.com').
13
14 %% tls interfaces required by ejabberd_socket & ejabberd_receiver modules.
15 -export([tcp_to_tls/2,
16 default_ciphers/0,
17 send/2,
18 recv_data/2,
19 controlling_process/2,
20 sockname/1,
21 peername/1,
22 setopts/2,
23 get_peer_certificate/1,
24 get_tls_last_message/1,
25 close/1]).
26
27 -export([get_sockmod/1]).
28
29 -ignore_xref([behaviour_info/1, close/1, controlling_process/2, peername/1,
30 send/2, setopts/2, sockname/1]).
31
32 -type tls_socket() :: any().
33 -type cert() :: {ok, Cert::any()} | {bad_cert, bitstring()} | no_peer_cert.
34
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %% behaviour definition
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 -callback tcp_to_tls(inet:socket(), Opts::list()) -> {ok, tls_socket()} | {error, any()}.
39
40 -callback send(tls_socket(), binary()) -> ok | {error , any()}.
41
42 -callback recv_data(tls_socket(), binary()) -> {ok, binary()} | {error, any()}.
43
44 -callback controlling_process(tls_socket(), pid()) -> ok | {error, any()}.
45
46 -callback sockname(tls_socket()) -> {ok, mongoose_transport:peer()} |
47 {error, any()}.
48
49 -callback peername(tls_socket()) -> {ok, mongoose_transport:peer()} |
50 {error, any()}.
51
52 -callback setopts(tls_socket(), Opts::list()) -> ok | {error, any()}.
53
54 -callback get_peer_certificate(tls_socket()) -> cert().
55
56 -callback close(tls_socket()) -> ok.
57
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59 %% socket type definition
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
62 -record(ejabberd_tls_socket, {tls_module :: module(),
63 tcp_socket :: inet:socket(),
64 tls_socket :: tls_socket(),
65 tls_opts :: list(),
66 has_cert :: boolean()
67 }).
68
69 -type socket() :: #ejabberd_tls_socket{}.
70
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %% APIs
73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74
75 -spec tcp_to_tls(inet:socket(), Opts::list()) -> {ok, socket()} | {error, any()}.
76 tcp_to_tls(TCPSocket, Opts) ->
77 1092 Module = proplists:get_value(tls_module, Opts, fast_tls),
78 1092 NewOpts1 = proplists:delete(tls_module, Opts),
79 1092 NewOpts2 = case proplists:get_value(ciphers, NewOpts1) of
80 916 undefined -> [{ciphers, default_ciphers()} | NewOpts1];
81 176 _ -> NewOpts1
82 end,
83 1092 case Module:tcp_to_tls(TCPSocket, NewOpts2) of
84 {ok, TLSSocket} ->
85 639 HasCert = has_peer_cert(NewOpts2),
86 639 {ok, #ejabberd_tls_socket{tls_module = Module,
87 tcp_socket = TCPSocket,
88 tls_socket = TLSSocket,
89 tls_opts = NewOpts2,
90 has_cert = HasCert}};
91 453 Error -> Error
92 end.
93
94 default_ciphers() ->
95 1080 "TLSv1.2:TLSv1.3".
96
97 -spec send(socket(), binary()) -> ok | {error, any()}.
98 662 send(#ejabberd_tls_socket{tls_module = M, tls_socket = S}, B) -> M:send(S, B).
99
100
101 -spec recv_data(socket(), binary()) -> {ok, binary()} | {error, any()}.
102 2006 recv_data(#ejabberd_tls_socket{tls_module = M, tls_socket = S}, B) -> M:recv_data(S, B).
103
104
105 -spec controlling_process(socket(), pid()) -> ok | {error, any()}.
106 controlling_process(#ejabberd_tls_socket{tls_module = M, tls_socket = S}, Pid) ->
107
:-(
M:controlling_process(S, Pid).
108
109
110 -spec sockname(tls_socket()) -> {ok, mongoose_transport:peer()} | {error, any()}.
111
:-(
sockname(#ejabberd_tls_socket{tls_module = M, tls_socket = S}) -> M:sockname(S).
112
113
114 -spec peername(tls_socket()) -> {ok, mongoose_transport:peer()} | {error, any()}.
115 1594 peername(#ejabberd_tls_socket{tls_module = M, tls_socket = S}) -> M:peername(S).
116
117
118 -spec setopts(socket(), Opts::list()) -> ok | {error, any()}.
119 1594 setopts(#ejabberd_tls_socket{tls_module = M, tls_socket = S}, Opts) -> M:setopts(S, Opts).
120
121
122 -spec get_peer_certificate(socket()) -> cert().
123 get_peer_certificate(#ejabberd_tls_socket{has_cert = false}) ->
124 29 no_peer_cert;
125 get_peer_certificate(#ejabberd_tls_socket{tls_module = just_tls, tls_socket = S}) ->
126 120 just_tls:get_peer_certificate(S);
127 get_peer_certificate(#ejabberd_tls_socket{tls_module = fast_tls, tls_socket = S,
128 tls_opts = TLSOpts}) ->
129 85 case {fast_tls:get_verify_result(S), fast_tls:get_peer_certificate(S)} of
130 64 {0, {ok, Cert}} -> {ok, Cert};
131 {Error, {ok, Cert}} ->
132 18 SSLOpts = proplists:get_value(ssl_options, TLSOpts, []),
133 18 maybe_allow_selfsigned(Error, Cert, SSLOpts);
134 3 {_, error} -> no_peer_cert
135 end.
136
137 -spec close(socket()) -> ok.
138 639 close(#ejabberd_tls_socket{tls_module = M, tls_socket = S}) -> M:close(S).
139
140 -spec get_sockmod(socket()) -> module().
141 99 get_sockmod(#ejabberd_tls_socket{tls_module = Module}) -> Module.
142
143 -spec get_tls_last_message(ejabberd_socket:socket()) -> {ok, binary()} | {error, term()}.
144 get_tls_last_message(#ejabberd_tls_socket{} = Socket) ->
145 5 case get_sockmod(Socket) of
146 fast_tls ->
147 5 fast_tls:get_tls_last_message(peer, Socket#ejabberd_tls_socket.tls_socket);
148 _ ->
149
:-(
{error, undefined}
150 end;
151 get_tls_last_message(_) ->
152
:-(
{error, undefined}.
153
154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155 %% local functions
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 has_peer_cert(Opts) ->
158 %% server always provides cert, client - only per request
159 639 case {lists:member(connect, Opts), lists:member(verify_none, Opts)} of
160 {false, true} -> %% we are tls server, and we haven't requested client's certificate
161 540 false;
162 _ ->
163 99 true
164 end.
165
166 %% 18 is OpenSSL's and fast_tls's error code for self-signed certs
167 maybe_allow_selfsigned(18 = Error, Cert, SSLOpts) ->
168
:-(
case lists:keyfind(verify_fun, 1, SSLOpts) of
169 {verify_fun, {selfsigned_peer, _}} ->
170
:-(
{ok, Cert};
171 _ ->
172
:-(
cert_verification_error(Error, Cert)
173 end;
174 maybe_allow_selfsigned(Error, Cert, _SSLOpts) ->
175 18 cert_verification_error(Error, Cert).
176
177 cert_verification_error(Error, Cert) ->
178 18 {bad_cert, fast_tls:get_cert_verify_string(Error, Cert)}.
Line Hits Source