Skip to content

Instantly share code, notes, and snippets.

@weiss
Last active August 29, 2015 14:00
Show Gist options
  • Save weiss/11379060 to your computer and use it in GitHub Desktop.
Save weiss/11379060 to your computer and use it in GitHub Desktop.
Shortened version of the patch submitted as ejabberd pull request #185
diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl
index 057c60a..eb98943 100644
--- a/src/ejabberd_s2s.erl
+++ b/src/ejabberd_s2s.erl
@@ -207,6 +216,31 @@ try_register(FromTo) ->
dirty_get_connections() ->
mnesia:dirty_all_keys(s2s).
+check_peer_certificate(SockMod, Sock, Peer) ->
+ case SockMod:get_peer_certificate(Sock) of
+ {ok, Cert} ->
+ case SockMod:get_verify_result(Sock) of
+ 0 ->
+ case idna:domain_utf8_to_ascii(Peer) of
+ false ->
+ {error, <<"Cannot decode remote server name">>};
+ AsciiPeer ->
+ case
+ lists:any(fun(D) -> match_domain(AsciiPeer, D) end,
+ get_cert_domains(Cert)) of
+ true ->
+ {ok, <<"Verification successful">>};
+ false ->
+ {error, <<"Certificate host name mismatch">>}
+ end
+ end;
+ VerifyRes ->
+ {error, p1_tls:get_cert_verify_string(VerifyRes, Cert)}
+ end;
+ error ->
+ {error, <<"Cannot get peer certificate">>}
+ end.
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index 3eb0b71..c490704 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -227,45 +218,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs},
Auth = if StateData#state.tls_enabled ->
case jlib:nameprep(xml:get_attr_s(<<"from">>, Attrs)) of
From when From /= <<"">>, From /= error ->
- case
- (StateData#state.sockmod):get_peer_certificate(StateData#state.socket)
- of
- {ok, Cert} ->
- case
- (StateData#state.sockmod):get_verify_result(StateData#state.socket)
- of
- 0 ->
- case
- idna:domain_utf8_to_ascii(From)
- of
- false ->
- {error, From,
- <<"Cannot decode 'from' attribute">>};
- PCAuthDomain ->
- case
- lists:any(fun (D) ->
- match_domain(PCAuthDomain,
- D)
- end,
- get_cert_domains(Cert))
- of
- true ->
- {ok, From,
- <<"Success">>};
- false ->
- {error, From,
- <<"Certificate host name mismatch">>}
- end
- end;
- CertVerifyRes ->
- {error, From,
- p1_tls:get_cert_verify_string(CertVerifyRes,
- Cert)}
- end;
- error ->
- {error, From,
- <<"Cannot get peer certificate">>}
- end;
+ {Result, Message} =
+ ejabberd_s2s:check_peer_certificate(StateData#state.sockmod,
+ StateData#state.socket,
+ From),
+ {Result, From, Message};
_ ->
{error, <<"(unknown)">>,
<<"Got no valid 'from' attribute">>}
diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
index a0a8363..9977fcd 100644
--- a/src/ejabberd_s2s_out.erl
+++ b/src/ejabberd_s2s_out.erl
@@ -345,35 +345,57 @@ open_socket2(Type, Addr, Port) ->
wait_for_stream({xmlstreamstart, _Name, Attrs},
StateData) ->
+ {CertCheckRes, CertCheckMsg, NewStateData} =
+ if StateData#state.tls_certverify, StateData#state.tls_enabled ->
+ {Res, Msg} =
+ ejabberd_s2s:check_peer_certificate(ejabberd_socket,
+ StateData#state.socket,
+ StateData#state.server),
+ ?DEBUG("Certificate verification result for ~s: ~s",
+ [StateData#state.server, Msg]),
+ {Res, Msg, StateData#state{tls_certverify = false}};
+ true ->
+ {no_verify, <<"Not verified">>, StateData}
+ end,
case {xml:get_attr_s(<<"xmlns">>, Attrs),
xml:get_attr_s(<<"xmlns:db">>, Attrs),
xml:get_attr_s(<<"version">>, Attrs) == <<"1.0">>}
of
+ _ when CertCheckRes == error ->
+ send_text(NewStateData,
+ <<(xml:element_to_binary(?SERRT_POLICY_VIOLATION(<<"en">>,
+ CertCheckMsg)))/binary,
+ (?STREAM_TRAILER)/binary>>),
+ ?INFO_MSG("Closing s2s connection: ~s -> ~s (~s)",
+ [NewStateData#state.myname,
+ NewStateData#state.server,
+ CertCheckMsg]),
+ {stop, normal, NewStateData};
{<<"jabber:server">>, <<"jabber:server:dialback">>,
false} ->
send_db_request(StateData);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment