How to verify signatures of XML File in C# with <x509certificate> (not cert file)?
Asked Answered
S

1

7

i am making some codes for goverment billing system and after reading for some weeks i reached a dead end.

I need to validate at least two signatures inside a xml file i receive from a server, i had made some code based on public MSDN to verify signatures when I am the one who's signing with a cert file or a x509store, and works fine, i can sign and validate each signature based on their reference with no trouble.

But, when i receive the file i don't know how to validate it as i don't have the certificate file, i am certainly aware there's the tag inside and if i get that value and put it on openssl.exe i can verify the identity of the signer, but idk how to check if the signature was made correctly

http://puu.sh/dypRH/c45e200202.png

in the past i used

if (signedXml.CheckSignature(cert, true))

now i try signedXml.CheckSignature())

fails every time, i can't reference which signature to pick, so i made a for

                foreach (XmlNode node1 in nodeList)
            {
                    testt = node1.OuterXml;
                     testt = testt.Replace(Environment.NewLine, string.Empty);
                    ttt.PreserveWhitespace = true;     
                    ttt.LoadXml(testt);

                    testt = testt.Replace(Environment.NewLine, string.Empty);
                   signedXml.LoadXml(ttt.DocumentElement);
                    //if (signedXml.CheckSignature(cert, true))
                    if (signedXml.CheckSignature())
                    {
                        Console.WriteLine("The XML signature is valid.");
                    }
                    else
                    {
                        Console.WriteLine("The XML signature is not valid.");
                    }


            #endregion
        }

yet they still fail

i've also made a certificate based on the xml file,

X509Certificate c = X509Certificate.CreateFromSignedFile("test.xml");
theCertificate = new X509Certificate2(c);

to validate, but fails too

I really don't know what to do now, i am kinda desperated, here's the xml file

http://puu.sh/dyqcv/356dd289ae.xml

i need to validate signatures with, after this i have to make a response file and send it back to the server (it's ready but as i can't validate signatures i don't want to go forth)

Oh and yes, i have removed the namespaces and linarized everything before the signature check/calculation

    public static XElement RemoveAllNamespaces(XElement e)
    {
        return new XElement(e.Name.LocalName,
           (from n in e.Nodes()
            select ((n is XElement) ? RemoveAllNamespaces(n as XElement) : n)),
           (e.HasAttributes) ? (from a in e.Attributes()
                                where (!a.IsNamespaceDeclaration)
                                select new XAttribute(a.Name.LocalName, a.Value)) : null);
    }

I will really appreciate from heart all kinds of help, even a little pointer of where should i try it will help.

Oh and sorry, but i really checked all the website, i hope this question ain't repeated, last time i got really bashed out and lost all my rep :(

But i got motivated enough to ask again

https://mcmap.net/q/11795/-c-string-replace-does-not-work-as-it-doesn-39-t-replace-the-value-duplicate

I suffered with this lol

Regards!

EDIT: as asked by user409104 here's the signature value for the entire file (the 1st of three), it inclused the signature nodes and keyinfo values too

<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="#SetDoc">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>pIQ3XhBvaULXo7vPOktydkK+c3g=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
n/bgCyPOI01quzrpt0OLRUbBnUd5vzjyv44S/3Oow56fS/DEtBF+83g1I4WXsw13h81rFhiApgku
tffdWuu23ox3ubGtuAVihK1xaOYBqim8dIBoLBN84M6P3H2+NDi4x01/c+4w7wtNCGedGNrjguwQ
0b864BTj0iavTpu0urUicWipsmxCv9p6JlkyVxmUdlgEvP5pPlv43qHopWvUDrYhXP9m45ap4ubg
47Zwpa7QCadghf4vEYUQOcrGcf4oDYa7KUc71VKTY8cAgmdTool8ugYD2ipNV75R5i3Cfbe8Jsyt
q9wy8iuo2Xc3FpUShojyr3JMl7meJupnmT4qGg==
</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>
xUg5RWGM6yKTu1hctQ0J9VZtr6+7VOQ75lDq7MeqxDTJgkHxO+P49GV/hRjLv3rCXvo9JBM8AKj5
U+/uue5OE6PgeqdS+M7HBF4ieD33wVsRYWuu2TLrw+/DRd6yEs61mPVRLDrIqjxxpa41VUAfwPXV
ksCZ7RNklyfSa5D+Zm6sx3v5kGPylWVpdW+k3BFYmUCW2j1rjGb5X9zV9Egi2VGe2SGsYLNu1aJS
HHAIPc+COJIBMENga/syQSNF2l4/GNUkn84RnlW5P75rPg6Oa+y2UwfUgmgrCeMcyJJKDMy6heqm
6huvgaxOTr9DZqWkxJYW5GGWTUUiq64JB3EjOQ==
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
<X509Data>
<X509Certificate>
MIIElTCCA32gAwIBAgIBLjANBgkqhkiG9w0BAQUFADCBpTEUMBIGA1UEAxMLU0lJLUNBLTIwMTMx
GjAYBgNVBAcTEVNhbnRpYWdvIGRlIENoaWxlMR0wGwYDVQQIExRSZWdpb24gTWV0cm9wb2xpdGFu
YTELMAkGA1UEBhMCQ0wxHDAaBgkqhkiG9w0BCQEWDXNpaS1jYUBzaWkuY2wxJzAlBgNVBAoTHlNl
cnZpY2lvIGRlIEltcHVlc3RvcyBJbnRlcm5vczAeFw0xMzA0MjQxMDM0NDJaFw0xNTA0MjQxMDM0
NDJaMIIBATE6MDgGA1UECxMxRGVwdG8uIGRlIEF0ZW5jaW9uIHkgQXNpc3RlbmNpYSBkZSBDb250
cmlidXllbnRlczEnMCUGA1UEChMeU2VydmljaW8gZGUgSW1wdWVzdG9zIEludGVybm9zMQswCQYD
VQQGEwJDTDEdMBsGA1UECBMUUmVnaW9uIE1ldHJvcG9saXRhbmExGjAYBgNVBAcTEVNhbnRpYWdv
IGRlIENoaWxlMSYwJAYJKoZIhvcNAQkBFhdTSUlfZHRlX2ltcHJlc29zQHNpaS5jbDEqMCgGA1UE
AxMhQ2VydGlmaWNhY2lvbiAgQ0NNICBEZXNhcnJvbGxhZG9yMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAxUg5RWGM6yKTu1hctQ0J9VZtr6+7VOQ75lDq7MeqxDTJgkHxO+P49GV/hRjL
v3rCXvo9JBM8AKj5U+/uue5OE6PgeqdS+M7HBF4ieD33wVsRYWuu2TLrw+/DRd6yEs61mPVRLDrI
qjxxpa41VUAfwPXVksCZ7RNklyfSa5D+Zm6sx3v5kGPylWVpdW+k3BFYmUCW2j1rjGb5X9zV9Egi
2VGe2SGsYLNu1aJSHHAIPc+COJIBMENga/syQSNF2l4/GNUkn84RnlW5P75rPg6Oa+y2UwfUgmgr
CeMcyJJKDMy6heqm6huvgaxOTr9DZqWkxJYW5GGWTUUiq64JB3EjOQIDAQABo3EwbzAJBgNVHRME
AjAAMD0GA1UdEQQ2MDSgGAYIKwYBBAHBAQGgDBMKNDUwMDAwNTItM6AYBggrBgEEAcEBA6AMEwo2
MDgwMzAwMC1LMCMGA1UdEgQcMBqgGAYIKwYBBAHBAQKgDBMKNjA4MDMwMDAtSzANBgkqhkiG9w0B
AQUFAAOCAQEAWbf4jOaJgvx4676oKqHoHlO5/y/8umb2eCjddVKWxrytL4Ncx/6aJSgmMBj52Whe
gHJf3+SCarDYgo2L7AzaIL7/nM1KtlKpcpqFU+LC+AFf4MctSe8nthdg7VaKze1f5W2ZKvVBDNwI
1LFrbBEn6w3PlkcJ0AjvlJBEgPlMzQVEKSEGdPOTbsiWvSxdxj8HuFFKx3R+bH9ZkNjP5s06nTFh
SFVVIYZvCQ/qIYyUCBe4ZvH02ekYK8KeO6suiDI8cctoC+DWGfSvcLEt07AuwuVbqzAde32ACnC2
lqqstjt3FuB3nYymxbrnzhJjpPkTt9m9MbSFvJzrAgQ7joO1Dw==
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>

i have made this to create the key based on the xml file, yet i can't choose which to pick, i guess it uses the first found, (but there are 3 in the xml) also still don't know how to use it to validate.

i can't make a x509certificate/2 with a RSAKeyValue right?

XmlElement XmlSignature;
XmlSignature = (XmlElement)fix2.DocumentElement.SelectSingleNode("//Signature");
RSAKeyValue key = new RSAKeyValue();
key.LoadXml(XmlSignature);
Shantel answered 17/12, 2014 at 15:6 Comment(3)
In order to validate a signature you need the public key from the party that signed the content. Do you have that public key? I did not want to click the link you provided for the xml document so I have not looked at it. Do you know with certainty that the public key of the signer is part of that xml document? If so, could you update the question to include the node that contains the public key.Downstage
According to Billing system developer guide it says the public key values will be between <keyinfo> tags, seems there is as RSA type, yet i searched and can't find a way to validate it check this screenshot puu.sh/dyre9/fb6d89928b.pngShantel
@Downstage i have made this to create the key based on the xml file, yet i can't choose which <signature> to pick, i guess it uses the first found, (but there are 3 in the xml) ` XmlElement XmlSignature; XmlSignature = (XmlElement)fix2.DocumentElement.SelectSingleNode("//Signature"); RSAKeyValue key = new RSAKeyValue(); key.LoadXml(XmlSignature);`Shantel
D
13

This should be sufficient to get you to a solution. The code below will validate the signature of the outermost Signature element in your xml document.

I believe the reason why it will not validate the inner ones is that they are wrapped by the outer signature block, you would need to take the steps of creating separate XmlDocument instance for each contained element and take the same steps separately for each of those nodes.

In the code below, 'passes' will be true on the third iteration.

What you would want to do in your solution is to grab the outer Signature node through xpath and only validate that one, then create new XmlDocument instances for each node in the document and do a separate certificate validation per each of those nodes.

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = true;
        xmlDoc.Load("ENVIO_DTE_345508.xml");
        SignedXml signedXml = new SignedXml(xmlDoc);
        XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
        XmlNodeList certificates = xmlDoc.GetElementsByTagName("X509Certificate");
        X509Certificate2 dcert2 = new X509Certificate2(Convert.FromBase64String(certificates[0].InnerText));
        foreach (XmlElement element in nodeList) {
            signedXml.LoadXml(element);
            bool passes = signedXml.CheckSignature(dcert2, true);
        }
Downstage answered 17/12, 2014 at 18:28 Comment(2)
This certainly solved my issue, after making the individual split process for each document, all the validations went OK, i even simulated a wrong signature and it gave error on validation Many thanks! Kudos for you!Shantel
The cspParams and rsaKey variables are not needed in this code, but great workZach

© 2022 - 2024 — McMap. All rights reserved.