2

Been bashing my head against the wall for a while on this one.

I'm trying to setup a quickfix initiator to establish an SSL connection to a Bloomberg FIX server. And based on the docs, I thought this would be relatively straight forward to achieve. However, I can't seem to figure out where I'm going wrong. Any assistance would be super appreciated.

Things to note:

  • I'm using the dotnet cli to create, build and run the project
  • Bloomberg has provided us with certificates in 3 formats: JKS, PEM & PKCS12
  • I've gone ahead and generated the resulting mycerts.cer file from the provided PKCS12 certificate using the process described in this S/O comment (Convert PFX to CER). However, the error message is the same whether or not this step is performed
  • It also might be worth noting that I've previously managed to establish and maintain the secure connection to the bloomberg FIX server using the python version of quickfix as well as stunnel (to handle the SSL connection). However I now need to remove the dependency on stunnel, hence the attempted switch to quickfix/n

The setup:

Here's the current .csproj file

<Project Sdk="Microsoft.NET.Sdk">

  <ItemGroup>
    <ProjectReference Include="..\Heimdall.AppTest\Heimdall.AppTest.csproj" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="QuickFIXn.Core" Version="1.10.0" />
    <PackageReference Include="QuickFIXn.FIX4.4" Version="1.10.0" />
  </ItemGroup>

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Copy SourceFiles=".\FIX44.xml" DestinationFolder="$(TargetDir)" />
    <Copy SourceFiles=".\bbgEtomsClient.cfg" DestinationFolder="$(TargetDir)" />
    <Copy SourceFiles=".\pkcs12\cert.pfx" DestinationFolder="$(TargetDir)" />
    <Copy SourceFiles=".\openssl\mycerts.cer" DestinationFolder="$(TargetDir)" />
  </Target>

</Project>

And here's the actual bbgEtomsClient.cfg file that is used by the initiator application (based off this issue)

[DEFAULT]
ApplicationID=client
ConnectionType=initiator
HeartBtInt=60
ResetOnLogon=N
ResetSeqNumFlag=N
FileStorePath=incoming
FileLogPath=outgoing
ScreenLogShowIncoming=Y
ScreenLogShowOutgoing=Y
ScreenLogShowEvents=Y
UseDataDictionary=Y
DataDictionary=FIX44.xml
SocketConnectPort=xxxx
SocketConnectHost=xxx.xx.xxx.xx (same as SSLServerName)
SSLEnable=Y
SSLProtocols=Tls12
SSLCheckCertificateRevocation=N
SSLValidateCertificates=N
SSLServerName=xxx.xx.xxx.xx
SSLCertificate=cert.pfx
SSLCertificatePassword=<PfxCertPassword>
SSLCACertificate=mycerts.cer

[SESSION]
BeginString=FIX.4.4
SenderCompID=<SenderCompID>
TargetCompID=<TargetCompID>
StartTime=00:00:01
EndTime=23:59:59

And here's the super basic program.cs

using System;
using System.Collections.Generic;
using System.Text;
using QuickFix;
using QuickFix.Fields;
using QuickFix.Transport;
using System.Linq;

namespace Heimdall.App
{
    public class MyQuickFixApp : IApplication
    {
        public void FromApp(Message msg, SessionID sessionID) 
        {
            Console.WriteLine("IN:<FromApp>  " + msg); 
        }
        public void OnCreate(SessionID sessionID) { }
        public void OnLogout(SessionID sessionID) { }
        public void OnLogon(SessionID sessionID) { }
        public void FromAdmin(Message msg, SessionID sessionID) 
        {
            Console.WriteLine("IN:<FromAdmin>  " + msg); 
        }
        public void ToAdmin(Message msg, SessionID sessionID) 
        {
            Console.WriteLine("OUT:<ToAdmin>  " + msg); 
        }
        public void ToApp(Message msg, SessionID sessionID) 
        {
            Console.WriteLine("IN:<ToApp>  " + msg); 
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SessionSettings settings = new SessionSettings("bbgEtomsClient.cfg");
            IApplication myApp = new MyQuickFixApp();
            IMessageStoreFactory storeFactory = new FileStoreFactory(settings);
            ILogFactory logFactory = new FileLogFactory(settings);
            SocketInitiator initiator = new SocketInitiator(
                myApp,
                storeFactory,
                settings,
                logFactory);

            try
            {


                initiator.Start();
                while (true)
                {
                    System.Threading.Thread.Sleep(2000);
                }
                

            }
            catch (System.Exception e)
            {
                Console.WriteLine("==FATAL ERROR==");
                Console.WriteLine(e.ToString());
                initiator.Stop();
            }

        }
    }
}

The errors:

When the project is run using the setup listed above, the following error is observed:

20210107-13:23:00.242 : Unexpected exception: System.ArgumentNullException: Value cannot be null. (Parameter 'value')
   at System.Collections.CollectionBase.OnValidate(Object value)
   at System.Security.Cryptography.X509Certificates.X509CertificateCollection.OnValidate(Object value)
   at System.Collections.CollectionBase.System.Collections.IList.Add(Object value)
   at System.Security.Cryptography.X509Certificates.X509CertificateCollection.Add(X509Certificate value)
   at QuickFix.Transport.StreamFactory.SSLStreamFactory.GetClientCertificates()
   at QuickFix.Transport.StreamFactory.SSLStreamFactory.CreateClientStreamAndAuthenticate(Stream innerStream)
   at QuickFix.Transport.StreamFactory.CreateClientStream(IPEndPoint endpoint, SocketSettings settings, ILog logger)
   at QuickFix.SocketInitiatorThread.SetupStream()
   at QuickFix.Transport.SocketInitiator.SocketInitiatorThreadStart(Object socketInitiatorThread)

And from what I can understand it looks like my error might be related to this issue (.NetCore3.1 and QuickFIXn problem #571)

squircle
  • 21
  • 2
  • The certificate is text. So open certificate and check the date. Looks like the date on certificate has expired. – jdweng Jan 07 '21 at 14:26
  • So I just opened the cert, and it say's it's valid until 2022. – squircle Jan 07 '21 at 14:47
  • I read ValiDATE and thought it was referring to date. What machine are you using? Old versions of Net/Core was doing TLS. Newer version Net/Core are using the operating system to do TLS. So I believe netcore 3.1 is using operating system. So you may have an older version of Operating System (and or Kernel) that isn't supporting the Encryption Mode. The certificate should have in ASCII the encryption mode. Then check Wiki to see if encryption mode is supported in TLS 1.2 (you may need 1.3) : https://en.wikipedia.org/wiki/Transport_Layer_Security. – jdweng Jan 07 '21 at 15:58
  • I'm currently using a windows 10 machine with netcore 3.1. I'm gonna go ahead and try rollback to netcore 2.2 and see what happens. Thanks for your insight man! Appreciate it. – squircle Jan 07 '21 at 16:22
  • I don't think that will work. Do you have all the updates in Windows 10? What type of machine are you running? There is a kernel below Windows and kernel needs be compatible. – jdweng Jan 07 '21 at 16:42

0 Answers0