我正在设置一个私有(private) CA,我想使用 PHP 与其交互。我试过使用 PHP 的 built-in openssl library .因此,我创建了一个 CSR,并使用 openssl_csr_sign
对其进行签名。
这确实签署了 CSR,仅此而已。在 OpenSSL 的 CLI 中,它类似于
openssl x509 -req -days 360 -in file.csr -CA ca.crt -CAkey ca.key ...
而我想要类似的东西
openssl ca -cert ca.crt -keyfile ca.key -in file.csr -out file.crt ...
基本上它使用 x509 模块而不是 ca 模块对其进行签名。所以它不会将其写入openssl.cnf
中指定的数据库,它不会使用或更新序列号;它更像是“我信任这个人,所以我会用我的私钥签署他的公钥”而不是实际的 CA。有没有办法在 PHP 中管理私有(private) CA,是否使用 openssl?
最佳答案
是也不是。
尽管使用提供的 openssl.conf 文件,但 PHP 的 OpenSSL 扩展不会自动管理证书数据库和/或序列号,并且它不会提供任何实用程序来帮助实现这一点。
另一方面,数据库本身有一个relatively simple format ,因此您可以使用原始文件系统函数自己实现它。如果您真的选择了这条路线,这里有一些提示:
- 由于每个证书记录都位于单独的一行中,
fgets()
解析它时派上用场。-
fscanf()
乍一看看起来更好,但它对所有空格都一视同仁,制表符是格式的重要组成部分,所以 ... -
file()
更容易,但仅供阅读。您可能需要同时读取和写入,并且需要获取文件锁以避免竞争条件。
-
- DN 字符串元素可以按任意顺序排列,并非所有元素都是强制性的,并且分隔符在值中出现时不会转义,因此您会发现很难以与 OpenSSL CLI 工具相同的方式生成它.你最好做一个 openssl_x509_parse()在刚刚签署的证书上并从那里读取值。
- 我不记得它是什么,但该函数在 PHP 5 和 7 之间的结果上有一些细微差别,它对 DN 字符串很重要。
- PHP(正确地)将序列号作为整数处理,但它以十六进制表示法存储,因此您需要来回转换它。
- 序列文件存储下一个序列号,所以你可以做
$serial = hexdec(file_get_contents($pathToSerial))
, 将该变量传递给openssl_csr_sign()
然后写sprintf("%X\n", $serial + 1)
到文件。
- 序列文件存储下一个序列号,所以你可以做
- 吊销时间戳位于数据库的第 3 列,但由于您在签署证书时没有立即吊销证书,因此它不会出现 - 这就是为什么在到期日期和序列号之间有 2 个选项卡的原因,不要写作时不要忘记这一点。
- 与人们的预期相反,OpenSSL CLI 工具实际上并不对同一个数据库文件进行操作。它读取当前的,将其重命名为
<filename>.old
然后创建一个全新的<filename>
.这意味着无论何时使用 CLI 工具,任何文件系统所有权和授予 PHP 脚本访问权限的权限都会丢失。- 对文件的访问进行运行时检查;失败时 - 中止生成/签名并记录/打印消息(可能带有
chown
、chmod
说明)以通知您。 - 同样适用于序列号和所有其他文件。
- 对文件的访问进行运行时检查;失败时 - 中止生成/签名并记录/打印消息(可能带有
- 虽然我从未见过这种情况,但 key 生成、CSR 创建和签名中的任何一个都可能失败。
- 生成的 pKey、CSR、证书都是相互依赖的,类型为
resource
(使用后应关闭)。要抛出异常并仅在必要时关闭资源,我喜欢预先定义保存它们的变量和use
它们在一个闭包中,该闭包在抛出异常之前处理所有条件性无资源例程。 - 3个都成功后才写入数据库,最后写入串口文件。
- 生成的 pKey、CSR、证书都是相互依赖的,类型为
- 您可能已经想通了,但是他们的 pKey 资源同时包含私钥和公钥。
如您所见,如果您知道自己在做什么,它是可以管理的,但它有很多问题,对于简单的 PoC 来说并不值得。通过 exec()
调用 CLI 工具(和 sibling )是一个更简单的选择。
关于php - PHP 中的私有(private)证书颁发机构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48164595/