|
|
|
@ -123,44 +123,37 @@ class AssinaturaA1(Assinatura): |
|
|
|
# Acrescenta a tag de doctype (como o lxml nao suporta alteracao do doctype, |
|
|
|
# converte para string para faze-lo) |
|
|
|
xml = etree.tostring(raiz, xml_declaration=True, encoding='utf-8') |
|
|
|
pos = xml.find('>') + 1 |
|
|
|
xml = xml[:pos] + doctype + xml[pos:] |
|
|
|
raiz = etree.parse(StringIO(xml)) |
|
|
|
|
|
|
|
# Ativa funções criptográficas |
|
|
|
self._ativa_funcoes_criptograficas() |
|
|
|
if xml.find('<!DOCTYPE ') == -1: |
|
|
|
pos = xml.find('>') + 1 |
|
|
|
xml = xml[:pos] + doctype + xml[pos:] |
|
|
|
#raiz = etree.parse(StringIO(xml)) |
|
|
|
|
|
|
|
# Colocamos o texto no avaliador XML |
|
|
|
#doc_xml = libxml2.parseMemory(xml, len(xml)) |
|
|
|
doc_xml, ctxt, noh_assinatura, assinador = self._antes_de_assinar_ou_verificar(raiz) |
|
|
|
|
|
|
|
# Cria o contexto para manipulação do XML via sintaxe XPATH |
|
|
|
#ctxt = doc_xml.xpathNewContext() |
|
|
|
#ctxt.xpathRegisterNs(u'sig', NAMESPACE_SIG) |
|
|
|
# Realiza a assinatura |
|
|
|
assinador.sign(noh_assinatura) |
|
|
|
|
|
|
|
# Separa o nó da assinatura |
|
|
|
#noh_assinatura = ctxt.xpathEval(u'//*/sig:Signature')[0] |
|
|
|
# Coloca na instância Signature os valores calculados |
|
|
|
doc.Signature.DigestValue = ctxt.xpathEval(u'//sig:DigestValue')[0].content.replace(u'\n', u'') |
|
|
|
doc.Signature.SignatureValue = ctxt.xpathEval(u'//sig:SignatureValue')[0].content.replace(u'\n', u'') |
|
|
|
|
|
|
|
# Buscamos a chave no arquivo do certificado |
|
|
|
chave = xmlsec.cryptoAppKeyLoad( |
|
|
|
filename=str(self.certificado.caminho_arquivo), |
|
|
|
format=xmlsec.KeyDataFormatPkcs12, |
|
|
|
pwd=str(self.senha), |
|
|
|
pwdCallback=None, |
|
|
|
pwdCallbackCtx=None, |
|
|
|
) |
|
|
|
# Provavelmente retornarão vários certificados, já que o xmlsec inclui a cadeia inteira |
|
|
|
certificados = ctxt.xpathEval(u'//sig:X509Data/sig:X509Certificate') |
|
|
|
doc.Signature.X509Certificate = certificados[len(certificados)-1].content.replace(u'\n', u'') |
|
|
|
|
|
|
|
# Cria a variável de chamada (callable) da função de assinatura |
|
|
|
assinador = xmlsec.DSigCtx() |
|
|
|
resultado = assinador.status == xmlsec.DSigStatusSucceeded |
|
|
|
|
|
|
|
# Atribui a chave ao assinador |
|
|
|
assinador.signKey = chave |
|
|
|
|
|
|
|
# Desativa funções criptográficas |
|
|
|
self._desativa_funcoes_criptograficas() |
|
|
|
# Limpa objetos da memoria e desativa funções criptográficas |
|
|
|
self._depois_de_assinar_ou_verificar(doc_xml, ctxt, assinador) |
|
|
|
|
|
|
|
#print etree.tostring(raiz, pretty_print=True, xml_declaration=True, encoding='utf-8') |
|
|
|
|
|
|
|
def _ativa_funcoes_criptograficas(self): |
|
|
|
return resultado |
|
|
|
|
|
|
|
def _ativar_funcoes_criptograficas(self): |
|
|
|
# FIXME: descobrir forma de evitar o uso do libxml2 neste processo |
|
|
|
|
|
|
|
# Ativa as funções de análise de arquivos XML FIXME |
|
|
|
libxml2.initParser() |
|
|
|
libxml2.substituteEntitiesDefault(1) |
|
|
|
@ -170,7 +163,7 @@ class AssinaturaA1(Assinatura): |
|
|
|
xmlsec.cryptoAppInit(None) |
|
|
|
xmlsec.cryptoInit() |
|
|
|
|
|
|
|
def _desativa_funcoes_criptograficas(self): |
|
|
|
def _desativar_funcoes_criptograficas(self): |
|
|
|
''' Desativa as funções criptográficas e de análise XML |
|
|
|
As funções devem ser chamadas aproximadamente na ordem inversa da ativação |
|
|
|
''' |
|
|
|
@ -184,6 +177,71 @@ class AssinaturaA1(Assinatura): |
|
|
|
# Shutdown xmlsec library |
|
|
|
xmlsec.shutdown() |
|
|
|
|
|
|
|
# Shutdown LibXML2 FIXME |
|
|
|
# Shutdown LibXML2 FIXME: descobrir forma de evitar o uso do libxml2 neste processo |
|
|
|
libxml2.cleanupParser() |
|
|
|
|
|
|
|
def verificar_arquivo(self, caminho_arquivo): |
|
|
|
# Carrega o XML do arquivo |
|
|
|
raiz = etree.parse(caminho_arquivo) |
|
|
|
return self.verificar_etree(raiz) |
|
|
|
|
|
|
|
def verificar_xml(self, xml): |
|
|
|
raiz = etree.parse(StringIO(xml)) |
|
|
|
return self.verificar_etree(raiz) |
|
|
|
|
|
|
|
def verificar_etree(self, raiz): |
|
|
|
doc_xml, ctxt, noh_assinatura, assinador = self._antes_de_assinar_ou_verificar(raiz) |
|
|
|
|
|
|
|
# Verifica a assinatura |
|
|
|
assinador.verify(noh_assinatura) |
|
|
|
resultado = assinador.status == xmlsec.DSigStatusSucceeded |
|
|
|
|
|
|
|
# Limpa objetos da memoria e desativa funções criptográficas |
|
|
|
self._depois_de_assinar_ou_verificar(doc_xml, ctxt, assinador) |
|
|
|
|
|
|
|
return resultado |
|
|
|
|
|
|
|
def _antes_de_assinar_ou_verificar(self, raiz): |
|
|
|
# Converte etree para string |
|
|
|
xml = etree.tostring(raiz, xml_declaration=True, encoding='utf-8') |
|
|
|
|
|
|
|
# Ativa funções criptográficas |
|
|
|
self._ativar_funcoes_criptograficas() |
|
|
|
|
|
|
|
# Colocamos o texto no avaliador XML FIXME: descobrir forma de evitar o uso do libxml2 neste processo |
|
|
|
doc_xml = libxml2.parseMemory(xml, len(xml)) |
|
|
|
|
|
|
|
# Cria o contexto para manipulação do XML via sintaxe XPATH |
|
|
|
ctxt = doc_xml.xpathNewContext() |
|
|
|
ctxt.xpathRegisterNs(u'sig', NAMESPACE_SIG) |
|
|
|
|
|
|
|
# Separa o nó da assinatura |
|
|
|
noh_assinatura = ctxt.xpathEval(u'//*/sig:Signature')[0] |
|
|
|
|
|
|
|
# Buscamos a chave no arquivo do certificado |
|
|
|
chave = xmlsec.cryptoAppKeyLoad( |
|
|
|
filename=str(self.certificado.caminho_arquivo), |
|
|
|
format=xmlsec.KeyDataFormatPkcs12, |
|
|
|
pwd=str(self.senha), |
|
|
|
pwdCallback=None, |
|
|
|
pwdCallbackCtx=None, |
|
|
|
) |
|
|
|
|
|
|
|
# Cria a variável de chamada (callable) da função de assinatura |
|
|
|
assinador = xmlsec.DSigCtx() |
|
|
|
|
|
|
|
# Atribui a chave ao assinador |
|
|
|
assinador.signKey = chave |
|
|
|
|
|
|
|
return doc_xml, ctxt, noh_assinatura, assinador |
|
|
|
|
|
|
|
def _depois_de_assinar_ou_verificar(self, doc_xml, ctxt, assinador): |
|
|
|
# Libera a memória do assinador; isso é necessário, pois na verdade foi feita uma chamada |
|
|
|
# a uma função em C cujo código não é gerenciado pelo Python |
|
|
|
assinador.destroy() |
|
|
|
ctxt.xpathFreeContext() |
|
|
|
doc_xml.freeDoc() |
|
|
|
|
|
|
|
# E, por fim, desativa todas as funções ativadas anteriormente |
|
|
|
self._desativar_funcoes_criptograficas() |
|
|
|
|