博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP版本兼容之openssl调用参数
阅读量:7231 次
发布时间:2019-06-29

本文共 5330 字,大约阅读时间需要 17 分钟。

背景与问题解决方式

老项目重构支付宝部分代码整合支付宝新的sdk时发现验签总是失败,才发现是open_verify最后的参数传输问题。而open_sign同样如此。本文主要说明open_verify的解决方式和代码解析。而问题的解决方式也是修改最后的加密类型参数,解决方式代码如下:

// 将最后的常量OPENSSL_ALGO_SHA256修改成字符串  openssl_verify($data, base64_decode($sign), $res, "sha256WithRSAEncryption");复制代码

官方文档解释

上面只说了问题的出现与对应的解决方式,如果有兴趣继续了解该函数的,可以继续往下读,首先来看下官方文档对此函数的解释。

int openssl_verify ( string $data , string $signature , mixed $pub_key_id [, mixed $signature_alg = OPENSSL_ALGO_SHA1 ] )复制代码

参数注释

  • data 以前用来生成签名的数据字符串。

  • signature 原始二进制字符串,通过openssl_sign()或类似的函数生成。

  • pub_key_id

    • resource - 一个密钥, 通过 openssl_get_publickey() 函数返回。
    • string - 一个 PEM 格式的密钥, 比如, "-----BEGIN PUBLIC KEY----- MIIBCgK..."
  • signature_alg

    • int - 以下签名算法之一Signature Algorithms.
    • string - 由openssl_get_md_methods()函数返回的可用字符串,比如, "sha1WithRSAEncryption" 或者 "sha512".

官方文档给出的signature_alg参数可以为int或者string类型,int类型直接调用对应的枚举值,string则是openssl_get_md_methods函数返回的可用字符串,调用openssl_get_md_methods方法打印参数如下,而这些字符串也是对应加密方式的摘要信息,后文源码中可能会看的对函数调用稍微明白那么一丢丢。

Array(    [0] => DSA    [1] => DSA-SHA    [2] => DSA-SHA1    [3] => DSA-SHA1-old    [4] => DSS1    [5] => GOST 28147-89 MAC    [6] => GOST R 34.11-94    [7] => MD4    [8] => MD5    [9] => MDC2    [10] => RIPEMD160    [11] => RSA-MD4    [12] => RSA-MD5    [13] => RSA-MDC2    [14] => RSA-RIPEMD160    [15] => RSA-SHA    [16] => RSA-SHA1    [17] => RSA-SHA1-2    [18] => RSA-SHA224    [19] => RSA-SHA256    [20] => RSA-SHA384    [21] => RSA-SHA512    [22] => SHA    [23] => SHA1    [24] => SHA224    [25] => SHA256    [26] => SHA384    [27] => SHA512    [28] => dsaEncryption    [29] => dsaWithSHA    [30] => dsaWithSHA1    [31] => dss1    [32] => ecdsa-with-SHA1    [33] => gost-mac    [34] => md4    [35] => md4WithRSAEncryption    [36] => md5    [37] => md5WithRSAEncryption    [38] => md_gost94    [39] => mdc2    [40] => mdc2WithRSA    [41] => ripemd    [42] => ripemd160    [43] => ripemd160WithRSA    [44] => rmd160    [45] => sha    [46] => sha1    [47] => sha1WithRSAEncryption    [48] => sha224    [49] => sha224WithRSAEncryption    [50] => sha256    [51] => sha256WithRSAEncryption    [52] => sha384    [53] => sha384WithRSAEncryption    [54] => sha512    [55] => sha512WithRSAEncryption    [56] => shaWithRSAEncryption    [57] => ssl2-md5    [58] => ssl3-md5    [59] => ssl3-sha1    [60] => whirlpool)复制代码

由此也可看出函数是兼容两种模式的,但是为什么php版本会有兼容问题么?在openssl库版本是一致的情况下,接下来的原因应该只遗留在php扩展的问题上。那下面来看看对应的源码去发现问题出现在哪吧。

函数源码

openssl_verify函数源码

openssl_verify源码中有这样一段,如果参数method为string类型的时候,调用openssl库的EVP_get_digestbyname方法,在网上查看了下此方法的作用,主要是根据摘要信息返回 EVP_MD结构,而EVP_get_digestbyname方法由于是openssl库源代码并且对C语言知之甚少,熊某就没去查看, 只是了解php代码调用背后的一些处理逻辑,有兴趣的可以看看openssl库的代码实现。

if (method == NULL || Z_TYPE_P(method) == IS_LONG) {        if (method != NULL) {            signature_algo = Z_LVAL_P(method);        }        mdtype = php_openssl_get_evp_md_from_algo(signature_algo);    } else if (Z_TYPE_P(method) == IS_STRING) {        mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));    } else {        php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");        RETURN_FALSE;    }复制代码

原来是枚举值的问题?

一开始本人以为php5.3版本会是method参数类型的限制,一看源代码才发现,openssl_verify函数的实现逻辑是一致的,都是检测method参数类型,那么问题就不出现在参数类型上,然后我查看了参数为long类型是所调用的php_openssl_get_evp_md_from_algo函数,果然发现了问题所在。源码如下:

  • php5.3.27
static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {
{
{ */ EVP_MD *mdtype; switch (algo) { case OPENSSL_ALGO_SHA1: mdtype = (EVP_MD *) EVP_sha1(); break; case OPENSSL_ALGO_MD5: mdtype = (EVP_MD *) EVP_md5(); break; case OPENSSL_ALGO_MD4: mdtype = (EVP_MD *) EVP_md4(); break;#ifdef HAVE_OPENSSL_MD2_H case OPENSSL_ALGO_MD2: mdtype = (EVP_MD *) EVP_md2(); break;#endif case OPENSSL_ALGO_DSS1: mdtype = (EVP_MD *) EVP_dss1(); break; default: return NULL; break; } return mdtype;}复制代码
  • php7.1.18
static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {
{
{ */ EVP_MD *mdtype; switch (algo) { case OPENSSL_ALGO_SHA1: mdtype = (EVP_MD *) EVP_sha1(); break; case OPENSSL_ALGO_MD5: mdtype = (EVP_MD *) EVP_md5(); break; case OPENSSL_ALGO_MD4: mdtype = (EVP_MD *) EVP_md4(); break;#ifdef HAVE_OPENSSL_MD2_H case OPENSSL_ALGO_MD2: mdtype = (EVP_MD *) EVP_md2(); break;#endif#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) case OPENSSL_ALGO_DSS1: mdtype = (EVP_MD *) EVP_dss1(); break;#endif case OPENSSL_ALGO_SHA224: mdtype = (EVP_MD *) EVP_sha224(); break; case OPENSSL_ALGO_SHA256: mdtype = (EVP_MD *) EVP_sha256(); break; case OPENSSL_ALGO_SHA384: mdtype = (EVP_MD *) EVP_sha384(); break; case OPENSSL_ALGO_SHA512: mdtype = (EVP_MD *) EVP_sha512(); break; case OPENSSL_ALGO_RMD160: mdtype = (EVP_MD *) EVP_ripemd160(); break; default: return NULL; break; } return mdtype;}复制代码

由上面源代码可以很清晰的发现问题所在,随着php版本的升级,其所在的openssl扩展对应的调用条件也增加了很多,最后导致上述问题的源码也只是switch...case少了几个条件,在此也希望大家发现问题的时候,可以先去解决问题,然后有兴趣的话可以去查看源代码分析下问题所导致的原因。

转载地址:http://vepfm.baihongyu.com/

你可能感兴趣的文章
Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)【转】...
查看>>
ubantu系统安装ssh
查看>>
js实现对上传图片的路径转成base64编码,并且对图片进行压缩,实现预览功能...
查看>>
LeetCode OJ:Multiply Strings (字符串乘法)
查看>>
LeetCode OJ:Search in Rotated Sorted Array(翻转排序数组的查找)
查看>>
VLC打开.264文件
查看>>
常用的一些webService
查看>>
Codeigniter开发技巧:连接多个数据库(可实现DB读写分离)
查看>>
Mybatis注意点之#与$区别
查看>>
IP地址分类(A类 B类 C类 D类 E类)
查看>>
RedirectResult,RedirectToRoute
查看>>
解决spark-shell输出日志过多的问题
查看>>
npm包管理工具
查看>>
[洛谷P3168][CQOI2015]任务查询系统
查看>>
鼠标放上去图片切换效果
查看>>
String Method的字符串变换的一个例子
查看>>
浅谈for...in与for....of
查看>>
无效报表文件路径
查看>>
MySQL使用存储过程,光标的使用的简单示例
查看>>
php.ini在php脚本文件中的配置
查看>>