string 在 Windows 上从 bash 脚本运行 Openssl - 主题不以“/”开头
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31506158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Running Openssl from a bash script on windows - Subject does not start with '/'
提问by iss42
In my script I have:
在我的脚本中,我有:
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}"
Running this on Windows in Git Bash 3.1 gives:
在 Git Bash 3.1 中的 Windows 上运行它给出:
Subject does not start with '/'.
Tried escaping the subj like so: -subj \"/C=UK/ST=someplace/L=Provo/O=Achme/CN=${FQDN}\"
尝试像这样转义 subj: -subj \"/C=UK/ST=someplace/L=Provo/O=Achme/CN=${FQDN}\"
Still doesn't work. Any ideas?
还是不行。有任何想法吗?
回答by Korroz
This issue is specific to MinGW/MSYSwhich is commonly used as part of the Git for Windowspackage.
此问题特定于MinGW/MSYS,它通常用作Git for Windows包的一部分。
The solution is to pass the -subj
argument with leading //
(double forward slashes) and then use \
(backslashes) to separate the key/value pairs. Like this:
解决方案是-subj
使用前导//
(双正斜杠)传递参数,然后使用\
(反斜杠)分隔键/值对。像这样:
"//O=Org\CN=Name"
This will then be magically passed to openssl
in the expected form:
然后这将以openssl
预期的形式神奇地传递给:
"/O=Org/CN=Name"
So to answer the specific question, you should change the -subj
line in your script to the following.
因此,要回答特定问题,您应该-subj
将脚本中的行更改为以下内容。
-subj "//C=GB\ST=someplace\L=Provo\O=Achme\CN=${FQDN}"
That should be all you need.
这应该就是你所需要的。
What is this magic?
这是什么魔法?
For those curious about exactly what is going on here, I can explain this mystery. The reason is that MSYS reasonably assumes that arguments containing slashes are actually paths. And when those arguments are passed to an executable that haven't been compiled specifically for MSYS (like openssl
in this case) then it will convert POSIX paths to Win32 paths. The rules for this conversion are quite complex as MSYS tries its best to cover most common scenarios for interoperability. This also explains why using openssl
from a windows command prompt (cmd.exe
) works fine, because no magical conversions are made.
对于那些对这里到底发生了什么感到好奇的人,我可以解释这个谜。原因是 MSYS 合理地假设包含斜杠的参数实际上是路径。当这些参数传递给尚未专门为 MSYS 编译的可执行文件(如openssl
本例中)时,它会将POSIX 路径转换为 Win32 路径。这种转换的规则非常复杂,因为 MSYS 会尽力覆盖最常见的互操作性场景。这也解释了为什么openssl
从 Windows 命令提示符 ( cmd.exe
) 使用可以正常工作,因为没有进行神奇的转换。
You can test the conversion like this.
您可以像这样测试转换。
$ cmd //c echo "/CN=Name"
"C:/Program Files (x86)/Git/CN=Name"
We can't use the echo
executable that comes with MSYS since it was compiled for MSYS, instead we'll use the echo
builtin in cmd
. Notice that since cmd
switches starts with /
(common for windows commands) we need to handle that with double slashes. As we can see in the output the argument was expanded to a windows path and it becomes clear why openssl
does indeed claim that Subject does not start with '/'.
.
我们不能用echo
自带的MSYS,因为它被编译为可执行MSYS,相反,我们将使用echo
内置在cmd
。请注意,由于cmd
开关以/
(Windows 命令常见)开头,因此我们需要用双斜杠来处理它。正如我们在输出中看到的,参数被扩展为一个 windows 路径,很明显为什么openssl
确实声称Subject does not start with '/'.
.
Let's see some more conversions.
让我们看看更多的转换。
$ cmd //c echo "//CN=Name"
/CN=Name
Double slashes makes MSYS believe the argument is a windows style switch which results in stripping a /
only (no path conversion). You would think that with this we could just use slashes to add more key/value pairs. Let's try that.
双斜线使 MSYS 相信该参数是一个 Windows 样式开关,它导致/
仅剥离一个(无路径转换)。你会认为这样我们可以只使用斜杠来添加更多的键/值对。让我们试试看。
$ cmd //c echo "//O=Org/CN=Name"
//O=Org/CN=Name
Suddenly the double slashes in the start isn't stripped down. This is because now, with a slash following the initial double slashes, MSYS thinks we are referencing a UNC path (e.g. //server/path). If this was passed to openssl
it would skip the first key/value saying Subject Attribute /O has no known NID, skipped
.
突然间,开始时的双斜线没有被剥离。这是因为现在,在最初的双斜杠后面有一个斜杠,MSYS 认为我们正在引用一个 UNC 路径(例如 //server/path)。如果传递给openssl
它,它将跳过第一个键/值说Subject Attribute /O has no known NID, skipped
.
Here is the relevant rule from the MinGW wikiexplaining this behavior:
以下是MinGW wiki 中解释此行为的相关规则:
- An argument starting with 2 or more / is considered an escaped Windows style switch and will be passed with the leading / removed and all \ changed to /.
- Except that if there is a / following the leading block of /, the argument is considered to be a UNC path and the leading / is not removed.
- 以 2 个或更多 / 开头的参数被认为是转义的 Windows 样式开关,将在传递前导 / 的情况下删除所有 \ 更改为 /。
- 除了如果 / 的前导块后面有 /,则该参数被认为是 UNC 路径,并且不会删除前导 /。
In this rule we can see the method we could use to create the argument we want. Since all \
that follows in an argument starting with //
will be converted to plain /
. Let's try that out.
在这个规则中,我们可以看到我们可以用来创建我们想要的参数的方法。由于\
以 开头的参数中的所有内容//
都将转换为 plain /
。让我们试试看。
$ cmd //c echo "//O=Org\CN=Name"
/O=Org/CN=Name
And as we can see it does work.
正如我们所见,它确实有效。
Hope this demystifies the magic a little bit.
希望这能稍微揭开魔法的神秘面纱。
回答by Rob Frey
I personally found this to be specific to the OpenSSL binary in use. On my system using msys2/mingw64 I've noticed that two different OpenSSL binaries are present, for example:
我个人发现这是特定于使用的 OpenSSL 二进制文件的。在我使用 msys2/mingw64 的系统上,我注意到存在两个不同的 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
I believe it to be the use of /mingw64/bin/openssl
that requires using a subject that begins with //
, however I'm not sure if this is specific to the package/build or the version of OpenSSL so to be sure, the version of each binary is below:
我相信它的使用/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
I've found the following example of bash code to select the correct binary based on the OpenSSL version when using msys/mingw to work on my machine:
我发现了以下 bash 代码示例,用于在使用 msys/mingw 在我的机器上工作时根据 OpenSSL 版本选择正确的二进制文件:
# determine openssl binary to use based on OS
# -------------------------------------------
_os="$(uname -s | awk 'BEGIN{FS="_"} {print }' | egrep -o '[A-Za-z]+')"
if [ "${_os,,}" = "mingw" ] || [ "${_os,,}" == "msys" ]; then
while read -r _currentOpenSslBin; do
if [[ "$(${_currentOpenSslBin} version | awk '{print }')" =~ ^(1\.0\.[0-9].*|0\.\.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 }'))\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
In addition to fixing issues with passing the subject string I also found this to resolve issues with the size of the DN (I passed a custom openssl.cnf with a policy that did not set a max_size for any of the fields and that still had problems when using /mingw64/bin/openssl.exe
).
除了解决传递主题字符串的问题之外,我还发现这可以解决 DN 大小的问题(我传递了一个自定义 openssl.cnf,其策略未为任何字段设置 max_size 并且仍然存在问题使用时/mingw64/bin/openssl.exe
)。