This technique relies on the MINA SSL I/O filter.
The default usage of SSL is very simple. Just add the following setting to your QFJ settings file.
SocketUseSSL=YThis setting must be used for both acceptors and initiators. If you need to use a specific SSL certificate, configure your session like below.
SocketUseSSL=Y SocketKeyStore=[your key store path] SocketKeyStorePassword=[your key store password]If certificates require authentication additional settings must be provided.
SocketTrustStore=[your trust store path] SocketTrustStorePassword=[your trust store password]Acceptor certificates are always authenticated by the initiator. Authenticating client certificates require the following setting.
NeedClientAuth=YExample acceptor configuration with client certificate authentication.
[DEFAULT] StartTime=00:00:00 EndTime=00:00:00 ReconnectInterval=2 ConnectionType=acceptor HeartBtInt=30 SocketConnectProtocol=SOCKET SocketAcceptHost=localhost # SSL properties SocketUseSSL=Y CipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA EnabledProtocols=TLSv1.2 SocketKeyStore=acceptor.keystore SocketKeyStorePassword=password NeedClientAuth=Y [SESSION] BeginString=FIX.4.4 DataDictionary=FIX44.xml SocketAcceptPort=12341 TargetCompID=ZULU1 SenderCompID=ALFA1 # SSL properties SocketTrustStore=acceptor1.truststore SocketTrustStorePassword=password [SESSION] BeginString=FIX.4.4 DataDictionary=FIX44.xml SocketAcceptPort=12342 TargetCompID=ZULU2 SenderCompID=ALFA2 # SSL properties SocketTrustStore=acceptor2.truststore SocketTrustStorePassword=passwordExample initiator configuration.
[DEFAULT] StartTime=00:00:00 EndTime=00:00:00 ReconnectInterval=2 ConnectionType=initiator HeartBtInt=30 SocketConnectProtocol=SOCKET SocketConnectHost=localhost SocketConnectPort=12341 # SSL properties SocketUseSSL=Y CipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA EnabledProtocols=TLSv1.2 SocketKeyStore=initiator1.keystore SocketKeyStorePassword=password SocketTrustStore=initiator1.truststore SocketTrustStorePassword=password [SESSION] BeginString=FIX.4.4 DataDictionary=FIX44.xml TargetCompID=ALFA1 SenderCompID=ZULU1Also see the tests in
quickfix.mina.ssl.SecureSocketTest and quickfix.mina.ssl.SSLCertificateTest.
By default, QuickFIX/J loads the key and trust stores named in the settings from the file system or
classpath. An application can instead supply the SSLContext itself through an
SSLContextProvider, e.g. when the stores come from a secrets manager and should stay in
memory. For example, with stores provided as Base64-encoded environment variables:
char[] password = System.getenv("FIX_KEYSTORE_PASSWORD").toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new ByteArrayInputStream(Base64.getMimeDecoder().decode(System.getenv("FIX_KEYSTORE_B64"))), password);
KeyStore trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(new ByteArrayInputStream(Base64.getMimeDecoder().decode(System.getenv("FIX_TRUSTSTORE_B64"))),
System.getenv("FIX_TRUSTSTORE_PASSWORD").toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SocketInitiator initiator = SocketInitiator.newBuilder()
// ... application, store factory, settings
.withSSLContextProvider(sslConfig -> sslContext)
.build();
The provider is set with withSSLContextProvider on the builders of
SocketInitiator, SocketAcceptor and their threaded variants; without it, the
configured stores are loaded as before. The provider receives the
SSLConfig of the session or acceptor address, so it can return different contexts, e.g. a
different client certificate per counterparty, and delegate to
SSLContextFactory.getInstance(sslConfig) for stores that should still be loaded from files.
SocketUseSSL=Y is still required. Only the context comes from the provider; protocols,
cipher suites, NeedClientAuth, SNI and endpoint identification are still applied from the
settings, while store settings are not used.GeneralSecurityException or returns null, the session
(initiator) or listening address (acceptor) fails to initialize, subject to
ContinueInitializationOnError. There is no implicit fallback to the default behavior.SSLContextFactory have their trust managers wrapped so that a
RuntimeException thrown during certificate validation is reported as a
CertificateException. A supplied context is used as is; wrap its trust managers with
X509TrustManagerWrapper.wrap(...) to get the same behaviour.