从Windows上的bash脚本运行Openssl - 主题不以'/'开头

iss*_*s42 69 windows string bash openssl

在我的剧本中我有:

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}"
Run Code Online (Sandbox Code Playgroud)

在Git Bash 3.1中在Windows上运行它给出:

Subject does not start with '/'.
Run Code Online (Sandbox Code Playgroud)

试图像这样逃避subj:-subj \"/ C = UK/ST = someplace/L = Provo/O = Achme/CN = $ {FQDN} \"

仍然无法正常工作.有任何想法吗?

Kor*_*roz 163

此问题特定于MinGW/MSYS,它通常用作Git for Windows软件包的一部分.

解决方案是-subj使用前导//(双正斜杠)传递参数,然后使用\(反斜杠)分隔键/值对.像这样:

"//O=Org\CN=Name"
Run Code Online (Sandbox Code Playgroud)

然后将以openssl预期的形式神奇地传递给它:

"/O=Org/CN=Name"
Run Code Online (Sandbox Code Playgroud)

因此,要回答具体问题,您应该-subj将脚本中的行更改为以下内容.

-subj "//C=GB\ST=someplace\L=Provo\O=Achme\CN=${FQDN}"
Run Code Online (Sandbox Code Playgroud)

这应该就是你所需要的.

这个魔法是什么?

对于那些对这里正在发生的事情感到好奇的人,我可以解释这个谜.原因是MSYS合理地假设包含斜杠的参数实际上是路径.当这些参数传递给一个尚未专门为MSYS编译的可执行文件时(如openssl本例所示),它会将POSIX路径转换为Win32路径.这种转换的规则非常复杂,因为MSYS尽力涵盖互操作性的大多数常见场景.这也解释了为什么使用opensslWindows命令提示符(cmd.exe)工作正常,因为没有进行神奇的转换.

您可以像这样测试转换.

$ cmd //c echo "/CN=Name"
"C:/Program Files (x86)/Git/CN=Name"
Run Code Online (Sandbox Code Playgroud)

我们不能使用echoMSYS附带的可执行文件,因为它是为MSYS编译的,而是我们将使用echo内置的cmd.请注意,由于cmd开关以/(常见于windows命令)开头,我们需要使用双斜杠处理它.正如我们在输出中看到的那样,参数被扩展为一个Windows路径,并且很明显为什么openssl确实声称这一点Subject does not start with '/'..

让我们看看更多转换.

$ cmd //c echo "//CN=Name"
/CN=Name
Run Code Online (Sandbox Code Playgroud)

双斜线使MSYS认为参数是一个Windows样式开关,导致/仅剥离(无路径转换).你会认为通过这个我们可以使用斜杠来添加更多的键/值对.我们试试吧.

$ cmd //c echo "//O=Org/CN=Name"
//O=Org/CN=Name
Run Code Online (Sandbox Code Playgroud)

突然间,开始时的双斜线没有被剥离.这是因为现在,在初始双斜杠之后有一个斜杠,MSYS认为我们正在引用一个UNC路径(例如// server/path).如果这被传递给openssl它将跳过第一个键/值说Subject Attribute /O has no known NID, skipped.

以下是MinGW维基解释此行为的相关规则:

  • 以2或更多/开头的参数被视为转义的Windows样式开关,将与前导/删除一起传递,并将所有\更改为/.
    • 除非在/的前导块之后有/,该参数被认为是UNC路径并且未删除前导/.

在这个规则中,我们可以看到我们可以用来创建我们想要的参数的方法.因为\以参数开头的所有内容//都将转换为plain /.让我们尝试一下.

$ cmd //c echo "//O=Org\CN=Name"
/O=Org/CN=Name
Run Code Online (Sandbox Code Playgroud)

我们可以看到它确实有效.

希望这可以揭开魔法的神秘面纱.

  • 如果我使用相同的`bash`脚本在linux环境中生成密钥怎么办?怎么会被解释为在行的中间引导双斜线和反斜杠? (4认同)
  • @Orient Linux需要另一个方向的斜杠,所以你需要检测它运行的系统类型 - 这是一个使用`case`语句和`uname -s`来检测环境的答案,你可以然后使用`if`来使用相应的斜杠 - /sf/ask/242631651/ (2认同)