From dd903bec95b3ab24b12ab8013a64cdbddfe4a312 Mon Sep 17 00:00:00 2001 From: Eng ChongMeng Date: Mon, 6 May 2019 00:38:22 +0200 Subject: [PATCH 1/5] SMACK-868: Fix XHTMLText producing invalid XML --- .../main/java/org/jivesoftware/smackx/xhtmlim/XHTMLText.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xhtmlim/XHTMLText.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xhtmlim/XHTMLText.java index b08507ad0..2ef66949f 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xhtmlim/XHTMLText.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xhtmlim/XHTMLText.java @@ -105,7 +105,7 @@ public class XHTMLText { private XHTMLText appendOpenBodyTag(String style, String lang) { text.halfOpenElement(Message.BODY); text.xmlnsAttribute(NAMESPACE); - text.optElement(STYLE, style); + text.optAttribute(STYLE, style); text.xmllangAttribute(lang); text.rightAngleBracket(); return this; From edcde28ecdfa56cd55ed68dd4e2a6a0566e5aaa7 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 9 May 2019 11:04:26 +0200 Subject: [PATCH 2/5] Set UncaughtExceptionHandler for CACHED_EXECUTOR_SERVICE In order to avoid uncaught exceptions from terminating the program (SMACK-896). --- .../java/org/jivesoftware/smack/AbstractXMPPConnection.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index fe82c07f6..d65fb0b24 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -294,6 +294,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { Thread thread = new Thread(runnable); thread.setName("Smack Cached Executor"); thread.setDaemon(true); + thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + LOGGER.log(Level.WARNING, t + " encountered uncaught exception", e); + } + }); return thread; } }); From 381190a45c0cafc13171611689d181f154bb68d6 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 16 May 2019 14:02:01 +0200 Subject: [PATCH 3/5] Add ConnectionConfiguration.getXmppServiceDomainAsDnsNameIfPossible() in preperation of SMACK-870, so that the DNS name can be used for the certificate verification. --- .../smack/ConnectionConfiguration.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java index 7115a2bc3..d14a82d46 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2017-2018 Florian Schmaus. + * Copyright 2003-2007 Jive Software, 2017-2019 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,8 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.net.SocketFactory; import javax.net.ssl.HostnameVerifier; @@ -46,6 +48,7 @@ import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; import org.minidns.dnsname.DnsName; +import org.minidns.dnsname.InvalidDnsNameException; import org.minidns.util.InetAddressUtil; /** @@ -61,6 +64,8 @@ public abstract class ConnectionConfiguration { SmackConfiguration.getVersion(); } + private static final Logger LOGGER = Logger.getLogger(ConnectionConfiguration.class.getName()); + /** * The XMPP domain of the XMPP Service. Usually servers use the same service name as the name * of the server. However, there are some servers like google where host would be @@ -68,6 +73,8 @@ public abstract class ConnectionConfiguration { */ protected final DomainBareJid xmppServiceDomain; + protected final DnsName xmppServiceDomainDnsName; + protected final InetAddress hostAddress; protected final DnsName host; protected final int port; @@ -140,6 +147,19 @@ public abstract class ConnectionConfiguration { if (xmppServiceDomain == null) { throw new IllegalArgumentException("Must define the XMPP domain"); } + + DnsName xmppServiceDomainDnsName; + try { + xmppServiceDomainDnsName = DnsName.from(xmppServiceDomain); + } catch (InvalidDnsNameException e) { + LOGGER.log(Level.INFO, + "Could not transform XMPP service domain '" + xmppServiceDomain + + "' to a DNS name. TLS X.509 certificate validiation may not be possible.", + e); + xmppServiceDomainDnsName = null; + } + this.xmppServiceDomainDnsName = xmppServiceDomainDnsName; + hostAddress = builder.hostAddress; host = builder.host; port = builder.port; @@ -201,6 +221,17 @@ public abstract class ConnectionConfiguration { return xmppServiceDomain; } + /** + * Returns the XMPP service domain as DNS name if possible. Note that since not every XMPP address domainpart is a + * valid DNS name, this method may return null. + * + * @return the XMPP service domain as DNS name or null. + * @since 4.3.4 + */ + public DnsName getXmppServiceDomainAsDnsNameIfPossible() { + return xmppServiceDomainDnsName; + } + /** * Returns the TLS security mode used when making the connection. By default, * the mode is {@link SecurityMode#ifpossible}. From f60e4055ec529f0b8160acedf13275592ab10a4b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 16 May 2019 14:09:05 +0200 Subject: [PATCH 4/5] Use ACE representation of XMPP domain on certificate verification This is based on the patch provided by Georg Lukas, modified to take XMPP domain names that can not be represented as DNS names into account. See https://github.com/Flowdalic/Smack/pull/23/commits/c42d2eea24bc86d9de5da398d341f6085a50dd33#r269250137 Fixes SMACK-870. --- .../smack/tcp/XMPPTCPConnection.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index a08221ddb..0329ef4b1 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -141,6 +141,7 @@ import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; import org.jxmpp.util.XmppStringUtils; +import org.minidns.dnsname.DnsName; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -861,8 +862,27 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { final HostnameVerifier verifier = getConfiguration().getHostnameVerifier(); if (verifier == null) { throw new IllegalStateException("No HostnameVerifier set. Use connectionConfiguration.setHostnameVerifier() to configure."); - } else if (!verifier.verify(getXMPPServiceDomain().toString(), sslSocket.getSession())) { - throw new CertificateException("Hostname verification of certificate failed. Certificate does not authenticate " + getXMPPServiceDomain()); + } + + final String verifierHostname; + { + DnsName xmppServiceDomainDnsName = getConfiguration().getXmppServiceDomainAsDnsNameIfPossible(); + // Try to convert the XMPP service domain, which potentially includes Unicode characters, into ASCII + // Compatible Encoding (ACE) to match RFC3280 dNSname IA5String constraint. + // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=280839#c1 + if (xmppServiceDomainDnsName != null) { + verifierHostname = xmppServiceDomainDnsName.ace; + } + else { + LOGGER.log(Level.WARNING, "XMPP service domain name '" + getXMPPServiceDomain() + + "' can not be represented as DNS name. TLS X.509 certificate validiation may fail."); + verifierHostname = getXMPPServiceDomain().toString(); + } + } + if (!verifier.verify(verifierHostname, sslSocket.getSession())) { + throw new CertificateException( + "Hostname verification of certificate failed. Certificate does not authenticate " + + getXMPPServiceDomain()); } // Set that TLS was successful From 2ceadc0de106a25012c5bcae1665a96764006d4f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 16 May 2019 16:50:47 +0200 Subject: [PATCH 5/5] Introduce verificationSuccessful boolean --- .../java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 0329ef4b1..405b06d23 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -879,7 +879,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { verifierHostname = getXMPPServiceDomain().toString(); } } - if (!verifier.verify(verifierHostname, sslSocket.getSession())) { + + final boolean verificationSuccessful; + // Verify the TLS session. + verificationSuccessful = verifier.verify(verifierHostname, sslSocket.getSession()); + if (!verificationSuccessful) { throw new CertificateException( "Hostname verification of certificate failed. Certificate does not authenticate " + getXMPPServiceDomain());