WIndows 11 Mosquitto Broker TLS/SSL 接続テスト 備忘録


### インストール
https://mosquitto.org/download/
mosquitto-2.0.14-install-windows-x64.exe をインストールする。
Visual Studio Runtime 未チェック

### Mosquittoのインストールフォルダにパスを通す
左下Winアイコンクリック -> 検索で環境変数 -> 環境変数を編集 が出るのでクリック
システムのプロパティが開く -> 環境変数ボタン -> xxxユーザの環境変数ボックス内のPathを選択 -> 編集ボタン -> 新規ボタン
Mosquittoインストールフォルダ（C:\Program Files\mosquitto）を追加する。

### Mosquitto サービス起動
Dos窓で `> mosquitto` Enterでサービスが起動する。
サービスで開始してもいい。

### 接続テスト

Dos窓A
```
> mosquitto_sub -d -t topicA
```
Dos窓B
```
> mosquitto_pub -d -t topicA -m "Hello world!"
```
すると
Dos窓A
```
> mosquitto_sub -d -t topicA
・・・
Client null received PUBLISH (d0, q0, r0, m0, 'topicA', ... (12 bytes))
Hello world!
```
となれば成功。

※ "対象のコンピューターによって拒否されたため、接続できませんでした。" が出る場合はサービスが起動していないので コンピュータの管理 -> サービス -> Mosquitto 開始

```test.mosquitto.org
> mosquitto_sub -h test.mosquitto.org -t "test/signalA"
```

### LAN内違うPCで接続
デフォルトではローカルモード（自分自身からのデータのみ処理）になっているので、他のコンピュータから接続できない。
- 設定変更
C:\Program Files\mosquitto\mosquitto.conf
```mosquitto.conf
port 1883
listener 9001
protocol websockets
socket_domain ipv4
allow_anonymous true
```
mosquitto サービスを再起動する。

### ポート開放
Windows Defender 又は ウィルスソフトで 1883 TCP でポート開放する

### python で購読確認
管理者でDos窓
```
> pip install --upgrade pip
> pip install paho-mqtt
```
```MQTT_Test_Python.py
import paho.mqtt.client as paho
import readchar
import datetime
import threading

# MQTT Broker
MQTT_HOST = "192.168.0.200"       # brokerのアドレス
MQTT_PORT = 1883                # brokerのport
MQTT_KEEP_ALIVE = 60            # keep alive
PROTOCOL = "MQTT"
TOPIC = "topicA"

print("\nMQTT(m) or WebSocket(w) ? ", end="", flush=True)
while True:
    #c = readchar.readchar()
    c = readchar.readkey()
    if c == 'w':
        MQTT_PORT = 9001
        PROTOCOL = "WebSocket"
        break
    elif c == 'm':
        break

print(f'\n{MQTT_HOST}:{MQTT_PORT} {PROTOCOL} プロトコルでテストします。')

# broker接続時
def on_connect(mqtt, obj, flags, rc):
    print(f"{str(mqtt)} {str(obj)} {str(flags)} {str(rc)}")

#メッセージ受信時
def on_message(mqtt, obj, msg):
    print(f"{msg.topic} : {str(msg.qos)} : {str(msg.payload)}")

mqtt = paho.Client() if c == 'm' else paho.Client("control1", transport ='websockets')
mqtt.on_message = on_message  # メッセージ受信時に実行するコールバック関数設定
mqtt.on_connect = on_connect
mqtt.connect(MQTT_HOST, MQTT_PORT, MQTT_KEEP_ALIVE)

mqtt.subscribe(TOPIC)  # Topic名："topic1"を購読

# ５秒毎にパブリッシュ
def publish():
    mqtt.publish(TOPIC, f"Python {PROTOCOL}({MQTT_PORT}) --> {str(datetime.datetime.now())}")
    t=threading.Timer(5,publish)
    t.start()
t=threading.Thread(target=publish)
t.start()

mqtt.loop_forever()  # 永久ループ
```

### Webで購読
```MQTT_Test_LAN_WebSocket.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>MQTT</title>
  <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
</head>

<body>

    <p id="data"/>

<script>
let client = mqtt.connect('ws://192.168.0.200:9001');
let topic = "topicA"
let metric = '{"name": "sensor1", "temp": 10}'

client.subscribe(topic);
client.publish(topic, metric);

client.on('message', function (topic, message) { // message is Buffer
  console.log(message.toString());

  // const msg = JSON.parse(message.toString());
  const element = document.getElementById("data");
  element.innerHTML = `${message.toString()}`;
});

/**client.end();**/
</script>

</body>

</html>
```

---
# TLS(SSL)接続

### 証明書の作成
まず適当なフォルダにcertsフォルダを作成する。
こちらを参考に「[MosquittoブローカのTLS(SSL)認証設定](https://ficus-forum.myvnc.com/t/mosquitto-tls-ssl/154)」手順通りにcertsフォルダに証明書を作成する。
※ 証明書作成時にCN:exsample.com, ファイアーウォール8883, ルーターNAT設定8883 で外部からも接続できた。 
※ 「[複数ホスト](https://kazuhira-r.hatenablog.com/entry/20180803/1533302929)」随時適用
```ca_new_mosquitto.bat
@echo off

set PW=<パスワード>

SET CN=localhost
SET /P CN="コモン・ネーム CN [ %CN% ] : "
echo "コモン・ネーム CN = %CN%"

cd C:\Users\admin\OneDrive\.ssh\mosquitto\certs
del /Q *.*

echo;
@REM # Root Key
echo '$ openssl req -new -x509 -days 36500 -extensions v3_ca -keyout ca.key -out ca.crt -subj "/C=JP/ST=Fukuoka/O=LEE Root CA/CN="'
        openssl req -new -x509 -days 36500 -extensions v3_ca -keyout ca.key -passout pass:%PW% -out ca.crt -subj "/C=JP/ST=Tokyo/O=MY Root CA/CN="

echo;
@REM # Server key
echo '$ openssl genrsa -out server.key 2048'
        openssl genrsa -out server.key 2048

echo;
@REM # Server 署名要求
echo '$ openssl req -out server.csr -key server.key -new -subj "/C=JP/ST=Tokyo/O=LEE MQTT Server CA/CN=%CN%"'
        openssl req -out server.csr -key server.key -new -subj "/C=JP/ST=Fukuoka/O=MY MQTT Server CA/CN=%CN%"

echo;
@REM # Sever 署名要求に署名をする
echo '$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -passin pass:%PW% -CAcreateserial -out server.crt -days 36500'
        openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -passin pass:%PW% -CAcreateserial -out server.crt -days 36500
@REM    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -passin pass:%PW% -CAcreateserial -out server.crt -days 36500 -extfile C:\Users\admin\OneDrive\Documents\wsl\oo9\local\bin\subjectnames.txt
@REM    マルチドメインで接続できた。

echo;
openssl x509 -noout -text -in server.crt

echo;
echo "サーバー証明書チェーン検証 Root -> Server"
openssl verify -CAfile ca.crt server.crt

echo;
dir
```

mosquitto ユーザー追加
```add_mosquitto_user.bat
@if ["%1"] == [""] (
    echo "ユーザー名が必要です。"
    exit /b
)

if not exist "C:\Users\admin\OneDrive\.ssh\mosquitto\pwfile" (
    type nul > "C:\Users\admin\OneDrive\.ssh\mosquitto\pwfile"
)

mosquitto_passwd -c "C:\Users\admin\OneDrive\.ssh\mosquitto\temp0101" %1
copy /b "C:\Users\admin\OneDrive\.ssh\mosquitto\pwfile" + "C:\Users\admin\OneDrive\.ssh\mosquitto\temp0101" "C:\Users\admin\OneDrive\.ssh\mosquitto\pwfile"
del "C:\Users\admin\OneDrive\.ssh\mosquitto\temp0101"
```
`C:\Program Files\mosquitto\mosquitto.conf 書き換え
```mosquitto.conf
# TLS ポート
listener 8883

# ユーザー名, パスワード 必須
allow_anonymous false

# ユーザー・パスワードファイル
password_file C:\Users\admin\OneDrive\.ssh\mosquitto\pwfile

# CA証明書
cafile   C:\Users\admin\OneDrive\.ssh\mosquitto\certs\ca.crt
certfile C:\Users\admin\OneDrive\.ssh\mosquitto\certs\server.crt
keyfile  C:\Users\admin\OneDrive\.ssh\mosquitto\certs\server.key
```

サービスで mosquitto 再起動

通信テスト
```Dos.Subscribe
mosquitto_sub -d -h localhost -u test -P パスワード --cafile "C:\Program Files\mosquitto\certs\ca.crt" -p 8883 -t "topic/test"
```

```Dos.Publish
mosquitto_pub -d -h localhost -u test -P パスワード --cafile "C:\Program Files\mosquitto\certs\ca.crt" -p 8883 -t "topic/test" -m "hello world"
```



#### 参考
- [MQTT.js でブラウザから MQTTブローカ に Pub/Sub する](https://qiita.com/narutaro/items/2819ce79eb82a87357eb)
- [MQTTライブラリ Paho Python を理解しようとしてみる](https://www.sunbit.co.jp/blog/2019/11/21802/)
TSL
- [Mosquittoを用いてMQTT＋SSL/TLS通信を試してみる](https://qiita.com/udai1532/items/c0f58e73f76900a8469f)
- [MosquittoブローカのTLS(SSL)認証設定](https://ficus-forum.myvnc.com/t/mosquitto-tls-ssl/154)
- [opensslでマルチドメイン証明書証明書用のCSRを作成](https://rms.ne.jp/sslserver/csr/openssl-html/)
- [OpenSSLで自己署名証明書を作成する（複数ホスト名：SAN／Subject Alternative Name設定付き）](https://kazuhira-r.hatenablog.com/entry/20180803/1533302929)