Mosquittoを用いてMQTT＋SSL/TLS通信を試してみる

# 概要
MQTTを用いてセキュアに通信するためにOSX上でのMosquittoとTLS周りの動作手順です．
手元のMacbook Proにサーバとクライアントを両方走らせてみました．
参考記事
http://www.steves-internet-guide.com/mosquitto-tls/

# 利用する機器・ソフト
* PC: Macbook Pro 2017 OSX(10.14.3)

* MQTTブローカ: Mosquitto 1.5.8
* MQTTクライアント: Mosquitto-client
    →mosquitto_pub, mosquitto_subを今回は用います．
* SSL/TLS: openssl (version: 1.0.2q)

# 手順
## Mosquittoのインストール
```zsh
% brew install mosquitto
```
このコマンドを実行することで以下のパスにMosquittoのブローカとクライアントがインストールされます．

* mosquitto : /usr/local/opt/sbin
* mosquitto_sub : /usr/local/opt/bin
* mosquitto_pub : /usr/local/opt/bin



## 認証局の証明書生成の流れ
CA証明書に必要な秘密鍵を以下のコマンドで作成します．

```zsh
% openssl genrsa -des3 -out ca.key 2048
Generating RSA private key, 2048 bit long modulus
...............................+++
.....................................................................................................................................................................................................................................+++
e is 65537 (0x10001)
Enter pass phrase for ca.key:
Verifying - Enter pass phrase for ca.key:
```

続いて以下のコマンドを実行しCA証明書を作成します．
パスフレーズを入力した後は証明書の情報を入力します．
Common Nameも含めてこちらの情報は適当に決めてしまって大丈夫だと思います．

```zsh
% openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
Enter pass phrase for ca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:JP
State or Province Name (full name) []:Aichi
Locality Name (eg, city) []:Nagoya
Organization Name (eg, company) []:CAmaster
Organizational Unit Name (eg, section) []:TEST
Common Name (eg, fully qualified host name) []:localhost
Email Address []:test@test.com
```

## サーバ証明書作成の流れ
続いてサーバ証明書を作成します．
以下のコマンドを実行して秘密鍵を作成します．

```zsh
% openssl genrsa -out server.key 2048                                  
Generating RSA private key, 2048 bit long modulus
..................+++
.......................+++
e is 65537 (0x10001)
```

次にサーバ証明書を先ほど作ったCAで認証してもらうためのcsrファイルを作成します．
Common Nameに関してはローカルで動かす際は以下の記述で大丈夫です．
クライアントとブローカを別端末で動かす際は, Common Nameにブローカを実行する端末のIPアドレスorドメイン名を記述すれば大丈夫です．

```zsh
% openssl req -new -out server.csr -key server.key                      
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:JP
State or Province Name (full name) []:Aichi
Locality Name (eg, city) []:Nagoya
Organization Name (eg, company) []:Server
Organizational Unit Name (eg, section) []:TEST
Common Name (eg, fully qualified host name) []:localhost
Email Address []:test@test.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
```

そして以下のコマンドを実行し，サーバ証明書をCAに認証してもらいます．

```zsh
% openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360
Signature ok
subject=/C=JP/ST=Aichi/L=Nagoya/O=Server/OU=TEST/CN=localhost/emailAddress=test@test.com
Getting CA Private Key
Enter pass phrase for ca.key:
```

ここまででopensslを利用した証明書作成は完了しました．

## Mosquittoの設定変更
上の手順で作成したファイルのうち，server.crt，server.key，ca.crtを1つのディレクトリにまとめます．Linuxでは， ```etc/mosuiqtto```に```certs```というディレクトリが用意されていますが，自分のMacでは見つからなかったため，自前でディレクトリを用意しましょう．

次に，Mosquittoの設定ファイルであるmosquitto.confを修正します． 場所は, ```/usr/local/opt/mosquitto/etc/mosquitto```にありました． 
修正点は以下の通りです．

```conf
# =================================================================
# Default listener
# =================================================================

# IP address/hostname to bind the default listener to. If not
# given, the default listener will not be bound to a specific 
# address and so will be accessible to all network interfaces.
# bind_address ip-address/host name
#bind_address

# Port to use for the default listener.
#port 1883
port 8883

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# -----------------------------------------------------------------
# Certificate based SSL/TLS support
# -----------------------------------------------------------------
# The following options can be used to enable SSL/TLS support for 
# this listener. Note that the recommended port for MQTT over TLS
# is 8883, but this must be set manually.
#
# See also the mosquitto-tls man page.

# At least one of cafile or capath must be defined. They both 
# define methods of accessing the PEM encoded Certificate 
# Authority certificates that have signed your server certificate 
# and that you wish to trust.
# cafile defines the path to a file containing the CA certificates.
# capath defines a directory that will be searched for files
# containing the CA certificates. For capath to work correctly, the
# certificate files must have ".crt" as the file ending and you must run
# "openssl rehash <path to capath>" each time you add/remove a certificate.
#cafile
#capath
cafile /usr/local/opt/mosquitto/etc/mosquitto/certs/ca.crt
keyfile /usr/local/opt/mosquitto/etc/mosquitto/certs/server.key
certfile /usr/local/opt/mosquitto/etc/mosquitto/certs/server.crt
```

## 通信の実行
これらの修正が終わったら，Mosquittoブローカを立ち上げてみます．
以下の表示が出ればOKです．

```zsh
% mosquitto -c /usr/local/opt/mosquitto/etc/mosquitto/mosquitto.conf
1553144935: mosquitto version 1.5.8 starting
1553144935: Config loaded from /usr/local/opt/mosquitto/etc/mosquitto/mosquitto.conf.
1553144935: Opening ipv6 listen socket on port 8883.
1553144935: Opening ipv4 listen socket on port 8883.
```

続いて，クライアントであるサブスクライバとパブリッシャを実行します．この時にポート番号とCA証明書をオプションで指定するのを忘れないようにしましょう．

```zsh
% mosquitto_pub -d -h localhost -t "topic/test" -m "hello world" --cafile /usr/local/opt/mosquitto/etc/mosquitto/certs/ca.crt -p 8883
Client mosqpub|67450-<username> sending CONNECT
Client mosqpub|67450-<username> received CONNACK (0)
Client mosqpub|67450-<username> sending PUBLISH (d0, q0, r0, m1, 'topic/test', ... (11 bytes))
Client mosqpub|67450-<username> sending DISCONNECT
```

```zsh
% mosquitto_sub -h localhost -t "topic/test" --cafile /usr/local/opt/mosquitto/etc/mosquitto/certs/ca.crt -p 8883    
hello world
```


これでSSL/TLSを利用したMQTT通信が可能となりました．

# 終わりに
以上でMQTT＋TLS通信の手順は終了です．今回はクライアントはMosquittoが用意した簡易的なクライアントアプリケーションを利用しました． Linuxでも同様の方法でできると思います．(未確認)
MQTT Pahoライブラリを用いたクライアントアプリケーションを利用することも可能です．Qiitaにもすでに多くの記事が掲載されていますが，そちらの方も実践した記事もあげてみたいと思っています．

↑Pahoを用いたMQTTの画像通信を行う記事をあげました．
https://qiita.com/udai1532/items/9e4cca55f75b2c213173