Git BashでCSRを作ろうとしたらエラーが出た

# 三行まとめ

- Git Bashを使って、OpenSSLでcsrファイルを作成しようとしたけどエラーになった
- 原因はGit Bash経由で叩くOpenSSLのsubjオプション内でドットの文字解釈がうまくいってないっぽい
- PowerShellでコマンドを叩き直したらうまくいった

# 目次

- [三行まとめ](#三行まとめ)
- [目次](#目次)
- [経緯と事象](#経緯と事象)
- [試したこと（失敗例）](#試したこと失敗例)
  - [だめその1：環境変数 `MSYS_NO_PATHCONV` を設定する](#だめその1環境変数-msys_no_pathconv-を設定する)
  - [だめその2：区切り文字をバックスラッシュにする](#だめその2区切り文字をバックスラッシュにする)
- [\[解決\] うまく行った方法](#解決-うまく行った方法)
- [たぶん根本原因](#たぶん根本原因)
  - [余談](#余談)
- [おわりに](#おわりに)

# 経緯と事象

とある日、いくつかのWebサービスの証明書を更新するため、csrファイルを準備していました。
当方ではWindowsをメインで使っているため、csrファイルはGit Bashを使って作成する運用としていました。

従来の手順は、 `openssl req` コマンドの対話形式でSubjectを入力し、CSRを作成していました。
最近は作業対象の証明書が多くなってきたことから、`subj` オプションを用いてコマンドラインからSubjectを指定する方法に変更しました。

実際には以下のようなコマンドを叩いています。

```bash:実行したコマンド例
winpty openssl req -new -key ./sample.key -out ./sample.csr -subj "/C=JP/ST=Tokyo/L=Nakano-ku/O=TEST INC./OU=DEV DIVISION/CN=sample.com"
```

上記コマンドを実行したところ、以下のようなエラーが表示され、csrファイルは作成されませんでした。

```bash:エラー文言
req: subject name is expected to be in the format /type0=value0/type1=value1/type2=... where characters may be escaped by \. This name is not in that format: ...
```

エラー文言をそのまま読めば、「ドット文字がエスケープされてないエラーだよ」と教えてくれているようです。
先のコマンドでドット文字を探してみると、subjオプション内の “/O=TEST INC.” の末尾にドットが存在するので、そいつがエラーの原因のように思えます。

:::note info
急ぎ解決方法だけ知りたい方は、[\[解決\] うまく行った方法](#解決-うまく行った方法) に飛んでください！
:::

# 試したこと（失敗例）

エラーの忠告通り、ドット文字をエスケープしてコマンドを再実行しましたが、結局同じエラーとなりました。

困ったのでエラー文言で検索をかけると、以下のページにぶち当たりました。

https://github.com/openssl/openssl/issues/8795

私は光の速さでGoogle翻訳を実行して内容を確認しました。以下は、このページで提案された方法の試行錯誤の記録をしておきます。

## だめその1：環境変数 `MSYS_NO_PATHCONV` を設定する

Git Bashのパス変換を無効化する環境変数とのことです。
意味もわからず（よくない）環境変数を設定（よくない）しましたが、事象は解決しませんでした。

## だめその2：区切り文字をバックスラッシュにする

前述のGitHubのページの [このコメント](https://github.com/openssl/openssl/issues/8795#issuecomment-1334356802) に記載されている方法です。
もともとのコマンドでは、subjオプションの区切り文字をスラッシュで指定していましたが、それを、「**最初の区切り文字をスラッシュ2つ、以降の区切り文字をバックスラッシュにする**」という内容です。

これに従ってコマンドを実行すると、確かにエラーは出ない。CSRも出力されました。

```sh:こんな感じ
winpty openssl req -new -key ./sample.key -out ./sample.csr -subj "//C=JP\ST=Tokyo\L=Nakano-ku\O=TEST INC.\OU=DEV DIVISION\CN=sample.com"
```

ただし、出力されたファイルの内容を **CSRの中身をサイトで確認すると、Subjectがバグってました。**
一見うまくいっているように見えて、本質的な解決ではなかったようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879145/b137f346-3b3d-48d3-a1bb-37d0024e52d6.png)

先のGitHubのサイトでは、このコメントをもとにして動いたって人がいたんですが、その人は本当に大丈夫でしょうか、、、確かにエラーは出ないけど、、、。

# [解決] うまく行った方法

結局、元のコマンドでOpenSSLをフルパスにし、PowerShellで叩いたらエラーも表示されず、内容も期待値通りのCSRが作成できました。たぶんコマンドプロンプトでも通ると思う。
例えば以下のようなコマンドです。

```powershell:Powershellで実行する
C:\Users\ユーザー名\AppData\Local\Programs\Git\usr\bin\openssl.exe req -new -key ./sample.key -out ./sample.csr -subj "/C=JP/ST=Tokyo/L=Nakano-ku/O=TEST INC./OU=DEV DIVISION/CN=sample.com"
```

# たぶん根本原因

Git Bashでは、winptyコマンドを用いることでWindows環境におけるUNIXエミュレーターとの文字コード差分を吸収し、入出力を可能にしているとのことです。
以下サイトを参考にさせていただきました。

https://mseeeen.msen.jp/what-does-winpty-command-do/

ここからは推測ですが、Windowsとエミュレーターの値渡しの際、本来のOpenSSLコマンドが期待する形式でオプションが渡されずにエラーとなってしまったのだと思います。

## 余談

手元のMacで以下のコマンドを実行したら、普通に実行できました。
やっぱりwinptyが原因ぽい。

```bash
openssl req -new -key ./sample.key -out ./sample.csr -subj "/C=JP/ST=Tokyo/L=Nakano-ku/O=TEST INC./OU=DEV DIVISION/CN=sample.com"
```

# おわりに

この件以前にも、エラーが解消したように見えるけど実は解決してなかった、、ということがあり、再確認の重要性をしみじみ実感した一件でした。
Wチェックだいじ。