Skip to content

Instantly share code, notes, and snippets.

@ovnicraft
Created October 24, 2019 22:08
Show Gist options
  • Save ovnicraft/f1ed9c42b79ce7c724d24b761e678ee5 to your computer and use it in GitHub Desktop.
Save ovnicraft/f1ed9c42b79ce7c724d24b761e678ee5 to your computer and use it in GitHub Desktop.
import os
from abc import ABC, abstractmethod
from base64 import b64encode, b64decode
from secrets import randbelow
from enum import Enum
from datetime import datetime
from OpenSSL.crypto import X509Name, load_pkcs12, FILETYPE_PEM, FILETYPE_ASN1
from cryptography.hazmat.primitives.asymmetric import rsa, dsa, ec
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from cryptography.hazmat.primitives.hashes import (
Hash,
SHA1,
SHA224,
SHA256,
SHA384,
SHA512,
)
from cryptography.hazmat.backends import default_backend
# from .util import (
# bytes_to_long,
# long_to_bytes,
# strip_pem_header,
# add_pem_header,
# ensure_bytes,
# ensure_str,
# Namespace,
# XMLProcessor,
# iterate_pem,
# verify_x509_cert_chain,
# )
# namespaces = Namespace(
# ds="http://www.w3.org/2000/09/xmldsig#",
# dsig11="http://www.w3.org/2009/xmldsig11#",
# dsig2="http://www.w3.org/2010/xmldsig2#",
# ec="http://www.w3.org/2001/10/xml-exc-c14n#",
# dsig_more="http://www.w3.org/2001/04/xmldsig-more#",
# xenc="http://www.w3.org/2001/04/xmlenc#",
# xenc11="http://www.w3.org/2009/xmlenc11#",
# )
# methods = Enum("Methods", "enveloped enveloping detached")
def check_cert_not_after(cert):
cert_not_after = datetime.strptime(
cert.get_notAfter().decode("ascii"), "%Y%m%d%H%M%SZ"
)
if cert_not_after < datetime.utcnow():
raise ValueError(
"Client certificate expired: Not After: {cert_not_after:%Y-%m-%d %H:%M:%SZ}".format(
**locals()
)
)
class Xades(ABC):
def __init__(self):
self._template_name = False
@property
@abstractmethod
def template(self):
raise NotImplementedError
def sign(self, data, cert=None, passphrase=None):
raise NotImplementedError
def verify(self):
return None
def generate_random_id(self):
return randbelow(100000)
class X509NamePKCS12(X509Name):
def slug_pkcs12(self):
x509name = self.get_components()
x509name.reverse()
return ",".join([f"{var.decode()}={alias.decode()}" for var, alias in x509name])
class XadesBES(Xades):
def __init__(self):
"""
"""
self._template_name = "xades_bes.xml"
self._X509_issuername = False
self.data = {}
def read_issuer_slug(self, certificate):
return X509NamePKCS12(certificate.get_issuer()).slug_pkcs12()
@property
def template(self):
return self._template_name
def load_certificate(self, cert_path, password):
cert_data = open(cert_path, "+rb").read()
bpass = password.encode()
p12 = load_pkcs12(cert_data, bpass)
cert = p12.get_certificate()
check_cert_not_after(cert)
private_key = p12.get_privatekey()
self.data.update(
{
"X509IssuerName": self.read_issuer_slug(cert),
"X509SerialNumber": cert.get_serial_number(),
}
)
def generate_data_ids(self):
self.data.update(
{
"SignatureID": self.generate_random_id(),
"SignedInfoID": self.generate_random_id(),
"SignedPropertiesID": self.generate_random_id(),
"SignedProperties": self.generate_random_id(),
"CertificateID": self.generate_random_id(),
"ReferenceID": self.generate_random_id(),
"SignatureValueID": self.generate_random_id(),
"ObjectID": self.generate_random_id(),
}
)
@property
def signing_time(self):
return datetime.now().replace(microsecond=0).isoformat()
if __name__ == "__main__":
xades = XadesBES()
xades.render()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment