не удалось проверить подписанное сообщение dsawithSha1 на открытый ключ DSA в python / m2crypto

- Я пытаюсь проверить подписанное сообщение с помощью сертификата x509, содержащего открытый ключ dsa. Сертификат x509 был предоставлен системой SAP в кодировке PKCS7, и после преобразования в PEM с помощью openssl я могу читать содержимое (openssl x509 -in sapcert.pem -inform pem -text) Он содержит открытый ключ в dsaEncryption, показывая мне параметры DSA y (pub), p, q и g.

Поскольку я не нашел реализации DSA в классе M2Crypto x509, я попытался создать открытый ключ DSA самостоятельно. Поэтому я пропатчил MyCrypto (см .: Как мне создать объект M2Crypto DSA с заданными параметрами и значениями ключей?), скомпилировал его и получил новую функцию DSA.pub_key_from_params (p, q, g, y) для создания моего открытого ключа DSA с использованием параметры найдены в сертификате. До этого момента все работает нормально. (Хотя unittest прошел без ошибок).

на втором этапе я получаю подписанное сообщение (с именем seckey) в качестве параметра URL-адреса, и после его декодирования (base64) я получил правильную строку DER, которую я могу прочитать с помощью openssl (openssl ans1parse -in seckey -inform der). В выходных данных openssl я вижу подписанный messageDigest, который является именно тем файлом сообщения в формате SHA1, который я пытаюсь проверить (так что я могу быть уверен, что signedMessage был предоставлен правильно). Хотя я вижу строку подписи dsaWithSHA1, которая, кажется, содержит значения r и s, необходимые для проверки подписанного сообщения dsa (см .: M2Crypto: проверка подписей DSA)

На этом этапе я застрял в своих попытках проверить подписанное сообщение в течение нескольких дней, и я надеюсь, что есть специалист по криптографии, который может мне помочь. Я много пробовал и гуглил, вместо этого попробовал 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? Пожалуйста помоги! С наилучшими пожеланиями, Фалько


person Falko Schneider    schedule 11.07.2011    source источник


Ответы (1)


То, что вы назвали seckey64 в образце кода, на самом деле является структурой SignedData из CMS.

Он содержит два «подписанных атрибута»: время подписи и дайджест сообщения. Чтобы проверить это как подпись, вам необходимо следовать правилам RFC, которые применяются, когда присутствует хотя бы один подписанный атрибут.

В вашем случае дайджест сообщения исходных данных содержится в атрибуте дайджеста сообщения, поэтому вам нужно сначала сравнить свои вычисления с байтом значения атрибута на байт.

Если они равны, вы должны извлечь значение подписи из соответствующего поля структуры SignerInfo. Наконец, ваш дайджест сообщения SHA-1, который служит другим входом для проверки подписи DSA, будет вычислен на основе необработанного кодирования подписанных атрибутов SignerInfo. Я не уверен, есть ли в M2Crypto встроенная поддержка SignedData (ее все еще часто называют PKCS # 7), но я думаю, pyOpenSSL должен поддерживать его, поэтому вы можете попробовать, если M2Crypto заведет вас в тупик.

person emboss    schedule 14.07.2011
comment
Спасибо за ваш ответ и сожалею о моем позднем ответе. Я нашел способ проверить подпись с помощью вызова openssl новой реализованной функции cms в openssl 1.0.0, так что на данный момент это работает для меня. Если у меня будет намного больше времени, я постараюсь найти более питоническое решение, поэтому ваши объяснения и предложения будут очень полезны для этого. Я сообщу вам, если найду способ сделать это с помощью pyOpenSSL или M2Crypto. Большое спасибо, Фалько - person Falko Schneider; 28.07.2011