Digital signature validation

8

I am developing software for integrating with the webservice of the legal note for the issuance of electronic invoices of the city of Porto Alegre.

After some difficulties I managed to fine-tune the xml so that it conforms to the standard, but now I'm facing problems with signature validation.

Signatures are validated using the signed c: link

I'm developing in C # and I used the "SignXmlDocument" method that appears in a tutorial posted by Microsoft: link

My signature example:

<Signature Id="Ass_1_2015100000227"
    xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" />
        <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
        <Reference URI="12015100000227.xml">
            <Transforms>
                <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <DigestValue>pAukI83FOJt5xPAkuNfmaFkxGQ0=</DigestValue>
        </Reference>
    </SignedInfo>
<SignatureValue>vkgvOXOgFT4KiyMzOF+8iYf7wiorwG1SQao5y0F9AkvYBJI3EQHtHL4nOXRoAYOomaMpL/T30hNqmi50mOOgUu1EcYVjkpfnpVSmJMJTqcXUCbVkyYdLNayuZLkP9Q1tJqMcN6CG2j+huBDqQhfECD9Hv94TUtpg0TMMMohrFGA=</SignatureValue>
    <KeyInfo>
        <X509Data>
<X509Certificate>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</X509Certificate>
        </X509Data>
    </KeyInfo>
</Signature>

From the signature data:

  • Digest Value is the hash representation of the URI tag found in reference.
  • In the <x509Data> tag the data is the public key of my certificate (which is an A3)
  • The only value generated by the "ComputeSignature ()" method is Signature Value which made me think that it would be the problem, but looking at other source code that issues digital signature in C # all follow the same pattern.
  • I also performed a verification of the digitial signature pattern at www.w3.org/TR/xmldsig-core/ and realized that everything is correct.
  • In the signed message, the only thing that appears in the problem description is: "The document signature is not valid".

So the question is: why is this signature invalid?

    
asked by anonymous 15.12.2015 / 12:57

2 answers

5

After losing a considerable amount of time I found the reason:

I was saving the xml file like this:

XmlDocument xmlDoc = new XmlDocument();

xmlDoc.PreserveWhitespace = false;

xmlDoc.InnerXml = xml;

xmlDoc.Save(System.Configuration.ConfigurationManager.AppSettings["filePath"] + "generatedXml.xml");

It should be saved like this:

StreamWriter SW;
SW = File.CreateText(@"myxml.xml");
SW.Write(signedXmlData);
SW.Close();

The whole problem was in the xml encoding, from my experiences the Save method did not generate an xml with the valid encoding, so one option was to use the StreamWriter class and save the loaded file directly from the stream.

The digital signature method:

    public string SignXml(string xml, string refUri, string signatureId)
    {
        X509Certificate2 _X509Cert = LoadCertificate(@"C:\mycert.cer");

        XmlDocument doc = CreateSignXml(xml);

        // Create a SignedXml object.
        SignedXml signedXml = new SignedXml(doc);
        signedXml.Signature.Id = signatureId;
        signedXml.SigningKey = _X509Cert.PrivateKey;
        signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";

        Reference reference = new Reference("#" + refUri);
        reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
        reference.AddTransform(new XmlDsigC14NTransform());

        signedXml.AddReference(reference);

        KeyInfo keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(_X509Cert));

        signedXml.KeyInfo = keyInfo;          

        signedXml.ComputeSignature();

        XmlElement xmlDigitalSignature = signedXml.GetXml();

        return xmlDigitalSignature.OuterXml;
    }

    private static XmlDocument CreateSignXml(string xml)
    {
        XmlDocument doc = new XmlDocument();

        doc.PreserveWhitespace = false;

        doc.LoadXml(xml);

        return doc;
    }

    private static X509Certificate2 LoadCertificate(X509Certificate2 X509Cert)
    {
        X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
        X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
        X509Certificate2Collection collection1 = (X509Certificate2Collection)collection.Find(X509FindType.FindBySubjectDistinguishedName, X509Cert.Subject.ToString(), false);

        return collection1[0];//Só olhar o índice em collection1 que está o certificado desejado, no meu caso ele era o primeiro.
    }
    
18.12.2015 / 19:00
0

To calculate DigestValue

1 add the xmlns namespace with the link value in the infNFe tag

2 canonize the infNFe tag

3 calculate the Digest using SHA1 and convert the result to Base64

To sign the note

1 add the xmlns namespace with the value link in the SignedInfo tag

2 canonize the SignedInfo tag

3 Sign the SignedInfo tag, convert the result to Base64

The subscription template is this:

<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="#NFe00000000000000000000000000000000000000000000">
            <Transforms>
                <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>?</DigestValue>
        </Reference>
    </SignedInfo>
    <SignatureValue>?</SignatureValue>
    <KeyInfo>
        <X509Data>
            <X509Certificate>?</X509Certificate>
        </X509Data>
    </KeyInfo>
</Signature>
    
21.08.2016 / 18:22