javasslmirth

Add certificate to Mirth Keystore


This seems like it should be a simple thing to do. I'd like to be able to trust certs coming from services Mirth depends on without modifying the global Java cert store (or dropping a few grand per instance for the SSL plugin). I've tried the following:

Generate my own keystore:

Keytool commands:

keytool -genkey -keystore appdata\my.jks -storetype PKCS12 -keyalg RSA -keysize 2048 -storepass xxxxxxxx
keytool -importcert -alias my-ca-cert -file myCaCert.pem -keystore appdata\my.jks -trustcacerts -storepass xxxxxxxx
keytool -importcert -alias my-server-cert -file myServerCert.pem -keystore appdata\my.jks -trustcacerts -storepass xxxxxxxx

Mirth.properties:

keystore.path = ${dir.appdata}/my.jks
keystore.storepass = xxxxxxxx
keystore.keypass = xxxxxxxx
keystore.type = pkcs12

In this instance Mirth completely fails to start. First error from the log is

java.io.IOException: Invalid keystore format
  at com.sun.crypto.provider.JceKeyStore.engineLoad(JceKeyStore.java:724)
  at java.security.KeyStore.load(Unknown Source)
  at com.mirth.connect.server.MirthWebServer.createSSLConnector(MirthWebServer.java:370)
  at com.mirth.connect.server.MirthWebServer.<init>(MirthWebServer.java:150)
  at com.mirth.connect.server.Mirth.startWebServer(Mirth.java:385)
  at com.mirth.connect.server.Mirth.startup(Mirth.java:265)
  at com.mirth.connect.server.Mirth.run(Mirth.java:154)

Update Mirth built-in keystore:

Keytool commands:

keytool -importcert -alias my-ca-cert -file myCaCert.pem -keystore appdata\keystore.jks -trustcacerts -storetype jceks -storepass xxxxxxxx
keytool -importcert -alias my-server-cert -file myServerCert.pem -keystore appdata\keystore.jks -trustcacerts -storetype jceks -storepass xxxxxxxx

Mirth.properties:

keystore.path = ${dir.appdata}/keystore.jks
keystore.storepass = xxxxxxxx
keystore.keypass = xxxxxxxx
keystore.type = JCEKS

In this instance Mirth completely starts but the server certs are not considered valid. Error log is

DETAILS:    JavaException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  at 69352923-b68f-4e96-95a3-ad7681a7f3c1_Deploy:112 (doScript)
  at 69352923-b68f-4e96-95a3-ad7681a7f3c1_Deploy:118
  at com.mirth.connect.server.util.javascript.JavaScriptUtil.executeScript(JavaScriptUtil.java:547)
  at com.mirth.connect.server.util.javascript.JavaScriptUtil$2.doCall(JavaScriptUtil.java:379)
  at com.mirth.connect.server.util.javascript.JavaScriptTask.call(JavaScriptTask.java:113)
  at java.util.concurrent.FutureTask.run(Unknown Source)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
  at java.lang.Thread.run(Unknown Source)

Update the Java global keystore

Keytool commands:

keytool.exe -importcert -alias my-ca-cert -file myCaCert.pem -keystore cacerts -storepass xxxxxxxx
keytool.exe -importcert -alias my-server-cert -file myServerCert.pem -keystore cacerts -storepass xxxxxxxx

Mirth.properties: (same as above)

keystore.path = ${dir.appdata}/keystore.jks
keystore.storepass = xxxxxxxx
keystore.keypass = xxxxxxxx
keystore.type = JCEKS

This works but is not desirable because it complicates deployments (we have no control over customer environment), and I'm not confident that Java upgrades wouldn't simply overwrite the store.


Solution

  • Through way too much trial and error here's what I was able to learn:

    1. Native Mirth senders/receivers themselves use the Mirth Keystore defined in Mirth.properties. Importing certs as described above will work for these channels.

    2. If you're using the Rhino engine (e.g. Java/JavaScript) to send/receive http requests, the Mirth keystore is ignored and the global Java store is used. Again, the process described above works. Since my certs come from Windows it turns out I was able to simplify a bit by adding -Djavax.net.ssl.trustStoreType=WINDOWS-ROOT to Mirth.properties and not have my field techs futzing around with Java's keytool

    The reason I didn't see the Mirth channels working initially is because my channel's deploy script obtains an access token from an auth provider, and I didn't think to test the channel sender independently. I did not think it would matter whether I was doing things programmatically or configuring channels through the UI, but, well, that's Mirth for you. :/

    Anyway, hopefully this will help someone, someday.