9
我想验证文档是否以任何方式不被修改。如何验证数字XML签名
从Java Web服务,我收到一个数字XML签名以下SOAP响应:
<?xml version="1.0" encoding="UTF-8"?><Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" SOAP-ENV:mustUnderstand="1">
<wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="CertId-38670273">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</wsse:BinarySecurityToken><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-32516734">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>Rx5L4j8kF5RVYnC+spUCdvhh5N0=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-7716709">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>fFr2j5DoKTgpEvX1Se7gTC55bWM=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
jG1BaGgNbbk9JCc3R6JsJKY56p++f0+8RM2aL6TGOXS34NAGv48Sp3iAHEAuUt9+JV6w3VDAcFct
no3nCEISa0P4dVWTlPQJue3GVTWnnlcXao95tjukh9o8lIU7vZGgYHBUZLU+jgS6ZcaUlNW4KFUl
AdrPxR5DmJcFyGEtRY2yclqYhnJdnUc+ZBu5eWbRZgbJzR4MgtGsEQcgtftFe2i0CvRbOSe4mt3T
JQzbGY81ssFCnB44vitgjhVLfPd/08amSa5Xn8KRptbNatp2uq1iGXAifJLVup8T0yS0RzaqhCJg
CaHRPFVKFN3WaJcqPZex75KBwSZMZaaJDZW7lQ==
</ds:SignatureValue>
<ds:KeyInfo Id="KeyId-16708261">
<wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-32258670"><wsse:Reference URI="#CertId-38670273" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-32516734"><wsu:Created>2017-03-31T09:04:40.352Z</wsu:Created><wsu:Expires>2017-03-31T09:09:40.352Z</wsu:Expires></wsu:Timestamp></wsse:Security><wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" SOAP-ENV:mustUnderstand="0">uuid:12b93a00-15f1-11e7-af6b-f16d80f418ae</wsa:MessageID><wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" SOAP-ENV:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To></SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-7716709">
...
</SOAP-ENV:Body></Envelope>
我发现一个有用的例子来验证MSDN的xml文件:
' Verify the signature of an XML file and return the result.
Function VerifyXmlFile(ByVal Name As String) As [Boolean]
' Create a new XML document.
Dim xmlDocument As New XmlDocument()
' Format using white spaces.
xmlDocument.PreserveWhitespace = True
' Load the passed XML file into the document.
xmlDocument.Load(Name)
' Create a new SignedXml object and pass it
' the XML document class.
Dim signedXml As New SignedXml(xmlDocument)
' Find the "Signature" node and create a new
' XmlNodeList object.
Dim nodeList As XmlNodeList = xmlDocument.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#")
' Load the signature node.
signedXml.LoadXml(CType(nodeList(0), XmlElement))
' Check the signature and return the result.
Return signedXml.CheckSignature()
End Function
不幸的是,验证总是返回false。我很难理解为什么它不起作用。
UPDATE 1根据从Henk Holterman和Simon Mourier的提案:通过调用函数CheckSignature
Function VerifyXmlFile(ByVal Name As String) As Boolean
' <SOAP-ENV:Envelope ... > ... </SOAP-ENV:Envelope>
Dim xDoc = XDocument.Load(Name)
' <wsse:binarySecurityToken ... > ... </wsse:binarySecurityToken>
Dim xBinarySecurityToken = xDoc.Root.Descendants().Skip(2).FirstOrDefault
' <SOAP-ENV:Body ... > ... </SOAP-ENV:Body>
Dim xBody = xDoc.Root.Elements().Skip(1).FirstOrDefault
Dim signedXml = New SignedXml(ToXmlElement(xBody))
Dim xmlDocument As New XmlDocument()
xmlDocument.PreserveWhitespace = True
xmlDocument.Load(Name)
Dim nodeList = xmlDocument.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#")
signedXml.LoadXml(CType(nodeList(0), XmlElement))
Dim byteCert = Encoding.UTF8.GetBytes(xBinarySecurityToken.Value)
Dim cert = New X509Certificates.X509Certificate2(byteCert)
Return signedXml.CheckSignature(cert, True)
End Function
Public Shared Function ToXmlElement(xElement As XElement) As XmlElement
Dim xmlDoc = New XmlDocument() With {.PreserveWhitespace = True}
xmlDoc.Load(xElement.CreateReader())
Return xmlDoc.DocumentElement
End Function
在CryptographicException消息 “格式不正确的参考元件” 导致( )。
根据从@SimonMourier提案和@ lax1089
Private Function VerifyXmlfile(Name As String) As Boolean
CryptoConfig.AddAlgorithm(GetType(MyXmlDsigC14NTransform), "http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
Dim xmlDocument As New XmlDocument()
xmlDocument.PreserveWhitespace = True
xmlDocument.Load(Name)
MyXmlDsigC14NTransform.document = xmlDocument
Dim soapBody As XmlElement = xmlDocument.GetElementsByTagName("SOAP-ENV:Body")(0)
Dim securityToken = xmlDocument.GetElementsByTagName("SOAP-ENV:Header")(0).FirstChild.NextSibling.FirstChild.NextSibling.InnerText
Dim signedXml = New SignedXmlWithId(soapBody)
Dim nodeList = xmlDocument.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#")
signedXml.LoadXml(CType(nodeList(0), XmlElement))
Dim byteCert = Convert.FromBase64String(securityToken)
Dim cert = New X509Certificates.X509Certificate2(byteCert)
Return signedXml.CheckSignature(cert, True)
End Function
Public Class SignedXmlWithId
Inherits SignedXml
Public Sub New(xml As XmlDocument)
MyBase.New(xml)
End Sub
Public Sub New(xmlElement As XmlElement)
MyBase.New(xmlElement)
End Sub
Public Overrides Function GetIdElement(doc As XmlDocument, id As String) As XmlElement
' check to see if it's a standard ID reference
Dim idElem As XmlElement = MyBase.GetIdElement(doc, id)
If idElem Is Nothing Then
Dim nsManager As New XmlNamespaceManager(doc.NameTable)
nsManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")
idElem = TryCast(doc.SelectSingleNode((Convert.ToString("//*[@wsu:Id=""") & id) + """]", nsManager), XmlElement)
End If
Return idElem
End Function
End Class
积分被盗@SimonMourier和@CarlosLopez-MSFT
甲辅助类 UPDATE 2和SOLUTION
'Dim signedXml As New SignedXml(xmlDocument)'部分选择整个文档作为签名部分。我想你需要选择那里的SOAP-ENV:Body。请注意id-7716709。但你需要确保文档。时间戳似乎也被签名,我不知道这是否可选。 –
这是因为默认情况下,SignedXml没有看到任何公钥(它无法单独解码wsse:BinarySecurityToken(它是base64编码的X509证书)。但是,如果您创建的内容为wsse:BinarySecurityToken的X509Certificate解码为byte [],并将其传递给CheckSignature,它应该可以工作。但是,它仍然不适合我。也许是因为我没有所需的根证书(它来自瑞士的权威机构)...... –
[link] https://msdn.microsoft.com/zh-cn/library/ms229950(v = vs.110).aspx在那里你可以看到一个密钥是如何生成的,并在你的算法中用它来查看是否缺少key作为'signedXml.CheckSignature(Key)'函数的参数与你的问题有关 – mago