SAML响应“信封式签名”验证失败问题咨询
SAML信封式签名验证失败问题排查
1. 元素格式问题
你提供的
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:CanonicalizationMethod> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod> <ds:Reference URI="#pfxffef2099-cc79-fd84-e7e8-5bdced364715"> <ds:Transforms> <!-- 错误:enveloped-signature必须放在C14N之前 --> <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:Transform> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod> <ds:DigestValue>LC/2Thrnfl3SUqWp8LXfZFyXoZA=</ds:DigestValue> </ds:Reference> </ds:SignedInfo>
错误原因:
信封式签名(enveloped-signature)的作用是先将
修正后的Transforms顺序:
<ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform> <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:Transform> </ds:Transforms>
其他部分(命名空间、算法URI、DigestValue)均符合XML-DSig标准,无问题。
2. Python签名代码问题
你的代码存在签名填充算法不匹配的问题,这是验证失败的另一个关键原因:
from cryptography.hazmat.primitives.asymmetric import utils from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes import base64 # 原代码漏写该导入 with open("mysaml_pr_key.pem", "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend() ) # 错误:使用PSS填充,但XML-DSig的rsa-sha1要求用PKCS#1 v1.5填充 mypadding_for_signature=padding.PSS( mgf=padding.MGF1(hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ) hasher2 = hashes.Hash(hashes.SHA1()) hasher2.update(to_be_signed.encode()) digest_of_signed_info=hasher2.finalize() signature_before_64encode=private_key.sign(digest_of_signed_info,mypadding_for_signature,utils.prehashed(hashes.SHA1())) signature=base64.b64encode(signature_before_64encode)
错误原因:
return (<SignedInfo>中指定的签名算法`http://www.w3.org/2000/09/xmldsig#rsa-sha1`,标准要求使用**PKCS#1 v1.5**填充,而非代码中的PSS填充。验证方会按PKCS#1 v1.5规则验证,自然会失败。 ### 修正后的代码: ```python from cryptography.hazmat.primitives.asymmetric import utils from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes import base64 with open("mysaml_pr_key.pem", "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend() ) # 使用PKCS#1 v1.5填充,符合XML-DSig rsa-sha1规范 mypadding_for_signature = padding.PKCS1v15() # 确保to_be_signed是经过C14N#WithComments规范化后的字节流 hasher2 = hashes.Hash(hashes.SHA1()) hasher2.update(to_be_signed) # 若to_be_signed已是字节流,无需encode() digest_of_signed_info = hasher2.finalize() signature_before_64encode = private_key.sign( digest_of_signed_info, mypadding_for_signature, utils.Prehashed(hashes.SHA1()) ) signature = base64.b64encode(signature_before_64encode) ``` ### 额外注意: 必须保证`to_be_signed`是**严格按照C14N#WithComments规范处理后的<SignedInfo>字节流**,不能是原始未规范化的XML字符串,否则即使填充正确,签名仍会不匹配。 --- ## 总结 签名验证失败大概率由两个问题共同导致: 1. <SignedInfo>中Transform顺序错误,enveloped-signature未放在C14N之前 2. Python签名代码使用了错误的填充算法,应替换为PKCS#1 v1.5 修正这两个问题后重新生成签名,即可通过验证。 内容的提问来源于stack exchange,提问作者KimoAnalyzer)
相关产品推荐
相关产品推荐

