Technical Blog Post
Maximo Anywhere, MobileFirst and SSL : REDUX
A couple of years ago I wrote a basic SSL configuration doc for Maximo Anywhere, at the time of the document I was just showing how to configure the SSL Certificates with the run time keystore. This certificate is used for the MobileFirst adapter to communicate to the back-end server through SSL ( Maximo ). The problem with this is there is more configuration that may need to be done for SSL and MobileFirst if the plan is an end to end SSL solution.
Although this configuration is not specific to Maximo Anywhere it is something we should still go over. In this blog I will do my best to outline the process of configuring Maximo Anywhere with a secured Maximo server as well as a secured MobileFirst server hosted on a different machine.
So to start your Maximo is likely already configured with SSL if you are reading this document, so I'm not going to go over configuring the Maximo WebSphere server, what we will start with is what I ran through in my last document with some added details, as well as configuring MobileFirst.
Securing the connection between the MobileFirst adapter and Maximo
1. Our scenario starts with maximo secured and our mobile devices trying to connect via SSL without any configuration. Before we do anything on the Anywhere side we need to ensure the WebSphere server MobileFirst and our run time is deployed to can trust our Maximo servers certificates. We can do this by importing our Maximo signer certificate to our NodeDefaultTrustStore on the MobileFirst server and the easiest way to do this is to retrieve directly from the Maximo url.
From the WebSphere console Expand Security - Click on SSL Certificate and key management - > Keystores and Certificates - > NodeDefaultTrustStore - > Signer certificates and select 'Retrieve from port'. Enter your host and the SSL enabled port in use, then provide an alias (name for the certificate in the trust store) as seen below click retrieve signer information and click apply.
A common error seen in the WebSphere logs if this step is not complete would be the following.
000000b0 WSX509TrustMa E CWPKI0022E: SSL HANDSHAKE FAILURE: A signer with SubjectDN "CN=mobile-anymaxssl.swg.usma.ibm.com" was sent from target host:port "mobile-anymaxssl.swg.usma.ibm.com:9443". The signer may need to be added to local trust store "C:/IBM/WebSphere/AppServer/profiles/ctgAppSrv01/config/cells/ctgCell01/trust.p12" located in SSL configuration alias "NodeDefaultSSLSettings" loaded from SSL configuration file "security.xml". The extended error message from the SSL handshake exception is: "PKIX path building failed: java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl could not build a valid CertPath.; internal cause is:
java.security.cert.CertPathValidatorException: The certificate issued by CN=mobile-anymaxssl.swg.usma.ibm.com, OU=SWG, O=IBM, L=London, ST=Ontario, C=CA is not trusted; internal cause is:
java.security.cert.CertPathValidatorException: Certificate chaining error".
2. Now that we have our Maximo signer certificate in our Node trust store on the MobileFirst server we need to configure MobileFirst adapter key store to validate the SSL-Client identity. We can do this by extracting the certificate from our trust store and saving it to the Anywhere build server.
From SSL certificate and key management - > Key stores and certificates - > NodeDefaultTrustStore - > Signer certificates choose the Maximo signer and click extract. Choose the path to save the x509 encoded certificate then copy it over to the Maximo Anyhwere build machine.
Once copied over to the Anywhere build machine we need to import the certificate to our key store to build in to the run time. In the IBM\Anywhere\MaximoAnywhere\server\conf\ folder re-name default.keystore to default.keystore.jks. Then import your certificate in to the key store (if your key store type is different use it's extension). Below is an example to import with both ikeyman (IBM) and Keytool (Oracle)
From the IBM\WebSphere\AppServer\java\jre\bin folder run the following command ( the default keystore password is worklight)
ikeyman.cmd -cert -add -db c:\IBM\Anywhere\MaximoAnywhere\server\conf\default.keystore.jks -pw worklight -label maximo -file c:\IBM\maximo.cer -format ascii -trust enable
From the Java\JDK<version>\jre\bin folder run
keytool -import -alias maximo -file c:\IBM\maximo.cer -keystore c:\IBM\Anywhere\MaximoAnywhere\server\conf\default.keystore.jks -pw worklight
3. Now that your certificate is imported we need to update the worklight.properties and rename the default.keystore to default.keystore.jks as seen below.
You will also want to update the adapter properties in the build.properties to use SSL if not already defined during the install.
After updating the files, rebuild the and deploy your MaximoAnywhere.war and applications, at this point you should have a working HTTP connection between the device and MobileFirst and HTTPS connection between the adapter and Maximo.
*NOTE* Before proceeding any further, ensure you update the mxe.oslc.webappurl to reflect the HTTPS protocol and SSL enabled port or some transactions may still end up being sent through HTTP.
A common error seen in the WebSphere logs when the above 3 steps are not complete would be the following, which means the keystore does not exist or contains no certificates.
FWLSE0101E: Caused by: [project MaximoAnywhere]javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-emptyjava.lang.RuntimeException: Http request failed: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
Securing the connection between MobileFirst and the Mobile Device.
The above steps outline how to have a non-secured MobileFirst server interact with a secured Maximo, however what if we want to secure MobileFirst? What is Required? How do we trust the server from the device? That is what we will cover in the next set of steps.
Now before we get started one very important thing to note is that the mobile device platforms do not allow you to trust self-signed certificates that aren't not from CA. If you have created your own certificates and the basic constraints of the certificate do not show Subject Type=CA your certificates will not be trusted and you will not be able to make the connection to MobileFirst.
Most customers configuring a production environment likely will be using certificates signed by a verified certificate authority, however when testing on your own you will need to create a CA to self-sign your certificates with. I did this using ikeyman from the WebSphere java, but it can also be done fairly easily with OPENSSL.
So I have my root certificate and and intermediate self-signed CA certificates now in my private key. The first thing I want to do is import those certificates in to my NodeDefaultKeyStore on the MobileFirst server.
From SSL Certificate and and key management - > Key stores and certificates - > NodeDefaultKeyStore - > Personal Certificates click on Import. Select the 'Key Store File' option, enter the path to your keystore, the type and the password, mine is a JKS file, so I've entered what you see below. Ensure you select the certificate alias you wish to import and click apply.
As we have only imported the certificates in to the NodeDefaultKeystore, we will need to add the signer to the CellDefaultTrustStore as we will not be changing it's default certificates. From SSL Certificate and and key management - > Key stores and certificates check the CellDefaultTrustStore and the NodeDefaultKeystore boxes and click on Exchange Signers. Add the NodeDefaultKeyStore mobilefirst signer certificate to the CellDefaultTrustStore.
Now that are have our personal certificates imported and signers exchanged we need to tell the Node to use our certificate rather then the ones bundled with WebSphere.
Again from SSL Certificate and and key management click on SSL Configurations, then select NodeDefaultSSLSettings. From here change the Default server certificate alias to your certificate as well as the client certificate alias as seen below.
Click apply and save to master configuration, then do a full synchronization on your node and restart your MobileFirst JVM. Now when you access the MobileFirst application over your SSL enabled port and protocol, you should be able to see your certificate in use. If it is using the default WAS certificate still you may want to double check the last step has been updated from default to mobilefirst or your certificate name.
Updating Build Properties and the Device.
1. Now your MobileFirst server is secured we need to update your build properties to point to the secured server, from IBM\Anywhere\MaximoAnywhere open the build.properties section and search for the following blocks.
For the *.url properties ensure the SSL enabled port is defined as well as the protocol updated to HTTPs
For the *.protocol properties change http to https
For the *.port properties change the port to the SSL enabled port.
Rebuild and deploy your applications.
2. If you are using certificates signed by a verified CA (Symantec, Verisign etc..) you will likely not have to install any certificates to your device as most CA certificates pre-exist. However if you are using a self-signed CA you will need to install the certificate to the device, if chained the root certificate will also be required. My certificates are chained so I have two certificates I need to place on the device, you can email these to yourself and install to the device under VPN and Apps, example for Android found below.
If the certificate is signed by a CA it will show up under user in security certificates on the device, if it is not signed by a CA it will end up under user certificates. At this point you should successfully be able to log in to Maximo Anywhere end to end through SSL communication.
Common Device Errors.
Any error you may see in the device logs if the above is not configured correctly is the following, which is due to no trusted certificates for the server being found on the device or the self signed certificate not being trusted by the CA.
Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found
Another error you may see from the device is the following, which is due to the level of security being used by the server. This can be corrected by updating the QOP for the NodeDefaultSSLSettings in WebSphere to use a stronger protocol such as TLS_SSLv2
09-17 21:48:54.309 670-798/? W/System.err: javax.net.ssl.SSLHandshakeException: Handshake failed
09-17 21:48:54.309 670-798/? W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:441)
09-17 21:48:54.309 670-798/? W/System.err: at android.net.SSLCertificateSocketFactory.verifyHostname(SSLCertificateSocketFactory.java:243)
09-17 21:48:54.309 670-798/? W/System.err: at android.net.SSLCertificateSocketFactory.createSocket(SSLCertificateSocketFactory.java:496)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:394)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:219)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:172)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:130)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.client.DefaultRequestDirector.executeOriginal(DefaultRequestDirector.java:1337)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:705)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:579)
09-17 21:48:54.309 670-798/? W/System.err: at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:503)
09-17 21:48:54.309 670-798/? W/System.err: at com.worklight.wlclient.WLRequestSender.run(WLRequestSender.java:47)
09-17 21:48:54.309 670-798/? W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
09-17 21:48:54.309 670-798/? W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
09-17 21:48:54.309 670-798/? W/System.err: at java.lang.Thread.run(Thread.java:818)
09-17 21:48:54.309 670-798/? W/System.err: Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x9634d480: Failure in SSL library, usually a protocol error
09-17 21:48:54.309 670-798/? W/System.err: error:100bd10c:SSL routines:ssl3_get_record:WRONG_VERSION_NUMBER (external/boringssl/src/ssl/s3_pkt.c:311 0xa9e107f7:0x00000000)
09-17 21:48:54.309 670-798/? W/System.err: at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
09-17 21:48:54.309 670-798/? W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:353)
The errors you see in the device logs will show on screen much different, the common indication there is a SSL related device error and no connection is happening to the MobileFirst server is the following.
1. As with my configuration if your certificates are chained on Maximo side, all chained certificates should be imported in to the default.keystore for the MobileFirst adapter.
2. WebSphere Liberty does not have an SSL Management interface, the keystore used exists in the ibm\
3. When using eclipse you would import your Maximo signer certificate in to the default.keystore used by the development environment (if the source is copied). The signer would also need to be imported in to the Liberty keystore in your work space used
For example : work
Just a quick recap of where certificates need to go.
1. The Maximo signer certificates should be imported in to the MobileFirst server NodeDefaultTrustStore
2. The Maximo signer certificates should be imported in to the Anywhere\MaximoAnywhere\server\conf\default.keystore and built in to the runt ime for Adapter communication to Maximo.
3. Ensure the mxe.oslc.webappurl is updated in Maximo to use HTTPS and the SSL enabled port
4. The MobileFirst server must be configured for SSL using a self-signed CA certificate, a private CA certificate or a public CA certificate and imported in to it's NodeDefaultKeystore
5. The MobileFirst certificates imported in to the NodeDefaultKeystore should be added to the CellDefaultTrustStore on the same server.
6. If the MobileFirst certificates are not signed by a Public CA, they will need to be installed to the device for VPN and Applicatinos.
This is a bit more information then I provided a couple years back, hopefully this helps a bit more, if anything needs to be added or if I run in to any new issues with SSL configuration I will keep this document updated. Questions, comments and concerns are all welcomed below.