オレオレ証明書を適用したNode-REDをiOSのSafariで開けない問題の対処

# 1. 何のための記事？

某 SNS にて
**『オレオレ証明書を Node-RED で利用すると iOS の Safari からは正常に使用できない』(超要約)**
という質問があったので調べた結果を記します。

# 2. 不具合調査概要と結果

不具合を特定するために、iOS 上の Safari で何が起きているか調査することにしました。
Mac は 14 年前の機種しかもっていないので、[こちらの記事](https://webkatu.com/archives/ios-safari-debug-on-windows/)を参考にして

- ios-webkit-debug-proxy
- remotedebug-ios-webkit-adapter

を組み合わせて Safari でのログを確認。

```
WebSocket network error: The operation couldn’t be completed. (OSStatus error -9807.)
```

というログが出力されていて、その詳細は [errSSLXCertChainInvalid](https://www.osstatus.com/search/results?platform=all&framework=all&search=-9807) とのことでした。

iOS の SSL 証明書について調べると、各種条件があり iOS に向けて追加対応したという記事が多かったので
iOS が許してくれる SSL 証明書を作る必要がありそうだね？という予想を立てました。
調査の結果、iOS が認めてくれるオレオレ証明書は [mkcert](https://github.com/FiloSottile/mkcert)を使うと作成できることが確認できました。

### 以降では、解決方法を記載します。

私は SSL 証明書に関しては素人同然ですので誤記等があれば教えてください。

# 3. 環境準備

[私の記事](https://qiita.com/eurogrve/items/189b850a870087b533f9)の手順で再現環境を準備します。

下記は git bash を利用したコマンド入力例です。

```shell
$ mkdir node-red-sample
$ cd node-red-sample
$ npm -y init
$ npm install node-red
$ mkdir data
$ cp ./node_modules/node-red/settings.js ./data/
# 下記コマンドを入力すると起動する
$ node ./node_modules/node-red/red.js  --userDir ./data
```

## 3.1 SSL 証明書を作る

[コチラの手順](https://one-it-thing.com/6514/)を参考に Node-RED で使用する方法を整理しました。
※以下の手順は Windows で行っていますので環境に応じて読み替えてください

- [mkcert](https://github.com/FiloSottile/mkcert/releases)を取得する  
  取得した実行ファイル名を mkcert.exe とします。
- 必要なファイルを作る

※ `192.168.1.100` は、Node-RED を起動する Windows PC の LAN の IP アドレス。

```shell
$ mkcert.exe -install
$ mkcert localhost 127.0.0.1 192.168.1.100
$ dir %LOCALAPPDATA%\mkcert /b
rootCA-key.pem
rootCA.pem
$ dir . /b
localhost+2-key.pem
localhost+2.pem
```

ファイルが 4 つほど出来ましたが、利用するファイルは下記の 3 ファイルです。

* (1) `localhost+2-key.pem`
* (2) `localhost+2.pem`
* (3) `rootCA.pem`

`(1)と(2)は、settings.jsと同じフォルダ(data)にコピーします。`

### 3.2 Node-RED の設定(settings.js)

`./data/settings.js` を(1)と(2)のファイルを使うように書き換えます。
`https: function()` 部分がコメントアウトされているので、その付近にコピペするのが楽かもしれません。

```javascript
    https: function () {
        // This function should return the options object, or a Promise
        // that resolves to the options object
        const path = require('path')
        return {
            // key: require("fs").readFileSync(path.join(__dirname, 'server.key')),
            key: require("fs").readFileSync(path.join(__dirname, 'localhost+2-key.pem')),
            cert: require("fs").readFileSync(path.join(__dirname, 'localhost+2.pem'))
        }
    },
```

以上で設定が終わったので、Node-RED を起動します。

```shell
$ node ./node_modules/node-red/red.js  --userDir ./data
```

PC のウェブブラウザで https://127.0.0.1:1880/#flow に接続して SSL 証明書が有効であることを確認します。

### 3.3 iOS の設定を行う

- 1. PC から(3)のファイル(rootCA.pem)をメールで iOS に送信します。  
     以降、全て iOS での操作
- 2. (3)を受信したら rootCA.pem をタッチする事でインストールできます。
- 3. 設定アプリを開くと上の方に「プロファイルがダウンロードされました」と表示されているのでインストールします。
- 4. 設定 → 一般 → 情報 → 証明書信頼設定を選択して、[mkcert ?????]と書いてあるルート証明書を有効にします。

以上でオレオレ証明書が有効になったので、Safari で Node-RED (https://192.168.1.100/#flow) を開いて動作に問題ないか確認してください。

# まとめ

Node-RED の https 対応の基盤は Node.js のものなので、Node-RED で調べるのではなく、express や Node.js https をキーワードに調べることで
問題に関連する記事が多数見つかったので、なんとか解決できました。先人達の苦労に感謝します。

ともかく、問題を解決するのって楽しいですね。スッキリ!