Browse Source

Agora o signxml funciona a assinatura. Uhull

tags/0.1.5
Danimar Ribeiro 9 years ago
parent
commit
ee135a6c9a
  1. 1
      pytrustnfe/certificado.py
  2. 12
      pytrustnfe/nfe/__init__.py
  3. 149
      pytrustnfe/nfe/assinatura.py
  4. 30
      pytrustnfe/nfe/templates/NfeAutorizacao.xml
  5. 87
      pytrustnfe/nfse/assinatura.py
  6. 2
      pytrustnfe/nfse/paulistana/__init__.py

1
pytrustnfe/certificado.py

@ -31,7 +31,6 @@ def extract_cert_and_key_from_pfx(pfx, password):
return cert, key
def save_cert_key(cert, key):
cert_temp = '/tmp/' + uuid4().hex
key_temp = '/tmp/' + uuid4().hex

12
pytrustnfe/nfe/__init__.py

@ -48,17 +48,9 @@ def _send(certificado, method, sign, **kwargs):
xml_send = render_xml(path, '%s.xml' % method, **kwargs)
if sign:
xml_send = '<!DOCTYPE NFe [<!ATTLIST infNFe Id ID #IMPLIED>]>' + \
xml_send
xml_send = xml_send.replace('\n', '')
pfx_path = certificado.save_pfx()
signer = Assinatura(pfx_path, certificado.password)
xml_send = signer.assina_xml_nota(
signer = Assinatura(certificado.pfx, certificado.password)
xml_send = signer.assina_xml(
xml_send, kwargs['NFes'][0]['infNFe']['Id'])
xml_send = xml_send.replace(
'\n<!DOCTYPE NFe [\n<!ATTLIST infNFe Id ID #IMPLIED>\n]>\n', '')
xml_send = xml_send.replace('\n', u'')
xml_send = xml_send.replace('<?xml version="1.0"?>', '')
url = localizar_url(method, kwargs['estado'], kwargs['ambiente'])
cabecalho = _build_header(method, **kwargs)

149
pytrustnfe/nfe/assinatura.py

@ -2,11 +2,11 @@
# © 2016 Danimar Ribeiro, Trustcode
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import xmlsec
import libxml2
import os.path
NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#'
import signxml
from lxml import etree
from pytrustnfe.certificado import extract_cert_and_key_from_pfx
from signxml import XMLSigner
from StringIO import StringIO
class Assinatura(object):
@ -15,125 +15,22 @@ class Assinatura(object):
self.arquivo = arquivo
self.senha = senha
def _checar_certificado(self):
if not os.path.isfile(self.arquivo):
raise Exception('Caminho do certificado não existe.')
def _inicializar_cripto(self):
libxml2.initParser()
libxml2.substituteEntitiesDefault(1)
xmlsec.init()
xmlsec.cryptoAppInit(None)
xmlsec.cryptoInit()
def _finalizar_cripto(self):
xmlsec.cryptoShutdown()
xmlsec.cryptoAppShutdown()
xmlsec.shutdown()
libxml2.cleanupParser()
def assina_xml(self, xml, reference):
self._checar_certificado()
self._inicializar_cripto()
try:
doc_xml = libxml2.parseMemory(
xml.encode('utf-8'), len(xml.encode('utf-8')))
signNode = xmlsec.TmplSignature(doc_xml,
xmlsec.transformInclC14NId(),
xmlsec.transformRsaSha1Id(), None)
doc_xml.getRootElement().addChild(signNode)
refNode = signNode.addReference(xmlsec.transformSha1Id(),
None, '#' + str(reference), None)
refNode.addTransform(xmlsec.transformEnvelopedId())
refNode.addTransform(xmlsec.transformInclC14NId())
keyInfoNode = signNode.ensureKeyInfo()
keyInfoNode.addX509Data()
dsig_ctx = xmlsec.DSigCtx()
chave = xmlsec.cryptoAppKeyLoad(filename=str(self.arquivo),
format=xmlsec.KeyDataFormatPkcs12,
pwd=str(self.senha),
pwdCallback=None,
pwdCallbackCtx=None)
dsig_ctx.signKey = chave
dsig_ctx.sign(signNode)
status = dsig_ctx.status
dsig_ctx.destroy()
if status != xmlsec.DSigStatusSucceeded:
raise RuntimeError(
'Erro ao realizar a assinatura do arquivo; status: "' +
str(status) +
'"')
xpath = doc_xml.xpathNewContext()
xpath.xpathRegisterNs('sig', NAMESPACE_SIG)
certificados = xpath.xpathEval(
'//sig:X509Data/sig:X509Certificate')
for i in range(len(certificados) - 1):
certificados[i].unlinkNode()
certificados[i].freeNode()
xml = doc_xml.serialize()
return xml
finally:
doc_xml.freeDoc()
# self._finalizar_cripto()
def assina_xml_nota(self, xml, reference):
self._checar_certificado()
self._inicializar_cripto()
try:
doc_xml = libxml2.parseMemory(
xml.encode('utf-8'), len(xml.encode('utf-8')))
signNode = xmlsec.TmplSignature(doc_xml,
xmlsec.transformInclC14NId(),
xmlsec.transformRsaSha1Id(), None)
doc_xml.getRootElement().get_last().addChild(signNode)
refNode = signNode.addReference(xmlsec.transformSha1Id(),
None, '#' + str(reference), None)
refNode.addTransform(xmlsec.transformEnvelopedId())
refNode.addTransform(xmlsec.transformInclC14NId())
keyInfoNode = signNode.ensureKeyInfo()
keyInfoNode.addX509Data()
dsig_ctx = xmlsec.DSigCtx()
chave = xmlsec.cryptoAppKeyLoad(filename=str(self.arquivo),
format=xmlsec.KeyDataFormatPkcs12,
pwd=str(self.senha),
pwdCallback=None,
pwdCallbackCtx=None)
dsig_ctx.signKey = chave
dsig_ctx.sign(signNode)
status = dsig_ctx.status
dsig_ctx.destroy()
if status != xmlsec.DSigStatusSucceeded:
raise RuntimeError(
'Erro ao realizar a assinatura do arquivo; status: "' +
str(status) +
'"')
xpath = doc_xml.xpathNewContext()
xpath.xpathRegisterNs('sig', NAMESPACE_SIG)
certificados = xpath.xpathEval(
'//sig:X509Data/sig:X509Certificate')
for i in range(len(certificados) - 1):
certificados[i].unlinkNode()
certificados[i].freeNode()
xml = doc_xml.serialize()
return xml
finally:
doc_xml.freeDoc()
# self._finalizar_cripto()
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha)
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
root = etree.parse(StringIO(xml), parser=parser)
for element in root.iter("*"):
if element.text is not None and not element.text.strip():
element.text = None
signer = XMLSigner(
method=signxml.methods.enveloped, signature_algorithm="rsa-sha1",
digest_algorithm='sha1',
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
signed_root = signer.sign(
root, key=key, cert=cert, reference_only=True,
reference_uri=('#%s' % reference))
signed_root[2].append(signed_root[3])
return etree.tostring(signed_root)

30
pytrustnfe/nfe/templates/NfeAutorizacao.xml

@ -32,11 +32,11 @@
<emit>
{% with emit = NFe.infNFe.emit %}
{% if emit.tipo == 'person' -%}
<CPF>{{ emit.cnpj_cpf }}</CPF>
{% endif %}
{% if emit.tipo == 'company' -%}
<CNPJ>{{ emit.cnpj_cpf }}</CNPJ>
{% endif %}
<CPF>{{ emit.cnpj_cpf }}</CPF>
{% endif %}
{% if emit.tipo == 'company' -%}
<CNPJ>{{ emit.cnpj_cpf }}</CNPJ>
{% endif %}
<xNome>{{ emit.xNome }}</xNome>
<xFant>{{ emit.xFant }}</xFant>
<enderEmit>
@ -58,11 +58,11 @@
<dest>
{% with dest = NFe.infNFe.dest %}
{% if dest.tipo == 'person' -%}
<CPF>{{ dest.cnpj_cpf }}</CPF>
{% endif %}
{% if dest.tipo == 'company' -%}
<CNPJ>{{ dest.cnpj_cpf }}</CNPJ>
{% endif %}
<CPF>{{ dest.cnpj_cpf }}</CPF>
{% endif %}
{% if dest.tipo == 'company' -%}
<CNPJ>{{ dest.cnpj_cpf }}</CNPJ>
{% endif %}
<xNome>{{ dest.xNome }}</xNome>
<enderDest>
<xLgr>{{ dest.enderDest.xLgr }}</xLgr>
@ -154,6 +154,16 @@
<vCOFINS>{{ imposto.COFINS.COFINSAliq.vCOFINS }}</vCOFINS>
</COFINSAliq>
</COFINS>
<ICMSUFDest>
<vBCUFDest>0.00</vBCUFDest>
<pFCPUFDest>0.00</pFCPUFDest>
<pICMSUFDest>0.00</pICMSUFDest>
<pICMSInter>12.00</pICMSInter>
<pICMSInterPart>40</pICMSInterPart>
<vFCPUFDest>0.00</vFCPUFDest>
<vICMSUFDest>0.00</vICMSUFDest>
<vICMSUFRemet>0.00</vICMSUFRemet>
</ICMSUFDest>
{% endwith %}
</imposto>
</det>

87
pytrustnfe/nfse/assinatura.py

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
# © 2016 Danimar Ribeiro, Trustcode
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import xmlsec
import libxml2
import os.path
NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#'
class Assinatura(object):
def __init__(self, arquivo, senha):
self.arquivo = arquivo
self.senha = senha
def _checar_certificado(self):
if not os.path.isfile(self.arquivo):
raise Exception('Caminho do certificado não existe.')
def _inicializar_cripto(self):
libxml2.initParser()
libxml2.substituteEntitiesDefault(1)
xmlsec.init()
xmlsec.cryptoAppInit(None)
xmlsec.cryptoInit()
def _finalizar_cripto(self):
xmlsec.cryptoShutdown()
xmlsec.cryptoAppShutdown()
xmlsec.shutdown()
libxml2.cleanupParser()
def assina_xml(self, xml, reference):
self._checar_certificado()
self._inicializar_cripto()
try:
doc_xml = libxml2.parseMemory(
xml, len(xml))
signNode = xmlsec.TmplSignature(doc_xml,
xmlsec.transformInclC14NId(),
xmlsec.transformRsaSha1Id(), None)
doc_xml.getRootElement().addChild(signNode)
refNode = signNode.addReference(xmlsec.transformSha1Id(),
None, reference, None)
refNode.addTransform(xmlsec.transformEnvelopedId())
refNode.addTransform(xmlsec.transformInclC14NId())
keyInfoNode = signNode.ensureKeyInfo()
keyInfoNode.addX509Data()
dsig_ctx = xmlsec.DSigCtx()
chave = xmlsec.cryptoAppKeyLoad(filename=str(self.arquivo),
format=xmlsec.KeyDataFormatPkcs12,
pwd=str(self.senha),
pwdCallback=None,
pwdCallbackCtx=None)
dsig_ctx.signKey = chave
dsig_ctx.sign(signNode)
status = dsig_ctx.status
dsig_ctx.destroy()
if status != xmlsec.DSigStatusSucceeded:
raise RuntimeError(
'Erro ao realizar a assinatura do arquivo; status: "' +
str(status) +
'"')
xpath = doc_xml.xpathNewContext()
xpath.xpathRegisterNs('sig', NAMESPACE_SIG)
certificados = xpath.xpathEval(
'//sig:X509Data/sig:X509Certificate')
for i in range(len(certificados) - 1):
certificados[i].unlinkNode()
certificados[i].freeNode()
xml = doc_xml.serialize()
return xml
finally:
doc_xml.freeDoc()

2
pytrustnfe/nfse/paulistana/__init__.py

@ -9,7 +9,7 @@ from base64 import b64encode
from pytrustnfe.xml import render_xml, sanitize_response
from pytrustnfe.client import get_authenticated_client
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key
from pytrustnfe.nfe.assinatura import Assinatura
from pytrustnfe.nfse.assinatura import Assinatura
def sign_tag(certificado, **kwargs):

Loading…
Cancel
Save