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