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;
+}