
本文详解如何利用 PHP 的 openssl_csr_sign() 函数,借助自有 CA 证书和私钥对 CSR 进行签名,生成受信任的非自签名证书,并解决常见的 PEM 格式“no start line”错误。
本文详解如何利用 php 的 `openssl_csr_sign()` 函数,借助自有 ca 证书和私钥对 csr 进行签名,生成受信任的非自签名证书,并解决常见的 pem 格式“no start line”错误。
在 PKI 体系中,“非自签名证书”指由可信证书颁发机构(CA)签发、而非由证书自身私钥签名的证书。PHP 的 openssl_csr_sign() 正是实现这一功能的核心函数——它允许你以本地 CA 身份,为合法的证书签名请求(CSR)签发正式证书。
但实践中常遇到 PEM routines:PEM_read_bio:no start line 错误,其根本原因在于:openssl_csr_sign() 默认将传入的字符串参数视为 原始 PEM 内容,而非文件路径。而你的 $csrdata = "client.crt" 实际指向的是一个文件名,PHP 尝试将其当作 PEM 文本解析,却找不到 -----BEGIN CERTIFICATE REQUEST----- 等有效起始标记,从而报错。
✅ 正确做法是显式使用 file:// 协议前缀,告知 OpenSSL 从文件系统读取内容:
<?php // ✅ 正确:使用 file:// 前缀指定文件路径
$csrdata = "file://client.csr"; // 注意:应为 .csr 文件,非 .crt
$cacert = "file://CA.crt";
$privkey = array("file://CA.key", "la_cle_secrete_de_votre_certificat");
// 签发证书(有效期365天)
$usercert = openssl_csr_sign($csrdata, $cacert, $privkey, 365);
if ($usercert === false) {
die("Certificate signing failed: " . openssl_error_string());
}
// 导出为 PEM 格式字符串
openssl_x509_export($usercert, $certout);
echo "<br>FINAL RESULT:<br><pre class="brush:php;toolbar:false;">" . htmlspecialchars($certout) . "";
// 清理并输出所有 OpenSSL 错误(调试用)
while ($e = openssl_error_string()) {
echo "⚠️ 关键注意事项:
- CSR 文件必须是标准 PEM 格式,且以 -----BEGIN CERTIFICATE REQUEST----- 开头;
- client.crt 应为 client.csr —— .crt 通常表示证书(已签名),而签发操作需输入未签名的 CSR;
- CA 私钥(CA.key)必须与 CA 证书(CA.crt)匹配,且私钥需保持加密(密码正确)或解密状态(如使用空密码需确保安全);
- openssl_csr_sign() 不会自动验证 CSR 签名有效性,建议前置调用 openssl_csr_get_subject() 或 openssl_csr_verify() 增强健壮性;
- 生产环境请避免直接 echo 敏感证书内容,应通过 HTTPS 安全传输或写入受权限保护的文件。
通过以上修正,即可成功模拟 CA 行为,签发具备链式信任基础的非自签名证书,为构建内部 PKI 或开发测试环境提供可靠支持。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











