Browse Source

Merge branch 'master' of https://github.com/leotada/PyNFe

pull/1/head
Junior Tada 11 years ago
parent
commit
3d160d32e7
  1. 47
      pynfe/entidades/certificado.py
  2. 18
      pynfe/processamento/assinatura.py
  3. 2
      pynfe/processamento/serializacao.py
  4. 8
      test.py

47
pynfe/entidades/certificado.py

@ -1,12 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
from .base import Entidade from .base import Entidade
from OpenSSL import crypto from OpenSSL import crypto
class Certificado(Entidade): class Certificado(Entidade):
u"""Classe abstrata responsavel por definir o modelo padrao para as demais
"""Classe abstrata responsavel por definir o modelo padrao para as demais
classes de certificados digitais. classes de certificados digitais.
Caso va implementar um novo formato de certificado, crie uma classe que Caso va implementar um novo formato de certificado, crie uma classe que
@ -18,41 +17,31 @@ class Certificado(Entidade):
else: else:
return super(Certificado, cls).__new__(cls) return super(Certificado, cls).__new__(cls)
class CertificadoA1(Certificado): class CertificadoA1(Certificado):
u"""Implementa a entidade do certificado eCNPJ A1, suportado pelo OpenSSL,
"""Implementa a entidade do certificado eCNPJ A1, suportado pelo OpenSSL,
e amplamente utilizado.""" e amplamente utilizado."""
caminho_arquivo = None caminho_arquivo = None
conteudo_x509 = None
pasta_temporaria = '/tmp/'
arquivo_chave = 'key.pem'
arquivo_cert = 'cert.pem'
def __init__(self, caminho_arquivo=None, conteudo_x509=None):
self.caminho_arquivo = caminho_arquivo or self.caminho_arquivo
self.conteudo_x509 = conteudo_x509 or self.conteudo_x509
def __init__(self, caminho_arquivo=None):
self.caminho_arquivo = caminho_arquivo
def separar_arquivo(self, senha, caminho_chave=None, caminho_cert=None): def separar_arquivo(self, senha, caminho_chave=None, caminho_cert=None):
u"""Separa o arquivo de certificado em dois: de chave e de certificado,
em arquivos temporários separados"""
caminho_chave = caminho_chave or os.path.join(self.pasta_temporaria, self.arquivo_chave)
caminho_cert = caminho_cert or os.path.join(self.pasta_temporaria, self.arquivo_cert)
# Lendo o arquivo pfx no formato pkcs12 como binario
pkcs12 = crypto.load_pkcs12(open(self.caminho_arquivo, 'rb').read(), senha)
# Retorna a string decodificado da chave privada
key_str = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkcs12.get_privatekey())
"""Separa o arquivo de certificado em dois: de chave e de certificado,
e retorna a string."""
# Retorna a string decodificado do certificado
cert_str = crypto.dump_certificate(crypto.FILETYPE_PEM, pkcs12.get_certificate())
# Carrega o arquivo .pfx, erro pode ocorrer se a senha estiver errada ou formato invalido.
pkcs12 = crypto.load_pkcs12(open(self.caminho_arquivo, "rb").read(), senha)
# Gravando a string no dicso
open(caminho_cert, 'wb').write(cert_str)
# Certificado
cert = crypto.dump_certificate(crypto.FILETYPE_PEM, pkcs12.get_certificate()).decode('utf-8')
cert = cert.replace('\n', '')
cert = cert.replace('-----BEGIN CERTIFICATE-----', '')
cert = cert.replace('-----END CERTIFICATE-----', '')
# Gravando a string no dicso
open(caminho_chave, 'wb').write(key_str)
# Chave, string decodificada da chave privada
chave = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkcs12.get_privatekey())
return caminho_chave, caminho_cert
return chave, cert

18
pynfe/processamento/assinatura.py

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import signxml import signxml
from OpenSSL import crypto
from pynfe.utils import etree from pynfe.utils import etree
from pynfe.entidades.certificado import CertificadoA1 from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SIG from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SIG
@ -27,22 +28,17 @@ class AssinaturaA1(Assinatura):
def assinar(self, xml): def assinar(self, xml):
arquivo_cert = CertificadoA1(self.certificado) arquivo_cert = CertificadoA1(self.certificado)
#key, cert = arquivo_cert.separar_arquivo(self.senha)
cert = open("cert.pem").read()
key = open("key.pem", "rb").read()
chave, cert = arquivo_cert.separar_arquivo(self.senha)
begin = cert.find('-----BEGIN CERTIFICATE-----')
if begin < 0:
raise Exception('Formato de certificado inválido. Não encontrado tag inicial BEGIN.')
cert = cert[begin:]
# converte xml para bytes antes do parse
#root = etree.parse(xml).getroot() # caminho #root = etree.parse(xml).getroot() # caminho
root = etree.fromstring(xml) # string root = etree.fromstring(xml) # string
signer = signxml.xmldsig(root, digest_algorithm="sha1") signer = signxml.xmldsig(root, digest_algorithm="sha1")
signer.sign(method=signxml.methods.enveloped, key=key, cert=cert,
signer.sign(method=signxml.methods.enveloped, key=chave, cert=cert,
algorithm="rsa-sha1", c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315', algorithm="rsa-sha1", c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
reference_uri='#NFe41150715380524000122651010000000271333611649')
reference_uri='')
#verified_data = signer.verify(require_x509=True, ca_pem_file="cert.pem") #verified_data = signer.verify(require_x509=True, ca_pem_file="cert.pem")
#root = etree.SubElement(signer.data, "{http://www.w3.org/2000/09/xmldsig#}Reference",
# URI='#NFe41150715389524000122651010000000271333611649')
result = etree.tostring(signer.data) result = etree.tostring(signer.data)
return result return result

2
pynfe/processamento/serializacao.py

@ -58,7 +58,7 @@ class SerializacaoXML(Serializacao):
raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False)) raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False))
if retorna_string: if retorna_string:
return etree.tostring(raiz, pretty_print=True)
return etree.tostring(raiz, pretty_print=True).decode('utf-8')
else: else:
return raiz return raiz

8
test.py

@ -57,7 +57,7 @@ nota_fiscal = NotaFiscal(
cliente=cliente, cliente=cliente,
uf='PR', uf='PR',
codigo_numerico_aleatorio='66998237', codigo_numerico_aleatorio='66998237',
natureza_operacao='VENDA ASSINATURAS',
natureza_operacao='VENDA',
forma_pagamento='1', forma_pagamento='1',
modelo=65, modelo=65,
serie='1', serie='1',
@ -100,9 +100,9 @@ nota_fiscal.adicionar_produto_servico(codigo='000328', # id do produto (000328 e
cofins_valor=Decimal('3.51')) cofins_valor=Decimal('3.51'))
serializador = SerializacaoXML(_fonte_dados, homologacao=True) serializador = SerializacaoXML(_fonte_dados, homologacao=True)
xml = serializador.exportar(retorna_string=True).decode('utf-8')
certificado = "certificado_A1.pfx"
senha = 'sua_senha'
xml = serializador.exportar(retorna_string=True)
certificado = "JC.pfx"
senha = '12345678'
# assinatura # assinatura
a1 = AssinaturaA1(certificado, senha) a1 = AssinaturaA1(certificado, senha)
xml = a1.assinar_nfe(xml) xml = a1.assinar_nfe(xml)

Loading…
Cancel
Save