0

- 我正在尝试使用持有 dsa 公钥的 x509 证书验证签名消息。x509 证书由 SAP 系统以 PKCS7 编码提供,在使用 openssl 在 PEM 中转换后,我能够读取内容(openssl x509 -in sapcert.pem -inform pem -text)它在 dsaEncryption 中保存一个公钥,显示我是 DSA 参数 y(pub)、p、q 和 g。

因为我没有在 M2Crypto x509 类中找到 DSA 实现,所以我尝试自己构建 DSA 公钥。为此我修补了 MyCrypto,(请参阅:如何在给定参数和密钥值的情况下创建 M2Crypto DSA 对象?),编译它并获得一个新函数 DSA.pub_key_from_params(p,q,g,y) 来构建我的 DSA 公钥使用证书中的参数。到此为止,一切正常。(单元测试虽然运行没有错误)。

在第二步中,我收到signedMessage(名为seckey)作为URL参数,在解码它(base64)后,我得到了一个正确的DER字符串,我可以用openssl(openssl ans1parse -in seckey -inform der)读取。在 openssl 的输出中,我可以看到已签名的 messageDigest,这正是我尝试验证的 SHA1 编码的 messagedigest(因此我可以确定已正确提供了 signedMessage)。虽然我可以看到一个 dsaWithSHA1 签名字符串,它似乎包含验证 dsa 签名消息所需的 r 和 s 值(请参阅:M2Crypto:验证 DSA 签名

在这一点上,我坚持尝试验证signedMessage 几天了,我希望那里有一位密码专家可以帮助我。我尝试并搜索了很多,尝试了 pyCrypto lib,但都没有成功。

我试图将 SHA1 MessageDigest 以及 r 和 s 值传递给 M2Crypto.DSA.verify 函数,但由于它失败了,我想我要么必须传递 signedMessage 要么传递其中的一部分。(在一个 Java 论坛中,我发现了一些关于验证 SAP 提供的签名消息的帖子,还有一些关于通过“签名属性的 DER 编码”计算签名的文章。?)

这是我的示例代码:

# -*- coding: iso-8859-1 -*-

import M2Crypto
import urllib
import base64
from Crypto.Util import asn1
from M2Crypto import m2
import sha

# the certificate
cert = """subject=/C=DE/O=SAP Trust Community/OU=SAP Web AS/OU=I0020154766/CN=RE2
issuer=/C=DE/O=SAP Trust Community/OU=SAP Web AS/OU=I0020154766/CN=RE2
-----BEGIN CERTIFICATE-----
MIICMDCCAe8CAQAwCQYHKoZIzjgEAzBkMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
U0FQIFRydXN0IENvbW11bml0eTETMBEGA1UECxMKU0FQIFdlYiBBUzEUMBIGA1UE
CxMLSTAwMjAxNTQ3NjYxDDAKBgNVBAMTA1JFMjAeFw05NzEwMDEwMDAwMDBaFw0z
ODAxMDEwMDAwMDBaMGQxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNTQVAgVHJ1c3Qg
Q29tbXVuaXR5MRMwEQYDVQQLEwpTQVAgV2ViIEFTMRQwEgYDVQQLEwtJMDAyMDE1
NDc2NjEMMAoGA1UEAxMDUkUyMIHyMIGpBgcqhkjOOAQBMIGdAkEA//8x1Bqn4a00
FKr9CTwPPskxy0yrx7iU6T4vza4wW93Mo2d/IYTZNAxFqhrm+fIUrEp5fxIpYRmJ
rKL2qRCUmQIVANrcsXlFvrXH455gM69vKZebhQZfAkEAmYzXTzHYwvqKEM46FvQX
yC5O+JInwgk7Dac7gqGAkkhCS1aII4Vkc9kIEx3GFLD2mx4+yJuMQ8pQ4wz4FkfB
JANEAAJBAI1em/0owxMTEP+akz56BovQ7Q6LiqUmVLLxJcjDozjI+5z6IrAPtub2
veLXPdghDHcHB5jHKoqT4JHpqRc+uhIwCQYHKoZIzjgEAwMwADAtAhRm2jqiMWL+
26mA7HdKfZdkawMuYQIVAMekXdAT4wbyrb5/yFtuIPjCBfpr
-----END CERTIFICATE-----

"""
f = open('sapcert.pem', 'w')
f.write(cert)
f.close()

# now you can see it content with openssl
# openssl x509 -in sapcert.pem -inform pem -text


# this is the signedMessage
secKey = "MIIBSwYJKoZIhvcNAQcCoIIBPDCCATgCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGCARcwggETAgEBMGkwZDELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1NBUCBUcnVzdCBDb21tdW5pdHkxEzARBgNVBAsTClNBUCBXZWIgQVMxFDASBgNVBAsTC0kwMDIwMTU0NzY2MQwwCgYDVQQDEwNSRTICAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTExMDUyNjE1MzAyNVowIwYJKoZIhvcNAQkEMRYEFPelg4iVtaKORpuFxUvgo23Du7%2BtMAkGByqGSM44BAMELjAsAhQ46oCNmzZArb5yOFSYGY0hWu8dZwIUT35hPccJ6B9HIsOE0u8LwYZaFNk%3D"
secKey = urllib.unquote(secKey)
secKey64 = base64.b64decode(secKey)
# now you can save it as a DER encoded file
f = open('seckey.der', 'wb')
f.write(secKey64)
f.close()
# you can pass it to openssl to see the the content
# openssl asn1parse -in seckey.der -inform der


# here is the sha1 encoded messagedigest I had to verify
hashstr = "ZS4DDB9616BA031C40E1008003AC100097dCN%3DRE2,OU%3DI0020154766,OU%3DSAPWebAS,O%3DSAPTrustCommunity,C%3DDE20110526173025"
osha1=M2Crypto.EVP.MessageDigest('sha1')
osha1.update(hashstr)
sha1_md = osha1.digest()
print sha1_md.encode('hex')

# now i build a DSA key with the params found in the certificate

pub="8d5e9bfd28c3131310ff9a933e7a068bd0ed0e8b8aa52654b2f125c8c3a338c8fb9cfa22b00fb6e6f6bde2d73dd8210c77070798c72a8a93e091e9a9173eba12"
p="ffff31d41aa7e1ad3414aafd093c0f3ec931cb4cabc7b894e93e2fcdae305bddcca3677f2184d9340c45aa1ae6f9f214ac4a797f1229611989aca2f6a9109499"
q="dadcb17945beb5c7e39e6033af6f29979b85065f"
g="998cd74f31d8c2fa8a10ce3a16f417c82e4ef89227c2093b0da73b82a1809248424b568823856473d908131dc614b0f69b1e3ec89b8c43ca50e30cf81647c124"


pub1 = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(pub))
p1 = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(p))
q1 = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(q))
g1 = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(g))

# this function is available after patching und compiling M2Crypto
# https://bugzilla.osafoundation.org/attachment.cgi?id=5700
dsa1 = M2Crypto.DSA.pub_key_from_params(p1, q1, g1, pub1)
print dsa1.check_key()

# this seems to be the signature-values r and s in seckey.der
asn_hex = "302C021438EA808D9B3640ADBE72385498198D215AEF1D6702144F7E613DC709E81F4722C384D2EF0BC1865A14D9"

r = asn_hex[8:48]
s = asn_hex[52:]
r1 = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(r))
s1 = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(s))

# but this fails
v = dsa1.verify(sha1_md, r1, s1)
print v

# this too
sk = M2Crypto.m2.bn_to_mpi(M2Crypto.m2.bin_to_bn(secKey64))
v = dsa1.verify(sk, r1, s1)
print v

有没有人知道如何进行正确的 dsawithsha1 签名验证?请帮忙!最好的问候,法尔科

4

1 回答 1

0

seckey64在示例代码中命名的实际上是来自CMS的 SignedData 结构。

它包含两个“签名属性”,签名时间和消息摘要。为了将其验证为签名,您需要遵循至少存在一个签名属性时适用的 RFC 规则。

在您的情况下,原始数据的消息摘要包含在 message-digest 属性中,因此您需要首先将您的计算与每个字节的属性值字节进行比较。

如果它们相等,那么您将从 SignerInfo 结构的相应字段中提取签名值。最后,作为 DSA 签名验证的另一个输入的 SHA-1 消息摘要将通过 SignerInfo 的签名属性的原始编码进行计算。我不确定 M2Crypto 是否内置了对 SignedData 的支持(它仍然经常被称为 PKCS#7),但我猜pyOpenSSL应该支持它,所以如果 M2Crypto 将你带入死胡同,你可以尝试一下。

于 2011-07-14T02:53:01.870 回答