Here is a case study showing how I implemented XMPP Client Certificate Authentication with Openfire.
User “Andrew” installs a Windows XMPP Client along with a certificate signed by the local Certification Authority.
The certificate has a private key and owner designated as “CNemail@example.com”.
The first time Andrew runs the XMPP Client, he gets presented with a dialog to enter JID.
He enters “firstname.lastname@example.org”, hits “Login” button and after a short delay, is
presented with a roster containing mydomain.local contacts.
The XMPP Client uses Jivesoftware Smack library v4.1.4.
The Openfire XMPP Server v3.10.0 is hosted on Linux box “mychat”.
The Server listens for XMPP clients on port 5222 and requires TLS security for all connections.
The Openfire sole SASL Mechanism to be employed is “EXTERNAL”.
Set up keystore and truststore following instructions http://www.javacodegeeks.com/2015/02/secure-openfire-xmpp-server.html.
This describes how to install Certificate trust chain in both the the keystore and truststore.
The client.truststore file co-located with keystore and truststore must also contain the Certificate trust chain.
BEWARE: Use the default “changeit” keystore password initially to avoid issues with logging in to the admin console after making these changes.
Also, if on Linux, ensure the client.truststore, keystore and truststore files are owned by the Openfire user.
These are what I believe are the significant property settings for Client Certificate Authentication in this scenario:
xmpp.client.cert.policy = needed
xmpp.client.certificate.accept-selfsigned = false
xmpp.client.certificate.verify = true
xmpp.client.certificate.verify.chain = true
xmpp.client.certificate.verify.root = true
xmpp.client.certificate.verify.validity = true
xmpp.client.tls.policy = true
xmpp.domain = mychat.mydomain.local
xmpp.socket.ssl.active = true
sasl.mechs = EXTERNAL
In Security Settings - Client Connection Security: Select “Required”.
Note I also had an “xmpp.client.certificate.crl” property set but this appears to be optional judging from the code.
Certificate Revocation Lists are important for production systems.
Turn on SSL debugging on the client using Java VM argument “-Djavax.net.debug=ssl”. If the Openfire configuration is correct,
you will see the “mydomain” CA Certificate listed during SSL Handshaking under the CertificateRequest Cert Authorities:
Cert Types: RSA, DSS, ECDSA
matching alias: email@example.com
*** Certificate chain
chain  = [
If the CA Certificate is missing, then a “bad_certificate” error is reported.
The same error is reported if the client certificate is missing from the client application keystore or
the keystore is omitted when setting up the SSL Context. This problem can be determined from the debug log
by whether there is a line at the start of the log containing something like “found key for : firstname.lastname@example.org”.
If the certificate chain is missing from client.truststore, then there is NullPointerException generated from within the SSL implementation code.
If the certificate chain is missing from trustore, then this error occurs after successful SSL Handshake completion:
org.jivesoftware.util.CertificateManager - Path builder: unable to find valid certification path to requested target
Here is a routine to create an XMPPTCPConnectionConfiguration object which can be used as a guide:
private XMPPTCPConnectionConfiguration getConfiguration(
String host /* eg. “mychat.mydomain.local” */,
String keypass /* Keystore password */ )
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
// Allow empty password
// Host and service name are the same. Port is 5222 by default.
// JKS with private key placed in home directory
File keystorePath = new File(System.getProperty(“user.home”), “andrew.mychat.jks”);
// Create SSLContext same as Openfire ie. the “TLSv1”
SSLContext sslContext = SSLContext.getInstance( “TLSv1” );
KeyStore ks = KeyStore.getInstance(“JKS”);
ks.load(new FileInputStream(keystorePath), keypass.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(“SunX509”);
KeyManager kms = kmf.getKeyManagers();
sslContext.init(kms, null, new java.security.SecureRandom());
XMPPTCPConnectionConfiguration config = configBuilder.build();
Note that the client keystore contains the certificate chain and this is particularly important if there are intermediate CA certificates in the chain.
The most important thing I want to say is that Client Certificate Authentication does work on Openfire V3.10 for TLS on port 5222.
I failed to get it working until I followed the keystore and truststore setup procedure on the javacodegeeks site.
Note that “xmpp.client.certificate.accept-selfsigned = false” means self-signed client certificates are not supported.
That is not to there may be a work-around, but the designers of SSL were keen to prevent “man-in-middle” attacks and
self-signed certificates break the spirit of their intentions.