@@ -50,8 +50,7 @@ tcp_to_tls(TCPSocket, Options) ->
50
50
{Ref , SSLOpts } = format_opts_with_ref (Options , false ),
51
51
{Ref , ssl :connect (TCPSocket , SSLOpts )};
52
52
#{} ->
53
- FailIfNoPeerCert = fail_if_no_peer_cert_opt (Options ),
54
- {Ref , SSLOpts } = format_opts_with_ref (Options , FailIfNoPeerCert ),
53
+ {Ref , SSLOpts } = format_opts_with_ref (Options , fail_if_no_peer_cert ),
55
54
{Ref , ssl :handshake (TCPSocket , SSLOpts , 5000 )}
56
55
end ,
57
56
VerifyResults = receive_verify_results (Ref1 ),
@@ -61,42 +60,36 @@ tcp_to_tls(TCPSocket, Options) ->
61
60
_ -> Ret
62
61
end .
63
62
64
- % % -callback send(tls_socket(), binary()) -> ok | {error, any()}.
63
+ - spec send (tls_socket (), binary ()) -> ok | {error , any ()}.
65
64
send (# tls_socket {ssl_socket = SSLSocket }, Packet ) -> ssl :send (SSLSocket , Packet ).
66
65
67
- % % -callback recv_data(tls_socket(), binary()) -> {ok, binary()} | {error, any()}.
68
- recv_data (_ , <<" " >>) ->
66
+ - spec recv_data (tls_socket (), binary ()) -> {ok , binary ()} | {error , any ()}.
67
+ recv_data (_ , <<>>) ->
69
68
% % such call is required for fast_tls to accomplish
70
69
% % tls handshake, for just_tls we can ignore it
71
- {ok , <<" " >>};
70
+ {ok , <<>>};
72
71
recv_data (# tls_socket {ssl_socket = SSLSocket }, Data1 ) ->
73
72
case ssl :recv (SSLSocket , 0 , 0 ) of
74
73
{ok , Data2 } -> {ok , <<Data1 /binary , Data2 /binary >>};
75
74
_ -> {ok , Data1 }
76
75
end .
77
76
78
- % % -callback controlling_process(tls_socket(), pid()) -> ok | {error, any()}.
77
+ - spec controlling_process (tls_socket (), pid ()) -> ok | {error , any ()}.
79
78
controlling_process (# tls_socket {ssl_socket = SSLSocket }, Pid ) ->
80
79
ssl :controlling_process (SSLSocket , Pid ).
81
80
82
-
83
- % % -callback sockname(tls_socket()) -> {ok, {inet:ip_address(), inet:port_number()}} |
84
- % % {error, any()}.
81
+ -spec sockname (tls_socket ()) -> {ok , {inet :ip_address (), inet :port_number ()}} | {error , any ()}.
85
82
sockname (# tls_socket {ssl_socket = SSLSocket }) -> ssl :sockname (SSLSocket ).
86
83
87
-
88
- % % -callback peername(tls_socket()) -> {ok, {inet:ip_address(), inet:port_number()}} |
89
- % % {error, any()}.
84
+ -spec peername (tls_socket ()) ->
85
+ {ok , {inet :ip_address (), inet :port_number ()}} | {error , any ()}.
90
86
peername (# tls_socket {ssl_socket = SSLSocket }) -> ssl :peername (SSLSocket ).
91
87
92
-
93
- % % -callback setopts(tls_socket(), Opts::list()) -> ok | {error, any()}.
88
+ -spec setopts (tls_socket (), Opts :: list ()) -> ok | {error , any ()}.
94
89
setopts (# tls_socket {ssl_socket = SSLSocket }, Opts ) -> ssl :setopts (SSLSocket , Opts ).
95
90
96
-
97
- % % -callback get_peer_certificate(tls_socket()) -> {ok, Cert::any()} |
98
- % % {bad_cert, bitstring()} |
99
- % % no_peer_cert.
91
+ -spec get_peer_certificate (tls_socket ()) ->
92
+ {ok , Cert :: any ()} | {bad_cert , bitstring ()} | no_peer_cert .
100
93
get_peer_certificate (# tls_socket {verify_results = [], ssl_socket = SSLSocket }) ->
101
94
case ssl :peercert (SSLSocket ) of
102
95
{ok , PeerCert } ->
@@ -107,66 +100,74 @@ get_peer_certificate(#tls_socket{verify_results = [], ssl_socket = SSLSocket}) -
107
100
get_peer_certificate (# tls_socket {verify_results = [Err | _ ]}) ->
108
101
{bad_cert , error_to_list (Err )}.
109
102
110
- % % -callback close(tls_socket()) -> ok.
111
- close (# tls_socket {ssl_socket = SSLSocket }) -> ssl :close (SSLSocket ).
103
+ -spec close (tls_socket ()) -> ok .
104
+ close (# tls_socket {ssl_socket = SSLSocket }) ->
105
+ ssl :close (SSLSocket ).
112
106
113
107
% % @doc Prepare SSL options for direct use of ssl:connect/2 (client side)
114
108
% % The `disconnect_on_failure' option is expected to be unset or true
115
109
-spec make_ssl_opts (mongoose_tls :options ()) -> [ssl :tls_option ()].
116
- make_ssl_opts (Opts ) ->
117
- { dummy_ref , SSLOpts } = format_opts_with_ref (Opts , false ),
118
- SSLOpts .
110
+ make_ssl_opts (#{ verify_mode : = Mode } = Opts ) ->
111
+ SslOpts = format_opts (Opts , false ),
112
+ [{ verify_fun , verify_fun ( Mode )} | SslOpts ] .
119
113
120
114
% % @doc Prepare SSL options for direct use of ssl:handshake/2 (server side)
121
115
% % The `disconnect_on_failure' option is expected to be unset or true
122
116
-spec make_cowboy_ssl_opts (mongoose_tls :options ()) -> [ssl :tls_option ()].
123
- make_cowboy_ssl_opts (Opts ) ->
124
- FailIfNoPeerCert = fail_if_no_peer_cert_opt (Opts ),
125
- {dummy_ref , SSLOpts } = format_opts_with_ref (Opts , FailIfNoPeerCert ),
126
- SSLOpts .
117
+ make_cowboy_ssl_opts (#{verify_mode := Mode } = Opts ) ->
118
+ SslOpts = format_opts (Opts , fail_if_no_peer_cert ),
119
+ [{verify_fun , verify_fun (Mode )} | SslOpts ].
127
120
128
121
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129
122
% % local functions
130
123
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131
124
132
125
format_opts_with_ref (Opts , FailIfNoPeerCert ) ->
133
- Verify = verify_opt (Opts ),
126
+ SslOpts0 = format_opts (Opts , FailIfNoPeerCert ),
134
127
{Ref , VerifyFun } = verify_fun_opt (Opts ),
135
- SNIOpts = sni_opts (Opts ),
136
- SSLOpts = maps :to_list (maps :with (ssl_option_keys (), Opts )),
137
- {Ref , [{fail_if_no_peer_cert , FailIfNoPeerCert }, {verify , Verify }, {verify_fun , VerifyFun }] ++
138
- SNIOpts ++ SSLOpts }.
128
+ SslOpts = [{verify_fun , VerifyFun } | SslOpts0 ],
129
+ {Ref , SslOpts }.
130
+
131
+ format_opts (Opts , FailIfNoPeerCert ) ->
132
+ SslOpts0 = maps :to_list (maps :with (ssl_option_keys (), Opts )),
133
+ SslOpts1 = sni_opts (SslOpts0 , Opts ),
134
+ SslOpts2 = verify_opts (SslOpts1 , Opts ),
135
+ SslOpts3 = hibernate_opts (SslOpts2 , Opts ),
136
+ fail_if_no_peer_cert_opts (SslOpts3 , Opts , FailIfNoPeerCert ).
139
137
140
138
ssl_option_keys () ->
141
139
[certfile , cacertfile , ciphers , keyfile , password , versions , dhfile ].
142
140
143
- sni_opts (#{server_name_indication := SNIOpts }) ->
144
- process_sni_opts (SNIOpts );
145
- sni_opts (#{}) ->
146
- [].
147
-
148
- process_sni_opts (#{enabled := false }) ->
149
- [{server_name_indication , disable }];
150
- process_sni_opts (#{enabled := true , host := SNIHost , protocol := https }) ->
151
- [{server_name_indication , SNIHost },
152
- {customize_hostname_check , [{match_fun , public_key :pkix_verify_hostname_match_fun (https )}]}];
153
- process_sni_opts (#{enabled := true , host := SNIHost , protocol := default }) ->
154
- [{server_name_indication , SNIHost }];
155
- process_sni_opts (#{enabled := true }) ->
156
- [].
157
-
158
- error_to_list (_Error ) ->
159
- % TODO: implement later if needed
160
- " verify_fun failed" .
161
-
162
- verify_opt (#{verify_mode := none }) -> verify_none ;
163
- verify_opt (#{}) -> verify_peer .
164
-
165
141
% % accept empty peer certificate if explicitly requested not to fail
166
- fail_if_no_peer_cert_opt (#{disconnect_on_failure := false }) -> false ;
167
- fail_if_no_peer_cert_opt (#{verify_mode := peer }) -> true ;
168
- fail_if_no_peer_cert_opt (#{verify_mode := selfsigned_peer }) -> true ;
169
- fail_if_no_peer_cert_opt (#{}) -> false .
142
+ fail_if_no_peer_cert_opts (Opts , #{}, false ) ->
143
+ [{fail_if_no_peer_cert , false } | Opts ];
144
+ fail_if_no_peer_cert_opts (Opts , #{disconnect_on_failure := false }, _ ) ->
145
+ [{fail_if_no_peer_cert , false } | Opts ];
146
+ fail_if_no_peer_cert_opts (Opts , #{verify_mode := Mode }, _ )
147
+ when Mode =:= peer ; Mode =:= selfsigned_peer ->
148
+ [{fail_if_no_peer_cert , true } | Opts ];
149
+ fail_if_no_peer_cert_opts (Opts , #{}, _ ) ->
150
+ [{fail_if_no_peer_cert , false } | Opts ].
151
+
152
+ hibernate_opts (Opts , #{hibernate_after := Timeout }) ->
153
+ [{hibernate_after , Timeout } | Opts ];
154
+ hibernate_opts (Opts , #{}) ->
155
+ Opts .
156
+
157
+ verify_opts (Opts , #{verify_mode := none }) ->
158
+ [{verify , verify_none } | Opts ];
159
+ verify_opts (Opts , #{}) ->
160
+ [{verify , verify_peer } | Opts ].
161
+
162
+ sni_opts (Opts , #{server_name_indication := #{enabled := false }}) ->
163
+ [{server_name_indication , disable } | Opts ];
164
+ sni_opts (Opts , #{server_name_indication := #{enabled := true , host := SNIHost , protocol := default }}) ->
165
+ [{server_name_indication , SNIHost } | Opts ];
166
+ sni_opts (Opts , #{server_name_indication := #{enabled := true , host := SNIHost , protocol := https }}) ->
167
+ [{server_name_indication , SNIHost },
168
+ {customize_hostname_check , [{match_fun , public_key :pkix_verify_hostname_match_fun (https )}]} | Opts ];
169
+ sni_opts (Opts , #{}) ->
170
+ Opts .
170
171
171
172
% % This function translates TLS options to the function
172
173
% % which will later be used when TCP socket is upgraded to TLS
@@ -226,8 +227,10 @@ verify_fun(none) ->
226
227
send_verification_failure (Pid , Ref , Reason ) ->
227
228
Pid ! {cert_verification_failure , Ref , Reason }.
228
229
229
- receive_verify_results (dummy_ref ) -> [];
230
- receive_verify_results (Ref ) -> receive_verify_results (Ref , []).
230
+ receive_verify_results (dummy_ref ) ->
231
+ [];
232
+ receive_verify_results (Ref ) ->
233
+ receive_verify_results (Ref , []).
231
234
232
235
receive_verify_results (Ref , Acc ) ->
233
236
receive
@@ -236,3 +239,7 @@ receive_verify_results(Ref, Acc) ->
236
239
after 0 ->
237
240
lists :reverse (Acc )
238
241
end .
242
+
243
+ error_to_list (_Error ) ->
244
+ % TODO: implement later if needed
245
+ " verify_fun failed" .
0 commit comments