首先对不起我的英语。我正在Python中使用signxml迈出第一步,从我看到的文章来看,它看起来很容易使用,但我无法根据需要正确签署文档。
我正在查看网络上的文档和一些文章,在使用 signxml 签署文档时遇到的问题中,我在 https://technotes.shemyak.com/posts/xml-signatures- 找到了一篇文章with-python-elementtree/。所以我尝试使用这种结构的数据。
ET.register_namespace("ds", "http://www.w3.org/2000/09/xmldsig#")
xml_con_semilla = ET.fromstring("<getToken><item><Semilla>000009574333</Semilla></item><ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" Id=\"placeholder\"></ds:Signature></getToken>")
在这里他们解释了签名和验证时的一些困难。使用这个网站上的方法,即使在步骤结束时序列化数据,我也得到了正确的签名和验证,但是当我将 xml 发送到我需要的服务时,它给我带来了问题。我想这一定是因为它不具有所要求的结构。
服务等待的结构如下
<?xml version="1.0"?>
<getToken>
<item>
<Semilla>000009574333</Semilla>
</item>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>XX...</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>XX...</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>XX...</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
<X509Data>
<X509Certificate>XX...</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</getToken>
所以我正在从 etree 生成的 XML 中进行一次干净的尝试,因为我认为上述解决方案不能满足我的需要。
import xml.etree.ElementTree as ET
import signxml
semilla = '000009574333'
xml_semilla = ET.Element('getToken')
item = ET.SubElement(xml_semilla, 'item')
ET.SubElement(item, 'Semilla').text = semilla
>>> <getToken><item><Semilla>000009574333</Semilla></item></getToken>
semilla_xml_firmada = FirmarXMLSemilla(xml_semilla)
def FirmarXMLSemilla(xml_semilla):
pem_cert, pem_key = [open(f, "rb").read() for f in ("cert.pem", "key.pem")]
signer = XMLSigner(method=signxml.methods.enveloped,
signature_algorithm='rsa-sha1',
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
digest_algorithm="sha1")
signed_root = signer.sign(xml_semilla, key=pem_key, cert=pem_cert, always_add_key_value=True)
try:
verified_data = XMLVerifier().verify(signed_root, x509_cert=pem_cert)
print('Documento Firmado Correctamente')
except Exception as e:
logging.error('Error de Verificación en la Firma o Respuesta SAML: {}'.format(e))
到目前为止,在没有序列化的情况下,签名是正确的
VerifyResult(signed_data=b'<getToken><item><Semilla>000009574333</Semilla></item></getToken>', signed_xml=<Element getToken at 0x24cd69e65c0>, signature_xml=<Element {http://www.w3.org/2000/09/xmldsig#}Signature at 0x24cd69e6640>)
data_serialized = ET.tostring(signed_root)
data_serialized =
<getToken xmlns:ns0="http://www.w3.org/2000/09/xmldsig#">
<item>
<Semilla>000009574333</Semilla>
</item>
<ns0:Signature>
<ns0:SignedInfo>
<ns0:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<ns0:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ns0:Reference URI="">
<ns0:Transforms>
<ns0:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</ns0:Transforms>
<ns0:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ns0:DigestValue>XX...</ns0:DigestValue>
</ns0:Reference>
</ns0:SignedInfo>
<ns0:SignatureValue>XX...</ns0:SignatureValue>
<ns0:KeyInfo>
<ns0:KeyValue>
<ns0:RSAKeyValue>
<ns0:Modulus>XX...</ns0:Modulus>
<ns0:Exponent>AQAB</ns0:Exponent>
</ns0:RSAKeyValue>
</ns0:KeyValue>
<ns0:X509Data>
<ns0:X509Certificate>XX...</ns0:X509Certificate>
</ns0:X509Data>
</ns0:KeyInfo>
</ns0:Signature>
</getToken>
# Sending the data...
data_parsed = ET.fromstring(data_serialized)
try:
verified_data = XMLVerifier().verify(data_parsed, x509_cert=pem_cert)
print('Documento Firmado Correctamente')
logging.debug(verified_data)
except Exception as e:
logging.error('Error de Verificación en la Firma o Respuesta SAML: {}'.format(e))
ERROR:root:Error de Verificación en la Firma o Respuesta SAML: Signature verification failed: bad signature
您会注意到,转换为字符串时,命名空间会添加到数据中,这会破坏签名。此外,还添加了“ns0:”前缀。
我需要将 xmlns="http://www.w3.org/2000/09/xmldsig#" 添加到签名中,而不是 getToken
我还尝试了Python signxml XML签名包。如何为签名标签添加xml占位符?但这也给我带来了问题。
我使用的是signxml版本3.0.1,这样我就可以使用SHA-1。
谢谢!
我有同样的问题,似乎问题是你保存xml的方式,如果你使用etree,它应该可以做到“with open('key.pem', 'rb') as key_file: private_key_data = key_file.read()
private_key = serialization.load_pem_private_key(
private_key_data,
password=None, # Add your passphrase if the key is encrypted
backend=default_backend()
)
with open('cer.rec.pem', 'rb') as cert_file:
certificate = cert_file.read()
tree = ET.parse('path_to_xml.xml')
root = tree.getroot()
signer = XMLSigner(
method=methods.enveloped,
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments'
)
# signer.sign_alg = SignatureMethod('http://www.w3.org/2000/09/xmldsig#rsa-sha1')
signer.namespaces = {None: namespaces.ds}
# Pass the private key object and certificate bytes to the signer
signed_xml = signer.sign(
root,
key=private_key,
# cert=certificate,
always_add_key_value=True,
)
# XMLVerifier().verify(signed_xml)
final_signed_xml = etree.ElementTree(signed_xml)
final_signed_xml.write('signed_xml.xml', encoding='UTF-8', xml_declaration=False)`
同样使用signer.namespaces = {None: namespaces.ds}你应该能够消除命名空间