Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove xmlsec #26

Merged
merged 16 commits into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.2.0
current_version = 1.3.0
commit = True
tag = True

Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ Overview
:alt: PyPI Package latest release
:target: https://erpbrasilassinatura.readthedocs.io/en/latest/

.. |commits-since| image:: https://img.shields.io/github/commits-since/erpbrasil/erpbrasil.assinatura/v1.2.0...svg
.. |commits-since| image:: https://img.shields.io/github/commits-since/erpbrasil/erpbrasil.assinatura/v1.3.0...svg
:alt: Commits since latest release
:target: https://github.com/erpbrasil/erpbrasil.assinatura/compare/v1.2.0...master
:target: https://github.com/erpbrasil/erpbrasil.assinatura/compare/v1.3.0...master

.. |wheel| image:: https://img.shields.io/pypi/wheel/erpbrasil.assinatura.svg
:alt: PyPI Wheel
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
year = '2019'
author = 'Luis Felipe Mileo'
copyright = '{0}, {1}'.format(year, author)
version = release = '1.2.0'
version = release = '1.3.0'

pygments_style = 'trac'
templates_path = ['.']
Expand Down
7 changes: 3 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
pyopenssl==19.1.0
pytz==2016.7
signxml==2.8.1
pytz>=2016.7
cryptography==3.3.2
signxml==2.8.2
pycrypto==2.6.1
endesive==2.0.1
chardet==3.0.4
xmlsec==1.3.8
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def read(*names, **kwargs):

setup(
name='erpbrasil.assinatura',
version='1.2.0',
version='1.3.0',
license='MIT license',
description='Assinatura de documentos com certificados digitais A1 e A3',
long_description='%s\n%s' % (
Expand Down
2 changes: 1 addition & 1 deletion src/erpbrasil/assinatura/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '1.2.0'
__version__ = '1.3.0'

from erpbrasil.assinatura.assinatura import Assinatura # noqa: F401
from erpbrasil.assinatura.certificado import Certificado # noqa: F401
141 changes: 60 additions & 81 deletions src/erpbrasil/assinatura/assinatura.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
# coding=utf-8

from base64 import b64encode

import signxml
import xmlsec
from base64 import b64encode
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from endesive import pdf
from endesive import signer
from endesive import xades
from lxml import etree
from OpenSSL import crypto
from xmlsec import constants as consts
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from Crypto.Signature import PKCS1_v1_5
from hashlib import sha1


class Assinatura(object):
Expand All @@ -22,6 +19,31 @@ def __init__(self, certificado):
self.chave_privada = certificado._chave
self.senha = certificado._senha

@classmethod
def digest(self, text):
hasher = sha1()
hasher.update(str(text).encode('utf-8'))
digest = hasher.digest()
return b64encode(digest).decode('utf-8')

def assina_xml(self, arquivo):
signer = signxml.XMLSigner(
method=signxml.methods.enveloped,
signature_algorithm="rsa-sha1",
digest_algorithm='sha1',
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
)

root = etree.fromstring(arquivo)

signed_root = signer.sign(
root,
key=self.certificado.key,
cert=self.certificado._cert,
)

return etree.tostring(signed_root)

def assina_xml2(self, xml_element, reference, getchildren=False):
for element in xml_element.iter("*"):
if element.text is not None and not element.text.strip():
Expand Down Expand Up @@ -70,83 +92,26 @@ def assina_xml2(self, xml_element, reference, getchildren=False):
parent.append(signature)
return etree.tostring(signed_root, encoding=str)

def _checar_certificado(self):
if not self.chave_privada:
raise Exception("Certificado não existe.")

def assina_nfse(self, template):
self._checar_certificado()

key = xmlsec.Key.from_memory(
self.chave_privada,
format=xmlsec.constants.KeyDataFormatPem,
password=self.senha,
)

signature_node = xmlsec.template.create(
template,
c14n_method=consts.TransformInclC14N,
sign_method=consts.TransformRsaSha1,
)
template.append(signature_node)
ref = xmlsec.template.add_reference(
signature_node, consts.TransformSha1, uri=""
)

xmlsec.template.add_transform(ref, consts.TransformEnveloped)
xmlsec.template.add_transform(ref, consts.TransformInclC14N)

ki = xmlsec.template.ensure_key_info(signature_node)
xmlsec.template.add_x509_data(ki)

ctx = xmlsec.SignatureContext()
ctx.key = key
def assina_nfse(self, xml_etree):

ctx.key.load_cert_from_memory(self.cert,
consts.KeyDataFormatPem)

ctx.sign(signature_node)
return etree.tostring(template, encoding=str)

def assina_pdf(self, arquivo, dados_assinatura, altoritimo='sha256'):
return pdf.cms.sign(
datau=arquivo,
udct=dados_assinatura,
key=self.certificado.key,
cert=self.certificado.cert,
othercerts=self.certificado.othercerts,
algomd=altoritimo
signer = signxml.XMLSigner(
method=signxml.methods.enveloped,
signature_algorithm="rsa-sha1",
digest_algorithm='sha1',
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
)

@staticmethod
def verifica_pdf(arquivo, certificados_de_confianca):
return pdf.verify(
data=arquivo,
trusted_cert_pems=certificados_de_confianca
signed_root = signer.sign(
xml_etree,
key=self.chave_privada,
cert=self.cert,
)

def assina_xml(self, arquivo):
def signproc(tosign, algosig):
key = self.certificado.key
signed_value_signature = key.sign(
tosign,
padding.PKCS1v15(),
getattr(hashes, algosig.upper())()
)
return signed_value_signature
signed_root = etree.tostring(signed_root, encoding=str)

cert = self.certificado.cert
certcontent = signer.cert2asn(cert).dump()
signed_root = signed_root.replace('\r', '').replace('\n', '')

cls = xades.BES()
doc = cls.enveloping(
'documento.xml', arquivo, 'application/xml',
cert, certcontent, signproc, False, True
)

return etree.tostring(
doc, encoding='UTF-8', xml_declaration=True, standalone=False
)
return signed_root

def assina_string(self, message):
private_key = self.certificado.key
Expand All @@ -160,10 +125,24 @@ def assina_string(self, message):
)
return signature

def assina_pdf(self, arquivo, dados_assinatura, algoritmo='sha256'):
return pdf.cms.sign(
datau=arquivo,
udct=dados_assinatura,
key=self.certificado.key,
cert=self.certificado.cert,
othercerts=self.certificado.othercerts,
algomd=algoritmo
)

def assina_tag(self, message):
chave_privada = self.certificado._pkcs12.get_privatekey()
assianado = crypto.sign(chave_privada, message, "SHA1")
return b64encode(assianado).decode()
privateKeyContent = (self.certificado._chave).decode('utf-8')
message = message.encode('utf-8')
message = SHA.new(message)
rsaKey = RSA.importKey(privateKeyContent)
signer = PKCS1_v1_5.new(rsaKey)
signature = signer.sign(message)
return b64encode(signature).decode()

def verificar_assinatura_string(self, message, signature):
public_key = self.certificado.key.public_key()
Expand Down