Openfire Server SSL configuration with SASL External authentication for clients using certificates

Openfire Server SSL configuration with SASL External authentication

You need the following to start with.

  • A running Openfire server
  • Certificate/keys for Openfire server, generated as above. Copy them over to the machine running the Openfire server. (Copied to geni-imf-xmpp.renci.org:/home/anirban/certs/openfire-server-certs/.)
  • The certificate of the CA (cacert.pem), generated above. Copy it over to the machine running the Openfire server. (Copied to geni-imf-xmpp.renci.org:/home/anirban/certs/ca-certs/.)

Steps:

0. Go to the web portal of the running Openfire server. Click Server -> Server Manager -> System Properties . Make sure the following properties are as follows. If you need to add a property, you can enter the property name and value in the form at the bottom and click save property. Note, paths to different keystores are relative to openfire installation (/opt/openfire)

sasl.mechs = PLAIN, EXTERNAL
xmpp.auth.anonymous = false
xmpp.client.cert.policy = wanted
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 = required

xmpp.server.certificate.accept-selfsigned = true
xmpp.server.dialback.enabled = true
xmpp.server.tls.enabled = true

xmpp.pubsub.credentials.url = http://geni-images.renci.org/images/credentials/
xmpp.pubsub.credentials.verify = true

xmpp.socket.ssl.active = true
xmpp.socket.ssl.client.truststore = resources/security/client.truststore
xmpp.socket.ssl.client.trustpass = changeit
xmpp.socket.ssl.keystore = resources/security/keystore
xmpp.socket.ssl.keypass = changeit
xmpp.socket.ssl.truststore = resources/security/truststore
xmpp.socket.ssl.trustpass = changeit

The credential url needs to be changed to wherever client credentials are stored.

1. Stop the Openfire server.

$ service openfire stop

2. Backup the current keystore and truststore, just in case. Save the following files - /opt/openfire/resources/security/keystore and /opt/openfire/resources/security/truststore

3. Since keytool will not accept the extra information in the certificate file (when using a PEM format), copy cacert.pem to another file and strip out everything apart from the lines -----BEGIN CERTIFICATE----- up to and including -----END CERTIFICATE-----.

$ cd /home/anirban/certs/ca-certs/
$ cp cacert.pem cacert-only-certPortion.pem
$ vi cacert-only-certPortion.pem  

4. Import the resulting CA certificate into Openfire truststore. You would be asked to enter password for accessing java keystores. Default password for accessing keystores is "changeit" , unless you have changed it.

$ cd /home/anirban/certs/ca-certs/
$ keytool -importcert -alias "RENCIAnirbanTestCA" -keystore /opt/openfire/resources/security/truststore -file cacert-only-certPortion.pem

5. Find out aliases of existing default openfire server certificates stored in Openfire's server keytore (/opt/openfire/resources/security/keystore). Note down the aliases.

$ keytool -list -keystore /opt/openfire/resources/security/keystore

6. Remove default certificates in Openfire's server keystore (/opt/openfire/resources/security/keystore).

$ keytool -delete -keystore keystore -alias geni-imf-xmpp.renci.org_rsa
$ keytool -delete -keystore keystore -alias geni-imf-xmpp.renci.org_dsa

7. Convert Openfire server private key from PEM format to DER format. Convert Openfire server certificate from PEM to DER format.

$ cd /home/anirban/certs/openfire-server-certs/
$ openssl pkcs8 -topk8 -nocrypt -in newkey.pem -inform PEM -out newkey.der -outform DER
$ openssl x509 -in newcert.pem -inform PEM -out newcert.der -outform DER
$ cat newcert.der > chain-newcert.der

If you had intermediate CAs, then you would have to convert the intermediate CA certs to DER format and did "cat newcert.der intercacert.der > chain-newcert.der" . But here we have only one root CA, and hence this step is not required.

8. Copy "KeyStoreImport?.java" from  http://www.nealgroothuis.name/import-a-private-key-into-a-java-keystore/ and compile it.

$ javac KeyStoreImport.java

9. Now import server cert and key generated in step 7 to Openfire server keystore.

$ java KeyStoreImport /opt/openfire/resources/security/keystore chain-newcert.der newkey.der "geni-imf-xmpp.renci.org_rsa"

Enter same passwords for keystore password and private key entry password, asked by KeyStoreImport?.

10. Do additional configuration for client certificate authentication. Convert the CA certificate (/home/anirban/certs/ca-certs/cacert.pem) from PEM format to binary DER format that is understood by keytool better. Import this CA certificate to Openfire server's client truststore.

$ cd /home/anirban/certs/ca-certs/
$ openssl x509 -in cacert.pem -inform PEM -out cacert.der -outform DER
$ keytool -importcert -keystore /opt/openfire/resources/security/client.truststore -alias RENCIAnirbanTestCA -file /home/anirban/certs/ca-certs/cacert.der -trustcacerts

NOTE: in the above example, we used the same CA that issued the xmpp server certificate for issuing client certificates. If your client certificates are issued by other CAs like the GENI CHs/ emulab/ protogeni etc, you need to import those CH certs into the client.trustore jks file. If you already have a jks file storing the certificates of the CHs, you can change the xmpp.socket.ssl.client.truststore and xmpp.socket.ssl.client.trustpass properties in the Openfire portal to point to the location of the jks file and the password to access the certificates respectively.

11. Start the Openfire server.

$ service openfire start

From the web interface, geni-imf-xmpp.renci.org:9090, Server->Sever Settings -> Server Certificates, you would see the imported server certificate. To turn Openfire debugging on, go to Server-> Server Manager -> Logs and click on the radio button for enabling Debug log. The Openfire logs are in /opt/openfire/logs - info.log, warn.log and debug.log

12. On the Openfire portal, click User/Groups -> Users -> Create New user and add a new user with Username/JID same as the common name (CN) of the XMPP user certificate. The CN should have been provided during creation of XMPP user certificate. This step is optional if client accounts are created on the fly.

Testing SSL handshake with client certificates

1. Make sure that the SSL port (5223) is open on the machine hosting the Openfire server. If, not change firewall rules to open 5223.

2. Use openssl s_client to test SSL handshake. Supply the XMPP server IP:SSL port, client certificate and key as arguments. In the output, you must check whether the server is sending a certificateRequest to the client. You must also check whether the server is sending "Acceptable client certificate CA names" for acceptable client certs. Details on understanding the openssl output and SSL handshake details can be found at  http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html

$ openssl s_client -connect geni-imf-xmpp.renci.org:5223 -showcerts -cert /home/anirban/user-certs/newcert.pem  -key /home/anirban/user-certs/newkey.pem  -msg -state -debug

Testing SSL and SASL external authentication with client certificates using Swift XMPP IM client

1. Download and install Swift client from  http://swift.im/download/

2. Copy the XMPP user certificate and keys to the machine running the Swift IM client. You would need the PKCS12 version of the certificate - xmpp-user-renci2.p12 in our example. This client needs the name of the certificate to end with .cert . So rename xmpp-user-renci2.p12 to xmpp-user-renci2.p12.cert .

3. Start the client. For username, provide the JID, which is also the CN of the client certificate along with the XMPP domain name. In our example, it is xmpp-user-renci2@…

4. Click on the Golden circular button next to password field and load the xmpp-user-renci2.p12.cert file.

5. In the password field, provide the private key passphrase for the client's private key. Now, you should be able to be authenticated and logged in.

We have also tested with the Pidgin client, compiled from the im.pidgin.cpw.ljfisher.ssl_client_auth branch, as described in  http://developer.pidgin.im/wiki/Openfire%20Client%20SSL%20Authentication%20How-to . Modulo an error while importing a pkcs12 certificate during addition of client certificate, it works. Using opelssl's pkcs8 utility, build the pkcs8 private key and that needs to be manually installed in ~/.purple/privatekeys/x509/user/ under the same file name as in ~/.purple/certificates/x509/user/ .

Testing SASL external authentication with client certificates using Spark XMPP IM client

1. Download and install Spark client from  http://www.igniterealtime.org/projects/spark/

2. Copy the XMPP user certificate and keys to the machine running the Spark IM client. You would need the PKCS12 version of the certificate - xmpp-user-renci2.p12 in our example. Then use Portecle, available as a Java webstart application at  http://portecle.sourceforge.net to generate a Java keystore from the PKCS12 certificate. On Portecle, a. File -> New -> Select JKS. b. Click Import key pair -> point it to the location of PKCS12 certificate (xmpp-user-renci2.p12 in our eg.) -> Supply the password for private key -> Supply the keystore password SAME as this password. Also, for alias/name, provide the name of the user, xmpp-user-renci2 in our eg. c. Click Save keystore and store the Java keystore. The location of this file needs to be specified in the next sections.

3. Start the Spark client. For username, provide the JID, which is also the CN of the client certificate. In our example, it is xmpp-user-renci2 . For password, you need to give the passphrase for your private key.

4. Click on Advanced -> General. Check "Automatically discover server and port". "Use Old-style SSL" needs to be unchecked. Click on PKI tab. Check "Use PKI authentication" . Select type of keystore as Java keystore. Point keystore and truststore locations to the Java keystore file generated in step 2. Supply password provided in step 2 in the field that says "Trust store password" . Click ok.

5. Click Login and you should be authenticated. Remember, Spark uses TLS on standard port 5222 for certificate based authentication.

Creating an User account on the XMPP server with Spark

Since the JID needs to exist on the server for certificate based authentication, it is essential that we can create an account on the XMPP server first using an IM client. Using Spark, do the following.

1. Start the Spark client. Click on Advanced tab. Make sure "Automatically discover server and port" is checked and "Use Old-style SSL" is unchecked on the General tab, and "Use PKI authentication" is unchecked on the PKI tab. Click ok.

2. Click on "Accounts#" and provide the JID of the user, a password (which is preferably different from the private key password) and select XMPP server name (geni-imf-xmpp.renci.org in our example). Then click on "Create account"

Notes on using Spark for normal login using SASL PLAIN mechanism with or without SSL

For normal login using SASL PLAIN without SSL and using standard port, make sure "Automatically discover server and port" is checked and "Use Old-style SSL" is unchecked on the Advanced->General tab, and "Use PKI authentication" is unchecked on the Advanced->PKI tab. Provide JID, normal password and server name and click login.

For login using no certificates, i.e. using SASL PLAIN , but with SSL using port 5223, make sure "Automatically discover server and port" is unchecked and "Use Old-style SSL" is checked on the Advanced->General tab. Also, provide the server name and port (5223) on Advanced->General tab. Make sure "Use PKI authentication" is unchecked on the Advanced->PKI tab. Provide JID, normal password and server name and click login.