Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Examples/Executor/executor_ssl.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ ScreenLogShowEvents=Y
SSLEnable=Y
# It is recommended to install the certificate and refer to it by name instead of using filename + password
SSLCertificate=../QuickFixn-TestServer.pfx
SSLCertificatePassword=QuickFixn-TestServer
SSLCertificatePassword=qfnpass123
# For production refer to certificate by name instead: SSLCertificate=CN=QuickFixn-TestServer
SSLCACertificate=../QuickFixn-TestCA.cer
SSLCheckCertificateRevocation=N
SSLProtocols=Default

[SESSION]
BeginString=FIX.4.4
Expand Down
10 changes: 10 additions & 0 deletions Examples/GenerateKeys/Examples.GenerateKeys.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
17 changes: 17 additions & 0 deletions Examples/GenerateKeys/GenerateKeys.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
$rootCert = New-SelfSignedCertificate -Subject "CN=QuickFixn-TestCA" -Type Custom -KeyUsage CertSign, CRLSign, DigitalSignature -SuppressOid "2.5.29.37" -KeyLength 2048 -NotAfter (Get-Date).AddDays(30)

$rootCertPath = "QuickFixn-TestCA.cer"
Export-Certificate -Cert $rootCert -FilePath $rootCertPath

$serverCert = New-SelfSignedCertificate -Subject "CN=QuickFixn-TestServer" -DnsName localhost, 127.0.0.1 -Signer $rootCert -KeyUsage DigitalSignature, KeyEncipherment -TextExtension "2.5.29.37={text}1.3.6.1.5.5.7.3.1" -KeyLength 2048 -NotAfter (Get-Date).AddDays(5)
$serverCertPath = "QuickFixn-TestServer.pfx"
$password = ConvertTo-SecureString -String "qfnpass123" -Force -AsPlainText
Export-Certificate -Cert $serverCert -FilePath "QuickFixn-TestServer.cer"
Export-PfxCertificate -Cert $serverCert -FilePath $serverCertPath -Password $password


$clientCert = New-SelfSignedCertificate -Subject "CN=QuickFixn-TestClient" -DnsName localhost, 127.0.0.1 -Signer $rootCert -KeyUsage DigitalSignature, KeyEncipherment -TextExtension "2.5.29.37={text}1.3.6.1.5.5.7.3.2" -KeyLength 2048 -NotAfter (Get-Date).AddDays(5)
$clientCertPath = "QuickFixn-TestClient.pfx"
$password = ConvertTo-SecureString -String "qfnpass123" -Force -AsPlainText
Export-Certificate -Cert $clientCert -FilePath "QuickFixn-TestClient.cer"
Export-PfxCertificate -Cert $clientCert -FilePath $clientCertPath -Password $password
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works in an elevated prompt on windows.
powershell -noexit -executionpolicy bypass -File .\GenerateKeys.ps1

79 changes: 79 additions & 0 deletions Examples/GenerateKeys/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

const string CaCertificatePath = "..\\..\\..\\..\\QuickFixn-TestCA.cer";
const string ServerPfxCertificatePath = "..\\..\\..\\..\\QuickFixn-TestServer.pfx";
const string ClientPfxCertificatePath = "..\\..\\..\\..\\QuickFixn-TestClient.pfx";

const string PfxPassword = @"qfnpass123";

static X509Certificate2 CreateCACertificate()
{
using var rsa = RSA.Create();
var request = new CertificateRequest("CN=QuickFixn-TestCA", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.DigitalSignature, true));

X509Certificate2 certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddDays(30));
return certificate;
}

static X509Certificate2 CreateServerCertificate(X509Certificate2 caCertificate)
{
using var rsa = RSA.Create();
using (RSA caPrivateKey = caCertificate.GetRSAPrivateKey())

Check warning on line 25 in Examples/GenerateKeys/Program.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 25 in Examples/GenerateKeys/Program.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
{
var request = new CertificateRequest($"CN=QuickFixn-TestServer", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, true));

var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName("localhost");
sanBuilder.AddIpAddress(IPAddress.Loopback);
request.CertificateExtensions.Add(sanBuilder.Build());

var enhancedKeyUsages = new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1"), // OID for Server Authentication
};
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(enhancedKeyUsages, true));

X509Certificate2 certificate = request.Create(caCertificate, DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddDays(5), [0, 0, 0, 0, 0, 0, 0, 1]);
return certificate.CopyWithPrivateKey(rsa);
}
}

static X509Certificate2 CreateClientCertificate(X509Certificate2 caCertificate)
{
using var rsa = RSA.Create();
using (RSA caPrivateKey = caCertificate.GetRSAPrivateKey())

Check warning on line 50 in Examples/GenerateKeys/Program.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 50 in Examples/GenerateKeys/Program.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
{
var request = new CertificateRequest($"CN=QuickFixn-TestClient", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, true));

var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName("localhost");
sanBuilder.AddIpAddress(IPAddress.Loopback);
request.CertificateExtensions.Add(sanBuilder.Build());

var enhancedKeyUsages = new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.2") // OID for Client Authentication
};
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(enhancedKeyUsages, true));

X509Certificate2 certificate = request.Create(caCertificate, DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddDays(5), [0, 0, 0, 0, 0, 0, 0, 2]);
return certificate.CopyWithPrivateKey(rsa);
}
}

var caCertificate = CreateCACertificate();
File.WriteAllBytes(CaCertificatePath, caCertificate.Export(X509ContentType.Cert));

var serverCertificate = CreateServerCertificate(caCertificate);
File.WriteAllBytes(ServerPfxCertificatePath, serverCertificate.Export(X509ContentType.Pfx, PfxPassword));

var clientCertificate = CreateClientCertificate(caCertificate);
File.WriteAllBytes(ClientPfxCertificatePath, clientCertificate.Export(X509ContentType.Pfx, PfxPassword));
5 changes: 3 additions & 2 deletions Examples/TradeClient/tradeclient_ssl.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ ResetOnLogon=Y

# It is recommended to install the certificate and refer to it by name instead of using filename + password
SSLCertificate=../QuickFixn-TestClient.pfx
SSLCertificatePassword=QuickFixn-TestClient
SSLCertificatePassword=qfnpass123
# For production refer to certificate by name instead: SSLCertificate=CN=QuickFixn-TestClient
SSLServerName=QuickFixn-TestServer
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key Resolution really cares about Subject Alternative Names

SSLCACertificate=../QuickFixn-TestCA.cer
SSLCheckCertificateRevocation=N
SSLProtocols=Default
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use SSLProtocols=Default instead of SSLProtocols=None to let the OS pick the best one.


[SESSION]
# inherit ConnectionType, ReconnectInterval and SenderCompID from default
Expand Down
10 changes: 10 additions & 0 deletions QuickFIXn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuickFix", "QuickFIXn\Quick
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{755A0272-0599-4729-A519-AEDDF7DA36D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples.GenerateKeys", "Examples\GenerateKeys\Examples.GenerateKeys.csproj", "{308AF5BC-87E1-48EB-9542-EC53B13CD503}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.Executor", "Examples\Executor\Examples.Executor.csproj", "{54B02E22-AD44-444E-BA4E-4DB156ABC47C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.FixToJson", "Examples\FixToJson\Examples.FixToJson.csproj", "{495CA3EF-1899-4410-B152-814ACAF44AF5}"
Expand Down Expand Up @@ -192,6 +194,14 @@ Global
{A6E267D7-CF1E-4C28-BB72-8F004E4375FC}.Release|Any CPU.Build.0 = Release|Any CPU
{A6E267D7-CF1E-4C28-BB72-8F004E4375FC}.Release|x64.ActiveCfg = Release|Any CPU
{A6E267D7-CF1E-4C28-BB72-8F004E4375FC}.Release|x64.Build.0 = Release|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Debug|Any CPU.Build.0 = Debug|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Debug|x64.ActiveCfg = Debug|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Debug|x64.Build.0 = Debug|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Release|Any CPU.ActiveCfg = Release|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Release|Any CPU.Build.0 = Release|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Release|x64.ActiveCfg = Release|Any CPU
{308AF5BC-87E1-48EB-9542-EC53B13CD503}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down