From 8b29af629b816529a3ce6385a8445114447c30ba Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 7 Mar 2017 14:20:50 +0300 Subject: [PATCH] Best Practices for Use of SASL EXTERNAL with Certificates (XEP-0178) support 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 | 2 +- src/ejabberd_socket.erl | 6 +- src/xmpp_stream_pkix.erl | 291 +++++++++++------- test/ejabberd_SUITE.erl | 45 ++- test/ejabberd_SUITE_data/cert.pem | 96 +++--- test/ejabberd_SUITE_data/ejabberd.yml | 2 + test/ejabberd_SUITE_data/gencerts.sh | 4 +- test/ejabberd_SUITE_data/openssl.cnf | 5 +- test/ejabberd_SUITE_data/self-signed-cert.pem | 83 ++--- test/suite.erl | 25 +- 10 files changed, 343 insertions(+), 216 deletions(-) diff --git a/rebar.config b/rebar.config index c04b075b7..f38591955 100644 --- a/rebar.config +++ b/rebar.config @@ -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"}}, diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index c690888a9..c5c56cd58 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -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). diff --git a/src/xmpp_stream_pkix.erl b/src/xmpp_stream_pkix.erl index d556510f6..0dfcecf78 100644 --- a/src/xmpp_stream_pkix.erl +++ b/src/xmpp_stream_pkix.erl @@ -22,12 +22,15 @@ -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}. diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 175a6e69a..c15fa52b8 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -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). diff --git a/test/ejabberd_SUITE_data/cert.pem b/test/ejabberd_SUITE_data/cert.pem index ee9cf1641..656369cbc 100644 --- a/test/ejabberd_SUITE_data/cert.pem +++ b/test/ejabberd_SUITE_data/cert.pem @@ -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----- -MIIEpAIBAAKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oPDl5n -d04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNLh0Z3 -XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5Rj1W -ojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNrePCs -6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd+3vZ -Q+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABAoIBAQCWIyxVx+36YgGA -E927VzIkyqJ0tMncbOAYq/228oj4yy6th4l1Kx1fkHdWtnjDxBJFpc9l+u4ArI1r -Cao8wIAadmxp48dshtJC7TBv86EXuvdgH11XiPcknGRVWv4T4cX099gN8cX3QcWR -jHCC3B4phnD9s8RcZAs6X/cQWQU0mxiHodYJefSXDyRIx9wimXmmW83ZqcsFftXS -MI0+jflmRTf07M4gALVL0LlaBkg2FMoNiaKYPTbubcrEMUgTDsoDsjX3Fi43qLdF -QTq+lF7HrHQ1EQlngCJupka9JxwZc3Fae6XYlDQvSDPcRxzWJoOuVBPtheGeoU3c -PAry9KihAoGBAN8HCb0k4bMN06WZjSzClKhb6eFw4GMbVpDAOwPDl2N+9+pwrGxE -ztekrM+VdXVScIj23g6wKd6fPqK6EYuEEu3Hre82e9ApqjJ34p1UcOs9Vs4N3VDy -HJnWhEytsc9c03O5nhsK1YAXoGHEPmCYGsg2UA171LDcarnO1WDmpKkNAoGBAMw2 -sTCC/LBwgsuPZL5fR10wQ1sr1fIheSL+VK10jSRDwNXT2Y4wdCpQXQ6XNi+n98n5 -VvKaE6PxFqjnKCrUUty8X5+fzVcTKpBYVICceEzpVY9FrKbeY1shMnOBRTCkaQwz -8CoEbbQz6SH5s4qW7M8iJdUJ0RulaFDfpmangTStAoGBALMkMxVjZ4rsI0GT2grG -7KNi2LTFducEUX8JeR2n4JUBql78S/LXPhGGa2x9z5ACPPQ23tyLccYowSXyMR+Q -YafuyO4pJEBrBxNsqnDXH7BEX9I43rkjEAgdf70bk4RNOmdtA+sSw7UUxTVibPwn -kPOadKiv+4JoOa2vzkL8X+yNAoGAbU85OUZkC+2tlViEDILjqDYVV8/3DUxtkxWg -LdidVDQQHGTxpvK4u42Ywh6empPGRw54RBPFP5PlFTPmhEZytEUAymi3eUyBFBKz -6MPYgRLFAZPB/vA7LqRuZPVlG8xljmqeu17zeenveIg4Wo6+44Dbz1UZ4TqAxAlz -AK/YsWECgYAPuZnIo9fWJtUAIe5IA2LIqcN0rj3PsZ/tL6eaMXqKZgCYwTvVUGbT -XD4O352t+yLM8v2hJGHrIPuHooN2dCadYuzoBvVFsRTZjGpBlAZ+EJ5WfDYFL0qf -68O2KZNXaSS8ZARlp9g3C8AFiakm/uWhtSfwx09uSBHJgld1V3GAoA== +MIIEowIBAAKCAQEAnzzyImmDW0BdGoqsBJkIfcp0YjkMN6HDuRxTHvkvlXU1q9u1 +VOsoC84Uf+x2VC+UauT44lyqQPH2WorztEqB5y0N0BLISf1ZNcS/s6iBOaL6nAmA ++A6Lm73Gt+HZP8yFWCerPWchHppOebei+edcxhRdjOJYU4wudvxr/tGgqsqeY6be +V1T4gx8w5E/qRZ9r/ZCNQUjOS1Dj1KLigWVhVviF2Ynli2GG46cLwRPbMgK3i4Uu +57E0YlnZYKp9uWLn673yxwoOr7uVyvuVGx70SmvTIC3Logei6D76OCswuWCD8iKd +6jpg84sHCtlFxVbeMAXBSVTRXJVRJYb+hB7Q1QIDAQABAoIBACdBQv+wuy0XpNwS +K23GvA0mh6JfJd/hBPrxPJx6GXzitCR1uTIB9pFScENI67K9N/1SDPjglygDfhO8 +BXAAnh17Qdh1iOKUjhVvN0L220R2JQmqXhzImSn/kqlqB8BujsC4psIwVj3RFF91 +IbwxiPFbu+QrOFMAT8QNXiInU1BG1zM8O/9dXaDG1zSuLGH8hz8Xp6QYkZKWXErp +MGg4smvzk+HhMvf678Uzg/a6z6JJoVc1oaaaNhQzurCJmPJLCjVsR7O9y0/OwPI5 +PN+8Of06AdynWrx8LBdWFckTr8lvT/0FMYRIbubFG/ksLet+GHab/R0U49Ae0SMf +vQzsy9ECgYEA0+eF3sfTtLjXFCKtiTHsFfaNqX3mIwtd+d4gOSzhRxj0JAr2/AWA +c1vrk9wLanoi/awe7qQfJIZGQHbrmzk17IFJqzKEokmJqId07mVgCy9rRy/v2Tuy +vSXkSNHEqCQVdMQLVVZ78eUkonokrPrb8NvuV6La8p1+wqeHPuqnfnsCgYEAwF/O +XDs/pg/N6XzoBOq9xkhwXtrllvsd99LNhsO75nLo0EI6m4tc/fpm1bpVOMxDThwi +vEyCdYyxkBlHEbjW5r73ZjF+qBRmRLcp380+N71S1Ljj5AO5+5IFzoFw+lYNXbSB +aH+OuFanwnYVJF0E6RIahdadWZCWYNONBjJQdO8CgYAcuM3xY15zqXYlmYmyBd09 +IN0Usyblax4CxzPQ7B9g1qYI2J+fi1Ncz4G/2dyGQyXJAnJy4DYEalrNVBEdSgTg +GKoWlVNa9+K7wBh+U6lP+s5sqLe21xuj/aXSpPQl4jYyTHxIxd8o62kqyKl99Mao +//ZvVHie1/AdjD2NrpqjTwKBgQC9CKfQC8x0ks0lJb8crcqDoEUDgJfgr6v4DSY2 +yfnG7p2Fn77Vf7GGRNtuI6aApH9yrsUXQRtlBTaqQZyLdpV9sqOKwRITedAwr8ev +CpCb1ycgrvoI4fyMjyWzkZCB/bMupCQRml6VF1nMBZqq29jqaga0A3slOqX6SYcn +UqOq8wKBgF4gw/71uU40yQM4hKjKFT1iCWIfMEWTUxhZkGyntCzqTUsEBH7o+1C9 +BOzGeUn38MmZlQvsZj1BmnkyovX79i5b5o0OBUfGBBP+GfupYfUOyvYz9g7LV6Ry +pVHDD0k2iW1L5rcLtHECTZKKwXn9CyZISulXEuzMu0P0QhlN2TH5 -----END RSA PRIVATE KEY----- diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index e766d0cc3..828e0c03c 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -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 diff --git a/test/ejabberd_SUITE_data/gencerts.sh b/test/ejabberd_SUITE_data/gencerts.sh index d0acd4b0c..60dca9897 100755 --- a/test/ejabberd_SUITE_data/gencerts.sh +++ b/test/ejabberd_SUITE_data/gencerts.sh @@ -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 diff --git a/test/ejabberd_SUITE_data/openssl.cnf b/test/ejabberd_SUITE_data/openssl.cnf index ff11d1460..6d6b0750e 100644 --- a/test/ejabberd_SUITE_data/openssl.cnf +++ b/test/ejabberd_SUITE_data/openssl.cnf @@ -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 diff --git a/test/ejabberd_SUITE_data/self-signed-cert.pem b/test/ejabberd_SUITE_data/self-signed-cert.pem index d6b34f50e..69b50259d 100644 --- a/test/ejabberd_SUITE_data/self-signed-cert.pem +++ b/test/ejabberd_SUITE_data/self-signed-cert.pem @@ -1,46 +1,47 @@ -----BEGIN CERTIFICATE----- -MIIDKDCCAhACCQCsLYnJDV1wHDANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJB +MIIDLjCCAhYCCQCm79bLvTZtejANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJB VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMQ8wDQYDVQQDEwZhY3RpdmUwHhcNMTYwOTIzMDcwMzI0WhcNNDQw -MjA5MDcwMzI0WjBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEh -MB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZhY3Rp -dmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx6UGc6HTz2D9U3uAf -WbjdWjruRKqHxBGddnF+OnO3eg8OXmd3Th417Lh7OhIGjujWEqGP+bkovGbLWQ37 -GyzK62DO2jUVm7wYLaMPIu8HI0uHRndcubN3MHMGOiwK2WUm3MeVUvTxI+644h3m -FOiKJPyHcSWA0jgvrD54vOFkiTlGPVaiMZr6mdpMSCg5pk9w2uQ6PzWjW2Cdstc3 -sdjeEkqdGnvwOY/JKrzZxGG982t48KzoEmvfLvJgmTScb4Q5qPkEr3lhImid1nx8 -5m4KKAk8yiARpLDRIaxJSJCs+x37e9lD7dy06KaeFbtwXd8Azv2D7MN2/030TcP6 -KeHJAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEAIFwHpNCVUiivAcfkxcUPKp0nn -mhGqkMDRrPA7fOCm0ir1Puz4GQ/G4i+tWejzzFoS6kKQl+sUZAUYJdziftJFFoZ7 -br3q3Xafc2dWa8SHNcHH6lA1OEk8tXlhkNl+EgSLnRGMhIf0iZL2wGjE8Hlig6cu -3h+OpbUijXUmq0XdH+ui3wNgXb7+Tosg/Od+lr0fNjkopsk3t1oiVXD4OQBZdUyq -V5XValiZjMFDUUBdxBA+l6/Qj3bFmluz+FXI8UwfbinukqADTJzkMeUjEkvmKZWO -tb+EU77NIuvg/k7b1yp4lEmATpdUfcGEuhWNtgeh5AqgMxOhAsJ7zUTA80I= +cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcwMzA3MDk1ODE2WhcN +NDQwNzIzMDk1ODE2WjBZMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0 +ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwls +b2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfPPIiaYNb +QF0aiqwEmQh9ynRiOQw3ocO5HFMe+S+VdTWr27VU6ygLzhR/7HZUL5Rq5PjiXKpA +8fZaivO0SoHnLQ3QEshJ/Vk1xL+zqIE5ovqcCYD4Doubvca34dk/zIVYJ6s9ZyEe +mk55t6L551zGFF2M4lhTjC52/Gv+0aCqyp5jpt5XVPiDHzDkT+pFn2v9kI1BSM5L +UOPUouKBZWFW+IXZieWLYYbjpwvBE9syAreLhS7nsTRiWdlgqn25YufrvfLHCg6v +u5XK+5UbHvRKa9MgLcuiB6LoPvo4KzC5YIPyIp3qOmDziwcK2UXFVt4wBcFJVNFc +lVElhv6EHtDVAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAIO1fcAI8QjAgbfveLh +GbYWkEE5HjNtf2TlSoqnPStFAGSmv4C3H7bASt74pKaaMNQMkwaN97aYlNE2uBNP +wEUZqz81OpiSyyvo49YxZCBHs83K8/sNUOF/NdRMV9D21Ncx9uXsumJwLu6OvUC9 +TRtjXmUIEMF84v4agqHlWng1o6T2Y6etsMgS5TeejdjSB6CyT+JkxWGF0sSnFsFF +MxpvL33czUR0LzN82WqHnOF3Q6Uqa1K8SkDQ8NBTjQ0VI4lTYFXtBU2TdQXE3fuT +e8MdpWCUuTVtCML0GGD2ST5KdJ7y64nlfedFn8qNFYaGyjebrfjiwDEDHVHIGFZD +gLs= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/suite.erl b/test/suite.erl index 67dcd6c4d..6b8a49f21 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -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}) -> {<>, 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">>, _) -> {<<"">>, fun(_) -> ct:fail(sasl_challenge_is_not_expected) end}; -sasl_new(<<"ANONYMOUS">>, _User, _Server, _Password) -> - {<<"">>, - 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