PHP使用Base64公证书验签及字节数组适配openssl_verify问题
PHP适配X.509证书验签及字节数组合并数据的解决方案
一、处理Base64格式的公证书
你收到的是Base64编码的DER格式证书,而openssl_verify需要PEM格式的证书作为参数。只需给Base64内容加上PEM标准头尾,并按64字符换行即可:
// 接收的Base64公证书 $base64Cert = "你的Base64证书内容"; // 解码为DER格式二进制 $certDer = base64_decode($base64Cert); // 转换为PEM格式 $certPem = "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($certDer), 64, "\n") . "-----END CERTIFICATE-----\n"; // 此时$certPem可直接传入openssl_verify
二、构造正确的待验签字符串
发送方的原始签名数据是前缀UTF8字节数组 + JSON哈希字节数组的合并结果,PHP中字符串本质是字节序列,可直接拼接字节字符串来模拟这个过程:
步骤1:构造前缀字节字符串
按发送方规则拼接前缀,并确保是UTF8编码:
$verb = "POST"; $destination = "https://example.com/webhook"; $signatureDate = "2023-10-12T20:53:50+00:00"; $signaturePrefix = $verb . ";" . $destination . ";" . $signatureDate . ";"; // 转换为UTF8字节序列(PHP字符串直接存储字节) $prefixBytes = mb_convert_encoding($signaturePrefix, "UTF-8");
步骤2:获取JSON哈希的字节字符串
需要和发送方使用完全相同的哈希算法(比如SHA256),并获取原始字节而非十六进制字符串:
// 原始JSON数据 $jsonData = "你的JSON内容"; // 计算哈希(第三个参数true返回原始字节字符串) $hashBytes = hash("sha256", $jsonData, true);
步骤3:合并字节字符串得到待验签数据
$data = $prefixBytes . $hashBytes;
三、完整验签代码
注意指定正确的签名算法(需和发送方一致,示例为SHA256withRSA):
// 解码收到的Base64签名 $signature = "接收的Base64签名内容"; $signatureDecoded = base64_decode($signature); // 执行验签 $ok = openssl_verify($data, $signatureDecoded, $certPem, OPENSSL_ALGO_SHA256); switch ($ok) { case 1: echo "签名验证通过"; break; case 0: echo "签名验证失败"; break; default: echo "验签错误:" . openssl_error_string(); }
常见验签失败排查点
- 确认哈希算法完全匹配(比如发送方用SHA1还是SHA256)
- 检查前缀拼接规则是否和发送方一致(包括末尾的分号)
- 确保JSON数据未被修改(比如空格、换行符是否和发送方一致)
- 验证证书转换是否正确(可通过
openssl_x509_parse($certPem)检查证书信息)
内容的提问来源于stack exchange,提问作者Tym
相关产品推荐
相关产品推荐

