diff --git a/ChangeLog b/ChangeLog index e645ccd88..8a22998bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-11-05 Alexey Shchepin + + * src/ejabberd_config.erl: Support for per host certificates + * src/ejabberd_c2s.erl: Likewise + * src/ejabberd_s2s_out.erl: Likewise + * src/ejabberd.cfg.example: Updated + + * src/ejabberd_s2s_in.erl: Fixed id-on-xmppAddr processing + 2005-11-03 Alexey Shchepin * src/mod_disco.erl: Fixed extra_domains option processing diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 1cc468bf5..cf8e72036 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -119,6 +119,8 @@ % Use STARTTLS+Dialback for S2S connections {s2s_use_starttls, true}. {s2s_certfile, "./ssl.pem"}. +%{domain_certfile, "example.org", "./example_org.pem"}. +%{domain_certfile, "example.com", "./example_com.pem"}. % If SRV lookup fails, then port 5269 is used to communicate with remote server {outgoing_s2s_port, 5269}. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index a567303b6..abc0cf670 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -473,7 +473,16 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> TLSEnabled == false, SockMod == gen_tcp -> Socket = StateData#state.socket, - TLSOpts = StateData#state.tls_options, + TLSOpts = case ejabberd_config:get_local_option( + {domain_certfile, StateData#state.server}) of + undefined -> + StateData#state.tls_options; + CertFile -> + [{certfile, CertFile} | + lists:keydelete( + certfile, 1, StateData#state.tls_options)] + end, + io:format("O: ~p~n", [TLSOpts]), {ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts), ejabberd_receiver:starttls(StateData#state.receiver, TLSSocket), send_element(StateData, diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 51c183a21..93aee3e19 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -110,8 +110,10 @@ process_term(Term, State) -> add_option(outgoing_s2s_port, Port, State); {s2s_use_starttls, Port} -> add_option(s2s_use_starttls, Port, State); - {s2s_certfile, Port} -> - add_option(s2s_certfile, Port, State); + {s2s_certfile, CertFile} -> + add_option(s2s_certfile, CertFile, State); + {domain_certfile, Domain, CertFile} -> + add_option({domain_certfile, Domain}, CertFile, State); {Opt, Val} -> lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end, State, State#state.hosts) diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 79ae93387..ca2a32c56 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -31,6 +31,7 @@ -include("jlib.hrl"). %-include_lib("ssl/pkix/SSL-PKIX.hrl"). -include_lib("ssl/pkix/PKIX1Explicit88.hrl"). +-include_lib("ssl/pkix/PKIX1Implicit88.hrl"). -include("tls/XmppAddr.hrl"). -define(DICT, dict). @@ -542,6 +543,8 @@ is_key_packet(_) -> get_cert_domains(Cert) -> {rdnSequence, Subject} = (Cert#'Certificate'.tbsCertificate)#'TBSCertificate'.subject, + Extensions = + (Cert#'Certificate'.tbsCertificate)#'TBSCertificate'.extensions, lists:flatmap( fun(#'AttributeTypeAndValue'{type = ?'id-at-commonName', value = Val}) -> @@ -555,11 +558,13 @@ get_cert_domains(Cert) -> end, if D /= error -> - case jlib:nameprep(D) of - error -> - []; - LD -> - [LD] + case jlib:string_to_jid(D) of + #jid{luser = "", + lserver = LD, + lresource = ""} -> + [LD]; + _ -> + [] end; true -> [] @@ -567,23 +572,48 @@ get_cert_domains(Cert) -> _ -> [] end; - (#'AttributeTypeAndValue'{type = ?'id-on-xmppAddr', - value = Val}) -> - case 'XmppAddr':decode( - 'XmppAddr', Val) of - {ok, D} when is_binary(D) -> - case jlib:nameprep(binary_to_list(D)) of - error -> - []; - LD -> - [LD] - end; - _ -> - [] - end; (_) -> [] - end, lists:flatten(Subject)). + end, lists:flatten(Subject)) ++ + lists:flatmap( + fun(#'Extension'{extnID = ?'id-ce-subjectAltName', + extnValue = Val}) -> + BVal = if + is_list(Val) -> list_to_binary(Val); + is_binary(Val) -> Val; + true -> Val + end, + case 'PKIX1Implicit88':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) -> + case jlib:string_to_jid( + binary_to_list(D)) of + #jid{luser = "", + lserver = LD, + lresource = ""} -> + [LD]; + _ -> + [] + end; + _ -> + [] + end; + (_) -> + [] + end, SANs); + _ -> + [] + end; + (_) -> + [] + end, Extensions). diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 0384297d2..c1b092bb0 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -438,7 +438,17 @@ wait_for_starttls_proceed({xmlstreamelement, El}, StateData) -> ?INFO_MSG("starttls: ~p", [{StateData#state.myname, StateData#state.server}]), Socket = StateData#state.socket, - TLSOpts = StateData#state.tls_options, + TLSOpts = case ejabberd_config:get_local_option( + {domain_certfile, + StateData#state.server}) of + undefined -> + StateData#state.tls_options; + CertFile -> + [{certfile, CertFile} | + lists:keydelete( + certfile, 1, + StateData#state.tls_options)] + end, {ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts), ejabberd_receiver:starttls( StateData#state.receiver, TLSSocket),