WindowsでbashスクリプトからOpensslを実行する-件名が「/」で始まらない


83

私のスクリプトには次のものがあります。

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のGitBash 3.1で実行すると、次のようになります。

Subject does not start with '/'.

次のようにsubjをエスケープしようとしました:-subj \ "/ C = UK / ST = someplace / L = Provo / O = Achme / CN = $ {FQDN} \"

それでも動作しません。何か案は?


1
標準の最初の質問:スクリプトファイルにはDOS / Windowsスタイルの行末(キャリッジリターン+ラインフィード)がありますか、それともUNIXスタイル(ラインフィードのみ)ですか?スクリプトをcat -vet /path/to/scriptで印刷してみて、行が「^ M $」(Windowsスタイル)で終わるのか、「$」(unixスタイル)だけで終わるのかを確認してください。
ゴードンデイヴィソン2015

1
これはbashスクリプトですか?どのような環境で実行しますか?set -vxこの行では、スクリプトショーの先頭に何が追加されていますか?
Etan Reisner

@EtanReisnerset -vxは便利なおかげです!環境はWindows、Git bash3.1です。-vx、私が得る+ 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=domain.comかを示し、非引用符で囲まれた-subj文字列を。しかし、これをスクリプトから引用形式に変換する方法を理解することはできません。
iss42 2015

@GordonDavissonありがとう!スクリプトには「^ M $」行末があります
iss42 2015

1
-vx出力の引用符で囲まれていない引数は、驚くべきことでも問題でもありません。引用符は、コマンドの実行自体ではなく、シェルの解析用です。その出力は私には正しいように見えます。DOSの行末は一般的には良い考えではありませんが、ここで問題を引き起こしたようには見えません(DOSの行末を削除すると問題が修正されない限り、エラーメッセージで少し混乱します)。
Etan Reisner

回答:


197

この問題は、Git forWindowsパッケージの一部として一般的に使用されているMinGW / MSYSに固有のものです。

解決策は、-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"

echoMSYS用にコンパイルされているため、MSYSに付属の実行可能ファイルを使用することはできません。代わりに、echo組み込みのを使用しますcmdcmdスイッチは/(Windowsコマンドで一般的)で始まるため、ダブルスラッシュで処理する必要があることに注意してください。出力でわかるように、引数はWindowsパスに展開され、なぜopenssl実際にそれを主張するのかが明らかになりSubject does not start with '/'.ます。

さらにいくつかの変換を見てみましょう。

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

二重スラッシュにより、MSYSは、引数がWindowsスタイルのスイッチであると信じて、結果としてストリッピング/のみ(パス変換なし)になります。これにより、スラッシュを使用してキーと値のペアを追加できると思うでしょう。それを試してみましょう。

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

突然、開始時の二重スラッシュが削除されません。これは、最初の二重スラッシュの後にスラッシュが付いているため、MSYSはUNCパス(例:// server / path)を参照していると見なしているためです。これが渡された場合openssl、最初のキー/値をスキップしてSubject Attribute /O has no known NID, skipped

この動作を説明するMinGWwikiの関連ルールは次のとおりです。

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

このルールでは、必要な引数を作成するために使用できるメソッドを確認できます。で\始まる引数に続くものはすべて//プレーンに変換されるためです/。それを試してみましょう。

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

そして、私たちが見ることができるように、それは機能します。

これが魔法を少しわかりやすくすることを願っています。


1
素晴らしい説明。
trebor 2016年

4
同じbashスクリプトを使用してLinux環境でキーを生成するとどうなりますか?行の中央にある先頭のダブルスラッシュとバックスラッシュはどのように解釈されますか?
Tomilov Anatoliy 2017

3
@Orient Linuxは反対方向にスラッシュが必要なので、実行されているシステムのタイプを検出する必要があります-caseステートメントを使用しuname -sて環境を検出するための回答を次に示します。これifを使用して、適切なシステムを使用できます。スラッシュ-stackoverflow.com/questions/3466166/…–
ティムルイス

完全に素晴らしい。私は同じ問題に巻き込まれ、POSIXからWin32へのパス変換について完全に忘れていました。私はそれを間違って引用していると思い続けました。
davewasthere

0

私は個人的に、これが使用中のOpenSSLバイナリに固有であることに気づきました。msys2 / mingw64を使用している私のシステムでは、2つの異なるOpenSSLバイナリが存在することに気づきました。次に例を示します。

$ whereis openssl; echo; which openssl
openssl: /usr/bin/openssl.exe /usr/lib/openssl /mingw64/bin/openssl.exe /usr/share/man/man1/openssl.1ssl.gz

/mingw64/bin/openssl

それを使用するには/mingw64/bin/openssl、で始まるサブジェクトを使用する必要があると思いますが//、これがパッケージ/ビルドまたはOpenSSLのバージョンに固有であるかどうかはわかりません。確かに、各バイナリのバージョンは以下のとおりです。

$ while read -r _openSslBin; do printf "${_openSslBin}: "; ${_openSslBin} version; done < <(whereis openssl | egrep -o '[^ ]+?\.exe ')
/usr/bin/openssl.exe: OpenSSL 1.0.2p  14 Aug 2018
/mingw64/bin/openssl.exe: OpenSSL 1.1.1  11 Sep 2018

msys / mingwを使用してマシンで作業するときに、OpenSSLバージョンに基づいて正しいバイナリを選択するbashコードの次の例を見つけました。

# determine openssl binary to use based on OS
# -------------------------------------------
_os="$(uname -s | awk 'BEGIN{FS="_"} {print $1}' | egrep -o '[A-Za-z]+')"
if [ "${_os,,}" = "mingw" ] || [ "${_os,,}" == "msys" ]; then
  while read -r _currentOpenSslBin; do
    if [[ "$(${_currentOpenSslBin}  version | awk '{print $2}')" =~ ^(1\.0\.[0-9].*|0\.\9\.8.*)$ ]]; then
      _openSslBin="${_currentOpenSslBin}"
    fi
  done < <(whereis openssl | egrep -o '\/[^ ]+?\.exe ' | egrep -v 'mingw')
  if [ -n "${_openSslBin}" ]; then
    printf "OpenSSL Binary: ${_openSslBin} (v. $(${_openSslBin}  version | awk '{print $2}'))\n"
  else
    printf "Unable to find compatible version of OpenSSL for use with '${_os}' OS, now exiting...\n"
    exit 1
  fi
else
  _openSslBin="openssl"
fi

# display selected openssl binary and it's version
# ------------------------------------------------
printf "${_openSslBin}: "; ${_openSslBin} version

件名文字列の受け渡しに関する問題の修正に加えて、DNのサイズに関する問題を解決することもわかりました(どのフィールドにもmax_sizeを設定せず、まだ問題が発生しているポリシーを使用してカスタムopenssl.cnfを渡しましたを使用する場合/mingw64/bin/openssl.exe)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.