Skip to content

Commit d2ee5ac

Browse files
moznionbrocaar
authored andcommitted
Support MQTT client certificate authentication (#74)
1 parent 91c3154 commit d2ee5ac

File tree

5 files changed

+69
-30
lines changed

5 files changed

+69
-30
lines changed

backend/mqttpubsub/backend.go

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type Backend struct {
2424
}
2525

2626
// NewBackend creates a new Backend.
27-
func NewBackend(server, username, password, cafile string) (*Backend, error) {
27+
func NewBackend(server, username, password, cafile, certFile, certKeyFile string) (*Backend, error) {
2828
b := Backend{
2929
txPacketChan: make(chan gw.TXPacketBytes),
3030
gateways: make(map[lorawan.EUI64]struct{}),
@@ -37,11 +37,16 @@ func NewBackend(server, username, password, cafile string) (*Backend, error) {
3737
opts.SetOnConnectHandler(b.onConnected)
3838
opts.SetConnectionLostHandler(b.onConnectionLost)
3939

40-
if cafile != "" {
41-
tlsconfig, err := NewTLSConfig(cafile)
42-
if err == nil {
43-
opts.SetTLSConfig(tlsconfig)
44-
}
40+
tlsconfig, err := NewTLSConfig(cafile, certFile, certKeyFile)
41+
if err != nil {
42+
log.WithError(err).WithFields(log.Fields{
43+
"ca_cert": cafile,
44+
"tls_cert": certFile,
45+
"tls_key": certKeyFile,
46+
}).Fatal("error loading mqtt certificate files")
47+
}
48+
if tlsconfig != nil {
49+
opts.SetTLSConfig(tlsconfig)
4550
}
4651

4752
log.WithField("server", server).Info("backend: connecting to mqtt broker")
@@ -54,23 +59,43 @@ func NewBackend(server, username, password, cafile string) (*Backend, error) {
5459
}
5560

5661
// NewTLSConfig returns the TLS configuration.
57-
func NewTLSConfig(cafile string) (*tls.Config, error) {
62+
func NewTLSConfig(cafile, certFile, certKeyFile string) (*tls.Config, error) {
63+
// Here are three valid options:
64+
// - Only CA
65+
// - TLS cert + key
66+
// - CA, TLS cert + key
67+
68+
if cafile == "" && certFile == "" && certKeyFile == "" {
69+
log.Info("backend: TLS config is empty")
70+
return nil, nil
71+
}
72+
73+
tlsConfig := &tls.Config{}
74+
5875
// Import trusted certificates from CAfile.pem.
76+
if cafile != "" {
77+
cacert, err := ioutil.ReadFile(cafile)
78+
if err != nil {
79+
log.Errorf("backend: couldn't load cafile: %s", err)
80+
return nil, err
81+
}
82+
certpool := x509.NewCertPool()
83+
certpool.AppendCertsFromPEM(cacert)
5984

60-
cert, err := ioutil.ReadFile(cafile)
61-
if err != nil {
62-
log.Errorf("backend: couldn't load cafile: %s", err)
63-
return nil, err
85+
tlsConfig.RootCAs = certpool // RootCAs = certs used to verify server cert.
6486
}
6587

66-
certpool := x509.NewCertPool()
67-
certpool.AppendCertsFromPEM(cert)
88+
// Import certificate and the key
89+
if certFile != "" && certKeyFile != "" {
90+
kp, err := tls.LoadX509KeyPair(certFile, certKeyFile)
91+
if err != nil {
92+
log.Errorf("backend: couldn't load MQTT TLS key pair: %s", err)
93+
return nil, err
94+
}
95+
tlsConfig.Certificates = []tls.Certificate{kp}
96+
}
6897

69-
// Create tls.Config with desired tls properties
70-
return &tls.Config{
71-
// RootCAs = certs used to verify server cert.
72-
RootCAs: certpool,
73-
}, nil
98+
return tlsConfig, nil
7499
}
75100

76101
// Close closes the backend.

backend/mqttpubsub/backend_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestBackend(t *testing.T) {
2222
defer c.Disconnect(0)
2323

2424
Convey("Given a new Backend", func() {
25-
backend, err := NewBackend(conf.Server, conf.Username, conf.Password, "")
25+
backend, err := NewBackend(conf.Server, conf.Username, conf.Password, "", "", "")
2626
So(err, ShouldBeNil)
2727
defer backend.Close()
2828

cmd/lora-gateway-bridge/doc.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@ USAGE:
66
main [global options] command [command options] [arguments...]
77
88
COMMANDS:
9-
help, h Shows a list of commands or help for one command
9+
help, h Shows a list of commands or help for one command
1010
1111
GLOBAL OPTIONS:
12-
--udp-bind "0.0.0.0:1700" ip:port to bind the UDP listener to [$UDP_BIND]
13-
--mqtt-server "tcp://127.0.0.1:1883" MQTT server [$MQTT_SERVER]
14-
--mqtt-username MQTT username [$MQTT_USERNAME]
15-
--mqtt-password MQTT password [$MQTT_PASSWORD]
16-
--mqtt-ca-cert CA certificate file [$MQTT_CA_CERT]
17-
--log-level "4" debug=5, info=4, warning=3, error=2, fatal=1, panic=0 [$LOG_LEVEL]
18-
--help, -h show help
19-
--version, -v print the version
12+
--udp-bind value ip:port to bind the UDP listener to (default: "0.0.0.0:1700") [$UDP_BIND]
13+
--mqtt-server value mqtt server (e.g. scheme://host:port where scheme is tcp, ssl or ws) (default: "tcp://127.0.0.1:1883") [$MQTT_SERVER]
14+
--mqtt-username value mqtt server username (optional) [$MQTT_USERNAME]
15+
--mqtt-password value mqtt server password (optional) [$MQTT_PASSWORD]
16+
--mqtt-ca-cert value mqtt CA certificate file (optional) [$MQTT_CA_CERT]
17+
--mqtt-tls-cert value mqtt certificate file (optional) [$MQTT_TLS_CERT]
18+
--mqtt-tls-key value mqtt key file of certificate (optional) [$MQTT_TLS_KEY]
19+
--skip-crc-check skip the CRC status-check of received packets [$SKIP_CRC_CHECK]
20+
--log-level value debug=5, info=4, warning=3, error=2, fatal=1, panic=0 (default: 4) [$LOG_LEVEL]
21+
--help, -h show help
22+
--version, -v print the version
2023
2124
COPYRIGHT:
2225
See http://github.com/brocaar/lora-gateway-bridge for copyright information
2326
24-
2527
*/
2628
package main

cmd/lora-gateway-bridge/main.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func run(c *cli.Context) error {
2828
var pubsub *mqttpubsub.Backend
2929
for {
3030
var err error
31-
pubsub, err = mqttpubsub.NewBackend(c.String("mqtt-server"), c.String("mqtt-username"), c.String("mqtt-password"), c.String("mqtt-ca-cert"))
31+
pubsub, err = mqttpubsub.NewBackend(c.String("mqtt-server"), c.String("mqtt-username"), c.String("mqtt-password"), c.String("mqtt-ca-cert"), c.String("mqtt-tls-cert"), c.String("mqtt-tls-key"))
3232
if err == nil {
3333
break
3434
}
@@ -126,6 +126,16 @@ func main() {
126126
Usage: "mqtt CA certificate file (optional)",
127127
EnvVar: "MQTT_CA_CERT",
128128
},
129+
cli.StringFlag{
130+
Name: "mqtt-tls-cert",
131+
Usage: "mqtt certificate file (optional)",
132+
EnvVar: "MQTT_CERT",
133+
},
134+
cli.StringFlag{
135+
Name: "mqtt-tls-key",
136+
Usage: "mqtt key file of certificate (optional)",
137+
EnvVar: "MQTT_CERT_KEY",
138+
},
129139
cli.BoolFlag{
130140
Name: "skip-crc-check",
131141
Usage: "skip the CRC status-check of received packets",

docs/content/install/config.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ GLOBAL OPTIONS:
3030
--mqtt-username value mqtt server username (optional) [$MQTT_USERNAME]
3131
--mqtt-password value mqtt server password (optional) [$MQTT_PASSWORD]
3232
--mqtt-ca-cert value mqtt CA certificate file (optional) [$MQTT_CA_CERT]
33+
--mqtt-tls-cert value mqtt certificate file (optional) [$MQTT_TLS_CERT]
34+
--mqtt-tls-key value mqtt key file of certificate (optional) [$MQTT_TLS_KEY]
3335
--skip-crc-check skip the CRC status-check of received packets [$SKIP_CRC_CHECK]
3436
--log-level value debug=5, info=4, warning=3, error=2, fatal=1, panic=0 (default: 4) [$LOG_LEVEL]
3537
--help, -h show help

0 commit comments

Comments
 (0)