1. ホーム
  2. windows

[解決済み] WindowsでbashスクリプトからOpensslを実行する - Subjectが'/'で始まらない

2023-03-27 12:24:26

質問

私のスクリプトでは

openssl req \
  -x509 \
  -new \
  -nodes \
  -key certs/ca/my-root-ca.key.pem \
  -days 3652 \
  -out certs/ca/my-root-ca.crt.pem \
  -subj "/C=GB/ST=someplace/L=Provo/O=Achme/CN=${FQDN}"

WindowsでGit Bash 3.1で実行すると、このようになります。

Subject does not start with '/'.

こんな感じでsubjをエスケープしてみました。 -subj \"/C=UK/ST=someplace/L=Provo/O=Achme/CN=${FQDN}" のようにエスケープしてみました。

まだうまくいきません。何かアイデアはありますか?

どのように解決するのですか?

この問題は MinGW/MSYS の一部として一般的に使用されている Windows 用の Git パッケージの一部としてよく使われます。

解決策は -subj 引数に、先頭の // (ダブルフォワードスラッシュ)を使用し、その後 \ (バックスラッシュ)でキーと値のペアを区切ります。こんな感じ。

"//O=Org\CN=Name"

これは、魔法のように openssl に期待通りの形で渡されます。

"/O=Org/CN=Name"

ということで、具体的な質問には -subj の行を次のように変更してください。

-subj "//C=GB\ST=someplace\L=Provo\O=Achme\CN=${FQDN}"

これだけでいいはずです。

この魔法は何ですか?

正確に何が起こっているのか知りたがっている人のために、この謎を説明しましょう。MSYS は、スラッシュを含む引数が実際にパスであると合理的に仮定しているからです。そして、これらの引数がMSYS用に特別にコンパイルされていない実行ファイルに渡されたとき(たとえば openssl のような)実行ファイルに渡されると、それは POSIX パスを Win32 パスに変換します。 . この変換のルールは、MSYSが相互運用性のために最も一般的なシナリオをカバーしようとするため、非常に複雑になっています。これはまた、なぜ openssl を Windows のコマンドプロンプトから使用した場合 ( cmd.exe ) は、魔法のような変換が行われないので、問題なく動作します。

このように変換をテストすることができます。

$ cmd //c echo "/CN=Name"
"C:/Program Files (x86)/Git/CN=Name"

を使うことはできません。 echo はMSYS用にコンパイルされたものなので、MSYSに付属する実行ファイルを使うことはできませんが、代わりに echo のビルトインを使用します。 cmd . 注目すべきは cmd で始まるので / (Windowsコマンドの一般的なもの)で始まる場合は、ダブルスラッシュで処理する必要があります。出力でわかるように、引数はウィンドウズのパスに展開され、なぜ openssl が確かに Subject does not start with '/'. .

もう少しコンバージョンを見てみましょう。

$ cmd //c echo "//CN=Name"
/CN=Name

スラッシュが2つあると、MSYSは引数がウィンドウズ・スタイルのスイッチであると認識し、結果として / のみをストリッピングします(パス変換なし)。これなら、スラッシュを使ってキーと値のペアを増やせばいいと思うでしょう。それを試してみましょう。

$ cmd //c echo "//O=Org/CN=Name"
//O=Org/CN=Name

突然、冒頭のダブルスラッシュが取り除かれなくなりました。これは、最初のダブルスラッシュに続くスラッシュによって、MSYS が UNC パス (例: //server/path) を参照していると判断したためです。もしこれが openssl に渡された場合、最初のキー/値である Subject Attribute /O has no known NID, skipped .

以下は、関連するルールを MinGW wiki から、この挙動を説明する関連ルールを示します。

  • 2つ以上の / で始まる引数はエスケープされたWindowsスタイルスイッチとみなされ、先頭の / を削除し、すべてのディスクを / に変更して渡されます。
    • ただし、先頭の / のブロックの後に / がある場合、引数は UNC パスとみなされ、先頭の / は削除されません。

このルールでは、私たちが望む引数を作成するために使用できるメソッドを見ることができます。すべての \ で始まる引数に続くものは // で始まる引数は、プレーンな / . 試してみましょう。

$ cmd //c echo "//O=Org\CN=Name"
/O=Org/CN=Name

そして、見ての通り、これはうまくいっています。

これで少しは魔法が解明されたでしょうか。