我遇到了类似的问题,如无法根据 python/m2crypto 中的 DSA 公钥验证 dsawithSha1 签名消息中所述。遗憾的是,提问者找到了 OpenSSL 的解决方案,但没有分享他的知识。
我想在 PHP 中实现签名消息的验证,或者使用 OpenSSL 作为后备。
我有以下证书,最初以 PKCS#7 形式交付,我将其转换为 PEM 格式的 X.509(下面是 PHP 中的 $pubKey):
-----BEGIN CERTIFICATE-----
MIIC+zCCArsCByAUBAcGQhAwCQYHKoZIzjgEAzBkMQswCQYDVQQGEwJERTEcMBoG
A1UEChMTU0FQIFRydXN0IENvbW11bml0eTETMBEGA1UECxMKU0FQIFdlYiBBUzEU
MBIGA1UECxMLSTAwMjAxODQ4OTAxDDAKBgNVBAMTA1NFMjAeFw0xNDA0MDcwNjQy
MTBaFw0zODAxMDEwMDAwMDFaMGQxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNTQVAg
VHJ1c3QgQ29tbXVuaXR5MRMwEQYDVQQLEwpTQVAgV2ViIEFTMRQwEgYDVQQLEwtJ
MDAyMDE4NDg5MDEMMAoGA1UEAxMDU0UyMIIBtzCCASsGByqGSM44BAEwggEeAoGB
AP/jA7UNBUG5dqASOkGZ0+JLiKqwhHIEqKarqiuCGvho3Fwc8OzWxVr3cyGomHdw
q0UkwvMROGhGsg0DOvJc0u7wY4BKmR1gUkOwg6DzX0JZbZ/hMWW/wzixiC+LtoGD
p3DVvCzLbZ9ujaI4NhkhCaw/OPjli7Q0TbPPNxT15wmdAhUApZDvRmv7txM8IowT
JCJa0igBuw8CgYBqPNctSVdgszu2BJf9rYdafUUN6BP7jCY4JxGPgPqYkEdDsLAs
RdPfLohhjHUD8z6F0XBLvQBuwo+0ShAa3KZ8wEOYUAZ2IyJmoE7OBmW3uIcZ/s7g
jwftGABsfx2uJ8s2mbV6Mak++dw8Yn0WvsTWBD9NaI4cwn3Kw92GSNpQvgOBhQAC
gYEAisABEC7nuf3Stibic8RySBMbmg3CYLvX2N2MgQZcSC8dZ6WI6n39vtKDOT7k
ckS0ogDNFpWvfMZTjv2ZzyJkpcUbKI3K/yjWl5NeGRGuAM7wMZbpkPTe4eNWaW4k
exJWjWCSFz3W11XKgq7xDKzkTeb2oV+IfehxoTdTrJ1ZA2kwCQYHKoZIzjgEAwMv
ADAsAhQWUSemKo/Wa2y0asoNraOFlIE1DwIUGGM/Ll1zejSh5qzQVOrr1MzJRWI=
-----END CERTIFICATE-----
以及签名消息:
MIIBUgYJKoZIhvcNAQcCoIIBQzCCAT8CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGCAR4wggEaAgEBMG8wZDELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1NBUCBUcnVzdCBDb21tdW5pdHkxEzARBgNVBAsTClNBUCBXZWIgQVMxFDASBgNVBAsTC0kwMDIwMTg0ODkwMQwwCgYDVQQDEwNTRTICByAUBAcGQhAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE0MTEyNDA4MTYxM1owIwYJKoZIhvcNAQkEMRYEFCId8O7H%2Bwd1LCNg6ZiNNU6TZtJqMAkGByqGSM44BAMELzAtAhR6ELQT%2B8ueklNmizCrSjvG8vVTAwIVAJCi5juWEEBJeH2GUH4KtA8sRrIK
通过 urldecode 和 base64_decode 转换为二进制格式,以 DER 格式存储在名为 seckey.der 的文件中(下面 PHP 中的 $secKeyDer)
使用 OpenSSL 我可以查看 ASN.1 结构的内容:
openssl asn1parse -in seckey.der -inform der
结果是:
0:d=0 hl=4 l= 338 cons: SEQUENCE
4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
15:d=1 hl=4 l= 323 cons: cont [ 0 ]
19:d=2 hl=4 l= 319 cons: SEQUENCE
23:d=3 hl=2 l= 1 prim: INTEGER :01
26:d=3 hl=2 l= 11 cons: SET
28:d=4 hl=2 l= 9 cons: SEQUENCE
30:d=5 hl=2 l= 5 prim: OBJECT :sha1
37:d=5 hl=2 l= 0 prim: NULL
39:d=3 hl=2 l= 11 cons: SEQUENCE
41:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
52:d=3 hl=4 l= 286 cons: SET
56:d=4 hl=4 l= 282 cons: SEQUENCE
60:d=5 hl=2 l= 1 prim: INTEGER :01
63:d=5 hl=2 l= 111 cons: SEQUENCE
65:d=6 hl=2 l= 100 cons: SEQUENCE
67:d=7 hl=2 l= 11 cons: SET
69:d=8 hl=2 l= 9 cons: SEQUENCE
71:d=9 hl=2 l= 3 prim: OBJECT :countryName
76:d=9 hl=2 l= 2 prim: PRINTABLESTRING :DE
80:d=7 hl=2 l= 28 cons: SET
82:d=8 hl=2 l= 26 cons: SEQUENCE
84:d=9 hl=2 l= 3 prim: OBJECT :organizationName
89:d=9 hl=2 l= 19 prim: PRINTABLESTRING :SAP Trust Community
110:d=7 hl=2 l= 19 cons: SET
112:d=8 hl=2 l= 17 cons: SEQUENCE
114:d=9 hl=2 l= 3 prim: OBJECT :organizationalUnitName
119:d=9 hl=2 l= 10 prim: PRINTABLESTRING :SAP Web AS
131:d=7 hl=2 l= 20 cons: SET
133:d=8 hl=2 l= 18 cons: SEQUENCE
135:d=9 hl=2 l= 3 prim: OBJECT :organizationalUnitName
140:d=9 hl=2 l= 11 prim: PRINTABLESTRING :I0020184890
153:d=7 hl=2 l= 12 cons: SET
155:d=8 hl=2 l= 10 cons: SEQUENCE
157:d=9 hl=2 l= 3 prim: OBJECT :commonName
162:d=9 hl=2 l= 3 prim: PRINTABLESTRING :SE2
167:d=6 hl=2 l= 7 prim: INTEGER :20140407064210
176:d=5 hl=2 l= 9 cons: SEQUENCE
178:d=6 hl=2 l= 5 prim: OBJECT :sha1
185:d=6 hl=2 l= 0 prim: NULL
187:d=5 hl=2 l= 93 cons: cont [ 0 ]
189:d=6 hl=2 l= 24 cons: SEQUENCE
191:d=7 hl=2 l= 9 prim: OBJECT :contentType
202:d=7 hl=2 l= 11 cons: SET
204:d=8 hl=2 l= 9 prim: OBJECT :pkcs7-data
215:d=6 hl=2 l= 28 cons: SEQUENCE
217:d=7 hl=2 l= 9 prim: OBJECT :signingTime
228:d=7 hl=2 l= 15 cons: SET
230:d=8 hl=2 l= 13 prim: UTCTIME :141124081613Z
245:d=6 hl=2 l= 35 cons: SEQUENCE
247:d=7 hl=2 l= 9 prim: OBJECT :messageDigest
258:d=7 hl=2 l= 22 cons: SET
260:d=8 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:221DF0EEC7FB07752C2360E9988D354E9366D26A
282:d=5 hl=2 l= 9 cons: SEQUENCE
284:d=6 hl=2 l= 7 prim: OBJECT :dsaWithSHA1
293:d=5 hl=2 l= 47 prim: OCTET STRING [HEX DUMP]:302D02147A10B413FBCB9E9253668B30AB4A3BC6F2F5530302150090A2E63B96104049787D86507E0AB40F2C46B20A
我看到消息摘要,它是原始消息的 sha1 哈希值。原始消息是(下面 PHP 中的 $message):
W1005056A57D331ED49CF644B265BC8C33datarcudcCN%3DSE2,OU%3DI0020184890,OU%3DSAPWebAS,O%3DSAPTrustCommunity,C%3DDE20141124101613
该消息的sha1值为:
221df0eec7fb07752c2360e9988d354e9366d26a
与ASN.1结构中的消息摘要相同。还有一个带有 dsaWithSHA1 的哈希值。我不知道如何用这个算法生成哈希。
当我尝试通过 PHP 验证它时:
openssl_verify($message, $secKeyDer, $pubKey, 'sha1');
我收到错误:
error:0906D06C:PEM routines:PEM_read_bio:no start line
error:0606C06E:digital envelope routines:EVP_VerifyFinal:wrong public key type
这让我很恼火,因为 $pubKey 的值是 PEM 格式,如函数手册中所述。
我现在的问题是:如何使用给定的参数(原始消息、签名消息(seckey.der)、公钥)验证 PHP 中的消息。或者使用本机 OpenSSL 命令。
问候, 克里斯.
现在我用 OpenSSL 找到了答案:
openssl cms -verify -in seckey.der -inform der -content message.txt -noverify -certfile certificate.cer
其中 seckey.der 是 DER 格式的签名,message.txt 是原始消息,certificate.cer 是 PEM 格式的公钥。
老问题,但与@FrankStein相同,我花了一些时间才弄清楚消息是什么,但这里有一个 bash 和 openSSL cmd 来验证签名以及消息来源的一些详细信息:
####bash style check with openssl
##secKey directly from URL (well URL decode)
secKeyBase64='MIIBUQYJKoZIhvcN--removed a few chars--YEFF/iMK2ISP+vS5evTe--removed--UZ3vcpINI='
###all parameters from URL without pVersion and secKey. keep the order from URL!
message='Z3
002248AF19E21EEEB782F2D94A9D2B17
r
CN%3DID3,OU%3DI0120003411,OU%3DSAPWebAS,O%3DSAPTrustCommunity,C%3DDE
20240307021358'
#base64 decode and write seckey to file
base64 -d <<< $secKeyBase64 > sap-sec-key.p7b
#write message to file
tr -d '[:space:]' <<< $message > message.txt
##info about the secKey
openssl asn1parse -in sap-sec-key.p7b -inform der
##convert SAP cert to PEM format (as openssl want this)
openssl pkcs7 -inform der -print_certs -in Z3.cer -out Z3.pem
#now check signature for the message
openssl cms -verify -in sap-sec-key.p7b -inform der -content message.txt -noverify -certfile Z3.pem
##Output
Z3002248AF19E21EEEB782F2D94A9D2B17rCN%3DID3,OU%3DI0120003411,OU%3DSAPWebAS,O%3DSAPTrustCommunity,C%3DDE20240307021358CMS Verification successful