diff --git a/world/net/jabber/active.c b/world/net/jabber/active.c index 84c934b..acfdc40 100644 --- a/world/net/jabber/active.c +++ b/world/net/jabber/active.c @@ -315,7 +315,7 @@ tls_logon(result) { mixed cert = tls_certificate(ME, 0); P3(("active::certinfo %O\n", cert)) if (mappingp(cert)) { - unless (certificate_check_jabbername(hostname, cert)) { + unless (certificate_check_name(hostname, cert, "xmpp-server")) { #ifdef _flag_report_bogus_certificates monitor_report("_error_invalid_certificate_identity", sprintf("%O presented a certificate that " diff --git a/world/net/jabber/common.c b/world/net/jabber/common.c index 2e4c8de..0f2ab3a 100644 --- a/world/net/jabber/common.c +++ b/world/net/jabber/common.c @@ -393,6 +393,7 @@ xmpp_error(node, xmpperror) { return 0; } +// deprecated - use certificate_check_name from library/tls.c instead #ifdef WANT_S2S_TLS certificate_check_jabbername(name, cert) { mixed t; diff --git a/world/net/jabber/gateway.c b/world/net/jabber/gateway.c index 6979250..c88c0b5 100644 --- a/world/net/jabber/gateway.c +++ b/world/net/jabber/gateway.c @@ -291,8 +291,8 @@ jabberMsg(XMLNode node) { // paranoia note: as with XEP 0178 we might want to check dns anyway to // protect against stolen certificates if (mappingp(certinfo) && certinfo[0] == 0 - && node["@from"] && certificate_check_jabbername(node["@from"], certinfo)) { - P0(("dialback without dialback %O\n", certinfo)) + && node["@from"] && certificate_check_name(node["@from"], certinfo, "xmpp-server")) { + P2(("dialback without dialback %O\n", certinfo)) verify_connection(node["@to"], node["@from"], "valid"); } else { sendmsg(origin, @@ -414,7 +414,7 @@ jabberMsg(XMLNode node) { */ int success = 0; - success = certificate_check_jabbername(t, certinfo); + success = certificate_check_name(t, certinfo, "xmpp-server"); if (success) { emitraw(""); P2(("successful sasl external authentication with " @@ -542,8 +542,8 @@ open_stream(XMLNode node) { // sasl external if we know that it will succeed // later on if (node["@from"] && - certificate_check_jabbername(node["@from"], - certinfo)) { + certificate_check_name(node["@from"], + certinfo, "xmpp-server")) { packet += ""; packet += "EXTERNAL"; packet += ""; diff --git a/world/net/jabber/server.c b/world/net/jabber/server.c index a313651..b1d1625 100644 --- a/world/net/jabber/server.c +++ b/world/net/jabber/server.c @@ -485,6 +485,8 @@ open_stream(XMLNode node) { // sasl anonymous "ANONYMOUS"; #endif + // here it makes sense to use check_jabbername + // but that is currently unused anyway #if __EFUN_DEFINED__(tls_available) if (tls_available() && tls_query_connection_state(ME) > 0 && mappingp(certinfo) && certinfo[0] == 0 diff --git a/world/net/library/tls.c b/world/net/library/tls.c index a90ad77..c975171 100644 --- a/world/net/library/tls.c +++ b/world/net/library/tls.c @@ -82,3 +82,78 @@ mapping tls_certificate(object who, int longnames) { P2(("cert is %O\n", cert)) return cert; } + +// generalized variant of the old certificate_check_jabbername +// RFC 6125 describes the process in more detail +int certificate_check_name(string name, mixed cert, string scheme) { + mixed t; + string idn; + // FIXME: should probably be more careful about internationalized + // domain names - need testcases +#define WILDCARD_MATCH(thing) (strlen(thing) > 2 && thing[0] == '*' && thing[1] == '.' && trail(thing[2..], name)) + /* this does not support wildcards if there is more than one + * id-on-xmppAddr/CN + * API Note: name MUST be an utf8 string + */ + unless(name && cert && mappingp(cert)) return 0; + + name = NAMEPREP(name); + + // subjectAlternativeName - dNSName + if ((t = cert["2.5.29.17:dNSName"])) { + if (stringp(t)) t = ({ t }); + foreach(string t2 : t) { + t2 = NAMEPREP(t2); + if (name == t2 || WILDCARD_MATCH(t2)) + return 1; + } + } + + // subjectAlternativeName - SRV ID - FIXME + // unfortunately, the only ones I have encountered so far were ... unusable + if ((t = cert["2.5.29.17:1.3.6.1.5.5.7.8.7"])) { + P2(("encountered SRVName, please tell fippo: %O\n", t)) + } + + // URI ID - FIXME + // not seen yet + +#if 0 + // id-on-xmppAddr - have not seen them issued by anyone but + // startcom and those usually include dnsname, too + if ((t = cert["2.5.29.17:1.3.6.1.5.5.7.8.5"])) { + if (pointerp(t)) { + if (member(t, name) != -1) return 1; + foreach(string cn : t) { + if (NAMEPREP(cn) == name) return 1; + } + } + else if (name == NAMEPREP(t)) + return 1; + } +#endif + + // commonName - deprecated to put the host here but... + // this is only to be checked if no subjectAlternativeName is present + if (!cert["2.5.29.17"] && (t = cert["2.5.4.3"])) { // common name + if (pointerp(t)) { // does that happen?! I don't think so... + // fast way - works for traditional hostnames + if (member(t, name) != -1) return 1; + + // look for idn encoded stuff + foreach(string cn : t) { + idn = NAMEPREP(idna_to_unicode(cn)); + if (idn == name) return 1; + } + return 0; + } +#ifdef __IDNA__ + idn = NAMEPREP(idna_to_unicode(t)); +#else + idn = NAMEPREP(t); +#endif + if (idn == name || WILDCARD_MATCH(idn)) + return 1; + } + return 0; +}