Browse Source

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

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

55
pynfe/entidades/certificado.py

@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
import os
from .base import Entidade
from OpenSSL import crypto
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.
Caso va implementar um novo formato de certificado, crie uma classe que
@ -18,41 +17,31 @@ class Certificado(Entidade):
else:
return super(Certificado, cls).__new__(cls)
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."""
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):
u"""Separa o arquivo de certificado em dois: de chave e de certificado,
em arquivos temporários separados"""
"""Separa o arquivo de certificado em dois: de chave e de certificado,
e retorna a string."""
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())
# Retorna a string decodificado do certificado
cert_str = crypto.dump_certificate(crypto.FILETYPE_PEM, pkcs12.get_certificate())
# Gravando a string no dicso
open(caminho_cert, 'wb').write(cert_str)
# Gravando a string no dicso
open(caminho_chave, 'wb').write(key_str)
return caminho_chave, caminho_cert
# 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)
# 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-----', '')
# Chave, string decodificada da chave privada
chave = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkcs12.get_privatekey())
return chave, cert

18
pynfe/processamento/assinatura.py

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import signxml
from OpenSSL import crypto
from pynfe.utils import etree
from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SIG
@ -27,22 +28,17 @@ class AssinaturaA1(Assinatura):
def assinar(self, xml):
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.fromstring(xml) # string
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',
reference_uri='#NFe41150715380524000122651010000000271333611649')
reference_uri='')
#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)
return result

2
pynfe/processamento/serializacao.py

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

8
test.py

@ -57,7 +57,7 @@ nota_fiscal = NotaFiscal(
cliente=cliente,
uf='PR',
codigo_numerico_aleatorio='66998237',
natureza_operacao='VENDA ASSINATURAS',
natureza_operacao='VENDA',
forma_pagamento='1',
modelo=65,
serie='1',
@ -100,9 +100,9 @@ nota_fiscal.adicionar_produto_servico(codigo='000328', # id do produto (000328 e
cofins_valor=Decimal('3.51'))
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
a1 = AssinaturaA1(certificado, senha)
xml = a1.assinar_nfe(xml)

Loading…
Cancel
Save