diff options
author | Stu Tomlinson <stu@nosnilmot.com> | 2021-02-15 13:29:58 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-15 14:29:58 +0100 |
commit | 1f194e417d69ab0db878834cdf4c25aa00c4b044 (patch) | |
tree | 55c063bc2bcf69af500197cd969b75dbfc7a8486 /src/eldap.erl | |
parent | According to fast_tls, only atom and binary may accompany error tuple (diff) |
fix eldap certificate verification (#3528)
Reported in #3527. Add hostname matching function, and specify SNI
Also, OTP 23 dropped backwards compatibility for 0, 1, 2 values for verify, so
replace with combination of verify_none/verify_peer and fail_if_no_peer_cert
as appropriate
Diffstat (limited to 'src/eldap.erl')
-rw-r--r-- | src/eldap.erl | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/src/eldap.erl b/src/eldap.erl index 34c20228..3a9d8974 100644 --- a/src/eldap.erl +++ b/src/eldap.erl @@ -132,7 +132,8 @@ tls_options = [] :: [{certfile, string()} | {cacertfile, string()} | {depth, non_neg_integer()} | - {verify, non_neg_integer()}], + {verify, non_neg_integer()} | + {fail_if_no_peer_cert, boolean()}], fd :: gen_tcp:socket() | undefined, rootdn = <<"">> :: binary(), passwd = <<"">> :: binary(), @@ -604,9 +605,9 @@ init([Hosts, Port, Rootdn, Passwd, Opts]) -> []), CertOpts; Verify == soft -> - [{verify, 1}] ++ CertOpts ++ CacertOpts ++ DepthOpts; + [{verify, verify_peer}, {fail_if_no_peer_cert, false}] ++ CertOpts ++ CacertOpts ++ DepthOpts; Verify == hard -> - [{verify, 2}] ++ CertOpts ++ CacertOpts ++ DepthOpts; + [{verify, verify_peer}, {fail_if_no_peer_cert, true}] ++ CertOpts ++ CacertOpts ++ DepthOpts; true -> [] end, {ok, connecting, @@ -1035,22 +1036,40 @@ polish([H | T], Res, polish(T, Res, [H | Ref]); polish([], Res, Ref) -> {Res, Ref}. + +-ifdef(NO_CUSTOMIZE_HOSTNAME_CHECK). +check_hostname_opt(TLSOpts) -> + TLSOpts. +-else. +check_hostname_opt(TLSOpts) -> + MatchFun = public_key:pkix_verify_hostname_match_fun(https), + [{customize_hostname_check, [{match_fun, MatchFun}]} | TLSOpts]. +-endif. + +host_tls_options(Host, TLSOpts) -> + case proplists:get_value(verify, TLSOpts) of + verify_peer -> + check_hostname_opt([{server_name_indication, Host} | TLSOpts]); + _ -> + TLSOpts + end. + %%----------------------------------------------------------------------- %% Connect to next server in list and attempt to bind to it. %%----------------------------------------------------------------------- connect_bind(S) -> Host = next_host(S#eldap.host, S#eldap.hosts), + HostS = binary_to_list(Host), Opts = if S#eldap.tls == tls -> [{packet, asn1}, {active, true}, {keepalive, true}, binary - | S#eldap.tls_options]; + | host_tls_options(HostS, S#eldap.tls_options)]; true -> [{packet, asn1}, {active, true}, {keepalive, true}, {send_timeout, ?SEND_TIMEOUT}, binary] end, ?DEBUG("Connecting to LDAP server at ~ts:~p with options ~p", [Host, S#eldap.port, Opts]), - HostS = binary_to_list(Host), SockMod = case S#eldap.tls of tls -> ssl; _ -> gen_tcp |