]> granicus.if.org Git - ejabberd/commitdiff
Best Practices for Use of SASL EXTERNAL with Certificates (XEP-0178) support
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 7 Mar 2017 11:20:50 +0000 (14:20 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 7 Mar 2017 11:20:50 +0000 (14:20 +0300)
It is now possible for client connections to login using PKIX certificates.
This is disabled by default, to enable it:

- either set 'tls_verify: true' and 'cafile: /path/to/CAfile'
  in the corresponding listener's section
- or set equivalent per-vhost options 'c2s_tls_verify' and 'c2s_cafile'

rebar.config
src/ejabberd_socket.erl
src/xmpp_stream_pkix.erl
test/ejabberd_SUITE.erl
test/ejabberd_SUITE_data/cert.pem
test/ejabberd_SUITE_data/ejabberd.yml
test/ejabberd_SUITE_data/gencerts.sh
test/ejabberd_SUITE_data/openssl.cnf
test/ejabberd_SUITE_data/self-signed-cert.pem
test/suite.erl

index c04b075b7baabbce46986331c73005d2bf2b3322..f3859195580119a88c150e9f297b8c395e65e06d 100644 (file)
@@ -21,7 +21,7 @@
 {deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
         {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.7"}}},
         {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.6"}}},
-        {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.10"}}},
+        {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", "afdd07811e0e6eff444c035ffeb2aa9efb4dbe6d"}},
         {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.7"}}},
         {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.21"}}},
         {xmpp, ".*", {git, "https://github.com/processone/xmpp", "4aaed37a16fc21be505553aabf9f47a48b8af027"}},
index c690888a9a5bc688b8d0eb6d639a413cd49f3b90..c5c56cd58c569ebd3a83b23f994d0fdd659435f0 100644 (file)
@@ -45,7 +45,7 @@
         monitor/1,
         get_sockmod/1,
         get_transport/1,
-        get_peer_certificate/1,
+        get_peer_certificate/2,
         get_verify_result/1,
         close/1,
         pp/1,
@@ -263,8 +263,8 @@ get_transport(#socket_state{sockmod = SockMod,
        ejabberd_http_ws -> websocket
     end.
 
-get_peer_certificate(SocketData) ->
-    fast_tls:get_peer_certificate(SocketData#socket_state.socket).
+get_peer_certificate(SocketData, Type) ->
+    fast_tls:get_peer_certificate(SocketData#socket_state.socket, Type).
 
 get_verify_result(SocketData) ->
     fast_tls:get_verify_result(SocketData#socket_state.socket).
index d556510f643915a8185eaa79a0b79cf3d7d0d8bf..0dfcecf784daae962c1118b1b7563932cecc82e5 100644 (file)
 -module(xmpp_stream_pkix).
 
 %% API
--export([authenticate/1, authenticate/2, format_error/1]).
+-compile(export_all).
+-export([authenticate/1, authenticate/2, get_cert_domains/1, format_error/1]).
 
 -include("xmpp.hrl").
 -include_lib("public_key/include/public_key.hrl").
 -include("XmppAddr.hrl").
 
+-type cert() :: #'OTPCertificate'{}.
+
 %%%===================================================================
 %%% API
 %%%===================================================================
@@ -41,130 +44,176 @@ authenticate(State) ->
 authenticate(#{xmlns := ?NS_SERVER, sockmod := SockMod,
               socket := Socket} = State, Authzid) ->
     Peer = maps:get(remote_server, State, Authzid),
-    case SockMod:get_peer_certificate(Socket) of
+    case verify_cert(SockMod, Socket) of
        {ok, Cert} ->
-           case SockMod:get_verify_result(Socket) of
-               0 ->
-                   case ejabberd_idna:domain_utf8_to_ascii(Peer) of
+           case ejabberd_idna:domain_utf8_to_ascii(Peer) of
+               false ->
+                   {error, idna_failed, Peer};
+               AsciiPeer ->
+                   case lists:any(
+                          fun(D) -> match_domain(AsciiPeer, D) end,
+                          get_cert_domains(Cert)) of
+                       true ->
+                           {ok, Peer};
                        false ->
-                           {error, idna_failed, Peer};
-                       AsciiPeer ->
-                           case lists:any(
-                                  fun(D) -> match_domain(AsciiPeer, D) end,
-                                  get_cert_domains(Cert)) of
-                               true ->
-                                   {ok, Peer};
-                               false ->
-                                   {error, hostname_mismatch, Peer}
-                           end
-                   end;
-               VerifyRes ->
-                   %% TODO: return atomic errors
-                   %% This should be improved in fast_tls
-                   Reason = fast_tls:get_cert_verify_string(VerifyRes, Cert),
-                   {error, erlang:binary_to_atom(Reason, utf8), Peer}
+                           {error, hostname_mismatch, Peer}
+                   end
            end;
-       {error, _Reason} ->
-           {error, get_cert_failed, Peer};
-       error ->
-           {error, get_cert_failed, Peer}
+       {error, Reason} ->
+           {error, Reason, Peer}
     end;
-authenticate(_State, _Authzid) ->
-    %% TODO: client PKIX authentication
-    {error, client_not_supported, <<"">>}.
+authenticate(#{xmlns := ?NS_CLIENT, sockmod := SockMod,
+              socket := Socket, lserver := LServer}, Authzid) ->
+    JID = try jid:decode(Authzid)
+         catch _:{bad_jid, <<>>} -> jid:make(LServer);
+               _:{bad_jid, _} -> {error, invalid_authzid, Authzid}
+         end,
+    case JID of
+       #jid{user = User} ->
+           case verify_cert(SockMod, Socket) of
+               {ok, Cert} ->
+                   JIDs = get_xmpp_addrs(Cert),
+                   get_username(JID, JIDs, LServer);
+               {error, Reason} ->
+                   {error, Reason, User}
+           end;
+       Err ->
+           Err
+    end.
 
 format_error(idna_failed) ->
     {'bad-protocol', <<"Remote domain is not an IDN hostname">>};
 format_error(hostname_mismatch) ->
     {'not-authorized', <<"Certificate host name mismatch">>};
+format_error(jid_mismatch) ->
+    {'not-authorized', <<"Certifcate JID mismatch">>};
 format_error(get_cert_failed) ->
     {'bad-protocol', <<"Failed to get peer certificate">>};
-format_error(client_not_supported) ->
-    {'invalid-mechanism', <<"Client certificate verification is not supported">>};
+format_error(invalid_authzid) ->
+    {'invalid-authzid', <<"Malformed JID">>};
 format_error(Other) ->
     {'not-authorized', erlang:atom_to_binary(Other, utf8)}.
 
+-spec get_cert_domains(cert()) -> [binary()].
+get_cert_domains(Cert) ->
+    TBSCert = Cert#'OTPCertificate'.tbsCertificate,
+    {rdnSequence, Subject} = TBSCert#'OTPTBSCertificate'.subject,
+    Extensions = TBSCert#'OTPTBSCertificate'.extensions,
+    get_domain_from_subject(lists:flatten(Subject)) ++
+       get_domains_from_san(Extensions).
+
 %%%===================================================================
 %%% Internal functions
 %%%===================================================================
-get_cert_domains(Cert) ->
-    TBSCert = Cert#'Certificate'.tbsCertificate,
-    Subject = case TBSCert#'TBSCertificate'.subject of
-                 {rdnSequence, Subj} -> lists:flatten(Subj);
-                 _ -> []
-             end,
-    Extensions = case TBSCert#'TBSCertificate'.extensions of
-                    Exts when is_list(Exts) -> Exts;
-                    _ -> []
-                end,
-    lists:flatmap(
-      fun(#'AttributeTypeAndValue'{type = ?'id-at-commonName',value = Val}) ->
-             case 'OTP-PUB-KEY':decode('X520CommonName', Val) of
-                 {ok, {_, D1}} ->
-                     D = if is_binary(D1) -> D1;
-                            is_list(D1) -> list_to_binary(D1);
-                            true -> error
-                         end,
-                     if D /= error ->
-                             try jid:decode(D) of
-                                 #jid{luser = <<"">>, lserver = LD,
-                                      lresource = <<"">>} ->
-                                     [LD];
-                                 _ -> []
-                             catch _:{bad_jid, _} ->
-                                     []
+-spec verify_cert(module(), fast_tls:tls_socket()) -> {ok, cert()} | {error, atom()}.
+verify_cert(SockMod, Socket) ->
+    case SockMod:get_peer_certificate(Socket, otp) of
+       {ok, Cert} ->
+           case SockMod:get_verify_result(Socket) of
+               0 ->
+                   {ok, Cert};
+               VerifyRes ->
+                   %% TODO: return atomic errors
+                   %% This should be improved in fast_tls
+                   Reason = fast_tls:get_cert_verify_string(VerifyRes, Cert),
+                   {error, erlang:binary_to_atom(Reason, utf8)}
+           end;
+       {error, _Reason} ->
+           {error, get_cert_failed};
+       error ->
+           {error, get_cert_failed}
+    end.
+
+-spec get_domain_from_subject([#'AttributeTypeAndValue'{}]) -> [binary()].
+get_domain_from_subject(AttrVals) ->
+    case lists:keyfind(?'id-at-commonName',
+                      #'AttributeTypeAndValue'.type,
+                      AttrVals) of
+       #'AttributeTypeAndValue'{value = {_, S}} ->
+           try jid:decode(iolist_to_binary(S)) of
+               #jid{luser = <<"">>, lresource = <<"">>, lserver = Domain} ->
+                   [Domain];
+               _ ->
+                   []
+           catch _:{bad_jid, _} ->
+                   []
+           end;
+       _ ->
+           []
+    end.
+
+-spec get_domains_from_san([#'Extension'{}] | asn1_NOVALUE) -> [binary()].
+get_domains_from_san(Extensions) when is_list(Extensions) ->
+    case lists:keyfind(?'id-ce-subjectAltName',
+                      #'Extension'.extnID,
+                      Extensions) of
+       #'Extension'{extnValue = Vals} ->
+           lists:flatmap(
+             fun({dNSName, S}) ->
+                     [iolist_to_binary(S)];
+                ({otherName, AnotherName}) ->
+                     case decode_xmpp_addr(AnotherName) of
+                         {ok, #jid{luser = <<"">>,
+                                   lresource = <<"">>,
+                                   lserver = Domain}} ->
+                             case ejabberd_idna:domain_utf8_to_ascii(Domain) of
+                                 false ->
+                                     [];
+                                 ASCIIDomain ->
+                                     [ASCIIDomain]
                              end;
-                        true -> []
+                         _ ->
+                             []
                      end;
-                 _ -> []
-             end;
-        (_) -> []
-      end, Subject) ++
-       lists:flatmap(
-         fun(#'Extension'{extnID = ?'id-ce-subjectAltName',
-                          extnValue = Val}) ->
-                 BVal = if is_list(Val) -> list_to_binary(Val);
-                           true -> Val
-                        end,
-                 case 'OTP-PUB-KEY':decode('SubjectAltName', BVal) of
-                     {ok, SANs} ->
-                         lists:flatmap(
-                           fun({otherName, #'AnotherName'{'type-id' = ?'id-on-xmppAddr',
-                                                          value = XmppAddr}}) ->
-                                   case 'XmppAddr':decode('XmppAddr', XmppAddr) of
-                                       {ok, D} when is_binary(D) ->
-                                           try jid:decode(D) of
-                                               #jid{luser = <<"">>,
-                                                    lserver = LD,
-                                                    lresource = <<"">>} ->
-                                                   case ejabberd_idna:domain_utf8_to_ascii(LD) of
-                                                       false ->
-                                                           [];
-                                                       PCLD ->
-                                                           [PCLD]
-                                                   end;
-                                               _ -> []
-                                           catch _:{bad_jid, _} ->
-                                                   []
-                                           end;
-                                       _ -> []
-                                   end;
-                              ({dNSName, D}) when is_list(D) ->
-                                   try jid:decode(list_to_binary(D)) of
-                                       #jid{luser = <<"">>,
-                                            lserver = LD,
-                                            lresource = <<"">>} ->
-                                           [LD];
-                                       _ -> []
-                                   catch _:{bad_jid, _} ->
-                                           []
-                                   end;
-                              (_) -> []
-                           end, SANs);
-                     _ -> []
-                 end;
-            (_) -> []
-         end, Extensions).
+                (_) ->
+                     []
+             end, Vals);
+       _ ->
+           []
+    end;
+get_domains_from_san(_) ->
+    [].
+
+-spec decode_xmpp_addr(#'AnotherName'{}) -> {ok, jid()} | error.
+decode_xmpp_addr(#'AnotherName'{'type-id' = ?'id-on-xmppAddr',
+                               value = XmppAddr}) ->
+    try 'XmppAddr':decode('XmppAddr', XmppAddr) of
+       {ok, JIDStr} ->
+           try {ok, jid:decode(iolist_to_binary(JIDStr))}
+           catch _:{bad_jid, _} -> error
+           end;
+       _ ->
+           error
+    catch _:_ ->
+           error
+    end;
+decode_xmpp_addr(_) ->
+    error.
+
+-spec get_xmpp_addrs(cert()) -> [jid()].
+get_xmpp_addrs(Cert) ->
+    TBSCert = Cert#'OTPCertificate'.tbsCertificate,
+    case TBSCert#'OTPTBSCertificate'.extensions of
+       Extensions when is_list(Extensions) ->
+           case lists:keyfind(?'id-ce-subjectAltName',
+                              #'Extension'.extnID,
+                              Extensions) of
+               #'Extension'{extnValue = Vals} ->
+                   lists:flatmap(
+                     fun({otherName, AnotherName}) ->
+                             case decode_xmpp_addr(AnotherName) of
+                                 {ok, JID} -> [JID];
+                                 _ -> []
+                             end;
+                        (_) ->
+                             []
+                     end, Vals);
+               _ ->
+                   []
+           end;
+       _ ->
+           []
+    end.
 
 match_domain(Domain, Domain) -> true;
 match_domain(Domain, Pattern) ->
@@ -191,3 +240,33 @@ match_labels([DL | DLabels], [PL | PLabels]) ->
          end;
       false -> false
     end.
+
+-spec get_username(jid(), [jid()], binary()) ->
+                         {ok, binary()} | {error, jid_mismatch, binary()}.
+get_username(#jid{user = User, lserver = LS}, _, LServer) when LS /= LServer ->
+    %% The user provided JID from different domain
+    {error, jid_mismatch, User};
+get_username(#jid{user = <<>>}, [#jid{user = U, lserver = LS}], LServer)
+  when U /= <<>> andalso LS == LServer ->
+    %% The user didn't provide JID or username, and there is only
+    %% one 'non-global' JID matching current domain
+    {ok, U};
+get_username(#jid{user = User, luser = LUser}, JIDs, LServer) when User /= <<>> ->
+    %% The user provided username
+    lists:foldl(
+      fun(_, {ok, _} = OK) ->
+             OK;
+        (#jid{user = <<>>, lserver = LS}, _) when LS == LServer ->
+             %% Found "global" JID in the certficate
+             %% (i.e. in the form of 'domain.com')
+             %% within current domain, so we force matching
+             {ok, User};
+        (#jid{luser = LU, lserver = LS}, _) when LU == LUser, LS == LServer ->
+             %% Found exact JID matching
+             {ok, User};
+        (_, Err) ->
+             Err
+      end, {error, jid_mismatch, User}, JIDs);
+get_username(#jid{user = User}, _, _) ->
+    %% Nothing from above is true
+    {error, jid_mismatch, User}.
index 175a6e69a374262ccb233e6aff0e77165819b895..c15fa52b8fc96bdc723bcd6516c6ff6bfc25e20b 100644 (file)
@@ -32,7 +32,8 @@
                muc_room_jid/1, my_muc_jid/1, peer_muc_jid/1,
                mix_jid/1, mix_room_jid/1, get_features/2, recv_iq/1,
                re_register/1, is_feature_advertised/2, subscribe_to_events/1,
-                is_feature_advertised/3, set_opt/3, auth_SASL/2,
+                is_feature_advertised/3, set_opt/3,
+               auth_SASL/2, auth_SASL/3, auth_SASL/4,
                 wait_for_master/1, wait_for_slave/1, flush/1,
                 make_iq_result/1, start_event_relay/0, alt_room_jid/1,
                 stop_event_relay/1, put_event/2, get_event/1,
@@ -301,6 +302,8 @@ init_per_testcase(TestCase, OrigConfig) ->
             connect(Config);
         "auth_plain" ->
             connect(Config);
+       "auth_external" ++ _ ->
+           connect(Config);
        "unauthenticated_" ++ _ ->
            connect(Config);
         "test_bind" ->
@@ -371,6 +374,13 @@ no_db_tests() ->
        s2s_optional,
        s2s_required,
        s2s_required_trusted]},
+     auth_external,
+     auth_external_no_jid,
+     auth_external_no_user,
+     auth_external_malformed_jid,
+     auth_external_wrong_jid,
+     auth_external_wrong_server,
+     auth_external_invalid_cert,
      sm_tests:single_cases(),
      sm_tests:master_slave_cases(),
      muc_tests:single_cases(),
@@ -792,6 +802,39 @@ auth_plain(Config) ->
             {skipped, 'PLAIN_not_available'}
     end.
 
+auth_external(Config0) ->
+    Config = connect(starttls(Config0)),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config)).
+
+auth_external_no_jid(Config0) ->
+    Config = connect(starttls(Config0)),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config, _ShoudFail = false,
+                        {<<"">>, <<"">>, <<"">>})).
+
+auth_external_no_user(Config0) ->
+    Config = set_opt(user, <<"">>, connect(starttls(Config0))),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config)).
+
+auth_external_malformed_jid(Config0) ->
+    Config = connect(starttls(Config0)),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config, _ShouldFail = true,
+                        {<<"">>, <<"@">>, <<"">>})).
+
+auth_external_wrong_jid(Config0) ->
+    Config = set_opt(user, <<"wrong">>,
+                    connect(starttls(Config0))),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config, _ShouldFail = true)).
+
+auth_external_wrong_server(Config0) ->
+    Config = connect(starttls(Config0)),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config, _ShouldFail = true,
+                        {<<"">>, <<"wrong.com">>, <<"">>})).
+
+auth_external_invalid_cert(Config0) ->
+    Config = connect(starttls(
+                      set_opt(certfile, "self-signed-cert.pem", Config0))),
+    disconnect(auth_SASL(<<"EXTERNAL">>, Config, _ShouldFail = true)).
+
 test_legacy_auth_feature(Config) ->
     true = ?config(legacy_auth, Config),
     disconnect(Config).
index ee9cf16417a04ce03660f0e0df651cff2769be3a..656369cbc37c88ce1fee56629a519a84a65f9b1b 100644 (file)
@@ -1,54 +1,54 @@
 -----BEGIN CERTIFICATE-----
-MIIEmTCCA4GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET
+MIIEjTCCA3WgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET
 MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMB4XDTE2MDkyMzA3MDMyNFoXDTQ0MDIwOTA3MDMyNFowVjELMAkGA1UE
+dHkgTHRkMB4XDTE3MDMwNzA5NTgxNloXDTQ0MDcyMzA5NTgxNlowWTELMAkGA1UE
 BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp
-ZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAxMGYWN0aXZlMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oP
-Dl5nd04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNL
-h0Z3XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5
-Rj1WojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNr
-ePCs6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd
-+3vZQ+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABo4IBgTCCAX0wCQYD
-VR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm
-aWNhdGUwHQYDVR0OBBYEFJgip1fThIyZu9J+YNz3XKDkOcMKMB8GA1UdIwQYMBaA
-FND2ZsvHIjITekPKs0ywLfoNEen5MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9s
-b2NhbGhvc3Q6NTI4MC9kYXRhL2NybC5kZXIwNgYIKwYBBQUHAQEEKjAoMCYGCCsG
-AQUFBzABhhpodHRwOi8vbG9jYWxob3N0OjUyODAvb2NzcDALBgNVHQ8EBAMCBeAw
-JwYDVR0lBCAwHgYIKwYBBQUHAwkGCCsGAQUFBwMBBggrBgEFBQcDAjBfBgNVHREE
-WDBWoBcGCCsGAQUFBwgFoAsMCWxvY2FsaG9zdKAbBggrBgEFBQcIBaAPDA1zMnMu
-bG9jYWxob3N0oB4GCCsGAQUFBwgFoBIMEG1uZXNpYS5sb2NhbGhvc3QwDQYJKoZI
-hvcNAQEFBQADggEBAEwHeECqeEJIz0VFA0OZ0w9+3rfZPX9K59rbJNNnKVATPhk5
-g5NFpXy1mFTV/3MWjDS1QRbgoXzOYR64S87oez4l3jyDz3YxklyjbbiN3QKaUq5h
-284Ze6CiRqxIi6V2bhjjp3voMSP8BQ72bX9uAWjqQl7Z16wYuCzV4QzVZRD5p0c1
-y45WZ6J+sU1GTwEGh0vXZBlDMeTb+53smjEoCxET1ecJmStAvJi+UHiLn63Z3Yzz
-CTfdAZ/mj+ytaNLVsgrULXrmZAeo064HVqeyLWL8ZBoM0zLs6u14OQOeDCCB62cj
-UXb9npKmIdfsWvdii6emCVQqKBQmHnlUMCh56tE=
+ZGdpdHMgUHR5IEx0ZDESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAnzzyImmDW0BdGoqsBJkIfcp0YjkMN6HDuRxTHvkv
+lXU1q9u1VOsoC84Uf+x2VC+UauT44lyqQPH2WorztEqB5y0N0BLISf1ZNcS/s6iB
+OaL6nAmA+A6Lm73Gt+HZP8yFWCerPWchHppOebei+edcxhRdjOJYU4wudvxr/tGg
+qsqeY6beV1T4gx8w5E/qRZ9r/ZCNQUjOS1Dj1KLigWVhVviF2Ynli2GG46cLwRPb
+MgK3i4Uu57E0YlnZYKp9uWLn673yxwoOr7uVyvuVGx70SmvTIC3Logei6D76OCsw
+uWCD8iKd6jpg84sHCtlFxVbeMAXBSVTRXJVRJYb+hB7Q1QIDAQABo4IBcjCCAW4w
+CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFD4Lfl3x6oeBw/MfBdOCmyyFV2NKMB8GA1UdIwQY
+MBaAFND2ZsvHIjITekPKs0ywLfoNEen5MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6
+Ly9sb2NhbGhvc3Q6NTI4MC9kYXRhL2NybC5kZXIwNgYIKwYBBQUHAQEEKjAoMCYG
+CCsGAQUFBzABhhpodHRwOi8vbG9jYWxob3N0OjUyODAvb2NzcDALBgNVHQ8EBAMC
+BeAwJwYDVR0lBCAwHgYIKwYBBQUHAwkGCCsGAQUFBwMBBggrBgEFBQcDAjBQBgNV
+HREESTBHggsqLmxvY2FsaG9zdKA4BggrBgEFBQcIBaAsDCp0ZXN0X3NpbmdsZSEj
+JCVeKigpYH4rLTtfPVtde318XEBsb2NhbGhvc3QwDQYJKoZIhvcNAQEFBQADggEB
+AG4YXWyrGYBZqupfeAJ81IBz6gFFZ5GIDYdM+x6ewR/o+ALUxGpZRgnSHei1Fh4M
+wwrGLRIwqpeTtfs6BM0ld7tb0sJeO/B3QxzduKGPnmVni0S/s09m/4tehS4EnRd6
+OxRvdCQFxMT5t0bWpUyY063xytju4vHYBMdpAkqyRuqb7of0qY1zfAWk4TKPi1pr
+O/vCes/asXEumn4MLZPGaoIiHNMacjehimp0g5y8FmnldchuZO94NZ/SYoAo1MXC
+0SyW6WEuIelnNXpzib8EesDgGP5zsUSvlb3EbEnEXAnQlbHfkZJhUHojlFVX+ALc
+6WYvzGhKeh6QoJ64pUCnRlY=
 -----END CERTIFICATE-----
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
index e766d0cc3e36f236bfc1db365609fc7afe168ad1..828e0c03c38cf2519b7a6b8c00a44c116de2f93e 100644 (file)
@@ -429,8 +429,10 @@ listen:
     module: ejabberd_c2s
     max_stanza_size: 65536
     certfile: CERTFILE
+    cafile: CAFILE
     zlib: true
     starttls: true
+    tls_verify: true
     shaper: c2s_shaper
     access: c2s
     resume_timeout: 3
index d0acd4b0cbb1209fd01789eefc6d047e6514a9e9..60dca9897a53536195588ef81b0ccf8d17797e37 100755 (executable)
@@ -7,9 +7,9 @@ touch ssl/index.txt
 echo 01 > ssl/serial
 echo 1000 > ssl/crlnumber
 openssl genrsa -out ssl/client.key
-openssl req -new -key ssl/client.key -out ssl/client.csr -config openssl.cnf -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=active
+openssl req -new -key ssl/client.key -out ssl/client.csr -config openssl.cnf -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=localhost
 openssl ca -keyfile ca.key -cert ca.pem -in ssl/client.csr -out ssl/client.crt -config openssl.cnf -days 10000 -batch -notext
-openssl req -new -key ssl/client.key -out ssl/self-signed-client.csr -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=active
+openssl req -new -key ssl/client.key -out ssl/self-signed-client.csr -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=localhost
 openssl x509 -req -in ssl/self-signed-client.csr -signkey ssl/client.key -out ssl/self-signed-client.crt -days 10000
 cat ssl/client.crt > cert.pem
 cat ssl/self-signed-client.crt > self-signed-cert.pem
index ff11d1460a10918b8590bee28229a10bb5289daf..6d6b0750ed7b00f5a132b3038ab29e5bb5452a1c 100644 (file)
@@ -220,9 +220,8 @@ extendedKeyUsage = OCSPSigning,serverAuth,clientAuth
 subjectAltName          = @alt_names
 
 [alt_names]
-otherName.1 = 1.3.6.1.5.5.7.8.5;UTF8:"localhost"
-otherName.2 = 1.3.6.1.5.5.7.8.5;UTF8:"s2s.localhost"
-otherName.3 = 1.3.6.1.5.5.7.8.5;UTF8:"mnesia.localhost"
+DNS.1 = *.localhost
+otherName.1 = 1.3.6.1.5.5.7.8.5;UTF8:"test_single!#$%^*()`~+-;_=[]{}|\\@localhost"
 
 [ v3_ca ]
 crlDistributionPoints = URI:http://localhost:5280/data/crl.der
index d6b34f50ef87f02c38a723e09a208203720d65af..69b50259dccac9b35045a48a713b959a28026a09 100644 (file)
@@ -1,46 +1,47 @@
 -----BEGIN CERTIFICATE-----
-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
+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
-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
+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
+gLs=
 -----END CERTIFICATE-----
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
index 67dcd6c4d357f4c87c7990e6d30321d7a1b77b8c..6b8a49f215503f6bd7c6af63ca23936126b75663 100644 (file)
@@ -306,7 +306,7 @@ auth(Config, ShouldFail) ->
             auth_SASL(<<"PLAIN">>, Config, ShouldFail);
        HaveMD5 ->
             auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail);
-       HaveExternal andalso Type == server ->
+       HaveExternal ->
            auth_SASL(<<"EXTERNAL">>, Config, ShouldFail);
        Type == client ->
            auth_legacy(Config, false, ShouldFail);
@@ -414,10 +414,13 @@ auth_SASL(Mech, Config) ->
     auth_SASL(Mech, Config, false).
 
 auth_SASL(Mech, Config, ShouldFail) ->
-    {Response, SASL} = sasl_new(Mech,
-                                ?config(user, Config),
-                                ?config(server, Config),
-                                ?config(password, Config)),
+    Creds = {?config(user, Config),
+            ?config(server, Config),
+            ?config(password, Config)},
+    auth_SASL(Mech, Config, ShouldFail, Creds).
+
+auth_SASL(Mech, Config, ShouldFail, Creds) ->
+    {Response, SASL} = sasl_new(Mech, Creds),
     send(Config, #sasl_auth{mechanism = Mech, text = Response}),
     wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail).
 
@@ -549,16 +552,16 @@ send_recv(State, #iq{} = IQ) ->
     ID = send(State, IQ),
     receive #iq{id = ID} = Result -> Result end.
 
-sasl_new(<<"PLAIN">>, User, Server, Password) ->
+sasl_new(<<"PLAIN">>, {User, Server, Password}) ->
     {<<User/binary, $@, Server/binary, 0, User/binary, 0, Password/binary>>,
      fun (_) -> {error, <<"Invalid SASL challenge">>} end};
-sasl_new(<<"EXTERNAL">>, _User, _Server, _Password) ->
-    {<<"">>,
+sasl_new(<<"EXTERNAL">>, {User, Server, _Password}) ->
+    {jid:encode(jid:make(User, Server)),
      fun(_) -> ct:fail(sasl_challenge_is_not_expected) end};
-sasl_new(<<"ANONYMOUS">>, _User, _Server, _Password) ->
+sasl_new(<<"ANONYMOUS">>, _) ->
     {<<"">>,
      fun(_) -> ct:fail(sasl_challenge_is_not_expected) end};
-sasl_new(<<"DIGEST-MD5">>, User, Server, Password) ->
+sasl_new(<<"DIGEST-MD5">>, {User, Server, Password}) ->
     {<<"">>,
      fun (ServerIn) ->
             case cyrsasl_digest:parse(ServerIn) of