2017-05-12 74 views
9

Tôi muốn xác minh rằng tài liệu không bị sửa đổi theo bất kỳ cách nào.Cách xác minh chữ ký số XML

Từ một dịch vụ web Java, tôi nhận được phản hồi xà phòng sau đây với một kỹ thuật số chữ ký XML:

<?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">MIIHQzCCBSugAwIBAgIQY+wksDuKve+PKV1rHtR85TANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJDSDEOMAwGA1UEChMFQWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMScwJQYDVQQDEx5Td2lzcyBHb3Zlcm5tZW50IFJlZ3VsYXIgQ0EgMDEwHhcNMTUwOTA5MTMzNDA2WhcNMTgwOTA4MTMzNDA2WjCBkDELMAkGA1UEBhMCQ0gxOzA5BgNVBAoMMlRoZSBGZWRlcmFsIEF1dGhvcml0aWVzIG9mIHRoZSBTd2lzcyBDb25mZWRlcmF0aW9uMRQwEgYDVQQLDAtBbndlbmR1bmdlbjEMMAoGA1UECwwDWktWMSAwHgYDVQQDDBdlLWRlYyBQcm9kdWt0aW9uIDJMTkdFQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKE1N0hS+iLq84zDtHSJRouVoAFGajWxPg/00MHUqOVXudo42mGeJQk0gtoGIc71unaL8Mh58qMEOKfwJ6yvY66N2+KlmNTus0SoheQ71L76pNLxPoM1tHC5ohxWm+yvVb+a7jvuoscHn54KrDAHMitzOdWwezlQZlmUMvc/KcNJiKGnvrwkz3rqlTiAUdy9fBpHuRx4aPSWuZeXS8pwa95d88npXBJSLKyQcbtSSDy8QSUgQbnLqfBtMmdGMWCFkgeAOHFp+87vy8Ye2gjm2j22XmGjzDsE+SLo6BPtJ5nSanBhNk9tZFqZj50ey9G2ODA7FyaBZVnI7oKIuwNL8ssCAwEAAaOCAqkwggKlMB8GA1UdIwQYMBaAFE13teTvbZzDm6A6h+Gm7ginOeeLMB0GA1UdDgQWBBSiy8uK8Q6LPlGVDxFTGUvzyfwSszAMBgNVHRMBAf8EAjAAMIHABgNVHSAEgbgwgbUwgbIGCGCFdAERAxYZMIGlMEQGCCsGAQUFBwIBFjhodHRwOi8vd3d3LnBraS5hZG1pbi5jaC9jcHMvQ1BTXzJfMTZfNzU2XzFfMTdfM18yMV8xLnBkZjBdBggrBgEFBQcCAjBRGk9UaGlzIGlzIHRoZSBTd2lzcyBHb3Zlcm5tZW50IFJlZ3VsYXIgQ0EwIDEgQ1BTIGZvciBaS1YgYXV0aGVudGljYXRpb24gcHVycG9zZXMuMIHFBgNVHR8Egb0wgbowMaAvoC2GK2h0dHA6Ly93d3cucGtpLmFkbWluLmNoL2NybC9SZWd1bGFyQ0EwMS5jcmwwgYSggYGgf4Z9bGRhcDovL3d3dy5wa2kuYWRtaW4uY2g6Mzg5L2NuPVN3aXNzJTIwR292ZXJubWVudCUyMFJlZ3VsYXIlMjBDQSUyMDAxLG91PUNlcnRpZmljYXRpb24lMjBBdXRob3JpdGllcyxvdT1TZXJ2aWNlcyxvPUFkbWluLGM9Q0gwDgYDVR0PAQH/BAQDAgSwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAkBgNVHREEHTAbgRlyZWNlaXB0QGVkZWMuZXp2LmFkbWluLmNoMHUGCCsGAQUFBwEBBGkwZzA3BggrBgEFBQcwAoYraHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvYWlhL1JlZ3VsYXJDQTAxLmNydDAsBggrBgEFBQcwAYYgaHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvYWlhL29jc3AwDQYJKoZIhvcNAQELBQADggIBAARTJZaDVUh5zsLAFR0li96M3hQPV0mbqxey7RyoBvSn5JoqMr/77XKFSav6BpeDqbWCX6Gfmvdr/pXC3ZovSF6dB+0mN7N42DJ/wGTSO5liiRy5m00R8Rm7qReg56o26i7zC1Fh+S+A7RVJ0om19RqllB7L4c4DHcAo41zLNiT0XWOkQtwXY1xwprLd8Y7pGtO8z0mObCldj7K3OdtzrDkqWD0EfzhF6LELwaOBIDihU8SGe0/MTshe9d/mItQOYq4c0Lq4YJscOjyEu2yvtJGy4R331KfOB+R/oiamUz9BQJTFVrPRQZw6gSzbEGcV1MrsJDQiMo8NJxNKN61REk+0hHtkR96BTnUzg5XfDJ1USpX2CDrKY0R1XWtwgS+fahA030sDzcEHNKD5j4MJNl2Ou02J1R9BUBg7TRW7Eji9sOEccnfHUkjnRs31c3kESeqkKSqOKt1gZfGTovX2a+6q0FKw5E9xqz4TyxmCj5P0ibnDvwOlcZB3S0xEx9yVjxZneGgtHzG8m4s7MEYJTYURwp3jDfIs6fej3MkSIuczZif9sk9CQBugWniX7JjI3hI5S4fUp4vvsjUCpRmoQvgpru78u4xgkHB5hUAcNZMDaOp3KyFiQfTqrg239cuIOCrPe2afD3LfbOEPEQrcVVbVSVdxmc6alfQI1fzKbUHt</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> 

Tôi đã tìm thấy một ví dụ hữu ích để xác minh các tập tin xml trên MSDN:

' 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 

Thật không may, xác minh luôn trả về false. Tôi đấu tranh để hiểu tại sao nó không hoạt động.


UPDATE 1 theo đề nghị từ Henk HoltermanSimon Mourier:

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 

dẫn đến một CryptographicException với thông điệp "dạng sai tài liệu tham khảo yếu tố" bằng cách gọi hàm CheckSignature ().


UPDATE 2 và SOLUTION theo đề nghị từ @SimonMourier và @ 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 

Một lớp helper bị đánh cắp từ Dog Ears

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 

Tín dụng cho @SimonMourier@CarlosLopez-MSFT

+1

Phần 'Dim signedXml As New SignedXml (xmlDocument)' chọn toàn bộ tài liệu là phần đã ký. Tôi nghĩ bạn cần chọn SOAP-ENV: Thay vào đó là Body. Lưu ý id-7716709. Nhưng bạn sẽ cần các tài liệu để chắc chắn. Dấu thời gian dường như cũng đã được ký, tôi không biết đó có phải là tùy chọn hay không. –

+1

Điều này là do theo mặc định, SignedXml không thấy bất kỳ khóa công khai nào (nó không thể giải mã được wsse: BinarySecurityToken (đó là một chứng chỉ X509 được mã hóa base64) một mình.Tuy nhiên, nếu bạn tạo một X509Certificate với nội dung của wsse: BinarySecurityToken giải mã thành byte [], và truyền nó cho CheckSignature, nó sẽ hoạt động. Tuy nhiên, nó vẫn không hiệu quả với tôi. Có lẽ vì tôi không có các chứng chỉ gốc bắt buộc (từ cơ quan Thụy Sĩ) ... –

+0

Có một ví dụ khác từ [link] https://msdn.microsoft.com/en-us/library/ms229950 (v = vs.110) .aspx Ở đó bạn có thể thấy một khóa được tạo ra và sử dụng nó như thế nào trong thuật toán của bạn để xem thiếu khóa như một đối số của hàm 'signedXml.CheckSignature (Key)' có liên quan đến vấn đề của bạn – mago

Trả lời

1

Thực ra đây là sự cố đã biết và được ghi lại:

Việc triển khai Canonicalization giữa .NET 3.5 và .NET 4.0 đã thay đổi .

Tôi không biết điều này có hoạt động trên tất cả chữ ký XML hay không, nhưng nó hoạt động từ thử nghiệm mà tôi đã thực hiện.

Thêm C14N sau chuyển đổi lớp để dự án của bạn:

public class MyXmlDsigC14NTransform: XmlDsigC14NTransform { 
    static XmlDocument _document; 
    public static XmlDocument document { 
    set { 
     _document = value; 
    } 
    } 

    public MyXmlDsigC14NTransform() {} 

    public override Object GetOutput() { 
    return base.GetOutput(); 
    } 

    public override void LoadInnerXml(XmlNodeList nodeList) { 
    base.LoadInnerXml(nodeList); 
    } 

    protected override XmlNodeList GetInnerXml() { 
    XmlNodeList nodeList = base.GetInnerXml(); 
    return nodeList; 
    } 

    public XmlElement GetXml() { 
    return base.GetXml(); 
    } 

    public override void LoadInput(Object obj) { 
    int n; 
    bool fDefaultNS = true; 

    XmlElement element = ((XmlDocument) obj).DocumentElement; 

    if (element.Name.Contains("SignedInfo")) { 
     XmlNodeList DigestValue = element.GetElementsByTagName("DigestValue", element.NamespaceURI); 
     string strHash = DigestValue[0].InnerText; 
     XmlNodeList nodeList = _document.GetElementsByTagName(element.Name); 

     for (n = 0; n < nodeList.Count; n++) { 
     XmlNodeList DigestValue2 = ((XmlElement) nodeList[n]).GetElementsByTagName("DigestValue", ((XmlElement) nodeList[n]).NamespaceURI); 
     string strHash2 = DigestValue2[0].InnerText; 
     if (strHash == strHash2) break; 
     } 

     XmlNode node = nodeList[n]; 

     while (node.ParentNode != null) { 
     XmlAttributeCollection attrColl = node.ParentNode.Attributes; 
     if (attrColl != null) { 
      for (n = 0; n < attrColl.Count; n++) { 
      XmlAttribute attr = attrColl[n]; 
      if (attr.Prefix == "xmlns") { 
       element.SetAttribute(attr.Name, attr.Value); 
      } else if (attr.Name == "xmlns") { 
       if (fDefaultNS) { 
       element.SetAttribute(attr.Name, attr.Value); 
       fDefaultNS = false; 
       } 
      } 
      } 
     } 

     node = node.ParentNode; 
     } 
    } 

    base.LoadInput(obj); 
    } 
} 

Và đăng ký lớp học sử dụng phương pháp CryptoConfig.AddAlgorithm như chứng minh dưới đây:

CryptoConfig.AddAlgorithm(typeof(MyXmlDsigC14NTransform), "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"); 

var message = new XmlDocument(); 
message.PreserveWhitespace = true; 
message.Load("XmlSig.xml"); 

MyXmlDsigC14NTransform.document = message; // The transform class needs the xml document 

// Validate signature as normal. 

này sẽ cho phép bạn để xác minh đúng một Chữ ký XML và giải quyết vấn đề của bạn.

Các vấn đề liên quan