Question
Marcio Coelho · Dec 15, 2021

Validate XML signature

I Have a problem with a Signature validator to XML file, when this file have more than one Signature tag.

Like This

<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">
    <NFe>
        <infNFe Id="NFexxx" versao="4.00">
            ...
        </infNFe>
        <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="#NFexxx">
                    ...
                </Reference>
            </SignedInfo>
            ...
        </Signature>
    </NFe>
    <protNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">
        <infProt Id="ID666">
            ...
        </infProt>
        <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="#ID666">
                    ...
                </Reference>
            </SignedInfo>
            ...
        </Signature>
    </protNFe>
</nfeProc>

This is my method of validation

Validate(file,element,clazz) ;
new reader,sc,data,xmlSignature
;
set sc=reader.OpenFile(file)
quit:$$$ISERR(sc) sc
; get elementet
do reader.Correlate(element,clazz)
if 'reader.Next(.data,.sc){
quit sc 
}
;
do reader.Correlate("Signature","%XML.Security.Signature")
if 'reader.Next(.xmlSignature,.sc) {
    quit sc
}
;
quit xmlSignature.ValidateDocument(data)

I Get this error when to try call Validate("file.xml","NFe","class")

<METHOD DOES NOT EXIST>zValidateElement+35^%XML.Security.Signature.1 *GetNode "class"




 

00
2 0 3 81
Log in or sign up to continue

Try it like this:

new reader,sc,data,xmlSignature

set sc=reader.OpenFile(file)
quit:$$$ISERR(sc) sc

set document = reader.Document

do reader.Correlate("Signature","%XML.Security.Signature")
if 'reader.Next(.xmlSignature,.sc) {
    quit sc
}

quit xmlSignature.ValidateDocument(document)

From docs.

I talked to intersystems support. he asked me to break validation into two steps. one for each Tag. I'm trying to follow the support tips. But without success so far. In this example I'm trying to validate just the first <NFe> tag
 

; 
; set sc=$$ValidateNFe("teste.xml","v400")
;
ValidateNFe(cswFileNameOrStream,cswNFeVersion) ;
new reader,sc,data,nfeStream,protNFeStream,clazzProc,clazzNFe,clazzProtNFe
;
set sc=$$Reader(cswFileNameOrStream,.reader)
quit:$$$ISERR(sc) sc
;
set clazzProc="br.com.sefaz.nfe."_cswNFeVersion_".TNfeProc"
;
set sc=##class(%Dictionary.CompiledClass).%ExistsId(clazzProc)
quit:$$$ISERR(sc) $$$ERROR(10000,"Classe ("_clazzProc_") não existente!")
; 
do reader.Correlate("nfeProc",clazzProc)
if 'reader.Next(.data,.sc){
quit $$$ERROR(10000,"Arquivo XML inválido!") 
}
;
set sc=$$XmlToStream(data.NFe,.nfeStream)
quit:$$$ISERR(sc) sc
;
set sc=##class(%XML.Document).GetDocumentFromStream(nfeStream,.document)
do document.AddIDs()
quit data.NFe.Signature.ValidateDocument(document)

Reader(cswFileNameOrStream,cswReader) ;
new sc
;
set cswReader=##class(%XML.Reader).%New()
set sc=cswReader.OpenStream(cswFileNameOrStream)
quit sc

XmlToStream(cswObj,xmlStream) ;
new writer,sc
;
set writer=##class(%XML.Writer).%New() 
set writer.Charset="UTF-8"
set writer.Indent=1
set writer.NoXMLDeclaration=1
set xmlStream=##class(%GlobalBinaryStream).%New()
;
set sc=writer.OutputToStream(.xmlStream)
quit:$$$ISERR(sc) sc
;
set sc=writer.RootObject(cswObj)
quit sc 

I get this error
 

w sc
FailedCheck

I believe that my "XmlToStream" rule is changing the original XML and therefore the validation was compromised. Does that make any sense?

HI all.....
I found a simple solution....
 

ValidateSignature(cswFileNameOrStream) ;
new sc,status,xmlSignature,cswRootCA,reader
;
set cswRootCA="/certfiles/root_ca_icp-brasil.crt"
set reader=##class(%XML.Reader).%New()
;
set sc=reader.OpenFile(cswFileNameOrStream)
quit:$$$ISERR(sc) sc
;
do reader.Correlate("Signature", "%XML.Security.Signature")
while (reader.Next(.xmlSignature, .status) && (sc=$$$OK)) {
set sc = xmlSignature.ValidateDocument(reader.Document,,cswRootCA)
}
;
quit sc