Skip to content

Commit f3b2b96

Browse files
author
Chris Busbey
committed
introduces tls configuration
1 parent 4fb115e commit f3b2b96

File tree

10 files changed

+356
-10
lines changed

10 files changed

+356
-10
lines changed

Diff for: _test_data/ca.crt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDLzCCAhegAwIBAgIJAPGKEAYOJZ1BMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
3+
BAMMCWdvdGxzdGVzdDAeFw0xNjA4MDQxMzU4MTdaFw0yNjA4MDIxMzU4MTdaMBQx
4+
EjAQBgNVBAMMCWdvdGxzdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
5+
ggEBAKFHVRQr/yBkjSigBoYn+LAKeWLV5MPgiYGrOMJy5fj0KMTVEpERhyEfVQP8
6+
dRIOK79qFowgG4y2PoUgqZlh7yag8xvY5RTO3E/AYMQKT4E3w3Wv7SfwG5RiIYGp
7+
c5FnpTEFyXYisdbKv8lJqXm+X3jS4V458z/9j8vBN5O+q0hdHrDcxKLG2XrvkS7j
8+
w9vkN4PUyDmOIxLuSws8IALgoZ+RgeGyCIR6YepUk89PdU9dDdwXfW7d/t7H/UOm
9+
GW1/tlHPwaemFwI+WZ7NWSTyXg/w82cC1a8bVBSU2hvzKgoPC3Gcitu90AXbSe4I
10+
j9I0hWBjQluuWOaLZYjSzE2GlZMCAwEAAaOBgzCBgDAdBgNVHQ4EFgQU1YptIoNr
11+
ieOAqHc1Yi6ABH66BP0wRAYDVR0jBD0wO4AU1YptIoNrieOAqHc1Yi6ABH66BP2h
12+
GKQWMBQxEjAQBgNVBAMMCWdvdGxzdGVzdIIJAPGKEAYOJZ1BMAwGA1UdEwQFMAMB
13+
Af8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQA64DX2whJrxTdvSJX1
14+
mQ/bzHoqmT61qvTlk2qkiW7H2n9+KKKHlUp0my7b13S0DH7db9zNcnnbFLhNkoy6
15+
LQyDh4SU29PCkD8898nVHKX9KJBrHvRi/cfd/p3zpcrBGOhr/3dWlcgGx8CCUWCw
16+
u8KlWBJheD/1ljm2zuZMPq6sc/BouHrXczbtGri/cu9BQRSNGoZ4FOe37B11LjyB
17+
vhnjRINmvnUUhQT3eiqBcriyg5K/yZhDZv+sKnOyqj/3j8emcmGzLoFao4Sj3X9B
18+
Dz1tzXKGHJzyfkpQIIjegZRKIwHz2C+gxYPgjbyyvCZQH6jhiXGF9OpLrCvMmvss
19+
rRiW
20+
-----END CERTIFICATE-----

Diff for: _test_data/localhost.crt

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
Certificate:
2+
Data:
3+
Version: 3 (0x2)
4+
Serial Number:
5+
83:d2:c3:07:a1:bd:25:ad:d7:c1:5d:47:f2:c3:4b:b9
6+
Signature Algorithm: sha256WithRSAEncryption
7+
Issuer: CN=gotlstest
8+
Validity
9+
Not Before: Aug 4 14:00:05 2016 GMT
10+
Not After : Aug 2 14:00:05 2026 GMT
11+
Subject: CN=localhost
12+
Subject Public Key Info:
13+
Public Key Algorithm: rsaEncryption
14+
RSA Public Key: (2048 bit)
15+
Modulus (2048 bit):
16+
00:9a:5e:80:58:07:16:6c:e5:3d:57:5b:60:ad:27:
17+
09:fe:dc:cc:53:64:5d:b4:d3:dd:ca:c0:24:c2:51:
18+
ac:84:84:d3:27:79:a9:28:7b:d7:9b:83:ba:93:9f:
19+
e5:0b:0a:77:c4:66:55:b9:b2:67:c5:9b:a3:21:42:
20+
af:94:f6:03:6d:a8:9e:b2:42:91:99:5e:68:95:f1:
21+
02:59:4c:da:55:c1:35:d3:c2:e8:ab:dd:f0:26:18:
22+
02:11:4d:46:69:68:cd:05:2f:5d:e4:27:b1:6b:50:
23+
e5:70:01:bf:83:82:2c:0d:cc:5b:4f:6f:93:7d:ad:
24+
d6:5f:37:b7:f6:08:ab:2d:c1:1b:8d:e3:e0:85:97:
25+
55:29:2c:13:79:8d:a3:66:5f:dd:51:43:30:9e:d0:
26+
55:61:7d:18:fd:0f:7d:4a:6f:f4:d8:08:ba:3b:32:
27+
d3:b8:0c:4f:1b:c9:16:3c:71:77:1e:05:b1:fe:0a:
28+
eb:6e:e7:27:69:c5:fe:31:91:f2:05:9f:fb:6c:70:
29+
e5:7f:15:46:d9:3e:a4:39:99:d5:51:42:24:a2:63:
30+
a3:29:e8:dd:17:3f:79:73:ef:a6:ec:d8:9a:96:4f:
31+
65:30:70:40:0a:98:ad:3a:60:a2:10:c6:30:92:5c:
32+
f8:6c:c7:4e:1f:a6:b3:10:95:11:5c:2f:9b:2a:95:
33+
92:37
34+
Exponent: 65537 (0x10001)
35+
X509v3 extensions:
36+
X509v3 Basic Constraints:
37+
CA:FALSE
38+
X509v3 Subject Key Identifier:
39+
02:29:1F:26:4A:25:01:47:61:50:01:A8:B2:DB:38:53:F9:EA:8E:27
40+
X509v3 Authority Key Identifier:
41+
keyid:D5:8A:6D:22:83:6B:89:E3:80:A8:77:35:62:2E:80:04:7E:BA:04:FD
42+
DirName:/CN=gotlstest
43+
serial:F1:8A:10:06:0E:25:9D:41
44+
45+
X509v3 Extended Key Usage:
46+
TLS Web Server Authentication
47+
X509v3 Key Usage:
48+
Digital Signature, Key Encipherment
49+
Signature Algorithm: sha256WithRSAEncryption
50+
0c:69:32:44:b1:56:f0:d6:90:aa:6e:42:35:0d:f2:56:c0:58:
51+
c9:f8:4c:a7:29:de:74:06:03:85:fe:ca:c1:34:d1:1a:51:c0:
52+
aa:b8:06:bf:a0:c1:e1:1c:b7:57:74:09:53:ba:38:05:ce:8d:
53+
1a:e9:02:f9:d9:76:99:42:99:e6:57:3c:2a:00:7f:a7:1c:a7:
54+
5b:69:34:41:cd:e5:0f:35:ad:ff:c5:0f:e5:b9:ca:11:05:4b:
55+
5a:06:5d:ca:62:03:0a:5e:22:59:02:a8:9e:68:81:50:45:23:
56+
73:e6:08:e5:3c:d4:04:af:4c:c0:e2:5b:44:ea:f3:8a:11:a3:
57+
b7:3f:8b:44:f8:e6:da:b9:08:0e:2f:3c:f8:b4:7e:9f:f5:74:
58+
d2:74:3a:52:f8:8f:60:b6:79:96:7c:08:92:7d:1b:17:d3:fc:
59+
04:28:82:ab:c9:84:10:00:4f:f3:04:62:48:7d:62:f2:24:06:
60+
11:b8:ff:85:66:93:12:3b:e1:34:88:16:73:a2:c3:e3:e7:96:
61+
32:db:08:7f:86:5b:f4:4d:db:28:3f:65:11:ac:43:ed:41:be:
62+
03:ab:69:e2:bc:72:d1:1f:6c:2a:11:7c:3e:6e:e2:a4:1b:77:
63+
6f:10:ab:b2:76:d7:82:ea:10:23:5c:f1:b7:ab:07:ae:3d:05:
64+
32:1f:a6:a7
65+
-----BEGIN CERTIFICATE-----
66+
MIIDSTCCAjGgAwIBAgIRAIPSwwehvSWt18FdR/LDS7kwDQYJKoZIhvcNAQELBQAw
67+
FDESMBAGA1UEAwwJZ290bHN0ZXN0MB4XDTE2MDgwNDE0MDAwNVoXDTI2MDgwMjE0
68+
MDAwNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOC
69+
AQ8AMIIBCgKCAQEAml6AWAcWbOU9V1tgrScJ/tzMU2RdtNPdysAkwlGshITTJ3mp
70+
KHvXm4O6k5/lCwp3xGZVubJnxZujIUKvlPYDbaieskKRmV5olfECWUzaVcE108Lo
71+
q93wJhgCEU1GaWjNBS9d5Cexa1DlcAG/g4IsDcxbT2+Tfa3WXze39girLcEbjePg
72+
hZdVKSwTeY2jZl/dUUMwntBVYX0Y/Q99Sm/02Ai6OzLTuAxPG8kWPHF3HgWx/grr
73+
bucnacX+MZHyBZ/7bHDlfxVG2T6kOZnVUUIkomOjKejdFz95c++m7Nialk9lMHBA
74+
CpitOmCiEMYwklz4bMdOH6azEJURXC+bKpWSNwIDAQABo4GVMIGSMAkGA1UdEwQC
75+
MAAwHQYDVR0OBBYEFAIpHyZKJQFHYVABqLLbOFP56o4nMEQGA1UdIwQ9MDuAFNWK
76+
bSKDa4njgKh3NWIugAR+ugT9oRikFjAUMRIwEAYDVQQDDAlnb3Rsc3Rlc3SCCQDx
77+
ihAGDiWdQTATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZI
78+
hvcNAQELBQADggEBAAxpMkSxVvDWkKpuQjUN8lbAWMn4TKcp3nQGA4X+ysE00RpR
79+
wKq4Br+gweEct1d0CVO6OAXOjRrpAvnZdplCmeZXPCoAf6ccp1tpNEHN5Q81rf/F
80+
D+W5yhEFS1oGXcpiAwpeIlkCqJ5ogVBFI3PmCOU81ASvTMDiW0Tq84oRo7c/i0T4
81+
5tq5CA4vPPi0fp/1dNJ0OlL4j2C2eZZ8CJJ9GxfT/AQogqvJhBAAT/MEYkh9YvIk
82+
BhG4/4VmkxI74TSIFnOiw+PnljLbCH+GW/RN2yg/ZRGsQ+1BvgOraeK8ctEfbCoR
83+
fD5u4qQbd28Qq7J214LqECNc8berB649BTIfpqc=
84+
-----END CERTIFICATE-----

Diff for: _test_data/localhost.key

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEowIBAAKCAQEAml6AWAcWbOU9V1tgrScJ/tzMU2RdtNPdysAkwlGshITTJ3mp
3+
KHvXm4O6k5/lCwp3xGZVubJnxZujIUKvlPYDbaieskKRmV5olfECWUzaVcE108Lo
4+
q93wJhgCEU1GaWjNBS9d5Cexa1DlcAG/g4IsDcxbT2+Tfa3WXze39girLcEbjePg
5+
hZdVKSwTeY2jZl/dUUMwntBVYX0Y/Q99Sm/02Ai6OzLTuAxPG8kWPHF3HgWx/grr
6+
bucnacX+MZHyBZ/7bHDlfxVG2T6kOZnVUUIkomOjKejdFz95c++m7Nialk9lMHBA
7+
CpitOmCiEMYwklz4bMdOH6azEJURXC+bKpWSNwIDAQABAoIBAF3cJ91eMdx0Zh+/
8+
h8DAg+tbBUGPPQq955VnzvH4BxVsTZcq+heLdUUxizhHeFSGQNxB/M20FDSqtT17
9+
9pZ0HxGF/TgWEcFXDfBdYjg56mdJ2xiu4hneEC6ZWmh6u91Lw5zreANJvy6pOVgp
10+
N/EWLQMWxk4+YUeBc17h2hDWpH5kgkVSot4IGjdstUSxbEZCDePBqxEoZNgyloNn
11+
a8IuNWSB82GB0tujmWelK9xcg7A2OOC7E9PsQNfc/SkxK1enTxyVpS2yuFCtqUVZ
12+
ix5rBeExEA3Jk3bQoznpkDv8FbW44mWRGl+kLEXjKpdBzv1VrC5BHAhrCgIfeXnk
13+
tAp5B4ECgYEAx59RETheQyeDuBmC5Elfkp5+0OBo/LcU/8FS5DwoQgfIEuYMKDeq
14+
yBf2n6YIsWPO2wXxLd3vLQFUxAQfgDqKC2SGeJoLkKo1K/8gjmtPChc0ooODLlQX
15+
tPJBv6/+oPjaBvtKutpQ3y/2zBagv0SbbAjaFzTNoXgSOv3vUj7bTB8CgYEAxfdh
16+
xwXQ1s1YGUWU8TnLEi1zVMdF2XVezeaWhPMuns2it3LS+Ge4nCtAYBEJOmpvujHK
17+
xJ0mGbuP+xNmfd2se34lUCSqfSodtPVUN8nMBAFmS770JHR+gn+k5TKYlt+Crbng
18+
zh0ej4ffegPvO1gboncQJgzGWGKjp+XlH3M5dukCgYEAkIiGrrwsa90BXtuBzP5f
19+
J46AbYX+HfQFTURRWxU/ZMezkhNke/4KNkQ7ec5CfwWv8R81R6toECLll+MQV8yK
20+
xMLtJgcLFpxWUVuw281QdhLlNkGYSoPygj3hYwPvjeeAHQv3SKDnayGURKKhkrr+
21+
+VLTbXf65s1EDdhsXhVKvKsCgYBRnmjFsXQk24yS/sklm3pKCEsgjPgTa/ymT4eH
22+
UOvLtWR81e59U+YdHQfxk5SGbRObZKQA4/mtalM2ZQ1An4BZeezQWg2ghRiyXuNW
23+
DPD8RcdzO0tVLGJsU0wc4vteWNB758Lzt7W933sXxz9+7BiYpxYVWfb8wc5Pjs0k
24+
ZlEu4QKBgHwAGTSOL42WemEJ/FizWBxzc9RQ6Ipo6Erm3raYYhuM/0WK7rahRUU7
25+
1N1ghSQH6MIm+PdsKl9wbdDEySN2PPPioNOWOmi6SS1oEq8fs1Qizn8x2pmKIvHS
26+
L3CqlpjHdj50rbBwk2diboN+0FIanlFiM6kL8WmCmVGrV4QhMdUg
27+
-----END RSA PRIVATE KEY-----

Diff for: acceptor.go

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package quickfix
22

33
import (
4+
"crypto/tls"
45
"fmt"
5-
"github.com/quickfixgo/quickfix/config"
66
"net"
77
"strconv"
8+
9+
"github.com/quickfixgo/quickfix/config"
810
)
911

1012
//Acceptor accepts connections from FIX clients and manages the associated sessions.
@@ -19,17 +21,29 @@ type Acceptor struct {
1921
}
2022

2123
//Start accepting connections.
22-
func (a *Acceptor) Start() (e error) {
24+
func (a *Acceptor) Start() error {
2325
port, err := a.settings.GlobalSettings().IntSetting(config.SocketAcceptPort)
2426
if err != nil {
2527
return fmt.Errorf("error fetching required SocketAcceptPort: %v", err)
2628
}
2729

28-
server, err := net.Listen("tcp", ":"+strconv.Itoa(port))
29-
if server == nil {
30+
var tlsConfig *tls.Config
31+
if tlsConfig, err = loadTLSConfig(a.settings); err != nil {
3032
return err
3133
}
3234

35+
var server net.Listener
36+
address := ":" + strconv.Itoa(port)
37+
if tlsConfig != nil {
38+
if server, err = tls.Listen("tcp", address, tlsConfig); err != nil {
39+
return err
40+
}
41+
} else {
42+
if server, err = net.Listen("tcp", address); err != nil {
43+
return err
44+
}
45+
}
46+
3347
connections := a.listenForConnections(server)
3448

3549
a.quitChan = make(chan bool)
@@ -39,7 +53,7 @@ func (a *Acceptor) Start() (e error) {
3953
}
4054
}()
4155

42-
return
56+
return nil
4357
}
4458

4559
//Stop logs out existing sessions, close their connections, and stop accepting new connections.

Diff for: config/configuration.go

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const (
88
SocketAcceptPort string = "SocketAcceptPort"
99
SocketConnectHost string = "SocketConnectHost"
1010
SocketConnectPort string = "SocketConnectPort"
11+
SocketPrivateKeyFile string = "SocketPrivateKeyFile"
12+
SocketCertificateFile string = "SocketCertificateFile"
13+
SocketCAFile string = "SocketCAFile"
1114
DefaultApplVerID string = "DefaultApplVerID"
1215
DataDictionary string = "DataDictionary"
1316
TransportDataDictionary string = "TransportDataDictionary"

Diff for: config/doc.go

+12
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,18 @@ SocketAcceptPort
139139
140140
Socket port for listening to incoming connections, Only used with for acceptors. Value must be positive integer, valid open socket port.
141141
142+
SocketPrivateKeyFile
143+
144+
Private key to use for secure TLS connections. Must be used with SocketCertificateFile.
145+
146+
SocketCertificateFile
147+
148+
Certificate to use for secure TLS connections. Must be used with SocketPrivateKeyFile.
149+
150+
SocketCAFile
151+
152+
Optional root CA to use for secure TLS connections. For acceptors, client certificates will be verified against this CA. For initiators, clients will use the CA to verify the server certificate. If not configurated, initiators will verify the server certificate using the host's root CA set.
153+
142154
FileLogPath
143155
144156
Directory to store logs. Value must be valid directory for storing files, application must have write access.

Diff for: connection.go

+23-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package quickfix
22

33
import (
44
"bufio"
5+
"crypto/tls"
56
"io"
67
"net"
78
"time"
89
)
910

1011
//Picks up session from net.Conn Initiator
11-
func handleInitiatorConnection(address string, log Log, sessID SessionID, quit chan bool, reconnectInterval time.Duration) {
12+
func handleInitiatorConnection(address string, log Log, sessID SessionID, quit chan bool, reconnectInterval time.Duration, tlsConfig *tls.Config) {
1213
session := activate(sessID)
1314
if session == nil {
1415
log.OnEventf("Session not found for SessionID: %v", sessID)
@@ -21,9 +22,27 @@ func handleInitiatorConnection(address string, log Log, sessID SessionID, quit c
2122
msgIn := make(chan fixIn)
2223
msgOut := make(chan []byte)
2324

24-
netConn, err := net.Dial("tcp", address)
25-
if err != nil {
26-
goto reconnect
25+
var netConn net.Conn
26+
if tlsConfig != nil {
27+
tlsConn, err := tls.Dial("tcp", address, tlsConfig)
28+
if err != nil {
29+
log.OnEventf("Failed to connect: %v", err)
30+
goto reconnect
31+
}
32+
33+
err = tlsConn.Handshake()
34+
if err != nil {
35+
log.OnEventf("Failed handshake:%v", err)
36+
goto reconnect
37+
}
38+
netConn = tlsConn
39+
} else {
40+
var err error
41+
netConn, err = net.Dial("tcp", address)
42+
if err != nil {
43+
log.OnEventf("Failed to connect: %v", err)
44+
goto reconnect
45+
}
2746
}
2847

2948
go readLoop(newParser(bufio.NewReader(netConn)), msgIn)

Diff for: initiator.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package quickfix
22

33
import (
4+
"crypto/tls"
45
"fmt"
56
"time"
67

@@ -43,8 +44,12 @@ func (i *Initiator) Start() error {
4344
}
4445
}
4546

47+
var tlsConfig *tls.Config
48+
if tlsConfig, err = loadTLSConfig(i.settings); err != nil {
49+
return err
50+
}
4651
address := fmt.Sprintf("%v:%v", socketConnectHost, socketConnectPort)
47-
go handleInitiatorConnection(address, i.globalLog, sessionID, i.quitChan, time.Duration(reconnectInterval)*time.Second)
52+
go handleInitiatorConnection(address, i.globalLog, sessionID, i.quitChan, time.Duration(reconnectInterval)*time.Second, tlsConfig)
4853
}
4954

5055
return nil

Diff for: tls.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package quickfix
2+
3+
import (
4+
"crypto/tls"
5+
"crypto/x509"
6+
"fmt"
7+
"io/ioutil"
8+
9+
"github.com/quickfixgo/quickfix/config"
10+
)
11+
12+
func loadTLSConfig(settings *Settings) (tlsConfig *tls.Config, err error) {
13+
if !settings.GlobalSettings().HasSetting(config.SocketPrivateKeyFile) && !settings.GlobalSettings().HasSetting(config.SocketCertificateFile) {
14+
return
15+
}
16+
17+
privateKeyFile, err := settings.GlobalSettings().Setting(config.SocketPrivateKeyFile)
18+
if err != nil {
19+
return
20+
}
21+
22+
certificateFile, err := settings.GlobalSettings().Setting(config.SocketCertificateFile)
23+
if err != nil {
24+
return
25+
}
26+
27+
tlsConfig = defaultTLSConfig()
28+
tlsConfig.Certificates = make([]tls.Certificate, 1)
29+
30+
if tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(certificateFile, privateKeyFile); err != nil {
31+
return
32+
}
33+
34+
if !settings.GlobalSettings().HasSetting(config.SocketCAFile) {
35+
return
36+
}
37+
38+
caFile, err := settings.GlobalSettings().Setting(config.SocketCAFile)
39+
if err != nil {
40+
return
41+
}
42+
43+
pem, err := ioutil.ReadFile(caFile)
44+
if err != nil {
45+
return
46+
}
47+
48+
certPool := x509.NewCertPool()
49+
if !certPool.AppendCertsFromPEM(pem) {
50+
err = fmt.Errorf("Failed to parse %v", caFile)
51+
return
52+
}
53+
54+
tlsConfig.RootCAs = certPool
55+
tlsConfig.ClientCAs = certPool
56+
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
57+
58+
return
59+
}
60+
61+
//defaultTLSConfig brought to you by https://github.com/gtank/cryptopasta/
62+
func defaultTLSConfig() *tls.Config {
63+
return &tls.Config{
64+
// Avoids most of the memorably-named TLS attacks
65+
MinVersion: tls.VersionTLS12,
66+
// Causes servers to use Go's default ciphersuite preferences,
67+
// which are tuned to avoid attacks. Does nothing on clients.
68+
PreferServerCipherSuites: true,
69+
// Only use curves which have constant-time implementations
70+
CurvePreferences: []tls.CurveID{
71+
tls.CurveP256,
72+
},
73+
}
74+
}

0 commit comments

Comments
 (0)