16

Every time I try to send a signed XML, the web service verifier rejects it.

To sign the document I just adapted this sample code provided by Microsoft:

http://msdn.microsoft.com/es-es/library/ms229745(v=vs.110).aspx

My implementation:

    public static XmlDocument FirmarXML(XmlDocument xmlDoc)
    {
        try
        {
            X509Certificate2 myCert = null;
            var store = new X509Store(StoreLocation.CurrentUser); //StoreLocation.LocalMachine fails too
            store.Open(OpenFlags.ReadOnly);
            var certificates = store.Certificates;
            foreach (var certificate in certificates)
            {
                if (certificate.Subject.Contains("xxx"))
                {
                    myCert = certificate;
                    break;
                }
            }

            if (myCert != null)
            {
                RSA rsaKey = ((RSA)myCert.PrivateKey);

                // Sign the XML document. 
                SignXml(xmlDoc, rsaKey);                    
            }

        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message);
        }
        return xmlDoc;
    }


    // Sign an XML file. 
    // This document cannot be verified unless the verifying 
    // code has the key with which it was signed.
    public static void SignXml(XmlDocument xmlDoc, RSA Key)
    {
        // Check arguments.
        if (xmlDoc == null)
            throw new ArgumentException("xmlDoc");
        if (Key == null)
            throw new ArgumentException("Key");

        // Create a SignedXml object.
        SignedXml signedXml = new SignedXml(xmlDoc);

        // Add the key to the SignedXml document.
        signedXml.SigningKey = Key;

        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri = "";

        // Add an enveloped transformation to the reference.
        XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
        reference.AddTransform(env);

        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);

        // Compute the signature.
        signedXml.ComputeSignature();

        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

    }

I think I am following the same steps using my own certificate, however it doesn't works as expected.

Any suggestion will be welcome.

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Michael Knight
  • 648
  • 2
  • 10
  • 26

2 Answers2

17

How does the server know what certificate the document is signed with? You seem to not to include the cert in the signed document:

    KeyInfo keyInfo = new KeyInfo();
    KeyInfoX509Data keyInfoData = new KeyInfoX509Data( Key );
    keyInfo.AddClause( keyInfoData );
    signedXml.KeyInfo = keyInfo;

If you need more details, consult my blog entry

http://www.wiktorzychla.com/2012/12/interoperable-xml-digital-signatures-c_20.html

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • Hi Wiktor, your blog was very interesting and I used the samples you show to test. Unfortunately I still having the same issue, the signature is rejected. I will post more information below. – Michael Knight May 02 '14 at 18:31
  • Just wondering, does this way not expose private key in the payload or does the private key get encrypted somehow in the payload? – Jami Jul 23 '18 at 00:10
  • @Jami: there's no private key included this way, only the public key (certificate). – Wiktor Zychla Jul 23 '18 at 09:43
3

It's a long time since this post has been created. I got the same problem with the digital signature can not be validated.

For whom who has the same issue. In my case the difference is XmlDocument.PreserveWhitespace option.

When the PreserveWhitespace = true, the document is not valid when checking against the public key. PreserveWhitespace = false makes the signed XML valid.

I guess that when saving the signed XML to file and sending it to server. There is some space or special characters are inserted to the document and make it invalid.

Abrar Jahin
  • 13,970
  • 24
  • 112
  • 161
Eric Ngo
  • 111
  • 1
  • 7
  • 1
    If you want to keep the whitespaces in xml as original format using PreserveWhitespace = true, then in server code when validating the xml, you must set PreserveWhitespace = true when loading the xml as well. – Eric Ngo Oct 23 '19 at 19:40