PHP Conference Japan 2024

openssl_verify

(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)

openssl_verify验证签名

描述

openssl_verify(
    字符串 $data,
    字符串 $signature,
    OpenSSLAsymmetricKey|OpenSSLCertificate|数组|字符串 $public_key,
    字符串|整数 $algorithm = OPENSSL_ALGO_SHA1
): 整数|false

openssl_verify() 验证使用与 $public_key 关联的公钥,$signature 是否为指定 $data 的正确签名。这必须是用于签名的私钥对应的公钥。

参数

data

之前用于生成签名的字符串数据

signature

原始二进制字符串,由 openssl_sign() 或类似方法生成

public_key

OpenSSLAsymmetricKey - 由 openssl_get_publickey() 返回的密钥

字符串 - PEM 格式的密钥(例如 -----BEGIN PUBLIC KEY----- MIIBCgK...

algorithm

整数 - 这些 签名算法 之一。

字符串 - 由 openssl_get_md_methods() 返回的有效字符串,例如 "sha1WithRSAEncryption" 或 "sha512"。

返回值

如果签名正确,则返回 1;如果签名不正确,则返回 0;如果出错,则返回 -1 或 false

变更日志

版本 描述
8.0.0 $public_key 现在接受 OpenSSLAsymmetricKeyOpenSSLCertificate 实例;以前,接受类型为 OpenSSL keyOpenSSL X.509资源

范例

示例 #1 openssl_verify() 例子

<?php
// 假设 $data 和 $signature 包含数据和签名

// 从证书中获取公钥并准备它
$pubkeyid = openssl_pkey_get_public("file://src/openssl-0.9.6/demos/sign/cert.pem");

// 指明签名是否正确
$ok = openssl_verify($data, $signature, $pubkeyid);
if (
$ok == 1) {
echo
"good";
} elseif (
$ok == 0) {
echo
"bad";
} else {
echo
"ugly, error checking signature";
}
// 释放内存中的密钥
openssl_free_key($pubkeyid);
?>

示例 #2 openssl_verify() 例子

<?php
// 要签名的的数据
$data = 'my data';

// 创建新的私钥和公钥
$private_key_res = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
$details = openssl_pkey_get_details($private_key_res);
$public_key_res = openssl_pkey_get_public($details['key']);

// 创建签名
openssl_sign($data, $signature, $private_key_res, "sha256WithRSAEncryption");

// 验证签名
$ok = openssl_verify($data, $signature, $public_key_res, OPENSSL_ALGO_SHA256);
if (
$ok == 1) {
echo
"有效";
} elseif (
$ok == 0) {
echo
"无效";
} else {
echo
"错误: ".openssl_error_string();
}
?>

参见

添加备注

用户贡献的笔记 8 条笔记

Stiv
18年前
我终于找到了一种验证签名的方法。文档中的示例不起作用。下面的代码有效 :)

<?php
// 假设 $data 包含要签名的数据

// 从文件中获取证书并准备它
$fp = fopen("path/file.pem", "r");
$cert = fread($fp, 8192);
fclose($fp);

// 指明签名是否正确
// 使用证书,而不是公钥
$ok = openssl_verify($data, $signature, $cert);
if (
$ok == 1) {
echo
"good";
} elseif (
$ok == 0) {
echo
"bad";
} else {
echo
"ugly, error checking signature";
}
?>
mikey at badpenguins dot com
14年前
我花了几天时间仔细研究 php openssl 文档,试图弄清楚如何完成一项听起来很简单的事情——给定两个 PEM 编码的证书,一个是另一个的签名者吗?在 openssl_verify() 文档或注释中,都没有解释在哪里获取现有证书的签名。openssl_x509_parse() 函数看起来很有希望,但它是一个可能发生变化的不稳定 API。

我不得不编写自己的代码来确定一个证书是否签署了另一个证书,它位于此处:http://badpenguins.com/source/misc/isCertSigner.php?viewSource

简而言之,这是我学到的……

已签名的 X.509 证书中的签名数据包含使用签名者的公钥加密的关于签名的 DER 格式数据。数据包含原始主题证书的哈希值以及用于创建签名的加密算法信息。

因此,您需要获取此签名数据和原始证书的副本(已删除颁发者和签名序列)。使用颁发者使用的相同算法对原始证书的副本(无颁发者/签名序列)进行哈希处理,如果哈希值匹配,则您拥有签署证书的颁发者证书。
meint dot post at bigfoot dot com
23年前
任何尝试使基于 Win32 CryptoAPI 的数字签名组件与 openssl_verify() 函数一起工作的人都应该知道,CryptoAPI PKCS1 (RSA) 方法使用反向顺序的字节,而 openssl_verify() 方法则需要正确格式化的 PKCS1 数字签名(也应该是)。我以艰难的方式了解了这一点,并且花了一些时间才挖掘出这一点。一个简单的 VBScript 解决方案来反转字节顺序

N = Len(Blob.Hex)

’ 使用十六进制格式反转签名中的字节
For i = 1 To N - 1 Step 2
s = Mid(Blob, i, 2) & s
Next

s 包含反向顺序的数字签名。Blob 是一个任意的二进制容器。

以十六进制格式发送签名,并在 PHP 中使用 hex2bin 方法将其转换为 openssl_verify() 的正确格式,即

function hex2bin($data) {

$len = strlen($data);
return pack("H" . $len, $data);

}

就是这样,希望对您有所帮助。顺便说一句,我使用 ASPEncrypt 在 Win32 平台上进行测试。仅适用于 Internet Explorer,但您也可以使用 Java applet,并且不会出现上述任何问题 :-)
peter dot labos at gmail dot com
6年前
即使为 false,openssl_verify() 也会填充 openssl_error_string()。

当 openssl_verify() 返回 0 时,openssl_error_string() 将填充为 1。
我花了很长时间才理解,而我接下来对 openssl 的调用因错误检查而失败。

<?php
$c
= file_get_contents($filename);
$publicKey = openssl_pkey_get_public($c);
$result = openssl_verify('freedom', 'someirrelevantnosign', $publicKey);

$error = "";

while (
$msg = openssl_error_string() !== false) {
$error .= $msg;
}

if (!empty(
$error)) {
echo
$error; // 1
}
steve dot venable at lmco dot com
22年前
关于 openssl_verify()(以及其他一些函数)的说明。公钥来自任何支持格式的证书(如示例所示,使用 openssl_get_publickey() 获取资源 ID)。但是经过一些反复试验后,我发现签名字符串必须为二进制格式。虽然不会发生错误,但传递 base64 格式的签名字符串(PEM 格式?),您只会得到不匹配的结果。当我自行进行 base64 解码时,验证返回匹配项(返回值 1)。您可以简单地删除开头/结尾行并获取 'base64_decode()' 函数的输出。
phpdev at fpierrat dot fr
3年前
如文档所述:“如果签名正确,则返回 1;如果签名不正确,则返回 0;如果出错,则返回 -1 或 false。”

在第二个示例以及 Stiv 的注释中,以下条件将同时匹配 0 或 false,它们具有不同的含义
elseif ($ok == 0) {
echo "bad";
}

应该在这里进行相同的测试 (===) 而不是相等测试 (==)
elseif ($ok === 0) {
echo "bad";
}
---
var_dump(0==false); //==> true
var_dump(0===false);//==> false
attila dot m dot magyar at gmail dot com
10年前
mikey at badpenguins dot com -- 使用 openssl_x509_checkpurpose() 似乎可以在 php 中验证 X509 证书链。
jeremie dot gomez at gmail dot com
13年前
您实际上可以使用公钥作为第三个参数,而不是证书。

如果您无法使其工作,请确保

1) 您的公钥格式正确。似乎它必须具有 ----BEGIN PUBLIC KEY---- 和 ----END PUBLIC KEY----

2) 您的签名采用二进制格式。您可以为此使用 php base64_decode。
To Top