PHP中的私有证书颁发机构?

时间:2018-01-09 09:05:31

标签: php ssl x509 pki php-openssl

我正在设置私有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中管理私有CA,是否使用openssl?

1 个答案:

答案 0 :(得分:2)

是和否。

尽管使用了提供的openssl.conf文件,但PHP的OpenSSL扩展不会自动管理证书数据库和/或序列号,并且它不提供任何实用程序来帮助解决这个问题。

另一方面,数据库本身有relatively simple format,因此您可以使用原始文件系统函数自己实现它。如果你真的采用这条路线,这里有一些提示:

  • 由于每个证书记录都位于一个单独的行上,fgets()在解析时会很方便。
    • fscanf()乍一看看起来更好,但它会将所有空格都视为相同而且标签是格式的重要组成部分,所以......
    • file()更容易,但仅限于阅读。您可能需要同时读取和写入,并且您需要获取文件锁定以避免竞争条件。
  • DN字符串元素可以是任意顺序,并非所有都是必需的,并且当分隔符存在于值中时,分隔符不会被转义,因此您将发现很难以与OpenSSL CLI工具相同的方式生成分隔符。您最好在刚签名的证书上执行openssl_x509_parse()并从那里读取值。
    • 我不记得它是什么,但是这个函数在PHP 5和7之间的结果上有一些细微的差别,它对DN字符串来说很重要。
  • PHP(正确)将序列号作为整数处理,但它以十六进制表示法存储,因此您需要来回转换它。
    • 串行文件存储 next 序列号,因此您可以执行$serial = hexdec(file_get_contents($pathToSerial)),将该变量传递给openssl_csr_sign(),然后将sprintf("%X\n", $serial + 1)写入该文件。
  • 撤销时间戳位于数据库的第3列,但由于您在签名时没有撤销证书,因此它不会出现 - 这就是为什么在到期日期和序列号之间有2个选项卡,不要忘记写作时。
  • 与人们的期望相反,OpenSSL CLI工具实际上并不在同一个数据库文件上运行。它读取当前的一个,将其重命名为<filename>.old,然后创建一个全新的<filename>。这意味着,只要您使用CLI工具,任何文件系统所有权,允许您的PHP脚本访问它的权限都将丢失。
    • 运行运行时检查以访问该文件;失败时 - 中止生成/签名并记录/打印消息(可能包含chownchmod说明)以通知您。
    • 同样适用于串口和所有其他文件。
  • 虽然我从未见过它,但任何密钥生成,CSR创建和签名都不会失败。
    • 生成的pKey,CSR,证书都是相互依赖的,类型为resource(应在使用后关闭)。为了抛出异常并仅在必要时关闭资源,我喜欢预先定义保存它们的变量,并在一个闭包中预先定义use它们,以便在抛出异常之前处理所有无条件资源的例程。
    • 仅在所有3个成功后写入数据库,并最后写入串行文件。
  • 你可能已经想到了一个,但是他们的pKey资源同时拥有私钥和公钥。

正如你所看到的,如果你知道自己在做什么,它是可以管理的,但它有很多陷阱,对于一个简单的PoC来说并不值得。通过exec()(和兄弟姐妹)调用CLI工具是一个更简单的选择。