From bcbfd1eca346e7078159dda8648e56f63407d51a Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Thu, 15 Jul 2021 18:07:38 -0500 Subject: [PATCH] Firmar con fiel en formato PEM --- CHANGELOG.md | 8 +++++++- VERSION | 2 +- source/sat/cfdi_cert.py | 20 +++++++++++++++++++- source/sat/util.py | 35 +++++++++++++++++++++++++---------- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e15da1f..0da8b07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Lista de cambios -## v 0.1.0 + +## v 0.2.0 [15-Jul-21] +--- +* Se agrega la posibilidad de firmar con fiel en formato PEM + + +## v 0.1.0 [15-Jul-21] --- * Primera versión funcional de la descarga masiva diff --git a/VERSION b/VERSION index 6e8bf73..0ea3a94 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 +0.2.0 diff --git a/source/sat/cfdi_cert.py b/source/sat/cfdi_cert.py index 8623356..9fe9cbd 100644 --- a/source/sat/cfdi_cert.py +++ b/source/sat/cfdi_cert.py @@ -19,11 +19,12 @@ from conf import TOKEN class SATCertificate(object): - def __init__(self, cer=b'', key=b'', password=''): + def __init__(self, cer=b'', key=b'', pem='', password=''): self._error = '' self._init_values() self._get_data_cer(cer) self._get_data_key(key, password) + self._get_data_pem(pem) def _init_values(self): self._rfc = '' @@ -131,6 +132,11 @@ class SATCertificate(object): ) return key_pem + def _get_data_pem(self, pem): + self._key_pem = serialization.load_pem_private_key( + pem, None, backend=default_backend()) + return + # Not work def _get_p12(self): obj = serialization.pkcs12.serialize_key_and_certificates('test', @@ -144,7 +150,19 @@ class SATCertificate(object): firma = private_key.sign(data, padding.PKCS1v15(), hashes.SHA256()) return base64.b64encode(firma).decode() + def _sign_with_pem(self, data, name_hash): + if name_hash == 'sha256': + type_hash = hashes.SHA256() + elif name_hash == 'sha1': + type_hash = hashes.SHA1() + + firma = self._key_pem.sign(data, padding.PKCS1v15(), type_hash) + return base64.b64encode(firma).decode() + def sign_sha1(self, data, password=''): + if self._key_pem: + return self._sign_with_pem(data, 'sha1') + private_key = self._get_key(password) firma = private_key.sign(data, padding.PKCS1v15(), hashes.SHA1()) return base64.b64encode(firma).decode() diff --git a/source/sat/util.py b/source/sat/util.py index 40e4464..0cf49ae 100644 --- a/source/sat/util.py +++ b/source/sat/util.py @@ -33,7 +33,7 @@ def join(*paths): return Path(paths[0]).joinpath(*paths[1:]) -def _validate_fiel_args(args): +def _validate_fiel_args(args, need_key=False): fiel_path = args.fiel_dir fiel_name = args.fiel_nombre @@ -50,14 +50,15 @@ def _validate_fiel_args(args): path_cer = join(fiel_path, f'{fiel_name}.cer') path_key = join(fiel_path, f'{fiel_name}.key') path_enc = join(fiel_path, f'{fiel_name}.enc') + path_pem = join(fiel_path, f'{fiel_name}.pem') if not path_cer.is_file(): msg = f'No se encontró el archivo CER. \nRuta: {path_cer}' log.error(msg) return False, {} - if not path_key.is_file(): - msg = f'No se encontró el archivo KEY. \nRuta: {path_cer}' + if need_key and not path_key.is_file(): + msg = f'No se encontró el archivo KEY. \nRuta: {path_key}' log.error(msg) return False, {} @@ -65,12 +66,13 @@ def _validate_fiel_args(args): 'path_cer': path_cer, 'path_key': path_key, 'path_enc': path_enc, + 'path_pem': path_pem, } return True, data def fiel_validar(args): - result, data = _validate_fiel_args(args) + result, data = _validate_fiel_args(args, True) if not result: return @@ -82,7 +84,7 @@ def fiel_validar(args): cer = data['path_cer'].read_bytes() key = data['path_key'].read_bytes() - cert = SATCertificate(cer, key, password) + cert = SATCertificate(cer, key, password=password) if cert.error: msg = f'{cert.error}\n\nNo podrás conectarte el SAT.' @@ -110,19 +112,32 @@ def base_datos(): return +def _get_cert(data): + key = b'' + pem = b'' + cer = data['path_cer'].read_bytes() + if data['path_enc'].is_file(): + key = data['path_enc'].read_bytes() + elif data['path_pem'].is_file(): + pem = data['path_pem'].read_bytes() + cert = SATCertificate(cer, key, pem) + return cert + + def _validate_requests_args(args): result, data = _validate_fiel_args(args) if not result: return False, {} - if not data['path_enc'].is_file(): - msg = f"No se encontró la FIEL encriptada. \nRuta: {data['path_enc']}" + if not data['path_enc'].is_file() and not data['path_pem'].is_file(): + msg = f"No se encontró la FIEL [enc|pem].\nRuta: {data['path_enc']}" log.error(msg) return False, {} - cer = data['path_cer'].read_bytes() - key = data['path_enc'].read_bytes() - cert = SATCertificate(cer, key) + # ~ cer = data['path_cer'].read_bytes() + # ~ key = data['path_enc'].read_bytes() + # ~ cert = SATCertificate(cer, key) + cert = _get_cert(data) if not cert.is_valid_time: msg = 'La FIEL no es vigente'