コーヒー飲みながら仕事したい

仕事で使う技術的なことの備忘録とか

mosquitto で OpenSSL を 用いて TLS 接続する

mosquitto をで TLS 接続する方法です。
OpenSSL を使用するのが簡単だと思うけど、ちょっと間が空くとすぐやり方を忘れてしまうので備忘録として残しておきます。

2018/03/11 追記/修正

いろいろ TLS について勉強してみると、言葉の使い方や理解が正しくない箇所が複数あったので修正しました。
そして、まだ勉強不足なので間違っている箇所がある可能性は十分あります・・・。

前提

  1. OS : Windows 10 64bit
  2. mqtt ブローカーもクライアントも mosquitto を使用する
  3. 秘密鍵/公開鍵やサーバー証明書の生成は、OpenSSL を使用して行う
  4. TLS するためのサーバー証明書は、自己認証局(オレオレ認証局)で実現する
  5. あらかじめ pfx 形式1のものが存在しており、それを使用して自己認証局の開局する
    (pfx ファイルのパスワードは把握しているものとする)

今回は 5. が特殊な条件ですが、現案件がこういう条件下なのでこれを前提で記述します。

pfx ファイルを秘密鍵/公開鍵情報とルート証明書に分離する

pfx ファイル(ca.pfx)を OpenSSL を使用して秘密鍵/公開鍵情報(ca.key)と自己認証局ルート証明書(ca.crt)に分離します。

# 秘密鍵/公開鍵の取り出し
$ openssl pkcs12 -in ca.pfx -nocerts -nodes -out ca.key
Enter Import Password: # ca.pfx ファイルのパスワードを入力
MAC verified OK # ca.key が出力される

# 自己認証局のルート証明書の取り出し
$ openssl pkcs12 -in ca.pfx -clcerts -nokeys -out ca.crt
Enter Import Password: # ca.pfx ファイルのパスワードを入力
MAC verified OK # ca.crt が出力される

mosquitto で TSL 接続を行う場合は、出来上がった crt ファイルをOSに「信頼できるルート証明書」として登録する必要はないので、事実上これで自己認証局の開局は済んだことになります。(mosquitto を起動する際に、ブローカーでもクライアントでも、起動引数にパスを付加することでこのルート証明書を使用します)

参考

blog.prophet.jp

サーバー(ブローカー)の秘密鍵/公開鍵を生成

ブローカーの TSL 接続用の秘密鍵/公開鍵として server.key を生成します。

# 秘密鍵/公開鍵生成
$ openssl genrsa -out server.key 2048

サーバー(ブローカー)のサーバー証明書署名要求の作成

「証明書署名要求」とは、公開鍵にコモンネーム(Common Name)等のサーバーの情報を付加したものです。

www.infraexpert.com

ブローカーの証明書署名要求として server.csr を生成します。

# 証明書署名要求の生成
$ openssl req -out server.csr -key server.key -new

いろいろ入力を促されますが、とりあえずはオレオレ認証なので Common Name (e.g. server FQDN or YOUR name) []: 以外は全て未入力(そのまま Enter )でよいです。
Common Name には、ブローカーの FQDN (ホスト名またはIPアドレス)を入力する必要があります。
もし正しく FQDN を入力しなかったら、Error: A TLS error occurred. と言われてブローカーと接続できません。

Common Name (コモンネーム)について追記

そもそも、SSL/TLS 接続を行う際に、クライアント側がサーバーを認証する(なりすましでないと特定する)手法が、サーバーへの接続文字列とコモンネームを比較することらしいです。
つまり、コモンネームが一致しないならば、相手が本物と特定できない(クライアントは相手がなりすましだと思わざるをえない)ので、それくらいコモンネームは重要です。

詳細は↓のサイトが非常に参考になります。

cspssl.jp

このサイトは SSL 接続の知識が体系的にまとめられていて、非常に勉強になります。

サーバー証明書の署名と発行

上記で生成したサーバー証明書署名要求を、自己認証局秘密鍵ca.key)でデジタル署名して、サーバー証明書を発行します。

# サーバー証明書の署名と発行
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 36500

ここでは、有効期限を100年としています。(普通はこんなことしませんが、オレオレ認証なので・・・)

とりあえずここまでで、 OpenSSL を使用した TSL 接続用の鍵生成や署名は終了です。

参考

qiita.com

mosquitto.conf の設定

TSL 接続で使用する各証明書ファイルのパスを mosquitto.conf に追加します。
ファイルのどこに書いても良いそうです。

// C:\Program Files (x86)\mosquitto\mosquitto.conf
listener 8883
cafile   ./certs/ca.crt
certfile ./certs/server.crt
keyfile  ./certs/server.key

ここでは、上記で生成した鍵等を、 C:\Program Files (x86)\mosquitto\certs に入れているものとしています。

動作確認

# ブローカーの起動
$ mosquitto -v -c mosquitto.conf
1520414168: mosquitto version 1.4.12 (build date 29/05/2017 11:24:45.10) starting
1520414168: Config loaded from mosquitto.conf.
1520414168: Opening ipv6 listen socket on port 8883.
1520414168: Opening ipv4 listen socket on port 8883.
# mosquitto_sub の起動
$ mosquitto_sub -d -t test -h <BrokerのFQDN> -p 8883 --cafile ./certs/ca.crt
# mosquitto_pub の起動
$ mosquitto_pub -d -t test -m aaaaaa -h <BrokerのFQDN> -p 8883 --cafile ./certs/ca.crt

  1. 秘密鍵と公開鍵、サーバー証明書認証局の場合はルート証明書)をまとめて一つにし、パスワードにより暗号化されたもの