从Windows上的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}" 

在Git Bash 3.1的Windows上运行这个function给出:

 Subject does not start with '/'. 

尝试转义这样的主题:-subj \“/ C = UK / ST = someplace / L = Provo / O = Achme / CN = $ {FQDN} \”

依然不起作用。 有任何想法吗?

这个问题是特定于MinGW / MSYS ,它通常被用作Git for Windows包的一部分。

解决方法是传递带有前导的// (双正斜杠)的-subj参数,然后使用\ (反斜杠)来分隔键/值对。 喜欢这个:

 "//O=Org\CN=Name" 

这将会神奇地传递给预期的形式:

 "/O=Org/CN=Name" 

所以要回答具体的问题,你应该把脚本中的-subj行更改为以下内容。

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

这应该是你需要的一切。

这是什么魔术?

对于那些正在发生的事情,我可以解释这个谜。 原因是MSYS合理地认为包含斜线的参数实际上是路径。 当这些参数传递给一个没有专门针对MSYS编译的可执行文件(比如openssl )时,它将把POSIX路径转换成Win32路径 。 这个转换的规则是相当复杂的,因为MSYS尽力覆盖大多数常见的互操作场景。 这也解释了为什么从Windows命令提示符( cmd.exe )使用openssl工作正常,因为没有魔术转换。

你可以像这样测试转换。

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

我们不能使用MSYS自带的echo可执行文件,而是使用cmdecho内置cmd 。 请注意,由于cmd开关以/ (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路径(例如//服务器/路径)。 如果这被传递给openssl它会跳过第一个键/值,说Subject Attribute /O has no known NID, skipped

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

  • 一个以2或更多/开头的参数被认为是一个逃逸的Windows风格的开关,并将通过前导/删除和所有\改为/。
    • 除了如果/之后有一个/后面的参数,这个参数被认为是一个UNC路径,并且前导/不会被删除。

在这个规则中,我们可以看到我们可以用来创建我们想要的参数的方法。 由于以//开头的参数中的所有\将被转换为plain / 。 让我们试试看。

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

而且我们可以看到它确实有效。

希望这个神秘的一点点神秘。