frones / nfe

Bibliotecas para geração, validação, assinatura e transmissão de XMLs da NFe em Go
Mozilla Public License 2.0
33 stars 11 forks source link

Assinatura do XML #3

Open rodrigorodriguescosta opened 3 years ago

rodrigorodriguescosta commented 3 years ago

Olá, de uma olhada no seu código e não vi se tinha como assinar um XML usando o certificado, vi que vc ler o certificado, tem alguma função para assinatura do XML?

frones commented 3 years ago

Olá, Rodrigo! Na verdade eu só comecei esse projeto, minha necessidade imediata eram as consultas de situação da NFe e de cadastro. O restante (incluindo geração, assinatura e transmissão dos XMLs) ficou pra depois e eu acabei entrando em outro projeto que está bastante distante da NFe. Ainda pretendo finalizar os recursos inicialmente pretendidos, mas a essa altura não espere muita agilidade. Se você tiver flexibilidade de linguagem, recomendo dar uma olhada no ACBr e no UniNFe. São dois projetos bacanas e bem completos para NFe.

rodrigorodriguescosta commented 3 years ago

obrigado pelo retorno, eu ja tenho sistema que emite Nfe e assinatura feito em Python, estava migrando pra Go e queria emitir a partir de um servidor na nuvem em um programa Go, cheguei a testar esse https://github.com/russellhaering/goxmldsig/issues/65 e conseguir fazer gerar uma assinatura válida, porém, ele tem um bug que so assinsa se o Id tiver na raiz do XML.

eu conheço o Acbr, tentei o AcbrLib com comunicação via C para ser usada em Go mas nao conseguir funcionar. https://acbr.sourceforge.io/ACBrLib/CdeclouStdCallqualusar.html

novamente, obrigado pelo retorno

alexrosabr commented 2 years ago

@rodrigorodriguescosta você ainda tem interesse em assinar e enviar?

rodrigorodriguescosta commented 2 years ago

@alexrosabr eu conseguir assinar o XML em Go usando essa lib acima que falei

alexrosabr commented 2 years ago

@alexrosabr eu conseguir assinar o XML em Go usando essa lib acima que falei

@rodrigorodriguescosta Você precisou mexer na https://github.com/russellhaering/goxmldsig ou conseguiu fazer funcionar de outra forma? Tenho interesse em dar continuidade, pode ser aqui nesse projeto ou em algum fork.

RhuanPrado commented 2 years ago

@alexrosabr eu conseguir assinar o XML em Go usando essa lib acima que falei

Interessante poderia apresentar um exemplo da assinatura utilizando essa Lib? Eu tentei e não consegui uma assinatura válida.

alexrosabr commented 2 years ago

@alexrosabr eu conseguir assinar o XML em Go usando essa lib acima que falei

Interessante poderia apresentar um exemplo da assinatura utilizando essa Lib? Eu tentei e não consegui uma assinatura válida.

Não fui eu, foi o @rodrigorodriguescosta que conseguiu.

rodrigorodriguescosta commented 2 years ago

fala galera, segue a fucnao que fiz funcionar, precisa adaptar


        keyPair, _ := tls.X509KeyPair(certBytes, keBytes)
        keyStore := dsig.TLSCertKeyStore(keyPair)

        ctx := dsig.NewDefaultSigningContext(keyStore)
        ctx.Hash = crypto.SHA1
        ctx.IdAttribute = "Id"
        ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
        ctx.Prefix = ""
        doc := etree.NewDocument()

               //procura pele elemento que precisa de assinatura
        elementToSign := doc.FindElement(fmt.Sprintf("//%s", tagAssinatura))
        if elementToSign == nil {
            err = fmt.Errorf("nao foi possivel achar a tag de referencia '%s' para assinatura ", tagAssinatura)
            return
        }
        // so assina corretamente se tiver o xmlns dentro da tag que precisa assinar, entao caso nao exista, adicione
        // para poder efetuar a assinatura corretamente
        if elementToSign.SelectAttr("xmlns") == nil {
            if strings.Contains(xml, "http://www.portalfiscal.inf.br/mdfe") {
                elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/mdfe")
            } else {
                elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/nfe")
            }
        }

        // realiza a assinatura
        signedElement, err2 := ctx.SignEnveloped(elementToSign)
rodrigorodriguescosta commented 2 years ago

ou seja, a lib em si nao precisou de ajuste, precisou de ajuste na funcao para assinar o XML da nota

RhuanPrado commented 2 years ago

@alexrosabr eu conseguir assinar o XML em Go usando essa lib acima que falei

@rodrigorodriguescosta Você precisou mexer na https://github.com/russellhaering/goxmldsig ou conseguiu fazer funcionar de outra forma? Tenho interesse em dar continuidade, pode ser aqui nesse projeto ou em algum fork.

Obteve algum sucesso na assinatura?

RhuanPrado commented 2 years ago

Ao enivar para a Sefaz eu recebo: `

2 14.4.80-OR3 104 Lote processado 31 2022-09-06T10:35:31-03:00 2 14.4.80-OR3 31220705749654000136550010000104901220730125 2022-09-06T10:35:31-03:00 nNJuzqGxxkYkiFZqdtfbEtftgx8= 297 Rejeicao: Assinatura difere do calculado

</soap:Body></soap:Envelope>`

rodrigorodriguescosta commented 2 years ago

preste atencao aos comentários no código

RhuanPrado commented 2 years ago

fala galera, segue a fucnao que fiz funcionar, precisa adaptar

      keyPair, _ := tls.X509KeyPair(certBytes, keBytes)
      keyStore := dsig.TLSCertKeyStore(keyPair)

      ctx := dsig.NewDefaultSigningContext(keyStore)
      ctx.Hash = crypto.SHA1
      ctx.IdAttribute = "Id"
      ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
      ctx.Prefix = ""
      doc := etree.NewDocument()

               //procura pele elemento que precisa de assinatura
      elementToSign := doc.FindElement(fmt.Sprintf("//%s", tagAssinatura))
      if elementToSign == nil {
          err = fmt.Errorf("nao foi possivel achar a tag de referencia '%s' para assinatura ", tagAssinatura)
          return
      }
      // so assina corretamente se tiver o xmlns dentro da tag que precisa assinar, entao caso nao exista, adicione
      // para poder efetuar a assinatura corretamente
      if elementToSign.SelectAttr("xmlns") == nil {
          if strings.Contains(xml, "http://www.portalfiscal.inf.br/mdfe") {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/mdfe")
          } else {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/nfe")
          }
      }

      // realiza a assinatura
      signedElement, err2 := ctx.SignEnveloped(elementToSign)

Legal, eu estou faz algum tempo tentando realizar a assinatura!

rodrigorodriguescosta commented 2 years ago

eu passei mais de mês até descobrir o porque, que no caso é esse código que mandei

RhuanPrado commented 2 years ago

eu passei mais de mês até descobrir o porque, que no caso é esse código que mandei

Como você faz a manipulação do xml? utilizando https://pkg.go.dev/github.com/beevik/etree ou https://pkg.go.dev/encoding/xml

rodrigorodriguescosta commented 2 years ago

eu passei mais de mês até descobrir o porque, que no caso é esse código que mandei

Como você faz a manipulação do xml? utilizando https://pkg.go.dev/github.com/beevik/etree ou https://pkg.go.dev/encoding/xml

utilizando o etree, aqui está meu import


import (
    "comps/utils"
    "crypto"
    "crypto/tls"
    "encoding/xml"
    "fmt"
    "net/http"
    "strings"
    "time"

    "github.com/beevik/etree"
    dsig "github.com/russellhaering/goxmldsig"
)
RhuanPrado commented 2 years ago

fala galera, segue a fucnao que fiz funcionar, precisa adaptar

      keyPair, _ := tls.X509KeyPair(certBytes, keBytes)
      keyStore := dsig.TLSCertKeyStore(keyPair)

      ctx := dsig.NewDefaultSigningContext(keyStore)
      ctx.Hash = crypto.SHA1
      ctx.IdAttribute = "Id"
      ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
      ctx.Prefix = ""
      doc := etree.NewDocument()

               //procura pele elemento que precisa de assinatura
      elementToSign := doc.FindElement(fmt.Sprintf("//%s", tagAssinatura))
      if elementToSign == nil {
          err = fmt.Errorf("nao foi possivel achar a tag de referencia '%s' para assinatura ", tagAssinatura)
          return
      }
      // so assina corretamente se tiver o xmlns dentro da tag que precisa assinar, entao caso nao exista, adicione
      // para poder efetuar a assinatura corretamente
      if elementToSign.SelectAttr("xmlns") == nil {
          if strings.Contains(xml, "http://www.portalfiscal.inf.br/mdfe") {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/mdfe")
          } else {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/nfe")
          }
      }

      // realiza a assinatura
      signedElement, err2 := ctx.SignEnveloped(elementToSign)

essas alterações estão no seu Fork? https://github.com/rodrigorodriguescosta/goxmldsig

rodrigorodriguescosta commented 2 years ago

fala galera, segue a fucnao que fiz funcionar, precisa adaptar

        keyPair, _ := tls.X509KeyPair(certBytes, keBytes)
        keyStore := dsig.TLSCertKeyStore(keyPair)

        ctx := dsig.NewDefaultSigningContext(keyStore)
        ctx.Hash = crypto.SHA1
        ctx.IdAttribute = "Id"
        ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
        ctx.Prefix = ""
        doc := etree.NewDocument()

               //procura pele elemento que precisa de assinatura
        elementToSign := doc.FindElement(fmt.Sprintf("//%s", tagAssinatura))
        if elementToSign == nil {
            err = fmt.Errorf("nao foi possivel achar a tag de referencia '%s' para assinatura ", tagAssinatura)
            return
        }
        // so assina corretamente se tiver o xmlns dentro da tag que precisa assinar, entao caso nao exista, adicione
        // para poder efetuar a assinatura corretamente
        if elementToSign.SelectAttr("xmlns") == nil {
            if strings.Contains(xml, "http://www.portalfiscal.inf.br/mdfe") {
                elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/mdfe")
            } else {
                elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/nfe")
            }
        }

        // realiza a assinatura
        signedElement, err2 := ctx.SignEnveloped(elementToSign)

essas alterações estão no seu Fork? https://github.com/rodrigorodriguescosta/goxmldsig

nao, eu nao dei seguimento ao projeto, essas alteracoes fazem parte do projeto erp que eu desenvolvi, eu copiei do código aqui essa parte de assinatura, eu nao alterei o projeto de assinatura, na verdade vou ate excluir esse fork pq acabei nao utilizando ele

RhuanPrado commented 2 years ago

fala galera, segue a fucnao que fiz funcionar, precisa adaptar

      keyPair, _ := tls.X509KeyPair(certBytes, keBytes)
      keyStore := dsig.TLSCertKeyStore(keyPair)

      ctx := dsig.NewDefaultSigningContext(keyStore)
      ctx.Hash = crypto.SHA1
      ctx.IdAttribute = "Id"
      ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
      ctx.Prefix = ""
      doc := etree.NewDocument()

               //procura pele elemento que precisa de assinatura
      elementToSign := doc.FindElement(fmt.Sprintf("//%s", tagAssinatura))
      if elementToSign == nil {
          err = fmt.Errorf("nao foi possivel achar a tag de referencia '%s' para assinatura ", tagAssinatura)
          return
      }
      // so assina corretamente se tiver o xmlns dentro da tag que precisa assinar, entao caso nao exista, adicione
      // para poder efetuar a assinatura corretamente
      if elementToSign.SelectAttr("xmlns") == nil {
          if strings.Contains(xml, "http://www.portalfiscal.inf.br/mdfe") {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/mdfe")
          } else {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/nfe")
          }
      }

      // realiza a assinatura
      signedElement, err2 := ctx.SignEnveloped(elementToSign)

essas alterações estão no seu Fork? https://github.com/rodrigorodriguescosta/goxmldsig

nao, eu nao dei seguimento ao projeto, essas alteracoes fazem parte do projeto erp que eu desenvolvi, eu copiei do código aqui essa parte de assinatura

então vc não efetuou alterações na Lib

RhuanPrado commented 2 years ago

Obrigado pela resposta, precisando estou a disposição!

RhuanPrado commented 2 years ago

fala galera, segue a fucnao que fiz funcionar, precisa adaptar

      keyPair, _ := tls.X509KeyPair(certBytes, keBytes)
      keyStore := dsig.TLSCertKeyStore(keyPair)

      ctx := dsig.NewDefaultSigningContext(keyStore)
      ctx.Hash = crypto.SHA1
      ctx.IdAttribute = "Id"
      ctx.Canonicalizer = dsig.MakeC14N10RecCanonicalizer()
      ctx.Prefix = ""
      doc := etree.NewDocument()

               //procura pele elemento que precisa de assinatura
      elementToSign := doc.FindElement(fmt.Sprintf("//%s", tagAssinatura))
      if elementToSign == nil {
          err = fmt.Errorf("nao foi possivel achar a tag de referencia '%s' para assinatura ", tagAssinatura)
          return
      }
      // so assina corretamente se tiver o xmlns dentro da tag que precisa assinar, entao caso nao exista, adicione
      // para poder efetuar a assinatura corretamente
      if elementToSign.SelectAttr("xmlns") == nil {
          if strings.Contains(xml, "http://www.portalfiscal.inf.br/mdfe") {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/mdfe")
          } else {
              elementToSign.CreateAttr("xmlns", "http://www.portalfiscal.inf.br/nfe")
          }
      }

      // realiza a assinatura
      signedElement, err2 := ctx.SignEnveloped(elementToSign)

na variavel doc você carrega o arquivo xml? estou tendo problemas com o FindElement()

rodrigorodriguescosta commented 2 years ago

sim, esqueci de colocar essa parte, carrego o xml na variavel doc


doc := etree.NewDocument()
err = doc.ReadFromString(xml)
if err != nil {
    return
}
RhuanPrado commented 2 years ago

@rodrigorodriguescosta A tag para assinatura você passa a infNFe ? ou a NFe? por que quando eu passo a infNFe ele coloca dentro da Tag infNFe e não ao lado

rodrigorodriguescosta commented 2 years ago

eu passo a infNFe