8
I am developing a software integration with the legal note webservice for issuance of electronic tax notes of the city of Porto Alegre.
After some difficulties I was able to fine tune the xml so that it conforms to the standard, but now I’m facing problems with the signature validation.
Signatures are validated using signed: https://www.receita.fazenda.gov.br/Aplicacoes/SSL/ATBHE/Assinadoc/ValidadorAssinaturas.app/valida.aspx
I am developing in C# and I used the "Signxmldocument" method that is contained in a tutorial posted by Microsoft: https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.signedxml%28v=vs.110%29.aspx
Example of my signature:
<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>MIIICzCCBfOgAwIBAgIIK+lEzyepyEMwDQYJKoZIhvcNAQELBQAwdTELMAkGA1UEBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxNjA0BgNVBAsTLVNlY3JldGFyaWEgZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEZMBcGA1UEAxMQQUMgU0VSQVNBIFJGQiB2MjAeFw0xNDEwMTQxNTAwMDBaFw0xNzEwMTMxNTAwMDBaMIHyMQswCQYDVQQGEwJCUjELMAkGA1UECBMCUlMxFTATBgNVBAcTDFBPUlRPIEFMRUdSRTETMBEGA1UEChMKSUNQLUJyYXNpbDE2MDQGA1UECxMtU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgZG8gQnJhc2lsIC0gUkZCMRYwFAYDVQQLEw1SRkIgZS1DTlBKIEEzMRMwEQYDVQQLEwpBUiBTQUZFV0VCMUUwQwYDVQQDEzxKVVNUSUNBIEZBQ0lMIElORk9STUFDT0VTIFBST0NFU1NVQUlTIExUREEgTUU6MjEwNDgwNDIwMDAxNzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRIdp0ryu3IWsPJ7dl42wijH9RPqJw5H+6gFWdm9ivuZVQ1f7Vr0ZFvgTGmifPN9z3/Gy2fXI2U+X93dIJcIK79Hdm4Qd5lEwQ1eVRtHsrkmzhHH9C4fIefC8nGSdbu+/HcjwV1bd8KcitJkfstwX2r7yWeLcDRgr9AyCXvd29SU0IwbGbgtDt31UEId390+o+m4efi3WlKsNvCZosy2kpbZXD0+5fm0RHiMizXhnRanjbHgVekUPdjxLpQmiSJ5Ry/OCkqMKS0GnbewT97CwYXw4urVw3RTXbjnr1NO+7XvrU7dQzEmHgP6DGTNfcNRpMeLmiulW4CWMQz8UwJ9HBAgMBAAGjggMfMIIDGzCBmQYIKwYBBQUHAQEEgYwwgYkwSAYIKwYBBQUHMAKGPGh0dHA6Ly93d3cuY2VydGlmaWNhZG9kaWdpdGFsLmNvbS5ici9jYWRlaWFzL3NlcmFzYXJmYnYyLnA3YjA9BggrBgEFBQcwAYYxaHR0cDovL29jc3AuY2VydGlmaWNhZG9kaWdpdGFsLmNvbS5ici9zZXJhc2FyZmJ2MjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFLKgxD1GnnzIhWwIHhAylGVGcEFzMHEGA1UdIARqMGgwZgYGYEwBAgMKMFwwWgYIKwYBBQUHAgEWTmh0dHA6Ly9wdWJsaWNhY2FvLmNlcnRpZmljYWRvZGlnaXRhbC5jb20uYnIvcmVwb3NpdG9yaW8vZHBjL2RlY2xhcmFjYW8tcmZiLnBkZjCB8wYDVR0fBIHrMIHoMEqgSKBGhkRodHRwOi8vd3d3LmNlcnRpZmljYWRvZGlnaXRhbC5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL3NlcmFzYXJmYnYyLmNybDBEoEKgQIY+aHR0cDovL2xjci5jZXJ0aWZpY2Fkb3MuY29tLmJyL3JlcG9zaXRvcmlvL2xjci9zZXJhc2FyZmJ2Mi5jcmwwVKBSoFCGTmh0dHA6Ly9yZXBvc2l0b3Jpby5pY3BicmFzaWwuZ292LmJyL2xjci9TZXJhc2EvcmVwb3NpdG9yaW8vbGNyL3NlcmFzYXJmYnYyLmNybDAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIG4BgNVHREEgbAwga2BHkZJTkFOQ0VJUk9ASlVTVElDQUZBQ0lMLkNPTS5CUqAdBgVgTAEDAqAUExJMQVVSQSBNRVVSRVIgTE9QRVOgGQYFYEwBAwOgEBMOMjEwNDgwNDIwMDAxNzKgOAYFYEwBAwSgLxMtMTAxMjE5ODE4MTk2MDk5OTA4NzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwoBcGBWBMAQMHoA4TDDAwMDAwMDAwMDAwMDANBgkqhkiG9w0BAQsFAAOCAgEA3ge3eSzTJ6qaM839+xeyKI8ftqPIFftlMV9MdgfRNkCVDOTdC47Zn7FBQJLXOT+ajt+gQcM7EBGG8we/YLb7n8keNSEP37nvwQhDLgVSsw0F7yD87IbjJlRcoxIV3ZsgkTusmO6gYI7pRNnGvqwOj0AS44pBHnrG6u1ILTf1qXr8SnAAOP2Oz9jGesZ30xQj6tSsH8JAiLLiDxL9jEBWpsW9B1LKI8l3zVCULlH0YMP5tjYyBfVWj/PJvfab4gwIU6ke5YYtglbsSyK9q20lvjOUciCyeerfizhN6x1HM6Nk+D/oHr9II7ARM9CtvHtvh4I6JivVUhMx9bsYo0FEOwf04TYfAQBFLV7pnQ6ABrZcRFAsxvv4nagvympY4giKPwl4hG7GVFkPref980CEczIG8nPYr6vtJW0t4qCeDQaFzm1r1vzQ/VrdMEmk9EjVjroWQM6l1RfyfReQ6AVvWYdK0b1Z9lnzqNE80363MJPLMgir8VDqwyPt69zlfP+3Xjvxm71V/nF8J9Rv1N2f725DUdP3dhm9SEg9G2NdKHZbc/AOmtroj1V3oYqpqYHQfI8m+DhxhIrgJUoef4A44Z3Z6pkikuDyykvo7PVy1yyzkdYVmpk3hzhPzmt3kj/Zna3x2Z/XQqq3FOyc6J2eO6ZpvW1w/Ul9uWFomrFDd7A=</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
Of the signature data:
- Digest Value is the hash representation of the URI tag found in Ference.
- Tag
<x509Data>
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 codes that emit digital signature in C# all follow the same pattern.
- I also did a check of the Digitial signature pattern on the website: www.W3.org/TR/xmldsig-core/ and realized that everything is correct.
- In the signing message the only thing that appears in the description of the problem is: "The signing of the document is not valid".
So the question is, why is this signature not valid?
You used the
12015100000227.xml
as an entrance to theSignXmlDocument
? That oneDigestValue
was produced as? And what are you sending to the assinadoc, a single XML or more than one? (I ask because it seems to me that you are signing document A and keeping the signature on document B, which at first is ok, but depending on what the signed person expects it might be necessary that the signature be on the document itself; see that related question - unfortunately also no solution - for an example).– mgibsonbr
P.S. I don’t have a conclusive answer to give you, I’m just exploring the points where something could have gone wrong. This seems to be a common problem - from the point of view all questions about Nfe here on the website - but unfortunately I don’t have enough experience in the subject to better guide you... :(
– mgibsonbr
12015100000227.xml is the file itself (in this case I was doing a test on generating the saved xml and then referencing the file in the signature, it didn’t work either), I can change and put "http://www.microsoft.com" is just the hash, it is only there because it is mandatory. First I build all the xml and then I send the signatures (according to the developers forum of the legal note this is the most secure way). Sending yourself from an XML with multiple signatures. I’ll take a look at your links, thanks.
– João Pedro
The hash "is only there because it is mandatory", it is a fundamental part of the signature algorithm! If you are calculating the wrong hash, the signature will not hit. You need: 1) identify what needs to be signed (probably an element within XML, maybe the
infNFe
, do not know - look in the documentation); 2) Reference the element to be signed (put#id_do_elemento
in the URI ofReference
); 3) Hash this specific element; 4) Sign this hash and put it onSignatureValue
; 5) Place inX509Data
the same certificate used to sign. By the way, that’s it.– mgibsonbr
I understand what you mean, but several times I tried to put #id_do_element however the Uri property of the Reference class does not accept this reference and there is an error in the XML validation when the "Computesignature" method is called. Reference Reference = new Reference(); Reference.Uri = "#" + "12015100000232"; signedXml.Addreference(Reference); Keyinfo ... signedXml.Computesignature(); -> "Poorly formed Reference element" The step by step you said helped me understand the whole process, I’ll keep trying alternatives.
– João Pedro
I believe I have found the reference problem when I was instânciando the class Signedxml() I must pass the document until it adds the reference and it does not exist it will end up playing an exception so the correct is: Signedxml signedXml = new Signedxml(Mydocument); The clarification about the id and its respective element was priceless, thank you very much, with xmls so extensive some things go unnoticed, I will develop a few more lines and see if the validation passes this time.
– João Pedro
Despite modifying the entire code and leaving the part of the Referral round, it still does not pass the validation of the federal revenue. Seeing an example: signedXml.Signingkey = cert.Privatekey; Where the private key is retrieved and assigned to the main signature object I believe you should generate a valid signature, the way I was doing was generating a new signedXml.Signingkey = new Rsacryptoserviceprovider(); for each signature, but the correct one must be with the private key. But since my A3 certification is being very difficult to recover the private key, I’ll keep trying...
– João Pedro
I have just ruled out the possibility of retrieving the private key, at the url: http://www.pronova.com.br/wiki/index.php?title=FAQ_Certificaos_Digitais , it is clear that it is not possible to extract the private key from an A3 certificate: "According to ICP-Brazil standards, it is not allowed to export the private key from the device’s memory (token or smart card), so it is not possible to back up (backup) a type A3 certificate".
– João Pedro